ruckus/
opengl.rs

1
2use crate::buffers::VertexAttribute;
3use crate::buffers::VertexBuffer;
4use crate::buffers::DrawPrimitive;
5use std::ffi::CStr;
6use std::collections::HashMap;
7use crate::sys::read_file;
8use crate::graphics::{ShaderType};
9
10pub mod gl {
11    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
12}
13
14static mut GL_CONTEXT: Option<gl::Gl> = None;
15
16pub fn load_opengl<F>(loader: F) where F: FnMut(&'static str)  -> *const std::ffi::c_void {
17
18    let gl = gl::Gl::load_with(loader);
19
20    let version = unsafe {
21        let data = CStr::from_ptr(gl.GetString(gl::VERSION) as *const _)
22            .to_bytes()
23            .to_vec();
24        String::from_utf8(data).unwrap()
25    };
26
27    println!("OpenGL version {}", version);
28
29    unsafe {
30        GL_CONTEXT = Some(gl);
31    }
32}
33
34pub fn opengl() -> &'static gl::Gl {
35    unsafe {
36        GL_CONTEXT.as_ref().expect("Initialize OpenGL with load_opengl() before using any OpenGL draw calls)")
37    }
38}
39
40#[allow(dead_code)]
41pub(crate) fn gl_bind_vertex_array(id: u32) {
42    unsafe { opengl().BindVertexArray(id) };
43}
44
45#[allow(dead_code)]
46pub(crate) fn gl_bind_array_buffer(id: u32) {
47    unsafe { opengl().BindBuffer(gl::ARRAY_BUFFER, id) }
48}
49
50#[allow(dead_code)]
51pub(crate) fn gl_gen_vertex_array() -> u32 {
52    unsafe {
53        let mut id = std::mem::zeroed();
54        opengl().GenVertexArrays(1, &mut id);
55        id
56    }
57}
58
59#[allow(dead_code)]
60pub(crate) fn gl_gen_buffer() -> u32 {
61    let mut id = unsafe { std::mem::zeroed() };
62    unsafe { opengl().GenBuffers(1, &mut id) };
63    id
64}
65
66#[allow(dead_code)]
67pub(crate) fn gl_delete_buffer(id: u32) {
68    unsafe {
69        opengl().DeleteBuffers(1, &id);
70    }
71}
72
73#[allow(dead_code)]
74pub(crate) fn gl_gen_texture() -> u32 {
75    let mut id = unsafe { std::mem::zeroed() };
76    unsafe { opengl().GenTextures(1, &mut id) };
77    id
78}
79
80#[allow(dead_code)]
81pub(crate) fn gl_get_uniform_location(shader_id: u32, name: &str) -> i32 {
82    unsafe { opengl().GetUniformLocation(shader_id, name.as_ptr() as *const _) }
83}
84
85#[allow(dead_code)]
86pub(crate) fn gl_set_uniform_4f(location: i32, floats: (f32, f32, f32, f32)) {
87    unsafe { opengl().Uniform4f(location, floats.0, floats.1, floats.2, floats.3) }
88}
89
90#[allow(dead_code)]
91pub(crate) fn gl_set_uniform_3f(location: i32, floats: (f32, f32, f32)) {
92    unsafe { opengl().Uniform3f(location, floats.0, floats.1, floats.2) }
93}
94
95#[allow(dead_code)]
96pub(crate) fn gl_set_uniform_2f(location: i32, floats: (f32, f32)) {
97    unsafe { opengl().Uniform2f(location, floats.0, floats.1) }
98}
99
100#[allow(dead_code)]
101pub(crate) fn gl_set_uniform_f(location: i32, n: f32) {
102    unsafe { opengl().Uniform1f(location, n) }
103}
104#[allow(dead_code)]
105pub(crate) fn gl_set_uniform_matrix(location: i32, mat: &[f32]) {
106    gl_set_uniform_matrix_xpose(location, mat, false)
107}
108
109#[allow(dead_code)]
110pub(crate) fn gl_set_uniform_matrix_xpose(location: i32, mat: &[f32], transpose: bool) {
111    unsafe { opengl().UniformMatrix4fv(location, 1, transpose as u8, mat.as_ptr()) }
112}
113
114#[allow(dead_code)]
115pub(crate) fn gl_set_uniform_i(location: i32, n: i32) {
116    unsafe { opengl().Uniform1i(location, n) }
117}
118
119#[allow(dead_code)]
120pub(crate) fn gl_compile_shader_from_file(path: &str, shader_type: ShaderType) -> Result<u32, String> {
121    let shader_source = match read_file(path) {
122        Ok(s) => s,
123        Err(e) => return Err(format!("FILE READ ERROR :: {}", e))
124    };
125    gl_compile_shader(shader_source.as_bytes(), shader_type)
126}
127
128#[allow(dead_code)]
129pub fn gl_draw_arrays(start: u32, vert_count: u32, prim: DrawPrimitive) {
130    unsafe { opengl().DrawArrays(prim as u32, start as i32, vert_count as i32) }
131}
132
133#[allow(dead_code)]
134pub fn gl_draw_elements(count: u32, prim: DrawPrimitive) {
135    unsafe { opengl().DrawElements(prim as u32, count as i32, gl::UNSIGNED_INT, 0 as *const _) }
136}
137
138#[allow(dead_code)]
139const GL_MAX_LOG_BUFFER_LENGTH: usize = 2564;
140
141#[allow(dead_code)]
142// TODO :: Consolidate all default shaders (except instanced, do those too but separate) into a single shader with #ifdef to make
143//         everything more clean and DRY
144pub(crate) fn gl_compile_shader(source: &[u8], stype: ShaderType) -> Result<u32, String> {
145    let gl = opengl();
146    let sid = unsafe { gl.CreateShader(stype as u32) };
147    unsafe {
148        let source = vec![source.as_ptr() as *const _];
149        gl.ShaderSource(sid, 1, source.as_ptr() as *const _, 0 as *const _);
150        gl.CompileShader(sid);
151
152        let mut success = std::mem::zeroed();
153        gl.GetShaderiv(sid, gl::COMPILE_STATUS, &mut success);
154
155        if success == 0 {
156
157            let mut info_log = [0; GL_MAX_LOG_BUFFER_LENGTH];
158            gl.GetShaderInfoLog(sid, GL_MAX_LOG_BUFFER_LENGTH as i32, 0 as *mut _, info_log.as_mut_ptr() as *mut _);
159        
160            let cerror = std::ffi::CStr::from_ptr(info_log.as_ptr()).to_str().unwrap();
161            let shader_error = String::from(cerror);
162            gl.DeleteShader(sid);
163            return Err(format!("SHADER COMPILE ERROR\n\r--------------------\n\r{}", shader_error))
164        }
165    };        
166    Ok(sid)
167}
168
169#[allow(dead_code)]
170pub(crate) fn gl_create_shader_program(vert_id: u32, frag_id: u32) -> Result<u32, String> {
171    unsafe {
172        let gl = opengl();
173        let id = gl.CreateProgram();
174
175        gl.AttachShader(id, vert_id);
176        gl.AttachShader(id, frag_id);
177        gl.LinkProgram(id);
178
179        let mut success = std::mem::zeroed();
180        gl.GetProgramiv(id, gl::LINK_STATUS, &mut success);
181
182        if success == 0 {
183            
184            let mut info_log = [0; GL_MAX_LOG_BUFFER_LENGTH];
185            
186            gl.GetProgramInfoLog(id, info_log.len() as i32, 0 as *mut _, info_log.as_mut_ptr() as *mut _);
187
188            let cerror = std::ffi::CStr::from_ptr(info_log.as_ptr()).to_str().unwrap();
189            let shader_error = String::from(cerror);   
190
191            gl.DeleteProgram(id);
192            return Err(format!("SHADER PROGRAM LINK ERROR\n\r-------------------\n\r{}", shader_error));
193        }
194
195        gl.DeleteShader(vert_id);
196        gl.DeleteShader(frag_id);
197
198        Ok(id)
199    }
200}
201
202
203#[allow(dead_code)]
204pub(crate) fn gl_get_active_uniforms(shader_id: u32) -> HashMap<String, i32> {
205    let gl = opengl();
206    let count = unsafe {
207        let mut count = std::mem::zeroed();
208        gl.GetProgramiv(shader_id, gl::ACTIVE_UNIFORMS, &mut count);
209        count
210    };
211
212    let mut result = HashMap::new();
213
214    for i in 0..count {
215        const NAME_SIZE: usize = 32;
216        unsafe {
217            let mut length = std::mem::zeroed();
218            let mut size = std::mem::zeroed();
219            let mut dtype = std::mem::zeroed();
220            let mut name = vec![0; NAME_SIZE];
221            gl.GetActiveUniform(shader_id, i as u32, NAME_SIZE as i32, &mut length, &mut size, &mut dtype, name.as_mut_ptr() as *mut _);   
222
223            let name = unsafe { std::ffi::CStr::from_ptr(name.as_ptr()).to_str().unwrap() };
224            let k = String::from(name);
225
226            let v = gl_get_uniform_location(shader_id, &k);
227            let _ = result.insert(k, v);
228        }
229    }
230    result
231}
232
233#[allow(dead_code)]
234pub(crate) fn set_vertex_layout(buffer: &VertexBuffer, attribs: &[VertexAttribute]) {
235    buffer.apply();
236
237    for attr in attribs.iter() {
238        unsafe {
239            let gl = opengl();
240            gl.VertexAttribPointer(attr.buffer_index, attr.elem_count as i32, attr.dtype as u32, gl::FALSE, attr.stride as i32, attr.offset as *const _);
241            gl.EnableVertexAttribArray(attr.buffer_index);
242            gl.VertexAttribDivisor(attr.buffer_index, if attr.is_instanced { 1 } else { 0 })
243        }
244    }
245}
246
247
248#[allow(dead_code)]
249pub(crate) fn gl_unbind_element_buffer() {
250    unsafe { opengl().BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0) }
251}
252
253#[allow(dead_code)]
254pub(crate) fn gl_unbind_array_buffer() {
255    unsafe { opengl().BindBuffer(gl::ARRAY_BUFFER, 0) }
256}