diff --git a/fractional/src/easel.rs b/fractional/src/easel.rs index f43535d..1a19379 100644 --- a/fractional/src/easel.rs +++ b/fractional/src/easel.rs @@ -21,7 +21,7 @@ // along with this program. If not, see . // use std::cmp; -use std::fmt::{Formatter, Display, Result}; +use std::fmt::{Formatter, Debug, Display, Result}; use std::ops::{Add, Sub, Div}; use std::sync::mpsc; @@ -46,6 +46,10 @@ pub trait Drawable { fn plot(&self) -> Coordinates; } +pub trait Fillable { + fn fill(&self) -> Coordinates; +} + #[derive(Debug, Clone, Copy)] pub struct Coordinate(pub i32, pub i32, pub T); @@ -82,15 +86,15 @@ where T: Add + Sub + Div let dx = (bx - ax).abs(); let sx :i32 = if ax < bx { 1 } else { -1 }; - let dy = -(by - ay).abs(); + let dy = (by - ay).abs(); let sy :i32 = if ay < by { 1 } else { -1 }; - let size = cmp::max(dx, -dy); + let size = cmp::max(dx, dy); let dz = (bz - az) / size.into(); let mut v :Vec = vec!( Coordinate(0, 0, 0.into()) ; (size as usize) + 1); v[0] = Coordinate(ax, ay, az); - inner(&mut v, bx, by, dx, dy, sx, sy, dz, dx + dy); + inner(&mut v, bx, by, dx, -dy, sx, sy, dz, dx - dy); v } } @@ -258,6 +262,129 @@ where T: Add + Sub + Div } } +impl Fillable for Polygon +where T: Add + Sub + Div + + Debug + Clone + Copy + From { + fn fill(&self) -> Coordinates { + + /* bresenham kind of thing to get the outer x values for each y of one + * edge of the polygon. */ + fn walk_edge( a :Coordinate + , b :Coordinate ) -> Vec> + where T: Add + Sub + Div + + From + Debug + Copy { + + let Coordinate(mut x, mut y, mut z) = a; + let Coordinate( bx, by, bz) = b; + + // next should be called with the negative of this… but dz depends + // on the positive this. + let dy = -(by - y).abs(); + let dx = (bx - x).abs(); + let sx = if x < bx { 1 } else { -1 }; + let dz = (bz - z) / (-dy).into(); + let mut err = dx + dy; + + let mut v = Vec::>::with_capacity((-dy) as usize); + + while y != by { + match (2*err >= dy, 2*err <= dx) { + (true, false) => { x = x + sx + ; err = err + dy }, + (false, true) => { v.push(Coordinate(x, y, z)) + ; y = y + 1 + ; z = z + dz + ; err = err + dx }, + _ => { v.push(Coordinate(x, y, z)) + ; x = x + sx + ; y = y + 1 + ; z = z + dz + ; err = err + dx + dy }, + } + } + + v + } + + fn next_y( cs :&[Coordinate] + , c :usize + , f :&dyn Fn(usize) -> usize) -> Option { + fn inner( cs :&[Coordinate] + , c :usize + , n :usize + , f :&dyn Fn(usize) -> usize) -> Option { + if c == n { + None + } else { + let Coordinate(_, cy, _) = cs[c]; + let Coordinate(_, ny, _) = cs[n]; + + match ny.cmp(&cy) { + cmp::Ordering::Less => None, + cmp::Ordering::Equal => inner(cs, c, f(n), f), + cmp::Ordering::Greater => Some(n), + } + } + } + + inner(cs, c, f(c), f) + } + + let Polygon(Coordinates(cs)) = self; + + let vert_min = cs.iter().enumerate() + . fold( None + , |acc, x| 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)} } } ) + . unwrap().0; + + println!("== vert_min: [{:?}] - {:?}", vert_min, cs[vert_min]); + + let right = |x :usize| (x + 1) % cs.len(); + let left = |x :usize| if x == 0 { cs.len() - 1 } else { x - 1 }; + + let mut r = (vert_min, next_y(cs, vert_min, &right)); + let mut l = (vert_min, next_y(cs, vert_min, &left)); + + let mut l_edge :Vec> = Vec::new(); + let mut r_edge :Vec> = Vec::new(); + + while l.1 != None || r.1 != None { + match l.1 { + None => {}, + Some(a) => { + println!("== l: [{:?}] - {:?}", l, cs[a]); + l_edge.append(&mut walk_edge(cs[l.0], cs[a])); + l = (a, next_y(cs, a, &left)); + }, + } + + match r.1 { + None => {}, + Some(a) => { + println!("== r: [{:?}] - {:?}", r, cs[a]); + r_edge.append(&mut walk_edge(cs[r.0], cs[a])); + r = (a, next_y(cs, a, &right)); + } + } + } + + println!("== [{}] {:?}", l_edge.len(), l_edge); + println!("== [{}] {:?}", r_edge.len(), r_edge); + + // TODO we always miss the last scanline… + // TODO check what happend with at least 2 vertices with same y and + // different x… + // loop though edges… + + Coordinates(Vec::>::new()) + } +} + impl Display for Polygon where T: Copy { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Polygon(a) = self; diff --git a/fractional/src/geometry.rs b/fractional/src/geometry.rs index 51ce90d..47d0bf0 100644 --- a/fractional/src/geometry.rs +++ b/fractional/src/geometry.rs @@ -22,7 +22,7 @@ use std::convert::{From, Into}; use std::ops::{Add,Sub,Neg,Mul,Div}; use std::fmt::Debug; -use crate::easel::{Canvas,Coordinate,Coordinates,Polygon}; +use crate::easel::{Canvas,Coordinate,Coordinates,Polygon,Fillable}; use crate::transform::{TMatrix, Transformable}; use crate::trigonometry::Trig; use crate::vector::Vector; @@ -347,7 +347,7 @@ where T: Add + Sub + Neg // matrix we do not need to do it here. let to_coord = |p :&usize| { let Point(v, _) = camera.project(self.points[*p]); - println!("== {:?} / {:?}", self.points[*p], (v.z() - 1.into()).recip()); + // println!("== {:?} / {:?}", self.points[*p], (v.z() - 1.into()).recip()); Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into()) }; let to_poly = |f :&Face| { @@ -361,6 +361,8 @@ where T: Add + Sub + Neg / (n.mag() * light.dir().mag()), }; + // this if represents a first simple backface culling + // approach. We only return face that face towards us. if lf < 0.into() { r = r * -lf; g = g * -lf; @@ -370,14 +372,18 @@ where T: Add + Sub + Neg | (g.round() as u32) << 8 | (b.round() as u32); + (&pg).fill(); + Some((pg, c)) } else { None }}; - let mut ps :Vec<(Polygon, u32)> = self.faces.iter() - . filter_map(to_poly).collect(); - ps.sort_by(|a, b| a.1.cmp(&b.1)); + let ps :Vec<(Polygon, u32)> = self.faces.iter() + . filter_map(to_poly).collect(); + // this sorts by the color value which is no longer neccessary as soon + // as the z-buffer is complete. + // ps.sort_by(|a, b| a.1.cmp(&b.1)); ps } }