tiny_game_framework/graphics/
shader.rs

1use gl::*;
2use gl::types::*;
3use glam::{Mat4, Vec3};
4
5use std::ptr;
6use std::ffi::{CStr, CString};
7
8#[derive(Debug, Eq, PartialEq, Copy, Clone)]
9pub struct Shader {
10    pub id: u32,
11}
12
13impl Shader {
14    pub fn new(shader_type: GLenum, code: &str) -> Self {
15        unsafe {
16            let shader = CreateShader(shader_type);
17            let cstr = std::ffi::CString::new(code.as_bytes()).unwrap();
18            ShaderSource(shader, 1, &cstr.as_ptr(), std::ptr::null());
19            CompileShader(shader);
20            check_shader_error(shader);
21
22            let id = CreateProgram();
23            AttachShader(id, shader);
24            LinkProgram(id);
25            check_shader_link_error(id);
26
27            DeleteShader(shader);
28
29            Self { id }
30        }
31    }
32    
33    pub fn new_pipeline(vs_code: &str, fs_code: &str) -> Self {
34        unsafe {
35            let vs = CreateShader(VERTEX_SHADER);
36            let cstr = std::ffi::CString::new(vs_code.as_bytes()).unwrap();
37            ShaderSource(vs, 1, &cstr.as_ptr(), std::ptr::null());
38            CompileShader(vs);
39            check_shader_error(vs);
40
41            let fs = CreateShader(FRAGMENT_SHADER);
42            let cstr = std::ffi::CString::new(fs_code.as_bytes()).unwrap();
43            ShaderSource(fs, 1, &cstr.as_ptr(), std::ptr::null());
44            CompileShader(fs);
45            check_shader_error(fs);
46
47            let id = CreateProgram();
48            AttachShader(id, vs);
49            AttachShader(id, fs);
50            LinkProgram(id);
51            check_shader_link_error(id);
52
53            Self { id }
54        }
55    }
56
57    pub unsafe fn use_shader(&self) {
58        UseProgram(self.id);
59    }
60
61    pub unsafe fn stop_shader(&self) {
62
63    }
64
65    pub unsafe fn uniform_1f(&self, name: &CStr, val: f32) {
66        Uniform1f(GetUniformLocation(self.id, name.as_ptr()), val);
67    }
68    pub unsafe fn uniform_1i(&self, name: &CStr, val: i32) {
69        Uniform1i(
70            GetUniformLocation(self.id, name.as_ptr()), val);
71    }
72
73    pub unsafe fn uniform_mat4fv(&self, name: &CStr, mat: &[f32; 16]) {
74        UniformMatrix4fv(
75            GetUniformLocation(self.id, name.as_ptr()), 
76            1, 
77            FALSE, 
78            mat as *const f32
79        );
80    }
81
82    pub unsafe fn uniform_vec3f(&self, name: &CStr, vec: &Vec3) {
83        Uniform3f(
84            GetUniformLocation(self.id, name.as_ptr()),
85            vec.x, vec.y, vec.z
86        );
87    }
88}
89
90pub unsafe fn check_shader_error(shader: u32) {
91    let mut success = gl::FALSE as GLint;
92    let mut info_log = Vec::with_capacity(512);
93    info_log.set_len(54); // skip the trailing null char
94    GetShaderiv(shader, COMPILE_STATUS, &mut success);
95    if success != gl::TRUE as GLint {
96        GetShaderInfoLog(
97            shader,
98            512,
99            ptr::null_mut(),
100            info_log.as_mut_ptr() as *mut GLchar,
101        );
102        println!(
103            "ERROR::SHADER::COMPILATION::FAILED\n{}",
104            std::str::from_utf8(&info_log).unwrap()
105        );
106    }
107}
108
109pub unsafe fn check_shader_link_error(program: u32) {
110    let mut success = gl::FALSE as GLint;
111    let mut info_log = Vec::with_capacity(512);
112    gl::GetProgramiv(program, gl::LINK_STATUS, &mut success);
113    if success != gl::TRUE as GLint {
114        gl::GetProgramInfoLog(
115            program,
116            512,
117            ptr::null_mut(),
118            info_log.as_mut_ptr() as *mut GLchar,
119        );
120        println!(
121            "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n{}",
122            std::str::from_utf8(&info_log).unwrap()
123        );
124    }
125}
126
127#[macro_export]
128macro_rules! cstr {
129    ($s:expr) => {
130        CString::new($s).expect("CString conversion failed")
131            .as_c_str()
132    };
133}