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,7 +22,8 @@ use std::convert::{From, Into};
22 use std::ops::{Add,Sub,Neg,Mul,Div}; 22 use std::ops::{Add,Sub,Neg,Mul,Div};
23 use std::fmt::Debug; 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 use crate::transform::{TMatrix, Transformable}; 27 use crate::transform::{TMatrix, Transformable};
27 use crate::trigonometry::Trig; 28 use crate::trigonometry::Trig;
28 use crate::vector::Vector; 29 use crate::vector::Vector;
@@ -251,20 +252,15 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> @@ -251,20 +252,15 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
251 let f2 :T = 2.into(); 252 let f2 :T = 2.into();
252 let ch = a / (f2 * T::sqrt(f2).unwrap()); 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 let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom 260 let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom
261 , Face::new(vec!(3, 2, 0), &ps) 261 , Face::new(vec!(3, 2, 0), &ps)
262 , Face::new(vec!(0, 1, 3), &ps) 262 , Face::new(vec!(0, 1, 3), &ps)
263 , Face::new(vec!(1, 2, 3), &ps) ); 263 , Face::new(vec!(1, 2, 3), &ps) );
264 - //let fs = vec!( Face::new(vec!(0, 1, 2), &ps) // bottom  
265 - // , Face::new(vec!(0, 2, 3), &ps)  
266 - // , Face::new(vec!(3, 1, 0), &ps)  
267 - // , Face::new(vec!(3, 2, 1), &ps) );  
268 264
269 Polyeder{ points: ps, faces: fs } 265 Polyeder{ points: ps, faces: fs }
270 } 266 }
@@ -335,15 +331,15 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> @@ -335,15 +331,15 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
335 // Helper to create a Polygon from Coordinates… 331 // Helper to create a Polygon from Coordinates…
336 // TODO probably there needs to be a Polygon constructor for this. 332 // TODO probably there needs to be a Polygon constructor for this.
337 fn polygon<I, T>(c :I) -> Polygon<T> 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 // this one does the projection... as the projection was the last 338 // this one does the projection... as the projection was the last
343 // matrix we do not need to do it here. 339 // matrix we do not need to do it here.
344 let to_coord = |p :&usize| { 340 let to_coord = |p :&usize| {
345 let Point(v, _) = camera.project(self.points[*p]); 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 let to_poly = |f :&Face<T>| { 344 let to_poly = |f :&Face<T>| {
349 let pg = polygon(f.corners.iter().map(to_coord)); 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 extern crate lazy_static; 33 extern crate lazy_static;
2 34
3 pub type Error = &'static str; 35 pub type Error = &'static str;
@@ -11,253 +43,3 @@ pub mod geometry; @@ -11,253 +43,3 @@ pub mod geometry;
11 mod utils; 43 mod utils;
12 44
13 use vector::Vector; 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