From 44ed48d2eb82fc52679bec9f4fbeb17e22581b7d Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Thu, 1 Feb 2024 20:59:37 +0000 Subject: [PATCH 01/15] feat: API for IVec --- citro3d/src/math.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/citro3d/src/math.rs b/citro3d/src/math.rs index 949bb42..fcc04c3 100644 --- a/citro3d/src/math.rs +++ b/citro3d/src/math.rs @@ -16,9 +16,49 @@ pub use projection::{ }; /// A 4-vector of `u8`s. +/// +/// # Layout +/// Uses the PICA layout of WZYX #[doc(alias = "C3D_IVec")] +#[repr(transparent)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct IVec(citro3d_sys::C3D_IVec); +impl IVec { + pub fn new(x: u8, y: u8, z: u8, w: u8) -> Self { + Self(unsafe { citro3d_sys::IVec_Pack(x, y, z, w) }) + } + pub fn as_raw(&self) -> &citro3d_sys::C3D_IVec { + &self.0 + } + pub fn x(self) -> u8 { + self.0 as u8 + } + pub fn y(self) -> u8 { + (self.0 >> 8) as u8 + } + pub fn z(self) -> u8 { + (self.0 >> 16) as u8 + } + pub fn w(self) -> u8 { + (self.0 >> 24) as u8 + } +} + /// A quaternion, internally represented the same way as [`FVec`]. #[doc(alias = "C3D_FQuat")] pub struct FQuat(citro3d_sys::C3D_FQuat); + +#[cfg(test)] +mod tests { + use super::IVec; + + #[test] + fn ivec_getters_work() { + let iv = IVec::new(1, 2, 3, 4); + assert_eq!(iv.x(), 1); + assert_eq!(iv.y(), 2); + assert_eq!(iv.z(), 3); + assert_eq!(iv.w(), 4); + } +} From 97a1d12dda8cb9bc0fe0e517d773a77c1d59f5b6 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Thu, 1 Feb 2024 21:01:33 +0000 Subject: [PATCH 02/15] feat: improve uniform API and rewrite Matrix API --- citro3d/src/lib.rs | 8 +- citro3d/src/math.rs | 2 +- citro3d/src/math/fvec.rs | 7 ++ citro3d/src/math/matrix.rs | 169 +++++++++++++-------------------- citro3d/src/math/ops.rs | 75 +++++---------- citro3d/src/math/projection.rs | 4 +- citro3d/src/shader.rs | 3 +- citro3d/src/uniform.rs | 157 +++++++++++++++++++++++------- 8 files changed, 231 insertions(+), 194 deletions(-) diff --git a/citro3d/src/lib.rs b/citro3d/src/lib.rs index 544ed89..34d3160 100644 --- a/citro3d/src/lib.rs +++ b/citro3d/src/lib.rs @@ -192,8 +192,8 @@ impl Instance { /// let mtx = Matrix::identity(); /// instance.bind_vertex_uniform(idx, &mtx); /// ``` - pub fn bind_vertex_uniform(&mut self, index: uniform::Index, uniform: impl Uniform) { - uniform.bind(self, shader::Type::Vertex, index); + pub fn bind_vertex_uniform(&mut self, index: uniform::Index, uniform: impl Into) { + uniform.into().bind(self, shader::Type::Vertex, index); } /// Bind a uniform to the given `index` in the geometry shader for the next draw call. @@ -210,8 +210,8 @@ impl Instance { /// let mtx = Matrix::identity(); /// instance.bind_geometry_uniform(idx, &mtx); /// ``` - pub fn bind_geometry_uniform(&mut self, index: uniform::Index, uniform: impl Uniform) { - uniform.bind(self, shader::Type::Geometry, index); + pub fn bind_geometry_uniform(&mut self, index: uniform::Index, uniform: impl Into) { + uniform.into().bind(self, shader::Type::Geometry, index); } /// Retrieve the [`TexEnv`] for the given stage, initializing it first if necessary. diff --git a/citro3d/src/math.rs b/citro3d/src/math.rs index fcc04c3..35a188e 100644 --- a/citro3d/src/math.rs +++ b/citro3d/src/math.rs @@ -9,7 +9,7 @@ mod ops; mod projection; pub use fvec::{FVec, FVec3, FVec4}; -pub use matrix::{Matrix, Matrix3, Matrix4}; +pub use matrix::Matrix4; pub use projection::{ AspectRatio, ClipPlanes, CoordinateOrientation, Orthographic, Perspective, Projection, ScreenOrientation, StereoDisplacement, diff --git a/citro3d/src/math/fvec.rs b/citro3d/src/math/fvec.rs index 37e66c7..3fa888e 100644 --- a/citro3d/src/math/fvec.rs +++ b/citro3d/src/math/fvec.rs @@ -3,8 +3,15 @@ use std::fmt; /// A vector of `f32`s. +/// +/// # Layout +/// Note that this matches the PICA layout so is actually WZYX, this means using it +/// in vertex data as an attribute it will be reversed +/// +/// It is guaranteed to have the same layout as [`citro3d_sys::C3D_FVec`] in memory #[derive(Clone, Copy)] #[doc(alias = "C3D_FVec")] +#[repr(transparent)] pub struct FVec(pub(crate) citro3d_sys::C3D_FVec); /// A 3-vector of `f32`s. diff --git a/citro3d/src/math/matrix.rs b/citro3d/src/math/matrix.rs index e07f777..e3f958e 100644 --- a/citro3d/src/math/matrix.rs +++ b/citro3d/src/math/matrix.rs @@ -1,84 +1,55 @@ use std::mem::MaybeUninit; -pub use private::Matrix; - -use super::{CoordinateOrientation, FVec3}; - -mod private { - use std::fmt; - - /// An `M`x`N` row-major matrix of `f32`s. - #[doc(alias = "C3D_Mtx")] - #[derive(Clone)] - pub struct Matrix(citro3d_sys::C3D_Mtx); - - impl Matrix { - const ROW_SIZE: () = assert!(M == 3 || M == 4); - const COLUMN_SIZE: () = assert!(N > 0 && N <= 4); - - // This constructor validates, at compile time, that the - // constructed matrix is 3xN or 4xN matrix, where 0 < N ≤ 4. - // We put this struct in a submodule to enforce that nothing creates - // a Matrix without calling this constructor. - #[allow(clippy::let_unit_value)] - pub(crate) fn new(value: citro3d_sys::C3D_Mtx) -> Self { - let () = Self::ROW_SIZE; - let () = Self::COLUMN_SIZE; - Self(value) - } - - pub(crate) fn as_raw(&self) -> *const citro3d_sys::C3D_Mtx { - &self.0 - } +use super::{CoordinateOrientation, FVec3, FVec4}; - pub(crate) fn into_raw(self) -> citro3d_sys::C3D_Mtx { - self.0 - } +/// A 4x4 row-major matrix of `f32`s. +/// +/// # Layout details +/// Rows are actually stored as WZYX in memory. There are helper functions +/// for accessing the rows in XYZW form. The `Debug` implementation prints +/// the shows in WZYX form +/// +/// It is also guaranteed to have the same layout as [`citro3d_sys::C3D_Mtx`] +#[doc(alias = "C3D_Mtx")] +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Matrix4(citro3d_sys::C3D_Mtx); - pub(crate) fn as_mut(&mut self) -> *mut citro3d_sys::C3D_Mtx { - &mut self.0 - } +impl Matrix4 { + /// Create a new matrix from a raw citro3d_sys one + pub fn from_raw(value: citro3d_sys::C3D_Mtx) -> Self { + Self(value) + } - /// Trim the matrix down to only the rows and columns we care about, - /// since the inner representation is always 4x4. - /// - /// NOTE: this probably shouldn't be used in hot paths since it copies - /// the underlying storage. For some use cases slicing might be better, - /// although the underlying slice would always contain extra values for - /// matrices smaller than 4x4. - pub(crate) fn as_rows(&self) -> [[f32; N]; M] { - let rows = unsafe { self.0.r }.map(|row| -> [f32; N] { - // Rows are stored in WZYX order, so we slice from back to front. - // UNWRAP: N ≤ 4, so slicing to a smaller array should always work - unsafe { row.c[(4 - N)..].try_into() }.unwrap() - }); - - // UNWRAP: M ≤ 4, so slicing to a smaller array should always work - rows[..M].try_into().unwrap() - } + pub fn as_raw(&self) -> &citro3d_sys::C3D_Mtx { + &self.0 } - impl fmt::Debug for Matrix { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let inner = self.as_rows().map(|mut row| { - // Rows are stored in WZYX order which is opposite of how most people - // probably expect, so reverse each row in-place for debug printing - row.reverse(); - row - }); + pub fn as_raw_mut(&mut self) -> &mut citro3d_sys::C3D_Mtx { + &mut self.0 + } - let type_name = std::any::type_name::().split("::").last().unwrap(); - f.debug_tuple(type_name).field(&inner).finish() - } + pub fn into_raw(self) -> citro3d_sys::C3D_Mtx { + self.0 } -} -/// A 3x3 row-major matrix of `f32`s. -pub type Matrix3 = Matrix<3, 3>; -/// A 4x4 row-major matrix of `f32`s. -pub type Matrix4 = Matrix<4, 4>; + /// Get the rows in raw (WZYX) form + pub fn rows_wzyx(self) -> [FVec4; 4] { + // Safety: FVec4 is repr(C) to allow transmute from C3D_Vec + unsafe { core::mem::transmute::<[citro3d_sys::C3D_FVec; 4], [FVec4; 4]>(self.0.r) } + } -impl Matrix { + /// Get the rows in normal XYZW form + pub fn rows_xyzw(self) -> [[f32; 4]; 4] { + let mut rows = self.rows_wzyx(); + for r in &mut rows { + unsafe { + r.0.c.reverse(); + } + } + // Safety: FVec has same layout as citro3d_sys version which is a union with [f32; 4] as one variant + unsafe { std::mem::transmute::<_, [[f32; 4]; 4]>(rows) } + } /// Construct the zero matrix. #[doc(alias = "Mtx_Zeros")] pub fn zero() -> Self { @@ -86,17 +57,17 @@ impl Matrix { let mut out = MaybeUninit::uninit(); unsafe { citro3d_sys::Mtx_Zeros(out.as_mut_ptr()); - Self::new(out.assume_init()) + Self::from_raw(out.assume_init()) } } /// Transpose the matrix, swapping rows and columns. #[doc(alias = "Mtx_Transpose")] - pub fn transpose(mut self) -> Matrix { + pub fn transpose(mut self) -> Matrix4 { unsafe { - citro3d_sys::Mtx_Transpose(self.as_mut()); + citro3d_sys::Mtx_Transpose(self.as_raw_mut()); } - Matrix::new(self.into_raw()) + Matrix4::from_raw(self.into_raw()) } // region: Matrix transformations @@ -111,43 +82,39 @@ impl Matrix { /// directions. #[doc(alias = "Mtx_Translate")] pub fn translate(&mut self, x: f32, y: f32, z: f32) { - unsafe { citro3d_sys::Mtx_Translate(self.as_mut(), x, y, z, false) } + unsafe { citro3d_sys::Mtx_Translate(self.as_raw_mut(), x, y, z, false) } } /// Scale a transformation matrix by the given amounts in the X, Y, and Z directions. #[doc(alias = "Mtx_Scale")] pub fn scale(&mut self, x: f32, y: f32, z: f32) { - unsafe { citro3d_sys::Mtx_Scale(self.as_mut(), x, y, z) } + unsafe { citro3d_sys::Mtx_Scale(self.as_raw_mut(), x, y, z) } } /// Rotate a transformation matrix by the given angle around the given axis. #[doc(alias = "Mtx_Rotate")] pub fn rotate(&mut self, axis: FVec3, angle: f32) { - unsafe { citro3d_sys::Mtx_Rotate(self.as_mut(), axis.0, angle, false) } + unsafe { citro3d_sys::Mtx_Rotate(self.as_raw_mut(), axis.0, angle, false) } } /// Rotate a transformation matrix by the given angle around the X axis. #[doc(alias = "Mtx_RotateX")] pub fn rotate_x(&mut self, angle: f32) { - unsafe { citro3d_sys::Mtx_RotateX(self.as_mut(), angle, false) } + unsafe { citro3d_sys::Mtx_RotateX(self.as_raw_mut(), angle, false) } } /// Rotate a transformation matrix by the given angle around the Y axis. #[doc(alias = "Mtx_RotateY")] pub fn rotate_y(&mut self, angle: f32) { - unsafe { citro3d_sys::Mtx_RotateY(self.as_mut(), angle, false) } + unsafe { citro3d_sys::Mtx_RotateY(self.as_raw_mut(), angle, false) } } /// Rotate a transformation matrix by the given angle around the Z axis. #[doc(alias = "Mtx_RotateZ")] pub fn rotate_z(&mut self, angle: f32) { - unsafe { citro3d_sys::Mtx_RotateZ(self.as_mut(), angle, false) } + unsafe { citro3d_sys::Mtx_RotateZ(self.as_raw_mut(), angle, false) } } - // endregion -} - -impl Matrix { /// Find the inverse of the matrix. /// /// # Errors @@ -155,7 +122,7 @@ impl Matrix { /// If the matrix has no inverse, it will be returned unchanged as an [`Err`]. #[doc(alias = "Mtx_Inverse")] pub fn inverse(mut self) -> Result { - let determinant = unsafe { citro3d_sys::Mtx_Inverse(self.as_mut()) }; + let determinant = unsafe { citro3d_sys::Mtx_Inverse(self.as_raw_mut()) }; if determinant == 0.0 { Err(self) } else { @@ -169,31 +136,17 @@ impl Matrix { let mut out = MaybeUninit::uninit(); unsafe { citro3d_sys::Mtx_Identity(out.as_mut_ptr()); - Self::new(out.assume_init()) - } - } -} - -impl Matrix3 { - /// Construct a 3x3 matrix with the given values on the diagonal. - #[doc(alias = "Mtx_Diagonal")] - pub fn diagonal(x: f32, y: f32, z: f32) -> Self { - let mut out = MaybeUninit::uninit(); - unsafe { - citro3d_sys::Mtx_Diagonal(out.as_mut_ptr(), x, y, z, 0.0); - Self::new(out.assume_init()) + Self::from_raw(out.assume_init()) } } -} -impl Matrix4 { /// Construct a 4x4 matrix with the given values on the diagonal. #[doc(alias = "Mtx_Diagonal")] pub fn diagonal(x: f32, y: f32, z: f32, w: f32) -> Self { let mut out = MaybeUninit::uninit(); unsafe { citro3d_sys::Mtx_Diagonal(out.as_mut_ptr(), x, y, z, w); - Self::new(out.assume_init()) + Self::from_raw(out.assume_init()) } } @@ -215,7 +168,19 @@ impl Matrix4 { camera_up.0, coordinates.is_left_handed(), ); - Self::new(out.assume_init()) + Self::from_raw(out.assume_init()) } } } + +impl core::fmt::Debug for Matrix4 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("Matrix4").field(&self.rows_wzyx()).finish() + } +} +impl PartialEq for Matrix4 { + fn eq(&self, other: &Matrix4) -> bool { + self.rows_wzyx() == other.rows_wzyx() + } +} +impl Eq for Matrix4 {} diff --git a/citro3d/src/math/ops.rs b/citro3d/src/math/ops.rs index 3d487ea..92823ed 100644 --- a/citro3d/src/math/ops.rs +++ b/citro3d/src/math/ops.rs @@ -5,7 +5,7 @@ use std::ops::{Add, Deref, Div, Mul, Neg, Sub}; #[cfg(feature = "approx")] use approx::AbsDiffEq; -use super::{FVec, FVec3, FVec4, Matrix, Matrix3, Matrix4}; +use super::{FVec, FVec3, FVec4, Matrix4}; // region: FVec4 math operators @@ -126,59 +126,50 @@ impl AbsDiffEq for FVec { // region: Matrix math operators -impl, const M: usize, const N: usize> Add for &Matrix { - type Output = ::Target; +impl Add for Matrix4 { + type Output = Matrix4; #[doc(alias = "Mtx_Add")] - fn add(self, rhs: Rhs) -> Self::Output { + fn add(self, rhs: Matrix4) -> Self::Output { let mut out = MaybeUninit::uninit(); unsafe { - citro3d_sys::Mtx_Add(out.as_mut_ptr(), self.as_raw(), rhs.borrow().as_raw()); - Matrix::new(out.assume_init()) + citro3d_sys::Mtx_Add(out.as_mut_ptr(), self.as_raw(), rhs.as_raw()); + Matrix4::from_raw(out.assume_init()) } } } -impl, const M: usize, const N: usize> Sub for &Matrix { - type Output = ::Target; +impl Sub for Matrix4 { + type Output = Matrix4; #[doc(alias = "Mtx_Subtract")] - fn sub(self, rhs: Rhs) -> Self::Output { + fn sub(self, rhs: Matrix4) -> Self::Output { let mut out = MaybeUninit::uninit(); unsafe { - citro3d_sys::Mtx_Subtract(out.as_mut_ptr(), self.as_raw(), rhs.borrow().as_raw()); - Matrix::new(out.assume_init()) + citro3d_sys::Mtx_Subtract(out.as_mut_ptr(), self.as_raw(), rhs.as_raw()); + Matrix4::from_raw(out.assume_init()) } } } -impl Mul<&Matrix> for &Matrix { - type Output = Matrix; +impl Mul for Matrix4 { + type Output = Matrix4; #[doc(alias = "Mtx_Multiply")] - fn mul(self, rhs: &Matrix) -> Self::Output { + fn mul(self, rhs: Matrix4) -> Self::Output { let mut out = MaybeUninit::uninit(); unsafe { citro3d_sys::Mtx_Multiply(out.as_mut_ptr(), self.as_raw(), rhs.as_raw()); - Matrix::new(out.assume_init()) + Matrix4::from_raw(out.assume_init()) } } } -impl Mul> for &Matrix { - type Output = Matrix; +impl Mul for &Matrix4 { + type Output = Matrix4; - fn mul(self, rhs: Matrix) -> Self::Output { - self * &rhs - } -} - -impl Mul for &Matrix3 { - type Output = FVec3; - - #[doc(alias = "Mtx_MultiplyFVec3")] - fn mul(self, rhs: FVec3) -> Self::Output { - FVec(unsafe { citro3d_sys::Mtx_MultiplyFVec3(self.as_raw(), rhs.0) }) + fn mul(self, rhs: Matrix4) -> Self::Output { + *self * rhs } } @@ -191,7 +182,7 @@ impl Mul for &Matrix4 { } } -impl Mul for &Matrix<4, 3> { +impl Mul for &Matrix4 { type Output = FVec4; #[doc(alias = "Mtx_MultiplyFVecH")] @@ -202,17 +193,9 @@ impl Mul for &Matrix<4, 3> { // endregion -impl, const M: usize, const N: usize> PartialEq for Matrix { - fn eq(&self, other: &Rhs) -> bool { - self.as_rows() == other.borrow().as_rows() - } -} - -impl Eq for Matrix {} - #[cfg(feature = "approx")] #[doc(cfg(feature = "approx"))] -impl AbsDiffEq for Matrix { +impl AbsDiffEq for Matrix4 { type Epsilon = f32; fn default_epsilon() -> Self::Epsilon { @@ -222,18 +205,10 @@ impl AbsDiffEq for Matrix { } fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - let lhs = self.as_rows(); - let rhs = other.as_rows(); - - for row in 0..M { - for col in 0..N { - if !lhs[row][col].abs_diff_eq(&rhs[row][col], epsilon) { - return false; - } - } - } - - true + self.rows_wzyx() + .into_iter() + .zip(other.rows_wzyx().into_iter()) + .all(|(l, r)| l.abs_diff_eq(&r, epsilon)) } } diff --git a/citro3d/src/math/projection.rs b/citro3d/src/math/projection.rs index f694ad6..b0c1da4 100644 --- a/citro3d/src/math/projection.rs +++ b/citro3d/src/math/projection.rs @@ -209,7 +209,7 @@ impl From> for Matrix4 { } } - unsafe { Self::new(result.assume_init()) } + unsafe { Self::from_raw(result.assume_init()) } } } @@ -285,7 +285,7 @@ impl From> for Matrix4 { clip_planes_z.far, projection.coordinates.is_left_handed(), ); - Self::new(out.assume_init()) + Self::from_raw(out.assume_init()) } } } diff --git a/citro3d/src/shader.rs b/citro3d/src/shader.rs index 9f1de0b..512022b 100644 --- a/citro3d/src/shader.rs +++ b/citro3d/src/shader.rs @@ -96,7 +96,7 @@ impl Program { if idx < 0 { Err(crate::Error::NotFound) } else { - Ok(idx.into()) + Ok((idx as u8).into()) } } @@ -116,6 +116,7 @@ impl Drop for Program { /// The type of a shader. #[repr(u32)] +#[derive(Clone, Copy)] pub enum Type { /// A vertex shader. Vertex = ctru_sys::GPU_VERTEX_SHADER, diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index 22c7092..e35fc2c 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -1,15 +1,17 @@ //! Common definitions for binding uniforms to shaders. This is primarily //! done by implementing the [`Uniform`] trait for a given type. -use crate::math::Matrix; +use std::ops::Range; + +use crate::math::{FVec4, IVec, Matrix4}; use crate::{shader, Instance}; /// The index of a uniform within a [`shader::Program`]. -#[derive(Copy, Clone, Debug)] -pub struct Index(i8); +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Index(u8); -impl From for Index { - fn from(value: i8) -> Self { +impl From for Index { + fn from(value: u8) -> Self { Self(value) } } @@ -20,38 +22,125 @@ impl From for i32 { } } -mod private { - use crate::math::Matrix; +/// A shader uniform. This trait is implemented for types that can be bound to +/// shaders to be used as a uniform input to the shader. +pub enum Uniform { + Float(FVec4), + Float2([FVec4; 2]), + Float3([FVec4; 3]), + Float4(Matrix4), + Bool(bool), + Int(IVec), +} +impl Uniform { + pub fn index_range(&self) -> Range { + // these indexes are from the uniform table in the shader see: https://www.3dbrew.org/wiki/SHBIN#Uniform_Table_Entry + // the input registers then are excluded by libctru, see: https://github.com/devkitPro/libctru/blob/0da8705527f03b4b08ff7fee4dd1b7f28df37905/libctru/source/gpu/shbin.c#L93 + match self { + Uniform::Float(_) | Uniform::Float2(_) | Uniform::Float3(_) | Uniform::Float4(_) => { + Index(0)..Index(0x60) + } + Uniform::Int(_) => Index(0x60)..Index(0x64), + // this gap is intentional + Uniform::Bool(_) => Index(0x68)..Index(0x79), + } + } + pub fn len(&self) -> usize { + match self { + Uniform::Float(_) => 1, + Uniform::Float2(_) => 2, + Uniform::Float3(_) => 3, + Uniform::Float4(_) => 4, + Uniform::Bool(_) | Uniform::Int(_) => 1, + } + } - pub trait Sealed {} + /// Bind a uniform + /// + /// Note: `_instance` is here to ensure unique access to the global uniform buffers + /// otherwise we could race and/or violate aliasing + pub(crate) fn bind(self, _instance: &mut Instance, ty: shader::Type, index: Index) { + assert!( + self.index_range().contains(&index), + "tried to bind uniform to an invalid index (index: {}, valid range: {}..{})", + index.0, + self.index_range().start.0, + self.index_range().end.0 + ); + assert!(self.index_range().end.0 as usize >= self.len() + index.0 as usize, "tried to bind a uniform that would overflow the uniform buffer. index was {}, size was {} max is {}", index.0, self.len(), self.index_range().end.0); + let set_fvs = |fs: &[FVec4]| { + for (off, f) in fs.iter().enumerate() { + unsafe { + citro3d_sys::C3D_FVUnifSet( + ty.into(), + (index.0 as usize + off) as i32, + f.x(), + f.y(), + f.z(), + f.w(), + ); + } + } + }; + match self { + Uniform::Bool(b) => unsafe { + citro3d_sys::C3D_BoolUnifSet(ty.into(), index.into(), b); + }, + Uniform::Int(i) => unsafe { + citro3d_sys::C3D_IVUnifSet( + ty.into(), + index.into(), + i.x() as i32, + i.y() as i32, + i.z() as i32, + i.w() as i32, + ); + }, + Uniform::Float(f) => set_fvs(&[f]), + Uniform::Float2(fs) => { + set_fvs(&fs); + } + Uniform::Float3(fs) => set_fvs(&fs), + Uniform::Float4(m) => { + set_fvs(&m.rows_wzyx()); + } + } + } +} - impl Sealed for &Matrix {} +impl From for Uniform { + fn from(value: Matrix4) -> Self { + Self::Float4(value) + } +} +impl From<[FVec4; 3]> for Uniform { + fn from(value: [FVec4; 3]) -> Self { + Self::Float3(value) + } } -/// A shader uniform. This trait is implemented for types that can be bound to -/// shaders to be used as a uniform input to the shader. -pub trait Uniform: private::Sealed { - /// Bind the uniform to the given shader index for the given shader type. - /// An [`Instance`] is required to prevent concurrent binding of different - /// uniforms to the same index. - fn bind(self, instance: &mut Instance, shader_type: shader::Type, index: Index); -} - -impl Uniform for &Matrix { - #[doc(alias = "C34_FVUnifMtxNx4")] - #[doc(alias = "C34_FVUnifMtx4x4")] - #[doc(alias = "C34_FVUnifMtx3x4")] - #[doc(alias = "C34_FVUnifMtx2x4")] - fn bind(self, _instance: &mut Instance, type_: shader::Type, index: Index) { - unsafe { - citro3d_sys::C3D_FVUnifMtxNx4( - type_.into(), - index.into(), - self.as_raw(), - // UNWRAP: it should be impossible for end users to construct - // a matrix with M > i32::MAX - M.try_into().unwrap(), - ); - } +impl From<[FVec4; 2]> for Uniform { + fn from(value: [FVec4; 2]) -> Self { + Self::Float2(value) + } +} +impl From for Uniform { + fn from(value: FVec4) -> Self { + Self::Float(value) + } +} +impl From for Uniform { + fn from(value: IVec) -> Self { + Self::Int(value) + } +} +impl From for Uniform { + fn from(value: bool) -> Self { + Self::Bool(value) + } +} +impl From<&Matrix4> for Uniform { + fn from(value: &Matrix4) -> Self { + (*value).into() } } From 34532ae6b902e43b0c7ce949ea2ca4cc898c9226 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Thu, 1 Feb 2024 21:12:36 +0000 Subject: [PATCH 03/15] feat: add helpful constructors to matrix4 --- citro3d/src/math/matrix.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/citro3d/src/math/matrix.rs b/citro3d/src/math/matrix.rs index e3f958e..7397a3d 100644 --- a/citro3d/src/math/matrix.rs +++ b/citro3d/src/math/matrix.rs @@ -16,6 +16,20 @@ use super::{CoordinateOrientation, FVec3, FVec4}; pub struct Matrix4(citro3d_sys::C3D_Mtx); impl Matrix4 { + /// Construct a Matrix4 from the cells + /// + /// # Note + /// This expects rows to be in WZYX order + pub fn from_cells_wzyx(cells: [f32; 16]) -> Self { + Self(citro3d_sys::C3D_Mtx { m: cells }) + } + /// Construct a Matrix4 from its rows + pub fn from_rows(rows: [FVec4; 4]) -> Self { + Self(citro3d_sys::C3D_Mtx { + // Safety: FVec is repr(transparent) + r: unsafe { core::mem::transmute::<_, [citro3d_sys::C3D_FVec; 4]>(rows) }, + }) + } /// Create a new matrix from a raw citro3d_sys one pub fn from_raw(value: citro3d_sys::C3D_Mtx) -> Self { Self(value) @@ -39,7 +53,7 @@ impl Matrix4 { unsafe { core::mem::transmute::<[citro3d_sys::C3D_FVec; 4], [FVec4; 4]>(self.0.r) } } - /// Get the rows in normal XYZW form + /// Get the rows in XYZW form pub fn rows_xyzw(self) -> [[f32; 4]; 4] { let mut rows = self.rows_wzyx(); for r in &mut rows { @@ -47,7 +61,7 @@ impl Matrix4 { r.0.c.reverse(); } } - // Safety: FVec has same layout as citro3d_sys version which is a union with [f32; 4] as one variant + // Safety: FVec has same layout as citro3d_sys::C3D_FVec which is a union with [f32; 4] as one variant unsafe { std::mem::transmute::<_, [[f32; 4]; 4]>(rows) } } /// Construct the zero matrix. From 3d2a53d13338e6b11dbb795ceb235dc0856bb015 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Thu, 1 Feb 2024 23:55:57 +0000 Subject: [PATCH 04/15] feat: glam support --- citro3d/Cargo.toml | 5 ++++- citro3d/src/math/fvec.rs | 26 ++++++++++++++++++++++++++ citro3d/src/math/matrix.rs | 14 ++++++++++++++ citro3d/src/math/ops.rs | 3 +-- citro3d/src/uniform.rs | 14 ++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/citro3d/Cargo.toml b/citro3d/Cargo.toml index 4147662..a139e28 100644 --- a/citro3d/Cargo.toml +++ b/citro3d/Cargo.toml @@ -6,6 +6,7 @@ version = "0.1.0" edition = "2021" [dependencies] +glam = { version = "0.25.0", optional = true } approx = { version = "0.5.1", optional = true } bitflags = "1.3.2" bytemuck = { version = "1.10.0", features = ["extern_crate_std"] } @@ -17,9 +18,11 @@ document-features = "0.2.7" libc = "0.2.125" [features] -default = [] +default = ["glam"] ## Enable this feature to use the `approx` crate for comparing vectors and matrices. approx = ["dep:approx"] +# Enable for glam support in uniforms +glam = ["dep:glam"] [dev-dependencies] test-runner = { git = "https://github.com/rust3ds/test-runner.git" } diff --git a/citro3d/src/math/fvec.rs b/citro3d/src/math/fvec.rs index 3fa888e..127855b 100644 --- a/citro3d/src/math/fvec.rs +++ b/citro3d/src/math/fvec.rs @@ -250,6 +250,32 @@ impl FVec3 { } } +#[cfg(feature = "glam")] +impl From for FVec4 { + fn from(value: glam::Vec4) -> Self { + Self::new(value.x, value.y, value.z, value.w) + } +} +#[cfg(feature = "glam")] +impl From for FVec3 { + fn from(value: glam::Vec3) -> Self { + Self::new(value.x, value.y, value.z) + } +} +#[cfg(feature = "glam")] +impl From for glam::Vec4 { + fn from(value: FVec4) -> Self { + glam::Vec4::new(value.x(), value.y(), value.z(), value.w()) + } +} + +#[cfg(feature = "glam")] +impl From for glam::Vec3 { + fn from(value: FVec3) -> Self { + glam::Vec3::new(value.x(), value.y(), value.z()) + } +} + #[cfg(test)] mod tests { use approx::assert_abs_diff_eq; diff --git a/citro3d/src/math/matrix.rs b/citro3d/src/math/matrix.rs index 7397a3d..96fbbbe 100644 --- a/citro3d/src/math/matrix.rs +++ b/citro3d/src/math/matrix.rs @@ -198,3 +198,17 @@ impl PartialEq for Matrix4 { } } impl Eq for Matrix4 {} + +#[cfg(feature = "glam")] +impl From for Matrix4 { + fn from(mat: glam::Mat4) -> Self { + Matrix4::from_rows(core::array::from_fn(|i| mat.row(i).into())) + } +} + +#[cfg(feature = "glam")] +impl From for glam::Mat4 { + fn from(mat: Matrix4) -> Self { + glam::Mat4::from_cols_array_2d(&mat.rows_xyzw()).transpose() + } +} diff --git a/citro3d/src/math/ops.rs b/citro3d/src/math/ops.rs index 92823ed..ce962fc 100644 --- a/citro3d/src/math/ops.rs +++ b/citro3d/src/math/ops.rs @@ -1,6 +1,5 @@ -use std::borrow::Borrow; use std::mem::MaybeUninit; -use std::ops::{Add, Deref, Div, Mul, Neg, Sub}; +use std::ops::{Add, Div, Mul, Neg, Sub}; #[cfg(feature = "approx")] use approx::AbsDiffEq; diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index e35fc2c..e4eb46d 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -144,3 +144,17 @@ impl From<&Matrix4> for Uniform { (*value).into() } } + +#[cfg(feature = "glam")] +impl From for Uniform { + fn from(value: glam::Vec4) -> Self { + Self::Float(value.into()) + } +} + +#[cfg(feature = "glam")] +impl From for Uniform { + fn from(value: glam::Mat4) -> Self { + Self::Float4(value.into()) + } +} From 4eafa19f44a54f0f38ce81470ad061274a68e03f Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Fri, 2 Feb 2024 00:03:20 +0000 Subject: [PATCH 05/15] fix: warning and docs --- citro3d/src/uniform.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index e4eb46d..993aa21 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -22,17 +22,23 @@ impl From for i32 { } } -/// A shader uniform. This trait is implemented for types that can be bound to -/// shaders to be used as a uniform input to the shader. +/// A uniform which may be bound as input to a shader program pub enum Uniform { + /// Single float uniform (`.fvec name`) Float(FVec4), + /// Two element float uniform (`.fvec name[2]`) Float2([FVec4; 2]), + /// Three element float uniform (`.fvec name [3]`) Float3([FVec4; 3]), + /// Matrix/4 element float uniform (`.fvec name[4]`) Float4(Matrix4), + /// Bool uniform (`.bool name`) Bool(bool), + /// Integer uniform (`.ivec name`) Int(IVec), } impl Uniform { + /// Get range of valid indexes for this uniform to bind to pub fn index_range(&self) -> Range { // these indexes are from the uniform table in the shader see: https://www.3dbrew.org/wiki/SHBIN#Uniform_Table_Entry // the input registers then are excluded by libctru, see: https://github.com/devkitPro/libctru/blob/0da8705527f03b4b08ff7fee4dd1b7f28df37905/libctru/source/gpu/shbin.c#L93 @@ -45,6 +51,8 @@ impl Uniform { Uniform::Bool(_) => Index(0x68)..Index(0x79), } } + /// Get length of uniform, i.e. how many registers it will write to + #[allow(clippy::len_without_is_empty)] // is_empty doesn't make sense here pub fn len(&self) -> usize { match self { Uniform::Float(_) => 1, From 057ec9805b578dbd10406b8a95bc51262e40574c Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Fri, 2 Feb 2024 00:47:12 +0000 Subject: [PATCH 06/15] chore: downgrade glam version to slightly older --- citro3d/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/citro3d/Cargo.toml b/citro3d/Cargo.toml index a139e28..49402fa 100644 --- a/citro3d/Cargo.toml +++ b/citro3d/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" edition = "2021" [dependencies] -glam = { version = "0.25.0", optional = true } +glam = { version = "0.24.2", optional = true } approx = { version = "0.5.1", optional = true } bitflags = "1.3.2" bytemuck = { version = "1.10.0", features = ["extern_crate_std"] } From 12d62b3a4152d4c38ee5a2995674660f9d81bdd3 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 11:28:49 +0000 Subject: [PATCH 07/15] fix: uneeded usages of transmute --- citro3d/src/math/fvec.rs | 5 +++++ citro3d/src/math/matrix.rs | 15 +++------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/citro3d/src/math/fvec.rs b/citro3d/src/math/fvec.rs index 127855b..8f97f19 100644 --- a/citro3d/src/math/fvec.rs +++ b/citro3d/src/math/fvec.rs @@ -55,6 +55,11 @@ impl FVec4 { unsafe { self.0.__bindgen_anon_1.w } } + /// Wrap a raw [`citro3d_sys::C3D_FVec`] + pub fn from_raw(raw: citro3d_sys::C3D_FVec) -> Self { + Self(raw) + } + /// Create a new [`FVec4`] from its components. /// /// # Example diff --git a/citro3d/src/math/matrix.rs b/citro3d/src/math/matrix.rs index 96fbbbe..b498f66 100644 --- a/citro3d/src/math/matrix.rs +++ b/citro3d/src/math/matrix.rs @@ -26,8 +26,7 @@ impl Matrix4 { /// Construct a Matrix4 from its rows pub fn from_rows(rows: [FVec4; 4]) -> Self { Self(citro3d_sys::C3D_Mtx { - // Safety: FVec is repr(transparent) - r: unsafe { core::mem::transmute::<_, [citro3d_sys::C3D_FVec; 4]>(rows) }, + r: rows.map(|r| r.0), }) } /// Create a new matrix from a raw citro3d_sys one @@ -49,20 +48,12 @@ impl Matrix4 { /// Get the rows in raw (WZYX) form pub fn rows_wzyx(self) -> [FVec4; 4] { - // Safety: FVec4 is repr(C) to allow transmute from C3D_Vec - unsafe { core::mem::transmute::<[citro3d_sys::C3D_FVec; 4], [FVec4; 4]>(self.0.r) } + unsafe { self.0.r }.map(FVec4::from_raw) } /// Get the rows in XYZW form pub fn rows_xyzw(self) -> [[f32; 4]; 4] { - let mut rows = self.rows_wzyx(); - for r in &mut rows { - unsafe { - r.0.c.reverse(); - } - } - // Safety: FVec has same layout as citro3d_sys::C3D_FVec which is a union with [f32; 4] as one variant - unsafe { std::mem::transmute::<_, [[f32; 4]; 4]>(rows) } + self.rows_wzyx().map(|r| [r.x(), r.y(), r.z(), r.w()]) } /// Construct the zero matrix. #[doc(alias = "Mtx_Zeros")] From 44e3850bb1e14bcca0851aad2a981cc6ce03afd5 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 11:30:15 +0000 Subject: [PATCH 08/15] chore: Uniform -> Self --- citro3d/src/uniform.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index 993aa21..23586c9 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -43,23 +43,23 @@ impl Uniform { // these indexes are from the uniform table in the shader see: https://www.3dbrew.org/wiki/SHBIN#Uniform_Table_Entry // the input registers then are excluded by libctru, see: https://github.com/devkitPro/libctru/blob/0da8705527f03b4b08ff7fee4dd1b7f28df37905/libctru/source/gpu/shbin.c#L93 match self { - Uniform::Float(_) | Uniform::Float2(_) | Uniform::Float3(_) | Uniform::Float4(_) => { + Self::Float(_) | Self::Float2(_) | Self::Float3(_) | Self::Float4(_) => { Index(0)..Index(0x60) } - Uniform::Int(_) => Index(0x60)..Index(0x64), + Self::Int(_) => Index(0x60)..Index(0x64), // this gap is intentional - Uniform::Bool(_) => Index(0x68)..Index(0x79), + Self::Bool(_) => Index(0x68)..Index(0x79), } } /// Get length of uniform, i.e. how many registers it will write to #[allow(clippy::len_without_is_empty)] // is_empty doesn't make sense here pub fn len(&self) -> usize { match self { - Uniform::Float(_) => 1, - Uniform::Float2(_) => 2, - Uniform::Float3(_) => 3, - Uniform::Float4(_) => 4, - Uniform::Bool(_) | Uniform::Int(_) => 1, + Self::Float(_) => 1, + Self::Float2(_) => 2, + Self::Float3(_) => 3, + Self::Float4(_) => 4, + Self::Bool(_) | Uniform::Int(_) => 1, } } @@ -91,10 +91,10 @@ impl Uniform { } }; match self { - Uniform::Bool(b) => unsafe { + Self::Bool(b) => unsafe { citro3d_sys::C3D_BoolUnifSet(ty.into(), index.into(), b); }, - Uniform::Int(i) => unsafe { + Self::Int(i) => unsafe { citro3d_sys::C3D_IVUnifSet( ty.into(), index.into(), @@ -104,12 +104,12 @@ impl Uniform { i.w() as i32, ); }, - Uniform::Float(f) => set_fvs(&[f]), - Uniform::Float2(fs) => { + Self::Float(f) => set_fvs(&[f]), + Self::Float2(fs) => { set_fvs(&fs); } - Uniform::Float3(fs) => set_fvs(&fs), - Uniform::Float4(m) => { + Self::Float3(fs) => set_fvs(&fs), + Self::Float4(m) => { set_fvs(&m.rows_wzyx()); } } From 58e41fec04ad0c240ca1ee7c65cb9437abc332ff Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 11:35:05 +0000 Subject: [PATCH 09/15] fix: not using debug impl for printing Index --- citro3d/src/uniform.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index 23586c9..aa886e2 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -70,12 +70,11 @@ impl Uniform { pub(crate) fn bind(self, _instance: &mut Instance, ty: shader::Type, index: Index) { assert!( self.index_range().contains(&index), - "tried to bind uniform to an invalid index (index: {}, valid range: {}..{})", - index.0, - self.index_range().start.0, - self.index_range().end.0 + "tried to bind uniform to an invalid index (index: {:?}, valid range: {:?})", + index, + self.index_range(), ); - assert!(self.index_range().end.0 as usize >= self.len() + index.0 as usize, "tried to bind a uniform that would overflow the uniform buffer. index was {}, size was {} max is {}", index.0, self.len(), self.index_range().end.0); + assert!(self.index_range().end.0 as usize >= self.len() + index.0 as usize, "tried to bind a uniform that would overflow the uniform buffer. index was {:?}, size was {} max is {:?}", index, self.len(), self.index_range().end); let set_fvs = |fs: &[FVec4]| { for (off, f) in fs.iter().enumerate() { unsafe { From b3125756640ee9357c169e903ce49fc2c2b55ead Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 11:35:32 +0000 Subject: [PATCH 10/15] fix: Uniform not non-exhaustive --- citro3d/src/uniform.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index aa886e2..b30ff70 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -23,6 +23,7 @@ impl From for i32 { } /// A uniform which may be bound as input to a shader program +#[non_exhaustive] pub enum Uniform { /// Single float uniform (`.fvec name`) Float(FVec4), From 7a5b24c90cc1d4724dd8072fae296cc7b5696038 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 11:36:33 +0000 Subject: [PATCH 11/15] fix: Uniform missing standard derives --- citro3d/src/math.rs | 2 +- citro3d/src/uniform.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/citro3d/src/math.rs b/citro3d/src/math.rs index 35a188e..ec2ebfb 100644 --- a/citro3d/src/math.rs +++ b/citro3d/src/math.rs @@ -21,7 +21,7 @@ pub use projection::{ /// Uses the PICA layout of WZYX #[doc(alias = "C3D_IVec")] #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct IVec(citro3d_sys::C3D_IVec); impl IVec { diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index b30ff70..edd28bf 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -24,6 +24,7 @@ impl From for i32 { /// A uniform which may be bound as input to a shader program #[non_exhaustive] +#[derive(Debug, PartialEq, Clone, Copy)] pub enum Uniform { /// Single float uniform (`.fvec name`) Float(FVec4), From 61f7dbe0752182f0b43e8835f17f44ae7397b087 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 11:37:17 +0000 Subject: [PATCH 12/15] fix: matrix4 implementing Eq --- citro3d/src/math/matrix.rs | 6 ------ citro3d/src/math/ops.rs | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/citro3d/src/math/matrix.rs b/citro3d/src/math/matrix.rs index b498f66..aac8612 100644 --- a/citro3d/src/math/matrix.rs +++ b/citro3d/src/math/matrix.rs @@ -183,12 +183,6 @@ impl core::fmt::Debug for Matrix4 { f.debug_tuple("Matrix4").field(&self.rows_wzyx()).finish() } } -impl PartialEq for Matrix4 { - fn eq(&self, other: &Matrix4) -> bool { - self.rows_wzyx() == other.rows_wzyx() - } -} -impl Eq for Matrix4 {} #[cfg(feature = "glam")] impl From for Matrix4 { diff --git a/citro3d/src/math/ops.rs b/citro3d/src/math/ops.rs index ce962fc..3807a08 100644 --- a/citro3d/src/math/ops.rs +++ b/citro3d/src/math/ops.rs @@ -190,6 +190,12 @@ impl Mul for &Matrix4 { } } +impl PartialEq for Matrix4 { + fn eq(&self, other: &Matrix4) -> bool { + self.rows_wzyx() == other.rows_wzyx() + } +} + // endregion #[cfg(feature = "approx")] From 8e117c05da05606df4070ef3cfdc11f78ecb1d6e Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 11:43:26 +0000 Subject: [PATCH 13/15] chore: improve docs on Uniform --- citro3d/src/uniform.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/citro3d/src/uniform.rs b/citro3d/src/uniform.rs index edd28bf..c05157b 100644 --- a/citro3d/src/uniform.rs +++ b/citro3d/src/uniform.rs @@ -27,16 +27,22 @@ impl From for i32 { #[derive(Debug, PartialEq, Clone, Copy)] pub enum Uniform { /// Single float uniform (`.fvec name`) + #[doc(alias = "C3D_FVUnifSet")] Float(FVec4), /// Two element float uniform (`.fvec name[2]`) + #[doc(alias = "C3D_FVUnifMtx2x4")] Float2([FVec4; 2]), /// Three element float uniform (`.fvec name [3]`) + #[doc(alias = "C3D_FVUnifMtx3x4")] Float3([FVec4; 3]), /// Matrix/4 element float uniform (`.fvec name[4]`) + #[doc(alias = "C3D_FVUnifMtx4x4")] Float4(Matrix4), /// Bool uniform (`.bool name`) + #[doc(alias = "C3D_BoolUnifSet")] Bool(bool), /// Integer uniform (`.ivec name`) + #[doc(alias = "C3D_IVUnifSet")] Int(IVec), } impl Uniform { From d6ce8cd37a9b72efd3b6921608b10f8f67263d47 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 5 Feb 2024 13:05:23 +0000 Subject: [PATCH 14/15] fix: glam feature not in docs --- citro3d/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/citro3d/Cargo.toml b/citro3d/Cargo.toml index 49402fa..705d601 100644 --- a/citro3d/Cargo.toml +++ b/citro3d/Cargo.toml @@ -21,7 +21,7 @@ libc = "0.2.125" default = ["glam"] ## Enable this feature to use the `approx` crate for comparing vectors and matrices. approx = ["dep:approx"] -# Enable for glam support in uniforms +## Enable for glam support in uniforms glam = ["dep:glam"] [dev-dependencies] From 52f0019431964413a8c4a4255cd29b5d3003a2b6 Mon Sep 17 00:00:00 2001 From: Natasha England-Elbro Date: Mon, 12 Feb 2024 22:48:20 +0000 Subject: [PATCH 15/15] fix: tests build --- citro3d/src/math/ops.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/citro3d/src/math/ops.rs b/citro3d/src/math/ops.rs index 3807a08..229210e 100644 --- a/citro3d/src/math/ops.rs +++ b/citro3d/src/math/ops.rs @@ -247,25 +247,13 @@ mod tests { assert_abs_diff_eq!(l / 2.0, FVec4::splat(0.5)); } - #[test] - fn matrix3() { - let l = Matrix3::diagonal(1.0, 2.0, 3.0); - let r = Matrix3::identity(); - let (l, r) = (&l, &r); - - assert_abs_diff_eq!(&(l * r), l); - assert_abs_diff_eq!(&(l + r), &Matrix3::diagonal(2.0, 3.0, 4.0)); - assert_abs_diff_eq!(&(l - r), &Matrix3::diagonal(0.0, 1.0, 2.0)); - } - #[test] fn matrix4() { let l = Matrix4::diagonal(1.0, 2.0, 3.0, 4.0); let r = Matrix4::identity(); - let (l, r) = (&l, &r); - assert_abs_diff_eq!(&(l * r), l); - assert_abs_diff_eq!(&(l + r), &Matrix4::diagonal(2.0, 3.0, 4.0, 5.0)); - assert_abs_diff_eq!(&(l - r), &Matrix4::diagonal(0.0, 1.0, 2.0, 3.0)); + assert_abs_diff_eq!(l * r, l); + assert_abs_diff_eq!(l + r, Matrix4::diagonal(2.0, 3.0, 4.0, 5.0)); + assert_abs_diff_eq!(l - r, Matrix4::diagonal(0.0, 1.0, 2.0, 3.0)); } }