diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index 9412e59..a6a5152 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -79,7 +79,8 @@ fn main() { let shader = shader::Library::from_bytes(SHADER_BYTES).unwrap(); let vertex_shader = shader.get(0).unwrap(); - let mut program = shader::Program::new(vertex_shader).unwrap(); + let program = shader::Program::new(vertex_shader).unwrap(); + instance.bind_program(&program); let mut vbo_data = Vec::with_capacity_in(VERTICES.len(), ctru::linear::LinearAllocator); vbo_data.extend_from_slice(VERTICES); @@ -87,7 +88,7 @@ fn main() { let mut buf_info = buffer::Info::new(); let (attr_info, vbo_idx) = prepare_vbos(&mut buf_info, &vbo_data); - scene_init(&mut program); + scene_init(); let projection_uniform_idx = program.get_uniform("projection").unwrap(); @@ -191,11 +192,9 @@ fn calculate_projections() -> Projections { } } -fn scene_init(program: &mut shader::Program) { +fn scene_init() { // Load the vertex shader, create a shader program and bind it unsafe { - citro3d_sys::C3D_BindProgram(program.as_raw_mut()); - // Configure the first fragment shading substage to just pass through the vertex color // See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight let env = citro3d_sys::C3D_GetTexEnv(0); diff --git a/citro3d/src/lib.rs b/citro3d/src/lib.rs index a100e31..9368b5c 100644 --- a/citro3d/src/lib.rs +++ b/citro3d/src/lib.rs @@ -73,7 +73,8 @@ impl Instance { } /// Render a frame. The passed in function/closure can mutate the instance, - /// such as to [select a render target](Self::select_render_target). + /// such as to [select a render target](Self::select_render_target) + /// or [bind a new shader program](Self::bind_program). #[doc(alias = "C3D_FrameBegin")] #[doc(alias = "C3D_FrameEnd")] pub fn render_frame_with(&mut self, f: impl FnOnce(&mut Self)) { @@ -139,6 +140,15 @@ impl Instance { } } + /// Use the given [`shader::Program`] for subsequent draw calls. + pub fn bind_program(&mut self, program: &shader::Program) { + // SAFETY: AFAICT C3D_BindProgram just copies pointers from the given program, + // instead of mutating the pointee in any way that would cause UB + unsafe { + citro3d_sys::C3D_BindProgram(program.as_raw().cast_mut()); + } + } + /// Bind a uniform to the given `index` in the vertex shader for the next draw call. /// /// # Example diff --git a/citro3d/src/shader.rs b/citro3d/src/shader.rs index c2042bf..9f1de0b 100644 --- a/citro3d/src/shader.rs +++ b/citro3d/src/shader.rs @@ -17,6 +17,7 @@ use crate::uniform; /// /// The PICA200 does not support user-programmable fragment shaders. #[doc(alias = "shaderProgram_s")] +#[must_use] pub struct Program { program: ctru_sys::shaderProgram_s, } @@ -102,18 +103,13 @@ impl Program { pub(crate) fn as_raw(&self) -> *const ctru_sys::shaderProgram_s { &self.program } - - // TODO: pub(crate) - pub fn as_raw_mut(&mut self) -> *mut ctru_sys::shaderProgram_s { - &mut self.program - } } impl Drop for Program { #[doc(alias = "shaderProgramFree")] fn drop(&mut self) { unsafe { - let _ = ctru_sys::shaderProgramFree(self.as_raw_mut()); + let _ = ctru_sys::shaderProgramFree(self.as_raw().cast_mut()); } } }