// // This is an abstraction over a drawing environment. // Future note: z-Buffer is described here: // https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes // // Georg Hopp // // Copyright © 2019 Georg Hopp // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // use std::cmp; use std::fmt::{Formatter, Debug, Display, Result}; use std::ops::{Add, Sub, Div}; use std::sync::mpsc; pub trait Easel { //fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>; } pub trait Canvas { fn init_events(&self); fn start_events(&self, tx :mpsc::Sender); fn width(&self) -> u16; fn height(&self) -> u16; fn clear(&mut self); fn draw(&mut self, c :&dyn Drawable, ofs :Coordinate, color :u32); fn put_text(&self, ofs :Coordinate, s :&str); fn set_pixel(&mut self, c :Coordinate, color :u32); fn show(&self); } pub trait Drawable { fn plot(&self) -> Coordinates; } pub trait Fillable where T: Add + Sub + Div + Debug + Copy + From { fn fill(&self, canvas :&mut dyn Canvas, color :u32); } #[derive(Debug, Clone, Copy)] pub struct Coordinate(pub i32, pub i32, pub T); #[derive(Debug, Clone)] pub struct Coordinates(pub Vec>); #[derive(Debug, Clone, Copy)] pub struct LineIterator where T: Debug { a :Option> , b :Coordinate , dx :i32 , dy :i32 , dz :T , sx :i32 , sy :i32 , err :i32 , only_edges :bool } impl Iterator for LineIterator where T: Add + Debug + Copy + From { type Item = Coordinate; fn next(&mut self) -> Option { match self.a { None => None, Some(a) => { let Coordinate(ax, ay, az) = a; let Coordinate(bx, by, _) = self.b; if ax != bx || ay != by { match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) { (true, false) => { let r = self.a; self.a = Some(Coordinate( ax + self.sx , ay , az + self.dz )); self.err = self.err + self.dy; if self.only_edges { self.next() } else { r } }, (false, true) => { let r = self.a; self.a = Some(Coordinate( ax , ay + self.sy , az + self.dz )); self.err = self.err + self.dx; r }, _ => { let r = self.a; self.a = Some(Coordinate( ax + self.sx , ay + self.sy , az + self.dz )); self.err = self.err + self.dx + self.dy; r }, } } else { self.a = None; Some(self.b) } } } } } impl Coordinate where T: Add + Sub + Div + Debug + Clone + Copy + From { fn iter(self, b :&Self, only_edges :bool) -> LineIterator { let Coordinate(ax, ay, az) = self; let Coordinate(bx, by, bz) = *b; let dx = (bx - ax).abs(); let dy = -(by - ay).abs(); LineIterator { a: Some(self) , b: *b , dx: dx , dy: dy , dz: (bz - az) / cmp::max(dx, -dy).into() , sx: if ax < bx { 1 } else { -1 } , sy: if ay < by { 1 } else { -1 } , err: dx + dy , only_edges: only_edges } } fn line_iter(self, b :&Self) -> LineIterator { self.iter(b, false) } fn line(self, b :&Self) -> Vec { self.line_iter(b).collect() } fn edge_iter(self, b :&Self) -> LineIterator { self.iter(b, true) } fn edge(self, b :&Self) -> Vec { self.edge_iter(b).collect() } fn face(edges :&[Self]) -> Vec { edges.to_vec() } } impl Display for Coordinate { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!(f, "<{},{}>", self.0, self.1) } } impl Display for Coordinates where T: Copy { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Coordinates(is) = self; let c = match is[..] { [] => String::from(""), [a] => format!("{}", a), _ => { let mut a = format!("{}", is[0]); for i in is[1..].iter() { a = a + &format!(",{}", i); } a } }; write!(f, "Coordinates[{}]", c) } } #[derive(Debug, Clone, Copy)] pub struct Point(pub Coordinate); impl Drawable for Point where T: Copy { fn plot(&self) -> Coordinates { let Point(c) = *self; Coordinates(vec!(c)) } } impl Display for Point { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Point(p) = self; write!(f, "Point[{}]", p) } } #[derive(Debug, Clone, Copy)] pub struct Line(pub Coordinate, pub Coordinate); impl Drawable for Line where T: Add + Sub + Div + Debug + Clone + Copy + From { fn plot(&self) -> Coordinates { let Line(a, b) = *self; Coordinates(a.line(&b)) } } impl Display for Line { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Line(a, b) = self; write!(f, "Line[{},{}]", a, b) } } #[derive(Debug, Clone)] pub struct Polyline(pub Coordinates); impl Drawable for Polyline where T: Add + Sub + Div + Debug + Clone + Copy + From { fn plot(&self) -> Coordinates { let Polyline(Coordinates(cs)) = self; match cs[..] { [] => Coordinates(Vec::>::new()), [a] => Coordinates(vec!(a)), [a, b] => Coordinates(a.line(&b)), _ => { let (a, b) = (cs[0], cs[1]); let mut r = a.line(&b); let mut i = b; for j in cs[2..].iter() { r.append(&mut i.line(j)[1..].to_vec()); i = *j; } Coordinates(r) }, } } } impl Display for Polyline where T: Copy { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Polyline(a) = self; write!(f, "PLine[{}]", a) } } #[derive(Debug, Clone, Copy)] enum Direction { Left, Right } #[derive(Debug, Clone)] pub struct Polygon(pub Coordinates); #[derive(Debug, Clone)] enum VertexIteratorMode { Vertex, Edge } #[derive(Debug, Clone)] pub struct VertexIterator<'a,T> where T: Debug { p :&'a Polygon, top :usize, current :Option, edge :Option>, mode :VertexIteratorMode, direction :Direction, } impl<'a,T> VertexIterator<'a,T> where T: Add + Sub + Div + Debug + Copy + From { fn edge(p :&'a Polygon, direction :Direction) -> Self { let top = p.vert_min(direction); let next = p.next_y(top, direction); let edge = match next { None => None, Some(next) => Some(p.vertex(top).edge_iter(&p.vertex(next))), }; VertexIterator { p: p , top: top , current: next , edge: edge , mode: VertexIteratorMode::Edge , direction: direction } } fn vertex(p :&'a Polygon, direction :Direction) -> Self { let top = p.vert_min(direction); let next = p.next_y(top, direction); VertexIterator { p: p , top: top , current: next , edge: None , mode: VertexIteratorMode::Vertex , direction: direction } } // if this yields "None" we are finished. fn next_edge(&mut self) -> Option> { let current = self.current?; let next = self.p.next_y(current, self.direction)?; let mut edge = self.p.vertex(current).edge_iter(&self.p.vertex(next)); match edge.next() { // It should be impossible that a new edge iterator has no values // at all… anyway, just in case I handle it here. None => self.next_edge(), Some(_) => { self.current = Some(next); self.edge = Some(edge); self.edge }, } } } impl<'a,T> Iterator for VertexIterator<'a,T> where T: Add + Sub + Div + Debug + Copy + From { type Item = Coordinate; fn next(&mut self) -> Option { match self.mode { VertexIteratorMode::Edge => { // if for whatever reason edge is "None" finish this iterator. let next = self.edge.as_mut()?.next(); match next { Some(_) => next, None => { self.next_edge()?; self.next() }, } }, VertexIteratorMode::Vertex => { let current = self.current?; self.current = self.p.next_y(current, self.direction); Some(self.p.vertex(current)) }, } } } impl Polygon where T: Add + Sub + Div + Copy + Debug + From { #[inline] fn vertex(&self, v :usize) -> Coordinate { let Polygon(Coordinates(cs)) = self; cs[v] } fn vert_min<'a>(&'a self, d :Direction) -> usize { let Polygon(Coordinates(cs)) = self; type ICoord<'a,T> = (usize, &'a Coordinate); // TODO I guess the problem here is that it does not account for the // same y vertex on the beggining and the end. So i guess correct // would be finding the first one and then dependings on the // given direction either search left or right for same y's. let fold = |acc :Option>, x :ICoord<'a,T>| match acc { None => Some(x), Some(a) => { let Coordinate(_, ay, _) = a.1; let Coordinate(_, xy, _) = x.1; if xy < ay {Some(x)} else {Some(a)} }, }; let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0; let mut next = self.step(min, d); while self.vertex(min).1 == self.vertex(next).1 { min = next; next = self.step(min, d); } min } fn left_edge(&self) -> VertexIterator { VertexIterator::edge(self, Direction::Left) } fn right_edge(&self) -> VertexIterator { VertexIterator::edge(self, Direction::Right) } fn left_vertices(&self) -> VertexIterator { VertexIterator::vertex(self, Direction::Left) } fn right_vertices(&self) -> VertexIterator { VertexIterator::vertex(self, Direction::Right) } fn left(&self, v :usize) -> usize { let Polygon(Coordinates(cs)) = self; match v { 0 => cs.len() - 1, _ => v - 1, } } fn right(&self, v :usize) -> usize { let Polygon(Coordinates(cs)) = self; (v + 1) % cs.len() } fn step(&self, v :usize, d :Direction) -> usize { match d { Direction::Left => self.left(v), Direction::Right => self.right(v), } } fn next_y(&self, c :usize, d :Direction) -> Option { fn inner( p :&Polygon , c :usize , n :usize , d :Direction) -> Option where T: Add + Sub + Div + Copy + Debug + From { if c == n { None } else { let Coordinate(_, cy, _) = p.vertex(c); let Coordinate(_, ny, _) = p.vertex(n); if ny < cy { None } else { Some(n) } } } inner(self, c, self.step(c, d), d) } pub fn debug(&self) { let mut left = self.left_vertices(); let mut right = self.right_vertices(); if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() { let left :Vec> = self.left_vertices().collect(); let right :Vec> = self.right_vertices().collect(); println!("==="); println!("== poly : {:?}", self); println!("== ltop : {:?}", self.vert_min(Direction::Left)); println!("== rtop : {:?}", self.vert_min(Direction::Right)); println!("== left : {:?}", left); println!("== right : {:?}", right); println!("==="); } } } impl Drawable for Polygon where T: Add + Sub + Div + Debug + Clone + Copy + From { fn plot(&self) -> Coordinates { let Polygon(Coordinates(cs)) = self; match cs[..] { [] => Coordinates(Vec::>::new()), [a] => Coordinates(vec!(a)), [a, b] => Coordinates(a.line(&b)), _ => { let (a, b) = (cs[0], cs[1]); let mut r = a.line(&b); let mut i = b; for j in cs[2..].iter() { r.append(&mut i.line(j)[1..].to_vec()); i = *j; } let mut j = a.line(&i); let l = j.len(); if l > 1 { r.append(&mut j[1..l-1].to_vec()); } Coordinates(r) }, } } } impl Fillable for Polygon where T: Add + Sub + Div + Debug + Clone + Copy + From { fn fill(&self, canvas :&mut dyn Canvas, color :u32) { let scanlines = self.left_edge().zip(self.right_edge()); for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) { canvas.set_pixel(l, color); } } } impl Display for Polygon where T: Copy { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Polygon(a) = self; write!(f, "Poly[{}]", a) } }