1use 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
8macro_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#[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#[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#[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#[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#[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#[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#[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
129pub struct Framebuffer {
132 id: gl32::types::GLuint
133}
134impl Framebuffer {
135 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 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 pub fn status() -> gl32::types::GLenum {
177 check_loaded!(
178 CheckFramebufferStatus,
179 unsafe {
180 gl32::CheckFramebufferStatus(gl32::FRAMEBUFFER)
181 }
182 )
183 }
184 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 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 fn drop(&mut self) {
220 check_loaded!(
221 DeleteFramebuffers,
222 unsafe {
223 gl32::DeleteFramebuffers(1, &self.id);
224 }
225 );
226 }
227}
228
229pub struct Texture2D {
231 id: gl32::types::GLuint
232}
233impl Texture2D {
234 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 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 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 fn drop(&mut self) {
303 check_loaded!(
304 DeleteTextures,
305 unsafe {
306 gl32::DeleteTextures(1, &self.id);
307 }
308 );
309 }
310}
311
312pub struct Renderbuffer {
314 id: gl32::types::GLuint
315}
316impl Renderbuffer {
317 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 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 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 fn drop(&mut self) {
365 check_loaded!(
366 DeleteRenderbuffers,
367 unsafe {
368 gl32::DeleteRenderbuffers(1, &self.id);
369 }
370 );
371 }
372}
373
374pub struct VBO {
376 id: gl32::types::GLuint
377}
378impl VBO {
379 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 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 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 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 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 fn drop(&mut self) {
461 check_loaded!(
462 DeleteBuffers,
463 unsafe {
464 gl32::DeleteBuffers(1, &self.id);
465 }
466 );
467 }
468}
469
470pub struct EBO {
472 id: gl32::types::GLuint
473}
474impl EBO {
475 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 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 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 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 fn drop(&mut self) {
529 check_loaded!(
530 DeleteBuffers,
531 unsafe {
532 gl32::DeleteBuffers(1, &self.id);
533 }
534 );
535 }
536}
537
538pub struct VAO {
540 id: gl32::types::GLuint
541}
542impl VAO {
543 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 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 fn drop(&mut self) {
579 check_loaded!(
580 DeleteVertexArrays,
581 unsafe {
582 gl32::DeleteVertexArrays(1, &self.id);
583 }
584 );
585 }
586}
587
588pub struct Shader {
590 id: gl32::types::GLuint
591}
592impl Shader {
593 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 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 fn drop(&mut self) {
641 check_loaded!(
642 DeleteShader,
643 unsafe {
644 gl32::DeleteShader(self.id);
645 }
646 );
647 }
648}
649
650pub struct Program {
652 id: gl32::types::GLuint
653}
654impl Program {
655 pub fn create() -> Self {
657 check_loaded!(
658 CreateProgram,
659 unsafe {
660 Self {
661 id: gl32::CreateProgram()
662 }
663 }
664 )
665 }
666 pub fn attach(&self, shader: &Shader) {
668 check_loaded!(
669 AttachShader,
670 unsafe {
671 gl32::AttachShader(self.id, shader.id);
672 }
673 );
674 }
675 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 pub fn using(&self) {
697 check_loaded!(
698 UseProgram,
699 unsafe {
700 gl32::UseProgram(self.id);
701 }
702 );
703 }
704 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 fn drop(&mut self) {
717 check_loaded!(
718 DeleteProgram,
719 unsafe {
720 gl32::DeleteProgram(self.id);
721 }
722 );
723 }
724}