stocking

git clone https://git.bradleygannon.com/stocking.git
Log | Files | Refs

commit 8f21b8640274351d594fd25ca9d1e47b295fa116
parent 3a2c64c30f0b2fc03b986a67a36d689ac3feb4d4
Author: Bradley Gannon <bradley@bradleygannon.com>
Date:   Fri, 12 Dec 2025 23:04:48 -0500

Add vec3

Complete Chapter 3

Diffstat:
Msrc/main.rs | 36++++++++++++++++++++----------------
Asrc/vec3.rs | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 201 insertions(+), 16 deletions(-)

diff --git a/src/main.rs b/src/main.rs @@ -1,22 +1,26 @@ -#[derive(Clone, Copy, Default)] -struct Pixel { - red: f32, - green: f32, - blue: f32, -} +use crate::vec3::Vec3; +use std::{ + fmt::{Debug, Display}, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub}, +}; + +mod vec3; + +vec3!(Color, f64, red, green, blue); +vec3!(Point3, f64, x, y, z); struct Image { - data: Vec<Vec<Pixel>>, + data: Vec<Vec<Color>>, } -fn scale_f32_to_u8(value: f32) -> u8 { +fn scale_f64_to_u8(value: f64) -> u8 { (value * 255.) as u8 } impl Image { fn new(width: usize, height: usize) -> Self { Image { - data: vec![vec![Pixel::default(); width]; height], + data: vec![vec![Color::default(); width]; height], } } fn to_ppm_string(&self) -> String { @@ -27,12 +31,12 @@ impl Image { output += "255\n"; for (row_idx, row_data) in self.data.iter().enumerate() { eprintln!("Scanlines remaining: {}", height - row_idx); - for Pixel { red, green, blue } in row_data.iter() { + for Color { red, green, blue } in row_data.iter() { output += &format!( "{} {} {}\n", - scale_f32_to_u8(*red), - scale_f32_to_u8(*green), - scale_f32_to_u8(*blue) + scale_f64_to_u8(*red), + scale_f64_to_u8(*green), + scale_f64_to_u8(*blue) ); } } @@ -46,10 +50,10 @@ fn main() { let mut image = Image::new(width, height); for i in 0..width { for j in 0..height { - let red = i as f32 / (width - 1) as f32; - let green = j as f32 / (height - 1) as f32; + let red = i as f64 / (width - 1) as f64; + let green = j as f64 / (height - 1) as f64; let blue = 0.; - image.data[j][i] = Pixel { red, green, blue }; + image.data[j][i] = Color { red, green, blue }; } } println!("{}", image.to_ppm_string()); diff --git a/src/vec3.rs b/src/vec3.rs @@ -0,0 +1,181 @@ +use std::{ + fmt::{Debug, Display}, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub}, +}; + +#[allow(dead_code)] +pub trait Vec3: + Add + + AddAssign + + Clone + + Copy + + Debug + + Default + + Display + + DivAssign<f64> + + Div<f64> + + MulAssign<f64> + + Mul<f64> + + Neg + + Sub +{ +} + +#[macro_export] +macro_rules! vec3 { + ( $name:ident, $type:ty, $dim0:ident, $dim1:ident, $dim2:ident ) => { + #[derive(Copy, Clone, Debug, Default)] + struct $name { + $dim0: $type, + $dim1: $type, + $dim2: $type, + } + + #[allow(dead_code)] + impl $name { + pub fn new($dim0: $type, $dim1: $type, $dim2: $type) -> Self { + $name { + $dim0, + $dim1, + $dim2, + } + } + + pub fn $dim0(&self) -> $type { + self.$dim0 + } + + pub fn $dim1(&self) -> $type { + self.$dim1 + } + + pub fn $dim2(&self) -> $type { + self.$dim2 + } + + pub fn cross(&self, other: &$name) -> $name { + $name { + $dim0: self.$dim1 * other.$dim2 - self.$dim2 * other.$dim1, + $dim1: self.$dim2 * other.$dim0 - self.$dim0 * other.$dim2, + $dim2: self.$dim0 * other.$dim1 - self.$dim1 * other.$dim0, + } + } + + pub fn dot(&self, other: &$name) -> $type { + self.$dim0 * other.$dim0 + self.$dim1 * other.$dim1 + self.$dim2 * other.$dim2 + } + + pub fn length(&self) -> $type { + self.length_squared().sqrt() + } + + pub fn length_squared(&self) -> $type { + self.$dim0.powi(2) + self.$dim1.powi(2) + self.$dim2.powi(2) + } + + pub fn unit(&self) -> $name { + *self / self.length() + } + } + + impl Vec3 for $name {} + + impl Add for $name { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + $name { + $dim0: self.$dim0 + rhs.$dim0, + $dim1: self.$dim1 + rhs.$dim1, + $dim2: self.$dim2 + rhs.$dim2, + } + } + } + + impl AddAssign for $name { + fn add_assign(&mut self, rhs: Self) { + self.$dim0 += rhs.$dim0; + self.$dim1 += rhs.$dim1; + self.$dim2 += rhs.$dim2; + } + } + + impl Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {} {}", self.$dim0, self.$dim1, self.$dim2) + } + } + + impl DivAssign<$type> for $name { + fn div_assign(&mut self, rhs: $type) { + self.$dim0 /= rhs; + self.$dim1 /= rhs; + self.$dim2 /= rhs; + } + } + + impl Div<$type> for $name { + type Output = $name; + + fn div(self, rhs: $type) -> Self::Output { + $name { + $dim0: self.$dim0 / rhs, + $dim1: self.$dim1 / rhs, + $dim2: self.$dim2 / rhs, + } + } + } + + impl MulAssign<$type> for $name { + fn mul_assign(&mut self, rhs: $type) { + self.$dim0 *= rhs; + self.$dim1 *= rhs; + self.$dim2 *= rhs; + } + } + + impl Mul<$type> for $name { + type Output = $name; + + fn mul(self, rhs: $type) -> Self::Output { + $name { + $dim0: self.$dim0 * rhs, + $dim1: self.$dim1 * rhs, + $dim2: self.$dim2 * rhs, + } + } + } + + impl Mul<$name> for $type { + type Output = $name; + + fn mul(self, rhs: $name) -> Self::Output { + rhs * self + } + } + + impl Neg for $name { + type Output = Self; + + fn neg(self) -> Self::Output { + $name { + $dim0: -self.$dim0, + $dim1: -self.$dim1, + $dim2: -self.$dim2, + } + } + } + + impl Sub for $name { + type Output = $name; + + fn sub(self, rhs: Self) -> Self::Output { + $name { + $dim0: self.$dim0 - rhs.$dim0, + $dim1: self.$dim1 - rhs.$dim1, + $dim2: self.$dim2 - rhs.$dim2, + } + } + } + }; +}