Commit c856f7b8c595986cdec6be68ef7faaf124f3994b

Authored by Georg Hopp
1 parent 3087691d

split easel into multiple files

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 +// …
  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, Display, Formatter, Result};
  23 +use std::ops::{Add, Div, Sub};
  24 +use std::sync::mpsc;
  25 +
  26 +use super::drawable::Drawable;
  27 +use super::line_iterator::LineIterator;
  28 +
  29 +// A 2D drawing surface.
  30 +pub trait Canvas<T> {
  31 + fn init_events(&self);
  32 + fn start_events(&self, tx :mpsc::Sender<i32>);
  33 +
  34 + fn width(&self) -> u16;
  35 + fn height(&self) -> u16;
  36 +
  37 + fn clear(&mut self);
  38 + fn draw(&mut self, c :&dyn Drawable<T>, color :u32);
  39 + fn set_pixel(&mut self, c :Vertex<T>, color :u32);
  40 + fn put_text(&self, ofs :Vertex<T>, s :&str);
  41 + fn show(&self);
  42 +}
  43 +
  44 +// A Vertex is a position on a 2D drawing surface along other stuff
  45 +// that needs to iterate between those coordinates.
  46 +#[derive(Debug, Clone, Copy)]
  47 +pub struct Vertex<T>{ x :i32 // canvas x coordinate
  48 + , y :i32 // canvas y coordinate
  49 + , zr :T } // z reciprocal from 3D projection.
  50 +
  51 +pub type Vertices<T> = Vec<Vertex<T>>;
  52 +
  53 +impl<T> Vertex<T>
  54 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  55 + + Debug + Clone + Copy + From<i32> {
  56 + pub fn new(x :i32, y :i32, zr :T) -> Self {
  57 + Vertex{x, y, zr}
  58 + }
  59 +
  60 + #[inline]
  61 + pub fn as_tuple(&self) -> (i32, i32, T) {
  62 + (self.x, self.y, self.zr)
  63 + }
  64 +
  65 + #[inline]
  66 + pub fn same_x(&self, b :&Self) -> bool {
  67 + self.x == b.x
  68 + }
  69 +
  70 + #[inline]
  71 + pub fn same_y(&self, b :&Self) -> bool {
  72 + self.y == b.y
  73 + }
  74 +
  75 + #[inline]
  76 + pub fn same_position(&self, b :&Self) -> bool {
  77 + self.same_x(b) && self.same_y(b)
  78 + }
  79 +
  80 + fn iter(self, b :Self, only_edges :bool) -> LineIterator<T> {
  81 + LineIterator::new(self, b, only_edges)
  82 + }
  83 +
  84 + pub fn line_iter(self, b :Self) -> LineIterator<T> {
  85 + self.iter(b, false)
  86 + }
  87 +
  88 + pub fn line(self, b :Self) -> Vec<Self> {
  89 + self.line_iter(b).collect()
  90 + }
  91 +
  92 + pub fn edge_iter(self, b :Self) -> LineIterator<T> {
  93 + self.iter(b, true)
  94 + }
  95 +
  96 + fn edge(self, b :Self) -> Vec<Self> {
  97 + self.edge_iter(b).collect()
  98 + }
  99 +
  100 + fn face(edges :&[Self]) -> Vec<Self> {
  101 + edges.to_vec()
  102 + }
  103 +}
  104 +
  105 +impl<T> Display for Vertex<T> {
  106 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  107 + write!(f, "<{},{}>", self.x, self.y)
  108 + }
  109 +}
  110 +
  111 +impl<T> Add for Vertex<T> where T: Add<Output=T> {
  112 + type Output = Self;
  113 +
  114 + fn add(self, other :Self) -> Vertex<T> {
  115 + Vertex{ x: self.x + other.x
  116 + , y: self.y + other.y
  117 + , zr: self.zr + other.zr }
  118 + }
  119 +}
... ...
  1 +//
  2 +// …
  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 super::canvas::Vertices;
  23 +
  24 +pub trait Drawable<T> {
  25 + fn plot(&self) -> Vertices<T>;
  26 +}
... ...
  1 +//
  2 +// …
  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, Sub};
  24 +
  25 +use super::canvas::Canvas;
  26 +
  27 +pub trait Fillable<T>
  28 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  29 + + Debug + Copy + From<i32> {
  30 + fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32);
  31 +}
... ...
  1 +//
  2 +// …
  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, Display, Formatter, Result};
  23 +use std::ops::{Add, Div, Sub};
  24 +
  25 +use super::canvas::{Vertex, Vertices};
  26 +use super::drawable::Drawable;
  27 +
  28 +#[derive(Debug, Clone, Copy)]
  29 +pub struct Line<T>(pub Vertex<T>, pub Vertex<T>);
  30 +
  31 +impl<T> Drawable<T> for Line<T>
  32 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  33 + + Debug + Clone + Copy + From<i32> {
  34 + fn plot(&self) -> Vertices<T> {
  35 + let Line(a, b) = *self;
  36 + a.line(b)
  37 + }
  38 +}
  39 +
  40 +impl<T> Display for Line<T> {
  41 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  42 + let Line(a, b) = self;
  43 + write!(f, "Line[{},{}]", a, b)
  44 + }
  45 +}
... ...
  1 +//
  2 +// …
  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::cmp::max;
  23 +use std::fmt::Debug;
  24 +use std::ops::{Add, Div, Sub};
  25 +
  26 +use super::canvas::Vertex;
  27 +
  28 +#[derive(Debug, Clone, Copy)]
  29 +pub struct LineIterator<T> where T: Debug {
  30 + a :Option<Vertex<T>>
  31 + , b :Vertex<T>
  32 + , dx :i32
  33 + , dy :i32
  34 + , incx :Vertex<T>
  35 + , incy :Vertex<T>
  36 + , incxy :Vertex<T>
  37 + , err :i32
  38 + , edges :bool
  39 +}
  40 +
  41 +impl<T> LineIterator<T>
  42 +where T: Add<Output=T> + Div<Output=T> + Sub<Output=T>
  43 + + Debug + Clone + Copy + From<i32> {
  44 + pub fn new(a :Vertex<T>, b :Vertex<T>, edges :bool) -> LineIterator<T> {
  45 + let (ax, ay, azr) = a.as_tuple();
  46 + let (bx, by, bzr) = b.as_tuple();
  47 +
  48 + let dx = (bx - ax).abs();
  49 + let dy = -(by - ay).abs();
  50 + let dz = (bzr - azr) / max(dx, -dy).into();
  51 +
  52 + let sx = if ax < bx { 1 } else { -1 };
  53 + let sy = if ay < by { 1 } else { -1 };
  54 +
  55 + LineIterator { a: Some(a)
  56 + , b: b
  57 + , dx: dx
  58 + , dy: dy
  59 + , incx: Vertex::new( sx, 0.into(), dz)
  60 + , incy: Vertex::new(0.into(), sy, dz)
  61 + , incxy: Vertex::new( sx, sy, dz)
  62 + , err: dx + dy
  63 + , edges: edges }
  64 + }
  65 +}
  66 +
  67 +impl<T> Iterator for LineIterator<T>
  68 +where T: Add<Output=T> + Div<Output=T> + Sub<Output=T>
  69 + + Debug + Copy + From<i32> {
  70 + type Item = Vertex<T>;
  71 +
  72 + // Bresenham based line iteration.
  73 + fn next(&mut self) -> Option<Self::Item> {
  74 + if ! self.a?.same_position(&self.b) {
  75 + let ret = self.a;
  76 + let inc = match (2*self.err >= self.dy, 2*self.err <= self.dx ) {
  77 + (true, false) => ( self.incx, self.dy, self.edges),
  78 + (false, true) => ( self.incy, self.dx, false),
  79 + _ => (self.incxy, self.dx+self.dy, false),
  80 + };
  81 +
  82 + self.a = Some(self.a? + inc.0);
  83 + self.err = self.err + inc.1;
  84 + if inc.2 { self.next() } else { ret }
  85 + } else {
  86 + self.a = None;
  87 + Some(self.b)
  88 + }
  89 + }
  90 +}
... ...
  1 +//
  2 +// …
  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 trait Easel {
  23 +}
  24 +
  25 +// Trait to implement for a concrete canvas as well as struct for canvas
  26 +// coordinates (which also includes z reciprocal)
  27 +pub mod canvas;
  28 +
  29 +// Traits that new drawing primitives must implement to be drawn on a canvas.
  30 +pub mod drawable;
  31 +pub mod fillable;
  32 +
  33 +// Drawing primitives
  34 +pub mod line;
  35 +pub mod point;
  36 +pub mod polygon;
  37 +pub mod polyline;
  38 +
  39 +// Helper iterators to find all positions a primitive needs to draw.
  40 +mod line_iterator;
  41 +mod vertex_iterator;
... ...
  1 +//
  2 +// …
  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::{Display, Formatter, Result};
  23 +
  24 +use super::canvas::{Vertex, Vertices};
  25 +use super::drawable::Drawable;
  26 +
  27 +#[derive(Debug, Clone, Copy)]
  28 +pub struct Point<T>(pub Vertex<T>);
  29 +
  30 +impl<T> Drawable<T> for Point<T> where T: Copy {
  31 + fn plot(&self) -> Vertices<T> {
  32 + let Point(c) = *self;
  33 + vec!(c)
  34 + }
  35 +}
  36 +
  37 +impl<T> Display for Point<T> {
  38 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  39 + let Point(p) = self;
  40 + write!(f, "Point[{}]", p)
  41 + }
  42 +}
... ...
  1 +//
  2 +// …
  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, Sub};
  24 +
  25 +use super::canvas::{Canvas, Vertex, Vertices};
  26 +use super::drawable::Drawable;
  27 +use super::fillable::Fillable;
  28 +use super::vertex_iterator::{Direction, VertexIterator};
  29 +
  30 +#[derive(Debug, Clone)]
  31 +pub struct Polygon<T>(pub Vertices<T>);
  32 +
  33 +impl<T> Polygon<T>
  34 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  35 + + Copy + Debug + From<i32> {
  36 + #[inline]
  37 + pub fn vertex(&self, v :usize) -> Vertex<T> {
  38 + let Polygon(cs) = self;
  39 + cs[v]
  40 + }
  41 +
  42 + pub fn vert_min<'a>(&'a self, d :Direction) -> usize {
  43 + let Polygon(cs) = self;
  44 +
  45 + type ICoord<'a, T> = (usize, &'a Vertex<T>);
  46 +
  47 + let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a, T>|
  48 + match acc {
  49 + None => Some(x),
  50 + Some(a) => {
  51 + let (_, ay, _) = a.1.as_tuple();
  52 + let (_, xy, _) = x.1.as_tuple();
  53 + if xy < ay {Some(x)} else {Some(a)}
  54 + },
  55 + };
  56 +
  57 + let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0;
  58 + let mut next = self.step(min, d);
  59 +
  60 + while self.vertex(min).same_y(&self.vertex(next)) {
  61 + min = next;
  62 + next = self.step(min, d);
  63 + }
  64 +
  65 + min
  66 + }
  67 +
  68 + fn left_edge(&self) -> VertexIterator<T> {
  69 + VertexIterator::edge(self, Direction::Left)
  70 + }
  71 +
  72 + fn right_edge(&self) -> VertexIterator<T> {
  73 + VertexIterator::edge(self, Direction::Right)
  74 + }
  75 +
  76 + fn left_vertices(&self) -> VertexIterator<T> {
  77 + VertexIterator::line(self, Direction::Left)
  78 + }
  79 +
  80 + fn right_vertices(&self) -> VertexIterator<T> {
  81 + VertexIterator::line(self, Direction::Right)
  82 + }
  83 +
  84 + fn left(&self, v :usize) -> usize {
  85 + let Polygon(cs) = self;
  86 +
  87 + match v {
  88 + 0 => cs.len() - 1,
  89 + _ => v - 1,
  90 + }
  91 + }
  92 +
  93 + fn right(&self, v :usize) -> usize {
  94 + let Polygon(cs) = self;
  95 +
  96 + (v + 1) % cs.len()
  97 + }
  98 +
  99 + fn step(&self, v :usize, d :Direction) -> usize {
  100 + match d {
  101 + Direction::Left => self.left(v),
  102 + Direction::Right => self.right(v),
  103 + }
  104 + }
  105 +
  106 + pub fn next_y(&self, c :usize, d :Direction) -> Option<usize> {
  107 + fn inner<T>( p :&Polygon<T>
  108 + , c :usize
  109 + , n :usize
  110 + , d :Direction) -> Option<usize>
  111 + where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  112 + + Copy + Debug + From<i32> {
  113 + if c == n {
  114 + None
  115 + } else {
  116 + let (_, cy, _) = p.vertex(c).as_tuple();
  117 + let (_, ny, _) = p.vertex(n).as_tuple();
  118 +
  119 + if ny < cy { None } else { Some(n) }
  120 + }
  121 + }
  122 +
  123 + inner(self, c, self.step(c, d), d)
  124 + }
  125 +}
  126 +
  127 +impl<T> Drawable<T> for Polygon<T>
  128 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  129 + + Debug + Clone + Copy + From<i32> {
  130 + fn plot(&self) -> Vertices<T> {
  131 + let Polygon(cs) = self;
  132 +
  133 + match cs[..] {
  134 + [] => Vec::<Vertex<T>>::new(),
  135 + [a] => vec!(a),
  136 + [a, b] => a.line(b),
  137 + _ => {
  138 + let (a, b) = (cs[0], cs[1]);
  139 + let mut r = a.line(b);
  140 + let mut i = b;
  141 + for j in cs[2..].iter() {
  142 + r.append(&mut i.line(*j)[1..].to_vec());
  143 + i = *j;
  144 + }
  145 + let mut j = a.line(i);
  146 + let l = j.len();
  147 + if l > 1 {
  148 + r.append(&mut j[1..l-1].to_vec());
  149 + }
  150 + r
  151 + },
  152 + }
  153 + }
  154 +}
  155 +
  156 +impl<T> Fillable<T> for Polygon<T>
  157 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  158 + + Debug + Clone + Copy + From<i32> {
  159 + fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {
  160 + let scanlines = self.left_edge().zip(self.right_edge());
  161 + let vertices = |(l, r) :(Vertex<T>, Vertex<T>)| l.line_iter(r);
  162 +
  163 + for p in scanlines.flat_map(vertices) {
  164 + canvas.set_pixel(p, color);
  165 + }
  166 + }
  167 +}
  168 +
  169 +/*
  170 +impl<T> Display for Polygon<T> where T: Copy {
  171 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  172 + let Polygon(a) = self;
  173 + write!(f, "Poly[{}]", a)
  174 + }
  175 +}
  176 +*/
... ...
  1 +//
  2 +// …
  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, Sub};
  24 +
  25 +use super::canvas::{Vertex, Vertices};
  26 +use super::drawable::Drawable;
  27 +
  28 +#[derive(Debug, Clone)]
  29 +pub struct Polyline<T>(pub Vertices<T>);
  30 +
  31 +impl<T> Drawable<T> for Polyline<T>
  32 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  33 + + Debug + Clone + Copy + From<i32> {
  34 + fn plot(&self) -> Vertices<T> {
  35 + let Polyline(cs) = self;
  36 +
  37 + match cs[..] {
  38 + [] => Vec::<Vertex<T>>::new(),
  39 + [a] => vec!(a),
  40 + [a, b] => a.line(b),
  41 + _ => {
  42 + let (a, b) = (cs[0], cs[1]);
  43 + let mut r = a.line(b);
  44 + let mut i = b;
  45 + for j in cs[2..].iter() {
  46 + r.append(&mut i.line(*j)[1..].to_vec());
  47 + i = *j;
  48 + }
  49 + r
  50 + },
  51 + }
  52 + }
  53 +}
  54 +/*
  55 +impl<T> Display for Polyline<T> where T: Copy {
  56 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  57 + let Polyline(a) = self;
  58 + write!(f, "PLine[{}]", a)
  59 + }
  60 +}
  61 +*/
... ...
  1 +//
  2 +// …
  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;
  22 +use std::ops::{Add, Sub, Div};
  23 +
  24 +use super::line_iterator::LineIterator;
  25 +use super::canvas::Vertex;
  26 +use super::polygon::Polygon;
  27 +
  28 +#[derive(Debug, Clone, Copy)]
  29 +pub enum Direction {
  30 + Left,
  31 + Right,
  32 +}
  33 +
  34 +#[derive(Debug, Clone)]
  35 +enum VertexIteratorMode {
  36 + Line,
  37 + Edge
  38 +}
  39 +
  40 +#[derive(Debug, Clone)]
  41 +pub struct VertexIterator<'a, T> where T: Debug {
  42 + p :&'a Polygon<T>,
  43 + top :usize,
  44 + current :Option<usize>,
  45 + edge :Option<LineIterator<T>>,
  46 + mode :VertexIteratorMode,
  47 + direction :Direction,
  48 +}
  49 +
  50 +impl<'a, T> VertexIterator<'a, T>
  51 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  52 + + Debug + Copy + From<i32> {
  53 + pub fn line(p :&'a Polygon<T>, direction :Direction) -> Self {
  54 + let top = p.vert_min(direction);
  55 + let next = p.next_y(top, direction);
  56 +
  57 + VertexIterator { p: p
  58 + , top: top
  59 + , current: next
  60 + , edge: None
  61 + , mode: VertexIteratorMode::Line
  62 + , direction: direction }
  63 + }
  64 +
  65 + pub fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {
  66 + let mut vi = Self::line(p, direction);
  67 +
  68 + vi.mode = VertexIteratorMode::Edge;
  69 + vi.edge = match vi.current {
  70 + None => None,
  71 + Some(next) => Some(p.vertex(vi.top).edge_iter(p.vertex(next))),
  72 + };
  73 +
  74 + vi
  75 + }
  76 +
  77 + // if this yields "None" we are finished.
  78 + fn next_edge(&mut self) -> Option<LineIterator<T>> {
  79 + let current = self.current?;
  80 + let next = self.p.next_y(current, self.direction)?;
  81 + let mut edge = self.p.vertex(current).edge_iter(self.p.vertex(next));
  82 +
  83 + match edge.next() {
  84 + // It should be impossible that a new edge iterator has no values
  85 + // at all… anyway, just in case I handle it here.
  86 + None => self.next_edge(),
  87 + Some(_) => {
  88 + self.current = Some(next);
  89 + self.edge = Some(edge);
  90 + self.edge
  91 + },
  92 + }
  93 + }
  94 +}
  95 +
  96 +impl<'a,T> Iterator for VertexIterator<'a,T>
  97 +where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
  98 + + Debug + Copy + From<i32> {
  99 + type Item = Vertex<T>;
  100 +
  101 + fn next(&mut self) -> Option<Self::Item> {
  102 + match self.mode {
  103 + VertexIteratorMode::Edge => {
  104 + // if for whatever reason edge is "None" finish this iterator.
  105 + let next = self.edge.as_mut()?.next();
  106 +
  107 + match next {
  108 + Some(_) => next,
  109 + None => {
  110 + self.next_edge()?;
  111 + self.next()
  112 + },
  113 + }
  114 + },
  115 + VertexIteratorMode::Line => {
  116 + let current = self.current?;
  117 + self.current = self.p.next_y(current, self.direction);
  118 + Some(self.p.vertex(current))
  119 + },
  120 + }
  121 + }
  122 +}
... ...
... ... @@ -22,7 +22,8 @@ use std::convert::{From, Into};
22 22 use std::ops::{Add,Sub,Neg,Mul,Div};
23 23 use std::fmt::Debug;
24 24
25   -use crate::easel::{Canvas, Coordinate, Coordinates, Polygon};
  25 +use crate::easel::canvas::{Canvas, Vertex};
  26 +use crate::easel::polygon::Polygon;
26 27 use crate::transform::{TMatrix, Transformable};
27 28 use crate::trigonometry::Trig;
28 29 use crate::vector::Vector;
... ... @@ -251,20 +252,15 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
251 252 let f2 :T = 2.into();
252 253 let ch = a / (f2 * T::sqrt(f2).unwrap());
253 254
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
  255 + let ps = vec!( Point::new(-ch, -ch, ch)
  256 + , Point::new(-ch, ch, -ch)
  257 + , Point::new( ch, -ch, -ch)
  258 + , Point::new( ch, ch, ch) );
258 259
259   - // bottom: 1, 2, 3
260 260 let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom
261 261 , Face::new(vec!(3, 2, 0), &ps)
262 262 , Face::new(vec!(0, 1, 3), &ps)
263 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 264
269 265 Polyeder{ points: ps, faces: fs }
270 266 }
... ... @@ -335,15 +331,15 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
335 331 // Helper to create a Polygon from Coordinates…
336 332 // TODO probably there needs to be a Polygon constructor for this.
337 333 fn polygon<I, T>(c :I) -> Polygon<T>
338   - where I: Iterator<Item = Coordinate<T>> {
339   - Polygon(Coordinates(c.collect()))
  334 + where I: Iterator<Item = Vertex<T>> {
  335 + Polygon(c.collect())
340 336 }
341 337
342 338 // this one does the projection... as the projection was the last
343 339 // matrix we do not need to do it here.
344 340 let to_coord = |p :&usize| {
345 341 let Point(v, _) = camera.project(self.points[*p]);
346   - Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())
  342 + Vertex::new(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())
347 343 };
348 344 let to_poly = |f :&Face<T>| {
349 345 let pg = polygon(f.corners.iter().map(to_coord));
... ...
  1 +//
  2 +// easel3d is a library that provides basic math for 3D transformation and
  3 +// projection as well as a simple software resterizer.
  4 +//
  5 +// All of them implemented as generics so that they work with f64 and other
  6 +// suitable types.
  7 +//
  8 +// This is mainly the result of my learning rust experiments. So it is
  9 +// very likely not optimal and improvements and suggestions are welcome.
  10 +//
  11 +// The rasterization part, called easel consists of two traits (easel and
  12 +// canvas) where the one is cuttently empty because I found no methods that
  13 +// I currently need. And the other needs to be implemented to get a
  14 +// concrete rasterizer. After that one can use all of the other types there.
  15 +//
  16 +// Georg Hopp <georg@steffers.org>
  17 +//
  18 +// Copyright © 2019 Georg Hopp
  19 +//
  20 +// This program is free software: you can redistribute it and/or modify
  21 +// it under the terms of the GNU General Public License as published by
  22 +// the Free Software Foundation, either version 3 of the License, or
  23 +// (at your option) any later version.
  24 +//
  25 +// This program is distributed in the hope that it will be useful,
  26 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  27 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28 +// GNU General Public License for more details.
  29 +//
  30 +// You should have received a copy of the GNU General Public License
  31 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  32 +//
1 33 extern crate lazy_static;
2 34
3 35 pub type Error = &'static str;
... ... @@ -11,253 +43,3 @@ pub mod geometry;
11 43 mod utils;
12 44
13 45 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   -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   -}
Please register or login to post a comment