From 6689f31146ea5de999fa604066396ddcdb62a3ab Mon Sep 17 00:00:00 2001 From: gered Date: Sat, 1 Apr 2023 14:24:29 -0400 Subject: [PATCH] implement triangle drawing "optimizations" these don't actually improve performance at all judging from the criterion benchmarks. lol. --- ggdt/src/graphics/bitmap/triangles.rs | 42 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/ggdt/src/graphics/bitmap/triangles.rs b/ggdt/src/graphics/bitmap/triangles.rs index 4fc8887..bba7609 100644 --- a/ggdt/src/graphics/bitmap/triangles.rs +++ b/ggdt/src/graphics/bitmap/triangles.rs @@ -4,7 +4,7 @@ use crate::math::vector2::Vector2; #[inline] fn cross(a: Vector2, b: Vector2, c: Vector2) -> f32 { - (c.x - a.x) * (b.y - a.y) - (c.y - a.y) * (b.x - a.x) + (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) } impl Bitmap { @@ -55,9 +55,6 @@ impl Bitmap { // https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/rasterization-stage.html // https://kitsunegames.com/post/development/2016/07/28/software-3d-rendering-in-javascript-pt2/ - // TODO: optimize further. have had some trouble with some explanations of the optmizations presented in the - // linked article and the math presented. in particular i would prefer to have counter-clockwise vertex - // ordering but the math presented seems to only work as-is with clockwise ordering ... *grumble* // TODO: implement fill rules, probably using top-left ordering as most 3d APIs do i guess let min_x = a.x.min(b.x).min(c.x).floor() as i32; @@ -70,24 +67,41 @@ impl Bitmap { let max_x = std::cmp::min(self.clip_region().right(), max_x); let max_y = std::cmp::min(self.clip_region().bottom(), max_y); + let a01 = a.y - b.y; + let b01 = b.x - a.x; + let a12 = b.y - c.y; + let b12 = c.x - b.x; + let a20 = c.y - a.y; + let b20 = a.x - c.x; + + let p = Vector2::new(min_x as f32, min_y as f32); + let mut w0_row = cross(b, c, p); + let mut w1_row = cross(c, a, p); + let mut w2_row = cross(a, b, p); + let draw_width = (max_x - min_x + 1) as usize; let next_row_inc = self.width() as usize; let mut pixels = unsafe { self.pixels_at_mut_ptr_unchecked(min_x, min_y) }; - for y in min_y..=max_y { + for _ in min_y..=max_y { + let mut w0 = w0_row; + let mut w1 = w1_row; + let mut w2 = w2_row; + let row_pixels = unsafe { std::slice::from_raw_parts_mut(pixels, draw_width) }; - for (idx, pixel) in row_pixels.iter_mut().enumerate() { - let x = min_x + idx as i32; - - let p = Vector2::new(x as f32, y as f32); - let w0 = cross(b, c, p); - let w1 = cross(c, a, p); - let w2 = cross(a, b, p); - - if w0 >= 0.0 && w1 >= 0.0 && w2 >= 0.0 { + for pixel in row_pixels.iter_mut() { + if w0 < 0.0 && w1 < 0.0 && w2 < 0.0 { pixel_fn(pixel, w0, w1, w2); } + + w0 += a12; + w1 += a20; + w2 += a01; } + + w0_row += b12; + w1_row += b20; + w2_row += b01; pixels = unsafe { pixels.add(next_row_inc) }; } }