From df1eb1c028b102449d53eaed293ec36e442690e5 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 3 Jan 2020 18:45:10 +0100 Subject: [PATCH] Pass 1/z into rasterizer and already interpolate on polygon edges --- fractional/src/easel.rs | 114 +++++++++++++++++++++---------------- fractional/src/geometry.rs | 28 ++++----- fractional/src/main.rs | 51 ++++++++--------- fractional/src/xcb.rs | 18 +++--- 4 files changed, 114 insertions(+), 97 deletions(-) diff --git a/fractional/src/easel.rs b/fractional/src/easel.rs index 6a2ea27..f43535d 100644 --- a/fractional/src/easel.rs +++ b/fractional/src/easel.rs @@ -22,13 +22,14 @@ // use std::cmp; use std::fmt::{Formatter, 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 { +pub trait Canvas { fn init_events(&self); fn start_events(&self, tx :mpsc::Sender); @@ -36,65 +37,71 @@ pub trait Canvas { 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 draw(&mut self, c :&dyn Drawable, ofs :Coordinate, color :u32); + fn put_text(&self, ofs :Coordinate, s :&str); fn show(&self); } -pub trait Drawable { - fn plot(&self) -> Coordinates; +pub trait Drawable { + fn plot(&self) -> Coordinates; } #[derive(Debug, Clone, Copy)] -pub struct Coordinate(pub i32, pub i32); +pub struct Coordinate(pub i32, pub i32, pub T); #[derive(Debug, Clone)] -pub struct Coordinates(pub Vec); +pub struct Coordinates(pub Vec>); -impl Coordinate { +impl Coordinate +where T: Add + Sub + Div + + Clone + Copy + From { // Tail recursive Bresenham line with integer incremental error. fn line(self, b :&Self) -> Vec { - fn inner( v :&mut [Coordinate] + fn inner( v :&mut [Coordinate] , bx :i32, by :i32 , dx :i32, dy :i32 , sx :i32, sy :i32 - , err :i32) { - let Coordinate(x, y) = v[0]; + , dz :T, err :i32) + where T: Add + Copy { + + let Coordinate(x, y, z) = v[0]; if x != bx || y != by { - let (x, y, err) = match (2*err >= dy, 2*err <= dx) { - (true, false) => (x + sx, y, err + dy), - (false, true) => ( x, y + sy, err + dx), - _ => (x + sx, y + sy, err + dx + dy ), + let (x, y, z, err) = match (2*err >= dy, 2*err <= dx) { + (true, false) => (x + sx, y, z + dz, err + dy ), + (false, true) => ( x, y + sy, z + dz, err + dx ), + _ => (x + sx, y + sy, z + dz, err + dx + dy ), }; - v[1] = Coordinate(x, y); - inner(&mut v[1..], bx, by, dx, dy, sx, sy, err); + v[1] = Coordinate(x, y, z); + inner(&mut v[1..], bx, by, dx, dy, sx, sy, dz, err); } } - let Coordinate(ax, ay) = self; - let Coordinate(bx, by) = *b; + let Coordinate(ax, ay, az) = self; + let Coordinate(bx, by, bz) = *b; let dx = (bx - ax).abs(); let sx :i32 = if ax < bx { 1 } else { -1 }; let dy = -(by - ay).abs(); let sy :i32 = if ay < by { 1 } else { -1 }; + let size = cmp::max(dx, -dy); + let dz = (bz - az) / size.into(); - let mut v :Vec = vec!( Coordinate(0, 0) - ; cmp::max(dx, -dy) as usize + 1); - v[0] = Coordinate(ax, ay); - inner(&mut v, bx, by, dx, dy, sx, sy, dx + dy); + 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); v } } -impl Display for Coordinate { +impl Display for Coordinate { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!(f, "<{},{}>", self.0, self.1) } } -impl Display for Coordinates { +impl Display for Coordinates where T: Copy { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Coordinates(is) = self; @@ -116,16 +123,16 @@ impl Display for Coordinates { #[derive(Debug, Clone, Copy)] -pub struct Point(pub Coordinate); +pub struct Point(pub Coordinate); -impl Drawable for Point{ - fn plot(&self) -> Coordinates { +impl Drawable for Point where T: Copy { + fn plot(&self) -> Coordinates { let Point(c) = *self; Coordinates(vec!(c)) } } -impl Display for Point { +impl Display for Point { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Point(p) = self; write!(f, "Point[{}]", p) @@ -133,30 +140,36 @@ impl Display for Point { } #[derive(Debug, Clone, Copy)] -pub struct Line(pub Coordinate, pub Coordinate); +pub struct Line(pub Coordinate, pub Coordinate); -impl Drawable for Line { - fn plot(&self) -> Coordinates { +impl Drawable for Line +where T: Add + Sub + Div + + Clone + Copy + From { + fn plot(&self) -> Coordinates { let Line(a, b) = *self; Coordinates(a.line(&b)) } } -impl Display for Line { +impl Display for Line { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Line(a, b) = self; write!(f, "Line[{},{}]", a, b) } } +// In 3D a rectangle is not as trivial as in 2D, it might be somehow rotate +// and thus we need to specify a Z offset for the other two corners. +// As I do not need rectangle at all I just comment out this code for now. +/* #[derive(Debug, Clone, Copy)] -pub struct Rectangle(pub Coordinate, pub Coordinate); +pub struct Rectangle(pub Coordinate, pub Coordinate); -impl Drawable for Rectangle { - fn plot(&self) -> Coordinates { +impl Drawable for Rectangle { + fn plot(&self) -> Coordinates { let Rectangle(a, c) = *self; - let Coordinate(ax, ay) = a; - let Coordinate(cx, cy) = c; + let Coordinate(ax, ay, az) = a; + let Coordinate(cx, cy, cz) = c; let b = Coordinate(cx, ay); let d = Coordinate(ax, cy); @@ -177,16 +190,19 @@ impl Display for Rectangle { write!(f, "Rec[{},{}]", a, b) } } +*/ #[derive(Debug, Clone)] -pub struct Polyline(pub Coordinates); +pub struct Polyline(pub Coordinates); -impl Drawable for Polyline { - fn plot(&self) -> Coordinates { +impl Drawable for Polyline +where T: Add + Sub + Div + + Clone + Copy + From { + fn plot(&self) -> Coordinates { let Polyline(Coordinates(cs)) = self; match cs[..] { - [] => Coordinates(Vec::::new()), + [] => Coordinates(Vec::>::new()), [a] => Coordinates(vec!(a)), [a, b] => Coordinates(a.line(&b)), _ => { @@ -203,7 +219,7 @@ impl Drawable for Polyline { } } -impl Display for Polyline { +impl Display for Polyline where T: Copy { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Polyline(a) = self; write!(f, "PLine[{}]", a) @@ -211,14 +227,16 @@ impl Display for Polyline { } #[derive(Debug, Clone)] -pub struct Polygon(pub Coordinates); +pub struct Polygon(pub Coordinates); -impl Drawable for Polygon { - fn plot(&self) -> Coordinates { +impl Drawable for Polygon +where T: Add + Sub + Div + + Clone + Copy + From { + fn plot(&self) -> Coordinates { let Polygon(Coordinates(cs)) = self; match cs[..] { - [] => Coordinates(Vec::::new()), + [] => Coordinates(Vec::>::new()), [a] => Coordinates(vec!(a)), [a, b] => Coordinates(a.line(&b)), _ => { @@ -240,7 +258,7 @@ impl Drawable for Polygon { } } -impl Display for Polygon { +impl Display for Polygon where T: Copy { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Polygon(a) = self; write!(f, "Poly[{}]", a) diff --git a/fractional/src/geometry.rs b/fractional/src/geometry.rs index 3319ca5..51ce90d 100644 --- a/fractional/src/geometry.rs +++ b/fractional/src/geometry.rs @@ -150,7 +150,7 @@ where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From { fn project( &self , camera :&Camera , light :&DirectLight - , col :u32 ) -> Vec<(Polygon, u32)>; + , col :u32 ) -> Vec<(Polygon, u32)>; } pub struct Camera @@ -173,7 +173,7 @@ where T: Add + Sub + Neg // equal to the size of the physical screen… e.g. window/canvas thus some // effects can't be done. See book for examples with different viewport // and screen sizes. - pub fn new(c :&dyn Canvas, angle :i32) -> Self { + pub fn new(c :&dyn Canvas, angle :i32) -> Self { let width :T = (c.width() as i32).into(); let height :T = (c.height() as i32).into(); let d :T = 1.into(); @@ -194,9 +194,8 @@ where T: Add + Sub + Neg self.project } - pub fn project(&self, p :Point) -> Coordinate { - let Point(v, _) = p.transform(&self.project); - Coordinate(T::round(&v.x()), T::round(&v.y())) + pub fn project(&self, p :Point) -> Point { + p.transform(&self.project) } } @@ -318,6 +317,7 @@ impl Primitives for Polyeder where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From + PartialOrd { + // TODO Maybe this should also be an instance of Transformable… fn transform(&self, m :&TMatrix) -> Self { let Polyeder{ points: ps, faces: fs } = self; @@ -332,23 +332,24 @@ where T: Add + Sub + Neg p } - // TODO for now we assume already prejected vertices (points) - // in future we need to distinguish more clear between vertex and point - // and projected_point. fn project( &self , camera :&Camera , light :&DirectLight - , color :u32 ) -> Vec<(Polygon, u32)> { + , color :u32 ) -> Vec<(Polygon, u32)> { // Helper to create a Polygon from Coordinates… // TODO probably there needs to be a Polygon constructor for this. - fn polygon(c :I) -> Polygon - where I: Iterator { + fn polygon(c :I) -> Polygon + where I: Iterator> { Polygon(Coordinates(c.collect())) } // this one does the projection... as the projection was the last // matrix we do not need to do it here. - let to_coord = |p :&usize| camera.project(self.points[*p]); + let to_coord = |p :&usize| { + let Point(v, _) = camera.project(self.points[*p]); + 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| { let pg = polygon(f.corners.iter().map(to_coord)); let mut r :T = (((color >> 16) & 0xFF) as i32).into(); @@ -374,7 +375,8 @@ where T: Add + Sub + Neg None }}; - let mut ps :Vec<(Polygon, u32)> = self.faces.iter().filter_map(to_poly).collect(); + let mut ps :Vec<(Polygon, u32)> = self.faces.iter() + . filter_map(to_poly).collect(); ps.sort_by(|a, b| a.1.cmp(&b.1)); ps } diff --git a/fractional/src/main.rs b/fractional/src/main.rs index 6f09ef1..903f259 100644 --- a/fractional/src/main.rs +++ b/fractional/src/main.rs @@ -30,13 +30,13 @@ use std::time::{Duration, Instant}; use fractional::continuous::Continuous; use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline - , Polygon, Rectangle}; + , Polygon}; use fractional::fractional::{Fractional, from_vector}; use fractional::trigonometry::Trig; use fractional::vector::Vector; use fractional::transform::{TMatrix, Transformable}; -use fractional::xcb::XcbEasel; +use fractional::xcb::{XcbEasel, XcbCanvas}; use fractional::easel::Canvas; use fractional::geometry::{Camera,DirectLight,Polyeder,Primitives}; @@ -243,20 +243,16 @@ fn _transform(v :Vector, v1 :Vector, v2 :Vector, v3 :Vector) } fn _line() { - let a = (Coordinate(0, 1), Coordinate(6, 4)); - let b = (Coordinate(0, 4), Coordinate(6, 1)); - let c = (Coordinate(1, 0), Coordinate(6, 8)); - let d = (Coordinate(1, 8), Coordinate(6, 0)); + let a = (Coordinate(0, 1, 0.0), Coordinate(6, 4, 0.0)); + let b = (Coordinate(0, 4, 0.0), Coordinate(6, 1, 0.0)); + let c = (Coordinate(1, 0, 0.0), Coordinate(6, 8, 0.0)); + let d = (Coordinate(1, 8, 0.0), Coordinate(6, 0, 0.0)); for i in [a, b, c, d].iter() { println!("{:>14} : {}", Line(i.0, i.1), Line(i.0, i.1).plot()); println!("{:>14} : {}", Line(i.1, i.0), Line(i.1, i.0).plot()); } - println!(); - let r = Rectangle(Coordinate(1, 1), Coordinate(10, 5)); - println!("{:>14} : {}", r, r.plot()); - println!(); let pl = Polyline( Coordinates(vec!(a.0, a.1, b.0, b.1, c.0, c.1, d.0, d.1))); @@ -264,9 +260,9 @@ fn _line() { println!(); let pg = Polygon( - Coordinates(vec!( Coordinate( 0, -10) - , Coordinate( 10, 10) - , Coordinate(-10, 10) ))); + Coordinates(vec!( Coordinate( 0, -10, 0.0) + , Coordinate( 10, 10, 0.0) + , Coordinate(-10, 10, 0.0) ))); println!("{:>14} : {}", pg, pg.plot()); let i = Vector(Fractional( 0,1), Fractional(-30,1), Fractional(0,1)); @@ -285,9 +281,9 @@ fn _line() { println!(); let pg = Polygon( - Coordinates(vec!( Coordinate(to_i32(ix) + 100, to_i32(iy) + 100) - , Coordinate(to_i32(jx) + 100, to_i32(jy) + 100) - , Coordinate(to_i32(kx) + 100, to_i32(ky) + 100) ))); + Coordinates(vec!( Coordinate(to_i32(ix) + 100, to_i32(iy) + 100, 0.0) + , Coordinate(to_i32(jx) + 100, to_i32(jy) + 100, 0.0) + , Coordinate(to_i32(kx) + 100, to_i32(ky) + 100, 0.0) ))); println!("{:>14} : {}", pg, pg.plot()); let i = Vector( 0.0, -30.0, 0.0); @@ -305,9 +301,9 @@ fn _line() { println!(); let pg = Polygon( - Coordinates(vec!( Coordinate(to_i32_2(ix) + 100, to_i32_2(iy) + 100) - , Coordinate(to_i32_2(jx) + 100, to_i32_2(jy) + 100) - , Coordinate(to_i32_2(kx) + 100, to_i32_2(ky) + 100) ))); + Coordinates(vec!( Coordinate(to_i32_2(ix) + 100, to_i32_2(iy) + 100, 0.0) + , Coordinate(to_i32_2(jx) + 100, to_i32_2(jy) + 100, 0.0) + , Coordinate(to_i32_2(kx) + 100, to_i32_2(ky) + 100, 0.0) ))); println!("{:>14} : {}", pg, pg.plot()); } @@ -327,8 +323,8 @@ fn _democanvas( xcb :&XcbEasel // was 50. canvas.set_title(title); - canvas.init_events(); - canvas.start_events(tx.clone()); + >::init_events(&canvas); + >::start_events(&canvas, tx.clone()); thread::spawn(move || { let start = Instant::now(); @@ -351,11 +347,11 @@ fn _democanvas( xcb :&XcbEasel , ( cube.transform(&rot2), 0x0000FF) ); //let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) ); - canvas.clear(); + >::clear(&mut canvas); for (o, color) in objects { for (pg, c) in o.project(&camera, &light, color) { - canvas.draw(&pg, Coordinate(0,0), c); + canvas.draw(&pg, Coordinate(0, 0, 0.into()), c); } } @@ -367,10 +363,11 @@ fn _democanvas( xcb :&XcbEasel } last = last + step*(f + 1); - canvas.put_text( Coordinate(10, 15) - , &format!( "sleep: {:?}" - , last - Instant::now() )); - canvas.show(); + >::put_text( &canvas + , Coordinate(10, 15, 0.into()) + , &format!( "sleep: {:?}" + , last - Instant::now() )); + >::show(&canvas); thread::sleep(last - Instant::now()); } }); diff --git a/fractional/src/xcb.rs b/fractional/src/xcb.rs index 89210c9..6b33fac 100644 --- a/fractional/src/xcb.rs +++ b/fractional/src/xcb.rs @@ -129,7 +129,7 @@ fn getshm<'a>(size :usize) -> (i32, &'a mut [u32]) { impl Easel for XcbEasel {} -impl<'a> Canvas for XcbCanvas<'a> { +impl<'a,T> Canvas for XcbCanvas<'a> { fn init_events(&self) { let mask = [( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS @@ -223,18 +223,18 @@ impl<'a> Canvas for XcbCanvas<'a> { } } - fn draw(&mut self, d :&dyn Drawable, ofs :Coordinate, color: u32) { - let Coordinates(c) = d.plot(); - let Coordinate(xofs, yofs) = ofs; + fn draw(&mut self, d :&dyn Drawable, ofs :Coordinate, color: u32) { + let Coordinates(c) = d.plot(); + let Coordinate(xofs, yofs, _) = ofs; - for Coordinate(x, y) in c { + for Coordinate(x, y, _) in c { let idx :usize = ((y+yofs)*(self.width as i32)+x+xofs) as usize; self.shm[idx] = color; } } - fn put_text(&self, ofs :Coordinate, s :&str) { - let Coordinate(xofs, yofs) = ofs; + fn put_text(&self, ofs :Coordinate, s :&str) { + let Coordinate(xofs, yofs, _) = ofs; xcb::xproto::image_text_8( &self.conn, self.pixmap, self.gc , xofs as i16, yofs as i16, s ); self.conn.flush(); @@ -242,8 +242,8 @@ impl<'a> Canvas for XcbCanvas<'a> { fn show(&self) { xcb::copy_area( &self.conn, self.pixmap, self.window, self.gc - , 0, 0, 0, 0 - , self.width, self.height ); + , 0, 0, 0, 0 + , self.width, self.height ); self.conn.flush(); } }