use anyhow::Result; use rtchallenge::{ canvas::Canvas, float::consts::PI, matrices::Matrix4x4, tuples::{Color, Tuple}, Float, }; fn draw_dot(c: &mut Canvas, x: usize, y: usize) { let red = Color::new(1., 0., 0.); c.set(x.saturating_sub(1), y.saturating_sub(1), red); c.set(x, y.saturating_sub(1), red); c.set(x + 1, y.saturating_sub(1), red); c.set(x.saturating_sub(1), y, red); c.set(x, y, red); c.set(x + 1, y, red); c.set(x.saturating_sub(1), y + 1, red); c.set(x, y + 1, red); c.set(x + 1, y + 1, red); } fn main() -> Result<()> { let w = 200; let h = w; let bg = Color::new(0.2, 0.2, 0.2); let mut c = Canvas::new(w, h, bg); let t = Matrix4x4::translation(0., 0.4, 0.); let p = Tuple::point(0., 0., 0.); let rot_hour = Matrix4x4::rotation_z(-PI / 6.); let mut p = t * p; let w = w as Float; let h = h as Float; // The 'world' exists between -0.5 - 0.5 in X-Y plane. // To convert to screen space, we translate by 0.5, scale to canvas size, // and invert the Y-axis. let world_to_screen = Matrix4x4::scaling(w as Float, -h as Float, 1.0) * Matrix4x4::translation(0.5, -0.5, 0.); for _ in 0..12 { let canvas_pixel = world_to_screen * p; draw_dot(&mut c, canvas_pixel.x as usize, canvas_pixel.y as usize); p = rot_hour * p; } let path = "/tmp/eoc4.png"; println!("saving output to {}", path); c.write_to_file(path)?; Ok(()) }