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)]
142pub(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}