Commit e78ff6b6132e602aa67ff751a0360d4083b00ea8

Authored by Georg Hopp
1 parent e4b19add

reduce to easel3d-xcb demo program

Showing 56 changed files with 163 additions and 4581 deletions

Too many changes to show.

To preserve performance only 56 of 56+ files are displayed.

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();