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#[derive(Debug)]
12#[repr(transparent)]
13pub struct Shader {
14 pub(crate) raw: ffi::Shader,
15}
16
17impl Shader {
18 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline]
144 pub fn as_raw(&self) -> &ffi::Shader {
145 &self.raw
146 }
147
148 #[inline]
151 pub fn as_raw_mut(&mut self) -> &mut ffi::Shader {
152 &mut self.raw
153 }
154
155 #[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
173pub trait ShaderValue
176where
177 Self: Sized,
178{
179 const UNIFORM_TYPE: ShaderUniformDataType;
181
182 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}