Browse Source

Define matrix as MxN with const generics

pull/28/head
Ian Chamberlain 1 year ago
parent
commit
4e0fc5a409
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 8
      citro3d/examples/triangle.rs
  2. 45
      citro3d/src/math.rs
  3. 14
      citro3d/src/math/projection.rs
  4. 21
      citro3d/src/uniform.rs

8
citro3d/examples/triangle.rs

@ -4,7 +4,7 @@
#![feature(allocator_api)] #![feature(allocator_api)]
use citro3d::macros::include_shader; use citro3d::macros::include_shader;
use citro3d::math::{AspectRatio, ClipPlanes, Matrix, Projection, StereoDisplacement}; use citro3d::math::{AspectRatio, ClipPlanes, Matrix4, Projection, StereoDisplacement};
use citro3d::render::ClearFlags; use citro3d::render::ClearFlags;
use citro3d::{attrib, buffer, render, shader}; use citro3d::{attrib, buffer, render, shader};
use ctru::prelude::*; use ctru::prelude::*;
@ -158,9 +158,9 @@ where
} }
struct Projections { struct Projections {
left_eye: Matrix, left_eye: Matrix4,
right_eye: Matrix, right_eye: Matrix4,
center: Matrix, center: Matrix4,
} }
fn calculate_projections() -> Projections { fn calculate_projections() -> Projections {

45
citro3d/src/math.rs

@ -21,11 +21,40 @@ pub struct IVec(citro3d_sys::C3D_IVec);
#[doc(alias = "C3D_FQuat")] #[doc(alias = "C3D_FQuat")]
pub struct FQuat(citro3d_sys::C3D_FQuat); pub struct FQuat(citro3d_sys::C3D_FQuat);
mod mtx {
/// An `M`x`N` row-major matrix of `f32`s.
#[doc(alias = "C3D_Mtx")]
pub struct Matrix<const M: usize, const N: usize>(citro3d_sys::C3D_Mtx);
impl<const M: usize, const N: usize> Matrix<M, N> {
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
}
}
}
pub use mtx::Matrix;
/// A 3x3 row-major matrix of `f32`s.
pub type Matrix3 = Matrix<3, 3>;
/// A 4x4 row-major matrix of `f32`s. /// A 4x4 row-major matrix of `f32`s.
#[doc(alias = "C3D_Mtx")] pub type Matrix4 = Matrix<4, 4>;
pub struct Matrix(citro3d_sys::C3D_Mtx);
impl Matrix { impl<const M: usize, const N: usize> Matrix<M, N> {
/// Construct the zero matrix. /// Construct the zero matrix.
#[doc(alias = "Mtx_Zeros")] #[doc(alias = "Mtx_Zeros")]
pub fn zero() -> Self { pub fn zero() -> Self {
@ -33,23 +62,21 @@ impl Matrix {
let mut out = MaybeUninit::uninit(); let mut out = MaybeUninit::uninit();
unsafe { unsafe {
citro3d_sys::Mtx_Zeros(out.as_mut_ptr()); citro3d_sys::Mtx_Zeros(out.as_mut_ptr());
Self(out.assume_init()) Self::new(out.assume_init())
} }
} }
}
impl<const N: usize> Matrix<N, N> {
/// Construct the identity matrix. /// Construct the identity matrix.
#[doc(alias = "Mtx_Identity")] #[doc(alias = "Mtx_Identity")]
pub fn identity() -> Self { pub fn identity() -> Self {
let mut out = MaybeUninit::uninit(); let mut out = MaybeUninit::uninit();
unsafe { unsafe {
citro3d_sys::Mtx_Identity(out.as_mut_ptr()); citro3d_sys::Mtx_Identity(out.as_mut_ptr());
Self(out.assume_init()) Self::new(out.assume_init())
} }
} }
pub(crate) fn as_raw(&self) -> *const citro3d_sys::C3D_Mtx {
&self.0
}
} }
// region: Projection configuration // region: Projection configuration

14
citro3d/src/math/projection.rs

@ -2,14 +2,14 @@ use std::mem::MaybeUninit;
use std::ops::Range; use std::ops::Range;
use super::{ use super::{
AspectRatio, ClipPlanes, CoordinateOrientation, Matrix, ScreenOrientation, StereoDisplacement, AspectRatio, ClipPlanes, CoordinateOrientation, Matrix4, ScreenOrientation, StereoDisplacement,
}; };
/// Configuration for a 3D [projection](https://en.wikipedia.org/wiki/3D_projection). /// Configuration for a 3D [projection](https://en.wikipedia.org/wiki/3D_projection).
/// See specific `Kind` implementations for constructors, e.g. /// See specific `Kind` implementations for constructors, e.g.
/// [`Projection::perspective`] and [`Projection::orthographic`]. /// [`Projection::perspective`] and [`Projection::orthographic`].
/// ///
/// To use the resulting projection, convert it to a [`Matrix`] with [`From`]/[`Into`]. /// To use the resulting projection, convert it to a [`Matrix`](super::Matrix) with [`From`]/[`Into`].
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Projection<Kind> { pub struct Projection<Kind> {
coordinates: CoordinateOrientation, coordinates: CoordinateOrientation,
@ -122,7 +122,7 @@ impl Projection<Perspective> {
self, self,
left_eye: StereoDisplacement, left_eye: StereoDisplacement,
right_eye: StereoDisplacement, right_eye: StereoDisplacement,
) -> (Matrix, Matrix) { ) -> (Matrix4, Matrix4) {
// TODO: we might be able to avoid this clone if there was a conversion // TODO: we might be able to avoid this clone if there was a conversion
// from &Self to Matrix instead of Self... but it's probably fine for now // from &Self to Matrix instead of Self... but it's probably fine for now
let left = self.clone().stereo(left_eye); let left = self.clone().stereo(left_eye);
@ -137,7 +137,7 @@ impl Projection<Perspective> {
} }
} }
impl From<Projection<Perspective>> for Matrix { impl From<Projection<Perspective>> for Matrix4 {
fn from(projection: Projection<Perspective>) -> Self { fn from(projection: Projection<Perspective>) -> Self {
let Perspective { let Perspective {
vertical_fov_radians, vertical_fov_radians,
@ -182,7 +182,7 @@ impl From<Projection<Perspective>> for Matrix {
} }
} }
unsafe { Self(result.assume_init()) } unsafe { Self::new(result.assume_init()) }
} }
} }
@ -233,7 +233,7 @@ impl Projection<Orthographic> {
} }
} }
impl From<Projection<Orthographic>> for Matrix { impl From<Projection<Orthographic>> for Matrix4 {
fn from(projection: Projection<Orthographic>) -> Self { fn from(projection: Projection<Orthographic>) -> Self {
let make_mtx = match projection.rotation { let make_mtx = match projection.rotation {
ScreenOrientation::Rotated => citro3d_sys::Mtx_OrthoTilt, ScreenOrientation::Rotated => citro3d_sys::Mtx_OrthoTilt,
@ -258,7 +258,7 @@ impl From<Projection<Orthographic>> for Matrix {
clip_planes_z.far, clip_planes_z.far,
projection.coordinates.is_left_handed(), projection.coordinates.is_left_handed(),
); );
Self(out.assume_init()) Self::new(out.assume_init())
} }
} }
} }

21
citro3d/src/uniform.rs

@ -24,7 +24,8 @@ mod private {
use crate::math::Matrix; use crate::math::Matrix;
pub trait Sealed {} pub trait Sealed {}
impl Sealed for &Matrix {}
impl<const M: usize, const N: usize> Sealed for &Matrix<M, N> {}
} }
/// A shader uniform. This trait is implemented for types that can be bound to /// A shader uniform. This trait is implemented for types that can be bound to
@ -36,9 +37,21 @@ pub trait Uniform: private::Sealed {
fn bind(self, instance: &mut Instance, shader_type: shader::Type, index: Index); fn bind(self, instance: &mut Instance, shader_type: shader::Type, index: Index);
} }
impl Uniform for &Matrix { impl<const M: usize> Uniform for &Matrix<M, 4> {
#[doc(alias = "C3D_FVUnifMtx4x4")] #[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) { fn bind(self, _instance: &mut Instance, type_: shader::Type, index: Index) {
unsafe { citro3d_sys::C3D_FVUnifMtx4x4(type_.into(), index.into(), self.as_raw()) } 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(),
);
}
} }
} }

Loading…
Cancel
Save