uni_gl/
webgl_native.rs

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)]
16/// uni-gl internal OpenGL context.
17///
18/// You shouldn't use this struct directly. Instead, call the methods on [`WebGLRenderingContext`]
19/// as it automatically dereferences into a [`GLContext`].
20///
21/// This doc is not intended to cover all OpenGL API in depth.
22/// Check [https://www.khronos.org/opengl/](https://www.khronos.org/opengl/) for more information.
23pub struct GLContext {
24    /// openGL internal reference
25    pub reference: Reference,
26    /// whether this context is a WebGL 2.0 context
27    pub is_webgl2: bool,
28}
29
30/// panics with a proper message if the last OpenGL call returned an error
31pub 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
53/// gl::GetString convenient wrapper
54fn 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    /// create an OpenGL context.
67    ///
68    /// uni-gl should be used with the uni-app crate.
69    /// You can create a [`WebGLRenderingContext`] with following code :
70    /// ```ignore
71    /// let app = uni_app::App::new(...);
72    /// let gl = uni_gl::WebGLRenderingContext::new(app.canvas());
73    /// ```
74    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        //  unsafe { gl::Enable(gl::DEPTH_TEST) };
86        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    /// create a new OpenGL buffer
103    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    /// delete an existing buffer
113    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    /// bind a buffer to current state.
121    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    /// fills a buffer with data.
129    ///
130    /// kind : see [`GLContext::bind_buffer`].
131    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    /// update a subset of a buffer
139    ///
140    /// kind : see [`GLContext::bind_buffer`].
141    ///
142    /// offset : offset in the buffer where data replacement will begin
143    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    /// this buffer is not bound to the current state anymore.
151    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    /// create a new shader.
159    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    /// set or replace the source code in a shader
167    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    /// compile a shader
176    pub fn compile_shader(&self, shader: &WebGLShader) {
177        unsafe {
178            gl::CompileShader(shader.0);
179
180            // Get the compile status
181            let mut status = gl::FALSE as gl::types::GLint;
182            gl::GetShaderiv(shader.0, gl::COMPILE_STATUS, &mut status);
183
184            // Fail on error
185            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); // subtract 1 to skip the trailing null character
190                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    /// create a program
208    pub fn create_program(&self) -> WebGLProgram {
209        let p = unsafe { WebGLProgram(gl::CreateProgram()) };
210        check_gl_error("create_program");
211        p
212    }
213
214    /// link a program
215    pub fn link_program(&self, program: &WebGLProgram) {
216        unsafe {
217            gl::LinkProgram(program.0);
218            // Get the link status
219            let mut status = gl::FALSE as gl::types::GLint;
220            gl::GetProgramiv(program.0, gl::LINK_STATUS, &mut status);
221
222            // Fail on error
223            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); // subtract 1 to skip the trailing null character
228                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    /// bind a program to the current state.
245    pub fn use_program(&self, program: &WebGLProgram) {
246        unsafe {
247            gl::UseProgram(program.0);
248        }
249        check_gl_error("use_program");
250    }
251
252    /// attach a shader to a program. A program must have two shaders : vertex and fragment shader.
253    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    /// associate a generic vertex attribute index with a named attribute
261    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    /// return the location of an attribute variable
270    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    /// return the location of a uniform variable
283    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    /// define an array of generic vertex attribute data
303    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        // println!(
323        //     "{:?} {:?} {:?} {:?} {:?} {:?} {:?}",
324        //     location, size, kind, kind as u32, normalized, stride, offset
325        // );
326        check_gl_error("vertex_attrib_pointer");
327    }
328
329    /// enable a generic vertex attribute array
330    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    /// specify clear values for the color buffers
338    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    /// enable GL capabilities.
346    ///
347    /// flag should be one of [`Flag`]
348    pub fn enable(&self, flag: i32) {
349        unsafe {
350            gl::Enable(flag as _);
351        }
352        check_gl_error("enable");
353    }
354
355    /// disable GL capabilities.
356    ///
357    /// flag should be one of [`Flag`]
358    pub fn disable(&self, flag: i32) {
359        unsafe {
360            gl::Disable(flag as _);
361        }
362        check_gl_error("disable");
363    }
364
365    /// specify whether front- or back-facing polygons can be culled
366    pub fn cull_face(&self, flag: Culling) {
367        unsafe {
368            gl::CullFace(flag as _);
369        }
370        check_gl_error("cullface");
371    }
372
373    /// enable or disable writing into the depth buffer
374    pub fn depth_mask(&self, b: bool) {
375        unsafe {
376            gl::DepthMask(b as _);
377        }
378        check_gl_error("depth_mask");
379    }
380
381    /// specify the value used for depth buffer comparisons
382    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    /// specify the clear value for the depth buffer
391    pub fn clear_depth(&self, value: f32) {
392        unsafe {
393            gl::ClearDepth(value as _);
394        }
395        check_gl_error("clear_depth");
396    }
397
398    /// clear buffers to preset values
399    pub fn clear(&self, bit: BufferBit) {
400        unsafe {
401            gl::Clear(bit as _);
402        }
403        check_gl_error("clear");
404    }
405
406    /// set the viewport
407    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    /// render primitives from indexed array data
415    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    /// render primitives from array data
423    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    /// read a block of pixels from the frame buffer
431    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    /// set pixel storage modes
456    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    /// specify a two-dimensional texture image
464    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 _, // internal format
487                width as _,
488                height as _,
489                0,
490                format as _, // format
491                kind as _,
492                p as _,
493            );
494        }
495
496        check_gl_error("tex_image2d");
497    }
498
499    /// update a part of a two-dimensional texture subimage
500    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    /// specify a two-dimensional texture image in a compressed format
530    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 _, //gl::UNSIGNED_BYTE as _,
548                data.as_ptr() as _,
549            );
550        }
551
552        check_gl_error("compressed_tex_image2d");
553    }
554
555    /// return informations about current program
556    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 get_active_uniform(&self, program: &WebGLProgram, location: u32) -> WebGLActiveInfo {
567    //     let mut name: Vec<u8> = Vec::with_capacity(NAME_SIZE);
568    //     let mut size = 0i32;
569    //     let mut len = 0i32;
570    //     let mut kind = 0u32;
571
572    //     unsafe {
573    //         gl::GetActiveUniform(
574    //             program.0,
575    //             location as _,
576    //             NAME_SIZE as _,
577    //             &mut len,
578    //             &mut size,
579    //             &mut kind,
580    //             name.as_mut_ptr() as _,
581    //         );
582    //         name.set_len(len as _);
583    //     };
584
585    //     use std::mem;
586
587    //     WebGLActiveInfo::new(
588    //         String::from_utf8(name).unwrap(),
589    //         //location as _,
590    //         size as _,
591    //         unsafe { mem::transmute::<u16, UniformType>(kind as _) },
592    //         0
593    //         //unsafe { mem::transmute::<u16, DataType>(kind as _) },
594    //     )
595    // }
596
597    // pub fn get_active_attrib(&self, program: &WebGLProgram, location: u32) -> WebGLActiveInfo {
598    //     let mut name: Vec<u8> = Vec::with_capacity(NAME_SIZE);
599    //     let mut size = 0i32;
600    //     let mut len = 0i32;
601    //     let mut kind = 0u32;
602
603    //     unsafe {
604    //         gl::GetActiveAttrib(
605    //             program.0,
606    //             location as _,
607    //             NAME_SIZE as _,
608    //             &mut len,
609    //             &mut size,
610    //             &mut kind,
611    //             name.as_mut_ptr() as _,
612    //         );
613    //         name.set_len(len as _);
614    //     }
615    //     println!("name {:?}", name);
616    //     use std::mem;
617    //     //let c_name = unsafe { CString::from_raw(name[0..(len+1)].as_mut_ptr())};
618    //     WebGLActiveInfo::new(
619    //         String::from_utf8(name).expect("utf8 parse failed"),
620    //         //location,
621    //         size as _,
622    //         //DataType::Float
623    //         unsafe { mem::transmute::<u16, UniformType>(kind as _) },
624    //         0,
625    //     )
626    // }
627
628    /// create a new texture object
629    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    /// destroy a texture object
640    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    /// generate mipmaps for current 2D texture
649    pub fn generate_mipmap(&self) {
650        unsafe {
651            gl::GenerateMipmap(gl::TEXTURE_2D);
652        }
653
654        check_gl_error("generate_mipmap");
655    }
656
657    /// generate mipmaps for current cube map texture
658    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    /// select active texture unit
667    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    /// bind a named 2D texture to a texturing target
676    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    /// current 2D texture is not bound to current state anymore
685    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    /// bind a named cube map texture to a texturing target
694    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    /// current cube map texture is not bound to current state anymore
703    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    /// set the RGB alpha blend equation
712    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    /// specify pixel arithmetic for RGB and alpha components separately
721    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    /// set the blend color
730    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    /// specify the value of a mat4 uniform variable for the current program object
739    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    /// specify the value of a mat3 uniform variable for the current program object
747    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    /// specify the value of a mat2 uniform variable for the current program object
755    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    /// specify the value of an int uniform variable for the current program object
763    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    /// specify the value of a float uniform variable for the current program object
771    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    /// specify the value of a vec2 uniform variable for the current program object
779    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    /// specify the value of a vec3 uniform variable for the current program object
787    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    /// specify the value of a vec4 uniform variable for the current program object
795    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    /// set texture integer parameters
803    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    /// set texture float parameters
811    pub fn tex_parameterfv(&self, kind: TextureKind, pname: TextureParameter, param: f32) {
812        unsafe {
813            gl::TexParameterfv(kind as _, pname as _, &param);
814        }
815        check_gl_error("tex_parameterfv");
816    }
817
818    /// create a vertex array object
819    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    /// destroy a vertex array object
829    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    /// bind a vertex array object to current state
837    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    /// current vertex array object is not bound to the current state anymore
845    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    /// specify which color buffers are to be drawn into
853    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    /// create a new framebuffer
863    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    /// destroy a framebuffer
873    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    /// bind a framebuffer to the current state
881    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    /// attach a texture to a framebuffer
890    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    /// unbind a framebuffer
912    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}