ssb_renderer/gl_utils/
safe.rs

1// Imports
2use std::ffi::{CStr, CString};
3use std::os::raw::{c_char};
4use std::ptr::{null, null_mut};
5use std::mem::size_of;
6use super::error::GlError;
7
8// Helper macro
9macro_rules! check_loaded {
10    ($name:ident, $body:expr) => {
11        if gl32::$name::is_loaded() {
12            $body
13        } else {
14            panic!("{} not loaded!", stringify!($name));
15        }
16    }
17}
18
19
20// FUNCTIONS
21// GetString
22#[allow(non_snake_case)]
23pub fn GetString(name: gl32::types::GLenum) -> String {
24    check_loaded!(
25        GetString,
26        unsafe {
27            CStr::from_ptr(gl32::GetString(name) as *const c_char).to_string_lossy().to_string()
28        }
29    )
30}
31
32// GetError
33#[allow(non_snake_case)]
34pub fn GetError() -> gl32::types::GLenum {
35    check_loaded!(
36        GetError,
37        unsafe {
38            gl32::GetError()
39        }
40    )
41}
42
43// ClearColor
44#[allow(non_snake_case)]
45pub fn ClearColor(red: f32, green: f32, blue: f32, alpha: f32) {
46    check_loaded!(
47        ClearColor,
48        unsafe {
49            gl32::ClearColor(red, green, blue, alpha);
50        }
51    );
52}
53
54// Clear
55#[allow(non_snake_case)]
56pub fn Clear(mask: gl32::types::GLenum) {
57    check_loaded!(
58        Clear,
59        unsafe {
60            gl32::Clear(mask);
61        }
62    );
63}
64
65// Viewport
66#[allow(non_snake_case)]
67pub fn Viewport(x: u16, y: u16, width: u16, height: u16) {
68    check_loaded!(
69        Viewport,
70        unsafe {
71            gl32::Viewport(
72                x as gl32::types::GLint, y as gl32::types::GLint,
73                width as gl32::types::GLsizei, height as gl32::types::GLsizei
74            );
75        }
76    );
77}
78
79// Enable / Disable
80#[allow(non_snake_case)]
81pub fn Enable(cap: gl32::types::GLenum) {
82    check_loaded!(
83        Enable,
84        unsafe {
85            gl32::Enable(cap);
86        }
87    );
88}
89#[allow(non_snake_case)]
90pub fn Disable(cap: gl32::types::GLenum) {
91    check_loaded!(
92        Disable,
93        unsafe {
94            gl32::Disable(cap);
95        }
96    );
97}
98
99// Blending
100#[allow(non_snake_case)]
101pub fn BlendFunc(sfactor: gl32::types::GLenum, dfactor: gl32::types::GLenum) {
102    check_loaded!(
103        BlendFunc,
104        unsafe {
105            gl32::BlendFunc(sfactor, dfactor);
106        }
107    );
108}
109#[allow(non_snake_case)]
110pub fn BlendFuncSeparate(srcRGB: gl32::types::GLenum, dstRGB: gl32::types::GLenum, srcAlpha: gl32::types::GLenum, dstAlpha: gl32::types::GLenum) {
111    check_loaded!(
112        BlendFuncSeparate,
113        unsafe {
114            gl32::BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
115        }
116    );
117}
118#[allow(non_snake_case)]
119pub fn BlendEquation(mode: gl32::types::GLenum) {
120    check_loaded!(
121        BlendEquation,
122        unsafe {
123            gl32::BlendEquation(mode);
124        }
125    );
126}
127
128
129// OBJECTS
130// Framebuffer
131pub struct Framebuffer {
132    id: gl32::types::GLuint
133}
134impl Framebuffer {
135    // New
136    pub fn generate() -> Self {
137        check_loaded!(
138            GenFramebuffers,
139            {
140                let mut id: gl32::types::GLuint = 0;
141                unsafe {
142                    gl32::GenFramebuffers(1, &mut id);
143                }
144                Self{
145                    id
146                }
147            }
148        )
149    }
150    // Bind
151    pub fn bind(&self) {
152        check_loaded!(
153            BindFramebuffer,
154            unsafe {
155                gl32::BindFramebuffer(gl32::FRAMEBUFFER, self.id);
156            }
157        );
158    }
159    pub fn bind_target(&self, target: gl32::types::GLenum) {
160        check_loaded!(
161            BindFramebuffer,
162            unsafe {
163                gl32::BindFramebuffer(target, self.id);
164            }
165        );
166    }
167    pub fn unbind() {
168        check_loaded!(
169            BindFramebuffer,
170            unsafe {
171                gl32::BindFramebuffer(gl32::FRAMEBUFFER, 0);
172            }
173        );
174    }
175    // Check complete status
176    pub fn status() -> gl32::types::GLenum {
177        check_loaded!(
178            CheckFramebufferStatus,
179            unsafe {
180                gl32::CheckFramebufferStatus(gl32::FRAMEBUFFER)
181            }
182        )
183    }
184    // Link
185    pub fn texture_2d(attachment: gl32::types::GLenum, texture: &Texture2D) {
186        check_loaded!(
187            FramebufferTexture2D,
188            unsafe {
189                gl32::FramebufferTexture2D(gl32::FRAMEBUFFER, attachment, gl32::TEXTURE_2D, texture.id, 0);
190            }
191        );
192    }
193    pub fn renderbuffer(attachment: gl32::types::GLenum, renderbuffer: &Renderbuffer) {
194        check_loaded!(
195            FramebufferRenderbuffer,
196            unsafe {
197                gl32::FramebufferRenderbuffer(gl32::FRAMEBUFFER, attachment, gl32::RENDERBUFFER, renderbuffer.id);
198            }
199        );
200    }
201    // Blit
202    pub fn blit(src_x0: i32, src_y0: i32, src_x1: i32, src_y1: i32,
203        dst_x0: i32, dst_y0: i32, dst_x1: i32, dst_y1: i32,
204        mask: gl32::types::GLbitfield, filter: gl32::types::GLenum) {
205        check_loaded!(
206            BlitFramebuffer,
207            unsafe {
208                gl32::BlitFramebuffer(
209                    src_x0, src_y0, src_x1, src_y1,
210                    dst_x0, dst_y0, dst_x1, dst_y1,
211                    mask, filter
212                );
213            }
214        );
215    }
216}
217impl Drop for Framebuffer {
218    // Delete
219    fn drop(&mut self) {
220        check_loaded!(
221            DeleteFramebuffers,
222            unsafe {
223                gl32::DeleteFramebuffers(1, &self.id);
224            }
225        );
226    }
227}
228
229// Texture (2D)
230pub struct Texture2D {
231    id: gl32::types::GLuint
232}
233impl Texture2D {
234    // New
235    pub fn generate() -> Self {
236        check_loaded!(
237            GenTextures,
238            {
239                let mut id: gl32::types::GLuint = 0;
240                unsafe {
241                    gl32::GenTextures(1, &mut id);
242                }
243                Self{
244                    id
245                }
246            }
247        )
248    }
249    // Bind
250    pub fn bind(&self) {
251        check_loaded!(
252            BindTexture,
253            unsafe {
254                gl32::BindTexture(gl32::TEXTURE_2D, self.id);
255            }
256        );
257    }
258    pub fn unbind() {
259        check_loaded!(
260            BindTexture,
261            unsafe {
262                gl32::BindTexture(gl32::TEXTURE_2D, 0);
263            }
264        );
265    }
266    // Memory
267    pub fn tex_image_2d(internalformat: gl32::types::GLenum, width: u16, height: u16, data_format: gl32::types::GLenum, data_type: gl32::types::GLenum, data: Option<&[u8]>) {
268        check_loaded!(
269            TexImage2D,
270            unsafe {
271                gl32::TexImage2D(
272                    gl32::TEXTURE_2D, 0, internalformat as gl32::types::GLint,
273                    width as gl32::types::GLsizei, height as gl32::types::GLsizei, 0,
274                    data_format, data_type, data.map_or(null(), |bytes| bytes.as_ptr() as *const _)
275                );
276            }
277        );
278    }
279    pub fn tex_sub_image_2d(xoffset: i16, yoffset: i16, width: u16, height: u16, data_format: gl32::types::GLenum, data_type: gl32::types::GLenum, data: &[u8]) {
280        check_loaded!(
281            TexSubImage2D,
282            unsafe {
283                gl32::TexSubImage2D(
284                    gl32::TEXTURE_2D, 0,
285                    xoffset as gl32::types::GLint, yoffset as gl32::types::GLint, width as gl32::types::GLsizei, height as gl32::types::GLsizei,
286                    data_format, data_type, data.as_ptr() as *const _
287                );
288            }
289        );
290    }
291    pub fn get_tex_image(data_format: gl32::types::GLenum, data_type: gl32::types::GLenum, data: &mut [u8]) {
292        check_loaded!(
293            GetTexImage,
294            unsafe {
295                gl32::GetTexImage(gl32::TEXTURE_2D, 0, data_format, data_type, data.as_ptr() as *mut _);
296            }
297        );
298    }
299}
300impl Drop for Texture2D {
301    // Delete
302    fn drop(&mut self) {
303        check_loaded!(
304            DeleteTextures,
305            unsafe {
306                gl32::DeleteTextures(1, &self.id);
307            }
308        );
309    }
310}
311
312// Renderbuffer (with multisampling)
313pub struct Renderbuffer {
314    id: gl32::types::GLuint
315}
316impl Renderbuffer {
317    // New
318    pub fn generate() -> Self {
319        check_loaded!(
320            GenRenderbuffers,
321            {
322                let mut id: gl32::types::GLuint = 0;
323                unsafe {
324                    gl32::GenRenderbuffers(1, &mut id);
325                }
326                Self{
327                    id
328                }
329            }
330        )
331    }
332    // Bind
333    pub fn bind(&self) {
334        check_loaded!(
335            BindRenderbuffer,
336            unsafe {
337                gl32::BindRenderbuffer(gl32::RENDERBUFFER, self.id);
338            }
339        );
340    }
341    pub fn unbind() {
342        check_loaded!(
343            BindRenderbuffer,
344            unsafe {
345                gl32::BindRenderbuffer(gl32::RENDERBUFFER, 0);
346            }
347        );
348    }
349    // Memory
350    pub fn storage_multisample(samples: u8, internalformat: gl32::types::GLenum, width: u16, height: u16) {
351        check_loaded!(
352            RenderbufferStorageMultisample,
353            unsafe {
354                gl32::RenderbufferStorageMultisample(
355                    gl32::RENDERBUFFER, samples as gl32::types::GLsizei, internalformat,
356                    width as gl32::types::GLsizei, height as gl32::types::GLsizei
357                );
358            }
359        );
360    }
361}
362impl Drop for Renderbuffer {
363    // Delete
364    fn drop(&mut self) {
365        check_loaded!(
366            DeleteRenderbuffers,
367            unsafe {
368                gl32::DeleteRenderbuffers(1, &self.id);
369            }
370        );
371    }
372}
373
374// VBO (Vertex buffer object)
375pub struct VBO {
376    id: gl32::types::GLuint
377}
378impl VBO {
379    // New
380    pub fn generate() -> Self {
381        check_loaded!(
382            GenBuffers,
383            {
384                let mut id: gl32::types::GLuint = 0;
385                unsafe {
386                    gl32::GenBuffers(1, &mut id);
387                }
388                Self{
389                    id
390                }
391            }
392        )
393    }
394    // Bind
395    pub fn bind(&self) {
396        check_loaded!(
397            BindBuffer,
398            unsafe {
399                gl32::BindBuffer(gl32::ARRAY_BUFFER, self.id);
400            }
401        );
402    }
403    pub fn unbind() {
404        check_loaded!(
405            BindBuffer,
406            unsafe {
407                gl32::BindBuffer(gl32::ARRAY_BUFFER, 0);
408            }
409        );
410    }
411    // Memory
412    pub fn data(data: &[f32]) {
413        check_loaded!(
414            BufferData,
415            unsafe {
416                gl32::BufferData(gl32::ARRAY_BUFFER, (data.len() * size_of::<f32>()) as gl32::types::GLsizeiptr, data.as_ptr() as *const _, gl32::STATIC_DRAW);
417            }
418        );
419    }
420    // Attributes
421    pub fn enable_attrib_array(index: u32) {
422        check_loaded!(
423            EnableVertexAttribArray,
424            unsafe {
425                gl32::EnableVertexAttribArray(index);
426            }
427        );
428    }
429    pub fn disable_attrib_array(index: u32) {
430        check_loaded!(
431            DisableVertexAttribArray,
432            unsafe {
433                gl32::DisableVertexAttribArray(index);
434            }
435        );
436    }
437    pub fn attrib_pointer(index: u32, size: i32, stride: i32, offset: isize) {
438        check_loaded!(
439            VertexAttribPointer,
440            unsafe {
441                gl32::VertexAttribPointer(
442                    index, size, gl32::FLOAT, gl32::FALSE,
443                    stride * size_of::<f32>() as i32, (offset * size_of::<f32>() as isize) as *const _
444                );
445            }
446        );
447    }
448    // Draw
449    pub fn draw_arrays(mode: gl32::types::GLenum, first: u16, count: u16) {
450        check_loaded!(
451            DrawArrays,
452            unsafe {
453                gl32::DrawArrays(mode, first as gl32::types::GLint, count as gl32::types::GLsizei);
454            }
455        );
456    }
457}
458impl Drop for VBO {
459    // Delete
460    fn drop(&mut self) {
461        check_loaded!(
462            DeleteBuffers,
463            unsafe {
464                gl32::DeleteBuffers(1, &self.id);
465            }
466        );
467    }
468}
469
470// EBO (Element buffer object)
471pub struct EBO {
472    id: gl32::types::GLuint
473}
474impl EBO {
475    // New
476    pub fn generate() -> Self {
477        check_loaded!(
478            GenBuffers,
479            {
480                let mut id: gl32::types::GLuint = 0;
481                unsafe {
482                    gl32::GenBuffers(1, &mut id);
483                }
484                Self{
485                    id
486                }
487            }
488        )
489    }
490    // Bind
491    pub fn bind(&self) {
492        check_loaded!(
493            BindBuffer,
494            unsafe {
495                gl32::BindBuffer(gl32::ELEMENT_ARRAY_BUFFER, self.id);
496            }
497        );
498    }
499    pub fn unbind() {
500        check_loaded!(
501            BindBuffer,
502            unsafe {
503                gl32::BindBuffer(gl32::ELEMENT_ARRAY_BUFFER, 0);
504            }
505        );
506    }
507    // Memory
508    pub fn data(data: &[u32]) {
509        check_loaded!(
510            BufferData,
511            unsafe {
512                gl32::BufferData(gl32::ELEMENT_ARRAY_BUFFER, (data.len() * size_of::<u32>()) as gl32::types::GLsizeiptr, data.as_ptr() as *const _, gl32::STATIC_DRAW);
513            }
514        );
515    }
516    // Draw
517    pub fn draw_elements(mode: gl32::types::GLenum, count: u16) {
518        check_loaded!(
519            DrawElements,
520            unsafe {
521                gl32::DrawElements(mode, count as gl32::types::GLsizei, gl32::UNSIGNED_INT, null() as *const _);
522            }
523        );
524    }
525}
526impl Drop for EBO {
527    // Delete
528    fn drop(&mut self) {
529        check_loaded!(
530            DeleteBuffers,
531            unsafe {
532                gl32::DeleteBuffers(1, &self.id);
533            }
534        );
535    }
536}
537
538// VAO (Vertex array object)
539pub struct VAO {
540    id: gl32::types::GLuint
541}
542impl VAO {
543    // New
544    pub fn generate() -> Self {
545        check_loaded!(
546            GenVertexArrays,
547            {
548                let mut id: gl32::types::GLuint = 0;
549                unsafe {
550                    gl32::GenVertexArrays(1, &mut id);
551                }
552                Self{
553                    id
554                }
555            }
556        )
557    }
558    // Bind
559    pub fn bind(&self) {
560        check_loaded!(
561            BindVertexArray,
562            unsafe {
563                gl32::BindVertexArray(self.id);
564            }
565        );
566    }
567    pub fn unbind() {
568        check_loaded!(
569            BindVertexArray,
570            unsafe {
571                gl32::BindVertexArray(0);
572            }
573        );
574    }
575}
576impl Drop for VAO {
577    // Delete
578    fn drop(&mut self) {
579        check_loaded!(
580            DeleteVertexArrays,
581            unsafe {
582                gl32::DeleteVertexArrays(1, &self.id);
583            }
584        );
585    }
586}
587
588// Shader
589pub struct Shader {
590    id: gl32::types::GLuint
591}
592impl Shader {
593    // New
594    pub fn create(shader_type: gl32::types::GLenum) -> Self {
595        check_loaded!(
596            CreateShader,
597            unsafe {
598                Self {
599                    id: gl32::CreateShader(shader_type)
600                }
601            }
602        )
603    }
604    // Source
605    pub fn source(&self, string: &str) {
606        check_loaded!(
607            ShaderSource,
608            unsafe {
609                let source = CString::new(string).expect("Source string shouldn't contain null bytes!");
610                gl32::ShaderSource(
611                    self.id, 1,
612                    &source.as_ptr() as *const *const gl32::types::GLchar,
613                    null()
614                );
615            }
616        );
617    }
618    pub fn compile(&self) -> Result<(), GlError> {
619        check_loaded!(
620            CompileShader,
621            unsafe {
622                gl32::CompileShader(self.id);
623                let mut success: gl32::types::GLint = 0;
624                gl32::GetShaderiv(self.id, gl32::COMPILE_STATUS, &mut success);
625                if success == 0 {
626                    const BUF_SIZE: gl32::types::GLsizei = 1024;
627                    let mut info_log: [gl32::types::GLchar; BUF_SIZE as usize] = [0; BUF_SIZE as usize];
628                    gl32::GetShaderInfoLog(self.id, BUF_SIZE, null_mut(), info_log.as_mut_ptr());
629                    return Err(GlError::new(
630                        &CStr::from_ptr(info_log.as_ptr()).to_string_lossy().to_string()
631                    ));
632                }
633                Ok(())
634            }
635        )
636    }
637}
638impl Drop for Shader {
639    // Delete
640    fn drop(&mut self) {
641        check_loaded!(
642            DeleteShader,
643            unsafe {
644                gl32::DeleteShader(self.id);
645            }
646        );
647    }
648}
649
650// Program
651pub struct Program {
652    id: gl32::types::GLuint
653}
654impl Program {
655    // New
656    pub fn create() -> Self {
657        check_loaded!(
658            CreateProgram,
659            unsafe {
660                Self {
661                    id: gl32::CreateProgram()
662                }
663            }
664        )
665    }
666    // Attach
667    pub fn attach(&self, shader: &Shader) {
668        check_loaded!(
669            AttachShader,
670            unsafe {
671                gl32::AttachShader(self.id, shader.id);
672            }
673        );
674    }
675    // Link
676    pub fn link(&self) -> Result<(), GlError> {
677        check_loaded!(
678            LinkProgram,
679            unsafe {
680                gl32::LinkProgram(self.id);
681                let mut success: gl32::types::GLint = 0;
682                gl32::GetProgramiv(self.id, gl32::LINK_STATUS, &mut success);
683                if success == 0 {
684                    const BUF_SIZE: gl32::types::GLsizei = 1024;
685                    let mut info_log: [gl32::types::GLchar; BUF_SIZE as usize] = [0; BUF_SIZE as usize];
686                    gl32::GetProgramInfoLog(self.id, BUF_SIZE, null_mut(), info_log.as_mut_ptr());
687                    return Err(GlError::new(
688                        &CStr::from_ptr(info_log.as_ptr()).to_string_lossy().to_string()
689                    ));
690                }
691                Ok(())
692            }
693        )
694    }
695    // Use
696    pub fn using(&self) {
697        check_loaded!(
698            UseProgram,
699            unsafe {
700                gl32::UseProgram(self.id);
701            }
702        );
703    }
704    // Attributes
705    pub fn attrib_location(&self, name: &str) -> gl32::types::GLint {
706        check_loaded!(
707            GetAttribLocation,
708            unsafe {
709                gl32::GetAttribLocation(self.id, CString::new(name).expect("Name string shouldn't contain null bytes!").as_ptr())
710            }
711        )
712    }
713}
714impl Drop for Program {
715    // Delete
716    fn drop(&mut self) {
717        check_loaded!(
718            DeleteProgram,
719            unsafe {
720                gl32::DeleteProgram(self.id);
721            }
722        );
723    }
724}