Commit e78ff6b6132e602aa67ff751a0360d4083b00ea8

Authored by Georg Hopp
1 parent e4b19add

reduce to easel3d-xcb demo program

Showing 104 changed files with 163 additions and 7040 deletions
1 1 [package]
2   -name = "xcb-test"
  2 +name = "easel3d-xcb"
3 3 version = "0.1.0"
4 4 authors = ["Georg Hopp <georg@steffers.org>"]
5 5 edition = "2018"
6 6
7 7 [dependencies]
  8 +easel3d = { path = "../easel3d" }
8 9 libc = "0.2"
9   -gl = "0.5.2"
10   -x11 = { version = "2.3", features = ["glx"] }
11 10 xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] }
... ...
1   -# Rust playground
  1 +# Easel3D-XCB
2 2
3   -Things I have recently done while learning the Rust programming language.
  3 +X windows demo application using Easel3D...
4 4
5 5 ## Synopsis
6 6
7   -Change in one of the toplevel subdirectories and try `cargo build` or
8   -`cargo run`. Maybe not everything is working oob. Feel free to fix whatever
9   -you want.
  7 +Checkout this repository as well as the _easel3d_ repository to the same
  8 +destination directory.
10 9
11   -## Description
12   -
13   -Various small examples I have tried while learning rust. The biggest and
14   -currently most active project is **fractional** which started as an
15   -implamentation of a rational number data type and then switched to a 3D
16   -math playground visualizing using **XCB** (in future it might also use
17   -a **HTML5 Canvas** for drawing as WebAssembly application.
18   -Using fractions with 3D math has several drawbacks:
  10 +In the root of this repository call `cargo run`.
19 11
20   -1. A huge part of 3D math is non rational, like sin, cos, tan and sqrt.
21   -2. The numerator and denominator tend to become very huge while nearing to non
22   - rational numbers and reduction is difficult and time consuming.
23   -3. Because of 2 it is way slower than the floating point calculation (at least
24   - with a decent coprocessor).
  12 +## Description
25 13
26   -Anyway, implementing the vector math stuff for both fractions and floating
27   -point was a nice playground for generics and traits. In future I might add
28   -another data type which implements the math as done by David Braben for the
29   -elite computer game.
  14 +A demo application using easel3d to draw in an X-Window.
30 15
31 16 ## Requirements
32 17
33   -### Always
34   -
35 18 - A recent version of the Rust programming language as well as tooling.
36 19 Currently I use Rust 1.39.0.
  20 +- X11 (xcb, x11-shm)
37 21
38   -### For fractional
  22 +## Dependencies
39 23
40   -- A running X Server with **XCB** and **X11-SHM** extentions
  24 +### Rust crates.
41 25
42   -## Dependencies
  26 +- easel3d (from parent directory)
  27 +- libc >=0.2
  28 +- xcb >=0.8
43 29
44   -...
  30 +Along with the dependencies of the xcb crate. `cargo build` should take care
  31 +of having them available.
45 32
46 33 ## Contributing
47 34
... ...
1   -# This file is automatically @generated by Cargo.
2   -# It is not intended for manual editing.
3   -[[package]]
4   -name = "branches"
5   -version = "0.1.0"
6   -
1   -[package]
2   -name = "branches"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -//
2   -// Control Flow Examples
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -
22   -fn main() {
23   - let condition = true;
24   - let number = if condition {
25   - 5
26   - } else {
27   - 6
28   - };
29   -
30   - println!("The value of number is: {}", number);
31   -}
No preview for this file type
1   -[package]
2   -name = "fractional"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -[dependencies]
8   -lazy_static = "1.4.0"
9   -libc = "0.2"
10   -gl = "0.5.2"
11   -x11 = { version = "2.3", features = ["glx"] }
12   -xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] }
No preview for this file type
1   -http://www.jongware.com/galaxy1.html
1   -I really would like to see a HTML5 canvas as canvas for the 3D code.
2   -
3   -Some URLs:
4   -- https://stackoverflow.com/questions/42806037/modify-canvas-from-wasm
5   -- https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.HtmlCanvasElement.html
6   -- https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.CanvasRenderingContext2d.html
7   -- https://stackoverflow.com/questions/49935207/editing-canvas-pixel-data-in-webassembly-rust
1   -https://www.themathpage.com/Alg/reciprocals.htm
No preview for this file type
No preview for this file type
1   -https://en.wikipedia.org/wiki/Texture_mapping
2   -http://www.gamers.org/dEngine/quake/papers/checker_texmap.html
3   -https://www.cs.uic.edu/~jbell/CourseNotes/ComputerGraphics/TextureMapping.html
4   -http://www.decew.net/OSS/References/chapter_2_texture_mapping.pdf
5   -
6   -# example affine texture mapping
7   -http://archive.gamedev.net/archive/reference/articles/article852.html
8   -
9   -
10   -http://www.lysator.liu.se/~mikaelk/doc/perspectivetexture/
11   -
12   -# Shader... This also describes z-Buffer... :)
13   -https://people.ece.cornell.edu/land/OldStudentProjects/cs490-95to96/GUO/report.html
14   -https://software.intel.com/en-us/articles/the-basics-of-the-art-of-lighting-part-3-lighting-and-shaders/
15   -https://docs.unity3d.com/Manual/Lighting.html
1   -//
2   -// A «continued fraction» is a representation of a fraction as a vector
3   -// of integrals… Irrational fractions will result in infinite most of the
4   -// time repetitive vectors. They can be used to get a resonable approximation
5   -// for sqrt on fractionals.
6   -//
7   -// Georg Hopp <georg@steffers.org>
8   -//
9   -// Copyright © 2019 Georg Hopp
10   -//
11   -// This program is free software: you can redistribute it and/or modify
12   -// it under the terms of the GNU General Public License as published by
13   -// the Free Software Foundation, either version 3 of the License, or
14   -// (at your option) any later version.
15   -//
16   -// This program is distributed in the hope that it will be useful,
17   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
18   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19   -// GNU General Public License for more details.
20   -//
21   -// You should have received a copy of the GNU General Public License
22   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
23   -//
24   -use crate::Fractional;
25   -
26   -#[derive(Debug)]
27   -pub struct Continuous (Vec<i64>);
28   -
29   -impl Continuous {
30   - // calculate a sqrt as continued fraction sequence. Taken from:
31   - // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#
32   - // Continued_fraction_expansion
33   - pub fn sqrt(x :i64, a0 :i64) -> Self {
34   - fn inner(v :&mut [i64], x :i64, a0 :i64, mn :i64, dn :i64, an :i64) {
35   - let mn_1 = dn * an - mn;
36   - let dn_1 = (x - mn_1 * mn_1) / dn;
37   - let an_1 = (a0 + mn_1) / dn_1;
38   -
39   - v[0] = an;
40   - // The convergence criteria „an_1 == 2 * a0“ is not good for
41   - // very small x thus I decided to break the iteration at constant
42   - // time. Which is the 5 below.
43   - if v.len() > 1 {
44   - inner(&mut v[1..], x, a0, mn_1, dn_1, an_1);
45   - }
46   - }
47   -
48   - let mut v :Vec<i64> = vec!(0; 5);
49   - inner(&mut v, x, a0, 0, 1, a0);
50   - Continuous(v)
51   - }
52   -
53   - // general continous fraction form of a fractional...
54   - pub fn from_prec(f :&Fractional, prec :Option<usize>) -> Self {
55   - fn inner(v :&mut Vec<i64>, f :Fractional, prec :Option<usize>) {
56   - let mut process = |prec :Option<usize>| {
57   - let Fractional(n, d) = f;
58   - let a = n / d;
59   - let Fractional(_n, _d) = f.noreduce_sub(a.into());
60   -
61   - v.push(a);
62   - match _n {
63   - 1 => v.push(_d),
64   - 0 => {},
65   - _ => inner(v, Fractional(_d, _n), prec),
66   - }
67   - };
68   -
69   - match prec {
70   - Some(0) => {},
71   - None => process(None),
72   - Some(p) => process(Some(p - 1)),
73   - }
74   - }
75   -
76   - let mut v = match prec {
77   - None => Vec::with_capacity(100),
78   - Some(p) => Vec::with_capacity(p + 1),
79   - };
80   -
81   - inner(&mut v, *f, prec);
82   - Continuous(v)
83   - }
84   -
85   - pub fn into_prec(&self, prec :Option<usize>) -> Fractional {
86   - let Continuous(c) = self;
87   - let p = match prec {
88   - Some(p) => if p <= c.len() { p } else { c.len() },
89   - None => c.len(),
90   - };
91   -
92   - let to_frac = |acc :Fractional, x :&i64| {
93   - let Fractional(an, ad) = acc.noreduce_add((*x).into());
94   - Fractional(ad, an)
95   - };
96   -
97   - let Fractional(n, d) = c[..p]
98   - . into_iter()
99   - . rev()
100   - . fold(Fractional(0, 1), to_frac);
101   - Fractional(d, n)
102   - }
103   -}
104   -
105   -impl From<&Fractional> for Continuous {
106   - fn from(x :&Fractional) -> Self {
107   - Self::from_prec(x, None)
108   - }
109   -}
110   -
111   -impl Into<Fractional> for &Continuous {
112   - fn into(self) -> Fractional {
113   - (&self).into_prec(None)
114   - }
115   -}
1   -//
2   -// This is an abstraction over a drawing environment.
3   -// Future note: z-Buffer is described here:
4   -// https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
5   -//
6   -// Georg Hopp <georg@steffers.org>
7   -//
8   -// Copyright © 2019 Georg Hopp
9   -//
10   -// This program is free software: you can redistribute it and/or modify
11   -// it under the terms of the GNU General Public License as published by
12   -// the Free Software Foundation, either version 3 of the License, or
13   -// (at your option) any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful,
16   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
17   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18   -// GNU General Public License for more details.
19   -//
20   -// You should have received a copy of the GNU General Public License
21   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -use std::cmp;
24   -use std::fmt::{Formatter, Debug, Display, Result};
25   -use std::ops::{Add, Sub, Div};
26   -use std::sync::mpsc;
27   -
28   -pub trait Easel {
29   - //fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>;
30   -}
31   -
32   -pub trait Canvas<T> {
33   - fn init_events(&self);
34   - fn start_events(&self, tx :mpsc::Sender<i32>);
35   -
36   - fn width(&self) -> u16;
37   - fn height(&self) -> u16;
38   -
39   - fn clear(&mut self);
40   - fn draw(&mut self, c :&dyn Drawable<T>, ofs :Coordinate<T>, color :u32);
41   - fn put_text(&self, ofs :Coordinate<T>, s :&str);
42   - fn set_pixel(&mut self, c :Coordinate<T>, color :u32);
43   - fn show(&self);
44   -}
45   -
46   -pub trait Drawable<T> {
47   - fn plot(&self) -> Coordinates<T>;
48   -}
49   -
50   -pub trait Fillable<T>
51   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
52   - + Debug + Copy + From<i32> {
53   - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32);
54   -}
55   -
56   -#[derive(Debug, Clone, Copy)]
57   -pub struct Coordinate<T>(pub i32, pub i32, pub T);
58   -
59   -#[derive(Debug, Clone)]
60   -pub struct Coordinates<T>(pub Vec<Coordinate<T>>);
61   -
62   -#[derive(Debug, Clone, Copy)]
63   -pub struct LineIterator<T> where T: Debug {
64   - a :Option<Coordinate<T>>
65   - , b :Coordinate<T>
66   - , dx :i32
67   - , dy :i32
68   - , dz :T
69   - , sx :i32
70   - , sy :i32
71   - , err :i32
72   - , only_edges :bool
73   -}
74   -
75   -impl<T> Iterator for LineIterator<T>
76   -where T: Add<Output = T> + Debug + Copy + From<i32> {
77   - type Item = Coordinate<T>;
78   -
79   - fn next(&mut self) -> Option<Self::Item> {
80   - match self.a {
81   - None => None,
82   - Some(a) => {
83   - let Coordinate(ax, ay, az) = a;
84   - let Coordinate(bx, by, _) = self.b;
85   -
86   - if ax != bx || ay != by {
87   - match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) {
88   - (true, false) => {
89   - let r = self.a;
90   - self.a = Some(Coordinate( ax + self.sx
91   - , ay
92   - , az + self.dz ));
93   - self.err = self.err + self.dy;
94   - if self.only_edges { self.next() } else { r }
95   - },
96   - (false, true) => {
97   - let r = self.a;
98   - self.a = Some(Coordinate( ax
99   - , ay + self.sy
100   - , az + self.dz ));
101   - self.err = self.err + self.dx;
102   - r
103   - },
104   - _ => {
105   - let r = self.a;
106   - self.a = Some(Coordinate( ax + self.sx
107   - , ay + self.sy
108   - , az + self.dz ));
109   - self.err = self.err + self.dx + self.dy;
110   - r
111   - },
112   - }
113   - } else {
114   - self.a = None;
115   - Some(self.b)
116   - }
117   - }
118   - }
119   - }
120   -}
121   -
122   -impl<T> Coordinate<T>
123   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
124   - + Debug + Clone + Copy + From<i32> {
125   - fn iter(self, b :&Self, only_edges :bool) -> LineIterator<T> {
126   - let Coordinate(ax, ay, az) = self;
127   - let Coordinate(bx, by, bz) = *b;
128   -
129   - let dx = (bx - ax).abs();
130   - let dy = -(by - ay).abs();
131   -
132   - LineIterator { a: Some(self)
133   - , b: *b
134   - , dx: dx
135   - , dy: dy
136   - , dz: (bz - az) / cmp::max(dx, -dy).into()
137   - , sx: if ax < bx { 1 } else { -1 }
138   - , sy: if ay < by { 1 } else { -1 }
139   - , err: dx + dy
140   - , only_edges: only_edges
141   - }
142   - }
143   -
144   - fn line_iter(self, b :&Self) -> LineIterator<T> {
145   - self.iter(b, false)
146   - }
147   -
148   - fn line(self, b :&Self) -> Vec<Self> {
149   - self.line_iter(b).collect()
150   - }
151   -
152   - fn edge_iter(self, b :&Self) -> LineIterator<T> {
153   - self.iter(b, true)
154   - }
155   -
156   - fn edge(self, b :&Self) -> Vec<Self> {
157   - self.edge_iter(b).collect()
158   - }
159   -
160   - fn face(edges :&[Self]) -> Vec<Self> {
161   - edges.to_vec()
162   - }
163   -}
164   -
165   -impl<T> Display for Coordinate<T> {
166   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
167   - write!(f, "<{},{}>", self.0, self.1)
168   - }
169   -}
170   -
171   -impl<T> Display for Coordinates<T> where T: Copy {
172   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
173   - let Coordinates(is) = self;
174   -
175   - let c = match is[..] {
176   - [] => String::from(""),
177   - [a] => format!("{}", a),
178   - _ => {
179   - let mut a = format!("{}", is[0]);
180   - for i in is[1..].iter() {
181   - a = a + &format!(",{}", i);
182   - }
183   - a
184   - }
185   - };
186   -
187   - write!(f, "Coordinates[{}]", c)
188   - }
189   -}
190   -
191   -
192   -#[derive(Debug, Clone, Copy)]
193   -pub struct Point<T>(pub Coordinate<T>);
194   -
195   -impl<T> Drawable<T> for Point<T> where T: Copy {
196   - fn plot(&self) -> Coordinates<T> {
197   - let Point(c) = *self;
198   - Coordinates(vec!(c))
199   - }
200   -}
201   -
202   -impl<T> Display for Point<T> {
203   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
204   - let Point(p) = self;
205   - write!(f, "Point[{}]", p)
206   - }
207   -}
208   -
209   -#[derive(Debug, Clone, Copy)]
210   -pub struct Line<T>(pub Coordinate<T>, pub Coordinate<T>);
211   -
212   -impl<T> Drawable<T> for Line<T>
213   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
214   - + Debug + Clone + Copy + From<i32> {
215   - fn plot(&self) -> Coordinates<T> {
216   - let Line(a, b) = *self;
217   - Coordinates(a.line(&b))
218   - }
219   -}
220   -
221   -impl<T> Display for Line<T> {
222   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
223   - let Line(a, b) = self;
224   - write!(f, "Line[{},{}]", a, b)
225   - }
226   -}
227   -
228   -#[derive(Debug, Clone)]
229   -pub struct Polyline<T>(pub Coordinates<T>);
230   -
231   -impl<T> Drawable<T> for Polyline<T>
232   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
233   - + Debug + Clone + Copy + From<i32> {
234   - fn plot(&self) -> Coordinates<T> {
235   - let Polyline(Coordinates(cs)) = self;
236   -
237   - match cs[..] {
238   - [] => Coordinates(Vec::<Coordinate<T>>::new()),
239   - [a] => Coordinates(vec!(a)),
240   - [a, b] => Coordinates(a.line(&b)),
241   - _ => {
242   - let (a, b) = (cs[0], cs[1]);
243   - let mut r = a.line(&b);
244   - let mut i = b;
245   - for j in cs[2..].iter() {
246   - r.append(&mut i.line(j)[1..].to_vec());
247   - i = *j;
248   - }
249   - Coordinates(r)
250   - },
251   - }
252   - }
253   -}
254   -
255   -impl<T> Display for Polyline<T> where T: Copy {
256   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
257   - let Polyline(a) = self;
258   - write!(f, "PLine[{}]", a)
259   - }
260   -}
261   -
262   -#[derive(Debug, Clone, Copy)]
263   -enum Direction { Left, Right }
264   -
265   -#[derive(Debug, Clone)]
266   -pub struct Polygon<T>(pub Coordinates<T>);
267   -
268   -#[derive(Debug, Clone)]
269   -enum VertexIteratorMode { Vertex, Edge }
270   -#[derive(Debug, Clone)]
271   -pub struct VertexIterator<'a,T> where T: Debug {
272   - p :&'a Polygon<T>,
273   - top :usize,
274   - current :Option<usize>,
275   - edge :Option<LineIterator<T>>,
276   - mode :VertexIteratorMode,
277   - direction :Direction,
278   -}
279   -
280   -impl<'a,T> VertexIterator<'a,T>
281   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
282   - + Debug + Copy + From<i32> {
283   - fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {
284   - let top = p.vert_min(direction);
285   - let next = p.next_y(top, direction);
286   - let edge = match next {
287   - None => None,
288   - Some(next) => Some(p.vertex(top).edge_iter(&p.vertex(next))),
289   - };
290   -
291   - VertexIterator { p: p
292   - , top: top
293   - , current: next
294   - , edge: edge
295   - , mode: VertexIteratorMode::Edge
296   - , direction: direction }
297   - }
298   -
299   - fn vertex(p :&'a Polygon<T>, direction :Direction) -> Self {
300   - let top = p.vert_min(direction);
301   - let next = p.next_y(top, direction);
302   -
303   - VertexIterator { p: p
304   - , top: top
305   - , current: next
306   - , edge: None
307   - , mode: VertexIteratorMode::Vertex
308   - , direction: direction }
309   - }
310   -
311   - // if this yields "None" we are finished.
312   - fn next_edge(&mut self) -> Option<LineIterator<T>> {
313   - let current = self.current?;
314   - let next = self.p.next_y(current, self.direction)?;
315   - let mut edge = self.p.vertex(current).edge_iter(&self.p.vertex(next));
316   -
317   - match edge.next() {
318   - // It should be impossible that a new edge iterator has no values
319   - // at all… anyway, just in case I handle it here.
320   - None => self.next_edge(),
321   - Some(_) => {
322   - self.current = Some(next);
323   - self.edge = Some(edge);
324   - self.edge
325   - },
326   - }
327   - }
328   -}
329   -
330   -impl<'a,T> Iterator for VertexIterator<'a,T>
331   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
332   - + Debug + Copy + From<i32> {
333   - type Item = Coordinate<T>;
334   -
335   - fn next(&mut self) -> Option<Self::Item> {
336   - match self.mode {
337   - VertexIteratorMode::Edge => {
338   - // if for whatever reason edge is "None" finish this iterator.
339   - let next = self.edge.as_mut()?.next();
340   -
341   - match next {
342   - Some(_) => next,
343   - None => {
344   - self.next_edge()?;
345   - self.next()
346   - },
347   - }
348   - },
349   - VertexIteratorMode::Vertex => {
350   - let current = self.current?;
351   - self.current = self.p.next_y(current, self.direction);
352   - Some(self.p.vertex(current))
353   - },
354   - }
355   - }
356   -}
357   -
358   -impl<T> Polygon<T>
359   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
360   - + Copy + Debug + From<i32> {
361   - #[inline]
362   - fn vertex(&self, v :usize) -> Coordinate<T> {
363   - let Polygon(Coordinates(cs)) = self;
364   - cs[v]
365   - }
366   -
367   - fn vert_min<'a>(&'a self, d :Direction) -> usize {
368   - let Polygon(Coordinates(cs)) = self;
369   -
370   - type ICoord<'a,T> = (usize, &'a Coordinate<T>);
371   -
372   - // TODO I guess the problem here is that it does not account for the
373   - // same y vertex on the beggining and the end. So i guess correct
374   - // would be finding the first one and then dependings on the
375   - // given direction either search left or right for same y's.
376   - let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a,T>|
377   - match acc {
378   - None => Some(x),
379   - Some(a) => {
380   - let Coordinate(_, ay, _) = a.1;
381   - let Coordinate(_, xy, _) = x.1;
382   - if xy < ay {Some(x)} else {Some(a)}
383   - },
384   - };
385   -
386   - let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0;
387   - let mut next = self.step(min, d);
388   -
389   - while self.vertex(min).1 == self.vertex(next).1 {
390   - min = next;
391   - next = self.step(min, d);
392   - }
393   -
394   - min
395   - }
396   -
397   - fn left_edge(&self) -> VertexIterator<T> {
398   - VertexIterator::edge(self, Direction::Left)
399   - }
400   -
401   - fn right_edge(&self) -> VertexIterator<T> {
402   - VertexIterator::edge(self, Direction::Right)
403   - }
404   -
405   - fn left_vertices(&self) -> VertexIterator<T> {
406   - VertexIterator::vertex(self, Direction::Left)
407   - }
408   -
409   - fn right_vertices(&self) -> VertexIterator<T> {
410   - VertexIterator::vertex(self, Direction::Right)
411   - }
412   -
413   - fn left(&self, v :usize) -> usize {
414   - let Polygon(Coordinates(cs)) = self;
415   -
416   - match v {
417   - 0 => cs.len() - 1,
418   - _ => v - 1,
419   - }
420   - }
421   -
422   - fn right(&self, v :usize) -> usize {
423   - let Polygon(Coordinates(cs)) = self;
424   -
425   - (v + 1) % cs.len()
426   - }
427   -
428   - fn step(&self, v :usize, d :Direction) -> usize {
429   - match d {
430   - Direction::Left => self.left(v),
431   - Direction::Right => self.right(v),
432   - }
433   - }
434   -
435   - fn next_y(&self, c :usize, d :Direction) -> Option<usize> {
436   - fn inner<T>( p :&Polygon<T>
437   - , c :usize
438   - , n :usize
439   - , d :Direction) -> Option<usize>
440   - where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
441   - + Copy + Debug + From<i32> {
442   - if c == n {
443   - None
444   - } else {
445   - let Coordinate(_, cy, _) = p.vertex(c);
446   - let Coordinate(_, ny, _) = p.vertex(n);
447   -
448   - if ny < cy { None } else { Some(n) }
449   - }
450   - }
451   -
452   - inner(self, c, self.step(c, d), d)
453   - }
454   -
455   - pub fn debug(&self) {
456   - let mut left = self.left_vertices();
457   - let mut right = self.right_vertices();
458   -
459   - if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() {
460   - let left :Vec<Coordinate<T>> = self.left_vertices().collect();
461   - let right :Vec<Coordinate<T>> = self.right_vertices().collect();
462   -
463   - println!("===");
464   - println!("== poly : {:?}", self);
465   - println!("== ltop : {:?}", self.vert_min(Direction::Left));
466   - println!("== rtop : {:?}", self.vert_min(Direction::Right));
467   - println!("== left : {:?}", left);
468   - println!("== right : {:?}", right);
469   - println!("===");
470   - }
471   - }
472   -}
473   -
474   -impl<T> Drawable<T> for Polygon<T>
475   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
476   - + Debug + Clone + Copy + From<i32> {
477   - fn plot(&self) -> Coordinates<T> {
478   - let Polygon(Coordinates(cs)) = self;
479   -
480   - match cs[..] {
481   - [] => Coordinates(Vec::<Coordinate<T>>::new()),
482   - [a] => Coordinates(vec!(a)),
483   - [a, b] => Coordinates(a.line(&b)),
484   - _ => {
485   - let (a, b) = (cs[0], cs[1]);
486   - let mut r = a.line(&b);
487   - let mut i = b;
488   - for j in cs[2..].iter() {
489   - r.append(&mut i.line(j)[1..].to_vec());
490   - i = *j;
491   - }
492   - let mut j = a.line(&i);
493   - let l = j.len();
494   - if l > 1 {
495   - r.append(&mut j[1..l-1].to_vec());
496   - }
497   - Coordinates(r)
498   - },
499   - }
500   - }
501   -}
502   -
503   -impl<T> Fillable<T> for Polygon<T>
504   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
505   - + Debug + Clone + Copy + From<i32> {
506   - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {
507   - let scanlines = self.left_edge().zip(self.right_edge());
508   -
509   - for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) {
510   - canvas.set_pixel(l, color);
511   - }
512   - }
513   -}
514   -
515   -impl<T> Display for Polygon<T> where T: Copy {
516   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
517   - let Polygon(a) = self;
518   - write!(f, "Poly[{}]", a)
519   - }
520   -}
1   -//
2   -// Some code to support fractional numbers for full precision rational number
3   -// calculations. (At least for the standard operations.)
4   -// This also implements a sqrt on fractional numbers, which can not be precise
5   -// because of the irrational nature of most sqare roots.
6   -// Fractions can only represent rational numbers precise.
7   -//
8   -// Georg Hopp <georg@steffers.org>
9   -//
10   -// Copyright © 2019 Georg Hopp
11   -//
12   -// This program is free software: you can redistribute it and/or modify
13   -// it under the terms of the GNU General Public License as published by
14   -// the Free Software Foundation, either version 3 of the License, or
15   -// (at your option) any later version.
16   -//
17   -// This program is distributed in the hope that it will be useful,
18   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
19   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20   -// GNU General Public License for more details.
21   -//
22   -// You should have received a copy of the GNU General Public License
23   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
24   -//
25   -use std::cmp::Ordering;
26   -use std::convert::{TryFrom, TryInto};
27   -use std::fmt::{Formatter, Display};
28   -use std::num::TryFromIntError;
29   -use std::ops::{Add,Sub,Neg,Mul,Div};
30   -
31   -use crate::continuous::Continuous;
32   -
33   -#[derive(Debug, Eq, Clone, Copy)]
34   -pub struct Fractional (pub i64, pub i64);
35   -
36   -#[inline]
37   -fn hcf(x :i64, y :i64) -> i64 {
38   - match y {
39   - 0 => x,
40   - _ => hcf(y, x % y),
41   - }
42   -}
43   -
44   -pub fn from_vector(xs: &Vec<i64>) -> Vec<Fractional> {
45   - xs.iter().map(|x| Fractional(*x, 1)).collect()
46   -}
47   -
48   -impl Fractional {
49   - #[inline]
50   - pub fn gcd(self, other: Self) -> i64 {
51   - let Fractional(_, d1) = self;
52   - let Fractional(_, d2) = other;
53   - (d1 * d2) / hcf(d1, d2)
54   - }
55   -
56   - #[inline]
57   - pub fn reduce(self) -> Self {
58   - let Fractional(n, d) = self;
59   - let (_n, _d) = if n > d { (n, d) } else { (d, n) };
60   -
61   - // if the difference from _n % _d to _n is very big we are close to
62   - // a whole number and can ignore the fractional part... this reduces
63   - // the precision but ensures smaller numbers for numerator and
64   - // denominator.
65   - if _d > 1 && (_n % _d) * 10000000 < _n {
66   - if n == _n {
67   - Self(_n / _d, 1)
68   - } else {
69   - Self(1, _n / _d)
70   - }
71   - } else {
72   - // Self(n / hcf(n, d), d / hcf(n, d))
73   - // The above reduces prcisely but results in very large numerator
74   - // or denominator occasionally. The below is less precise but
75   - // keeps the numbers small… the bad point is, that it is not very
76   - // fast.
77   - let cont = Continuous::from_prec(&self, Some(5));
78   - (&cont).into()
79   - }
80   - }
81   -
82   - pub fn noreduce_add(self, other: Self) -> Self {
83   - let Fractional(n1, d1) = self;
84   - let Fractional(n2, d2) = other;
85   - let n = n1 * (self.gcd(other) / d1) + n2 * (self.gcd(other) / d2);
86   - Self(n, self.gcd(other))
87   - }
88   -
89   - pub fn noreduce_sub(self, other: Self) -> Self {
90   - self.noreduce_add(other.noreduce_neg())
91   - }
92   -
93   - pub fn noreduce_neg(self) -> Self {
94   - let Fractional(n, d) = self;
95   - Self(-n, d)
96   - }
97   -}
98   -
99   -impl From<i64> for Fractional {
100   - fn from(x: i64) -> Self {
101   - Self(x, 1)
102   - }
103   -}
104   -
105   -impl From<i32> for Fractional {
106   - fn from(x: i32) -> Self {
107   - Self(x as i64, 1)
108   - }
109   -}
110   -
111   -impl TryFrom<usize> for Fractional {
112   - type Error = &'static str;
113   -
114   - fn try_from(x: usize) -> Result<Self, Self::Error> {
115   - let v = i64::try_from(x);
116   - match v {
117   - Err(_) => Err("Conversion from usize to i32 failed"),
118   - Ok(_v) => Ok(Self(_v, 1)),
119   - }
120   - }
121   -}
122   -
123   -impl TryInto<f64> for Fractional {
124   - type Error = TryFromIntError;
125   -
126   - fn try_into(self) -> Result<f64, Self::Error> {
127   - let n :i32 = self.0.try_into()?;
128   - let d :i32 = self.1.try_into()?;
129   - Ok(f64::from(n) / f64::from(d))
130   - }
131   -}
132   -
133   -impl TryInto<(i32, i32)> for Fractional {
134   - type Error = TryFromIntError;
135   -
136   - fn try_into(self) -> Result<(i32, i32), Self::Error> {
137   - let a :i32 = (self.0 / self.1).try_into()?;
138   - let b :i32 = (self.0 % self.1).try_into()?;
139   - Ok((a, b))
140   - }
141   -}
142   -
143   -impl Display for Fractional {
144   - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
145   - write!(f, "({}/{})", self.0, self.1)
146   - }
147   -}
148   -
149   -impl PartialEq for Fractional {
150   - fn eq(&self, other: &Self) -> bool {
151   - let Fractional(n1, d1) = self;
152   - let Fractional(n2, d2) = other;
153   - n1 * (self.gcd(*other) / d1) == n2 * (self.gcd(*other) / d2)
154   - }
155   -}
156   -
157   -impl PartialOrd for Fractional {
158   - fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
159   - Some(self.cmp(other))
160   - }
161   -}
162   -
163   -impl Ord for Fractional {
164   - fn cmp(&self, other: &Self) -> Ordering {
165   - let Fractional(n1, d1) = self;
166   - let Fractional(n2, d2) = other;
167   - let x = n1 * (self.gcd(*other) / d1);
168   - let y = n2 * (self.gcd(*other) / d2);
169   - x.cmp(&y)
170   - }
171   -}
172   -
173   -impl Add for Fractional {
174   - type Output = Self;
175   -
176   - fn add(self, other: Self) -> Self {
177   - self.noreduce_add(other).reduce()
178   - }
179   -}
180   -
181   -impl Sub for Fractional {
182   - type Output = Self;
183   -
184   - fn sub(self, other: Self) -> Self {
185   - self + -other
186   - }
187   -}
188   -
189   -impl Neg for Fractional {
190   - type Output = Self;
191   -
192   - fn neg(self) -> Self {
193   - let Fractional(n, d) = self;
194   - Self(-n, d)
195   - }
196   -}
197   -
198   -impl Mul for Fractional {
199   - type Output = Self;
200   -
201   - fn mul(self, other :Self) -> Self {
202   - let Fractional(n1, d1) = self;
203   - let Fractional(n2, d2) = other;
204   - Self(n1 * n2, d1 * d2).reduce()
205   - }
206   -}
207   -
208   -impl Div for Fractional {
209   - type Output = Self;
210   -
211   - fn div(self, other: Self) -> Self {
212   - let Fractional(n, d) = other;
213   - self * Fractional(d, n)
214   - }
215   -}
216   -
217   - /* some stuff that could be tested...
218   - let x = Fractional(1, 3);
219   - let y = Fractional(1, 6);
220   -
221   - println!(
222   - "Greatest common denominator of {} and {}: {}", x, y, x.gcd(y));
223   - println!("Numerator of {}: {}", x, x.numerator());
224   - println!("Denominator of {}: {}", x, x.denominator());
225   - assert_eq!(Fractional(1, 3), Fractional(2, 6));
226   - assert_eq!(Fractional(1, 3), Fractional(1, 3));
227   - assert_eq!(y < x, true);
228   - assert_eq!(y > x, false);
229   - assert_eq!(x == y, false);
230   - assert_eq!(x == x, true);
231   - assert_eq!(x + y, Fractional(1, 2));
232   - println!("{} + {} = {}", x, y, x + y);
233   - assert_eq!(x - y, Fractional(1, 6));
234   - println!("{} - {} = {}", x, y, x - y);
235   - assert_eq!(y - x, Fractional(-1, 6));
236   - println!("{} - {} = {}", y, x, y - x);
237   - assert_eq!(-x, Fractional(-1, 3));
238   - println!("-{} = {}", x, -x);
239   - assert_eq!(x * y, Fractional(1, 18));
240   - println!("{} * {} = {}", x, y, x * y);
241   - assert_eq!(x / y, Fractional(2, 1));
242   - println!("{} / {} = {}", x, y, x / y);
243   - assert_eq!(y / x, Fractional(1, 2));
244   - println!("{} / {} = {}", y, x, y / x);
245   -
246   - println!("Fractional from 3: {}", Fractional::from(3));
247   - let z :f64 = Fractional::into(x);
248   - println!("Floating point of {}: {}", x, z);
249   - let (d, r) = Fractional::into(x);
250   - println!("(div, rest) of {}: ({}, {})", x, d, r);
251   - */
252   -
1   -//
2   -// Basic geometric things...
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -use std::convert::{From, Into};
22   -use std::ops::{Add,Sub,Neg,Mul,Div};
23   -use std::fmt::Debug;
24   -
25   -use crate::easel::{Canvas, Coordinate, Coordinates, Polygon};
26   -use crate::transform::{TMatrix, Transformable};
27   -use crate::trigonometry::Trig;
28   -use crate::vector::Vector;
29   -
30   -#[derive(Debug, Clone)]
31   -pub struct Face<T>
32   -where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
33   - corners :Vec<usize>,
34   - normal :Option<Vector<T>>,
35   -}
36   -
37   -#[derive(Debug, PartialEq, Eq, Clone, Copy)]
38   -pub struct Point<T>(pub Vector<T>, T)
39   - where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig;
40   -
41   -impl<T> Point<T>
42   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
43   - + Mul<Output = T> + Div<Output = T>
44   - + PartialEq + Trig + Copy + From<i32> {
45   - pub fn new(x :T, y :T, z :T) -> Self {
46   - Self(Vector(x, y, z), 1.into())
47   - }
48   -}
49   -
50   -impl<T> Add for Point<T>
51   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
52   - + Mul<Output = T> + Div<Output = T>
53   - + PartialEq + Trig + Copy {
54   - type Output = Self;
55   -
56   - fn add(self, other :Self) -> Self {
57   - let Point(v1, w1) = self;
58   - let Point(v2, w2) = other;
59   - Self(v1 + v2, w1 + w2)
60   - }
61   -}
62   -
63   -impl<T> Neg for Point<T>
64   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
65   - + Mul<Output = T> + Div<Output = T>
66   - + PartialEq + Trig + Copy {
67   - type Output = Self;
68   -
69   - fn neg(self) -> Self {
70   - let Point(v, w) = self;
71   - Self(-v, -w)
72   - }
73   -}
74   -
75   -impl<T> Sub for Point<T>
76   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
77   - + Mul<Output = T> + Div<Output = T>
78   - + PartialEq + Trig + Copy {
79   - type Output = Self;
80   -
81   - fn sub(self, other :Self) -> Self {
82   - self + -other
83   - }
84   -}
85   -
86   -impl<T> Mul for Point<T>
87   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
88   - + Mul<Output = T> + Div<Output = T>
89   - + PartialEq + Trig + Copy + From<i32> {
90   - type Output = Self;
91   -
92   - fn mul(self, other :Self) -> Self {
93   - let a :Vector<T> = self.into();
94   - let b :Vector<T> = other.into();
95   -
96   - Point(a * b, 1.into())
97   - }
98   -}
99   -
100   -impl<T> From<Vector<T>> for Point<T>
101   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
102   - + Mul<Output = T> + Div<Output = T>
103   - + PartialEq + Trig + Copy + From<i32> {
104   - fn from(v :Vector<T>) -> Self {
105   - Point(v, 1.into())
106   - }
107   -}
108   -
109   -impl<T> Into<Vector<T>> for Point<T>
110   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
111   - + Mul<Output = T> + Div<Output = T>
112   - + PartialEq + Trig + Copy + From<i32> {
113   - fn into(self) -> Vector<T> {
114   - let Point(v, w) = self;
115   -
116   - if w == 0.into() {
117   - v
118   - } else {
119   - v.mul(&w.recip())
120   - }
121   - }
122   -}
123   -
124   -impl<T> Transformable<T> for Point<T>
125   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
126   - + Mul<Output = T> + Div<Output = T>
127   - + PartialEq + Debug + Trig + Copy + From<i32> {
128   - fn transform(&self, m :&TMatrix<T>) -> Self {
129   - let Point(v, w) = *self;
130   - let (v, w) = m.apply(&v, w);
131   -
132   - if w == 0.into() {
133   - v.into()
134   - } else {
135   - v.mul(&w.recip()).into()
136   - }
137   - }
138   -}
139   -
140   -#[derive(Debug)]
141   -pub struct Polyeder<T>
142   -where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {
143   - points :Vec<Point<T>>,
144   - faces :Vec<Face<T>>,
145   -}
146   -
147   -pub trait Primitives<T>
148   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
149   - fn transform(&self, m :&TMatrix<T>) -> Self;
150   - fn project( &self
151   - , camera :&Camera<T>
152   - , light :&DirectLight<T>
153   - , col :u32 ) -> Vec<(Polygon<T>, u32)>;
154   -}
155   -
156   -pub struct Camera<T>
157   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
158   - width :T,
159   - height :T,
160   - distance :T,
161   - project :TMatrix<T>,
162   -}
163   -
164   -pub struct DirectLight<T>
165   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
166   - direction: Vector<T>,
167   -}
168   -
169   -impl<T> Camera<T>
170   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
171   - + Mul<Output = T> + Div<Output = T>
172   - + PartialEq + Debug + Copy + Trig + From<i32> {
173   - // This code assumes that the size of the viewport is always
174   - // equal to the size of the physical screen… e.g. window/canvas thus some
175   - // effects can't be done. See book for examples with different viewport
176   - // and screen sizes.
177   - pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {
178   - let width :T = (c.width() as i32).into();
179   - let height :T = (c.height() as i32).into();
180   - let d :T = 1.into();
181   - let fov = T::cot(angle) * width;
182   - let wh = width / 2.into();
183   - let hh = height / 2.into();
184   -
185   - Camera { width: width
186   - , height: height
187   - , distance: d
188   - , project: TMatrix::new(
189   - ( fov, 0.into(), wh, 0.into())
190   - , (0.into(), fov, hh, 0.into())
191   - , (0.into(), 0.into(), d, 1.into())
192   - , (0.into(), 0.into(), 1.into(), 0.into()) ) }
193   - }
194   -
195   - pub fn get_distance(&self) -> T {
196   - self.distance
197   - }
198   -
199   - pub fn get_projection(&self) -> TMatrix<T> {
200   - self.project
201   - }
202   -
203   - pub fn project(&self, p :Point<T>) -> Point<T> {
204   - p.transform(&self.project)
205   - }
206   -}
207   -
208   -impl<T> DirectLight<T>
209   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
210   - + Mul<Output = T> + Div<Output = T>
211   - + Debug + Copy + Trig + From<i32> {
212   - pub fn new(v :Vector<T>) -> Self {
213   - DirectLight{ direction: v }
214   - }
215   -
216   - pub fn dir(&self) -> Vector<T> {
217   - self.direction
218   - }
219   -}
220   -
221   -impl<T> Face<T>
222   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
223   - + Mul<Output = T> + Div<Output = T>
224   - + PartialEq + Debug + Copy + Trig + From<i32> {
225   - fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {
226   - let mut f = Face{ corners: corners, normal: None };
227   - f.update_normal(ps);
228   - f
229   - }
230   -
231   - fn update_normal(&mut self, ps :&[Point<T>]) {
232   - let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();
233   - let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();
234   - self.normal = Some(edge10 * edge12);
235   - }
236   -}
237   -
238   -impl<T> Polyeder<T>
239   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
240   - + Mul<Output = T> + Div<Output = T>
241   - + PartialEq + Debug + Copy + Trig + From<i32> {
242   - fn update_normals(&mut self) {
243   - for f in self.faces.iter_mut() {
244   - f.update_normal(&self.points);
245   - }
246   - }
247   -
248   - // construct via cube, see polyhedra.pdf
249   - pub fn tetrahedron(a :T) -> Polyeder<T> {
250   - let f2 :T = 2.into();
251   - let ch = a / (f2 * T::sqrt(f2).unwrap());
252   -
253   - let ps = vec!( Point::new(-ch, -ch, ch) // A
254   - , Point::new(-ch, ch, -ch) // C
255   - , Point::new( ch, -ch, -ch) // E
256   - , Point::new( ch, ch, ch) ); // G
257   -
258   - // bottom: 1, 2, 3
259   - let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom
260   - , Face::new(vec!(3, 2, 0), &ps)
261   - , Face::new(vec!(0, 1, 3), &ps)
262   - , Face::new(vec!(1, 2, 3), &ps) );
263   - //let fs = vec!( Face::new(vec!(0, 1, 2), &ps) // bottom
264   - // , Face::new(vec!(0, 2, 3), &ps)
265   - // , Face::new(vec!(3, 1, 0), &ps)
266   - // , Face::new(vec!(3, 2, 1), &ps) );
267   -
268   - Polyeder{ points: ps, faces: fs }
269   - }
270   -
271   - pub fn triangle(a :T) -> Polyeder<T> {
272   - let f0 :T = 0.into();
273   - let f3 :T = 3.into();
274   - let f6 :T = 6.into();
275   - let zi :T = T::sqrt(f3).unwrap() / f6 * a;
276   - let zc :T = T::sqrt(f3).unwrap() / f3 * a;
277   - let ah :T = a / 2.into();
278   -
279   - let ps = vec!( Point::new(-ah, f0, -zi)
280   - , Point::new( f0, f0, zc)
281   - , Point::new( ah, f0, -zi) );
282   -
283   - let fs = vec!(Face::new(vec!(0, 1, 2), &ps));
284   -
285   - Polyeder{ points: ps, faces: fs }
286   - }
287   -
288   - pub fn cube(a :T) -> Polyeder<T> {
289   - let ah :T = a / From::<i32>::from(2);
290   -
291   - let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1
292   - , Point::new(-ah, -ah, -ah) // 1 => front 2
293   - , Point::new( ah, -ah, -ah) // 2 => front 3
294   - , Point::new( ah, ah, -ah) // 3 => front 4
295   - , Point::new(-ah, ah, ah) // 4 => back 1
296   - , Point::new(-ah, -ah, ah) // 5 => back 2
297   - , Point::new( ah, -ah, ah) // 6 => back 3
298   - , Point::new( ah, ah, ah) ); // 7 => back 4
299   -
300   - let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front
301   - , Face::new(vec!(7, 6, 5, 4), &ps) // back
302   - , Face::new(vec!(1, 5, 6, 2), &ps) // top
303   - , Face::new(vec!(0, 3, 7, 4), &ps) // bottom
304   - , Face::new(vec!(0, 4, 5, 1), &ps) // left
305   - , Face::new(vec!(2, 6, 7, 3), &ps) ); // right
306   -
307   - Polyeder{ points: ps, faces: fs }
308   - }
309   -}
310   -
311   -impl<T> Primitives<T> for Polyeder<T>
312   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
313   - + Mul<Output = T> + Div<Output = T>
314   - + Debug + Copy + Trig + From<i32> + PartialOrd {
315   - // TODO Maybe this should also be an instance of Transformable…
316   - fn transform(&self, m :&TMatrix<T>) -> Self {
317   - let Polyeder{ points: ps, faces: fs } = self;
318   -
319   - let mut p = Polyeder{
320   - points: ps.iter().map(|p| p.transform(m)).collect()
321   - , faces: fs.to_vec()
322   - };
323   -
324   - // TODO alternatively we could rotate the normals too, but this cannot
325   - // done with the original matrix… the question is, what is faster.
326   - p.update_normals();
327   - p
328   - }
329   -
330   - fn project( &self
331   - , camera :&Camera<T>
332   - , light :&DirectLight<T>
333   - , color :u32 ) -> Vec<(Polygon<T>, u32)> {
334   - // Helper to create a Polygon from Coordinates…
335   - // TODO probably there needs to be a Polygon constructor for this.
336   - fn polygon<I, T>(c :I) -> Polygon<T>
337   - where I: Iterator<Item = Coordinate<T>> {
338   - Polygon(Coordinates(c.collect()))
339   - }
340   -
341   - // this one does the projection... as the projection was the last
342   - // matrix we do not need to do it here.
343   - let to_coord = |p :&usize| {
344   - let Point(v, _) = camera.project(self.points[*p]);
345   - Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())
346   - };
347   - let to_poly = |f :&Face<T>| {
348   - let pg = polygon(f.corners.iter().map(to_coord));
349   - let mut r :T = (((color >> 16) & 0xFF) as i32).into();
350   - let mut g :T = (((color >> 8) & 0xFF) as i32).into();
351   - let mut b :T = (((color ) & 0xFF) as i32).into();
352   - let lf :T = match f.normal {
353   - None => 1.into(),
354   - Some(n) => n.dot(light.dir())
355   - / (n.mag() * light.dir().mag()),
356   - };
357   -
358   - // this "if" represents a first simple backface culling
359   - // approach. We only return face that face towards us.
360   - if lf < 0.into() {
361   - r = r * -lf;
362   - g = g * -lf;
363   - b = b * -lf;
364   -
365   - let c :u32 = (r.round() as u32) << 16
366   - | (g.round() as u32) << 8
367   - | (b.round() as u32);
368   -
369   - Some((pg, c))
370   - } else {
371   - None
372   - }};
373   -
374   - self.faces.iter().filter_map(to_poly).collect()
375   - }
376   -}
1   -//
2   -// Lib for fractional calculations.
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -extern crate lazy_static;
22   -
23   -pub type Error = &'static str;
24   -
25   -pub mod continuous;
26   -pub mod easel;
27   -pub mod fractional;
28   -pub mod transform;
29   -pub mod trigonometry;
30   -pub mod vector;
31   -pub mod xcb;
32   -pub mod geometry;
33   -
34   -use fractional::Fractional;
35   -use vector::Vector;
1   -//
2   -// Test our fractional crate / module...
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -use std::convert::{TryFrom, TryInto, Into};
22   -use std::f64::consts::PI as FPI;
23   -use std::fmt::{Debug, Display};
24   -use std::marker::Send;
25   -use std::num::TryFromIntError;
26   -use std::ops::{Add,Sub,Neg,Mul,Div};
27   -use std::sync::mpsc;
28   -use std::thread;
29   -use std::time::{Duration, Instant};
30   -
31   -use fractional::continuous::Continuous;
32   -use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline
33   - , Polygon, Canvas, Fillable };
34   -use fractional::fractional::{Fractional, from_vector};
35   -use fractional::trigonometry::Trig;
36   -use fractional::vector::Vector;
37   -use fractional::transform::{TMatrix, Transformable};
38   -use fractional::xcb::XcbEasel;
39   -use fractional::geometry::{Camera, DirectLight, Polyeder, Primitives};
40   -
41   -fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> {
42   - let r = v.iter().fold(0, |acc, x| acc + x);
43   - let l = i64::try_from(v.len())?;
44   - Ok(Fractional(r, l))
45   -}
46   -
47   -fn common_fractional() {
48   - let a = vec![3, 6, 1, 9];
49   - let b = from_vector(&a);
50   - let c = mean(&a).unwrap(); // This might fail if the len of the
51   - // vector (usize) does not fit into i32.
52   - let cr :f64 = c.try_into().unwrap();
53   -
54   - println!(" [i32] : {:?}", a);
55   - println!(" [Fractional] : {:?}", b);
56   - println!(" mean of [i32] : {}" , c);
57   - println!(" as f64 : {}" , cr);
58   - println!(" again as f64 : {}" , TryInto::<f64>::try_into(c).unwrap());
59   -}
60   -
61   -fn continuous() {
62   - let d = Fractional(45, 16);
63   - let e = Fractional(16, 45);
64   -
65   - let dc :Continuous = (&d).into();
66   - let ec :Continuous = (&e).into();
67   -
68   - println!("cont frac of d : {} => {:?}", d, dc);
69   - println!("cont frac of e : {} => {:?}", e, ec);
70   - println!(" reverted dc : {:?} {}", dc, Into::<Fractional>::into(&dc));
71   - println!(" reverted ec : {:?} {}", ec, Into::<Fractional>::into(&ec));
72   -}
73   -
74   -fn sqrt() {
75   - let f = Fractional(-9, 4);
76   - let fr :f64 = f.try_into().unwrap();
77   - let sq = f.sqrt();
78   - let _sq = fr.sqrt();
79   -
80   - println!("{:>14} : {:?} / {}", format!("sqrt {}", f), sq, _sq);
81   -
82   - for f in [ Fractional(9, 4)
83   - , Fractional(45, 16)
84   - , Fractional(16, 45)
85   - , Fractional(9, 3) ].iter() {
86   - let fr :f64 = (*f).try_into().unwrap();
87   - let sq = f.sqrt().unwrap();
88   - let sqr :f64 = sq.try_into().unwrap();
89   - let _sqr = fr.sqrt();
90   -
91   - println!("{:>14} : {} {} / {}", format!("sqrt {}", f), sq, sqr, _sqr);
92   - }
93   -}
94   -
95   -fn pi() {
96   - let pi = Fractional::pi();
97   - let pir :f64 = pi.try_into().unwrap();
98   - let pit :(i32, i32) = pi.try_into().unwrap();
99   - let pi2r :f64 = (pi * pi).try_into().unwrap();
100   -
101   - println!(" Rust π : {}" , FPI);
102   - println!(" π : {} {}" , pi, pir);
103   - println!(" π as tuple : {:?}" , pit);
104   - println!(" Rust π² : {}" , FPI * FPI);
105   - println!(" π² : {} {}" , pi * pi, pi2r);
106   -}
107   -
108   -fn _sin() {
109   - for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
110   - , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
111   - let s = Fractional::sin(*d as i32);
112   - let sr :f64 = s.try_into().unwrap();
113   - let _s = f64::sin(*d as f64 * FPI / 180.0);
114   -
115   - println!("{:>14} : {} {} / {}", format!("sin {}", d), s, sr, _s);
116   - }
117   -}
118   -
119   -fn _tan() {
120   - for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
121   - , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
122   - let t = Fractional::tan(*d as i32);
123   - let tr :f64 = t.try_into().unwrap();
124   - let _t = f64::tan(*d as f64 * FPI / 180.0);
125   -
126   - println!("{:>14} : {} {} / {}", format!("tan {}", d), t, tr, _t);
127   - }
128   -}
129   -
130   -fn _cos() {
131   - for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
132   - , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
133   - let c = Fractional::cos(*d as i32);
134   - let cr :f64 = c.try_into().unwrap();
135   - let _c = f64::cos(*d as f64 * FPI / 180.0);
136   -
137   - println!("{:>14} : {} {} / {}", format!("cos {}", d), c, cr, _c);
138   - }
139   -}
140   -
141   -fn _vector1() {
142   - let v1 = Vector(1.into(), 2.into(), 3.into());
143   - let v2 = Vector(2.into(), 2.into(), 3.into());
144   - let s :Fractional = 3.into();
145   -
146   - _vector(v1, v2, s);
147   -}
148   -
149   -fn _vector2() {
150   - let v1 = Vector(1.0, 2.0, 3.0);
151   - let v2 = Vector(2.0, 2.0, 3.0);
152   - let s = 3.0;
153   -
154   - _vector(v1, v2, s);
155   -}
156   -
157   -fn _vector<T>(v1 :Vector<T>, v2 :Vector<T>, s :T)
158   - where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
159   - + Mul<Output = T> + Div<Output = T> + Trig + Copy + Display {
160   - println!("{:>14} : {}", "Vector v1", v1);
161   - println!("{:>14} : {}", "Vector v2", v2);
162   - println!("{:>14} : {}", "magnitude v1", v1.mag());
163   - println!("{:>14} : {}", "-v1", -v1);
164   - println!("{:>14} : {}", "v1 + v1", v1 + v1);
165   - println!("{:>14} : {}", "v1 - v1", v1 - v1);
166   - println!("{:>14} : {}", "v2 - v1", v2 - v1);
167   - println!("{:>14} : {}", format!("v1 * {}", s), v1.mul(&s));
168   - println!("{:>14} : {}", "norm v1", v1.norm());
169   - println!("{:>14} : {}", "magnitude norm v1", v1.norm().mag());
170   - println!("{:>14} : {}", "magnitude v1", v1.mag());
171   - println!("{:>14} : {}", "norm * magnitude", v1.norm().mul(&v1.mag()));
172   - println!("{:>14} : {}", "distance v1 v2", v1.distance(v2));
173   - println!("{:>14} : {}", "distance v2 v1", v2.distance(v1));
174   - println!("{:>14} : {}", "v1 dot v2", v1.dot(v2));
175   - println!("{:>14} : {}", "v2 dot v1", v2.dot(v1));
176   - println!("{:>14} : {}", "v1 * v2", v1 * v2);
177   - println!("{:>14} : {}", "v2 * v1", v2 * v1);
178   -}
179   -
180   -fn _transform1() {
181   - let v = Vector(Fractional(1,1), Fractional(1,1), Fractional(1,1));
182   - let v1 = Vector(Fractional(1,1), Fractional(2,1), Fractional(3,1));
183   - let v2 = Vector(Fractional(1,1), Fractional(1,1), Fractional(0,1));
184   - let v3 = Vector(Fractional(1,1), Fractional(0,1), Fractional(1,1));
185   -
186   - _transform(v, v1, v2, v3);
187   -}
188   -
189   -fn _transform2() {
190   - let v = Vector(1.0, 1.0, 1.0);
191   - let v1 = Vector(1.0, 2.0, 3.0);
192   - let v2 = Vector(1.0, 1.0, 0.0);
193   - let v3 = Vector(1.0, 0.0, 1.0);
194   -
195   - _transform(v, v1, v2, v3);
196   -}
197   -
198   -fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
199   - where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
200   - + Mul<Output = T> + Div<Output = T> + Trig
201   - + Debug + From<i32> + Copy + Display {
202   -
203   - println!("{:>14} : {}", "Vector v1", v1);
204   - println!( "{:>14} : {}", "translate v1"
205   - , v.transform(&TMatrix::translate(v)));
206   - println!();
207   -
208   - fn _rot<T>( o :&str , n :&str , v :&Vector<T>
209   - , fs :&[&dyn Fn(i32) -> TMatrix<T>] )
210   - where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
211   - + Mul<Output = T> + Div<Output = T> + Trig
212   - + Debug + From<i32> + Copy + Display {
213   -
214   - for d in [ 30, 45, 60, 90, 120, 135, 150, 180
215   - , 210, 225, 240, 270, 300, 315, 330 ].iter() {
216   - let mi = fs.iter().map(|f| f(*d as i32));
217   - println!( "{:>14} : {}"
218   - , format!("{} {} {}", o, d, n)
219   - , v.transform(&TMatrix::combine(mi)) );
220   - }
221   - }
222   -
223   - println!("{:>14} : {}", "Vector v2", v2);
224   - _rot("rot_x", "v2", &v2, &[&TMatrix::rotate_x]);
225   - println!();
226   - _rot("rot_y", "v2", &v2, &[&TMatrix::rotate_y]);
227   - println!();
228   - _rot("rot_xy", "v2", &v2, &[&TMatrix::rotate_x, &TMatrix::rotate_y]);
229   - println!();
230   - println!("{:>14} : {}", "Vector v3", v3);
231   - _rot("rot_z", "v3", &v3, &[&TMatrix::rotate_z]);
232   - println!();
233   -
234   - for d in [ 30, 45, 60, 90, 120, 135, 150, 180
235   - , 210, 225, 240, 270, 300, 315, 330 ].iter() {
236   - println!( "{:>14} : {}"
237   - , format!("rot_v {} v2", d)
238   - , v2.transform(&TMatrix::rotate_v(&v, *d as i32)) );
239   - }
240   -}
241   -
242   -fn _line() {
243   - let a = (Coordinate(0, 1, 0.0), Coordinate(6, 4, 0.0));
244   - let b = (Coordinate(0, 4, 0.0), Coordinate(6, 1, 0.0));
245   - let c = (Coordinate(1, 0, 0.0), Coordinate(6, 8, 0.0));
246   - let d = (Coordinate(1, 8, 0.0), Coordinate(6, 0, 0.0));
247   -
248   - for i in [a, b, c, d].iter() {
249   - println!("{:>14} : {}", Line(i.0, i.1), Line(i.0, i.1).plot());
250   - println!("{:>14} : {}", Line(i.1, i.0), Line(i.1, i.0).plot());
251   - }
252   -
253   - println!();
254   - let pl = Polyline(
255   - Coordinates(vec!(a.0, a.1, b.0, b.1, c.0, c.1, d.0, d.1)));
256   - println!("{:>14} : {}", pl, pl.plot());
257   -
258   - println!();
259   - let pg = Polygon(
260   - Coordinates(vec!( Coordinate( 0, -10, 0.0)
261   - , Coordinate( 10, 10, 0.0)
262   - , Coordinate(-10, 10, 0.0) )));
263   - println!("{:>14} : {}", pg, pg.plot());
264   -
265   - let i = Vector(Fractional( 0,1), Fractional(-30,1), Fractional(0,1));
266   - let j = Vector(Fractional( 30,1), Fractional( 30,1), Fractional(0,1));
267   - let k = Vector(Fractional(-30,1), Fractional( 30,1), Fractional(0,1));
268   -
269   - let rot :TMatrix<Fractional> = TMatrix::rotate_z(20);
270   - let Vector(ix, iy, _) = i.transform(&rot);
271   - let Vector(jx, jy, _) = j.transform(&rot);
272   - let Vector(kx, ky, _) = k.transform(&rot);
273   -
274   - fn to_i32(x :Fractional) -> i32 {
275   - let Fractional(n, d) = x;
276   - (n / d + if (n % d).abs() < (n / 2).abs() { 0 } else { 1 }) as i32
277   - }
278   -
279   - println!();
280   - let pg = Polygon(
281   - Coordinates(vec!( Coordinate(to_i32(ix) + 100, to_i32(iy) + 100, 0.0)
282   - , Coordinate(to_i32(jx) + 100, to_i32(jy) + 100, 0.0)
283   - , Coordinate(to_i32(kx) + 100, to_i32(ky) + 100, 0.0) )));
284   - println!("{:>14} : {}", pg, pg.plot());
285   -
286   - let i = Vector( 0.0, -30.0, 0.0);
287   - let j = Vector( 30.0, 30.0, 0.0);
288   - let k = Vector(-30.0, 30.0, 0.0);
289   -
290   - let rot :TMatrix<f64> = TMatrix::rotate_z(20);
291   - let Vector(ix, iy, _) = i.transform(&rot);
292   - let Vector(jx, jy, _) = j.transform(&rot);
293   - let Vector(kx, ky, _) = k.transform(&rot);
294   -
295   - fn to_i32_2(x :f64) -> i32 {
296   - x.round() as i32
297   - }
298   -
299   - println!();
300   - let pg = Polygon(
301   - Coordinates(vec!( Coordinate(to_i32_2(ix) + 100, to_i32_2(iy) + 100, 0.0)
302   - , Coordinate(to_i32_2(jx) + 100, to_i32_2(jy) + 100, 0.0)
303   - , Coordinate(to_i32_2(kx) + 100, to_i32_2(ky) + 100, 0.0) )));
304   - println!("{:>14} : {}", pg, pg.plot());
305   -}
306   -
307   -fn _democanvas<T>( xcb :&XcbEasel
308   - , title :&'static str
309   - , tx :mpsc::Sender<i32>
310   - , _triangle :Polyeder<T>
311   - , tetrahedron :Polyeder<T>
312   - , cube :Polyeder<T>
313   - , light :DirectLight<T> )
314   - where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T>
315   - + Mul<Output = T> + Div<Output = T>
316   - + Debug + Copy + Trig + Send + From<i32> + PartialOrd {
317   -
318   - let mut canvas = xcb.canvas(151, 151).unwrap();
319   - let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle
320   - // was 50.
321   -
322   - canvas.set_title(title);
323   - canvas.init_events();
324   - canvas.start_events(tx.clone());
325   -
326   - thread::spawn(move || {
327   - let start = Instant::now();
328   - let step = Duration::from_millis(25);
329   - let mut last = Instant::now();
330   -
331   - let t = TMatrix::translate(Vector(0.into() , 0.into() , 150.into()));
332   -
333   - loop {
334   - let deg = ((start.elapsed() / 25).as_millis() % 360) as i32;
335   -
336   - let rz = TMatrix::rotate_z(deg);
337   - let rx = TMatrix::rotate_x(-deg*2);
338   - let ry = TMatrix::rotate_y(-deg*2);
339   -
340   - let rot1 = TMatrix::combine(vec!(rz, rx, t));
341   - let rot2 = TMatrix::combine(vec!(rz, ry, t));
342   -
343   - let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00)
344   - , ( cube.transform(&rot2), 0x0000FF) );
345   - //let objects = vec!( ( cube.transform(&rot2), 0x0000FF) );
346   - //let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) );
347   - //let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) );
348   -
349   - canvas.clear();
350   -
351   - for (o, color) in objects {
352   - for (pg, c) in o.project(&camera, &light, color) {
353   - //canvas.draw(&pg, Coordinate(0, 0, 0.into()), c);
354   - (&pg).fill(&mut canvas, c);
355   - //(&pg).debug();
356   - //println!("\n");
357   - }
358   - }
359   -
360   - let passed = Instant::now() - last;
361   - let f = (passed.as_nanos() / step.as_nanos()) as u32;
362   -
363   - if f > 1 {
364   - println!("{} !!! Detected frame drop", title);
365   - }
366   -
367   - last = last + step*(f + 1);
368   - canvas.put_text( Coordinate(10, 15, 0.into())
369   - , &format!( "sleep: {:?}"
370   - , last - Instant::now() ));
371   - canvas.show();
372   - thread::sleep(last - Instant::now());
373   - }
374   - });
375   -}
376   -
377   -fn main() {
378   - common_fractional();
379   - println!();
380   - continuous();
381   - println!();
382   - sqrt();
383   - println!();
384   - pi();
385   - println!();
386   - _sin();
387   - println!();
388   - _cos();
389   - println!();
390   - _tan();
391   - println!();
392   - _vector1();
393   - println!();
394   - _vector2();
395   - println!();
396   - _transform1();
397   - println!();
398   - _transform2();
399   - println!();
400   - _line();
401   -
402   - let xcb = XcbEasel::new().unwrap();
403   - let (tx, rx) = mpsc::channel();
404   -
405   -
406   - _democanvas( &xcb, "Something...(f64)", tx.clone()
407   - , Polyeder::triangle(60.0)
408   - , Polyeder::tetrahedron(100.0)
409   - , Polyeder::cube(56.25)
410   - , DirectLight::new(Vector(0.0, 0.0, 1.0)) );
411   - /*
412   - _democanvas( &xcb, "Something...(Fractional)", tx.clone()
413   - , Polyeder::triangle(Fractional(60,1))
414   - , Polyeder::tetrahedron(Fractional(80,1))
415   - , Polyeder::cube(Fractional(55,1))
416   - , DirectLight::new(Vector( Fractional(0,1)
417   - , Fractional(0,1)
418   - , Fractional(1,1) )) );
419   - */
420   -
421   - for x in rx {
422   - match x {
423   - 1 => break,
424   - _ => {},
425   - }
426   - }
427   -}
1   -//
2   -// Transformation of vectors in a given coordinate system...
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -use std::ops::{Add, Sub, Neg, Mul, Div};
22   -use std::fmt::Debug;
23   -
24   -use crate::Vector;
25   -use crate::trigonometry::Trig;
26   -
27   -#[derive(Debug, Clone, Copy)]
28   -pub struct TMatrix<T>( (T, T, T, T)
29   - , (T, T, T, T)
30   - , (T, T, T, T)
31   - , (T, T, T, T) )
32   - where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy;
33   -
34   -pub trait Transformable<T>
35   -where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy {
36   - fn transform(&self, m :&TMatrix<T>) -> Self;
37   -}
38   -
39   -impl<T> TMatrix<T>
40   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
41   - + Mul<Output = T> + Div<Output = T>
42   - + Debug + Trig + From<i32> + Copy {
43   - pub fn new( r1 :(T, T, T, T)
44   - , r2 :(T, T, T, T)
45   - , r3 :(T, T, T, T)
46   - , r4 :(T, T, T, T) ) -> Self {
47   - TMatrix(r1, r2, r3, r4)
48   - }
49   -
50   - pub fn unit() -> Self {
51   - Self::new( (1.into(), 0.into(), 0.into(), 0.into())
52   - , (0.into(), 1.into(), 0.into(), 0.into())
53   - , (0.into(), 0.into(), 1.into(), 0.into())
54   - , (0.into(), 0.into(), 0.into(), 1.into()) )
55   - }
56   -
57   - pub fn translate(v :Vector<T>) -> Self {
58   - let Vector(x, y, z) = v;
59   -
60   - Self::new( (1.into(), 0.into(), 0.into(), x)
61   - , (0.into(), 1.into(), 0.into(), y)
62   - , (0.into(), 0.into(), 1.into(), z)
63   - , (0.into(), 0.into(), 0.into(), 1.into()) )
64   - }
65   -
66   - pub fn rotate_x(a :i32) -> Self {
67   - let sin :T = Trig::sin(a);
68   - let cos :T = Trig::cos(a);
69   -
70   - Self::new( (1.into(), 0.into(), 0.into(), 0.into())
71   - , (0.into(), cos , -sin , 0.into())
72   - , (0.into(), sin , cos , 0.into())
73   - , (0.into(), 0.into(), 0.into(), 1.into()) )
74   - }
75   -
76   - pub fn rotate_y(a :i32) -> Self {
77   - let sin :T = Trig::sin(a);
78   - let cos :T = Trig::cos(a);
79   -
80   - Self::new( (cos , 0.into(), sin , 0.into())
81   - , (0.into(), 1.into(), 0.into(), 0.into())
82   - , (-sin , 0.into(), cos , 0.into())
83   - , (0.into(), 0.into(), 0.into(), 1.into()) )
84   - }
85   -
86   - pub fn rotate_z(a :i32) -> Self {
87   - let sin :T = Trig::sin(a);
88   - let cos :T = Trig::cos(a);
89   -
90   - Self::new( (cos , -sin , 0.into(), 0.into())
91   - , (sin , cos , 0.into(), 0.into())
92   - , (0.into(), 0.into(), 1.into(), 0.into())
93   - , (0.into(), 0.into(), 0.into(), 1.into()) )
94   - }
95   -
96   - pub fn rotate_v(v :&Vector<T>, a :i32) -> Self {
97   - let Vector(x, y, z) = *v;
98   -
99   - let sin :T = Trig::sin(a);
100   - let cos :T = Trig::cos(a);
101   -
102   - let zero :T = 0.into();
103   - let one :T = 1.into();
104   -
105   - Self::new( ( (one - cos) * x * x + cos
106   - , (one - cos) * x * y - sin * z
107   - , (one - cos) * x * z + sin * y
108   - , zero )
109   - , ( (one - cos) * x * y + sin * z
110   - , (one - cos) * y * y + cos
111   - , (one - cos) * y * z - sin * x
112   - , zero )
113   - , ( (one - cos) * x * z - sin * y
114   - , (one - cos) * y * z + sin * x
115   - , (one - cos) * z * z + cos
116   - , zero )
117   - , (0.into(), 0.into(), 0.into(), 1.into()) )
118   - }
119   -
120   - pub fn scale(v :Vector<T>) -> Self {
121   - let Vector(x, y, z) = v;
122   -
123   - Self::new( ( x, 0.into(), 0.into(), 0.into())
124   - , (0.into(), y, 0.into(), 0.into())
125   - , (0.into(), 0.into(), z, 0.into())
126   - , (0.into(), 0.into(), 0.into(), 1.into()) )
127   - }
128   -
129   - pub fn combine<I>(mi :I) -> TMatrix<T>
130   - where I: IntoIterator<Item = TMatrix<T>> {
131   -
132   - mi.into_iter().fold(Self::unit(), |acc, x| x * acc)
133   - }
134   -
135   - pub fn apply(&self, v :&Vector<T>, w :T) -> (Vector<T>, T) {
136   - let TMatrix( (a11, a12, a13, a14)
137   - , (a21, a22, a23, a24)
138   - , (a31, a32, a33, a34)
139   - , (a41, a42, a43, a44) ) = *self;
140   - let Vector(x, y, z) = *v;
141   -
142   - let v = Vector( a11 * x + a12 * y + a13 * z + a14 * w
143   - , a21 * x + a22 * y + a23 * z + a24 * w
144   - , a31 * x + a32 * y + a33 * z + a34 * w );
145   - let w = a41 * x + a42 * y + a43 * z + a44 * w;
146   -
147   - //v.mul(&w.recip())
148   - (v, w)
149   - }
150   -}
151   -
152   -impl<T> Mul for TMatrix<T>
153   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
154   - + Mul<Output = T> + Div<Output = T>
155   - + Debug + Trig + From<i32> + Copy {
156   - type Output = Self;
157   -
158   - // ATTENTION: This is not commutative, nor assoziative.
159   - fn mul(self, other :Self) -> Self {
160   - let TMatrix( (a11, a12, a13, a14)
161   - , (a21, a22, a23, a24)
162   - , (a31, a32, a33, a34)
163   - , (a41, a42, a43, a44) ) = self;
164   - let TMatrix( (b11, b12, b13, b14)
165   - , (b21, b22, b23, b24)
166   - , (b31, b32, b33, b34)
167   - , (b41, b42, b43, b44) ) = other;
168   -
169   - TMatrix( ( a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41
170   - , a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42
171   - , a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43
172   - , a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44 )
173   - , ( a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41
174   - , a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42
175   - , a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43
176   - , a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44 )
177   - , ( a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41
178   - , a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42
179   - , a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43
180   - , a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44 )
181   - , ( a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41
182   - , a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42
183   - , a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43
184   - , a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44 ) )
185   - }
186   -}
1   -//
2   -// Some trigonometic functions with Fractions results.
3   -// Currently only sin, cos and tan are implemented.
4   -// As I was unable to find a really good integral approximation for them I
5   -// implement them as a table which is predefined using the floating point
6   -// function f64::sin and then transformed into a fraction of a given
7   -// PRECISION.
8   -// These approximations are quite good and for a few edge cases
9   -// even better than the floating point implementations.
10   -//
11   -// Georg Hopp <georg@steffers.org>
12   -//
13   -// Copyright © 2019 Georg Hopp
14   -//
15   -// This program is free software: you can redistribute it and/or modify
16   -// it under the terms of the GNU General Public License as published by
17   -// the Free Software Foundation, either version 3 of the License, or
18   -// (at your option) any later version.
19   -//
20   -// This program is distributed in the hope that it will be useful,
21   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
22   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23   -// GNU General Public License for more details.
24   -//
25   -// You should have received a copy of the GNU General Public License
26   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
27   -//
28   -use std::cmp::Ordering;
29   -use std::ops::Div;
30   -use std::ops::Neg;
31   -use std::marker::Sized;
32   -use crate::{Fractional, Error};
33   -use crate::continuous::Continuous;
34   -
35   -pub trait Trig {
36   - fn pi() -> Self;
37   - fn recip(self) -> Self;
38   - fn round(&self) -> i32;
39   - fn sqrt(self) -> Result<Self, Error> where Self: Sized;
40   - fn sintab() -> Vec<Self> where Self: Sized;
41   - fn tantab() -> Vec<Self> where Self: Sized;
42   -
43   - fn sin(d :i32) -> Self
44   - where Self: Sized + Neg<Output = Self> + Copy {
45   - match d {
46   - 0 ..=90 => Self::sintab()[d as usize],
47   - 91 ..=180 => Self::sintab()[180 - d as usize],
48   - 181..=270 => -Self::sintab()[d as usize - 180],
49   - 271..=359 => -Self::sintab()[360 - d as usize],
50   - _ => {
51   - Self::sin(if d < 0 { d % 360 + 360 } else { d % 360 })
52   - },
53   - }
54   - }
55   -
56   - fn cos(d :i32) -> Self
57   - where Self: Sized + Neg<Output = Self> + Copy {
58   - match d {
59   - 0 ..=90 => Self::sintab()[90 - d as usize],
60   - 91 ..=180 => -Self::sintab()[90 - (180 - d as usize)],
61   - 181..=270 => -Self::sintab()[90 - (d as usize - 180)],
62   - 271..=359 => Self::sintab()[90 - (360 - d as usize)],
63   - _ => {
64   - Self::cos(if d < 0 { d % 360 + 360 } else { d % 360 })
65   - },
66   - }
67   - }
68   -
69   - fn tan(d :i32) -> Self where Self: Sized + Copy {
70   - match d {
71   - 0 ..=179 => Self::tantab()[d as usize],
72   - 180..=359 => Self::tantab()[d as usize - 180],
73   - _ => {
74   - Self::tan(if d < 0 { d % 360 + 360 } else { d % 360 })
75   - },
76   - }
77   - }
78   -
79   - fn cot(d :i32) -> Self
80   - where Self: Sized + Copy + From<i32> + Div<Output = Self> {
81   - Into::<Self>::into(1) / Self::tan(d)
82   - }
83   -}
84   -
85   -// Try to keep precision as high as possible while having a denominator
86   -// as small as possible. The values are taken by try and error.
87   -const PRECISION :i64 = 1000000;
88   -const MAX_DENOMINATOR :i64 = 7000;
89   -
90   -// This is a really close fractional approximation for pi.
91   -impl Trig for Fractional {
92   - fn pi() -> Self {
93   - Fractional(355, 113)
94   - }
95   -
96   - fn recip(self) -> Self {
97   - let Fractional(n, d) = self;
98   - Fractional(d, n)
99   - }
100   -
101   - fn round(&self) -> i32 {
102   - let Fractional(n, d) = self;
103   - (n / d) as i32
104   - }
105   -
106   - // This is a really bad approximation of sqrt for a fractional...
107   - // for (9/3) it will result 3 which if way to far from the truth,
108   - // which is ~1.7320508075
109   - // BUT we can use this value as starting guess for creating a
110   - // continous fraction for the sqrt... and create a much better
111   - // fractional representation of the sqrt.
112   - // So, if inner converges, but is not a perfect square (does not
113   - // end up in an Ordering::Equal - which is the l > h case)
114   - // we use the l - 1 as starting guess for sqrt_cfrac.
115   - // taken from:
116   - // https://www.geeksforgeeks.org/square-root-of-an-integer/
117   - fn sqrt(self) -> Result<Self, Error> {
118   - // find the sqrt of x in O(log x/2).
119   - // This stops if a perfect sqare was found. Else it passes
120   - // the found value as starting guess to the continous fraction
121   - // sqrt function.
122   - fn floor_sqrt(x :i64) -> Fractional {
123   - fn inner(l :i64, h :i64, x :i64) -> Fractional {
124   - if l > h {
125   - (&Continuous::sqrt(x, l - 1)).into()
126   - } else {
127   - let m = (l + h) / 2;
128   - match x.cmp(&(m * m)) {
129   - Ordering::Equal => m.into(),
130   - Ordering::Less => inner(l, m - 1, x),
131   - Ordering::Greater => inner(m + 1, h, x),
132   - }
133   - }
134   - }
135   -
136   - match x {
137   - 0 => 0.into(),
138   - 1 => 1.into(),
139   - _ => inner(1, x / 2, x),
140   - }
141   - }
142   -
143   - let Fractional(n, d) = self;
144   -
145   - let n = match n.cmp(&0) {
146   - Ordering::Equal => 0.into(),
147   - Ordering::Less => return Err("sqrt on negative undefined"),
148   - Ordering::Greater => floor_sqrt(n),
149   - };
150   -
151   - let d = match d.cmp(&0) {
152   - Ordering::Equal => 0.into(),
153   - Ordering::Less => return Err("sqrt on negative undefined"),
154   - Ordering::Greater => floor_sqrt(d),
155   - };
156   -
157   - Ok(n / d)
158   - }
159   -
160   - fn sintab() -> Vec<Self> {
161   - // hold sin Fractionals from 0 to 89 ...
162   - // luckily with a bit of index tweeking this can also be used for
163   - // cosine values.
164   - lazy_static::lazy_static! {
165   - static ref SINTAB :Vec<Fractional> =
166   - (0..=90).map(|x| _sin(x)).collect();
167   - }
168   -
169   - // fractional sin from f64 sin. (From 0° to 90°)
170   - fn _sin(d: u32) -> Fractional {
171   - match d {
172   - 0 => Fractional(0, 1),
173   - 90 => Fractional(1, 1),
174   - _ => generate(d, PRECISION, &f64::sin),
175   - }
176   - }
177   -
178   - SINTAB.to_vec()
179   - }
180   -
181   - fn tantab() -> Vec<Self> {
182   - // This table exists only because the sin(α) / cos(α) method
183   - // yields very large unreducable denominators in a lot of cases.
184   - lazy_static::lazy_static! {
185   - static ref TANTAB :Vec<Fractional> =
186   - (0..180).map(|x| _tan(x)).collect();
187   - }
188   -
189   - // fractional tan from f64 tan. (From 0° to 179°)
190   - fn _tan(d: u32) -> Fractional {
191   - match d {
192   - 0 => Fractional(0, 1),
193   - 45 => Fractional(1, 1),
194   - 90 => Fractional(1, 0), // although they are both inf and -inf.
195   - 135 => -Fractional(1, 1),
196   - _ => generate(d, PRECISION, &f64::tan),
197   - }
198   - }
199   -
200   - TANTAB.to_vec()
201   - }
202   -}
203   -
204   -// search for a fraction with a denominator less than MAX_DENOMINATOR that
205   -// provides the minimal PRECISION criteria.
206   -// !! With f = &f64::tan and d close to the inf boundarys of tan
207   -// we get very large numerators because the numerator becomes a
208   -// multiple of the denominator.
209   -fn generate(d :u32, p :i64, f :&dyn Fn(f64) -> f64) -> Fractional {
210   - // This is undefined behaviour for very large f64, but our f64
211   - // is always between 0.0 and 1000000.0 which should be fine.
212   - let s = (f((d as f64).to_radians()) * p as f64).round() as i64;
213   - let Fractional(n, dn) = Fractional(s, p).reduce();
214   - match dn.abs().cmp(&MAX_DENOMINATOR) {
215   - Ordering::Less => Fractional(n, dn),
216   - _ => generate(d, p + 1, f),
217   - }
218   -}
219   -
220   -impl Trig for f64 {
221   - fn pi() -> Self {
222   - std::f64::consts::PI
223   - }
224   -
225   - fn recip(self) -> Self {
226   - self.recip()
227   - }
228   -
229   - fn round(&self) -> i32 {
230   - f64::round(*self) as i32
231   - }
232   -
233   - fn sqrt(self) -> Result<Self, Error> {
234   - let x = self.sqrt();
235   - match x.is_nan() {
236   - true => Err("sqrt on negative undefined"),
237   - false => Ok(x),
238   - }
239   - }
240   -
241   - fn sintab() -> Vec<Self> {
242   - lazy_static::lazy_static! {
243   - static ref SINTAB :Vec<f64> =
244   - (0..=90).map(|x| _sin(x)).collect();
245   - }
246   -
247   - // f64 sin. (From 0° to 90°)
248   - fn _sin(d: u32) -> f64 {
249   - match d {
250   - 0 => 0.0,
251   - 90 => 1.0,
252   - _ => (d as f64).to_radians().sin(),
253   - }
254   - }
255   -
256   - SINTAB.to_vec()
257   - }
258   -
259   - fn tantab() -> Vec<Self> {
260   - // This table exists only because the sin(α) / cos(α) method
261   - // yields very large unreducable denominators in a lot of cases.
262   - lazy_static::lazy_static! {
263   - static ref TANTAB :Vec<f64> =
264   - (0..180).map(|x| _tan(x)).collect();
265   - }
266   -
267   - // fractional tan from f64 tan. (From 0° to 179°)
268   - fn _tan(d: u32) -> f64 {
269   - match d {
270   - 0 => 0.0,
271   - 45 => 1.0,
272   - 90 => std::f64::INFINITY,
273   - 135 => -1.0,
274   - _ => (d as f64).to_radians().tan(),
275   - }
276   - }
277   -
278   - TANTAB.to_vec()
279   - }
280   -}
1   -//
2   -// Stuff for manipulating 3 dimensional vectors.
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -use std::fmt::{Debug, Display, Formatter, Result};
22   -use std::ops::{Add, Sub, Neg, Mul, Div};
23   -
24   -use crate::trigonometry::Trig;
25   -use crate::transform::{TMatrix, Transformable};
26   -
27   -#[derive(Debug, Eq, Clone, Copy)]
28   -pub struct Vector<T>(pub T, pub T, pub T)
29   - where T: Add + Sub + Neg + Mul + Div + Trig + Copy;
30   -
31   -impl<T> Vector<T>
32   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
33   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
34   - pub fn x(self) -> T { self.0 }
35   - pub fn y(self) -> T { self.1 }
36   - pub fn z(self) -> T { self.2 }
37   -
38   - pub fn mag(self) -> T {
39   - let Vector(x, y, z) = self;
40   - (x * x + y * y + z * z).sqrt().unwrap()
41   - }
42   -
43   - pub fn mul(self, s :&T) -> Self {
44   - let Vector(x, y, z) = self;
45   - Vector(x * *s, y * *s, z * *s)
46   - }
47   -
48   - pub fn dot(self, other :Self) -> T {
49   - let Vector(x1, y1, z1) = self;
50   - let Vector(x2, y2, z2) = other;
51   -
52   - x1 * x2 + y1 * y2 + z1 * z2
53   - }
54   -
55   - pub fn norm(self) -> Self {
56   - // TODO This can result in 0 or inf Vectors…
57   - // Maybe we need to handle zero and inf magnitude here…
58   - self.mul(&self.mag().recip())
59   - }
60   -
61   - pub fn distance(self, other :Self) -> T {
62   - (self - other).mag()
63   - }
64   -}
65   -
66   -impl<T> Display for Vector<T>
67   -where T: Add + Sub + Neg + Mul + Div + Trig + Display + Copy {
68   - fn fmt(&self, f :&mut Formatter<'_>) -> Result {
69   - let Vector(x, y, z) = self;
70   - write!(f, "({}, {}, {})", x, y, z)
71   - }
72   -}
73   -
74   -impl<T> PartialEq for Vector<T>
75   -where T: Add + Sub + Neg + Mul + Div + Trig + PartialEq + Copy {
76   - fn eq(&self, other :&Self) -> bool {
77   - let Vector(x1, y1, z1) = self;
78   - let Vector(x2, y2, z2) = other;
79   - x1 == x2 && y1 == y2 && z1 == z2
80   - }
81   -}
82   -
83   -impl<T> Add for Vector<T>
84   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
85   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
86   - type Output = Self;
87   -
88   - fn add(self, other :Self) -> Self {
89   - let Vector(x1, y1, z1) = self;
90   - let Vector(x2, y2, z2) = other;
91   - Vector(x1 + x2, y1 + y2, z1 + z2)
92   - }
93   -}
94   -
95   -impl<T> Sub for Vector<T>
96   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
97   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
98   - type Output = Self;
99   -
100   - fn sub(self, other :Self) -> Self {
101   - self + -other
102   - }
103   -}
104   -
105   -impl<T> Neg for Vector<T>
106   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
107   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
108   - type Output = Self;
109   -
110   - fn neg(self) -> Self {
111   - let Vector(x, y, z) = self;
112   - Self(-x, -y, -z)
113   - }
114   -}
115   -
116   -impl<T> Mul for Vector<T>
117   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
118   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
119   - type Output = Self;
120   -
121   - fn mul(self, other :Self) -> Self {
122   - let Vector(ax, ay, az) = self;
123   - let Vector(bx, by, bz) = other;
124   -
125   - Vector( ay * bz - az * by
126   - , az * bx - ax * bz
127   - , ax * by - ay * bx )
128   - }
129   -}
130   -
131   -impl<T> Transformable<T> for Vector<T>
132   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
133   - + Mul<Output = T> + Div<Output = T>
134   - + Trig + Copy + Debug + From<i32> {
135   - fn transform(&self, m :&TMatrix<T>) -> Self {
136   - let (v, _) = m.apply(self, 0.into());
137   - v
138   - }
139   -}
1   -# This file is automatically @generated by Cargo.
2   -# It is not intended for manual editing.
3   -[[package]]
4   -name = "functions"
5   -version = "0.1.0"
6   -
1   -[package]
2   -name = "functions"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -fn main() {
2   - another_function(5, add_five(6));
3   -}
4   -
5   -fn another_function(x: i32, y: i32) {
6   - println!("The value of x id: {}", x);
7   - println!("The value of y id: {}", y);
8   -}
9   -
10   -fn add_five(x: i32) -> i32 {
11   - x + 5
12   -}
1   -# This file is automatically @generated by Cargo.
2   -# It is not intended for manual editing.
3   -[[package]]
4   -name = "fuchsia-cprng"
5   -version = "0.1.1"
6   -source = "registry+https://github.com/rust-lang/crates.io-index"
7   -
8   -[[package]]
9   -name = "guessing_game"
10   -version = "0.1.0"
11   -dependencies = [
12   - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
13   -]
14   -
15   -[[package]]
16   -name = "libc"
17   -version = "0.2.65"
18   -source = "registry+https://github.com/rust-lang/crates.io-index"
19   -
20   -[[package]]
21   -name = "rand"
22   -version = "0.3.23"
23   -source = "registry+https://github.com/rust-lang/crates.io-index"
24   -dependencies = [
25   - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
26   - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
27   -]
28   -
29   -[[package]]
30   -name = "rand"
31   -version = "0.4.6"
32   -source = "registry+https://github.com/rust-lang/crates.io-index"
33   -dependencies = [
34   - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
35   - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
36   - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
37   - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
38   - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
39   -]
40   -
41   -[[package]]
42   -name = "rand_core"
43   -version = "0.3.1"
44   -source = "registry+https://github.com/rust-lang/crates.io-index"
45   -dependencies = [
46   - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
47   -]
48   -
49   -[[package]]
50   -name = "rand_core"
51   -version = "0.4.2"
52   -source = "registry+https://github.com/rust-lang/crates.io-index"
53   -
54   -[[package]]
55   -name = "rdrand"
56   -version = "0.4.0"
57   -source = "registry+https://github.com/rust-lang/crates.io-index"
58   -dependencies = [
59   - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
60   -]
61   -
62   -[[package]]
63   -name = "winapi"
64   -version = "0.3.8"
65   -source = "registry+https://github.com/rust-lang/crates.io-index"
66   -dependencies = [
67   - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
68   - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
69   -]
70   -
71   -[[package]]
72   -name = "winapi-i686-pc-windows-gnu"
73   -version = "0.4.0"
74   -source = "registry+https://github.com/rust-lang/crates.io-index"
75   -
76   -[[package]]
77   -name = "winapi-x86_64-pc-windows-gnu"
78   -version = "0.4.0"
79   -source = "registry+https://github.com/rust-lang/crates.io-index"
80   -
81   -[metadata]
82   -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
83   -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
84   -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
85   -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
86   -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
87   -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
88   -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
89   -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
90   -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
91   -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1   -[package]
2   -name = "guessing_game"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -[dependencies]
8   -rand = "0.3.14"
1   -use std::io;
2   -use std::cmp::Ordering;
3   -use rand::Rng;
4   -
5   -fn main() {
6   - println!("Guess the number!");
7   -
8   - let secret_number = rand::thread_rng()
9   - .gen_range(1, 101);
10   -
11   - loop {
12   - println!("Please input your guess.");
13   -
14   - let mut guess = String::new();
15   -
16   - io::stdin()
17   - .read_line(&mut guess)
18   - .expect("Failed to read line");
19   -
20   - let guess: u32 = match guess.trim().parse() {
21   - Ok(num) => num,
22   - Err(_) => continue,
23   - };
24   -
25   - println!("You guessed: {}", guess);
26   -
27   - match guess.cmp(&secret_number) {
28   - Ordering::Less => println!("Too small!"),
29   - Ordering::Greater => println!("Too big!"),
30   - Ordering::Equal => {
31   - println!("You win!");
32   - break;
33   - }
34   - }
35   - }
36   -}
1   -# This file is automatically @generated by Cargo.
2   -# It is not intended for manual editing.
3   -[[package]]
4   -name = "hello"
5   -version = "0.1.0"
6   -
1   -[package]
2   -name = "hello"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -[dependencies]
1   -fn main() {
2   - println!("Hello, world!");
3   -}
1   -# Here I collect some interesting links.
2   -
3   -## cargo environment
4   -
5   -Currently I always build all dependencies within th projects own .cargo subdir
6   -by setting the environment variable CARGO_HOME.
7   -
8   - export CARGO_HOME=./.cargo
9   -
10   -Actually I am quite unsure if that is really a good idea because this results
11   -in a lot of rebuilds for each new project.
12   -
13   -## Implement Monads with rust.
14   -
15   -Which is currently difficult through impossible, but might be feasible with
16   -some small additions to the rust type system, namely
17   -«(generic) associated traits.»
18   -
19   -[Read here](https://varkor.github.io/blog/2019/03/28/idiomatic-monads-in-rust.html)
20   -
21   -### Is impl Trait what we needed?
22   -
23   -A new language feature which sounded a bit like the needed one for above is:
24   -
25   -[impl Trait](https://medium.com/@iopguy/impl-trait-in-rust-explanation-efde0d94946a)
26   -
27   -Crossreading it a bit seems to indicate that this is not like the above needed
28   -language feature.
29   -
30   -## WASM ... on gentoo ...
31   -
32   -Right now rust is not really a first class citizen within the gentoo eco
33   -system. For that reason at least when compiling rust with the `system-llvm`
34   -use flag some manual preparations are needed.
35   -
36   -### general informations about Wasm from MDN ...
37   -
38   -[WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly)
39   -
40   -### rustwasm tutorial
41   -
42   -[rustwasm](https://rustwasm.github.io/book/introduction.html)
43   -
44   -### location of rustlib ...
45   -
46   -`wasm-pack` expects the wasm runtime under /usr/lib/rustlib/ but a gentoo
47   -installation puts it under /usr/lib/rust-1.39.0/rustlib/. To come around this
48   -issue I just created a symlink.
49   -
50   -Maybe it would be best to send a patch for also settings this symlink to
51   -upstream eselect-rust.
52   -
53   -### Missing lld
54   -
55   -Again `wasm-pack` searches for llvm-lld or rust-lld for the link phase. This
56   -is currently not a dependency for llvm with WASM support, so I installed it
57   -manually. Finally you have to tell rustc to use lld as linker via this
58   -environment variable:
59   -
60   - export RUSTFLAGS="-C linker=lld"
61   -
62   -## Traits when, how & why
63   -
64   -A slightly old but still worthwhile post about rusts standard traits.
65   -
66   -[About traits](https://llogiq.github.io/2015/07/30/traits.html)
67   -
68   -# Side note... 3d math
69   -[3d math primer](https://www.3dgep.com/3d-math-primer-for-game-programmers-vector-operations/)
70   -[basic 3d math](https://matrix44.net/cms/notes/opengl-3d-graphics/basic-3d-math-vectors/)
71   -[vector calculator](https://www.mathportal.org/calculators/matrices-calculators/vector-calculator.php)
72   -[3d vector mathematics](https://vvvv.org/documentation/3d-vector-mathematics)
73   -[sin appr. with fractions](https://dsp.stackexchange.com/questions/46629/finding-polynomial-approximations-of-a-sine-wave)
74   -
75   -# transformations within a coordinate system.
76   -[migenius](https://www.migenius.com/articles/3d-transformations-part1-matrices)
77   -[tutorialspoint](https://www.tutorialspoint.com/computer_graphics/3d_transformation.htm)
78   -
79   -# more math...
80   -
81   -A whole lot of interesting stuff about continued fractions:
82   -[continues fractions](http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/cfINTRO.html)
83   -
1   -# This file is automatically @generated by Cargo.
2   -# It is not intended for manual editing.
3   -[[package]]
4   -name = "loops"
5   -version = "0.1.0"
6   -
1   -[package]
2   -name = "loops"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -//
2   -// Loops examples.
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -
22   -fn main() {
23   - // It seams that to use loops this way you absolutely need a mutable.
24   - // If I build it with a normal type and try to shadow it within the loop
25   - // the outer variable is always used as input for the shadow, thus it is
26   - // always the same.... that really sucks.
27   - let mut counter = 0;
28   -
29   - let result = loop {
30   - counter = counter + 1;
31   - if counter == 10 {
32   - break counter * 2;
33   - }
34   - };
35   -
36   - println!("The result is {}", result);
37   -
38   - // The same is true with «while» ... which again sucks.
39   - let mut number = 3;
40   -
41   - while number != 0 {
42   - println!("{}!", number);
43   - number = number - 1;
44   - }
45   -
46   - println!("LIFTOFF!!!");
47   -
48   - // apart from beeing frustrated about the above facts... lets continue.
49   - let a = [10, 20, 30, 40, 50];
50   - let mut index = 0;
51   -
52   - while index < 5 {
53   - println!("the value is: {}", a[index]);
54   - index = index + 1;
55   - }
56   -
57   - for element in a.iter() {
58   - println!("the value is still: {}", element);
59   - }
60   -
61   - for number in (1..4).rev() {
62   - println!("for {}!", number);
63   - }
64   -}
1   -# This file is automatically @generated by Cargo.
2   -# It is not intended for manual editing.
3   -[[package]]
4   -name = "ownership"
5   -version = "0.1.0"
6   -
1   -[package]
2   -name = "ownership"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -//
2   -// Examples related to ownership, also introducing String.
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -
22   -fn main() {
23   - concat();
24   - move_variable();
25   - clone_variable();
26   -
27   - let s = String::from("hello"); // s comes into scope
28   -
29   - take_ownership(s); // s's value moves into the function
30   - // … and so is no longer valid here.
31   - let x = 5; // x comes into scope
32   -
33   - makes_copy(x); // the scalar value has the Copy trait and
34   - // lives on the stack and thus is still
35   - // valid here.
36   -
37   - let _s1 = gives_ownership(); // move the return value into _s1
38   - let s2 = String::from("hello"); // s2 comes into scope
39   - let _s3 = takes_and_gives(s2); // s2 is moved into function, which in
40   - // turn moves the return value into _s3.
41   -
42   - let s1 = String::from("hello"); // s1 comes into scope.
43   - let len = calculate_length(&s1); // A reference to s1 is given to a
44   - // calculate_length which effectively is
45   - // not s1 itself but another pointer to
46   - // s1… which is the reason that we still
47   - // can use it below.
48   - let _another_s = &s1; // again only a reference which does not
49   - // take ownership, thus s1 can still be
50   - // used below.
51   - println!("The length of '{}' is {}.", s1, len);
52   -
53   - // Passing values as reference to a function is called borrowing. A
54   - // borrowed value can't be changed.
55   - change(&s1);
56   -
57   - // but we can force this… which is probably not the best of ideas most
58   - // of the time…
59   - let mut s_mut = String::from("hello");
60   - change_mutable(&mut s_mut);
61   -
62   - // but you can have only one mutable reference of a value in a single
63   - // scope. The following would fail with:
64   - // cannot borrow `s_mut` as mutable more than once at a time second
65   - // mutable borrow occurs here
66   - // let r1 = &mut s_mut;
67   - // let r2 = &mut s_mut;
68   - // println!("{}, {}", r1, r2);
69   -
70   - // We also can't have an immutable reference while we have a mutable one.
71   - // Look on Page 98 for an explanation.
72   -
73   - // The scope of references is not the whole block they are introduced in
74   - // but goes only until their last usage. Thus if you first have an
75   - // immutable reference but never use it after a mutable reference is
76   - // declared, that would be ok… At all this is kind of confusing and very
77   - // Mozzilaish. :D
78   -
79   - // Now we demonstrate string slices…
80   - let s4 = String::from("hello world");
81   - let s_slice = first_word(&s4);
82   -
83   - // working with an mutable reference like with s4.clear() will not
84   - // compile at this point because we already have and use later on an
85   - // immutable reference.
86   -
87   - println!("The slice was: {}", s_slice);
88   -
89   - // not that string literals are slices. They are immutable references of
90   - // the programs TEXT segment. Thats the reason why they are immutable.
91   -
92   - // Thus try generic_first_word…
93   - println!("First word on literal: {}", generic_first_word("hello world"));
94   - println!("First word on String: {}", generic_first_word(&s4[..]));
95   -} // x and s go out of scope but nothing happens for s because this function
96   - // has no longer the ownership of s.
97   - // s3 goes out of scope and is dropped. s2 was moved and s1 is dropped.
98   -
99   -fn concat() {
100   - let mut s = String::from("hello");
101   - s.push_str(", world!");
102   - println!("{}", s);
103   -}
104   -
105   -fn move_variable() {
106   - let s1 = String::from("hello");
107   - let s2 = s1; // does not copy data but only the String structure.
108   - // when using s1 below we get an error that a moved value was borrowed.
109   - println!("{}, world!", s2);
110   -}
111   -
112   -fn clone_variable() {
113   - let s1 = String::from("hello");
114   - let s2 = s1.clone();
115   - // this time both are valid.
116   - println!("s1 = {}, s2 = {}", s1, s2)
117   -}
118   -
119   -fn take_ownership(some_string: String) { // some_string comes into scope
120   - println!("{}", some_string);
121   -} // some_string goes out of scope and «drop» is called, thus memory freed.
122   -
123   -fn makes_copy(some_integer: i32) { // some integer comes into scope
124   - println!("{}", some_integer);
125   -} // Here, some_integer goes out of scope but because it was a copy and on the
126   - // stack nothing special happens… beside that stack space is freed.
127   -
128   -fn gives_ownership() -> String { // this will move the return value into the
129   - // calling function.
130   - let some_string = String::from("hello"); // some_string comes into scope
131   - some_string
132   -}
133   -
134   -fn takes_and_gives(a_string: String) -> String { // a_string comes into scope
135   - a_string // and is returned and moved
136   - // to the calling function.
137   -} // a_string goes out of scope but nothing happens as it is moved.
138   -
139   -fn calculate_length(s: &String) -> usize { // s comes into scope. It is a
140   - // reference. References do not
141   - // take ownership of the underlying
142   - // value which is the String in
143   - // main.
144   - s.len()
145   -} // Here s goes out of scope but because it has no ownership of the String
146   - // nothing happens.
147   -
148   -fn change(_some_string: &String) {
149   - // the following would give this error:
150   - // `_some_string` is a `&` reference, so the data it refers to cannot be
151   - // borrowed as mutable
152   - // _some_string.push_str(", world!");
153   -}
154   -
155   -fn change_mutable(some_string: &mut String) {
156   - some_string.push_str(", world");
157   -}
158   -
159   -fn first_word(s: &String) -> &str {
160   - let bytes = s.as_bytes();
161   -
162   - for (i, &item) in bytes.iter().enumerate() {
163   - if item == b' ' {
164   - return &s[..i];
165   - }
166   - }
167   -
168   - &s[..]
169   -}
170   -
171   -// To make first_word work on either string literals (which are in fact string
172   -// slices, s.o.) one would write first_word like this…
173   -fn generic_first_word(s: &str) -> &str {
174   - let bytes = s.as_bytes();
175   -
176   - for (i, &item) in bytes.iter().enumerate() {
177   - if item == b' ' {
178   - return &s[..i];
179   - }
180   - }
181   -
182   - &s[..]
183   -}
1   -[package]
2   -name = "rectangles"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -//
2   -// Examples related to structs…
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -
22   -#[derive(Debug)]
23   -struct Rectangle {
24   - width: u32,
25   - height: u32,
26   -}
27   -
28   -impl Rectangle {
29   - fn area(&self) -> u32 {
30   - self.width * self.height
31   - }
32   -
33   - fn can_hold(&self, inner: &Rectangle) -> bool {
34   - self.width >= inner.width && self.height >= inner.height
35   - }
36   -
37   - fn square(size: u32) -> Rectangle {
38   - Rectangle { width: size, height: size }
39   - }
40   -}
41   -
42   -fn main() {
43   - let width1 = 30;
44   - let height1 = 50;
45   -
46   - println!(
47   - "The area of the rectangle ist {} square pixels.",
48   - area(width1, height1));
49   -
50   - let rect1 = (30, 50);
51   -
52   - println!(
53   - "The area of the rectangle ist {} square pixels.",
54   - _area(rect1));
55   -
56   - let rect1 = Rectangle { width: 30, height: 50 };
57   -
58   - println!(
59   - "The area of the rectangle ist {} square pixels.",
60   - __area(&rect1));
61   -
62   - println!("_rect1 is {:?}", rect1);
63   -
64   - println!(
65   - "The area of the rectangle ist {} square pixels.",
66   - rect1.area());
67   -
68   - let rect2 = Rectangle { width: 10, height: 40};
69   - let rect3 = Rectangle { width: 60, height: 45};
70   -
71   - println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
72   - println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
73   -
74   - let square1 = Rectangle::square(32);
75   -
76   - println!("Got the square rectange: {:?}", square1);
77   -}
78   -
79   -fn area(width: u32, height: u32) -> u32 {
80   - width * height
81   -}
82   -
83   -fn _area(dimensions: (u32, u32)) -> u32 {
84   - let (width, height) = dimensions;
85   - width * height
86   -}
87   -
88   -fn __area(rectangle: &Rectangle) -> u32 {
89   - rectangle.width * rectangle.height
90   -}
1   -[package]
2   -name = "recursion"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -//
2   -// Try some recursion with pattern matching... especially in
3   -// conjunction with match to get a similar behavious as in e.g.
4   -// haskell...
5   -//
6   -// Georg Hopp <georg@steffers.org>
7   -//
8   -// Copyright © 2019 Georg Hopp
9   -//
10   -// This program is free software: you can redistribute it and/or modify
11   -// it under the terms of the GNU General Public License as published by
12   -// the Free Software Foundation, either version 3 of the License, or
13   -// (at your option) any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful,
16   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
17   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18   -// GNU General Public License for more details.
19   -//
20   -// You should have received a copy of the GNU General Public License
21   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -
24   -// Borrowing rules do not apply here because everything lives on the stack.
25   -fn faculty(x: u32) -> u32 {
26   - match x {
27   - 0 => 1,
28   - _ => x * faculty(x - 1),
29   - }
30   -}
31   -
32   -// for a tail recursive version we need to pass the currently calculated
33   -// faculty to an inner tail recursive function.
34   -// This will probably be optimized better, because the compiler would be
35   -// able to unroll the complete recursion.
36   -fn tail_faculty(x: u32) -> u32 {
37   - fn faculty(x: u32, f: u32) -> u32 {
38   - match x {
39   - 0 => f,
40   - _ => faculty(x - 1, x * f),
41   - }
42   - };
43   - faculty(x, 1)
44   -}
45   -
46   -fn main() {
47   - for i in 0..10 {
48   - println!("Fakultät {} = {}", i, faculty(i));
49   - println!("tail recursive Fakultät {} = {}", i, tail_faculty(i));
50   - }
51   -}
1   -[package]
2   -name = "restaurant"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -//
2   -// Move some restaurant stuff in a different file....
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -
22   -pub mod hosting;
23   -
24   -mod serving {
25   - fn take_order() {}
26   - fn take_payment() {}
27   -}
1   -//
2   -// Now also sepatate hosting....
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -
22   -pub fn add_to_waitlist() {}
23   -fn seat_at_table() {}
1   -//
2   -// Restaurant lib for demontrating rust modules.
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -
22   -mod front_of_house;
23   -
24   -fn serve_order() {}
25   -
26   -mod back_of_house {
27   - pub struct Breakfast {
28   - pub toast: String,
29   - seasonal_fruit: String,
30   - }
31   -
32   - impl Breakfast {
33   - pub fn summer(toast: &str) -> Breakfast {
34   - Breakfast {
35   - toast: String::from(toast),
36   - seasonal_fruit: String::from("peaches"),
37   - }
38   - }
39   - }
40   -
41   - pub enum Appetizer {
42   - Soup,
43   - Salad,
44   - }
45   -
46   - fn fix_incorrect_order() {
47   - cook_order();
48   - super::serve_order();
49   - }
50   -
51   - fn cook_order() {}
52   -}
53   -
54   -// Either absolute:
55   -// use crate::front_of_house::hosting;
56   -// or relaive:
57   -use front_of_house::hosting;
58   -// we can also provide new names...
59   -use crate::front_of_house::hosting as host;
60   -// Public definitions braught into scope with use are
61   -// private in this scope except we use «pub use»
62   -pub use front_of_house::hosting as pubhost;
63   -
64   -pub fn eat_at_restaurant() {
65   - // Absolute path
66   - crate::front_of_house::hosting::add_to_waitlist();
67   -
68   - // Relative path
69   - front_of_house::hosting::add_to_waitlist();
70   -
71   - // With use'd path
72   - hosting::add_to_waitlist();
73   -
74   - // With renamed used path
75   - host::add_to_waitlist();
76   -
77   - pubhost::add_to_waitlist();
78   -
79   - // Order a breakfast in the summer with Rye toast
80   - let mut meal = back_of_house::Breakfast::summer("Rye");
81   -
82   - // Change our mind about what bread we'd like
83   - meal.toast = String::from("Wheat");
84   -
85   - println!("I'd like {} toast please", meal.toast);
86   -
87   - // The next line won't compile if we uncomment it; we're not allowed
88   - // to see or modify the seasonal fruit that comes with the meal
89   - // meal.seasonal_fruit = String::from("blueberries");
90   -
91   - let order1 = back_of_house::Appetizer::Soup;
92   - let order2 = back_of_house::Appetizer::Salad;
93   -}
... ... @@ -20,13 +20,16 @@
20 20 //
21 21 extern crate xcb;
22 22
  23 +use std::fmt::Debug;
23 24 use std::sync::Arc;
24   -use std::ptr; //::{null, null_mut};
  25 +use std::ptr;
25 26 use std::thread;
26 27 use std::sync::mpsc;
27 28 use std::ops::{Add, Sub, Div};
28 29
29   -use crate::easel::{Easel, Canvas, Drawable, Coordinate, Coordinates};
  30 +use easel3d::easel::Easel;
  31 +use easel3d::easel::canvas::{Canvas, Vertex};
  32 +use easel3d::easel::drawable::Drawable;
30 33
31 34 #[derive(Clone)]
32 35 pub struct XcbEasel (Arc<xcb::Connection>, i32);
... ... @@ -62,6 +65,7 @@ impl XcbEasel {
62 65 , height :u16) -> Option<XcbCanvas<'a, T>>
63 66 where T: Clone + From<i32> {
64 67 let Self(conn, _) = self;
  68 + let size = width as usize * height as usize;
65 69 let conn = conn.clone();
66 70 let screen = match self.screen() {
67 71 None => return None,
... ... @@ -85,8 +89,8 @@ impl XcbEasel {
85 89 , &[ (xcb::GC_FOREGROUND, screen.white_pixel())
86 90 , (xcb::GC_GRAPHICS_EXPOSURES, 0) ] );
87 91
88   - let zbuf :Vec<T> = vec!(0.into(); (width * height) as usize);
89   - let (shmid, shm) = getshm((width * height) as usize);
  92 + let zbuf :Vec<T> = vec!(0.into(); size);
  93 + let (shmid, shm) = getshm(size);
90 94 xcb::shm::attach(&conn, shmseg, shmid as u32, false);
91 95 unsafe { libc::shmctl(shmid, libc::IPC_RMID, ptr::null_mut()); }
92 96
... ... @@ -138,7 +142,7 @@ impl Easel for XcbEasel {}
138 142
139 143 impl<'a, T> Canvas<T> for XcbCanvas<'a, T>
140 144 where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
141   - + Copy + From<i32> + PartialOrd {
  145 + + Debug + Copy + From<i32> + PartialOrd {
142 146 fn init_events(&self) {
143 147 let mask = [( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE
144 148 | xcb::EVENT_MASK_KEY_PRESS
... ... @@ -233,12 +237,10 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
233 237 }
234 238 }
235 239
236   - fn draw(&mut self, d :&dyn Drawable<T>, ofs :Coordinate<T>, color: u32) {
237   - let Coordinates(c) = d.plot();
238   - let Coordinate(xofs, yofs, _) = ofs;
239   -
240   - for Coordinate(x, y, zr) in c {
241   - let idx :usize = ((y+yofs)*(self.width as i32)+x+xofs) as usize;
  240 + fn draw(&mut self, d :&dyn Drawable<T>, color: u32) {
  241 + for c in d.plot() {
  242 + let (x, y, zr) = c.as_tuple();
  243 + let idx :usize = (y*(self.width as i32)+x) as usize;
242 244 if self.zbuf[idx] < zr {
243 245 self.zbuf[idx] = zr;
244 246 self.shm[idx] = color;
... ... @@ -246,15 +248,15 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
246 248 }
247 249 }
248 250
249   - fn put_text(&self, ofs :Coordinate<T>, s :&str) {
250   - let Coordinate(xofs, yofs, _) = ofs;
  251 + fn put_text(&self, ofs :Vertex<T>, s :&str) {
  252 + let (xofs, yofs, _) = ofs.as_tuple();
251 253 xcb::xproto::image_text_8( &self.conn, self.pixmap, self.gc
252 254 , xofs as i16, yofs as i16, s );
253 255 self.conn.flush();
254 256 }
255 257
256   - fn set_pixel(&mut self, c :Coordinate<T>, color :u32) {
257   - let Coordinate(x, y, zr) = c;
  258 + fn set_pixel(&mut self, c :Vertex<T>, color :u32) {
  259 + let (x, y, zr) = c.as_tuple();
258 260 let idx :usize = (y * (self.width as i32) + x) as usize;
259 261
260 262 if self.zbuf[idx] < zr {
... ...
  1 +//
  2 +// Test our fractional crate / module...
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
  24 +use std::sync::mpsc;
  25 +use std::thread;
  26 +use std::time::{Duration, Instant};
  27 +
  28 +use easel3d::easel::canvas::{Vertex, Canvas};
  29 +use easel3d::easel::fillable::Fillable;
  30 +use easel3d::math::trigonometry::Trig;
  31 +use easel3d::math::vector::Vector;
  32 +use easel3d::math::transform::TMatrix;
  33 +use easel3d::space::camera::Camera;
  34 +use easel3d::space::light::DirectLight;
  35 +use easel3d::space::polyeder::Polyeder;
  36 +use easel3d::space::primitives::Primitives;
  37 +
  38 +mod easel3d_xcb;
  39 +
  40 +use easel3d_xcb::XcbEasel;
  41 +
  42 +fn democanvas<T>( xcb :&XcbEasel
  43 + , title :&'static str
  44 + , tx :mpsc::Sender<i32>
  45 + , _triangle :Polyeder<T>
  46 + , tetrahedron :Polyeder<T>
  47 + , cube :Polyeder<T>
  48 + , light :DirectLight<T> )
  49 + where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T>
  50 + + Mul<Output = T> + Div<Output = T>
  51 + + Debug + Copy + Trig + Send + From<i32> + From<f64> + PartialOrd {
  52 +
  53 + let mut canvas = xcb.canvas(301, 301).unwrap();
  54 + let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle
  55 + // was 50.
  56 +
  57 + canvas.set_title(title);
  58 + canvas.init_events();
  59 + canvas.start_events(tx.clone());
  60 +
  61 + thread::spawn(move || {
  62 + let start = Instant::now();
  63 + let step = Duration::from_millis(20);
  64 + let mut last = Instant::now();
  65 +
  66 + let t = TMatrix::translate(Vector(0.into() , 0.into() , 150.into()));
  67 +
  68 + loop {
  69 + let deg = ((start.elapsed() / 20).as_millis() % (4*360)) as i32;
  70 +
  71 + let rz = TMatrix::rotate_z(deg);
  72 + let rx = TMatrix::rotate_x(-deg*2);
  73 + let ry = TMatrix::rotate_y(-deg*2);
  74 +
  75 + let rot1 = TMatrix::combine(vec!(rz, rx, t));
  76 + let rot2 = TMatrix::combine(vec!(rz, ry, t));
  77 +
  78 + let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00)
  79 + , ( cube.transform(&rot2), 0x0000FF) );
  80 + //let objects = vec!( ( cube.transform(&rot2), 0x0000FF) );
  81 + //let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) );
  82 + //let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) );
  83 +
  84 + let rlx = TMatrix::rotate_x(-deg/4);
  85 + let rly = TMatrix::rotate_y(-deg/1);
  86 + let tlight = light.transform(&TMatrix::combine(vec!(rlx, rly)));
  87 +
  88 + canvas.clear();
  89 +
  90 + for (o, color) in objects {
  91 + for (pg, c) in o.project(&camera, &tlight, color) {
  92 + (&pg).fill(&mut canvas, c);
  93 + }
  94 + }
  95 +
  96 + let passed = Instant::now() - last;
  97 + let f = (passed.as_nanos() / step.as_nanos()) as u32;
  98 +
  99 + if f > 1 {
  100 + println!("{} !!! Detected frame drop", title);
  101 + }
  102 +
  103 + last = last + step*(f + 1);
  104 + canvas.put_text( Vertex::new(10, 15, 0.into())
  105 + , &format!( "sleep: {:?}"
  106 + , last - Instant::now() ));
  107 + canvas.show();
  108 + thread::sleep(last - Instant::now());
  109 + }
  110 + });
  111 +}
  112 +
  113 +fn main() {
  114 + let xcb = XcbEasel::new().unwrap();
  115 + let (tx, rx) = mpsc::channel();
  116 +
  117 + democanvas( &xcb, "Something...(f64)", tx.clone()
  118 + , Polyeder::triangle(60.0)
  119 + , Polyeder::tetrahedron(100.0)
  120 + , Polyeder::cube(56.25)
  121 + , DirectLight::new(Vector(0.0, 0.0, 1.0)) );
  122 +
  123 + for x in rx {
  124 + match x {
  125 + 1 => break,
  126 + _ => {},
  127 + }
  128 + }
  129 +}
... ...
1   -/target
2   -**/*.rs.bk
3   -Cargo.lock
4   -bin/
5   -pkg/
6   -wasm-pack/
7   -wasm-pack.log
1   -[package]
2   -name = "wasm-game-of-life"
3   -version = "0.1.0"
4   -authors = ["hopp@silpion.de"]
5   -edition = "2018"
6   -
7   -[lib]
8   -crate-type = ["cdylib", "rlib"]
9   -
10   -[features]
11   -default = ["console_error_panic_hook"]
12   -
13   -[dependencies]
14   -wasm-bindgen = "0.2"
15   -lazy_static = "1.4.0"
16   -
17   -# The `console_error_panic_hook` crate provides better debugging of panics by
18   -# logging them with `console.error`. This is great for development, but requires
19   -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
20   -# code size when deploying.
21   -console_error_panic_hook = { version = "0.1.1", optional = true }
22   -
23   -# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
24   -# compared to the default allocator's ~10K. It is slower than the default
25   -# allocator, however.
26   -#
27   -# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
28   -wee_alloc = { version = "0.4.2", optional = true }
29   -
30   -[dev-dependencies]
31   -wasm-bindgen-test = "0.2"
32   -
33   -[profile.release]
34   -# Tell `rustc` to optimize for small code size.
35   -opt-level = "s"
1   -<div align="center">
2   -
3   - <h1><code>wasm-pack-template</code></h1>
4   -
5   - <strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong>
6   -
7   - <p>
8   - <a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a>
9   - </p>
10   -
11   - <h3>
12   - <a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a>
13   - <span> | </span>
14   - <a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
15   - </h3>
16   -
17   - <sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
18   -</div>
19   -
20   -## About
21   -
22   -[**📚 Read this template tutorial! 📚**][template-docs]
23   -
24   -This template is designed for compiling Rust libraries into WebAssembly and
25   -publishing the resulting package to NPM.
26   -
27   -Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other
28   -templates and usages of `wasm-pack`.
29   -
30   -[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html
31   -[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html
32   -
33   -## 🚴 Usage
34   -
35   -### 🐑 Use `cargo generate` to Clone this Template
36   -
37   -[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)
38   -
39   -```
40   -cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
41   -cd my-project
42   -```
43   -
44   -### 🛠️ Build with `wasm-pack build`
45   -
46   -```
47   -wasm-pack build
48   -```
49   -
50   -### 🔬 Test in Headless Browsers with `wasm-pack test`
51   -
52   -```
53   -wasm-pack test --headless --firefox
54   -```
55   -
56   -### 🎁 Publish to NPM with `wasm-pack publish`
57   -
58   -```
59   -wasm-pack publish
60   -```
61   -
62   -## 🔋 Batteries Included
63   -
64   -* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
65   - between WebAssembly and JavaScript.
66   -* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
67   - for logging panic messages to the developer console.
68   -* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized
69   - for small code size.
1   -//
2   -// This is an abstraction over a drawing environment.
3   -// Future note: z-Buffer is described here:
4   -// https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
5   -//
6   -// Georg Hopp <georg@steffers.org>
7   -//
8   -// Copyright © 2019 Georg Hopp
9   -//
10   -// This program is free software: you can redistribute it and/or modify
11   -// it under the terms of the GNU General Public License as published by
12   -// the Free Software Foundation, either version 3 of the License, or
13   -// (at your option) any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful,
16   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
17   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18   -// GNU General Public License for more details.
19   -//
20   -// You should have received a copy of the GNU General Public License
21   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -use std::cmp;
24   -use std::fmt::{Formatter, Debug, Display, Result};
25   -use std::ops::{Add, Sub, Div};
26   -use std::sync::mpsc;
27   -
28   -pub trait Easel {
29   - //fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>;
30   -}
31   -
32   -pub trait Canvas<T> {
33   - fn init_events(&self);
34   - fn start_events(&self, tx :mpsc::Sender<i32>);
35   -
36   - fn width(&self) -> u16;
37   - fn height(&self) -> u16;
38   -
39   - fn clear(&mut self);
40   - fn draw(&mut self, c :&dyn Drawable<T>, ofs :Coordinate<T>, color :u32);
41   - fn put_text(&self, ofs :Coordinate<T>, s :&str);
42   - fn set_pixel(&mut self, c :Coordinate<T>, color :u32);
43   - fn show(&self);
44   -}
45   -
46   -pub trait Drawable<T> {
47   - fn plot(&self) -> Coordinates<T>;
48   -}
49   -
50   -pub trait Fillable<T>
51   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
52   - + Debug + Copy + From<i32> {
53   - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32);
54   -}
55   -
56   -#[derive(Debug, Clone, Copy)]
57   -pub struct Coordinate<T>(pub i32, pub i32, pub T);
58   -
59   -#[derive(Debug, Clone)]
60   -pub struct Coordinates<T>(pub Vec<Coordinate<T>>);
61   -
62   -#[derive(Debug, Clone, Copy)]
63   -pub struct LineIterator<T> where T: Debug {
64   - a :Option<Coordinate<T>>
65   - , b :Coordinate<T>
66   - , dx :i32
67   - , dy :i32
68   - , dz :T
69   - , sx :i32
70   - , sy :i32
71   - , err :i32
72   - , only_edges :bool
73   -}
74   -
75   -impl<T> Iterator for LineIterator<T>
76   -where T: Add<Output = T> + Debug + Copy + From<i32> {
77   - type Item = Coordinate<T>;
78   -
79   - fn next(&mut self) -> Option<Self::Item> {
80   - match self.a {
81   - None => None,
82   - Some(a) => {
83   - let Coordinate(ax, ay, az) = a;
84   - let Coordinate(bx, by, _) = self.b;
85   -
86   - if ax != bx || ay != by {
87   - match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) {
88   - (true, false) => {
89   - let r = self.a;
90   - self.a = Some(Coordinate( ax + self.sx
91   - , ay
92   - , az + self.dz ));
93   - self.err = self.err + self.dy;
94   - if self.only_edges { self.next() } else { r }
95   - },
96   - (false, true) => {
97   - let r = self.a;
98   - self.a = Some(Coordinate( ax
99   - , ay + self.sy
100   - , az + self.dz ));
101   - self.err = self.err + self.dx;
102   - r
103   - },
104   - _ => {
105   - let r = self.a;
106   - self.a = Some(Coordinate( ax + self.sx
107   - , ay + self.sy
108   - , az + self.dz ));
109   - self.err = self.err + self.dx + self.dy;
110   - r
111   - },
112   - }
113   - } else {
114   - self.a = None;
115   - Some(self.b)
116   - }
117   - }
118   - }
119   - }
120   -}
121   -
122   -impl<T> Coordinate<T>
123   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
124   - + Debug + Clone + Copy + From<i32> {
125   - fn iter(self, b :&Self, only_edges :bool) -> LineIterator<T> {
126   - let Coordinate(ax, ay, az) = self;
127   - let Coordinate(bx, by, bz) = *b;
128   -
129   - let dx = (bx - ax).abs();
130   - let dy = -(by - ay).abs();
131   -
132   - LineIterator { a: Some(self)
133   - , b: *b
134   - , dx: dx
135   - , dy: dy
136   - , dz: (bz - az) / cmp::max(dx, -dy).into()
137   - , sx: if ax < bx { 1 } else { -1 }
138   - , sy: if ay < by { 1 } else { -1 }
139   - , err: dx + dy
140   - , only_edges: only_edges
141   - }
142   - }
143   -
144   - fn line_iter(self, b :&Self) -> LineIterator<T> {
145   - self.iter(b, false)
146   - }
147   -
148   - fn line(self, b :&Self) -> Vec<Self> {
149   - self.line_iter(b).collect()
150   - }
151   -
152   - fn edge_iter(self, b :&Self) -> LineIterator<T> {
153   - self.iter(b, true)
154   - }
155   -
156   - fn edge(self, b :&Self) -> Vec<Self> {
157   - self.edge_iter(b).collect()
158   - }
159   -
160   - fn face(edges :&[Self]) -> Vec<Self> {
161   - edges.to_vec()
162   - }
163   -}
164   -
165   -impl<T> Display for Coordinate<T> {
166   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
167   - write!(f, "<{},{}>", self.0, self.1)
168   - }
169   -}
170   -
171   -impl<T> Display for Coordinates<T> where T: Copy {
172   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
173   - let Coordinates(is) = self;
174   -
175   - let c = match is[..] {
176   - [] => String::from(""),
177   - [a] => format!("{}", a),
178   - _ => {
179   - let mut a = format!("{}", is[0]);
180   - for i in is[1..].iter() {
181   - a = a + &format!(",{}", i);
182   - }
183   - a
184   - }
185   - };
186   -
187   - write!(f, "Coordinates[{}]", c)
188   - }
189   -}
190   -
191   -
192   -#[derive(Debug, Clone, Copy)]
193   -pub struct Point<T>(pub Coordinate<T>);
194   -
195   -impl<T> Drawable<T> for Point<T> where T: Copy {
196   - fn plot(&self) -> Coordinates<T> {
197   - let Point(c) = *self;
198   - Coordinates(vec!(c))
199   - }
200   -}
201   -
202   -impl<T> Display for Point<T> {
203   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
204   - let Point(p) = self;
205   - write!(f, "Point[{}]", p)
206   - }
207   -}
208   -
209   -#[derive(Debug, Clone, Copy)]
210   -pub struct Line<T>(pub Coordinate<T>, pub Coordinate<T>);
211   -
212   -impl<T> Drawable<T> for Line<T>
213   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
214   - + Debug + Clone + Copy + From<i32> {
215   - fn plot(&self) -> Coordinates<T> {
216   - let Line(a, b) = *self;
217   - Coordinates(a.line(&b))
218   - }
219   -}
220   -
221   -impl<T> Display for Line<T> {
222   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
223   - let Line(a, b) = self;
224   - write!(f, "Line[{},{}]", a, b)
225   - }
226   -}
227   -
228   -#[derive(Debug, Clone)]
229   -pub struct Polyline<T>(pub Coordinates<T>);
230   -
231   -impl<T> Drawable<T> for Polyline<T>
232   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
233   - + Debug + Clone + Copy + From<i32> {
234   - fn plot(&self) -> Coordinates<T> {
235   - let Polyline(Coordinates(cs)) = self;
236   -
237   - match cs[..] {
238   - [] => Coordinates(Vec::<Coordinate<T>>::new()),
239   - [a] => Coordinates(vec!(a)),
240   - [a, b] => Coordinates(a.line(&b)),
241   - _ => {
242   - let (a, b) = (cs[0], cs[1]);
243   - let mut r = a.line(&b);
244   - let mut i = b;
245   - for j in cs[2..].iter() {
246   - r.append(&mut i.line(j)[1..].to_vec());
247   - i = *j;
248   - }
249   - Coordinates(r)
250   - },
251   - }
252   - }
253   -}
254   -
255   -impl<T> Display for Polyline<T> where T: Copy {
256   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
257   - let Polyline(a) = self;
258   - write!(f, "PLine[{}]", a)
259   - }
260   -}
261   -
262   -#[derive(Debug, Clone, Copy)]
263   -enum Direction { Left, Right }
264   -
265   -#[derive(Debug, Clone)]
266   -pub struct Polygon<T>(pub Coordinates<T>);
267   -
268   -#[derive(Debug, Clone)]
269   -enum VertexIteratorMode { Vertex, Edge }
270   -#[derive(Debug, Clone)]
271   -pub struct VertexIterator<'a,T> where T: Debug {
272   - p :&'a Polygon<T>,
273   - top :usize,
274   - current :Option<usize>,
275   - edge :Option<LineIterator<T>>,
276   - mode :VertexIteratorMode,
277   - direction :Direction,
278   -}
279   -
280   -impl<'a,T> VertexIterator<'a,T>
281   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
282   - + Debug + Copy + From<i32> {
283   - fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {
284   - let top = p.vert_min(direction);
285   - let next = p.next_y(top, direction);
286   - let edge = match next {
287   - None => None,
288   - Some(next) => Some(p.vertex(top).edge_iter(&p.vertex(next))),
289   - };
290   -
291   - VertexIterator { p: p
292   - , top: top
293   - , current: next
294   - , edge: edge
295   - , mode: VertexIteratorMode::Edge
296   - , direction: direction }
297   - }
298   -
299   - fn vertex(p :&'a Polygon<T>, direction :Direction) -> Self {
300   - let top = p.vert_min(direction);
301   - let next = p.next_y(top, direction);
302   -
303   - VertexIterator { p: p
304   - , top: top
305   - , current: next
306   - , edge: None
307   - , mode: VertexIteratorMode::Vertex
308   - , direction: direction }
309   - }
310   -
311   - // if this yields "None" we are finished.
312   - fn next_edge(&mut self) -> Option<LineIterator<T>> {
313   - let current = self.current?;
314   - let next = self.p.next_y(current, self.direction)?;
315   - let mut edge = self.p.vertex(current).edge_iter(&self.p.vertex(next));
316   -
317   - match edge.next() {
318   - // It should be impossible that a new edge iterator has no values
319   - // at all… anyway, just in case I handle it here.
320   - None => self.next_edge(),
321   - Some(_) => {
322   - self.current = Some(next);
323   - self.edge = Some(edge);
324   - self.edge
325   - },
326   - }
327   - }
328   -}
329   -
330   -impl<'a,T> Iterator for VertexIterator<'a,T>
331   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
332   - + Debug + Copy + From<i32> {
333   - type Item = Coordinate<T>;
334   -
335   - fn next(&mut self) -> Option<Self::Item> {
336   - match self.mode {
337   - VertexIteratorMode::Edge => {
338   - // if for whatever reason edge is "None" finish this iterator.
339   - let next = self.edge.as_mut()?.next();
340   -
341   - match next {
342   - Some(_) => next,
343   - None => {
344   - self.next_edge()?;
345   - self.next()
346   - },
347   - }
348   - },
349   - VertexIteratorMode::Vertex => {
350   - let current = self.current?;
351   - self.current = self.p.next_y(current, self.direction);
352   - Some(self.p.vertex(current))
353   - },
354   - }
355   - }
356   -}
357   -
358   -impl<T> Polygon<T>
359   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
360   - + Copy + Debug + From<i32> {
361   - #[inline]
362   - fn vertex(&self, v :usize) -> Coordinate<T> {
363   - let Polygon(Coordinates(cs)) = self;
364   - cs[v]
365   - }
366   -
367   - fn vert_min<'a>(&'a self, d :Direction) -> usize {
368   - let Polygon(Coordinates(cs)) = self;
369   -
370   - type ICoord<'a,T> = (usize, &'a Coordinate<T>);
371   -
372   - // TODO I guess the problem here is that it does not account for the
373   - // same y vertex on the beggining and the end. So i guess correct
374   - // would be finding the first one and then dependings on the
375   - // given direction either search left or right for same y's.
376   - let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a,T>|
377   - match acc {
378   - None => Some(x),
379   - Some(a) => {
380   - let Coordinate(_, ay, _) = a.1;
381   - let Coordinate(_, xy, _) = x.1;
382   - if xy < ay {Some(x)} else {Some(a)}
383   - },
384   - };
385   -
386   - let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0;
387   - let mut next = self.step(min, d);
388   -
389   - while self.vertex(min).1 == self.vertex(next).1 {
390   - min = next;
391   - next = self.step(min, d);
392   - }
393   -
394   - min
395   - }
396   -
397   - fn left_edge(&self) -> VertexIterator<T> {
398   - VertexIterator::edge(self, Direction::Left)
399   - }
400   -
401   - fn right_edge(&self) -> VertexIterator<T> {
402   - VertexIterator::edge(self, Direction::Right)
403   - }
404   -
405   - fn left_vertices(&self) -> VertexIterator<T> {
406   - VertexIterator::vertex(self, Direction::Left)
407   - }
408   -
409   - fn right_vertices(&self) -> VertexIterator<T> {
410   - VertexIterator::vertex(self, Direction::Right)
411   - }
412   -
413   - fn left(&self, v :usize) -> usize {
414   - let Polygon(Coordinates(cs)) = self;
415   -
416   - match v {
417   - 0 => cs.len() - 1,
418   - _ => v - 1,
419   - }
420   - }
421   -
422   - fn right(&self, v :usize) -> usize {
423   - let Polygon(Coordinates(cs)) = self;
424   -
425   - (v + 1) % cs.len()
426   - }
427   -
428   - fn step(&self, v :usize, d :Direction) -> usize {
429   - match d {
430   - Direction::Left => self.left(v),
431   - Direction::Right => self.right(v),
432   - }
433   - }
434   -
435   - fn next_y(&self, c :usize, d :Direction) -> Option<usize> {
436   - fn inner<T>( p :&Polygon<T>
437   - , c :usize
438   - , n :usize
439   - , d :Direction) -> Option<usize>
440   - where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
441   - + Copy + Debug + From<i32> {
442   - if c == n {
443   - None
444   - } else {
445   - let Coordinate(_, cy, _) = p.vertex(c);
446   - let Coordinate(_, ny, _) = p.vertex(n);
447   -
448   - if ny < cy { None } else { Some(n) }
449   - }
450   - }
451   -
452   - inner(self, c, self.step(c, d), d)
453   - }
454   -
455   - pub fn debug(&self) {
456   - let mut left = self.left_vertices();
457   - let mut right = self.right_vertices();
458   -
459   - if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() {
460   - let left :Vec<Coordinate<T>> = self.left_vertices().collect();
461   - let right :Vec<Coordinate<T>> = self.right_vertices().collect();
462   -
463   - println!("===");
464   - println!("== poly : {:?}", self);
465   - println!("== ltop : {:?}", self.vert_min(Direction::Left));
466   - println!("== rtop : {:?}", self.vert_min(Direction::Right));
467   - println!("== left : {:?}", left);
468   - println!("== right : {:?}", right);
469   - println!("===");
470   - }
471   - }
472   -}
473   -
474   -impl<T> Drawable<T> for Polygon<T>
475   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
476   - + Debug + Clone + Copy + From<i32> {
477   - fn plot(&self) -> Coordinates<T> {
478   - let Polygon(Coordinates(cs)) = self;
479   -
480   - match cs[..] {
481   - [] => Coordinates(Vec::<Coordinate<T>>::new()),
482   - [a] => Coordinates(vec!(a)),
483   - [a, b] => Coordinates(a.line(&b)),
484   - _ => {
485   - let (a, b) = (cs[0], cs[1]);
486   - let mut r = a.line(&b);
487   - let mut i = b;
488   - for j in cs[2..].iter() {
489   - r.append(&mut i.line(j)[1..].to_vec());
490   - i = *j;
491   - }
492   - let mut j = a.line(&i);
493   - let l = j.len();
494   - if l > 1 {
495   - r.append(&mut j[1..l-1].to_vec());
496   - }
497   - Coordinates(r)
498   - },
499   - }
500   - }
501   -}
502   -
503   -impl<T> Fillable<T> for Polygon<T>
504   -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
505   - + Debug + Clone + Copy + From<i32> {
506   - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {
507   - let scanlines = self.left_edge().zip(self.right_edge());
508   -
509   - for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) {
510   - canvas.set_pixel(l, color);
511   - }
512   - }
513   -}
514   -
515   -impl<T> Display for Polygon<T> where T: Copy {
516   - fn fmt(&self, f: &mut Formatter<'_>) -> Result {
517   - let Polygon(a) = self;
518   - write!(f, "Poly[{}]", a)
519   - }
520   -}
1   -//
2   -// Basic geometric things...
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -use std::convert::{From, Into};
22   -use std::ops::{Add,Sub,Neg,Mul,Div};
23   -use std::fmt::Debug;
24   -
25   -use crate::easel::{Canvas, Coordinate, Coordinates, Polygon};
26   -use crate::transform::{TMatrix, Transformable};
27   -use crate::trigonometry::Trig;
28   -use crate::vector::Vector;
29   -
30   -#[derive(Debug, Clone)]
31   -pub struct Face<T>
32   -where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
33   - corners :Vec<usize>,
34   - normal :Option<Vector<T>>,
35   -}
36   -
37   -#[derive(Debug, PartialEq, Eq, Clone, Copy)]
38   -pub struct Point<T>(pub Vector<T>, T)
39   - where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig;
40   -
41   -impl<T> Point<T>
42   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
43   - + Mul<Output = T> + Div<Output = T>
44   - + PartialEq + Trig + Copy + From<i32> {
45   - pub fn new(x :T, y :T, z :T) -> Self {
46   - Self(Vector(x, y, z), 1.into())
47   - }
48   -}
49   -
50   -impl<T> Add for Point<T>
51   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
52   - + Mul<Output = T> + Div<Output = T>
53   - + PartialEq + Trig + Copy {
54   - type Output = Self;
55   -
56   - fn add(self, other :Self) -> Self {
57   - let Point(v1, w1) = self;
58   - let Point(v2, w2) = other;
59   - Self(v1 + v2, w1 + w2)
60   - }
61   -}
62   -
63   -impl<T> Neg for Point<T>
64   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
65   - + Mul<Output = T> + Div<Output = T>
66   - + PartialEq + Trig + Copy {
67   - type Output = Self;
68   -
69   - fn neg(self) -> Self {
70   - let Point(v, w) = self;
71   - Self(-v, -w)
72   - }
73   -}
74   -
75   -impl<T> Sub for Point<T>
76   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
77   - + Mul<Output = T> + Div<Output = T>
78   - + PartialEq + Trig + Copy {
79   - type Output = Self;
80   -
81   - fn sub(self, other :Self) -> Self {
82   - self + -other
83   - }
84   -}
85   -
86   -impl<T> Mul for Point<T>
87   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
88   - + Mul<Output = T> + Div<Output = T>
89   - + PartialEq + Trig + Copy + From<i32> {
90   - type Output = Self;
91   -
92   - fn mul(self, other :Self) -> Self {
93   - let a :Vector<T> = self.into();
94   - let b :Vector<T> = other.into();
95   -
96   - Point(a * b, 1.into())
97   - }
98   -}
99   -
100   -impl<T> From<Vector<T>> for Point<T>
101   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
102   - + Mul<Output = T> + Div<Output = T>
103   - + PartialEq + Trig + Copy + From<i32> {
104   - fn from(v :Vector<T>) -> Self {
105   - Point(v, 1.into())
106   - }
107   -}
108   -
109   -impl<T> Into<Vector<T>> for Point<T>
110   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
111   - + Mul<Output = T> + Div<Output = T>
112   - + PartialEq + Trig + Copy + From<i32> {
113   - fn into(self) -> Vector<T> {
114   - let Point(v, w) = self;
115   -
116   - if w == 0.into() {
117   - v
118   - } else {
119   - v.mul(&w.recip())
120   - }
121   - }
122   -}
123   -
124   -impl<T> Transformable<T> for Point<T>
125   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
126   - + Mul<Output = T> + Div<Output = T>
127   - + PartialEq + Debug + Trig + Copy + From<i32> {
128   - fn transform(&self, m :&TMatrix<T>) -> Self {
129   - let Point(v, w) = *self;
130   - let (v, w) = m.apply(&v, w);
131   -
132   - if w == 0.into() {
133   - v.into()
134   - } else {
135   - v.mul(&w.recip()).into()
136   - }
137   - }
138   -}
139   -
140   -#[derive(Debug)]
141   -pub struct Polyeder<T>
142   -where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {
143   - points :Vec<Point<T>>,
144   - faces :Vec<Face<T>>,
145   -}
146   -
147   -pub trait Primitives<T>
148   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
149   - fn transform(&self, m :&TMatrix<T>) -> Self;
150   - fn project( &self
151   - , camera :&Camera<T>
152   - , light :&DirectLight<T>
153   - , col :u32 ) -> Vec<(Polygon<T>, u32)>;
154   -}
155   -
156   -#[derive(Debug, Clone, Copy)]
157   -pub struct Camera<T>
158   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
159   - width :T,
160   - height :T,
161   - distance :T,
162   - project :TMatrix<T>,
163   -}
164   -
165   -pub struct DirectLight<T>
166   -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
167   - direction: Vector<T>,
168   -}
169   -
170   -impl<T> Camera<T>
171   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
172   - + Mul<Output = T> + Div<Output = T>
173   - + PartialEq + Debug + Copy + Trig + From<i32> {
174   - // This code assumes that the size of the viewport is always
175   - // equal to the size of the physical screen… e.g. window/canvas thus some
176   - // effects can't be done. See book for examples with different viewport
177   - // and screen sizes.
178   - pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {
179   - let width :T = (c.width() as i32).into();
180   - let height :T = (c.height() as i32).into();
181   - let d :T = 1.into();
182   - let fov = T::cot(angle) * width;
183   - let wh = width / 2.into();
184   - let hh = height / 2.into();
185   -
186   - Camera { width: width
187   - , height: height
188   - , distance: d
189   - , project: TMatrix::new(
190   - ( fov, 0.into(), wh, 0.into())
191   - , (0.into(), fov, hh, 0.into())
192   - , (0.into(), 0.into(), d, 1.into())
193   - , (0.into(), 0.into(), 1.into(), 0.into()) ) }
194   - }
195   -
196   - pub fn get_distance(&self) -> T {
197   - self.distance
198   - }
199   -
200   - pub fn get_projection(&self) -> TMatrix<T> {
201   - self.project
202   - }
203   -
204   - pub fn project(&self, p :Point<T>) -> Point<T> {
205   - p.transform(&self.project)
206   - }
207   -}
208   -
209   -impl<T> DirectLight<T>
210   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
211   - + Mul<Output = T> + Div<Output = T>
212   - + Debug + Copy + Trig + From<i32> {
213   - pub fn new(v :Vector<T>) -> Self {
214   - DirectLight{ direction: v }
215   - }
216   -
217   - pub fn dir(&self) -> Vector<T> {
218   - self.direction
219   - }
220   -}
221   -
222   -impl<T> Face<T>
223   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
224   - + Mul<Output = T> + Div<Output = T>
225   - + PartialEq + Debug + Copy + Trig + From<i32> {
226   - fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {
227   - let mut f = Face{ corners: corners, normal: None };
228   - f.update_normal(ps);
229   - f
230   - }
231   -
232   - fn update_normal(&mut self, ps :&[Point<T>]) {
233   - let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();
234   - let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();
235   - self.normal = Some(edge10 * edge12);
236   - }
237   -}
238   -
239   -impl<T> Polyeder<T>
240   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
241   - + Mul<Output = T> + Div<Output = T>
242   - + PartialEq + Debug + Copy + Trig + From<i32> {
243   - fn update_normals(&mut self) {
244   - for f in self.faces.iter_mut() {
245   - f.update_normal(&self.points);
246   - }
247   - }
248   -
249   - // construct via cube, see polyhedra.pdf
250   - pub fn tetrahedron(a :T) -> Polyeder<T> {
251   - let f2 :T = 2.into();
252   - let ch = a / (f2 * T::sqrt(f2).unwrap());
253   -
254   - let ps = vec!( Point::new(-ch, -ch, ch) // A
255   - , Point::new(-ch, ch, -ch) // C
256   - , Point::new( ch, -ch, -ch) // E
257   - , Point::new( ch, ch, ch) ); // G
258   -
259   - // bottom: 1, 2, 3
260   - let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom
261   - , Face::new(vec!(3, 2, 0), &ps)
262   - , Face::new(vec!(0, 1, 3), &ps)
263   - , Face::new(vec!(1, 2, 3), &ps) );
264   - //let fs = vec!( Face::new(vec!(0, 1, 2), &ps) // bottom
265   - // , Face::new(vec!(0, 2, 3), &ps)
266   - // , Face::new(vec!(3, 1, 0), &ps)
267   - // , Face::new(vec!(3, 2, 1), &ps) );
268   -
269   - Polyeder{ points: ps, faces: fs }
270   - }
271   -
272   - pub fn triangle(a :T) -> Polyeder<T> {
273   - let f0 :T = 0.into();
274   - let f3 :T = 3.into();
275   - let f6 :T = 6.into();
276   - let zi :T = T::sqrt(f3).unwrap() / f6 * a;
277   - let zc :T = T::sqrt(f3).unwrap() / f3 * a;
278   - let ah :T = a / 2.into();
279   -
280   - let ps = vec!( Point::new(-ah, f0, -zi)
281   - , Point::new( f0, f0, zc)
282   - , Point::new( ah, f0, -zi) );
283   -
284   - let fs = vec!(Face::new(vec!(0, 1, 2), &ps));
285   -
286   - Polyeder{ points: ps, faces: fs }
287   - }
288   -
289   - pub fn cube(a :T) -> Polyeder<T> {
290   - let ah :T = a / From::<i32>::from(2);
291   -
292   - let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1
293   - , Point::new(-ah, -ah, -ah) // 1 => front 2
294   - , Point::new( ah, -ah, -ah) // 2 => front 3
295   - , Point::new( ah, ah, -ah) // 3 => front 4
296   - , Point::new(-ah, ah, ah) // 4 => back 1
297   - , Point::new(-ah, -ah, ah) // 5 => back 2
298   - , Point::new( ah, -ah, ah) // 6 => back 3
299   - , Point::new( ah, ah, ah) ); // 7 => back 4
300   -
301   - let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front
302   - , Face::new(vec!(7, 6, 5, 4), &ps) // back
303   - , Face::new(vec!(1, 5, 6, 2), &ps) // top
304   - , Face::new(vec!(0, 3, 7, 4), &ps) // bottom
305   - , Face::new(vec!(0, 4, 5, 1), &ps) // left
306   - , Face::new(vec!(2, 6, 7, 3), &ps) ); // right
307   -
308   - Polyeder{ points: ps, faces: fs }
309   - }
310   -}
311   -
312   -impl<T> Primitives<T> for Polyeder<T>
313   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
314   - + Mul<Output = T> + Div<Output = T>
315   - + Debug + Copy + Trig + From<i32> + PartialOrd {
316   - // TODO Maybe this should also be an instance of Transformable…
317   - fn transform(&self, m :&TMatrix<T>) -> Self {
318   - let Polyeder{ points: ps, faces: fs } = self;
319   -
320   - let mut p = Polyeder{
321   - points: ps.iter().map(|p| p.transform(m)).collect()
322   - , faces: fs.to_vec()
323   - };
324   -
325   - // TODO alternatively we could rotate the normals too, but this cannot
326   - // done with the original matrix… the question is, what is faster.
327   - p.update_normals();
328   - p
329   - }
330   -
331   - fn project( &self
332   - , camera :&Camera<T>
333   - , light :&DirectLight<T>
334   - , color :u32 ) -> Vec<(Polygon<T>, u32)> {
335   - // Helper to create a Polygon from Coordinates…
336   - // TODO probably there needs to be a Polygon constructor for this.
337   - fn polygon<I, T>(c :I) -> Polygon<T>
338   - where I: Iterator<Item = Coordinate<T>> {
339   - Polygon(Coordinates(c.collect()))
340   - }
341   -
342   - // this one does the projection... as the projection was the last
343   - // matrix we do not need to do it here.
344   - let to_coord = |p :&usize| {
345   - let Point(v, _) = camera.project(self.points[*p]);
346   - Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())
347   - };
348   - let to_poly = |f :&Face<T>| {
349   - let pg = polygon(f.corners.iter().map(to_coord));
350   - let mut r :T = (((color >> 16) & 0xFF) as i32).into();
351   - let mut g :T = (((color >> 8) & 0xFF) as i32).into();
352   - let mut b :T = (((color ) & 0xFF) as i32).into();
353   - let lf :T = match f.normal {
354   - None => 1.into(),
355   - Some(n) => n.dot(light.dir())
356   - / (n.mag() * light.dir().mag()),
357   - };
358   -
359   - // this "if" represents a first simple backface culling
360   - // approach. We only return face that face towards us.
361   - if lf < 0.into() {
362   - r = r * -lf;
363   - g = g * -lf;
364   - b = b * -lf;
365   -
366   - let c :u32 = (r.round() as u32) << 16
367   - | (g.round() as u32) << 8
368   - | (b.round() as u32);
369   -
370   - Some((pg, c))
371   - } else {
372   - None
373   - }};
374   -
375   - self.faces.iter().filter_map(to_poly).collect()
376   - }
377   -}
1   -extern crate lazy_static;
2   -
3   -pub type Error = &'static str;
4   -
5   -pub mod easel;
6   -pub mod transform;
7   -pub mod trigonometry;
8   -pub mod vector;
9   -pub mod geometry;
10   -
11   -mod utils;
12   -
13   -use vector::Vector;
14   -use easel::{Canvas, Coordinate, Drawable, Fillable};
15   -use geometry::{Camera, DirectLight, Polyeder, Primitives};
16   -use transform::{TMatrix};
17   -
18   -use std::fmt::{Display, Formatter, Result};
19   -use std::sync::mpsc;
20   -use std::time::Instant;
21   -use wasm_bindgen::prelude::*;
22   -
23   -// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
24   -// allocator.
25   -#[cfg(feature = "wee_alloc")]
26   -#[global_allocator]
27   -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
28   -
29   -#[wasm_bindgen]
30   -#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31   -pub struct Color(u8, u8, u8, u8);
32   -
33   -#[wasm_bindgen]
34   -pub struct View3d { width :u16
35   - , height :u16
36   - , size :usize
37   - , degree :i32
38   - //, start :Instant
39   - , tetrahedron :Polyeder<f64>
40   - , cube :Polyeder<f64>
41   - , camera :Option<Camera<f64>>
42   - , light :DirectLight<f64>
43   - , zbuf :Vec<f64>
44   - , image :Vec<Color>
45   -}
46   -
47   -#[wasm_bindgen]
48   -impl View3d {
49   - pub fn new(width :u16, height :u16) -> Self {
50   - let size = width as usize * height as usize;
51   - let light_vector = Vector(0.0, 0.0, 1.0);
52   -
53   - let mut view3d = Self { width: width
54   - , height: height
55   - , size: size
56   - , degree: 0
57   - //, start: Instant::now()
58   - , tetrahedron: Polyeder::tetrahedron(100.0)
59   - , cube: Polyeder::cube(56.25)
60   - , camera: None
61   - , light: DirectLight::new(light_vector)
62   - , zbuf: vec!(0.0; size)
63   - , image: vec!(Color(0, 0, 0, 0xFF); size)
64   - };
65   -
66   - view3d.camera = Some(Camera::<f64>::new(&view3d, 45));
67   - view3d
68   - }
69   -
70   - pub fn width(&self) -> u16 {
71   - self.width
72   - }
73   -
74   - pub fn height(&self) -> u16 {
75   - self.height
76   - }
77   -
78   - pub fn update(&mut self) {
79   - //let deg = ((self.start.elapsed() / 25).as_millis() % 360) as i32;
80   - let t = TMatrix::translate(Vector(0.0, 0.0, 150.0));
81   - let rz = TMatrix::rotate_z(self.degree);
82   - let rx = TMatrix::rotate_x(-self.degree*2);
83   - let ry = TMatrix::rotate_y(-self.degree*2);
84   -
85   - let rot1 = TMatrix::combine(vec!(rz, rx, t));
86   - let rot2 = TMatrix::combine(vec!(rz, ry, t));
87   -
88   - let objects = vec!( (self.tetrahedron.transform(&rot1), 0xFFFF00)
89   - , ( self.cube.transform(&rot2), 0x0000FF) );
90   -
91   - self.degree = (self.degree + 1) % 360;
92   -
93   - self.clear();
94   -
95   - match self.camera {
96   - None => {},
97   - Some(camera) => {
98   - for (o, color) in objects {
99   - for (pg, c) in o.project(&camera, &self.light, color) {
100   - (&pg).fill(self, c);
101   - }
102   - }
103   - },
104   - }
105   - }
106   -
107   - pub fn image(&self) -> *const Color {
108   - self.image.as_ptr()
109   - }
110   -}
111   -
112   -impl Canvas<f64> for View3d {
113   - fn width(&self) -> u16 {
114   - self.width
115   - }
116   -
117   - fn height(&self) -> u16 {
118   - self.height
119   - }
120   -
121   - fn clear(&mut self) {
122   - self.zbuf = vec!(0.0; self.size);
123   - self.image = vec!(Color(0, 0, 0, 0xFF); self.size);
124   - }
125   -
126   - fn set_pixel(&mut self, c :Coordinate<f64>, color :u32) {
127   - let Coordinate(x, y, zr) = c;
128   - let idx :usize = (y * (self.width as i32) + x) as usize;
129   -
130   - let r = ((color >> 16) & 0xFF) as u8;
131   - let g = ((color >> 8) & 0xFF) as u8;
132   - let b = ( color & 0xFF) as u8;
133   -
134   - if self.zbuf[idx] < zr {
135   - self.zbuf[idx] = zr;
136   - self.image[idx] = Color(r, g, b, 0xFF);
137   - }
138   - }
139   -
140   - // Empty implementations for now… mostly not needed because it is
141   - // done from JavaScript…
142   - fn init_events(&self) {}
143   - fn start_events(&self, _ :mpsc::Sender<i32>) {}
144   - fn draw( &mut self, _ :&dyn Drawable<f64>, _ :Coordinate<f64>, _ :u32 ) {}
145   - fn put_text(&self, _ :Coordinate<f64>, _ :&str) {}
146   - fn show(&self) {}
147   -}
148   -
149   -#[wasm_bindgen]
150   -#[repr(u8)]
151   -#[derive(Clone, Copy, Debug, PartialEq, Eq)]
152   -pub enum Cell {
153   - Dead = 0,
154   - Alive = 1,
155   -}
156   -
157   -#[wasm_bindgen]
158   -pub struct Universe {
159   - width :u32,
160   - height :u32,
161   - cells :Vec<Cell>,
162   -}
163   -
164   -#[wasm_bindgen]
165   -impl Universe {
166   - pub fn new() -> Universe {
167   - let width = 64;
168   - let height = 64;
169   -
170   - let init_cells = |i :u32| {
171   - if i % 2 == 0 || i % 7 == 0 { Cell::Alive } else { Cell::Dead }
172   - };
173   -
174   - let cells = (0..width * height).map(init_cells).collect();
175   -
176   - Universe {
177   - width: width,
178   - height: height,
179   - cells: cells,
180   - }
181   - }
182   -
183   - pub fn width(&self) -> u32 {
184   - self.width
185   - }
186   -
187   - pub fn height(&self) -> u32 {
188   - self.height
189   - }
190   -
191   - pub fn cells(&self) -> *const Cell {
192   - self.cells.as_ptr()
193   - }
194   -
195   - pub fn render(&self) -> String {
196   - self.to_string()
197   - }
198   -
199   - pub fn tick(&mut self) {
200   - let mut next = self.cells.clone();
201   -
202   - for row in 0..self.height {
203   - for col in 0..self.width {
204   - let idx = self.get_index(row, col);
205   - let cell = self.cells[idx];
206   - let live_neighbors = self.live_neighbor_count(row, col);
207   -
208   - // Game of life rules....
209   - let next_cell = match (cell, live_neighbors) {
210   - (Cell::Alive, 2) |
211   - (Cell::Alive, 3) => Cell::Alive,
212   - (Cell::Alive, _) => Cell::Dead,
213   - ( Cell::Dead, 3) => Cell::Alive,
214   - ( otherwise, _) => otherwise,
215   - };
216   -
217   - next[idx] = next_cell;
218   - }
219   - }
220   -
221   - self.cells = next;
222   - }
223   -
224   - fn get_index(&self, row :u32, col :u32) -> usize {
225   - (row * self.width + col) as usize
226   - }
227   -
228   - fn live_neighbor_count(&self, row :u32, col :u32) -> u8 {
229   - let mut count = 0;
230   -
231   - for delta_row in [self.height - 1, 0, 1].iter().cloned() {
232   - for delta_col in [self.width - 1, 0, 1].iter().cloned() {
233   - if delta_row == 0 && delta_col == 0 {
234   - continue;
235   - }
236   -
237   - let neighbor_row = (row + delta_row) % self.height;
238   - let neighbor_col = (col + delta_col) % self.width;
239   - let idx = self.get_index(neighbor_row, neighbor_col);
240   - count += self.cells[idx] as u8;
241   - }
242   - }
243   -
244   - count
245   - }
246   -}
247   -
248   -impl Display for Universe {
249   - fn fmt(&self, f :&mut Formatter) -> Result {
250   - for line in self.cells.as_slice().chunks(self.width as usize) {
251   - for &cell in line {
252   - let symbol = match cell {
253   - Cell::Dead => ' ',
254   - Cell::Alive => '*',
255   - };
256   - write!(f, "{}", symbol)?;
257   - }
258   - write!(f, "\n")?;
259   - }
260   -
261   - Ok(())
262   - }
263   -}
1   -//
2   -// Transformation of vectors in a given coordinate system...
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -use std::ops::{Add, Sub, Neg, Mul, Div};
22   -use std::fmt::Debug;
23   -
24   -use crate::Vector;
25   -use crate::trigonometry::Trig;
26   -
27   -#[derive(Debug, Clone, Copy)]
28   -pub struct TMatrix<T>( (T, T, T, T)
29   - , (T, T, T, T)
30   - , (T, T, T, T)
31   - , (T, T, T, T) )
32   - where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy;
33   -
34   -pub trait Transformable<T>
35   -where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy {
36   - fn transform(&self, m :&TMatrix<T>) -> Self;
37   -}
38   -
39   -impl<T> TMatrix<T>
40   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
41   - + Mul<Output = T> + Div<Output = T>
42   - + Debug + Trig + From<i32> + Copy {
43   - pub fn new( r1 :(T, T, T, T)
44   - , r2 :(T, T, T, T)
45   - , r3 :(T, T, T, T)
46   - , r4 :(T, T, T, T) ) -> Self {
47   - TMatrix(r1, r2, r3, r4)
48   - }
49   -
50   - pub fn unit() -> Self {
51   - Self::new( (1.into(), 0.into(), 0.into(), 0.into())
52   - , (0.into(), 1.into(), 0.into(), 0.into())
53   - , (0.into(), 0.into(), 1.into(), 0.into())
54   - , (0.into(), 0.into(), 0.into(), 1.into()) )
55   - }
56   -
57   - pub fn translate(v :Vector<T>) -> Self {
58   - let Vector(x, y, z) = v;
59   -
60   - Self::new( (1.into(), 0.into(), 0.into(), x)
61   - , (0.into(), 1.into(), 0.into(), y)
62   - , (0.into(), 0.into(), 1.into(), z)
63   - , (0.into(), 0.into(), 0.into(), 1.into()) )
64   - }
65   -
66   - pub fn rotate_x(a :i32) -> Self {
67   - let sin :T = Trig::sin(a);
68   - let cos :T = Trig::cos(a);
69   -
70   - Self::new( (1.into(), 0.into(), 0.into(), 0.into())
71   - , (0.into(), cos , -sin , 0.into())
72   - , (0.into(), sin , cos , 0.into())
73   - , (0.into(), 0.into(), 0.into(), 1.into()) )
74   - }
75   -
76   - pub fn rotate_y(a :i32) -> Self {
77   - let sin :T = Trig::sin(a);
78   - let cos :T = Trig::cos(a);
79   -
80   - Self::new( (cos , 0.into(), sin , 0.into())
81   - , (0.into(), 1.into(), 0.into(), 0.into())
82   - , (-sin , 0.into(), cos , 0.into())
83   - , (0.into(), 0.into(), 0.into(), 1.into()) )
84   - }
85   -
86   - pub fn rotate_z(a :i32) -> Self {
87   - let sin :T = Trig::sin(a);
88   - let cos :T = Trig::cos(a);
89   -
90   - Self::new( (cos , -sin , 0.into(), 0.into())
91   - , (sin , cos , 0.into(), 0.into())
92   - , (0.into(), 0.into(), 1.into(), 0.into())
93   - , (0.into(), 0.into(), 0.into(), 1.into()) )
94   - }
95   -
96   - pub fn rotate_v(v :&Vector<T>, a :i32) -> Self {
97   - let Vector(x, y, z) = *v;
98   -
99   - let sin :T = Trig::sin(a);
100   - let cos :T = Trig::cos(a);
101   -
102   - let zero :T = 0.into();
103   - let one :T = 1.into();
104   -
105   - Self::new( ( (one - cos) * x * x + cos
106   - , (one - cos) * x * y - sin * z
107   - , (one - cos) * x * z + sin * y
108   - , zero )
109   - , ( (one - cos) * x * y + sin * z
110   - , (one - cos) * y * y + cos
111   - , (one - cos) * y * z - sin * x
112   - , zero )
113   - , ( (one - cos) * x * z - sin * y
114   - , (one - cos) * y * z + sin * x
115   - , (one - cos) * z * z + cos
116   - , zero )
117   - , (0.into(), 0.into(), 0.into(), 1.into()) )
118   - }
119   -
120   - pub fn scale(v :Vector<T>) -> Self {
121   - let Vector(x, y, z) = v;
122   -
123   - Self::new( ( x, 0.into(), 0.into(), 0.into())
124   - , (0.into(), y, 0.into(), 0.into())
125   - , (0.into(), 0.into(), z, 0.into())
126   - , (0.into(), 0.into(), 0.into(), 1.into()) )
127   - }
128   -
129   - pub fn combine<I>(mi :I) -> TMatrix<T>
130   - where I: IntoIterator<Item = TMatrix<T>> {
131   -
132   - mi.into_iter().fold(Self::unit(), |acc, x| x * acc)
133   - }
134   -
135   - pub fn apply(&self, v :&Vector<T>, w :T) -> (Vector<T>, T) {
136   - let TMatrix( (a11, a12, a13, a14)
137   - , (a21, a22, a23, a24)
138   - , (a31, a32, a33, a34)
139   - , (a41, a42, a43, a44) ) = *self;
140   - let Vector(x, y, z) = *v;
141   -
142   - let v = Vector( a11 * x + a12 * y + a13 * z + a14 * w
143   - , a21 * x + a22 * y + a23 * z + a24 * w
144   - , a31 * x + a32 * y + a33 * z + a34 * w );
145   - let w = a41 * x + a42 * y + a43 * z + a44 * w;
146   -
147   - //v.mul(&w.recip())
148   - (v, w)
149   - }
150   -}
151   -
152   -impl<T> Mul for TMatrix<T>
153   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
154   - + Mul<Output = T> + Div<Output = T>
155   - + Debug + Trig + From<i32> + Copy {
156   - type Output = Self;
157   -
158   - // ATTENTION: This is not commutative, nor assoziative.
159   - fn mul(self, other :Self) -> Self {
160   - let TMatrix( (a11, a12, a13, a14)
161   - , (a21, a22, a23, a24)
162   - , (a31, a32, a33, a34)
163   - , (a41, a42, a43, a44) ) = self;
164   - let TMatrix( (b11, b12, b13, b14)
165   - , (b21, b22, b23, b24)
166   - , (b31, b32, b33, b34)
167   - , (b41, b42, b43, b44) ) = other;
168   -
169   - TMatrix( ( a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41
170   - , a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42
171   - , a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43
172   - , a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44 )
173   - , ( a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41
174   - , a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42
175   - , a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43
176   - , a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44 )
177   - , ( a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41
178   - , a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42
179   - , a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43
180   - , a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44 )
181   - , ( a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41
182   - , a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42
183   - , a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43
184   - , a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44 ) )
185   - }
186   -}
1   -//
2   -// Some trigonometic functions with Fractions results.
3   -// Currently only sin, cos and tan are implemented.
4   -// As I was unable to find a really good integral approximation for them I
5   -// implement them as a table which is predefined using the floating point
6   -// function f64::sin and then transformed into a fraction of a given
7   -// PRECISION.
8   -// These approximations are quite good and for a few edge cases
9   -// even better than the floating point implementations.
10   -//
11   -// Georg Hopp <georg@steffers.org>
12   -//
13   -// Copyright © 2019 Georg Hopp
14   -//
15   -// This program is free software: you can redistribute it and/or modify
16   -// it under the terms of the GNU General Public License as published by
17   -// the Free Software Foundation, either version 3 of the License, or
18   -// (at your option) any later version.
19   -//
20   -// This program is distributed in the hope that it will be useful,
21   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
22   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23   -// GNU General Public License for more details.
24   -//
25   -// You should have received a copy of the GNU General Public License
26   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
27   -//
28   -use std::ops::Div;
29   -use std::ops::Neg;
30   -use std::marker::Sized;
31   -use crate::Error;
32   -
33   -pub trait Trig {
34   - fn pi() -> Self;
35   - fn recip(self) -> Self;
36   - fn round(&self) -> i32;
37   - fn sqrt(self) -> Result<Self, Error> where Self: Sized;
38   - fn sintab() -> Vec<Self> where Self: Sized;
39   - fn tantab() -> Vec<Self> where Self: Sized;
40   -
41   - fn sin(d :i32) -> Self
42   - where Self: Sized + Neg<Output = Self> + Copy {
43   - match d {
44   - 0 ..=90 => Self::sintab()[d as usize],
45   - 91 ..=180 => Self::sintab()[180 - d as usize],
46   - 181..=270 => -Self::sintab()[d as usize - 180],
47   - 271..=359 => -Self::sintab()[360 - d as usize],
48   - _ => {
49   - Self::sin(if d < 0 { d % 360 + 360 } else { d % 360 })
50   - },
51   - }
52   - }
53   -
54   - fn cos(d :i32) -> Self
55   - where Self: Sized + Neg<Output = Self> + Copy {
56   - match d {
57   - 0 ..=90 => Self::sintab()[90 - d as usize],
58   - 91 ..=180 => -Self::sintab()[90 - (180 - d as usize)],
59   - 181..=270 => -Self::sintab()[90 - (d as usize - 180)],
60   - 271..=359 => Self::sintab()[90 - (360 - d as usize)],
61   - _ => {
62   - Self::cos(if d < 0 { d % 360 + 360 } else { d % 360 })
63   - },
64   - }
65   - }
66   -
67   - fn tan(d :i32) -> Self where Self: Sized + Copy {
68   - match d {
69   - 0 ..=179 => Self::tantab()[d as usize],
70   - 180..=359 => Self::tantab()[d as usize - 180],
71   - _ => {
72   - Self::tan(if d < 0 { d % 360 + 360 } else { d % 360 })
73   - },
74   - }
75   - }
76   -
77   - fn cot(d :i32) -> Self
78   - where Self: Sized + Copy + From<i32> + Div<Output = Self> {
79   - Into::<Self>::into(1) / Self::tan(d)
80   - }
81   -}
82   -
83   -impl Trig for f64 {
84   - fn pi() -> Self {
85   - std::f64::consts::PI
86   - }
87   -
88   - fn recip(self) -> Self {
89   - self.recip()
90   - }
91   -
92   - fn round(&self) -> i32 {
93   - f64::round(*self) as i32
94   - }
95   -
96   - fn sqrt(self) -> Result<Self, Error> {
97   - let x = self.sqrt();
98   - match x.is_nan() {
99   - true => Err("sqrt on negative undefined"),
100   - false => Ok(x),
101   - }
102   - }
103   -
104   - fn sintab() -> Vec<Self> {
105   - lazy_static::lazy_static! {
106   - static ref SINTAB :Vec<f64> =
107   - (0..=90).map(|x| _sin(x)).collect();
108   - }
109   -
110   - // f64 sin. (From 0° to 90°)
111   - fn _sin(d: u32) -> f64 {
112   - match d {
113   - 0 => 0.0,
114   - 90 => 1.0,
115   - _ => (d as f64).to_radians().sin(),
116   - }
117   - }
118   -
119   - SINTAB.to_vec()
120   - }
121   -
122   - fn tantab() -> Vec<Self> {
123   - // This table exists only because the sin(α) / cos(α) method
124   - // yields very large unreducable denominators in a lot of cases.
125   - lazy_static::lazy_static! {
126   - static ref TANTAB :Vec<f64> =
127   - (0..180).map(|x| _tan(x)).collect();
128   - }
129   -
130   - // fractional tan from f64 tan. (From 0° to 179°)
131   - fn _tan(d: u32) -> f64 {
132   - match d {
133   - 0 => 0.0,
134   - 45 => 1.0,
135   - 90 => std::f64::INFINITY,
136   - 135 => -1.0,
137   - _ => (d as f64).to_radians().tan(),
138   - }
139   - }
140   -
141   - TANTAB.to_vec()
142   - }
143   -}
1   -pub fn set_panic_hook() {
2   - // When the `console_error_panic_hook` feature is enabled, we can call the
3   - // `set_panic_hook` function at least once during initialization, and then
4   - // we will get better error messages if our code ever panics.
5   - //
6   - // For more details see
7   - // https://github.com/rustwasm/console_error_panic_hook#readme
8   - #[cfg(feature = "console_error_panic_hook")]
9   - console_error_panic_hook::set_once();
10   -}
1   -//
2   -// Stuff for manipulating 3 dimensional vectors.
3   -//
4   -// Georg Hopp <georg@steffers.org>
5   -//
6   -// Copyright © 2019 Georg Hopp
7   -//
8   -// This program is free software: you can redistribute it and/or modify
9   -// it under the terms of the GNU General Public License as published by
10   -// the Free Software Foundation, either version 3 of the License, or
11   -// (at your option) any later version.
12   -//
13   -// This program is distributed in the hope that it will be useful,
14   -// but WITHOUT ANY WARRANTY; without even the implied warranty of
15   -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16   -// GNU General Public License for more details.
17   -//
18   -// You should have received a copy of the GNU General Public License
19   -// along with this program. If not, see <http://www.gnu.org/licenses/>.
20   -//
21   -use std::fmt::{Debug, Display, Formatter, Result};
22   -use std::ops::{Add, Sub, Neg, Mul, Div};
23   -
24   -use crate::trigonometry::Trig;
25   -use crate::transform::{TMatrix, Transformable};
26   -
27   -#[derive(Debug, Eq, Clone, Copy)]
28   -pub struct Vector<T>(pub T, pub T, pub T)
29   - where T: Add + Sub + Neg + Mul + Div + Trig + Copy;
30   -
31   -impl<T> Vector<T>
32   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
33   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
34   - pub fn x(self) -> T { self.0 }
35   - pub fn y(self) -> T { self.1 }
36   - pub fn z(self) -> T { self.2 }
37   -
38   - pub fn mag(self) -> T {
39   - let Vector(x, y, z) = self;
40   - (x * x + y * y + z * z).sqrt().unwrap()
41   - }
42   -
43   - pub fn mul(self, s :&T) -> Self {
44   - let Vector(x, y, z) = self;
45   - Vector(x * *s, y * *s, z * *s)
46   - }
47   -
48   - pub fn dot(self, other :Self) -> T {
49   - let Vector(x1, y1, z1) = self;
50   - let Vector(x2, y2, z2) = other;
51   -
52   - x1 * x2 + y1 * y2 + z1 * z2
53   - }
54   -
55   - pub fn norm(self) -> Self {
56   - // TODO This can result in 0 or inf Vectors…
57   - // Maybe we need to handle zero and inf magnitude here…
58   - self.mul(&self.mag().recip())
59   - }
60   -
61   - pub fn distance(self, other :Self) -> T {
62   - (self - other).mag()
63   - }
64   -}
65   -
66   -impl<T> Display for Vector<T>
67   -where T: Add + Sub + Neg + Mul + Div + Trig + Display + Copy {
68   - fn fmt(&self, f :&mut Formatter<'_>) -> Result {
69   - let Vector(x, y, z) = self;
70   - write!(f, "({}, {}, {})", x, y, z)
71   - }
72   -}
73   -
74   -impl<T> PartialEq for Vector<T>
75   -where T: Add + Sub + Neg + Mul + Div + Trig + PartialEq + Copy {
76   - fn eq(&self, other :&Self) -> bool {
77   - let Vector(x1, y1, z1) = self;
78   - let Vector(x2, y2, z2) = other;
79   - x1 == x2 && y1 == y2 && z1 == z2
80   - }
81   -}
82   -
83   -impl<T> Add for Vector<T>
84   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
85   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
86   - type Output = Self;
87   -
88   - fn add(self, other :Self) -> Self {
89   - let Vector(x1, y1, z1) = self;
90   - let Vector(x2, y2, z2) = other;
91   - Vector(x1 + x2, y1 + y2, z1 + z2)
92   - }
93   -}
94   -
95   -impl<T> Sub for Vector<T>
96   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
97   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
98   - type Output = Self;
99   -
100   - fn sub(self, other :Self) -> Self {
101   - self + -other
102   - }
103   -}
104   -
105   -impl<T> Neg for Vector<T>
106   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
107   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
108   - type Output = Self;
109   -
110   - fn neg(self) -> Self {
111   - let Vector(x, y, z) = self;
112   - Self(-x, -y, -z)
113   - }
114   -}
115   -
116   -impl<T> Mul for Vector<T>
117   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
118   - + Mul<Output = T> + Div<Output = T> + Trig + Copy {
119   - type Output = Self;
120   -
121   - fn mul(self, other :Self) -> Self {
122   - let Vector(ax, ay, az) = self;
123   - let Vector(bx, by, bz) = other;
124   -
125   - Vector( ay * bz - az * by
126   - , az * bx - ax * bz
127   - , ax * by - ay * bx )
128   - }
129   -}
130   -
131   -impl<T> Transformable<T> for Vector<T>
132   -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
133   - + Mul<Output = T> + Div<Output = T>
134   - + Trig + Copy + Debug + From<i32> {
135   - fn transform(&self, m :&TMatrix<T>) -> Self {
136   - let (v, _) = m.apply(self, 0.into());
137   - v
138   - }
139   -}
1   -//! Test suite for the Web and headless browsers.
2   -
3   -#![cfg(target_arch = "wasm32")]
4   -
5   -extern crate wasm_bindgen_test;
6   -use wasm_bindgen_test::*;
7   -
8   -wasm_bindgen_test_configure!(run_in_browser);
9   -
10   -#[wasm_bindgen_test]
11   -fn pass() {
12   - assert_eq!(1 + 1, 2);
13   -}
1   -#!/usr/bin/env node
2   -
3   -const { spawn } = require("child_process");
4   -const fs = require("fs");
5   -
6   -let folderName = '.';
7   -
8   -if (process.argv.length >= 3) {
9   - folderName = process.argv[2];
10   - if (!fs.existsSync(folderName)) {
11   - fs.mkdirSync(folderName);
12   - }
13   -}
14   -
15   -const clone = spawn("git", ["clone", "https://github.com/rustwasm/create-wasm-app.git", folderName]);
16   -
17   -clone.on("close", code => {
18   - if (code !== 0) {
19   - console.error("cloning the template failed!")
20   - process.exit(code);
21   - } else {
22   - console.log("🦀 Rust + 🕸 Wasm = ❤");
23   - }
24   -});
1   -<div align="center">
2   -
3   - <h1><code>create-wasm-app</code></h1>
4   -
5   - <strong>An <code>npm init</code> template for kick starting a project that uses NPM packages containing Rust-generated WebAssembly and bundles them with Webpack.</strong>
6   -
7   - <p>
8   - <a href="https://travis-ci.org/rustwasm/create-wasm-app"><img src="https://img.shields.io/travis/rustwasm/create-wasm-app.svg?style=flat-square" alt="Build Status" /></a>
9   - </p>
10   -
11   - <h3>
12   - <a href="#usage">Usage</a>
13   - <span> | </span>
14   - <a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
15   - </h3>
16   -
17   - <sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
18   -</div>
19   -
20   -## About
21   -
22   -This template is designed for depending on NPM packages that contain
23   -Rust-generated WebAssembly and using them to create a Website.
24   -
25   -* Want to create an NPM package with Rust and WebAssembly? [Check out
26   - `wasm-pack-template`.](https://github.com/rustwasm/wasm-pack-template)
27   -* Want to make a monorepo-style Website without publishing to NPM? Check out
28   - [`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template)
29   - and/or
30   - [`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template).
31   -
32   -## 🚴 Usage
33   -
34   -```
35   -npm init wasm-app
36   -```
37   -
38   -## 🔋 Batteries Included
39   -
40   -- `.gitignore`: ignores `node_modules`
41   -- `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you
42   -- `README.md`: the file you are reading now!
43   -- `index.html`: a bare bones html document that includes the webpack bundle
44   -- `index.js`: example js file with a comment showing how to import and use a wasm pkg
45   -- `package.json` and `package-lock.json`:
46   - - pulls in devDependencies for using webpack:
47   - - [`webpack`](https://www.npmjs.com/package/webpack)
48   - - [`webpack-cli`](https://www.npmjs.com/package/webpack-cli)
49   - - [`webpack-dev-server`](https://www.npmjs.com/package/webpack-dev-server)
50   - - defines a `start` script to run `webpack-dev-server`
51   -- `webpack.config.js`: configuration file for bundling your js with webpack
52   -
53   -## License
54   -
55   -Licensed under either of
56   -
57   -* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
58   -* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
59   -
60   -at your option.
61   -
62   -### Contribution
63   -
64   -Unless you explicitly state otherwise, any contribution intentionally
65   -submitted for inclusion in the work by you, as defined in the Apache-2.0
66   -license, shall be dual licensed as above, without any additional terms or
67   -conditions.
1   -// A dependency graph that contains any wasm must all be imported
2   -// asynchronously. This `bootstrap.js` file does the single async import, so
3   -// that no one else needs to worry about it again.
4   -import("./index.js")
5   - .catch(e => console.error("Error importing `index.js`:", e));
1   -<!DOCTYPE html>
2   -<html>
3   - <head>
4   - <meta charset="utf-8">
5   - <title>wasm-game-of-life!</title>
6   - <style>
7   - body {
8   - position: absolute;
9   - top: 0;
10   - left: 0;
11   - width: 100%;
12   - height: 100%;
13   - display: flex;
14   - flex-direction: column;
15   - align-items: center;
16   - justify-content: center;
17   - }
18   - </style>
19   - </head>
20   - <body>
21   - <canvas id="view3d"></canvas>
22   - <script src="./bootstrap.js"></script>
23   - </body>
24   -</html>
1   -import { View3d } from "wasm-game-of-life";
2   -import { memory } from "wasm-game-of-life/wasm_game_of_life_bg";
3   -
4   -// 3D canvas stuff
5   -const view3d = View3d.new(300, 300);
6   -
7   -const view3d_canvas = document.getElementById("view3d");
8   -view3d_canvas.width = view3d.width();
9   -view3d_canvas.height = view3d.height();
10   -const view3d_ctx = view3d_canvas.getContext('2d');
11   -
12   -const view3d_renderLoop = () => {
13   - view3d.update();
14   - drawView3d();
15   -
16   - requestAnimationFrame(view3d_renderLoop);
17   -}
18   -
19   -const drawView3d = () => {
20   - const view3d_imagePtr = view3d.image();
21   - const view3d_image = new ImageData(
22   - new Uint8ClampedArray( memory.buffer
23   - , view3d.image()
24   - , view3d.width() * view3d.height() * 4 )
25   - , view3d.width()
26   - , view3d.height() );
27   -
28   - view3d_ctx.putImageData(view3d_image, 0, 0);
29   -}
30   -
31   -// start everything ...
32   -view3d.update();
33   -drawView3d();
34   -requestAnimationFrame(view3d_renderLoop);
This diff could not be displayed because it is too large.
1   -{
2   - "name": "create-wasm-app",
3   - "version": "0.1.0",
4   - "description": "create an app to consume rust-generated wasm packages",
5   - "main": "index.js",
6   - "bin": {
7   - "create-wasm-app": ".bin/create-wasm-app.js"
8   - },
9   - "scripts": {
10   - "build": "webpack --config webpack.config.js",
11   - "start": "webpack-dev-server"
12   - },
13   - "repository": {
14   - "type": "git",
15   - "url": "git+https://github.com/rustwasm/create-wasm-app.git"
16   - },
17   - "keywords": [
18   - "webassembly",
19   - "wasm",
20   - "rust",
21   - "webpack"
22   - ],
23   - "author": "Ashley Williams <ashley666ashley@gmail.com>",
24   - "license": "(MIT OR Apache-2.0)",
25   - "bugs": {
26   - "url": "https://github.com/rustwasm/create-wasm-app/issues"
27   - },
28   - "homepage": "https://github.com/rustwasm/create-wasm-app#readme",
29   - "devDependencies": {
30   - "wasm-game-of-life": "file:../pkg",
31   - "hello-wasm-pack": "^0.1.0",
32   - "webpack": "^4.29.3",
33   - "webpack-cli": "^3.1.0",
34   - "webpack-dev-server": "^3.1.5",
35   - "copy-webpack-plugin": "^5.0.0"
36   - },
37   - "dependencies": {
38   - "wasm-game-of-life": "file:../pkg"
39   - }
40   -}
1   -const CopyWebpackPlugin = require("copy-webpack-plugin");
2   -const path = require('path');
3   -
4   -module.exports = {
5   - entry: "./bootstrap.js",
6   - output: {
7   - path: path.resolve(__dirname, "dist"),
8   - filename: "bootstrap.js",
9   - },
10   - mode: "development",
11   - plugins: [
12   - new CopyWebpackPlugin(['index.html'])
13   - ],
14   -};
1   -# This file is automatically @generated by Cargo.
2   -# It is not intended for manual editing.
3   -[[package]]
4   -name = "variables"
5   -version = "0.1.0"
6   -
1   -[package]
2   -name = "variables"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8   -
9   -[dependencies]
1   -fn main() {
2   - let mut x = 5;
3   - println!("The value of x is: {}", x);
4   - x = 6;
5   - println!("The value of x is: {}", x);
6   -}
1   -install:
2   - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
3   - - if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly
4   - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
5   - - rustc -V
6   - - cargo -V
7   -
8   -build: false
9   -
10   -test_script:
11   - - cargo test --locked
1   -bin/
2   -pkg/
3   -wasm-pack.log
1   -language: rust
2   -sudo: false
3   -
4   -cache: cargo
5   -
6   -matrix:
7   - include:
8   -
9   - # Builds with wasm-pack.
10   - - rust: beta
11   - env: RUST_BACKTRACE=1
12   - addons:
13   - firefox: latest
14   - chrome: stable
15   - before_script:
16   - - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
17   - - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
18   - - cargo install-update -a
19   - - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
20   - script:
21   - - cargo generate --git . --name testing
22   - # Having a broken Cargo.toml (in that it has curlies in fields) anywhere
23   - # in any of our parent dirs is problematic.
24   - - mv Cargo.toml Cargo.toml.tmpl
25   - - cd testing
26   - - wasm-pack build
27   - - wasm-pack test --chrome --firefox --headless
28   -
29   - # Builds on nightly.
30   - - rust: nightly
31   - env: RUST_BACKTRACE=1
32   - before_script:
33   - - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
34   - - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
35   - - cargo install-update -a
36   - - rustup target add wasm32-unknown-unknown
37   - script:
38   - - cargo generate --git . --name testing
39   - - mv Cargo.toml Cargo.toml.tmpl
40   - - cd testing
41   - - cargo check
42   - - cargo check --target wasm32-unknown-unknown
43   - - cargo check --no-default-features
44   - - cargo check --target wasm32-unknown-unknown --no-default-features
45   - - cargo check --no-default-features --features console_error_panic_hook
46   - - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
47   - - cargo check --no-default-features --features "console_error_panic_hook wee_alloc"
48   - - cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc"
49   -
50   - # Builds on beta.
51   - - rust: beta
52   - env: RUST_BACKTRACE=1
53   - before_script:
54   - - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
55   - - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
56   - - cargo install-update -a
57   - - rustup target add wasm32-unknown-unknown
58   - script:
59   - - cargo generate --git . --name testing
60   - - mv Cargo.toml Cargo.toml.tmpl
61   - - cd testing
62   - - cargo check
63   - - cargo check --target wasm32-unknown-unknown
64   - - cargo check --no-default-features
65   - - cargo check --target wasm32-unknown-unknown --no-default-features
66   - - cargo check --no-default-features --features console_error_panic_hook
67   - - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
68   - # Note: no enabling the `wee_alloc` feature here because it requires
69   - # nightly for now.
1   -[package]
2   -name = "wasm-game-of-life"
3   -version = "0.1.0"
4   -authors = ["Georg Hopp <georg@steffers.org>"]
5   -edition = "2018"
6   -
7   -[lib]
8   -crate-type = ["cdylib", "rlib"]
9   -
10   -[features]
11   -default = ["console_error_panic_hook"]
12   -
13   -[dependencies]
14   -wasm-bindgen = "0.2"
15   -
16   -# The `console_error_panic_hook` crate provides better debugging of panics by
17   -# logging them with `console.error`. This is great for development, but requires
18   -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
19   -# code size when deploying.
20   -console_error_panic_hook = { version = "0.1.1", optional = true }
21   -
22   -# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
23   -# compared to the default allocator's ~10K. It is slower than the default
24   -# allocator, however.
25   -#
26   -# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
27   -wee_alloc = { version = "0.4.2", optional = true }
28   -
29   -[dev-dependencies]
30   -wasm-bindgen-test = "0.2"
31   -
32   -[profile.release]
33   -# Tell `rustc` to optimize for small code size.
34   -opt-level = "s"
1   - Apache License
2   - Version 2.0, January 2004
3   - http://www.apache.org/licenses/
4   -
5   -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6   -
7   -1. Definitions.
8   -
9   - "License" shall mean the terms and conditions for use, reproduction,
10   - and distribution as defined by Sections 1 through 9 of this document.
11   -
12   - "Licensor" shall mean the copyright owner or entity authorized by
13   - the copyright owner that is granting the License.
14   -
15   - "Legal Entity" shall mean the union of the acting entity and all
16   - other entities that control, are controlled by, or are under common
17   - control with that entity. For the purposes of this definition,
18   - "control" means (i) the power, direct or indirect, to cause the
19   - direction or management of such entity, whether by contract or
20   - otherwise, or (ii) ownership of fifty percent (50%) or more of the
21   - outstanding shares, or (iii) beneficial ownership of such entity.
22   -
23   - "You" (or "Your") shall mean an individual or Legal Entity
24   - exercising permissions granted by this License.
25   -
26   - "Source" form shall mean the preferred form for making modifications,
27   - including but not limited to software source code, documentation
28   - source, and configuration files.
29   -
30   - "Object" form shall mean any form resulting from mechanical
31   - transformation or translation of a Source form, including but
32   - not limited to compiled object code, generated documentation,
33   - and conversions to other media types.
34   -
35   - "Work" shall mean the work of authorship, whether in Source or
36   - Object form, made available under the License, as indicated by a
37   - copyright notice that is included in or attached to the work
38   - (an example is provided in the Appendix below).
39   -
40   - "Derivative Works" shall mean any work, whether in Source or Object
41   - form, that is based on (or derived from) the Work and for which the
42   - editorial revisions, annotations, elaborations, or other modifications
43   - represent, as a whole, an original work of authorship. For the purposes
44   - of this License, Derivative Works shall not include works that remain
45   - separable from, or merely link (or bind by name) to the interfaces of,
46   - the Work and Derivative Works thereof.
47   -
48   - "Contribution" shall mean any work of authorship, including
49   - the original version of the Work and any modifications or additions
50   - to that Work or Derivative Works thereof, that is intentionally
51   - submitted to Licensor for inclusion in the Work by the copyright owner
52   - or by an individual or Legal Entity authorized to submit on behalf of
53   - the copyright owner. For the purposes of this definition, "submitted"
54   - means any form of electronic, verbal, or written communication sent
55   - to the Licensor or its representatives, including but not limited to
56   - communication on electronic mailing lists, source code control systems,
57   - and issue tracking systems that are managed by, or on behalf of, the
58   - Licensor for the purpose of discussing and improving the Work, but
59   - excluding communication that is conspicuously marked or otherwise
60   - designated in writing by the copyright owner as "Not a Contribution."
61   -
62   - "Contributor" shall mean Licensor and any individual or Legal Entity
63   - on behalf of whom a Contribution has been received by Licensor and
64   - subsequently incorporated within the Work.
65   -
66   -2. Grant of Copyright License. Subject to the terms and conditions of
67   - this License, each Contributor hereby grants to You a perpetual,
68   - worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69   - copyright license to reproduce, prepare Derivative Works of,
70   - publicly display, publicly perform, sublicense, and distribute the
71   - Work and such Derivative Works in Source or Object form.
72   -
73   -3. Grant of Patent License. Subject to the terms and conditions of
74   - this License, each Contributor hereby grants to You a perpetual,
75   - worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76   - (except as stated in this section) patent license to make, have made,
77   - use, offer to sell, sell, import, and otherwise transfer the Work,
78   - where such license applies only to those patent claims licensable
79   - by such Contributor that are necessarily infringed by their
80   - Contribution(s) alone or by combination of their Contribution(s)
81   - with the Work to which such Contribution(s) was submitted. If You
82   - institute patent litigation against any entity (including a
83   - cross-claim or counterclaim in a lawsuit) alleging that the Work
84   - or a Contribution incorporated within the Work constitutes direct
85   - or contributory patent infringement, then any patent licenses
86   - granted to You under this License for that Work shall terminate
87   - as of the date such litigation is filed.
88   -
89   -4. Redistribution. You may reproduce and distribute copies of the
90   - Work or Derivative Works thereof in any medium, with or without
91   - modifications, and in Source or Object form, provided that You
92   - meet the following conditions:
93   -
94   - (a) You must give any other recipients of the Work or
95   - Derivative Works a copy of this License; and
96   -
97   - (b) You must cause any modified files to carry prominent notices
98   - stating that You changed the files; and
99   -
100   - (c) You must retain, in the Source form of any Derivative Works
101   - that You distribute, all copyright, patent, trademark, and
102   - attribution notices from the Source form of the Work,
103   - excluding those notices that do not pertain to any part of
104   - the Derivative Works; and
105   -
106   - (d) If the Work includes a "NOTICE" text file as part of its
107   - distribution, then any Derivative Works that You distribute must
108   - include a readable copy of the attribution notices contained
109   - within such NOTICE file, excluding those notices that do not
110   - pertain to any part of the Derivative Works, in at least one
111   - of the following places: within a NOTICE text file distributed
112   - as part of the Derivative Works; within the Source form or
113   - documentation, if provided along with the Derivative Works; or,
114   - within a display generated by the Derivative Works, if and
115   - wherever such third-party notices normally appear. The contents
116   - of the NOTICE file are for informational purposes only and
117   - do not modify the License. You may add Your own attribution
118   - notices within Derivative Works that You distribute, alongside
119   - or as an addendum to the NOTICE text from the Work, provided
120   - that such additional attribution notices cannot be construed
121   - as modifying the License.
122   -
123   - You may add Your own copyright statement to Your modifications and
124   - may provide additional or different license terms and conditions
125   - for use, reproduction, or distribution of Your modifications, or
126   - for any such Derivative Works as a whole, provided Your use,
127   - reproduction, and distribution of the Work otherwise complies with
128   - the conditions stated in this License.
129   -
130   -5. Submission of Contributions. Unless You explicitly state otherwise,
131   - any Contribution intentionally submitted for inclusion in the Work
132   - by You to the Licensor shall be under the terms and conditions of
133   - this License, without any additional terms or conditions.
134   - Notwithstanding the above, nothing herein shall supersede or modify
135   - the terms of any separate license agreement you may have executed
136   - with Licensor regarding such Contributions.
137   -
138   -6. Trademarks. This License does not grant permission to use the trade
139   - names, trademarks, service marks, or product names of the Licensor,
140   - except as required for reasonable and customary use in describing the
141   - origin of the Work and reproducing the content of the NOTICE file.
142   -
143   -7. Disclaimer of Warranty. Unless required by applicable law or
144   - agreed to in writing, Licensor provides the Work (and each
145   - Contributor provides its Contributions) on an "AS IS" BASIS,
146   - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147   - implied, including, without limitation, any warranties or conditions
148   - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149   - PARTICULAR PURPOSE. You are solely responsible for determining the
150   - appropriateness of using or redistributing the Work and assume any
151   - risks associated with Your exercise of permissions under this License.
152   -
153   -8. Limitation of Liability. In no event and under no legal theory,
154   - whether in tort (including negligence), contract, or otherwise,
155   - unless required by applicable law (such as deliberate and grossly
156   - negligent acts) or agreed to in writing, shall any Contributor be
157   - liable to You for damages, including any direct, indirect, special,
158   - incidental, or consequential damages of any character arising as a
159   - result of this License or out of the use or inability to use the
160   - Work (including but not limited to damages for loss of goodwill,
161   - work stoppage, computer failure or malfunction, or any and all
162   - other commercial damages or losses), even if such Contributor
163   - has been advised of the possibility of such damages.
164   -
165   -9. Accepting Warranty or Additional Liability. While redistributing
166   - the Work or Derivative Works thereof, You may choose to offer,
167   - and charge a fee for, acceptance of support, warranty, indemnity,
168   - or other liability obligations and/or rights consistent with this
169   - License. However, in accepting such obligations, You may act only
170   - on Your own behalf and on Your sole responsibility, not on behalf
171   - of any other Contributor, and only if You agree to indemnify,
172   - defend, and hold each Contributor harmless for any liability
173   - incurred by, or claims asserted against, such Contributor by reason
174   - of your accepting any such warranty or additional liability.
175   -
176   -END OF TERMS AND CONDITIONS
1   -Copyright (c) 2018 Georg Hopp <georg@steffers.org>
2   -
3   -Permission is hereby granted, free of charge, to any
4   -person obtaining a copy of this software and associated
5   -documentation files (the "Software"), to deal in the
6   -Software without restriction, including without
7   -limitation the rights to use, copy, modify, merge,
8   -publish, distribute, sublicense, and/or sell copies of
9   -the Software, and to permit persons to whom the Software
10   -is furnished to do so, subject to the following
11   -conditions:
12   -
13   -The above copyright notice and this permission notice
14   -shall be included in all copies or substantial portions
15   -of the Software.
16   -
17   -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18   -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19   -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20   -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21   -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22   -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23   -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24   -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25   -DEALINGS IN THE SOFTWARE.
1   -<div align="center">
2   -
3   - <h1><code>wasm-pack-template</code></h1>
4   -
5   - <strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong>
6   -
7   - <p>
8   - <a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a>
9   - </p>
10   -
11   - <h3>
12   - <a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a>
13   - <span> | </span>
14   - <a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
15   - </h3>
16   -
17   - <sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
18   -</div>
19   -
20   -## About
21   -
22   -[**📚 Read this template tutorial! 📚**][template-docs]
23   -
24   -This template is designed for compiling Rust libraries into WebAssembly and
25   -publishing the resulting package to NPM.
26   -
27   -Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other
28   -templates and usages of `wasm-pack`.
29   -
30   -[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html
31   -[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html
32   -
33   -## 🚴 Usage
34   -
35   -### 🐑 Use `cargo generate` to Clone this Template
36   -
37   -[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)
38   -
39   -```
40   -cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
41   -cd my-project
42   -```
43   -
44   -### 🛠️ Build with `wasm-pack build`
45   -
46   -```
47   -wasm-pack build
48   -```
49   -
50   -### 🔬 Test in Headless Browsers with `wasm-pack test`
51   -
52   -```
53   -wasm-pack test --headless --firefox
54   -```
55   -
56   -### 🎁 Publish to NPM with `wasm-pack publish`
57   -
58   -```
59   -wasm-pack publish
60   -```
61   -
62   -## 🔋 Batteries Included
63   -
64   -* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
65   - between WebAssembly and JavaScript.
66   -* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
67   - for logging panic messages to the developer console.
68   -* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized
69   - for small code size.
1   -mod utils;
2   -
3   -use wasm_bindgen::prelude::*;
4   -
5   -// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
6   -// allocator.
7   -#[cfg(feature = "wee_alloc")]
8   -#[global_allocator]
9   -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
10   -
11   -#[wasm_bindgen]
12   -extern {
13   - fn alert(s: &str);
14   -}
15   -
16   -#[wasm_bindgen]
17   -pub fn greet(name: &str) {
18   - alert(&format!("Hello, wasm-game-of-life! {}", name));
19   -}
1   -pub fn set_panic_hook() {
2   - // When the `console_error_panic_hook` feature is enabled, we can call the
3   - // `set_panic_hook` function at least once during initialization, and then
4   - // we will get better error messages if our code ever panics.
5   - //
6   - // For more details see
7   - // https://github.com/rustwasm/console_error_panic_hook#readme
8   - #[cfg(feature = "console_error_panic_hook")]
9   - console_error_panic_hook::set_once();
10   -}
1   -//! Test suite for the Web and headless browsers.
2   -
3   -#![cfg(target_arch = "wasm32")]
4   -
5   -extern crate wasm_bindgen_test;
6   -use wasm_bindgen_test::*;
7   -
8   -wasm_bindgen_test_configure!(run_in_browser);
9   -
10   -#[wasm_bindgen_test]
11   -fn pass() {
12   - assert_eq!(1 + 1, 2);
13   -}
1   -#!/usr/bin/env node
2   -
3   -const { spawn } = require("child_process");
4   -const fs = require("fs");
5   -
6   -let folderName = '.';
7   -
8   -if (process.argv.length >= 3) {
9   - folderName = process.argv[2];
10   - if (!fs.existsSync(folderName)) {
11   - fs.mkdirSync(folderName);
12   - }
13   -}
14   -
15   -const clone = spawn("git", ["clone", "https://github.com/rustwasm/create-wasm-app.git", folderName]);
16   -
17   -clone.on("close", code => {
18   - if (code !== 0) {
19   - console.error("cloning the template failed!")
20   - process.exit(code);
21   - } else {
22   - console.log("🦀 Rust + 🕸 Wasm = ❤");
23   - }
24   -});
1   -language: node_js
2   -node_js: "10"
3   -
4   -script:
5   - - ./node_modules/.bin/webpack
1   - Apache License
2   - Version 2.0, January 2004
3   - http://www.apache.org/licenses/
4   -
5   -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6   -
7   -1. Definitions.
8   -
9   - "License" shall mean the terms and conditions for use, reproduction,
10   - and distribution as defined by Sections 1 through 9 of this document.
11   -
12   - "Licensor" shall mean the copyright owner or entity authorized by
13   - the copyright owner that is granting the License.
14   -
15   - "Legal Entity" shall mean the union of the acting entity and all
16   - other entities that control, are controlled by, or are under common
17   - control with that entity. For the purposes of this definition,
18   - "control" means (i) the power, direct or indirect, to cause the
19   - direction or management of such entity, whether by contract or
20   - otherwise, or (ii) ownership of fifty percent (50%) or more of the
21   - outstanding shares, or (iii) beneficial ownership of such entity.
22   -
23   - "You" (or "Your") shall mean an individual or Legal Entity
24   - exercising permissions granted by this License.
25   -
26   - "Source" form shall mean the preferred form for making modifications,
27   - including but not limited to software source code, documentation
28   - source, and configuration files.
29   -
30   - "Object" form shall mean any form resulting from mechanical
31   - transformation or translation of a Source form, including but
32   - not limited to compiled object code, generated documentation,
33   - and conversions to other media types.
34   -
35   - "Work" shall mean the work of authorship, whether in Source or
36   - Object form, made available under the License, as indicated by a
37   - copyright notice that is included in or attached to the work
38   - (an example is provided in the Appendix below).
39   -
40   - "Derivative Works" shall mean any work, whether in Source or Object
41   - form, that is based on (or derived from) the Work and for which the
42   - editorial revisions, annotations, elaborations, or other modifications
43   - represent, as a whole, an original work of authorship. For the purposes
44   - of this License, Derivative Works shall not include works that remain
45   - separable from, or merely link (or bind by name) to the interfaces of,
46   - the Work and Derivative Works thereof.
47   -
48   - "Contribution" shall mean any work of authorship, including
49   - the original version of the Work and any modifications or additions
50   - to that Work or Derivative Works thereof, that is intentionally
51   - submitted to Licensor for inclusion in the Work by the copyright owner
52   - or by an individual or Legal Entity authorized to submit on behalf of
53   - the copyright owner. For the purposes of this definition, "submitted"
54   - means any form of electronic, verbal, or written communication sent
55   - to the Licensor or its representatives, including but not limited to
56   - communication on electronic mailing lists, source code control systems,
57   - and issue tracking systems that are managed by, or on behalf of, the
58   - Licensor for the purpose of discussing and improving the Work, but
59   - excluding communication that is conspicuously marked or otherwise
60   - designated in writing by the copyright owner as "Not a Contribution."
61   -
62   - "Contributor" shall mean Licensor and any individual or Legal Entity
63   - on behalf of whom a Contribution has been received by Licensor and
64   - subsequently incorporated within the Work.
65   -
66   -2. Grant of Copyright License. Subject to the terms and conditions of
67   - this License, each Contributor hereby grants to You a perpetual,
68   - worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69   - copyright license to reproduce, prepare Derivative Works of,
70   - publicly display, publicly perform, sublicense, and distribute the
71   - Work and such Derivative Works in Source or Object form.
72   -
73   -3. Grant of Patent License. Subject to the terms and conditions of
74   - this License, each Contributor hereby grants to You a perpetual,
75   - worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76   - (except as stated in this section) patent license to make, have made,
77   - use, offer to sell, sell, import, and otherwise transfer the Work,
78   - where such license applies only to those patent claims licensable
79   - by such Contributor that are necessarily infringed by their
80   - Contribution(s) alone or by combination of their Contribution(s)
81   - with the Work to which such Contribution(s) was submitted. If You
82   - institute patent litigation against any entity (including a
83   - cross-claim or counterclaim in a lawsuit) alleging that the Work
84   - or a Contribution incorporated within the Work constitutes direct
85   - or contributory patent infringement, then any patent licenses
86   - granted to You under this License for that Work shall terminate
87   - as of the date such litigation is filed.
88   -
89   -4. Redistribution. You may reproduce and distribute copies of the
90   - Work or Derivative Works thereof in any medium, with or without
91   - modifications, and in Source or Object form, provided that You
92   - meet the following conditions:
93   -
94   - (a) You must give any other recipients of the Work or
95   - Derivative Works a copy of this License; and
96   -
97   - (b) You must cause any modified files to carry prominent notices
98   - stating that You changed the files; and
99   -
100   - (c) You must retain, in the Source form of any Derivative Works
101   - that You distribute, all copyright, patent, trademark, and
102   - attribution notices from the Source form of the Work,
103   - excluding those notices that do not pertain to any part of
104   - the Derivative Works; and
105   -
106   - (d) If the Work includes a "NOTICE" text file as part of its
107   - distribution, then any Derivative Works that You distribute must
108   - include a readable copy of the attribution notices contained
109   - within such NOTICE file, excluding those notices that do not
110   - pertain to any part of the Derivative Works, in at least one
111   - of the following places: within a NOTICE text file distributed
112   - as part of the Derivative Works; within the Source form or
113   - documentation, if provided along with the Derivative Works; or,
114   - within a display generated by the Derivative Works, if and
115   - wherever such third-party notices normally appear. The contents
116   - of the NOTICE file are for informational purposes only and
117   - do not modify the License. You may add Your own attribution
118   - notices within Derivative Works that You distribute, alongside
119   - or as an addendum to the NOTICE text from the Work, provided
120   - that such additional attribution notices cannot be construed
121   - as modifying the License.
122   -
123   - You may add Your own copyright statement to Your modifications and
124   - may provide additional or different license terms and conditions
125   - for use, reproduction, or distribution of Your modifications, or
126   - for any such Derivative Works as a whole, provided Your use,
127   - reproduction, and distribution of the Work otherwise complies with
128   - the conditions stated in this License.
129   -
130   -5. Submission of Contributions. Unless You explicitly state otherwise,
131   - any Contribution intentionally submitted for inclusion in the Work
132   - by You to the Licensor shall be under the terms and conditions of
133   - this License, without any additional terms or conditions.
134   - Notwithstanding the above, nothing herein shall supersede or modify
135   - the terms of any separate license agreement you may have executed
136   - with Licensor regarding such Contributions.
137   -
138   -6. Trademarks. This License does not grant permission to use the trade
139   - names, trademarks, service marks, or product names of the Licensor,
140   - except as required for reasonable and customary use in describing the
141   - origin of the Work and reproducing the content of the NOTICE file.
142   -
143   -7. Disclaimer of Warranty. Unless required by applicable law or
144   - agreed to in writing, Licensor provides the Work (and each
145   - Contributor provides its Contributions) on an "AS IS" BASIS,
146   - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147   - implied, including, without limitation, any warranties or conditions
148   - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149   - PARTICULAR PURPOSE. You are solely responsible for determining the
150   - appropriateness of using or redistributing the Work and assume any
151   - risks associated with Your exercise of permissions under this License.
152   -
153   -8. Limitation of Liability. In no event and under no legal theory,
154   - whether in tort (including negligence), contract, or otherwise,
155   - unless required by applicable law (such as deliberate and grossly
156   - negligent acts) or agreed to in writing, shall any Contributor be
157   - liable to You for damages, including any direct, indirect, special,
158   - incidental, or consequential damages of any character arising as a
159   - result of this License or out of the use or inability to use the
160   - Work (including but not limited to damages for loss of goodwill,
161   - work stoppage, computer failure or malfunction, or any and all
162   - other commercial damages or losses), even if such Contributor
163   - has been advised of the possibility of such damages.
164   -
165   -9. Accepting Warranty or Additional Liability. While redistributing
166   - the Work or Derivative Works thereof, You may choose to offer,
167   - and charge a fee for, acceptance of support, warranty, indemnity,
168   - or other liability obligations and/or rights consistent with this
169   - License. However, in accepting such obligations, You may act only
170   - on Your own behalf and on Your sole responsibility, not on behalf
171   - of any other Contributor, and only if You agree to indemnify,
172   - defend, and hold each Contributor harmless for any liability
173   - incurred by, or claims asserted against, such Contributor by reason
174   - of your accepting any such warranty or additional liability.
175   -
176   -END OF TERMS AND CONDITIONS
177   -
178   -APPENDIX: How to apply the Apache License to your work.
179   -
180   - To apply the Apache License to your work, attach the following
181   - boilerplate notice, with the fields enclosed by brackets "[]"
182   - replaced with your own identifying information. (Don't include
183   - the brackets!) The text should be enclosed in the appropriate
184   - comment syntax for the file format. We also recommend that a
185   - file or class name and description of purpose be included on the
186   - same "printed page" as the copyright notice for easier
187   - identification within third-party archives.
188   -
189   -Copyright [yyyy] [name of copyright owner]
190   -
191   -Licensed under the Apache License, Version 2.0 (the "License");
192   -you may not use this file except in compliance with the License.
193   -You may obtain a copy of the License at
194   -
195   - http://www.apache.org/licenses/LICENSE-2.0
196   -
197   -Unless required by applicable law or agreed to in writing, software
198   -distributed under the License is distributed on an "AS IS" BASIS,
199   -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200   -See the License for the specific language governing permissions and
201   -limitations under the License.
1   -Copyright (c) [year] [name]
2   -
3   -Permission is hereby granted, free of charge, to any
4   -person obtaining a copy of this software and associated
5   -documentation files (the "Software"), to deal in the
6   -Software without restriction, including without
7   -limitation the rights to use, copy, modify, merge,
8   -publish, distribute, sublicense, and/or sell copies of
9   -the Software, and to permit persons to whom the Software
10   -is furnished to do so, subject to the following
11   -conditions:
12   -
13   -The above copyright notice and this permission notice
14   -shall be included in all copies or substantial portions
15   -of the Software.
16   -
17   -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18   -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19   -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20   -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21   -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22   -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23   -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24   -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25   -DEALINGS IN THE SOFTWARE.
1   -<div align="center">
2   -
3   - <h1><code>create-wasm-app</code></h1>
4   -
5   - <strong>An <code>npm init</code> template for kick starting a project that uses NPM packages containing Rust-generated WebAssembly and bundles them with Webpack.</strong>
6   -
7   - <p>
8   - <a href="https://travis-ci.org/rustwasm/create-wasm-app"><img src="https://img.shields.io/travis/rustwasm/create-wasm-app.svg?style=flat-square" alt="Build Status" /></a>
9   - </p>
10   -
11   - <h3>
12   - <a href="#usage">Usage</a>
13   - <span> | </span>
14   - <a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
15   - </h3>
16   -
17   - <sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
18   -</div>
19   -
20   -## About
21   -
22   -This template is designed for depending on NPM packages that contain
23   -Rust-generated WebAssembly and using them to create a Website.
24   -
25   -* Want to create an NPM package with Rust and WebAssembly? [Check out
26   - `wasm-pack-template`.](https://github.com/rustwasm/wasm-pack-template)
27   -* Want to make a monorepo-style Website without publishing to NPM? Check out
28   - [`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template)
29   - and/or
30   - [`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template).
31   -
32   -## 🚴 Usage
33   -
34   -```
35   -npm init wasm-app
36   -```
37   -
38   -## 🔋 Batteries Included
39   -
40   -- `.gitignore`: ignores `node_modules`
41   -- `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you
42   -- `README.md`: the file you are reading now!
43   -- `index.html`: a bare bones html document that includes the webpack bundle
44   -- `index.js`: example js file with a comment showing how to import and use a wasm pkg
45   -- `package.json` and `package-lock.json`:
46   - - pulls in devDependencies for using webpack:
47   - - [`webpack`](https://www.npmjs.com/package/webpack)
48   - - [`webpack-cli`](https://www.npmjs.com/package/webpack-cli)
49   - - [`webpack-dev-server`](https://www.npmjs.com/package/webpack-dev-server)
50   - - defines a `start` script to run `webpack-dev-server`
51   -- `webpack.config.js`: configuration file for bundling your js with webpack
52   -
53   -## License
54   -
55   -Licensed under either of
56   -
57   -* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
58   -* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
59   -
60   -at your option.
61   -
62   -### Contribution
63   -
64   -Unless you explicitly state otherwise, any contribution intentionally
65   -submitted for inclusion in the work by you, as defined in the Apache-2.0
66   -license, shall be dual licensed as above, without any additional terms or
67   -conditions.
1   -// A dependency graph that contains any wasm must all be imported
2   -// asynchronously. This `bootstrap.js` file does the single async import, so
3   -// that no one else needs to worry about it again.
4   -import("./index.js")
5   - .catch(e => console.error("Error importing `index.js`:", e));
1   -<!DOCTYPE html>
2   -<html>
3   - <head>
4   - <meta charset="utf-8">
5   - <title>Hello wasm-pack!</title>
6   - </head>
7   - <body>
8   - <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
9   - <script src="./bootstrap.js"></script>
10   - </body>
11   -</html>
1   -import * as wasm from "wasm-game-of-life";
2   -
3   -wasm.greet("Georg");
This diff could not be displayed because it is too large.
1   -{
2   - "name": "create-wasm-app",
3   - "version": "0.1.0",
4   - "description": "create an app to consume rust-generated wasm packages",
5   - "main": "index.js",
6   - "bin": {
7   - "create-wasm-app": ".bin/create-wasm-app.js"
8   - },
9   - "scripts": {
10   - "build": "webpack --config webpack.config.js",
11   - "start": "webpack-dev-server"
12   - },
13   - "repository": {
14   - "type": "git",
15   - "url": "git+https://github.com/rustwasm/create-wasm-app.git"
16   - },
17   - "keywords": [
18   - "webassembly",
19   - "wasm",
20   - "rust",
21   - "webpack"
22   - ],
23   - "author": "Ashley Williams <ashley666ashley@gmail.com>",
24   - "license": "(MIT OR Apache-2.0)",
25   - "bugs": {
26   - "url": "https://github.com/rustwasm/create-wasm-app/issues"
27   - },
28   - "homepage": "https://github.com/rustwasm/create-wasm-app#readme",
29   - "devDependencies": {
30   - "wasm-game-of-life": "file:../pkg",
31   - "hello-wasm-pack": "^0.1.0",
32   - "webpack": "^4.29.3",
33   - "webpack-cli": "^3.1.0",
34   - "webpack-dev-server": "^3.1.5",
35   - "copy-webpack-plugin": "^5.0.0"
36   - }
37   -}
1   -const CopyWebpackPlugin = require("copy-webpack-plugin");
2   -const path = require('path');
3   -
4   -module.exports = {
5   - entry: "./bootstrap.js",
6   - output: {
7   - path: path.resolve(__dirname, "dist"),
8   - filename: "bootstrap.js",
9   - },
10   - mode: "development",
11   - plugins: [
12   - new CopyWebpackPlugin(['index.html'])
13   - ],
14   -};
1   -all: xcbshm xcbshm2
2   -
3   -xcbshm2: xcbshm2.c
4   - gcc -o $@ -lxcb -lxcb-shm -lxcb-image $<
5   -
6   -xcbshm: xcbshm.c
7   - gcc -o $@ -lxcb -lxcb-shm -lxcb-image $<
8   -
9   -.PHONY: clean
10   -
11   -clean:
12   - @rm -f xcbshm xcbshm2
1   -extern crate xcb;
2   -
3   -use std::iter::{Iterator};
4   -use xcb::randr;
5   -
6   -fn main() {
7   -
8   - let dpy = ":0";
9   - let (conn, screen_num) = xcb::Connection::connect(Some(&dpy)).unwrap();
10   -
11   - let setup = conn.get_setup();
12   - let screen = setup.roots().nth(screen_num as usize).unwrap();
13   -
14   - println!("");
15   - println!("Informations of screen {}:", screen.root());
16   - println!(" width..........: {}", screen.width_in_pixels());
17   - println!(" height.........: {}", screen.height_in_pixels());
18   - println!(" white pixel....: {:x}", screen.white_pixel());
19   - println!(" black pixel....: {:x}", screen.black_pixel());
20   -
21   - let window_dummy = conn.generate_id();
22   - xcb::create_window(
23   - &conn, 0, window_dummy, screen.root()
24   - , 0, 0, 1, 1, 0, 0, 0, &[]);
25   -
26   - conn.flush();
27   -
28   - let cookie = randr::get_screen_info(&conn, window_dummy);
29   - let reply = cookie.get_reply().unwrap();
30   - let sizes = reply.sizes();
31   -
32   - for (i, size) in sizes.enumerate() {
33   - if i != 0 { println!(""); }
34   - println!("size of screen {}:", i+1);
35   - println!(" {} x {} ({}mm x {}mm)", size.width(), size.height(),
36   - size.mwidth(), size.mheight());
37   - }
38   -
39   - // ====
40   -
41   - let window = conn.generate_id();
42   -
43   - let values = [
44   - (xcb::CW_BACK_PIXEL, screen.white_pixel()),
45   - (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS),
46   - ];
47   -
48   - xcb::create_window(&conn,
49   - xcb::COPY_FROM_PARENT as u8,
50   - window,
51   - screen.root(),
52   - 0, 0,
53   - 150, 150,
54   - 10,
55   - xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
56   - screen.root_visual(),
57   - &values);
58   -
59   - xcb::map_window(&conn, window);
60   -
61   - let title = "Basic Window";
62   - // setting title
63   - xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8, window,
64   - xcb::ATOM_WM_NAME, xcb::ATOM_STRING, 8, title.as_bytes());
65   -
66   - conn.flush();
67   -
68   - // retrieving title
69   - let cookie = xcb::get_property(&conn, false, window, xcb::ATOM_WM_NAME,
70   - xcb::ATOM_STRING, 0, 1024);
71   - if let Ok(reply) = cookie.get_reply() {
72   - assert_eq!(std::str::from_utf8(reply.value()).unwrap(), title);
73   - } else {
74   - panic!("could not retrieve window title!");
75   - }
76   -
77   - // retrieving a few atoms
78   - let (wm_state, wm_state_maxv, wm_state_maxh) = {
79   - let cook = xcb::intern_atom(&conn, true, "_NET_WM_STATE");
80   - let cook_maxv = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_VERT");
81   - let cook_maxh = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_HORZ");
82   -
83   - (cook.get_reply().unwrap().atom(),
84   - cook_maxv.get_reply().unwrap().atom(),
85   - cook_maxh.get_reply().unwrap().atom())
86   - };
87   -
88   - let mut maximized = false;
89   -
90   - loop {
91   - let event = conn.wait_for_event();
92   - match event {
93   - None => { break; }
94   - Some(event) => {
95   - let r = event.response_type();
96   - if r == xcb::KEY_PRESS as u8 {
97   - let key_press : &xcb::KeyPressEvent = unsafe {
98   - xcb::cast_event(&event)
99   - };
100   -
101   - println!("Key '{}' pressed", key_press.detail());
102   -
103   - if key_press.detail() == 0x3a { // M (on qwerty)
104   -
105   - // toggle maximized
106   - println!("toggle maximized: {} {}", wm_state_maxv, wm_state_maxh);
107   -
108   - // ClientMessageData is a memory safe untagged union
109   - let data = xcb::ClientMessageData::from_data32([
110   - if maximized { 0 } else { 1 },
111   - wm_state_maxv, wm_state_maxh,
112   - 0, 0
113   - ]);
114   -
115   - let ev = xcb::ClientMessageEvent::new(32, window,
116   - wm_state, data);
117   -
118   - xcb::send_event(&conn, false, screen.root(),
119   - xcb::EVENT_MASK_STRUCTURE_NOTIFY, &ev);
120   -
121   - conn.flush();
122   -
123   - maximized = !maximized;
124   - }
125   - else if key_press.detail() == 0x18 { // Q (on qwerty)
126   - break;
127   - }
128   - }
129   - }
130   - }
131   - }
132   -}
1   -
2   -extern crate x11;
3   -extern crate xcb;
4   -extern crate gl;
5   -extern crate libc;
6   -
7   -use xcb::dri2;
8   -
9   -use x11::xlib;
10   -use x11::glx::*;
11   -
12   -use std::ptr::null_mut;
13   -use std::ffi::{CStr, CString};
14   -use std::os::raw::{c_int, c_void};
15   -
16   -
17   -const GLX_CONTEXT_MAJOR_VERSION_ARB: u32 = 0x2091;
18   -const GLX_CONTEXT_MINOR_VERSION_ARB: u32 = 0x2092;
19   -
20   -type GlXCreateContextAttribsARBProc =
21   - unsafe extern "C" fn (dpy: *mut xlib::Display, fbc: GLXFBConfig,
22   - share_context: GLXContext, direct: xlib::Bool,
23   - attribs: *const c_int) -> GLXContext;
24   -
25   -
26   -unsafe fn load_gl_func (name: &str) -> *mut c_void {
27   - let cname = CString::new(name).unwrap();
28   - let ptr: *mut c_void = std::mem::transmute(glXGetProcAddress(
29   - cname.as_ptr() as *const u8
30   - ));
31   - if ptr.is_null() {
32   - panic!("could not load {}", name);
33   - }
34   - ptr
35   -}
36   -
37   -fn check_glx_extension(glx_exts: &str, ext_name: &str) -> bool {
38   - for glx_ext in glx_exts.split(" ") {
39   - if glx_ext == ext_name {
40   - return true;
41   - }
42   - }
43   - false
44   -}
45   -
46   -static mut ctx_error_occurred: bool = false;
47   -unsafe extern "C" fn ctx_error_handler(
48   - _dpy: *mut xlib::Display,
49   - _ev: *mut xlib::XErrorEvent) -> i32 {
50   - ctx_error_occurred = true;
51   - 0
52   -}
53   -
54   -
55   -unsafe fn check_gl_error() {
56   - let err = gl::GetError();
57   - if err != gl::NO_ERROR {
58   - println!("got gl error {}", err);
59   - }
60   -}
61   -
62   -// returns the glx version in a decimal form
63   -// eg. 1.3 => 13
64   -fn glx_dec_version(dpy: *mut xlib::Display) -> i32 {
65   - let mut maj: c_int = 0;
66   - let mut min: c_int = 0;
67   - unsafe {
68   - if glXQueryVersion(dpy,
69   - &mut maj as *mut c_int,
70   - &mut min as *mut c_int) == 0 {
71   - panic!("cannot get glx version");
72   - }
73   - }
74   - (maj*10 + min) as i32
75   -}
76   -
77   -
78   -fn get_glxfbconfig(dpy: *mut xlib::Display, screen_num: i32,
79   - visual_attribs: &[i32]) -> GLXFBConfig {
80   - unsafe {
81   - let mut fbcount: c_int = 0;
82   - let fbcs = glXChooseFBConfig(dpy, screen_num,
83   - visual_attribs.as_ptr(),
84   - &mut fbcount as *mut c_int);
85   -
86   - if fbcount == 0 {
87   - panic!("could not find compatible fb config");
88   - }
89   - // we pick the first from the list
90   - let fbc = *fbcs;
91   - xlib::XFree(fbcs as *mut c_void);
92   - fbc
93   - }
94   -}
95   -
96   -
97   -fn main() { unsafe {
98   - let (conn, screen_num) = xcb::Connection::connect_with_xlib_display().unwrap();
99   - conn.set_event_queue_owner(xcb::EventQueueOwner::Xcb);
100   -
101   - if glx_dec_version(conn.get_raw_dpy()) < 13 {
102   - panic!("glx-1.3 is not supported");
103   - }
104   -
105   - let fbc = get_glxfbconfig(conn.get_raw_dpy(), screen_num, &[
106   - GLX_X_RENDERABLE , 1,
107   - GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
108   - GLX_RENDER_TYPE , GLX_RGBA_BIT,
109   - GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
110   - GLX_RED_SIZE , 8,
111   - GLX_GREEN_SIZE , 8,
112   - GLX_BLUE_SIZE , 8,
113   - GLX_ALPHA_SIZE , 8,
114   - GLX_DEPTH_SIZE , 24,
115   - GLX_STENCIL_SIZE , 8,
116   - GLX_DOUBLEBUFFER , 1,
117   - 0
118   - ]);
119   -
120   - let vi: *const xlib::XVisualInfo =
121   - glXGetVisualFromFBConfig(conn.get_raw_dpy(), fbc);
122   -
123   - let dri2_ev = {
124   - conn.prefetch_extension_data(dri2::id());
125   - match conn.get_extension_data(dri2::id()) {
126   - None => { panic!("could not load dri2 extension") },
127   - Some(r) => { r.first_event() }
128   - }
129   - };
130   -
131   - let (wm_protocols, wm_delete_window) = {
132   - let pc = xcb::intern_atom(&conn, false, "WM_PROTOCOLS");
133   - let dwc = xcb::intern_atom(&conn, false, "WM_DELETE_WINDOW");
134   -
135   - let p = match pc.get_reply() {
136   - Ok(p) => p.atom(),
137   - Err(_) => panic!("could not load WM_PROTOCOLS atom")
138   - };
139   - let dw = match dwc.get_reply() {
140   - Ok(dw) => dw.atom(),
141   - Err(_) => panic!("could not load WM_DELETE_WINDOW atom")
142   - };
143   - (p, dw)
144   - };
145   -
146   - let setup = conn.get_setup();
147   - let screen = setup.roots().nth((*vi).screen as usize).unwrap();
148   -
149   - let cmap = conn.generate_id();
150   - let win = conn.generate_id();
151   -
152   - xcb::create_colormap(&conn, xcb::COLORMAP_ALLOC_NONE as u8,
153   - cmap, screen.root(), (*vi).visualid as u32);
154   -
155   - let cw_values = [
156   - (xcb::CW_BACK_PIXEL, screen.white_pixel()),
157   - (xcb::CW_BORDER_PIXEL, screen.black_pixel()),
158   - (xcb::CW_EVENT_MASK,
159   - xcb::EVENT_MASK_KEY_PRESS | xcb::EVENT_MASK_EXPOSURE),
160   - (xcb::CW_COLORMAP, cmap)
161   - ];
162   -
163   - xcb::create_window(&conn, (*vi).depth as u8, win, screen.root(), 0, 0, 640, 480,
164   - 0, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
165   - (*vi).visualid as u32, &cw_values);
166   -
167   - xlib::XFree(vi as *mut c_void);
168   -
169   - let title = "XCB OpenGL";
170   - xcb::change_property(&conn,
171   - xcb::PROP_MODE_REPLACE as u8,
172   - win,
173   - xcb::ATOM_WM_NAME,
174   - xcb::ATOM_STRING,
175   - 8, title.as_bytes());
176   -
177   - let protocols = [wm_delete_window];
178   - xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8,
179   - win, wm_protocols, xcb::ATOM_ATOM, 32, &protocols);
180   -
181   - xcb::map_window(&conn, win);
182   - conn.flush();
183   - xlib::XSync(conn.get_raw_dpy(), xlib::False);
184   -
185   - let glx_exts = CStr::from_ptr(
186   - glXQueryExtensionsString(conn.get_raw_dpy(), screen_num))
187   - .to_str().unwrap();
188   -
189   - if !check_glx_extension(&glx_exts, "GLX_ARB_create_context") {
190   - panic!("could not find GLX extension GLX_ARB_create_context");
191   - }
192   -
193   - // with glx, no need of a current context is needed to load symbols
194   - // otherwise we would need to create a temporary legacy GL context
195   - // for loading symbols (at least glXCreateContextAttribsARB)
196   - let glx_create_context_attribs: GlXCreateContextAttribsARBProc =
197   - std::mem::transmute(load_gl_func("glXCreateContextAttribsARB"));
198   -
199   - // loading all other symbols
200   - gl::load_with(|n| load_gl_func(&n));
201   -
202   - if !gl::GenVertexArrays::is_loaded() {
203   - panic!("no GL3 support available!");
204   - }
205   -
206   - // installing an event handler to check if error is generated
207   - ctx_error_occurred = false;
208   - let old_handler = xlib::XSetErrorHandler(Some(ctx_error_handler));
209   -
210   - let context_attribs: [c_int; 5] = [
211   - GLX_CONTEXT_MAJOR_VERSION_ARB as c_int, 3,
212   - GLX_CONTEXT_MINOR_VERSION_ARB as c_int, 0,
213   - 0
214   - ];
215   - let ctx = glx_create_context_attribs(conn.get_raw_dpy(), fbc, null_mut(),
216   - xlib::True, &context_attribs[0] as *const c_int);
217   -
218   - conn.flush();
219   - xlib::XSync(conn.get_raw_dpy(), xlib::False);
220   - xlib::XSetErrorHandler(std::mem::transmute(old_handler));
221   -
222   - if ctx.is_null() || ctx_error_occurred {
223   - panic!("error when creating gl-3.0 context");
224   - }
225   -
226   - if glXIsDirect(conn.get_raw_dpy(), ctx) == 0 {
227   - panic!("obtained indirect rendering context")
228   - }
229   -
230   - loop {
231   - if let Some(ev) = conn.wait_for_event() {
232   - let ev_type = ev.response_type() & !0x80;
233   - match ev_type {
234   - xcb::EXPOSE => {
235   - glXMakeCurrent(conn.get_raw_dpy(), win as xlib::XID, ctx);
236   - gl::ClearColor(0.5f32, 0.5f32, 1.0f32, 1.0f32);
237   - gl::Clear(gl::COLOR_BUFFER_BIT);
238   - gl::Flush();
239   - check_gl_error();
240   - glXSwapBuffers(conn.get_raw_dpy(), win as xlib::XID);
241   - glXMakeCurrent(conn.get_raw_dpy(), 0, null_mut());
242   - },
243   - xcb::KEY_PRESS => {
244   - break;
245   - },
246   - xcb::CLIENT_MESSAGE => {
247   - let cmev = unsafe {
248   - xcb::cast_event::<xcb::ClientMessageEvent>(&ev)
249   - };
250   - if cmev.type_() == wm_protocols && cmev.format() == 32 {
251   - let protocol = cmev.data().data32()[0];
252   - if protocol == wm_delete_window {
253   - break;
254   - }
255   - }
256   - },
257   - _ => {
258   - // following stuff is not obvious at all, but is necessary
259   - // to handle GL when XCB owns the event queue
260   - if ev_type == dri2_ev || ev_type == dri2_ev+1 {
261   - // these are libgl dri2 event that need special handling
262   - // see https://bugs.freedesktop.org/show_bug.cgi?id=35945#c4
263   - // and mailing thread starting here:
264   - // http://lists.freedesktop.org/archives/xcb/2015-November/010556.html
265   -
266   - if let Some(proc_) =
267   - xlib::XESetWireToEvent(conn.get_raw_dpy(),
268   - ev_type as i32, None) {
269   - xlib::XESetWireToEvent(conn.get_raw_dpy(),
270   - ev_type as i32, Some(proc_));
271   - let raw_ev = ev.ptr;
272   - (*raw_ev).sequence =
273   - xlib::XLastKnownRequestProcessed(
274   - conn.get_raw_dpy()) as u16;
275   - let mut dummy: xlib::XEvent = std::mem::zeroed();
276   - proc_(conn.get_raw_dpy(),
277   - &mut dummy as *mut xlib::XEvent,
278   - raw_ev as *mut xlib::xEvent);
279   - }
280   -
281   - }
282   - }
283   - }
284   - conn.flush();
285   - }
286   - else {
287   - break;
288   - }
289   - }
290   -
291   - // only to make sure that rs_client generate correct names for DRI2
292   - // (used to be "*_DRI_2_*")
293   - // should be in a "compile tests" section instead of example
294   - let _ = xcb::ffi::dri2::XCB_DRI2_ATTACHMENT_BUFFER_ACCUM;
295   -
296   - glXDestroyContext(conn.get_raw_dpy(), ctx);
297   -
298   - xcb::unmap_window(&conn, win);
299   - xcb::destroy_window(&conn, win);
300   - xcb::free_colormap(&conn, cmap);
301   - conn.flush();
302   -}}
1   -extern crate xcb;
2   -
3   -use std::iter::{Iterator};
4   -use std::{thread, time};
5   -use std::sync::Arc;
6   -use std::ptr::{null, null_mut};
7   -use std::slice::from_raw_parts_mut;
8   -
9   -pub fn getshm<'a>(size :usize) -> (i32, &'a mut [u32]) {
10   - unsafe {
11   - let id = libc::shmget( libc::IPC_PRIVATE
12   - , size * 4
13   - , libc::IPC_CREAT | 0o744 );
14   - let ptr = libc::shmat(id, null(), 0);
15   - (id as i32, from_raw_parts_mut(ptr as *mut u32, size))
16   - }
17   -}
18   -
19   -fn main() {
20   - let points: &[xcb::Point] = &[ xcb::Point::new(10, 10)
21   - , xcb::Point::new(10, 20)
22   - , xcb::Point::new(20, 10)
23   - , xcb::Point::new(20, 20) ];
24   - let polyline: &[xcb::Point] = &[ xcb::Point::new(50, 10 )
25   - // rest of points are relative
26   - , xcb::Point::new( 5, 20 )
27   - , xcb::Point::new(25, -20)
28   - , xcb::Point::new(10, 10 ) ];
29   - let segments: &[xcb::Segment] = &[ xcb::Segment::new(100, 10, 140, 30)
30   - , xcb::Segment::new(110, 25, 130, 60) ];
31   - let rectangles: &[xcb::Rectangle]
32   - = &[ xcb::Rectangle::new(10, 50, 40, 20)
33   - , xcb::Rectangle::new(80, 50, 10, 40) ];
34   - let arcs: &[xcb::Arc] = &[ xcb::Arc::new(10, 100, 60, 40, 0, 90 << 6)
35   - , xcb::Arc::new(90, 100, 55, 40, 0, 270 << 6) ];
36   -
37   - let (conn, screen_num) = {
38   - let (conn, screen_num) = xcb::Connection::connect(None).unwrap();
39   - (Arc::new(conn), screen_num)
40   - };
41   - let setup = conn.get_setup();
42   - let screen = setup.roots().nth(screen_num as usize).unwrap();
43   -
44   - let (shmid, shm) = getshm(150 * 150);
45   - let shmseg = conn.generate_id();
46   - xcb::shm::attach(&conn, shmseg, shmid as u32, false);
47   - unsafe { libc::shmctl(shmid, libc::IPC_RMID, null_mut()); }
48   -
49   - let foreground = conn.generate_id();
50   - let pix = conn.generate_id();
51   -
52   - xcb::create_gc( &conn
53   - , foreground
54   - , screen.root()
55   - , &[ (xcb::GC_FOREGROUND, screen.black_pixel())
56   - , (xcb::GC_GRAPHICS_EXPOSURES, 0) ] );
57   -
58   - let window = conn.generate_id();
59   - let values = [ ( xcb::CW_BACK_PIXEL, screen.white_pixel() )
60   - , ( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE
61   - | xcb::EVENT_MASK_KEY_PRESS
62   - | xcb::EVENT_MASK_STRUCTURE_NOTIFY
63   - | xcb::EVENT_MASK_PROPERTY_CHANGE ) ];
64   - xcb::create_window( &conn
65   - , xcb::COPY_FROM_PARENT as u8
66   - , window
67   - , screen.root()
68   - , 0, 0, 150, 150, 0
69   - , xcb::WINDOW_CLASS_INPUT_OUTPUT as u16
70   - , screen.root_visual()
71   - , &values);
72   -
73   - xcb::shm::create_pixmap( &conn
74   - , pix
75   - , window
76   - , 150, 150
77   - , screen.root_depth()
78   - , shmseg
79   - , 0 );
80   -
81   - xcb::map_window(&conn, window);
82   -
83   - {
84   - let conn = conn.clone();
85   -
86   - thread::spawn(move || {
87   - let mut blink = false;
88   -
89   - let mut i = 0;
90   - loop {
91   - let title = if blink {
92   - "Basic Threaded Window ;-)"
93   - } else {
94   - "Basic Threaded Window :-)"
95   - };
96   -
97   - shm[i] = 0xFFFFFF;
98   - i = (i + 1) % (150 * 150);
99   -
100   - let c = xcb::change_property_checked(
101   - &conn
102   - , xcb::PROP_MODE_REPLACE as u8
103   - , window
104   - , xcb::ATOM_WM_NAME
105   - , xcb::ATOM_STRING
106   - , 8
107   - , title.as_bytes() );
108   -
109   - xcb::copy_area( &conn
110   - , pix
111   - , window
112   - , foreground
113   - , 0, 0, 0, 0
114   - , 150, 150);
115   -
116   - if conn.has_error().is_err() || c.request_check().is_err() {
117   - break;
118   - }
119   -
120   - blink = !blink;
121   - thread::sleep(time::Duration::from_millis(500));
122   - }
123   - });
124   - }
125   -
126   - conn.flush();
127   -
128   - loop {
129   - let event = conn.wait_for_event();
130   -
131   - match event {
132   - None => break,
133   - Some(event) => {
134   - match event.response_type() & !0x80 {
135   - xcb::PROPERTY_NOTIFY => {
136   - let prop_notify: &xcb::PropertyNotifyEvent = unsafe {
137   - xcb::cast_event(&event)
138   - };
139   -
140   - if prop_notify.atom() == xcb::ATOM_WM_NAME {
141   - // retrieving title
142   - let cookie = xcb::get_property( &conn
143   - , false
144   - , window
145   - , xcb::ATOM_WM_NAME
146   - , xcb::ATOM_STRING
147   - , 0, 1024);
148   -
149   - if let Ok(reply) = cookie.get_reply() {
150   - let r = reply.value();
151   - let r = std::str::from_utf8(r).unwrap();
152   -
153   - println!( "title changed to \"{}\"", r);
154   - }
155   - }
156   - },
157   -
158   - xcb::EXPOSE => {
159   - xcb::poly_point( &conn
160   - , xcb::COORD_MODE_ORIGIN as u8
161   - , window
162   - , foreground
163   - , &points );
164   - xcb::poly_line( &conn
165   - , xcb::COORD_MODE_PREVIOUS as u8
166   - , window
167   - , foreground
168   - , &polyline );
169   - xcb::poly_segment( &conn
170   - , window
171   - , foreground
172   - , &segments );
173   - xcb::poly_rectangle( &conn
174   - , window
175   - , foreground
176   - , &rectangles );
177   - xcb::poly_arc( &conn
178   - , window
179   - , foreground
180   - , &arcs );
181   -
182   - conn.flush();
183   - },
184   -
185   - xcb::KEY_PRESS => {
186   - let key_press: &xcb::KeyPressEvent = unsafe {
187   - xcb::cast_event(&event)
188   - };
189   -
190   - println!("Key '{}' pressed", key_press.detail());
191   -
192   - if key_press.detail() == 0x18 { // Q (on qwerty)
193   - break;
194   - }
195   - },
196   -
197   - _ => {},
198   - }
199   - }
200   - }
201   - }
202   -}
1   -/**
2   - * \file
3   - * [: description :]
4   - *
5   - * \author
6   - * Georg Hopp <georg@steffers.org>
7   - *
8   - * \copyright
9   - * Copyright © 2019 Georg Hopp
10   - *
11   - * This program is free software: you can redistribute it and/or modify
12   - * it under the terms of the GNU General Public License as published by
13   - * the Free Software Foundation, either version 3 of the License, or
14   - * (at your option) any later version.
15   - *
16   - * This program is distributed in the hope that it will be useful,
17   - * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19   - * GNU General Public License for more details.
20   - *
21   - * You should have received a copy of the GNU General Public License
22   - * along with this program. If not, see <http://www.gnu.org/licenses/>.
23   - */
24   -// http://stackoverflow.com/questions/27745131
25   -
26   -#include <sys/ipc.h>
27   -#include <sys/shm.h>
28   -
29   -#include <xcb/xcb.h>
30   -#include <xcb/xcb_image.h>
31   -#include <xcb/shm.h>
32   -
33   -#include <stdio.h>
34   -
35   -#define W 512
36   -#define H 512
37   -
38   -
39   -int main(){
40   - //connect to the X server and get screen
41   - xcb_connection_t* connection = xcb_connect(NULL, NULL);
42   - xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
43   -
44   - //create a window
45   - uint32_t value_mask = XCB_CW_BACK_PIXEL|XCB_CW_EVENT_MASK;
46   - uint32_t value_list[2] = {screen->black_pixel, XCB_EVENT_MASK_EXPOSURE};
47   - xcb_window_t window = xcb_generate_id(connection);
48   - xcb_create_window(connection, screen->root_depth, window, screen->root, 0, 0, W, H, 0,
49   - XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list);
50   -
51   - //create a graphic context
52   - value_mask = XCB_GC_FOREGROUND|XCB_GC_GRAPHICS_EXPOSURES;
53   - value_list[0] = screen->black_pixel;
54   - value_list[1] = 0;
55   - xcb_gcontext_t gcontext = xcb_generate_id(connection);
56   - xcb_create_gc(connection, gcontext, window, value_mask, value_list);
57   -
58   - //map the window onto the screen
59   - xcb_map_window(connection, window);
60   - xcb_flush(connection);
61   -
62   - //Shm test
63   - xcb_shm_segment_info_t info;
64   - xcb_shm_query_version_reply(connection, xcb_shm_query_version(connection), NULL);
65   -
66   - info.shmid = shmget(IPC_PRIVATE, W*H*4, IPC_CREAT|0777);
67   - info.shmaddr = shmat(info.shmid, 0, 0);
68   - info.shmseg = xcb_generate_id(connection);
69   - xcb_shm_attach(connection, info.shmseg, info.shmid, 0);
70   - shmctl(info.shmid, IPC_RMID, 0);
71   - uint8_t* data = info.shmaddr;
72   -
73   - xcb_pixmap_t pix = xcb_generate_id(connection);
74   - xcb_shm_create_pixmap(connection, pix, window, W, H, screen->root_depth, info.shmseg, 0);
75   -
76   -
77   - uint8_t lala[W*H*4] = {0};
78   - const xcb_setup_t* setup = xcb_get_setup(connection);
79   - xcb_format_t* fmt = xcb_setup_pixmap_formats(setup);
80   - printf("scanline_pad %u depth %u bpp %u byte_order %u\n",
81   - fmt->scanline_pad, fmt->depth, fmt->bits_per_pixel, setup->image_byte_order);
82   - xcb_image_t* img = xcb_image_create(W,H, XCB_IMAGE_FORMAT_Z_PIXMAP,
83   - fmt->scanline_pad, 24, 32, 0, setup->image_byte_order, XCB_IMAGE_ORDER_LSB_FIRST, lala, W*H*4, lala);
84   -
85   - // xcb_image_shm_get(connection, window, img, info, 0,0, XCB_IMAGE_FORMAT_Z_PIXMAP);
86   - // xcb_image_shm_put(connection, window, img, info, 0,0, XCB_IMAGE_FORMAT_Z_PIXMAP);
87   -
88   -
89   - // --------------------------------------------------------------
90   - uint i = 0;
91   - while(1){
92   - data[i++] = 0xff;
93   - xcb_copy_area(connection, pix, window, gcontext, 0, 0, 0, 0, W, H);
94   - xcb_flush(connection);
95   - }
96   -
97   - xcb_shm_detach(connection, info.shmseg);
98   - shmdt(info.shmaddr);
99   -
100   - xcb_free_pixmap(connection, pix);
101   - xcb_destroy_window(connection, window);
102   - xcb_disconnect(connection);
103   -}
104   -
105   -// vim: set ts=4 sw=4:
1   -/**
2   - * \file
3   - * [: description :]
4   - *
5   - * \author
6   - * Georg Hopp <georg@steffers.org>
7   - *
8   - * \copyright
9   - * Copyright © 2019 Georg Hopp
10   - *
11   - * This program is free software: you can redistribute it and/or modify
12   - * it under the terms of the GNU General Public License as published by
13   - * the Free Software Foundation, either version 3 of the License, or
14   - * (at your option) any later version.
15   - *
16   - * This program is distributed in the hope that it will be useful,
17   - * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19   - * GNU General Public License for more details.
20   - *
21   - * You should have received a copy of the GNU General Public License
22   - * along with this program. If not, see <http://www.gnu.org/licenses/>.
23   - */
24   -#include <stdlib.h>
25   -#include <stdio.h>
26   -#include <unistd.h>
27   -
28   -#include <sys/ipc.h>
29   -#include <sys/shm.h>
30   -
31   -#include <xcb/xcb.h>
32   -#include <xcb/shm.h>
33   -#include <xcb/xcb_image.h>
34   -
35   -
36   -#define WID 512
37   -#define HEI 512
38   -
39   -
40   -int main(){
41   - xcb_connection_t* connection;
42   - xcb_window_t window;
43   - xcb_screen_t* screen;
44   - xcb_gcontext_t gcontext;
45   - xcb_generic_event_t* event;
46   -
47   - uint32_t value_mask;
48   - uint32_t value_list[2];
49   -
50   - //connect to the X server and get screen
51   -
52   - connection = xcb_connect(NULL, NULL);
53   - screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
54   -
55   - //create a window
56   -
57   - value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
58   - value_list[0] = screen->black_pixel;
59   - value_list[1] = XCB_EVENT_MASK_EXPOSURE;
60   -
61   - window = xcb_generate_id(connection);
62   -
63   - xcb_create_window(
64   - connection,
65   - screen->root_depth,
66   - window,
67   - screen->root,
68   - 0, 0,
69   - WID, HEI,
70   - 0,
71   - XCB_WINDOW_CLASS_INPUT_OUTPUT,
72   - screen->root_visual,
73   - value_mask, value_list
74   - );
75   -
76   - //create a graphic context
77   -
78   - value_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
79   - value_list[0] = screen->black_pixel;
80   - value_list[1] = 0;
81   -
82   - gcontext = xcb_generate_id(connection);
83   - xcb_create_gc(connection, gcontext, window, value_mask, value_list);
84   -
85   - //map the window onto the screen
86   -
87   - xcb_map_window(connection, window);
88   - xcb_flush(connection);
89   -
90   -
91   - //Shm test
92   - xcb_shm_query_version_reply_t* reply;
93   - xcb_shm_segment_info_t info;
94   -
95   - reply = xcb_shm_query_version_reply(
96   - connection,
97   - xcb_shm_query_version(connection),
98   - NULL
99   - );
100   -
101   - if(!reply || !reply->shared_pixmaps){
102   - printf("Shm error...\n");
103   - exit(0);
104   - }
105   -
106   - info.shmid = shmget(IPC_PRIVATE, WID*HEI*4, IPC_CREAT | 0777);
107   - info.shmaddr = shmat(info.shmid, 0, 0);
108   -
109   - info.shmseg = xcb_generate_id(connection);
110   - xcb_shm_attach(connection, info.shmseg, info.shmid, 0);
111   - shmctl(info.shmid, IPC_RMID, 0);
112   -
113   - uint32_t* data = (uint32_t*)info.shmaddr;
114   -
115   - xcb_pixmap_t pix = xcb_generate_id(connection);
116   - xcb_shm_create_pixmap(
117   - connection,
118   - pix,
119   - window,
120   - WID, HEI,
121   - screen->root_depth,
122   - info.shmseg,
123   - 0
124   - );
125   -
126   - int i = 0;
127   - while(1){
128   - usleep(10000);
129   -
130   - data[i] = 0xFFFFFF;
131   - i++;
132   -
133   - xcb_copy_area(
134   - connection,
135   - pix,
136   - window,
137   - gcontext,
138   - 0, 0, 0, 0,
139   - WID, HEI
140   - );
141   -
142   - xcb_flush(connection);
143   - }
144   -
145   - xcb_shm_detach(connection, info.shmseg);
146   - shmdt(info.shmaddr);
147   -
148   - xcb_free_pixmap(connection, pix);
149   -
150   - xcb_destroy_window(connection, window);
151   - xcb_disconnect(connection);
152   -
153   - return 0;
154   -}
155   -
156   -// vim: set ts=4 sw=4:
Please register or login to post a comment