Draw lines

Additionally convert Point2D to use f64
This commit is contained in:
2026-01-09 14:32:22 +11:00
parent 0850bc1032
commit 2f5865555b
4 changed files with 73 additions and 33 deletions
+12 -7
View File
@@ -18,7 +18,7 @@ use consts::*;
use core::f64; use std::{num::NonZeroU32, u32}; 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}; use winit::{self, event_loop::EventLoop, window::Window};
fn main() { fn main() {
@@ -45,20 +45,25 @@ fn main() {
) )
.expect("Couldn't resize surface"); .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![ vertices: vec![
Point3D(0.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, 0.0), // Point3D(f64::MAX / 2.0, -f64::MAX / 2.0, 1.0),
Point3D(-f64::MAX / 2.0, -f64::MAX / 2.0, 0.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, 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 { loop {
let mut sbuffer = surface.buffer_mut().expect("Couldn't create buffer"); let mut sbuffer = surface.buffer_mut().expect("Couldn't create buffer");
// set_scene(t, &mut scene);
render(t, &scene, &mut *sbuffer); render(t, &scene, &mut *sbuffer);
t += 1; t += 1;
+17 -9
View File
@@ -1,7 +1,7 @@
use crate::consts::*; use crate::consts::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Point2D(pub u32, pub u32); pub struct Point2D(pub f64, pub f64);
impl Point2D { impl Point2D {
pub fn to_canvas_coordinates(&self) -> Point3D { pub fn to_canvas_coordinates(&self) -> Point3D {
todo!(); todo!();
@@ -10,9 +10,10 @@ impl Point2D {
pub fn distance(self, p2: &Point2D) -> f64 { pub fn distance(self, p2: &Point2D) -> f64 {
let p1 = self; let p1 = self;
// Pythagorean formula // Pythagorean formula
// TODO: use hypot function
f64::sqrt( f64::sqrt(
(u32::pow(p2.0.max(p1.0) - p1.0.min(p2.0), 2) (f64::powf(p2.0.max(p1.0) - p1.0.min(p2.0), 2.0)
+ u32::pow(p2.1.max(p1.1) - p1.1.min(p2.1), 2)) as f64, + f64::powf(p2.1.max(p1.1) - p1.1.min(p2.1), 2.0)) as f64,
) )
} }
} }
@@ -23,6 +24,7 @@ impl Point3D {
pub fn to_screen_coordinates(&self) -> Point2D { pub fn to_screen_coordinates(&self) -> Point2D {
let Point3D(x, y, z) = *self; let Point3D(x, y, z) = *self;
if self.2 == 0.0 {
// Normalize to the interval [0, 1] // Normalize to the interval [0, 1]
let x = (x / f64::MAX + 1.0) / 2.0; let x = (x / f64::MAX + 1.0) / 2.0;
let y = (-y / f64::MAX + 1.0) / 2.0; let y = (-y / f64::MAX + 1.0) / 2.0;
@@ -30,18 +32,24 @@ impl Point3D {
assert!(x <= 1.0 && y <= 1.0 && z <= 1.0); assert!(x <= 1.0 && y <= 1.0 && z <= 1.0);
if self.2 == 0.0 {
Point2D( Point2D(
(x * (SCREEN_WIDTH - 1) as f64) as u32, // Scale to the interval [0, SCREEN_WIDTH) x * (SCREEN_WIDTH - 1) as f64, // Scale to the interval [0, SCREEN_WIDTH)
(y * (SCREEN_HEIGHT - 1) as f64) as u32, // Scale to the interval [0, SCREEN_HEIGHT) y * (SCREEN_HEIGHT - 1) as f64, // Scale to the interval [0, SCREEN_HEIGHT)
) )
} else { } else {
let x = x / z; let x = x / z;
let y = y / 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( Point2D(
(x * (SCREEN_WIDTH - 1) as f64) as u32, x * (SCREEN_WIDTH - 1) as f64,
(y * (SCREEN_HEIGHT - 1) as f64) as u32, y * (SCREEN_HEIGHT - 1) as f64,
) )
} }
} }
@@ -50,7 +58,7 @@ impl Point3D {
let p1 = self; let p1 = self;
// Pythagorean formula // Pythagorean formula
f64::sqrt( 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
) )
} }
} }
+36 -10
View File
@@ -1,7 +1,6 @@
use crate::consts::*; use crate::consts::*;
use crate::scene::Scene; use crate::scene::Scene;
type Pixel = u32; type Pixel = u32;
type Subpixels = (u8, u8, u8); type Subpixels = (u8, u8, u8);
@@ -14,27 +13,54 @@ fn to_rgb((red, green, blue): Subpixels) -> Pixel {
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]) { pub fn render(t: u128, scene: &Scene, buf: &mut [u32]) {
for pix in buf.iter_mut() { for pix in buf.iter_mut() {
*pix = to_rgb((0, 0, 0)); *pix = to_rgb((0, 0, 0));
} }
for obj in scene { for obj in scene {
for vertex in &obj.vertices { for vertex in &obj.vertices {
let vertex = vertex.to_screen_coordinates(); let vertex = vertex.to_screen_coordinates();
let x = vertex.0; let x = vertex.0;
let y = vertex.1; let y = vertex.1;
for i in [ for i in -10..10 {
-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..10 {
] { let x = x + i as f64;
for j in [ let y = y + j as f64;
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, *index_buffer(buf, x, y) = to_rgb((255, 255, 255));
] {
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 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));
}
}
} }
} }
+2 -1
View File
@@ -1,3 +1,4 @@
use core::f64;
use crate::points::Point3D; use crate::points::Point3D;
#[derive(Debug)] #[derive(Debug)]
@@ -12,6 +13,6 @@ pub type Scene = Vec<Object>;
pub fn set_scene(t: u128, scene: &mut Scene) { pub fn set_scene(t: u128, scene: &mut Scene) {
for obj in 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));
} }
} }