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 @@ @@ -4,7 +4,7 @@
#![feature(allocator_api)]
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::{attrib, buffer, render, shader};
use ctru::prelude::*;
@ -158,9 +158,9 @@ where @@ -158,9 +158,9 @@ where
}
struct Projections {
left_eye: Matrix,
right_eye: Matrix,
center: Matrix,
left_eye: Matrix4,
right_eye: Matrix4,
center: Matrix4,
}
fn calculate_projections() -> Projections {

45
citro3d/src/math.rs

@ -21,11 +21,40 @@ pub struct IVec(citro3d_sys::C3D_IVec); @@ -21,11 +21,40 @@ pub struct IVec(citro3d_sys::C3D_IVec);
#[doc(alias = "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.
#[doc(alias = "C3D_Mtx")]
pub struct Matrix(citro3d_sys::C3D_Mtx);
pub type Matrix4 = Matrix<4, 4>;
impl Matrix {
impl<const M: usize, const N: usize> Matrix<M, N> {
/// Construct the zero matrix.
#[doc(alias = "Mtx_Zeros")]
pub fn zero() -> Self {
@ -33,22 +62,20 @@ impl Matrix { @@ -33,22 +62,20 @@ impl Matrix {
let mut out = MaybeUninit::uninit();
unsafe {
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.
#[doc(alias = "Mtx_Identity")]
pub fn identity() -> Self {
let mut out = MaybeUninit::uninit();
unsafe {
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
}
}

14
citro3d/src/math/projection.rs

@ -2,14 +2,14 @@ use std::mem::MaybeUninit; @@ -2,14 +2,14 @@ use std::mem::MaybeUninit;
use std::ops::Range;
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).
/// See specific `Kind` implementations for constructors, e.g.
/// [`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)]
pub struct Projection<Kind> {
coordinates: CoordinateOrientation,
@ -122,7 +122,7 @@ impl Projection<Perspective> { @@ -122,7 +122,7 @@ impl Projection<Perspective> {
self,
left_eye: StereoDisplacement,
right_eye: StereoDisplacement,
) -> (Matrix, Matrix) {
) -> (Matrix4, Matrix4) {
// 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
let left = self.clone().stereo(left_eye);
@ -137,7 +137,7 @@ impl Projection<Perspective> { @@ -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 {
let Perspective {
vertical_fov_radians,
@ -182,7 +182,7 @@ impl From<Projection<Perspective>> for Matrix { @@ -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> { @@ -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 {
let make_mtx = match projection.rotation {
ScreenOrientation::Rotated => citro3d_sys::Mtx_OrthoTilt,
@ -258,7 +258,7 @@ impl From<Projection<Orthographic>> for Matrix { @@ -258,7 +258,7 @@ impl From<Projection<Orthographic>> for Matrix {
clip_planes_z.far,
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 { @@ -24,7 +24,8 @@ mod private {
use crate::math::Matrix;
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
@ -36,9 +37,21 @@ pub trait Uniform: private::Sealed { @@ -36,9 +37,21 @@ pub trait Uniform: private::Sealed {
fn bind(self, instance: &mut Instance, shader_type: shader::Type, index: Index);
}
impl Uniform for &Matrix {
#[doc(alias = "C3D_FVUnifMtx4x4")]
impl<const M: usize> Uniform for &Matrix<M, 4> {
#[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_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