tiny_game_framework/graphics/
shader.rs1use 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); 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}