1use gl;
2use std::os::raw::c_void;
3
4use std::ffi::CStr;
5use std::ffi::CString;
6use std::ops::Deref;
7use std::ptr;
8use std::str;
9
10use crate::common::*;
11use crate::glenum::*;
12
13pub type Reference = u32;
14
15#[derive(Debug, PartialEq, Clone)]
16pub struct GLContext {
24 pub reference: Reference,
26 pub is_webgl2: bool,
28}
29
30pub fn check_gl_error(msg: &str) {
32 unsafe {
33 let err = gl::GetError();
34 if err != gl::NO_ERROR {
35 panic!(
36 "GLError: {} {} ({})",
37 msg,
38 err,
39 match err {
40 gl::INVALID_ENUM => "invalid enum",
41 gl::INVALID_OPERATION => "invalid operation",
42 gl::INVALID_VALUE => "invalid value",
43 gl::OUT_OF_MEMORY => "out of memory",
44 gl::STACK_OVERFLOW => "stack overflow",
45 gl::STACK_UNDERFLOW => "stack underflow",
46 _ => "unknown error",
47 }
48 );
49 }
50 }
51}
52
53fn get_string(param: u32) -> String {
55 return unsafe {
56 let data = CStr::from_ptr(gl::GetString(param) as *const _)
57 .to_bytes()
58 .to_vec();
59 String::from_utf8(data).unwrap()
60 };
61}
62
63pub type WebGLContext<'p> = Box<dyn 'p + for<'a> FnMut(&'a str) -> *const c_void>;
64
65impl WebGLRenderingContext {
66 pub fn new<'p>(mut loadfn: WebGLContext<'p>) -> WebGLRenderingContext {
75 gl::load_with(move |name| loadfn(name));
76
77 WebGLRenderingContext {
78 common: GLContext::new(),
79 }
80 }
81}
82
83impl GLContext {
84 pub fn new() -> GLContext {
85 println!("opengl {}", get_string(gl::VERSION));
87 println!(
88 "shading language {}",
89 get_string(gl::SHADING_LANGUAGE_VERSION)
90 );
91 println!("vendor {}", get_string(gl::VENDOR));
92 GLContext {
93 reference: 0,
94 is_webgl2: true,
95 }
96 }
97
98 pub fn print<T: Into<String>>(msg: T) {
99 print!("{}", msg.into());
100 }
101
102 pub fn create_buffer(&self) -> WebGLBuffer {
104 let mut buffer = WebGLBuffer(0);
105 unsafe {
106 gl::GenBuffers(1, &mut buffer.0);
107 }
108 check_gl_error("create_buffer");
109 buffer
110 }
111
112 pub fn delete_buffer(&self, buffer: &WebGLBuffer) {
114 unsafe {
115 gl::DeleteBuffers(1, &buffer.0);
116 }
117 check_gl_error("delete_buffer");
118 }
119
120 pub fn bind_buffer(&self, kind: BufferKind, buffer: &WebGLBuffer) {
122 unsafe {
123 gl::BindBuffer(kind as _, buffer.0);
124 }
125 check_gl_error("bind_buffer");
126 }
127
128 pub fn buffer_data(&self, kind: BufferKind, data: &[u8], draw: DrawMode) {
132 unsafe {
133 gl::BufferData(kind as _, data.len() as _, data.as_ptr() as _, draw as _);
134 }
135 check_gl_error("buffer_data");
136 }
137
138 pub fn buffer_sub_data(&self, kind: BufferKind, offset: u32, data: &[u8]) {
144 unsafe {
145 gl::BufferSubData(kind as _, offset as _, data.len() as _, data.as_ptr() as _);
146 }
147 check_gl_error("buffer_sub_data");
148 }
149
150 pub fn unbind_buffer(&self, kind: BufferKind) {
152 unsafe {
153 gl::BindBuffer(kind as _, 0);
154 }
155 check_gl_error("unbind_buffer");
156 }
157
158 pub fn create_shader(&self, kind: ShaderKind) -> WebGLShader {
160 let shader = unsafe { WebGLShader(gl::CreateShader(kind as _)) };
161 check_gl_error("create_shader");
162
163 return shader;
164 }
165
166 pub fn shader_source(&self, shader: &WebGLShader, source: &str) {
168 let src = CString::new(source).unwrap();
169 unsafe {
170 gl::ShaderSource(shader.0, 1, &src.as_ptr(), ptr::null());
171 }
172 check_gl_error("shader_source");
173 }
174
175 pub fn compile_shader(&self, shader: &WebGLShader) {
177 unsafe {
178 gl::CompileShader(shader.0);
179
180 let mut status = gl::FALSE as gl::types::GLint;
182 gl::GetShaderiv(shader.0, gl::COMPILE_STATUS, &mut status);
183
184 if status != (gl::TRUE as gl::types::GLint) {
186 let mut len = 0;
187 gl::GetShaderiv(shader.0, gl::INFO_LOG_LENGTH, &mut len);
188 let mut buf = Vec::with_capacity(len as usize);
189 buf.set_len((len as usize) - 1); gl::GetShaderInfoLog(
191 shader.0,
192 len,
193 ptr::null_mut(),
194 buf.as_mut_ptr() as *mut gl::types::GLchar,
195 );
196
197 match String::from_utf8(buf) {
198 Ok(s) => panic!("{}", s),
199 Err(_) => panic!("Compile shader fail, reason unknown"),
200 }
201 }
202 }
203
204 check_gl_error("compile_shader");
205 }
206
207 pub fn create_program(&self) -> WebGLProgram {
209 let p = unsafe { WebGLProgram(gl::CreateProgram()) };
210 check_gl_error("create_program");
211 p
212 }
213
214 pub fn link_program(&self, program: &WebGLProgram) {
216 unsafe {
217 gl::LinkProgram(program.0);
218 let mut status = gl::FALSE as gl::types::GLint;
220 gl::GetProgramiv(program.0, gl::LINK_STATUS, &mut status);
221
222 if status != (gl::TRUE as gl::types::GLint) {
224 let mut len = 0;
225 gl::GetProgramiv(program.0, gl::INFO_LOG_LENGTH, &mut len);
226 let mut buf = Vec::with_capacity(len as usize);
227 buf.set_len((len as usize) - 1); gl::GetProgramInfoLog(
229 program.0,
230 len,
231 ptr::null_mut(),
232 buf.as_mut_ptr() as *mut gl::types::GLchar,
233 );
234
235 match String::from_utf8(buf) {
236 Ok(s) => panic!("{}", s),
237 Err(_) => panic!("Link program fail, reason unknown"),
238 }
239 }
240 }
241 check_gl_error("link_program");
242 }
243
244 pub fn use_program(&self, program: &WebGLProgram) {
246 unsafe {
247 gl::UseProgram(program.0);
248 }
249 check_gl_error("use_program");
250 }
251
252 pub fn attach_shader(&self, program: &WebGLProgram, shader: &WebGLShader) {
254 unsafe {
255 gl::AttachShader(program.0, shader.0);
256 }
257 check_gl_error("attach_shader");
258 }
259
260 pub fn bind_attrib_location(&self, program: &WebGLProgram, name: &str, loc: u32) {
262 let c_name = CString::new(name).unwrap();
263 unsafe {
264 gl::BindAttribLocation(program.0 as _, loc as _, c_name.as_ptr());
265 check_gl_error("bind_attrib_location");
266 }
267 }
268
269 pub fn get_attrib_location(&self, program: &WebGLProgram, name: &str) -> Option<u32> {
271 let c_name = CString::new(name).unwrap();
272 unsafe {
273 let location = gl::GetAttribLocation(program.0 as _, c_name.as_ptr());
274 check_gl_error("get_attrib_location");
275 if location == -1 {
276 return None;
277 }
278 return Some(location as _);
279 }
280 }
281
282 pub fn get_uniform_location(
284 &self,
285 program: &WebGLProgram,
286 name: &str,
287 ) -> Option<WebGLUniformLocation> {
288 let c_name = CString::new(name).unwrap();
289 unsafe {
290 let location = gl::GetUniformLocation(program.0 as _, c_name.as_ptr());
291 check_gl_error(&format!("get_uniform_location {}", name));
292 if location == -1 {
293 return None;
294 }
295 return Some(WebGLUniformLocation {
296 reference: location as _,
297 name: name.into(),
298 });
299 }
300 }
301
302 pub fn vertex_attrib_pointer(
304 &self,
305 location: u32,
306 size: AttributeSize,
307 kind: DataType,
308 normalized: bool,
309 stride: u32,
310 offset: u32,
311 ) {
312 unsafe {
313 gl::VertexAttribPointer(
314 location as _,
315 size as _,
316 kind as _,
317 normalized as _,
318 stride as _,
319 offset as _,
320 );
321 }
322 check_gl_error("vertex_attrib_pointer");
327 }
328
329 pub fn enable_vertex_attrib_array(&self, location: u32) {
331 unsafe {
332 gl::EnableVertexAttribArray(location as _);
333 }
334 check_gl_error("enable_vertex_attrib_array");
335 }
336
337 pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
339 unsafe {
340 gl::ClearColor(r, g, b, a);
341 }
342 check_gl_error("clear_color");
343 }
344
345 pub fn enable(&self, flag: i32) {
349 unsafe {
350 gl::Enable(flag as _);
351 }
352 check_gl_error("enable");
353 }
354
355 pub fn disable(&self, flag: i32) {
359 unsafe {
360 gl::Disable(flag as _);
361 }
362 check_gl_error("disable");
363 }
364
365 pub fn cull_face(&self, flag: Culling) {
367 unsafe {
368 gl::CullFace(flag as _);
369 }
370 check_gl_error("cullface");
371 }
372
373 pub fn depth_mask(&self, b: bool) {
375 unsafe {
376 gl::DepthMask(b as _);
377 }
378 check_gl_error("depth_mask");
379 }
380
381 pub fn depth_func(&self, d: DepthTest) {
383 unsafe {
384 gl::DepthFunc(d as _);
385 }
386
387 check_gl_error("depth_func");
388 }
389
390 pub fn clear_depth(&self, value: f32) {
392 unsafe {
393 gl::ClearDepth(value as _);
394 }
395 check_gl_error("clear_depth");
396 }
397
398 pub fn clear(&self, bit: BufferBit) {
400 unsafe {
401 gl::Clear(bit as _);
402 }
403 check_gl_error("clear");
404 }
405
406 pub fn viewport(&self, x: i32, y: i32, width: u32, height: u32) {
408 unsafe {
409 gl::Viewport(x, y, width as _, height as _);
410 };
411 check_gl_error("viewport");
412 }
413
414 pub fn draw_elements(&self, mode: Primitives, count: usize, kind: DataType, offset: u32) {
416 unsafe {
417 gl::DrawElements(mode as _, count as _, kind as _, offset as _);
418 };
419 check_gl_error("draw_elements");
420 }
421
422 pub fn draw_arrays(&self, mode: Primitives, count: usize) {
424 unsafe {
425 gl::DrawArrays(mode as _, 0, count as _);
426 };
427 check_gl_error("draw_arrays");
428 }
429
430 pub fn read_pixels(
432 &self,
433 x: u32,
434 y: u32,
435 width: u32,
436 height: u32,
437 format: PixelFormat,
438 kind: PixelType,
439 data: &mut [u8],
440 ) {
441 unsafe {
442 gl::ReadPixels(
443 x as _,
444 y as _,
445 width as _,
446 height as _,
447 format as _,
448 kind as _,
449 data.as_mut_ptr() as _,
450 );
451 check_gl_error("read_pixels");
452 }
453 }
454
455 pub fn pixel_storei(&self, storage: PixelStorageMode, value: i32) {
457 unsafe {
458 gl::PixelStorei(storage as _, value);
459 check_gl_error("pixel_storei");
460 }
461 }
462
463 pub fn tex_image2d(
465 &self,
466 target: TextureBindPoint,
467 level: u8,
468 width: u16,
469 height: u16,
470 format: PixelFormat,
471 kind: PixelType,
472 pixels: &[u8],
473 ) {
474 let p: *const c_void;
475
476 if pixels.len() > 0 {
477 p = pixels.as_ptr() as _;
478 } else {
479 p = 0 as _;
480 }
481
482 unsafe {
483 gl::TexImage2D(
484 target as _,
485 level as _,
486 format as _, width as _,
488 height as _,
489 0,
490 format as _, kind as _,
492 p as _,
493 );
494 }
495
496 check_gl_error("tex_image2d");
497 }
498
499 pub fn tex_sub_image2d(
501 &self,
502 target: TextureBindPoint,
503 level: u8,
504 xoffset: u16,
505 yoffset: u16,
506 width: u16,
507 height: u16,
508 format: PixelFormat,
509 kind: PixelType,
510 pixels: &[u8],
511 ) {
512 unsafe {
513 gl::TexSubImage2D(
514 target as _,
515 level as _,
516 xoffset as _,
517 yoffset as _,
518 width as _,
519 height as _,
520 format as _,
521 kind as _,
522 pixels.as_ptr() as _,
523 );
524 }
525
526 check_gl_error("tex_sub_image2d");
527 }
528
529 pub fn compressed_tex_image2d(
531 &self,
532 target: TextureBindPoint,
533 level: u8,
534 compression: TextureCompression,
535 width: u16,
536 height: u16,
537 data: &[u8],
538 ) {
539 unsafe {
540 gl::CompressedTexImage2D(
541 target as _,
542 level as _,
543 compression as _,
544 width as _,
545 height as _,
546 0,
547 data.len() as _, data.as_ptr() as _,
549 );
550 }
551
552 check_gl_error("compressed_tex_image2d");
553 }
554
555 pub fn get_program_parameter(&self, program: &WebGLProgram, pname: ShaderParameter) -> i32 {
557 let mut res = 0;
558 unsafe {
559 gl::GetProgramiv(program.0, pname as _, &mut res);
560 }
561
562 check_gl_error("get_program_parameter");
563 res
564 }
565
566 pub fn create_texture(&self) -> WebGLTexture {
630 let mut handle = WebGLTexture(0);
631 unsafe {
632 gl::GenTextures(1, &mut handle.0);
633 }
634 check_gl_error("create_texture");
635
636 handle
637 }
638
639 pub fn delete_texture(&self, texture: &WebGLTexture) {
641 unsafe {
642 gl::DeleteTextures(1, texture.0 as _);
643 }
644
645 check_gl_error("delete_texture");
646 }
647
648 pub fn generate_mipmap(&self) {
650 unsafe {
651 gl::GenerateMipmap(gl::TEXTURE_2D);
652 }
653
654 check_gl_error("generate_mipmap");
655 }
656
657 pub fn generate_mipmap_cube(&self) {
659 unsafe {
660 gl::GenerateMipmap(gl::TEXTURE_CUBE_MAP);
661 }
662
663 check_gl_error("generate_mipmap_cube");
664 }
665
666 pub fn active_texture(&self, active: u32) {
668 unsafe {
669 gl::ActiveTexture(gl::TEXTURE0 + active);
670 }
671
672 check_gl_error("active_texture");
673 }
674
675 pub fn bind_texture(&self, texture: &WebGLTexture) {
677 unsafe {
678 gl::BindTexture(gl::TEXTURE_2D, texture.0);
679 }
680
681 check_gl_error("bind_texture");
682 }
683
684 pub fn unbind_texture(&self) {
686 unsafe {
687 gl::BindTexture(gl::TEXTURE_2D, 0);
688 }
689
690 check_gl_error("unbind_texture");
691 }
692
693 pub fn bind_texture_cube(&self, texture: &WebGLTexture) {
695 unsafe {
696 gl::BindTexture(gl::TEXTURE_CUBE_MAP, texture.0);
697 }
698
699 check_gl_error("bind_texture_cube");
700 }
701
702 pub fn unbind_texture_cube(&self) {
704 unsafe {
705 gl::BindTexture(gl::TEXTURE_CUBE_MAP, 0);
706 }
707
708 check_gl_error("unbind_texture_cube");
709 }
710
711 pub fn blend_equation(&self, eq: BlendEquation) {
713 unsafe {
714 gl::BlendEquation(eq as _);
715 }
716
717 check_gl_error("blend_equation");
718 }
719
720 pub fn blend_func(&self, b1: BlendMode, b2: BlendMode) {
722 unsafe {
723 gl::BlendFunc(b1 as _, b2 as _);
724 }
725
726 check_gl_error("blend_func");
727 }
728
729 pub fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
731 unsafe {
732 gl::BlendColor(r, g, b, a);
733 }
734
735 check_gl_error("blend_color");
736 }
737
738 pub fn uniform_matrix_4fv(&self, location: &WebGLUniformLocation, value: &[[f32; 4]; 4]) {
740 unsafe {
741 gl::UniformMatrix4fv(*location.deref() as i32, 1, false as _, &value[0] as _);
742 }
743 check_gl_error("uniform_matrix_4fv");
744 }
745
746 pub fn uniform_matrix_3fv(&self, location: &WebGLUniformLocation, value: &[[f32; 3]; 3]) {
748 unsafe {
749 gl::UniformMatrix3fv(*location.deref() as i32, 1, false as _, &value[0] as _);
750 }
751 check_gl_error("uniform_matrix_3fv");
752 }
753
754 pub fn uniform_matrix_2fv(&self, location: &WebGLUniformLocation, value: &[[f32; 2]; 2]) {
756 unsafe {
757 gl::UniformMatrix2fv(*location.deref() as i32, 1, false as _, &value[0] as _);
758 }
759 check_gl_error("uniform_matrix_2fv");
760 }
761
762 pub fn uniform_1i(&self, location: &WebGLUniformLocation, value: i32) {
764 unsafe {
765 gl::Uniform1i(*location.deref() as i32, value as _);
766 }
767 check_gl_error("uniform_1i");
768 }
769
770 pub fn uniform_1f(&self, location: &WebGLUniformLocation, value: f32) {
772 unsafe {
773 gl::Uniform1f(*location.deref() as i32, value as _);
774 }
775 check_gl_error("uniform_1f");
776 }
777
778 pub fn uniform_2f(&self, location: &WebGLUniformLocation, value: (f32, f32)) {
780 unsafe {
781 gl::Uniform2f(*location.deref() as _, value.0, value.1);
782 }
783 check_gl_error("uniform_2f");
784 }
785
786 pub fn uniform_3f(&self, location: &WebGLUniformLocation, value: (f32, f32, f32)) {
788 unsafe {
789 gl::Uniform3f(*location.deref() as _, value.0, value.1, value.2);
790 }
791 check_gl_error("uniform_3f");
792 }
793
794 pub fn uniform_4f(&self, location: &WebGLUniformLocation, value: (f32, f32, f32, f32)) {
796 unsafe {
797 gl::Uniform4f(*location.deref() as _, value.0, value.1, value.2, value.3);
798 }
799 check_gl_error("uniform_4f");
800 }
801
802 pub fn tex_parameteri(&self, kind: TextureKind, pname: TextureParameter, param: i32) {
804 unsafe {
805 gl::TexParameteri(kind as _, pname as _, param);
806 }
807 check_gl_error("tex_parameteri");
808 }
809
810 pub fn tex_parameterfv(&self, kind: TextureKind, pname: TextureParameter, param: f32) {
812 unsafe {
813 gl::TexParameterfv(kind as _, pname as _, ¶m);
814 }
815 check_gl_error("tex_parameterfv");
816 }
817
818 pub fn create_vertex_array(&self) -> WebGLVertexArray {
820 let mut vao = WebGLVertexArray(0);
821 unsafe {
822 gl::GenVertexArrays(1, &mut vao.0);
823 }
824 check_gl_error("create_vertex_array");
825 vao
826 }
827
828 pub fn delete_vertex_array(&self, vao: &WebGLVertexArray) {
830 unsafe {
831 gl::DeleteVertexArrays(1, &vao.0);
832 }
833 check_gl_error("delete_vertex_array");
834 }
835
836 pub fn bind_vertex_array(&self, vao: &WebGLVertexArray) {
838 unsafe {
839 gl::BindVertexArray(vao.0);
840 }
841 check_gl_error("bind_vertex_array");
842 }
843
844 pub fn unbind_vertex_array(&self, _vao: &WebGLVertexArray) {
846 unsafe {
847 gl::BindVertexArray(0);
848 }
849 check_gl_error("unbind_vertex_array");
850 }
851
852 pub fn draw_buffer(&self, buffers: &[ColorBuffer]) {
854 unsafe {
855 for value in buffers {
856 gl::DrawBuffer(*value as _);
857 }
858 }
859 check_gl_error("draw_buffer");
860 }
861
862 pub fn create_framebuffer(&self) -> WebGLFrameBuffer {
864 let mut fb = WebGLFrameBuffer(0);
865 unsafe {
866 gl::GenFramebuffers(1, &mut fb.0);
867 }
868 check_gl_error("create_framebuffer");
869 fb
870 }
871
872 pub fn delete_framebuffer(&self, fb: &WebGLFrameBuffer) {
874 unsafe {
875 gl::DeleteFramebuffers(1, &fb.0);
876 }
877 check_gl_error("delete_framebuffer");
878 }
879
880 pub fn bind_framebuffer(&self, buffer: Buffers, fb: &WebGLFrameBuffer) {
882 unsafe {
883 gl::BindFramebuffer(buffer as u32, fb.0);
884 }
885
886 check_gl_error("bind_framebuffer");
887 }
888
889 pub fn framebuffer_texture2d(
891 &self,
892 target: Buffers,
893 attachment: Buffers,
894 textarget: TextureBindPoint,
895 texture: &WebGLTexture,
896 level: i32,
897 ) {
898 unsafe {
899 gl::FramebufferTexture2D(
900 target as u32,
901 attachment as u32,
902 textarget as u32,
903 texture.0,
904 level,
905 );
906 }
907
908 check_gl_error("framebuffer_texture2d");
909 }
910
911 pub fn unbind_framebuffer(&self, buffer: Buffers) {
913 unsafe {
914 gl::BindFramebuffer(buffer as u32, 0);
915 }
916
917 check_gl_error("unbind_framebuffer");
918 }
919}