From 9f4a8f03dfedcefedee62381d2b6ddcf6a52f07e Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Mon, 8 Sep 2025 14:41:03 -0700 Subject: [PATCH] fix triangle interpolation --- src/main.rs | 16 ++++++++++------ src/point.rs | 45 +++++++++++++++++++++++++++++++++++++++++---- src/tga.rs | 17 ++++++++++++++++- 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index eb21adb..538867d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,6 +46,10 @@ fn main() { let b = Point2i::new(550, 390).with_color(GREEN); let c = Point2i::new(230, 590).with_color(RED); + a.render(20, &mut fb); + b.render(20, &mut fb); + c.render(20, &mut fb); + let t = Triangle2i::new(a, b, c); t.render_filled(BLACK, &mut fb); fb.write_file("triangle.tga", true, true).unwrap(); @@ -112,12 +116,12 @@ impl Triangle2i { return; } let it = 1.0 / total_area; - (bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| { - (bb.xmin()..bb.xmax()).into_par_iter().for_each(|x| { + (bb.xmin()..=bb.xmax()).into_par_iter().for_each(|x| { + (bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| { let p = Point2i::new(x, y); - let alpha = Triangle2i::new(p, self.a, self.b).signed_area() * it; - let beta = Triangle2i::new(p, self.b, self.c).signed_area() * it; - let gamma = Triangle2i::new(p, self.c, self.a).signed_area() * it; + let alpha = Triangle2i::new(p, self.b, self.c).signed_area() * it; + let beta = Triangle2i::new(p, self.c, self.a).signed_area() * it; + let gamma = Triangle2i::new(p, self.a, self.b).signed_area() * it; if alpha.is_sign_positive() && beta.is_sign_positive() @@ -128,7 +132,7 @@ impl Triangle2i { && let Some(cb) = self.b.color && let Some(cc) = self.c.color { - ca * alpha + cb * beta + cc * gamma + color + color + (ca * alpha) + (cb * beta) + (cc * gamma) } else { color }; diff --git a/src/point.rs b/src/point.rs index 122ae14..35c785e 100644 --- a/src/point.rs +++ b/src/point.rs @@ -1,6 +1,14 @@ -use std::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; +use std::{ + ops::{Add, Deref, DerefMut, Div, Mul, Sub}, + sync::{Arc, Mutex}, +}; -use crate::tga::TGAColor; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +use crate::{ + YELLOW, + tga::{TGAColor, TGAImage}, +}; #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Point2i { @@ -28,6 +36,25 @@ impl Point2i { ..self } } + + pub fn render(&self, radius: i32, fb: &mut TGAImage) { + let xmin = self.x - radius; + let xmax = self.x + radius; + let ymin = self.y - radius; + let ymax = self.y + radius; + let r2 = radius.pow(2); + let fb = Arc::new(Mutex::new(fb)); + (ymin..=ymax).into_par_iter().for_each(|y| { + (xmin..=xmax).into_par_iter().for_each(|x| { + let d2 = (x - self.x).pow(2) + (y - self.y).pow(2); + if d2 <= r2 + && let Ok(mut fb) = fb.lock() + { + fb.set(x as u32, y as u32, self.color.unwrap_or(YELLOW)); + } + }); + }); + } } impl Add for Point2i { @@ -37,7 +64,12 @@ impl Add for Point2i { Self { x: self.x + rhs.x, y: self.y + rhs.y, - color: None, + color: if self.color.is_none() { + rhs.color + } else { + self.color + .map(|c| if let Some(oc) = rhs.color { c + oc } else { c }) + }, } } } @@ -49,7 +81,12 @@ impl Sub for Point2i { Self { x: self.x - rhs.x, y: self.y - rhs.y, - color: None, + color: if self.color.is_none() { + rhs.color + } else { + self.color + .map(|c| if let Some(oc) = rhs.color { c - oc } else { c }) + }, } } } diff --git a/src/tga.rs b/src/tga.rs index f8e5409..2a28a7e 100644 --- a/src/tga.rs +++ b/src/tga.rs @@ -1,7 +1,7 @@ use std::{ fs::File, io::{Read, Write}, - ops::{Add, Deref, DerefMut, Mul}, + ops::{Add, Deref, DerefMut, Mul, Sub}, }; const HEADER_SIZE: usize = 18; @@ -88,6 +88,21 @@ impl Add for TGAColor { } } +impl Sub for TGAColor { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self { + bgra: [ + self[0].saturating_sub(rhs[0]), + self[1].saturating_sub(rhs[1]), + self[2].saturating_sub(rhs[2]), + self[3].saturating_sub(rhs[3]), + ], + } + } +} + impl Mul for TGAColor { type Output = Self;