Browse Source

Use a simple trait for binding uniforms

It's not much but it should be extensible enough to apply for other
uniform types. We might want a generic impl for &[u8] or something
as well to support custom uniform types, but that gets trickier.
pull/27/head
Ian Chamberlain 1 year ago
parent
commit
dcab5508f9
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 4
      citro3d/examples/triangle.rs
  2. 18
      citro3d/src/lib.rs
  3. 30
      citro3d/src/shader.rs
  4. 33
      citro3d/src/uniform.rs

4
citro3d/examples/triangle.rs

@ -91,7 +91,7 @@ fn main() {
scene_init(&mut program); scene_init(&mut program);
let projection_uniform_idx = program.get_uniform_location("projection").unwrap(); let projection_uniform_idx = program.get_uniform("projection").unwrap();
while apt.main_loop() { while apt.main_loop() {
hid.scan_input(); hid.scan_input();
@ -109,7 +109,7 @@ fn main() {
let clear_color: u32 = 0x7F_7F_7F_FF; let clear_color: u32 = 0x7F_7F_7F_FF;
target.clear(ClearFlags::ALL, clear_color, 0); target.clear(ClearFlags::ALL, clear_color, 0);
instance.update_vertex_uniform_mat4x4(projection_uniform_idx, projection); instance.bind_vertex_uniform(projection_uniform_idx, projection);
instance.set_attr_info(&attr_info); instance.set_attr_info(&attr_info);

18
citro3d/src/lib.rs

@ -8,10 +8,13 @@ pub mod error;
pub mod math; pub mod math;
pub mod render; pub mod render;
pub mod shader; pub mod shader;
pub mod uniform;
pub use error::{Error, Result}; pub use error::{Error, Result};
pub use math::Matrix; pub use math::Matrix;
use self::uniform::Uniform;
pub mod macros { pub mod macros {
//! Helper macros for working with shaders. //! Helper macros for working with shaders.
pub use citro3d_macros::*; pub use citro3d_macros::*;
@ -123,17 +126,12 @@ impl Instance {
} }
} }
// TODO: need separate versions for vertex/geometry and different dimensions? pub fn bind_vertex_uniform(&mut self, index: uniform::Index, uniform: &impl Uniform) {
// Maybe we could do something nicer with const generics, or something, although uniform.bind(self, shader::Type::Vertex, index);
// it will probably be tricker
pub fn update_vertex_uniform_mat4x4(&mut self, index: i8, matrix: &Matrix) {
unsafe {
citro3d_sys::C3D_FVUnifMtx4x4(
ctru_sys::GPU_VERTEX_SHADER,
index.into(),
matrix.as_raw(),
)
} }
pub fn bind_geometry_uniform(&mut self, index: uniform::Index, uniform: &impl Uniform) {
uniform.bind(self, shader::Type::Geometry, index);
} }
} }

30
citro3d/src/shader.rs

@ -8,10 +8,12 @@ use std::error::Error;
use std::ffi::CString; use std::ffi::CString;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use crate::uniform;
/// A PICA200 shader program. It may have one or both of: /// A PICA200 shader program. It may have one or both of:
/// ///
/// * A vertex shader [`Library`] /// * A [vertex](Type::Vertex) shader [`Library`]
/// * A geometry shader [`Library`] /// * A [geometry](Type::Geometry) shader [`Library`]
/// ///
/// The PICA200 does not support user-programmable fragment shaders. /// The PICA200 does not support user-programmable fragment shaders.
pub struct Program { pub struct Program {
@ -73,7 +75,7 @@ impl Program {
/// ///
/// * If the given `name` contains a null byte /// * If the given `name` contains a null byte
/// * If a uniform with the given `name` could not be found /// * If a uniform with the given `name` could not be found
pub fn get_uniform_location(&self, name: &str) -> crate::Result<i8> { pub fn get_uniform(&self, name: &str) -> crate::Result<uniform::Index> {
let vertex_instance = unsafe { (*self.as_raw()).vertexShader }; let vertex_instance = unsafe { (*self.as_raw()).vertexShader };
assert!( assert!(
!vertex_instance.is_null(), !vertex_instance.is_null(),
@ -88,14 +90,15 @@ impl Program {
if idx < 0 { if idx < 0 {
Err(crate::Error::NotFound) Err(crate::Error::NotFound)
} else { } else {
Ok(idx) Ok(idx.into())
} }
} }
// TODO: pub(crate)
pub fn as_raw(&self) -> *const ctru_sys::shaderProgram_s { pub(crate) fn as_raw(&self) -> *const ctru_sys::shaderProgram_s {
&self.program &self.program
} }
// TODO: pub(crate)
pub fn as_raw_mut(&mut self) -> *mut ctru_sys::shaderProgram_s { pub fn as_raw_mut(&mut self) -> *mut ctru_sys::shaderProgram_s {
&mut self.program &mut self.program
} }
@ -109,6 +112,19 @@ impl Drop for Program {
} }
} }
/// The type of a shader.
#[repr(u32)]
pub enum Type {
Vertex = ctru_sys::GPU_VERTEX_SHADER,
Geometry = ctru_sys::GPU_GEOMETRY_SHADER,
}
impl From<Type> for u32 {
fn from(value: Type) -> Self {
value as u32
}
}
/// A PICA200 Shader Library (commonly called DVLB). This can be comprised of /// A PICA200 Shader Library (commonly called DVLB). This can be comprised of
/// one or more [`Entrypoint`]s, but most commonly has one vertex shader and an /// one or more [`Entrypoint`]s, but most commonly has one vertex shader and an
/// optional geometry shader. /// optional geometry shader.
@ -131,7 +147,7 @@ impl Library {
// SAFETY: we're trusting the parse implementation doesn't mutate // SAFETY: we're trusting the parse implementation doesn't mutate
// the contents of the data. From a quick read it looks like that's // the contents of the data. From a quick read it looks like that's
// correct and it should just take a const arg in the API. // correct and it should just take a const arg in the API.
aligned.as_ptr() as *mut _, aligned.as_ptr().cast_mut(),
aligned.len().try_into()?, aligned.len().try_into()?,
) )
})) }))

33
citro3d/src/uniform.rs

@ -0,0 +1,33 @@
use crate::{shader, Instance, Matrix};
#[derive(Copy, Clone, Debug)]
pub struct Index(i8);
impl From<i8> for Index {
fn from(value: i8) -> Self {
Self(value)
}
}
impl From<Index> for i32 {
fn from(value: Index) -> Self {
value.0.into()
}
}
mod private {
use crate::Matrix;
pub trait Sealed {}
impl Sealed for Matrix {}
}
pub trait Uniform: private::Sealed {
fn bind(&self, instance: &mut Instance, shader_type: shader::Type, index: Index);
}
impl Uniform for Matrix {
fn bind(&self, _instance: &mut Instance, type_: shader::Type, index: Index) {
unsafe { citro3d_sys::C3D_FVUnifMtx4x4(type_.into(), index.into(), self.as_raw()) }
}
}
Loading…
Cancel
Save