diff --git a/src/main.rs b/src/main.rs index ed9f383..4ea0d3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ use consts::*; use core::f64; use std::{num::NonZeroU32, u32}; -use softbuffer::{Context, Rect, Surface}; +use softbuffer::{Buffer, Context, Rect, Surface}; use winit::{self, event_loop::EventLoop, window::Window}; fn main() { @@ -45,20 +45,25 @@ fn main() { ) .expect("Couldn't resize surface"); - let mut t: u128 = 0; + let mut t: u128 = 1; - let scene = vec![Object { + let mut scene = vec![Object { vertices: vec![ - Point3D(0.0, f64::MAX / 2.0, 0.0), - Point3D(f64::MAX / 2.0, -f64::MAX / 2.0, 0.0), - Point3D(-f64::MAX / 2.0, -f64::MAX / 2.0, 0.0), + // Point3D(0.0, f64::MAX / 2.0, 1.0), + // Point3D(f64::MAX / 2.0, -f64::MAX / 2.0, 1.0), + // Point3D(-f64::MAX / 2.0, -f64::MAX / 2.0, 1.0), // Point3D(0.0, 0.0, f64::MAX / 2.0), + // Point3D(0.0, 0.0, 0.0), + Point3D(f64::MAX / 2.0, f64::MAX / 2.0, 0.0) + ], + edges: vec![ + (Point3D(0.0, 0.0, 0.0), Point3D(f64::MAX / 2.0, f64::MAX / 2.0, 0.0)) ], - edges: vec![], }]; loop { let mut sbuffer = surface.buffer_mut().expect("Couldn't create buffer"); + // set_scene(t, &mut scene); render(t, &scene, &mut *sbuffer); t += 1; diff --git a/src/points.rs b/src/points.rs index c80ccee..295d1ad 100644 --- a/src/points.rs +++ b/src/points.rs @@ -1,7 +1,7 @@ use crate::consts::*; #[derive(Debug)] -pub struct Point2D(pub u32, pub u32); +pub struct Point2D(pub f64, pub f64); impl Point2D { pub fn to_canvas_coordinates(&self) -> Point3D { todo!(); @@ -10,9 +10,10 @@ impl Point2D { pub fn distance(self, p2: &Point2D) -> f64 { let p1 = self; // Pythagorean formula + // TODO: use hypot function f64::sqrt( - (u32::pow(p2.0.max(p1.0) - p1.0.min(p2.0), 2) - + u32::pow(p2.1.max(p1.1) - p1.1.min(p2.1), 2)) as f64, + (f64::powf(p2.0.max(p1.0) - p1.0.min(p2.0), 2.0) + + f64::powf(p2.1.max(p1.1) - p1.1.min(p2.1), 2.0)) as f64, ) } } @@ -23,25 +24,32 @@ impl Point3D { pub fn to_screen_coordinates(&self) -> Point2D { let Point3D(x, y, z) = *self; - // Normalize to the interval [0, 1] - let x = (x / f64::MAX + 1.0) / 2.0; - let y = (-y / f64::MAX + 1.0) / 2.0; - let z = (z / f64::MAX + 1.0) / 2.0; - - assert!(x <= 1.0 && y <= 1.0 && z <= 1.0); - if self.2 == 0.0 { + // Normalize to the interval [0, 1] + let x = (x / f64::MAX + 1.0) / 2.0; + let y = (-y / f64::MAX + 1.0) / 2.0; + let z = (z / f64::MAX + 1.0) / 2.0; + + assert!(x <= 1.0 && y <= 1.0 && z <= 1.0); + Point2D( - (x * (SCREEN_WIDTH - 1) as f64) as u32, // Scale to the interval [0, SCREEN_WIDTH) - (y * (SCREEN_HEIGHT - 1) as f64) as u32, // Scale to the interval [0, SCREEN_HEIGHT) + x * (SCREEN_WIDTH - 1) as f64, // Scale to the interval [0, SCREEN_WIDTH) + y * (SCREEN_HEIGHT - 1) as f64, // Scale to the interval [0, SCREEN_HEIGHT) ) } else { let x = x / z; let y = y / z; + // Normalize to the interval [0, 1] + let x = (x / f64::MAX + 1.0) / 2.0; + let y = (-y / f64::MAX + 1.0) / 2.0; + let z = (z / f64::MAX + 1.0) / 2.0; + + assert!(x <= 1.0 && y <= 1.0 && z <= 1.0); + Point2D( - (x * (SCREEN_WIDTH - 1) as f64) as u32, - (y * (SCREEN_HEIGHT - 1) as f64) as u32, + x * (SCREEN_WIDTH - 1) as f64, + y * (SCREEN_HEIGHT - 1) as f64, ) } } @@ -50,7 +58,7 @@ impl Point3D { let p1 = self; // Pythagorean formula f64::sqrt( - f64::powf(p2.0 - p1.0, 2.0) + f64::powf(p2.1 - p1.1, 2.0) + f64::powf(p2.2 - p1.2, 2.0), + f64::powf(p2.0 - p1.0, 2.0) + f64::powf(p2.1 - p1.1, 2.0) + f64::powf(p2.2 - p1.2, 2.0) // Fix to use max and min ) } } diff --git a/src/render.rs b/src/render.rs index f37dd72..f9edb5e 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,7 +1,6 @@ use crate::consts::*; use crate::scene::Scene; - type Pixel = u32; type Subpixels = (u8, u8, u8); @@ -14,27 +13,54 @@ fn to_rgb((red, green, blue): Subpixels) -> Pixel { pixel } +const fn index_buffer(buf: &mut [u32], x: f64, y: f64) -> &mut u32 { + let x = x.round_ties_even(); // Banker's round + let y = y.round_ties_even(); + + &mut buf[(x as usize) + (y as usize) * STRIDE as usize] +} + pub fn render(t: u128, scene: &Scene, buf: &mut [u32]) { for pix in buf.iter_mut() { *pix = to_rgb((0, 0, 0)); } + for obj in scene { for vertex in &obj.vertices { let vertex = vertex.to_screen_coordinates(); let x = vertex.0; let y = vertex.1; - for i in [ - -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - ] { - for j in [ - -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - ] { - let x = x as i32 + i; - let y = y as i32 + j; - buf[(x + y * STRIDE as i32) as usize] = to_rgb(((t % 256).try_into().unwrap(), 0, 0)); + for i in -10..10 { + for j in -10..10 { + let x = x + i as f64; + let y = y + j as f64; + *index_buffer(buf, x, y) = to_rgb((255, 255, 255)); } } } + + for edge in &obj.edges { // Draw lines + dbg!(&edge.0, &edge.1); + let start = edge.0.to_screen_coordinates(); + let end = edge.1.to_screen_coordinates(); + + dbg!(&start, &end); + if (end.0 - start.0).abs() == 0.0 { // Vertical line case - m is undefined + for y in (start.0.min(end.0) as u32)..(end.0.max(start.0) + 1.0) as u32 { + *index_buffer(buf, end.0, y as f64) = to_rgb((255, 255, 255)); + } + continue + } + + let m = (end.1 - start.1) / (end.0 - start.0); // m = rise/run + let c = start.1 as f64 - m * start.0 as f64; // c = y - mx + + for x in 0..SCREEN_WIDTH { + let x = x as f64; + let y = m * x + c; // y = mx + c + *index_buffer(buf, x, y) = to_rgb((255, 255, 255)); + } + } } } diff --git a/src/scene.rs b/src/scene.rs index 6fb8842..2c61468 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -1,3 +1,4 @@ +use core::f64; use crate::points::Point3D; #[derive(Debug)] @@ -12,6 +13,6 @@ pub type Scene = Vec; pub fn set_scene(t: u128, scene: &mut Scene) { for obj in scene { - obj.vertices.push(Point3D(t as f64, t as f64, t as f64)); + obj.vertices[0] = Point3D(f64::MAX / 2.0, f64::MAX / 2.0, 1.0_f64.max(t as f64 / 100.0)); } }