rust_raylib/
shader.rs

1use crate::{
2    ffi,
3    math::{Matrix, Vector2, Vector3, Vector4},
4    texture::Texture2D,
5};
6use std::ffi::CString;
7
8pub use crate::ffi::{ShaderAttributeDataType, ShaderLocationIndex, ShaderUniformDataType};
9
10/// Shader
11#[derive(Debug)]
12#[repr(transparent)]
13pub struct Shader {
14    pub(crate) raw: ffi::Shader,
15}
16
17impl Shader {
18    /// Shader locations array
19    #[inline]
20    pub fn locations(&self) -> &[u32] {
21        unsafe {
22            std::slice::from_raw_parts(self.raw.locs as *const u32, ffi::MAX_SHADER_LOCATIONS)
23        }
24    }
25
26    /// Shader locations array
27    #[inline]
28    pub fn locations_mut(&mut self) -> &mut [u32] {
29        unsafe {
30            std::slice::from_raw_parts_mut(self.raw.locs as *mut _, ffi::MAX_SHADER_LOCATIONS)
31        }
32    }
33
34    /// Load shader from files and bind default locations
35    #[inline]
36    pub fn from_file(vs_filename: Option<&str>, fs_filename: Option<&str>) -> Option<Self> {
37        let vs_filename = vs_filename.map(|s| CString::new(s).unwrap());
38        let fs_filename = fs_filename.map(|s| CString::new(s).unwrap());
39
40        let raw = unsafe {
41            ffi::LoadShader(
42                match vs_filename {
43                    Some(vs) => vs.as_ptr(),
44                    None => std::ptr::null(),
45                },
46                match fs_filename {
47                    Some(fs) => fs.as_ptr(),
48                    None => std::ptr::null(),
49                },
50            )
51        };
52
53        if unsafe { ffi::IsShaderReady(raw.clone()) } {
54            Some(Self { raw })
55        } else {
56            None
57        }
58    }
59
60    /// Load shader from code strings and bind default locations
61    #[inline]
62    pub fn from_memory(vs_code: Option<&str>, fs_code: Option<&str>) -> Option<Self> {
63        let vs_code = vs_code.map(|s| CString::new(s).unwrap());
64        let fs_code = fs_code.map(|s| CString::new(s).unwrap());
65
66        let raw = unsafe {
67            ffi::LoadShaderFromMemory(
68                match vs_code {
69                    Some(vs) => vs.as_ptr(),
70                    None => std::ptr::null(),
71                },
72                match fs_code {
73                    Some(fs) => fs.as_ptr(),
74                    None => std::ptr::null(),
75                },
76            )
77        };
78
79        if unsafe { ffi::IsShaderReady(raw.clone()) } {
80            Some(Self { raw })
81        } else {
82            None
83        }
84    }
85
86    /// Get shader uniform location
87    #[inline]
88    pub fn get_location(&self, uniform_name: &str) -> u32 {
89        let uniform_name = CString::new(uniform_name).unwrap();
90
91        unsafe { ffi::GetShaderLocation(self.raw.clone(), uniform_name.as_ptr()) as _ }
92    }
93
94    /// Get shader attribute location
95    #[inline]
96    pub fn get_location_attribute(&self, attribute_name: &str) -> u32 {
97        let attribute_name = CString::new(attribute_name).unwrap();
98
99        unsafe { ffi::GetShaderLocationAttrib(self.raw.clone(), attribute_name.as_ptr()) as _ }
100    }
101
102    /// Set shader uniform value
103    #[inline]
104    pub fn set_value<S: ShaderValue>(&mut self, loc_index: u32, value: S) {
105        unsafe {
106            ffi::SetShaderValue(
107                self.raw.clone(),
108                loc_index as _,
109                value.raw_value(),
110                S::UNIFORM_TYPE as _,
111            )
112        }
113    }
114
115    /// Set shader uniform value vector
116    #[inline]
117    pub fn set_value_vec<S: ShaderValue>(&mut self, loc_index: u32, values: &[S]) {
118        unsafe {
119            ffi::SetShaderValueV(
120                self.raw.clone(),
121                loc_index as _,
122                values.as_ptr() as *const _,
123                S::UNIFORM_TYPE as _,
124                values.len() as _,
125            )
126        }
127    }
128
129    /// Set shader uniform value (matrix 4x4)
130    #[inline]
131    pub fn set_value_matrix(&mut self, loc_index: u32, mat: Matrix) {
132        unsafe { ffi::SetShaderValueMatrix(self.raw.clone(), loc_index as _, mat.into()) }
133    }
134
135    /// Set shader uniform value for texture (sampler2d)
136    #[inline]
137    pub fn set_value_texture(&mut self, loc_index: u32, texture: &Texture2D) {
138        unsafe { ffi::SetShaderValueTexture(self.raw.clone(), loc_index as _, texture.raw.clone()) }
139    }
140
141    /// Get the 'raw' ffi type
142    /// Take caution when cloning so it doesn't outlive the original
143    #[inline]
144    pub fn as_raw(&self) -> &ffi::Shader {
145        &self.raw
146    }
147
148    /// Get the 'raw' ffi type
149    /// Take caution when cloning so it doesn't outlive the original
150    #[inline]
151    pub fn as_raw_mut(&mut self) -> &mut ffi::Shader {
152        &mut self.raw
153    }
154
155    /// Convert a 'raw' ffi object to a safe wrapper
156    ///
157    /// # Safety
158    /// * The raw object must be correctly initialized
159    /// * The raw object should be unique. Otherwise, make sure its clones don't outlive the newly created object.
160    #[inline]
161    pub unsafe fn from_raw(raw: ffi::Shader) -> Self {
162        Self { raw }
163    }
164}
165
166impl Drop for Shader {
167    #[inline]
168    fn drop(&mut self) {
169        unsafe { ffi::UnloadShader(self.raw.clone()) }
170    }
171}
172
173/// Shader uniform value
174/// You shouldn't need to implement this trait yourself.
175pub trait ShaderValue
176where
177    Self: Sized,
178{
179    /// Uniform type assiciated with the value
180    const UNIFORM_TYPE: ShaderUniformDataType;
181
182    /// Get the value as a `void*`
183    unsafe fn raw_value(&self) -> *const core::ffi::c_void {
184        self as *const Self as *const _
185    }
186}
187
188impl ShaderValue for f32 {
189    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::Float;
190}
191
192impl ShaderValue for Vector2 {
193    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::Vec2;
194}
195
196impl ShaderValue for Vector3 {
197    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::Vec3;
198}
199
200impl ShaderValue for Vector4 {
201    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::Vec4;
202}
203
204impl ShaderValue for i32 {
205    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::Int;
206}
207
208impl ShaderValue for mint::Vector2<i32> {
209    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::IVec2;
210}
211
212impl ShaderValue for mint::Vector3<i32> {
213    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::IVec3;
214}
215
216impl ShaderValue for mint::Vector4<i32> {
217    const UNIFORM_TYPE: ShaderUniformDataType = ShaderUniformDataType::IVec4;
218}