From f38e1dd36679f3f93fb0b7ad485f903cf7270c52 Mon Sep 17 00:00:00 2001 From: Tanner Rogalsky Date: Tue, 17 Dec 2024 06:22:56 -0500 Subject: [PATCH] Remove vek dependency. --- Cargo.toml | 21 +-- src/lib.rs | 2 +- src/pipeline.rs | 3 +- src/rasterizer/lines.rs | 81 ++++----- src/rasterizer/triangles.rs | 323 +++++++++++++++++++++++------------- src/sampler/mod.rs | 3 + 6 files changed, 267 insertions(+), 166 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7761bb3..5bdf055 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,37 +2,32 @@ name = "euc" version = "0.6.0" description = "A software rendering crate that lets you write shaders with Rust" -authors = ["Joshua Barretto ", "Martin Sandfuchs "] +authors = [ + "Joshua Barretto ", + "Martin Sandfuchs ", +] license = "Apache-2.0 AND MIT" repository = "https://github.com/zesterer/euc" readme = "README.md" edition = "2021" keywords = ["renderer", "3D", "graphics", "rasterizer", "shader"] -exclude = [ - "/misc", - "/misc/*", -] +exclude = ["/misc", "/misc/*"] [dependencies] -vek = { version = "0.17", default-features = false, features = [] } image = { version = "0.25", optional = true } fxhash = { version = "0.2", optional = true } micromath = { version = "2", optional = true } clipline = "0.2" [features] -default = ["std", "image", "par"] -std = ["vek/std"] -libm = ["vek/libm"] -nightly = [] -simd = ["vek/repr_simd", "vek/platform_intrinsics"] +default = ["image", "par"] image = ["dep:image"] -par = ["std", "fxhash"] +par = ["fxhash"] micromath = ["dep:micromath"] [dev-dependencies] vek = { version = "0.17", default-features = false, features = ["rgba"] } -minifb = "0.20" +minifb = "0.27" wavefront = "0.2" criterion = "0.5" image = "0.25" diff --git a/src/lib.rs b/src/lib.rs index be3b0a3..16950b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ extern crate alloc; -#[cfg(feature = "std")] +#[cfg(any(feature = "par", not(feature = "micromath")))] extern crate std; /// N-dimensional buffers that may be used as textures and render targets. diff --git a/src/pipeline.rs b/src/pipeline.rs index 8268d27..67e92e4 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -2,7 +2,7 @@ use crate::{ buffer::Buffer2d, math::WeightedSum, primitives::PrimitiveKind, rasterizer::Rasterizer, texture::Target, }; -use alloc::{collections::VecDeque, vec::Vec}; +use alloc::collections::VecDeque; use core::{borrow::Borrow, cmp::Ordering, ops::Range}; #[cfg(feature = "micromath")] @@ -314,6 +314,7 @@ fn render_par<'r, Pipe, S, P, D>( P: Target + Send + Sync, D: Target + Send + Sync, { + use alloc::vec::Vec; use core::sync::atomic::{AtomicUsize, Ordering}; use std::thread; diff --git a/src/rasterizer/lines.rs b/src/rasterizer/lines.rs index 8e36bed..d7056c6 100644 --- a/src/rasterizer/lines.rs +++ b/src/rasterizer/lines.rs @@ -1,9 +1,5 @@ use super::*; use crate::{CoordinateMode, YAxisDirection}; -use vek::*; - -#[cfg(feature = "micromath")] -use micromath::F32Ext; /// A rasterizer that produces filled triangles. #[derive(Copy, Clone, Debug, Default)] @@ -30,54 +26,59 @@ impl Rasterizer for Lines { let tgt_max = blitter.target_max(); let flip = match coords.y_axis_direction { - YAxisDirection::Down => Vec2::new(1.0, 1.0), - YAxisDirection::Up => Vec2::new(1.0, -1.0), + YAxisDirection::Down => [1.0f32, 1.0], + YAxisDirection::Up => [1.0f32, -1.0], }; - let size = Vec2::::from(tgt_size).map(|e| e as f32); + let size = tgt_size.map(|e| e as f32); - let verts_hom_out = - core::iter::from_fn(move || Some(Vec2::new(vertices.next()?, vertices.next()?))); + let verts_hom_out = core::iter::from_fn(move || Some([vertices.next()?, vertices.next()?])); - verts_hom_out.for_each(|verts_hom_out: Vec2<([f32; 4], V)>| { + verts_hom_out.for_each(|verts_hom_out: [([f32; 4], V); 2]| { blitter.begin_primitive(); // Calculate vertex shader outputs and vertex homogeneous coordinates - let verts_hom = Vec2::new(verts_hom_out.x.0, verts_hom_out.y.0).map(Vec4::::from); - let verts_out = verts_hom_out.map(|e| e.1); + let verts_hom = [verts_hom_out[0].0, verts_hom_out[1].0]; + let verts_out = verts_hom_out.map(|(_, v)| v); - let verts_hom = verts_hom.map(|v| v * Vec4::new(flip.x, flip.y, 1.0, 1.0)); + let verts_hom = verts_hom.map(|[a0, a1, a2, a3]| [a0 * flip[0], a1 * flip[1], a2, a3]); // Convert homogenous to euclidean coordinates - let verts_euc = verts_hom.map(|v_hom| v_hom.xyz() / v_hom.w.max(0.0001)); + let verts_euc = verts_hom.map(|[a0, a1, a2, a3]| { + let w = a3.max(0.0001); + [a0 / w, a1 / w, a2 / w] + }); // Convert vertex coordinates to screen space - let verts_screen = verts_euc.map(|euc| size * (euc.xy() * Vec2::new(0.5, -0.5) + 0.5)); + let verts_screen = verts_euc + .map(|[a0, a1, _a2]| [size[0] * (a0 * 0.5 + 0.5), size[1] * (a1 * -0.5 + 0.5)]); // Calculate the triangle bounds as a bounding box - let screen_min = Vec2::::from(tgt_min).map(|e| e as f32); - let screen_max = Vec2::::from(tgt_max).map(|e| e as f32); - let bounds_clamped = Aabr:: { - min: (verts_screen.reduce(Vec2::partial_min) + 0.0) - .clamped(screen_min, screen_max) - .as_(), - max: (verts_screen.reduce(Vec2::partial_max) + 1.0) - .clamped(screen_min, screen_max) - .as_(), - }; - - let (x1, y1) = verts_screen.x.as_::().into_tuple(); - let (x2, y2) = verts_screen.y.as_::().into_tuple(); - - let (wx1, wy1) = bounds_clamped.min.as_::().into_tuple(); - let (wx2, wy2) = bounds_clamped.max.as_::().into_tuple(); + let screen_min = tgt_min.map(|e| e as f32); + let screen_max = tgt_max.map(|e| e as f32); + + let [x1, y1] = [verts_screen[0][0] as isize, verts_screen[0][1] as isize]; + let [x2, y2] = [verts_screen[1][0] as isize, verts_screen[1][1] as isize]; + + let [wx1, wy1] = [ + (verts_screen[0][0].min(verts_screen[1][0]) + 0.) + .clamp(screen_min[0], screen_max[0]) as isize, + (verts_screen[0][1].min(verts_screen[1][1]) + 0.) + .clamp(screen_min[1], screen_max[1]) as isize, + ]; + let [wx2, wy2] = [ + (verts_screen[0][0].max(verts_screen[1][0]) + 1.) + .clamp(screen_min[0], screen_max[0]) as isize, + (verts_screen[0][1].max(verts_screen[1][1]) + 1.) + .clamp(screen_min[1], screen_max[1]) as isize, + ]; let use_x = (x1 - x2).abs() > (y1 - y2).abs(); let norm = 1.0 / if use_x { - verts_screen.y.x - verts_screen.x.x + verts_screen[1][0] - verts_screen[0][0] } else { - verts_screen.y.y - verts_screen.x.y + verts_screen[1][1] - verts_screen[0][1] }; clipline::clipline( @@ -87,25 +88,25 @@ impl Rasterizer for Lines { let (x, y) = (x as usize, y as usize); let frac = if use_x { - x as f32 - verts_screen.x.x + x as f32 - verts_screen[0][0] } else { - y as f32 - verts_screen.x.y + y as f32 - verts_screen[0][1] } * norm; // Calculate the interpolated z coordinate for the depth target - let z = Lerp::lerp(verts_euc.x.z, verts_euc.y.z, frac); + let z = verts_euc[0][2] + frac * (verts_euc[1][2] - verts_euc[0][2]); if coords.passes_z_clip(z) && blitter.test_fragment(x, y, z) { let get_v_data = |x: f32, y: f32| { let frac = if use_x { - x - verts_screen.x.x + x - verts_screen[0][0] } else { - y - verts_screen.x.y + y - verts_screen[0][1] } * norm; V::weighted_sum2( - verts_out.x.clone(), - verts_out.y.clone(), + verts_out[0].clone(), + verts_out[1].clone(), 1.0 - frac, frac, ) diff --git a/src/rasterizer/triangles.rs b/src/rasterizer/triangles.rs index 0dfa912..465f30f 100644 --- a/src/rasterizer/triangles.rs +++ b/src/rasterizer/triangles.rs @@ -1,6 +1,5 @@ use super::*; use crate::{CoordinateMode, YAxisDirection}; -use vek::*; #[cfg(feature = "micromath")] use micromath::F32Ext; @@ -36,43 +35,39 @@ impl Rasterizer for Triangles { }; let flip = match coords.y_axis_direction { - YAxisDirection::Down => Vec2::new(1.0, 1.0), - YAxisDirection::Up => Vec2::new(1.0, -1.0), + YAxisDirection::Down => [1.0f32, 1.0], + YAxisDirection::Up => [1.0f32, -1.0], }; - let size = Vec2::::from(tgt_size).map(|e| e as f32); + let [size_x, size_y] = tgt_size.map(|e| e as f32); - let to_ndc = Mat3::from_row_arrays([ - [2.0 / size.x, 0.0, -1.0], - [0.0, -2.0 / size.y, 1.0], + let to_ndc = [ + [2.0 / size_x, 0.0, -1.0], + [0.0, -2.0 / size_y, 1.0], [0.0, 0.0, 1.0], - ]); + ]; let verts_hom_out = core::iter::from_fn(move || { - Some(Vec3::new( - vertices.next()?, - vertices.next()?, - vertices.next()?, - )) + Some([vertices.next()?, vertices.next()?, vertices.next()?]) }); - verts_hom_out.for_each(|verts_hom_out: Vec3<([f32; 4], V)>| { + verts_hom_out.for_each(|verts_hom_out: [([f32; 4], V); 3]| { blitter.begin_primitive(); // Calculate vertex shader outputs and vertex homogeneous coordinates - let verts_hom = Vec3::new(verts_hom_out.x.0, verts_hom_out.y.0, verts_hom_out.z.0) - .map(Vec4::::from); - let verts_out = Vec3::new(verts_hom_out.x.1, verts_hom_out.y.1, verts_hom_out.z.1); + let verts_hom = [verts_hom_out[0].0, verts_hom_out[1].0, verts_hom_out[2].0]; + let verts_out = verts_hom_out.map(|(_, v)| v); - let verts_hom = verts_hom.map(|v| v * Vec4::new(flip.x, flip.y, 1.0, 1.0)); + let verts_hom = verts_hom.map(|[a0, a1, a2, a3]| [a0 * flip[0], a1 * flip[1], a2, a3]); // Convert homogenous to euclidean coordinates - let verts_euc = verts_hom.map(|v_hom| v_hom.xyz() / v_hom.w); + let verts_euc = verts_hom.map(|[a0, a1, a2, a3]| [a0 / a3, a1 / a3, a2 / a3]); // Calculate winding direction to determine culling behaviour - let winding = (verts_euc.y - verts_euc.x) - .cross(verts_euc.z - verts_euc.x) - .z; + let winding = cross( + sub(verts_euc[1], verts_euc[0]), + sub(verts_euc[2], verts_euc[0]), + )[2]; // Culling and correcting for winding let (verts_hom, verts_euc, verts_out) = if cull_dir @@ -82,83 +77,112 @@ impl Rasterizer for Triangles { return; // Cull the triangle } else if winding >= 0.0 { // Reverse vertex order - (verts_hom.zyx(), verts_euc.zyx(), verts_out.zyx()) + (rev(verts_hom), rev(verts_euc), rev(verts_out)) } else { (verts_hom, verts_euc, verts_out) }; // Create a matrix that allows conversion between screen coordinates and interpolation weights let coords_to_weights = { - let (a, b, c) = verts_hom.into_tuple(); - let c = Vec3::new(c.x, c.y, c.w); - let ca = Vec3::new(a.x, a.y, a.w) - c; - let cb = Vec3::new(b.x, b.y, b.w) - c; - let n = ca.cross(cb); - let rec_det = if n.magnitude_squared() > 0.0 { - 1.0 / n.dot(c).min(-core::f32::EPSILON) + let [a, b, c] = [verts_hom[0], verts_hom[1], verts_hom[2]]; + let c = [c[0], c[1], c[3]]; + let ca = sub([a[0], a[1], a[3]], c); + let cb = sub([b[0], b[1], b[3]], c); + let n = cross(ca, cb); + let rec_det = if magnitude_squared(n) > 0.0 { + 1.0 / dot(n, c).min(-core::f32::EPSILON) } else { 1.0 }; - Mat3::from_row_arrays([cb.cross(c), c.cross(ca), n].map(|v| v.into_array())) - * rec_det - * to_ndc + matmul( + [cross(cb, c), cross(c, ca), n].map(|v| v.map(|e| e * rec_det)), + to_ndc, + ) }; // Ensure we didn't accidentally end up with infinities or NaNs debug_assert!(coords_to_weights - .into_row_array() .iter() - .all(|e| e.is_finite())); + .all(|v| v.iter().all(|e| e.is_finite()))); // Convert vertex coordinates to screen space - let verts_screen = verts_euc.map(|euc| size * (euc.xy() * Vec2::new(0.5, -0.5) + 0.5)); + let verts_screen = verts_euc + .map(|[a0, a1, _a2]| [size_x * (a0 * 0.5 + 0.5), size_y * (a1 * -0.5 + 0.5)]); // Calculate the triangle bounds as a bounding box - let screen_min = Vec2::::from(tgt_min).map(|e| e as f32); - let screen_max = Vec2::::from(tgt_max).map(|e| e as f32); - let bounds_clamped = Aabr:: { - min: (verts_screen.reduce(Vec2::partial_min) + 0.0) - .map3(screen_min, screen_max, |e, min, max| e.max(min).min(max)) - .as_(), - max: (verts_screen.reduce(Vec2::partial_max) + 1.0) - .map3(screen_min, screen_max, |e, min, max| e.max(min).min(max)) - .as_(), - }; + let screen_min = tgt_min.map(|e| e as usize); + let screen_max = tgt_max.map(|e| e as usize); + let bounds_clamped_min = [ + ((verts_screen[0][0] + .min(verts_screen[1][0]) + .min(verts_screen[2][0]) + + 0.) as usize) + .clamp(screen_min[0], screen_max[0]), + ((verts_screen[0][1] + .min(verts_screen[1][1]) + .min(verts_screen[2][1]) + + 0.) as usize) + .clamp(screen_min[1], screen_max[1]), + ]; + let bounds_clamped_max = [ + ((verts_screen[0][0] + .max(verts_screen[1][0]) + .max(verts_screen[2][0]) + + 1.) as usize) + .clamp(screen_min[0], screen_max[0]), + ((verts_screen[0][1] + .max(verts_screen[1][1]) + .max(verts_screen[2][1]) + + 1.) as usize) + .clamp(screen_min[1], screen_max[1]), + ]; + // let bounds_clamped = Aabr:: { + // min: (verts_screen.reduce(Vec2::partial_min) + 0.0) + // .map3(screen_min, screen_max, |e, min, max| e.max(min).min(max)) + // .as_(), + // max: (verts_screen.reduce(Vec2::partial_max) + 1.0) + // .map3(screen_min, screen_max, |e, min, max| e.max(min).min(max)) + // .as_(), + // }; // Calculate change in vertex weights for each pixel - let weights_at = |p: Vec2| coords_to_weights * Vec3::new(p.x, p.y, 1.0); - let w_hom_origin = weights_at(Vec2::zero()); - let w_hom_dx = (weights_at(Vec2::unit_x() * 1000.0) - w_hom_origin) * (1.0 / 1000.0); - let w_hom_dy = (weights_at(Vec2::unit_y() * 1000.0) - w_hom_origin) * (1.0 / 1000.0); + let weights_at = |[p0, p1]: [f32; 2]| mat3_mul_vec3(coords_to_weights, [p0, p1, 1.0]); + let w_hom_origin = weights_at([0., 0.]); + let w_hom_dx = sub(weights_at([1000.0, 0.]), w_hom_origin).map(|e| e * (1.0 / 1000.0)); + let w_hom_dy = sub(weights_at([0., 1000.0]), w_hom_origin).map(|e| e * (1.0 / 1000.0)); // First, order vertices by height - let min_y = verts_screen.map(|v| v.y).reduce_partial_min(); - let verts_by_y = if verts_screen.x.y == min_y { - if verts_screen.y.y < verts_screen.z.y { - Vec3::new(verts_screen.x, verts_screen.y, verts_screen.z) + let min_y = { + let y = verts_screen.map(|v| v[1]); + y[0].min(y[1]).min(y[2]) + }; + let verts_by_y = if verts_screen[0][1] == min_y { + if verts_screen[1][1] < verts_screen[2][1] { + [verts_screen[0], verts_screen[1], verts_screen[2]] } else { - Vec3::new(verts_screen.x, verts_screen.z, verts_screen.y) + [verts_screen[0], verts_screen[2], verts_screen[1]] } - } else if verts_screen.y.y == min_y { - if verts_screen.x.y < verts_screen.z.y { - Vec3::new(verts_screen.y, verts_screen.x, verts_screen.z) + } else if verts_screen[1][1] == min_y { + if verts_screen[0][1] < verts_screen[2][1] { + [verts_screen[1], verts_screen[0], verts_screen[2]] } else { - Vec3::new(verts_screen.y, verts_screen.z, verts_screen.x) + [verts_screen[1], verts_screen[2], verts_screen[0]] } } else { #[allow(clippy::collapsible_else_if)] - if verts_screen.x.y < verts_screen.y.y { - Vec3::new(verts_screen.z, verts_screen.x, verts_screen.y) + if verts_screen[0][1] < verts_screen[1][1] { + [verts_screen[2], verts_screen[0], verts_screen[1]] } else { - Vec3::new(verts_screen.z, verts_screen.y, verts_screen.x) + [verts_screen[2], verts_screen[1], verts_screen[0]] } }; - if verts_euc.map(|v| coords.passes_z_clip(v.z)).reduce_and() { + if let [true, true, true] = verts_euc.map(|v| coords.passes_z_clip(v[2])) { rasterize::<_, _, true>( coords.clone(), - bounds_clamped, + bounds_clamped_min, + bounds_clamped_max, verts_by_y, verts_hom, w_hom_origin, @@ -170,7 +194,8 @@ impl Rasterizer for Triangles { } else { rasterize::<_, _, false>( coords.clone(), - bounds_clamped, + bounds_clamped_min, + bounds_clamped_max, verts_by_y, verts_hom, w_hom_origin, @@ -189,78 +214,90 @@ impl Rasterizer for Triangles { const NO_VERTS_CLIPPED: bool, >( coords: CoordinateMode, - bounds_clamped: Aabr, - verts_by_y: Vec3>, - verts_hom: Vec3>, - w_hom_origin: Vec3, - w_hom_dx: Vec3, - w_hom_dy: Vec3, - verts_out: Vec3, + bounds_clamped_min: [usize; 2], + bounds_clamped_max: [usize; 2], + verts_by_y: [[f32; 2]; 3], + verts_hom: [[f32; 4]; 3], + w_hom_origin: [f32; 3], + w_hom_dx: [f32; 3], + w_hom_dy: [f32; 3], + verts_out: [V; 3], blitter: &mut B, ) { - (bounds_clamped.min.y..bounds_clamped.max.y).for_each(|y| { - let row_range = if bounds_clamped.size().product() < 128 { + (bounds_clamped_min[1]..bounds_clamped_max[1]).for_each(|y| { + let extent = [ + bounds_clamped_max[0] - bounds_clamped_min[0], + bounds_clamped_max[1] - bounds_clamped_min[1], + ]; + let row_range = if extent.iter().product::() < 128 { // Stupid version - Vec2::new(bounds_clamped.min.x, bounds_clamped.max.x) + [bounds_clamped_min[0], bounds_clamped_max[0]] } else { - let Vec3 { x: a, y: b, z: c } = verts_by_y; + let [a, b, c] = verts_by_y; + // For each of the lines, calculate the point at which our row intersects it - let ac = Lerp::lerp(a.x, c.x, (y as f32 - a.y) / (c.y - a.y)); // Longest side - // Then, depending on the half of the triangle we're in, we need to check different lines - let row_bounds = if (y as f32) < b.y { - let ab = Lerp::lerp(a.x, b.x, (y as f32 - a.y) / (b.y - a.y)); - Vec2::new(ab.min(ac), ab.max(ac)) + let ac = lerp(a[0], c[0], (y as f32 - a[1]) / (c[1] - a[1])); // Longest side + // Then, depending on the half of the triangle we're in, we need to check different lines + let row_bounds = if (y as f32) < b[1] { + let ab = lerp(a[0], b[0], (y as f32 - a[1]) / (b[1] - a[1])); + [ab.min(ac), ab.max(ac)] } else { - let bc = Lerp::lerp(b.x, c.x, (y as f32 - b.y) / (c.y - b.y)); - Vec2::new(bc.min(ac), bc.max(ac)) + let bc = lerp(b[0], c[0], (y as f32 - b[1]) / (c[1] - b[1])); + [bc.min(ac), bc.max(ac)] }; // Now we have screen-space bounds for the row. Clean it up and clamp it to the screen bounds - Vec2::new(row_bounds.x.floor(), row_bounds.y.ceil()).map2( - Vec2::new(bounds_clamped.min.x, bounds_clamped.max.x), - |e, b| { - if e >= bounds_clamped.min.x as f32 - && e < bounds_clamped.max.x as f32 - { - e as usize - } else { - b - } - }, - ) + let screen_clamp = |e, b| { + if e >= bounds_clamped_min[0] as f32 && e < bounds_clamped_max[0] as f32 + { + e as usize + } else { + b + } + }; + [ + screen_clamp(row_bounds[0].floor(), bounds_clamped_min[0]), + screen_clamp(row_bounds[1].ceil(), bounds_clamped_max[0]), + ] }; // Find the barycentric weights for the start of this row - let mut w_hom = - w_hom_origin + w_hom_dy * y as f32 + w_hom_dx * row_range.x as f32; + let mut w_hom = add( + add(w_hom_origin, w_hom_dy.map(|e| e * y as f32)), + w_hom_dx.map(|e| e * row_range[0] as f32), + ); - (row_range.x..row_range.y).for_each(|x| { + (row_range[0]..row_range[1]).for_each(|x| { // Calculate vertex weights to determine vs_out lerping and intersection - let w_unbalanced = Vec3::new(w_hom.x, w_hom.y, w_hom.z - w_hom.x - w_hom.y); + let w_unbalanced = [w_hom[0], w_hom[1], w_hom[2] - w_hom[0] - w_hom[1]]; // Test the weights to determine whether the fragment is inside the triangle - if w_unbalanced.map(|e| e >= 0.0).reduce_and() { + if let [true, true, true] = w_unbalanced.map(|e| e >= 0.0) { // Calculate the interpolated z coordinate for the depth target - let z = verts_hom.map(|v| v.z).dot(w_unbalanced); + let z = dot(verts_hom.map(|v| v[2]), w_unbalanced); if (NO_VERTS_CLIPPED || coords.passes_z_clip(z)) && blitter.test_fragment(x, y, z) { let get_v_data = |x: f32, y: f32| { - let w_hom = w_hom_origin + w_hom_dy * y + w_hom_dx * x; + let w_hom = add( + add(w_hom_origin, w_hom_dy.map(|e| e * y)), + w_hom_dx.map(|e| e * x), + ); // Calculate vertex weights to determine vs_out lerping and intersection let w_unbalanced = - Vec3::new(w_hom.x, w_hom.y, w_hom.z - w_hom.x - w_hom.y); - let w = w_unbalanced * w_hom.z.recip(); + [w_hom[0], w_hom[1], w_hom[2] - w_hom[0] - w_hom[1]]; + let r = w_hom[2].recip(); + let w = w_unbalanced.map(|e| e * r); V::weighted_sum3( - verts_out.x.clone(), - verts_out.y.clone(), - verts_out.z.clone(), - w.x, - w.y, - w.z, + verts_out[0].clone(), + verts_out[1].clone(), + verts_out[2].clone(), + w[0], + w[1], + w[2], ) }; @@ -269,10 +306,74 @@ impl Rasterizer for Triangles { } // Update barycentric weight ready for the next fragment - w_hom += w_hom_dx; + w_hom = add(w_hom, w_hom_dx); }); }); } }); } } + +// fn mul([a0, a1, a2]: [f32; 3], [b0, b1, b2]: [f32; 3]) -> [f32; 3] { +// [a0 * b0, a1 * b1, a2 * b2] +// } + +fn cross([a0, a1, a2]: [f32; 3], [b0, b1, b2]: [f32; 3]) -> [f32; 3] { + [ + a1 * b2 - a2 * b1, // x-component + a2 * b0 - a0 * b2, // y-component + a0 * b1 - a1 * b0, // z-component + ] +} + +fn sub([a0, a1, a2]: [f32; 3], [b0, b1, b2]: [f32; 3]) -> [f32; 3] { + [ + a0 - b0, // x-component + a1 - b1, // y-component + a2 - b2, // z-component + ] +} + +fn add([a0, a1, a2]: [f32; 3], [b0, b1, b2]: [f32; 3]) -> [f32; 3] { + [ + a0 + b0, // x-component + a1 + b1, // y-component + a2 + b2, // z-component + ] +} + +fn dot([a0, a1, a2]: [f32; 3], [b0, b1, b2]: [f32; 3]) -> f32 { + a0 * b0 + a1 * b1 + a2 * b2 +} + +fn rev([a0, a1, a2]: [T; 3]) -> [T; 3] { + [a2, a1, a0] +} + +fn magnitude_squared([v0, v1, v2]: [f32; 3]) -> f32 { + v0 * v0 + v1 * v1 + v2 * v2 +} + +fn matmul(a: [[f32; 3]; 3], b: [[f32; 3]; 3]) -> [[f32; 3]; 3] { + let mut result = [[0.0; 3]; 3]; // Initialize a 3x3 matrix to store the result + + for i in 0..3 { + for j in 0..3 { + result[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j]; + } + } + + result +} + +fn mat3_mul_vec3(m: [[f32; 3]; 3], v: [f32; 3]) -> [f32; 3] { + [ + m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2], // x-component + m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2], // y-component + m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2], // z-component + ] +} + +fn lerp(a: f32, b: f32, t: f32) -> f32 { + a + t * (b - a) +} diff --git a/src/sampler/mod.rs b/src/sampler/mod.rs index f6f4648..8dc916e 100644 --- a/src/sampler/mod.rs +++ b/src/sampler/mod.rs @@ -5,6 +5,9 @@ pub use self::{linear::Linear, nearest::Nearest}; use crate::{math::*, texture::Texture}; +#[cfg(feature = "micromath")] +use micromath::F32Ext; + /// A trait that describes a sampler of a texture. /// /// Samplers use normalised coordinates (between 0 and 1) to sample textures. Often, samplers will combine this with