diff --git a/fractional/src/easel.rs b/fractional/src/easel.rs index d203f65..3437f06 100644 --- a/fractional/src/easel.rs +++ b/fractional/src/easel.rs @@ -30,8 +30,11 @@ 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); + fn draw(&mut self, c :&dyn Drawable, ofs :Coordinate, color :u32); fn show(&self); } @@ -225,7 +228,9 @@ impl Drawable for Polygon { } let mut j = a.line(&i); let l = j.len(); - r.append(&mut j[1..l-1].to_vec()); + if l > 1 { + r.append(&mut j[1..l-1].to_vec()); + } Coordinates(r) }, } diff --git a/fractional/src/main.rs b/fractional/src/main.rs index 0c6a7bc..bef0c3b 100644 --- a/fractional/src/main.rs +++ b/fractional/src/main.rs @@ -24,8 +24,8 @@ use std::fmt::Display; use std::num::TryFromIntError; use std::ops::{Add,Sub,Neg,Mul,Div}; use std::sync::mpsc; -use std::time; use std::thread; +use std::time::{Duration, Instant}; use fractional::continuous::Continuous; use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline @@ -340,37 +340,149 @@ fn main() { let (tx, rx) = mpsc::channel(); - let i = Vector(Fractional( 0,1), Fractional(-35,1), Fractional(0,1)); - let j = Vector(Fractional( 30,1), Fractional( 17,1), Fractional(0,1)); - let k = Vector(Fractional(-30,1), Fractional( 17,1), Fractional(0,1)); - - fn to_i32(x :Fractional) -> i32 { - let Fractional(n, d) = x; - (n / d + if (n % d).abs() < (n / 2).abs() { 0 } else { 1 }) as i32 + // TODO I ran into overflow issues using fractionals so for now + // use floating point values. + // https://rechneronline.de/pi/tetrahedron.php + // yi = a / 12 * √6 + // yc = a / 4 * √6 + // zi = √3 / 6 * a + // zc = √3 / 3 * a + let yi = 60.0 / 12.0 * 6.0.sqrt().unwrap(); + let yc = 60.0 / 4.0 * 6.0.sqrt().unwrap(); + let zi = 3.0.sqrt().unwrap() / 6.0 * 60.0; + let zc = 3.0.sqrt().unwrap() / 3.0 * 60.0; + + let i = Vector( 0.0, yc, 0.0); + let j = Vector(-30.0, -yi, -zi); + let k = Vector( 30.0, -yi, -zi); + let l = Vector( 0.0, -yi, zc); + + let cf1 = Vector(-30.0, 30.0, -30.0); + let cf2 = Vector(-30.0, -30.0, -30.0); + let cf3 = Vector( 30.0, -30.0, -30.0); + let cf4 = Vector( 30.0, 30.0, -30.0); + + let cb1 = Vector(-30.0, 30.0, 30.0); + let cb2 = Vector(-30.0, -30.0, 30.0); + let cb3 = Vector( 30.0, -30.0, 30.0); + let cb4 = Vector( 30.0, 30.0, 30.0); + + fn to_screen(c: &dyn Canvas, v :Vector) -> Coordinate { + // TODO .. these are in fact constants that should be stored once + // somewhere… Rust doesn't let me make this static here. + // In a way they are part of the canvas and they should change as the + // canvas is changing… + let fovx :f64 = 1.0 / ::tan(50); + let fovy :f64 = c.width() as f64 / c.height() as f64 * fovx; + + let xs = ( v.x() / v.z() * fovx * c.width() as f64 ).round() as i32 + + c.width() as i32 / 2; + let ys = ( -v.y() / v.z() * fovy * c.height() as f64 ).round() as i32 + + c.height() as i32 / 2; + + Coordinate(xs, ys) } canvas.start_events(tx); + let start = Instant::now(); + let step = Duration::from_millis(25); + let mut last = Instant::now(); thread::spawn(move || { - let mut deg :i32 = 0; - loop { - let rot :TMatrix = rotate_z(deg) * rotate_x(-deg); + //const DWC :f64 = 10.0; - let Vector(ix, iy, _) = rot.apply(&i); - let Vector(jx, jy, _) = rot.apply(&j); - let Vector(kx, ky, _) = rot.apply(&k); + loop { + let deg = ((start.elapsed() / 20).as_millis() % 360) as i32; + let rot1 :TMatrix = rotate_z(deg) + * rotate_x(-deg*2) + * translate(Vector(0.0, 0.0, 150.0)); + + let rot2 :TMatrix = rotate_z(deg) + * rotate_y(-deg*2) + * translate(Vector(0.0, 0.0, 150.0)); + + let ia = rot1.apply(&i); + let ja = rot1.apply(&j); + let ka = rot1.apply(&k); + let la = rot1.apply(&l); + + let cf1a = rot2.apply(&cf1); + let cf2a = rot2.apply(&cf2); + let cf3a = rot2.apply(&cf3); + let cf4a = rot2.apply(&cf4); + + let cb1a = rot2.apply(&cb1); + let cb2a = rot2.apply(&cb2); + let cb3a = rot2.apply(&cb3); + let cb4a = rot2.apply(&cb4); + + let pg1 = Polygon(Coordinates(vec!( to_screen(&canvas, ja) + , to_screen(&canvas, ka) + , to_screen(&canvas, la) ))); + let pg2 = Polygon(Coordinates(vec!( to_screen(&canvas, ja) + , to_screen(&canvas, ia) + , to_screen(&canvas, ka) ))); + let pg3 = Polygon(Coordinates(vec!( to_screen(&canvas, la) + , to_screen(&canvas, ia) + , to_screen(&canvas, ja) ))); + let pg4 = Polygon(Coordinates(vec!( to_screen(&canvas, ka) + , to_screen(&canvas, ia) + , to_screen(&canvas, la) ))); + + // front: cf1 cf2 cf3 cf4 + let cf = Polygon(Coordinates(vec!( to_screen(&canvas, cf1a) + , to_screen(&canvas, cf2a) + , to_screen(&canvas, cf3a) + , to_screen(&canvas, cf4a) ))); + // back: cb4 cb3 cb2 cb1 + let cb = Polygon(Coordinates(vec!( to_screen(&canvas, cb4a) + , to_screen(&canvas, cb3a) + , to_screen(&canvas, cb2a) + , to_screen(&canvas, cb1a) ))); + // top: cf2 cb2 cb3 cf3 + let ct = Polygon(Coordinates(vec!( to_screen(&canvas, cf2a) + , to_screen(&canvas, cb2a) + , to_screen(&canvas, cb3a) + , to_screen(&canvas, cf3a) ))); + // bottom: cf1 cf4 cb4 cb1 + let co = Polygon(Coordinates(vec!( to_screen(&canvas, cf1a) + , to_screen(&canvas, cf4a) + , to_screen(&canvas, cb4a) + , to_screen(&canvas, cb1a) ))); + // left: cf1 cb1 cb2 cf2 + let cl = Polygon(Coordinates(vec!( to_screen(&canvas, cf1a) + , to_screen(&canvas, cb1a) + , to_screen(&canvas, cb2a) + , to_screen(&canvas, cf2a) ))); + // right: cf3 cb3 cb4 cf4 + let cr = Polygon(Coordinates(vec!( to_screen(&canvas, cf3a) + , to_screen(&canvas, cb3a) + , to_screen(&canvas, cb4a) + , to_screen(&canvas, cf4a) ))); - let pg = Polygon( - Coordinates(vec!( Coordinate(to_i32(ix), to_i32(iy)) - , Coordinate(to_i32(jx), to_i32(jy)) - , Coordinate(to_i32(kx), to_i32(ky)) ))); canvas.clear(); - canvas.draw(&pg, Coordinate(75,75)); + canvas.draw(&pg1, Coordinate(0,0), 0xFFFF00); + canvas.draw(&pg2, Coordinate(0,0), 0xFFFF00); + canvas.draw(&pg3, Coordinate(0,0), 0xFFFF00); + canvas.draw(&pg4, Coordinate(0,0), 0xFFFF00); + canvas.draw( &cf, Coordinate(0,0), 0x0000FF); + canvas.draw( &cb, Coordinate(0,0), 0x0000FF); + canvas.draw( &ct, Coordinate(0,0), 0x0000FF); + canvas.draw( &co, Coordinate(0,0), 0x0000FF); + canvas.draw( &cl, Coordinate(0,0), 0x0000FF); + canvas.draw( &cr, Coordinate(0,0), 0x0000FF); canvas.show(); - deg = (deg + 1) % 360; + let passed = Instant::now() - last; + let f = (passed.as_nanos() / step.as_nanos()) as u32; + + if f > 1 { + println!("!!! Detected frame drop"); + } - thread::sleep(time::Duration::from_millis(5)); + last = last + step*(f + 1); + println!("Sleep for: {:?}", last - Instant::now()); + thread::sleep(last - Instant::now()); } }); diff --git a/fractional/src/xcb.rs b/fractional/src/xcb.rs index 6c6f63f..0cb29ee 100644 --- a/fractional/src/xcb.rs +++ b/fractional/src/xcb.rs @@ -207,6 +207,14 @@ impl<'a> Canvas for XcbCanvas<'a> { }); } + fn width(&self) -> u16 { + self.width + } + + fn height(&self) -> u16 { + self.height + } + fn clear(&mut self) { unsafe { let ptr = self.shm.as_mut_ptr(); @@ -215,13 +223,13 @@ impl<'a> Canvas for XcbCanvas<'a> { } } - fn draw(&mut self, d :&dyn Drawable, ofs :Coordinate) { + 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 { let idx :usize = ((y+yofs)*(self.width as i32)+x+xofs) as usize; - self.shm[idx] = 0xFFFFFF; + self.shm[idx] = color; } }