1use std::error::Error;
8use std::ffi::CString;
9use std::mem::MaybeUninit;
10
11use crate::uniform;
12
13#[doc(alias = "shaderProgram_s")]
20#[must_use]
21pub struct Program {
22 program: ctru_sys::shaderProgram_s,
23}
24
25impl Program {
26 #[doc(alias = "shaderProgramInit")]
34 #[doc(alias = "shaderProgramSetVsh")]
35 pub fn new(vertex_shader: Entrypoint) -> Result<Self, ctru::Error> {
36 let mut program = unsafe {
37 let mut program = MaybeUninit::uninit();
38 let result = ctru_sys::shaderProgramInit(program.as_mut_ptr());
39 if result != 0 {
40 return Err(ctru::Error::from(result));
41 }
42 program.assume_init()
43 };
44
45 let ret = unsafe { ctru_sys::shaderProgramSetVsh(&mut program, vertex_shader.as_raw()) };
46
47 if ret == 0 {
48 Ok(Self { program })
49 } else {
50 Err(ctru::Error::from(ret))
51 }
52 }
53
54 #[doc(alias = "shaderProgramSetGsh")]
61 pub fn set_geometry_shader(
62 &mut self,
63 geometry_shader: Entrypoint,
64 stride: u8,
65 ) -> Result<(), ctru::Error> {
66 let ret = unsafe {
67 ctru_sys::shaderProgramSetGsh(&mut self.program, geometry_shader.as_raw(), stride)
68 };
69
70 if ret == 0 {
71 Ok(())
72 } else {
73 Err(ctru::Error::from(ret))
74 }
75 }
76
77 #[doc(alias = "shaderInstanceGetUniformLocation")]
84 pub fn get_uniform(&self, name: &str) -> crate::Result<uniform::Index> {
85 let vertex_instance = unsafe { (*self.as_raw()).vertexShader };
86 assert!(
87 !vertex_instance.is_null(),
88 "vertex shader should never be null!"
89 );
90
91 let name = CString::new(name)?;
92
93 let idx =
94 unsafe { ctru_sys::shaderInstanceGetUniformLocation(vertex_instance, name.as_ptr()) };
95
96 if idx < 0 {
97 Err(crate::Error::NotFound)
98 } else {
99 Ok((idx as u8).into())
100 }
101 }
102
103 pub(crate) fn as_raw(&self) -> *const ctru_sys::shaderProgram_s {
104 &self.program
105 }
106}
107
108impl Drop for Program {
109 #[doc(alias = "shaderProgramFree")]
110 fn drop(&mut self) {
111 unsafe {
112 let _ = ctru_sys::shaderProgramFree(self.as_raw().cast_mut());
113 }
114 }
115}
116
117#[repr(u8)]
119#[derive(Clone, Copy)]
120pub enum Type {
121 Vertex = ctru_sys::GPU_VERTEX_SHADER,
123 Geometry = ctru_sys::GPU_GEOMETRY_SHADER,
125}
126
127impl From<Type> for u8 {
128 fn from(value: Type) -> Self {
129 value as u8
130 }
131}
132
133#[doc(alias = "DVLB_s")]
140pub struct Library(*mut ctru_sys::DVLB_s);
141
142impl Library {
143 #[doc(alias = "DVLB_ParseFile")]
150 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Box<dyn Error>> {
151 let aligned: &[u32] = bytemuck::try_cast_slice(bytes)?;
152 Ok(Self(unsafe {
153 ctru_sys::DVLB_ParseFile(
154 aligned.as_ptr().cast_mut(),
158 aligned.len().try_into()?,
159 )
160 }))
161 }
162
163 #[must_use]
165 #[doc(alias = "numDVLE")]
166 pub fn len(&self) -> usize {
167 unsafe { (*self.0).numDVLE as usize }
168 }
169
170 #[must_use]
172 pub fn is_empty(&self) -> bool {
173 self.len() == 0
174 }
175
176 #[must_use]
178 pub fn get(&self, index: usize) -> Option<Entrypoint<'_>> {
179 if index < self.len() {
180 Some(Entrypoint {
181 ptr: unsafe { (*self.0).DVLE.add(index) },
182 _library: self,
183 })
184 } else {
185 None
186 }
187 }
188
189 fn as_raw(&mut self) -> *mut ctru_sys::DVLB_s {
190 self.0
191 }
192}
193
194impl Drop for Library {
195 #[doc(alias = "DVLB_Free")]
196 fn drop(&mut self) {
197 unsafe {
198 ctru_sys::DVLB_Free(self.as_raw());
199 }
200 }
201}
202
203#[derive(Clone, Copy)]
206pub struct Entrypoint<'lib> {
207 ptr: *mut ctru_sys::DVLE_s,
208 _library: &'lib Library,
209}
210
211impl<'lib> Entrypoint<'lib> {
212 fn as_raw(self) -> *mut ctru_sys::DVLE_s {
213 self.ptr
214 }
215}