tea/
glsl.rs

1extern crate gl;
2
3use gl::types::{GLenum, GLint};
4use std::ffi::{CStr, CString};
5use crate::{GlEnum, GlUse, GlUniform, GlslType, GlObject};
6
7#[derive(PartialEq, PartialOrd, Eq, Clone, Copy)]
8pub enum ShaderType {
9    VertexShader,
10    FragmentShader,
11    GeometryShader,
12    ComputeShader,
13}
14
15impl GlEnum for ShaderType {
16    fn to_enum(&self) -> GLenum {
17        match *self {
18            ShaderType::VertexShader => { gl::VERTEX_SHADER },
19            ShaderType::FragmentShader => { gl::FRAGMENT_SHADER },
20            _ => { 0 }
21        }
22    }
23}
24
25pub enum GlslVersion {
26    V1_00,
27    V1_20,
28    V1_30,
29    V1_40,
30    V3_00,
31    V3_30,
32}
33
34#[derive(Default, Debug, PartialEq, PartialOrd, Eq, Clone, Copy)]
35pub enum GlslQualifier {
36    Default,
37    #[default]
38    Const,
39    Input,
40    Output,
41    Uniform
42}
43
44impl ToString for GlslQualifier {
45    fn to_string(&self) -> String {
46        match *self {
47            Self::Default => { return "".to_string() },
48            Self::Const => { return "const".to_string() },
49            Self::Input => { return "in".to_string() },
50            Self::Output => { return "out".to_string() },
51            Self::Uniform => { return "uniform".to_string() }
52        }
53    }
54}
55
56#[derive(Default, Debug, PartialEq, Eq, Clone)]
57pub struct GlslVariable {
58    qualifier: GlslQualifier,
59    type_: String,
60    size: u32,
61    name: String
62}
63
64impl GlslVariable {
65    pub fn new<T: GlslType>(qualifier: GlslQualifier, name: &str) -> GlslVariable {
66        GlslVariable { qualifier, type_: T::to_glsl(), size: 1, name: name.to_string() }
67    }
68
69    pub fn new_const<T: GlslType>(name: &str) -> GlslVariable {
70        GlslVariable::new::<T>(GlslQualifier::Const, name)
71    }
72    
73    pub fn new_input<T: GlslType>(name: &str) -> GlslVariable {
74        GlslVariable::new::<T>(GlslQualifier::Input, name)
75    }
76    
77    pub fn new_output<T: GlslType>(name: &str) -> GlslVariable {
78        GlslVariable::new::<T>(GlslQualifier::Output, name)
79    }
80    
81    pub fn new_uniform<T: GlslType>(name: &str) -> GlslVariable {
82        GlslVariable::new::<T>(GlslQualifier::Uniform, name)
83    }
84
85    pub fn set_size(&mut self, size: u32) {
86        debug_assert_ne!(size, 0);
87        self.size = size;
88    }
89}
90
91impl ToString for GlslVariable {
92    fn to_string(&self) -> String {
93        format!("{} {} {}", self.qualifier.to_string(), self.type_, self.name.to_string())
94    }
95}
96
97#[derive(Default, Debug, Eq, PartialEq, PartialOrd, Ord)]
98pub struct Shader(u32);
99
100#[derive(Default, Debug, PartialEq, Eq)]
101pub struct ShaderBuilder {
102    version: String,
103    precision: String,
104    variables: Vec<GlslVariable>,
105    pre_main: Vec<String>,
106    main: String
107}
108
109#[derive(Default, Debug, Eq, PartialEq, PartialOrd, Ord)]
110pub struct Program(u32);
111
112/******************************
113 * Shader
114 ******************************/
115impl Shader {
116    pub fn new(kind: ShaderType) -> Result<Self, String> {
117        let handle = unsafe { gl::CreateShader(kind.to_enum()) };
118        Ok(Shader(handle))
119    }
120
121    pub fn source(&self, source: Vec<String>) {
122        let v: Vec<CString> = source.iter()
123            .map(|s| CString::new(s.as_str()).unwrap())
124            .collect();
125        let src: Vec<_> = v.iter()
126            .map(|s| s.as_ptr())
127            .collect();
128
129        // println!("{} || {ptr:?} || {:?}", source.len(), source);
130        #[cfg(target_arch="aarch64")]
131        unsafe { gl::ShaderSource(self.0, source.len() as i32, src.as_ptr() as *const *const u8, std::ptr::null()) };
132        #[cfg(not(target_arch="aarch64"))]
133        unsafe { gl::ShaderSource(self.0, source.len() as i32, src.as_ptr() as *const *const i8, std::ptr::null()) };
134    }
135    
136    pub fn compile(&self) -> Result<(), String> {
137        unsafe { gl::CompileShader(self.0) };
138        let mut success = 1;
139        unsafe {
140            gl::GetShaderiv(self.0, gl::COMPILE_STATUS, &mut success);
141        }
142        if success == 0 {
143            let mut len = 0;
144            unsafe { gl::GetShaderiv(self.0, gl::INFO_LOG_LENGTH, &mut len); }
145            let error = create_whitespace_cstring_with_len(len as usize);
146            unsafe {
147                gl::GetShaderInfoLog(
148                    self.0,
149                    len,
150                    std::ptr::null_mut(),
151                    error.as_ptr() as *mut gl::types::GLchar
152                );
153            }
154            return Err(error.to_string_lossy().into_owned());
155        }
156        Ok(())
157    }
158    
159    pub fn from_source(kind: ShaderType, source: &CStr) -> Result<Self, String> {
160        let shader = Self::new(kind).unwrap();
161        unsafe { gl::ShaderSource(shader.get_id(), 1 as i32, &source.as_ptr(), std::ptr::null()) };
162        shader.compile().expect("Failed to compile shader");
163        Ok(shader)
164    }
165
166    // pub fn new(source: &CStr, kind: ShaderType) -> Result<Self, String> {
167    //     let handle = unsafe { gl::CreateShader(kind.to_enum()) };
168    //     unsafe {
169    //         gl::ShaderSource(handle, 1, &source.as_ptr(), std::ptr::null());
170    //         gl::CompileShader(handle);
171    //     }
172        
173    //     Ok(Shader(handle))
174    // }
175}
176
177impl GlObject for Shader {
178    fn get_id(&self) -> u32 {
179        self.0
180    }
181}
182
183impl Drop for Shader {
184    fn drop(&mut self) {
185        unsafe { gl::DeleteShader(self.0) };
186    }
187}
188
189/******************************
190 * Program
191 ******************************/
192
193impl Program {
194
195    pub fn new() -> Result<Self, String> {
196        let handle = unsafe { gl::CreateProgram() };
197        Ok(Program(handle))
198    }
199
200    pub fn attach_shader(&self, shader: &Shader) {
201        unsafe { gl::AttachShader(self.0, shader.get_id()) };
202    }
203
204    pub fn link(&self) -> Result<(), String> {
205        let mut success = 0;
206        unsafe {
207            gl::LinkProgram(self.0);
208            gl::GetProgramiv(self.0, gl::LINK_STATUS, &mut success);
209        }
210        if success == 0 {
211            let mut len: i32 = 0;
212            unsafe { gl::GetProgramiv(self.0, gl::INFO_LOG_LENGTH, &mut len) };
213            let error = create_whitespace_cstring_with_len(len as usize);
214            unsafe {
215                gl::GetProgramInfoLog(
216                    self.0,
217                    len,
218                    std::ptr::null_mut(),
219                    error.as_ptr() as *mut gl::types::GLchar
220                );
221            }
222            return Err(error.to_string_lossy().into_owned());
223        }
224        Ok(())
225    }
226
227    pub fn from_shaders(shaders: &[Shader]) -> Result<Self, String> {
228        let program = Self::new().unwrap();
229        let handle = unsafe { gl::CreateProgram() };
230        for shader in shaders {
231            program.attach_shader(shader);
232            unsafe { gl::AttachShader(handle, shader.get_id()); }
233        }
234        program.link().expect("Failed to link program");
235        Ok(program)
236    }
237
238    pub fn from_source(vert_src: &CStr, frag_src: &CStr) -> Result<Self, String> {
239        let vert_shd = Shader::from_source( ShaderType::VertexShader, vert_src).expect("Failed to create vertex shader");
240        let frag_shd = Shader::from_source( ShaderType::FragmentShader, frag_src).expect("Failed to create fragment shader");
241        let program = Self::new().unwrap();
242        program.attach_shader(&vert_shd);
243        program.attach_shader(&frag_shd);
244        program.link().expect("Failed to link program");
245        Ok(program)
246    }
247
248    pub fn get_attrib_location(&self, name: &str) -> GLint {
249        #[cfg(target_arch="aarch64")]
250        let loc = unsafe { gl::GetAttribLocation(self.0, name.as_ptr() as *const u8) };
251        #[cfg(not(target_arch="aarch64"))]
252        let loc = unsafe { gl::GetAttribLocation(self.0, name.as_ptr() as *const i8) };
253        return loc
254    }
255
256    pub fn get_uniform_location(&self, name: &str) -> GLint {
257        #[cfg(target_arch="aarch64")]
258        unsafe { gl::GetUniformLocation(self.0, name.as_ptr() as *const u8) }
259        #[cfg(not(target_arch="aarch64"))]
260        unsafe { gl::GetUniformLocation(self.0, name.as_ptr() as *const i8) }
261    }
262
263    pub fn send_uniform<T: GlUniform>(&self, location: i32, data: T) {
264        data.send_uniform(location);
265    }
266
267}
268
269impl GlObject for Program {
270    fn get_id(&self) -> u32 { self.0 }
271}
272
273impl GlUse for Program {
274    fn set_used(&self) {
275        unsafe { gl::UseProgram(self.0) };
276    }
277
278    fn set_unused(&self) {
279        unsafe { gl::UseProgram(0) };
280    }
281}
282
283impl Drop for Program {
284    fn drop(&mut self) {
285        unsafe { gl::DeleteProgram(self.0) };
286    }
287}
288
289/******************************
290 * Shader Builder
291 ******************************/
292
293impl ShaderBuilder {
294    pub fn new() -> Self {
295        ShaderBuilder { 
296            version: "#version 140".to_string(),
297            precision: "".to_string(),
298            variables: vec![],
299            pre_main: vec![],
300            main: "".to_string()
301        }
302    }
303
304    pub fn glsl_version(&mut self, version: &str) -> &mut Self {
305        self.version = version.to_string();
306        self
307    }
308
309    pub fn position<T: GlslType>(&mut self) -> &mut Self {
310        self.variables.insert(0, GlslVariable::new_input::<T>( "a_Position"));
311        self
312    }
313
314    pub fn color<T: GlslType>(&mut self) -> &mut Self {
315        self.variables.insert(1, GlslVariable::new_input::<T>("a_Color"));
316        self
317    }
318
319    pub fn texcoord<T: GlslType>(&mut self) -> &mut Self {
320        self.variables.insert(2, GlslVariable::new_input::<T>("a_Texcoord"));
321        self
322    }
323
324    pub fn normal<T: GlslType>(&mut self) -> &mut Self {
325        self.variables.insert(3, GlslVariable::new_input::<T>("a_Normal"));
326        self
327    }
328
329    pub fn add_input<T: GlslType>(&mut self, name: &str) -> &mut Self {
330        self.variables.push(GlslVariable::new_input::<T>(name));
331        self
332    }
333
334    pub fn add_output<T: GlslType>(&mut self, name: &str) -> &mut Self {
335        self.variables.push(GlslVariable::new_output::<T>(name));
336        self
337    }
338
339    pub fn add_uniform<T: GlslType>(&mut self, name: &str) -> &mut Self {
340        self.variables.push(GlslVariable::new_uniform::<T>(name));
341        self
342    }
343
344    pub fn push_pre_main(&mut self, src: &str) -> &mut Self {
345        self.pre_main.push(src.to_string());
346        self
347    }
348
349    pub fn set_main(&mut self, main: &str) -> &mut Self {
350        self.main = main.to_string();
351        self
352    }
353
354    pub fn build(&self, kind: ShaderType) -> Result<Shader, String> {
355        let mut source: Vec<String> = vec![];
356
357        source.push(format!("{}\n", self.version));
358        source.push(format!("{}\n", self.precision));
359        // source.push(self.precision.clone());
360
361        // writeln!(source, "{}", self.version).unwrap();
362        // write!(source, "{}", self.precision).unwrap();
363
364        match kind {
365            ShaderType::VertexShader {} => {},
366            _ => {}
367        }
368
369        for variable in &self.variables {
370            source.push(format!("{};", variable.to_string()));
371            // writeln!(source, "{};", variable.to_string()).unwrap();
372        }
373
374        let src = self.pre_main.clone();
375        source.extend(src);
376
377        source.push(self.main.clone());
378        
379        // write!(source, "{}", self.main).unwrap();
380        // println!("{:?}", source);
381        // let src: &CStr = unsafe { CStr::from_ptr(source.as_ptr() as *const i8) };
382        // Shader::from_source(kind, src)
383        
384        let shader = Shader::new(kind).unwrap();
385        shader.source(source);
386        shader.compile().expect("Failed to compile shader");
387        Ok(shader)
388    }
389}
390
391fn create_whitespace_cstring_with_len(len: usize) -> CString {
392    let mut buffer: Vec<u8> = Vec::with_capacity(len + 1);
393    buffer.extend([b' '].iter().cycle().take(len));
394    unsafe { CString::from_vec_unchecked(buffer) }
395}