egui_glow/
vao.rs

1#![allow(unsafe_code)]
2
3use glow::HasContext as _;
4
5use crate::check_for_gl_error;
6
7// ----------------------------------------------------------------------------
8
9#[derive(Debug)]
10pub(crate) struct BufferInfo {
11    pub location: u32, //
12    pub vector_size: i32,
13    pub data_type: u32, //GL_FLOAT,GL_UNSIGNED_BYTE
14    pub normalized: bool,
15    pub stride: i32,
16    pub offset: i32,
17}
18
19// ----------------------------------------------------------------------------
20
21/// Wrapper around either Emulated VAO or GL's VAO.
22pub(crate) struct VertexArrayObject {
23    // If `None`, we emulate VAO:s.
24    vao: Option<crate::glow::VertexArray>,
25    vbo: glow::Buffer,
26    buffer_infos: Vec<BufferInfo>,
27}
28
29impl VertexArrayObject {
30    #[allow(clippy::needless_pass_by_value)] // false positive
31    pub(crate) unsafe fn new(
32        gl: &glow::Context,
33        vbo: glow::Buffer,
34        buffer_infos: Vec<BufferInfo>,
35    ) -> Self {
36        let vao = if supports_vao(gl) {
37            unsafe {
38                let vao = gl.create_vertex_array().unwrap();
39                check_for_gl_error!(gl, "create_vertex_array");
40
41                // Store state in the VAO:
42                gl.bind_vertex_array(Some(vao));
43                gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));
44
45                for attribute in &buffer_infos {
46                    gl.vertex_attrib_pointer_f32(
47                        attribute.location,
48                        attribute.vector_size,
49                        attribute.data_type,
50                        attribute.normalized,
51                        attribute.stride,
52                        attribute.offset,
53                    );
54                    check_for_gl_error!(gl, "vertex_attrib_pointer_f32");
55                    gl.enable_vertex_attrib_array(attribute.location);
56                    check_for_gl_error!(gl, "enable_vertex_attrib_array");
57                }
58
59                gl.bind_vertex_array(None);
60
61                Some(vao)
62            }
63        } else {
64            log::debug!("VAO not supported");
65            None
66        };
67
68        Self {
69            vao,
70            vbo,
71            buffer_infos,
72        }
73    }
74
75    pub(crate) unsafe fn bind(&self, gl: &glow::Context) {
76        unsafe {
77            if let Some(vao) = self.vao {
78                gl.bind_vertex_array(Some(vao));
79                check_for_gl_error!(gl, "bind_vertex_array");
80            } else {
81                gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo));
82                check_for_gl_error!(gl, "bind_buffer");
83
84                for attribute in &self.buffer_infos {
85                    gl.vertex_attrib_pointer_f32(
86                        attribute.location,
87                        attribute.vector_size,
88                        attribute.data_type,
89                        attribute.normalized,
90                        attribute.stride,
91                        attribute.offset,
92                    );
93                    check_for_gl_error!(gl, "vertex_attrib_pointer_f32");
94                    gl.enable_vertex_attrib_array(attribute.location);
95                    check_for_gl_error!(gl, "enable_vertex_attrib_array");
96                }
97            }
98        }
99    }
100
101    pub(crate) unsafe fn unbind(&self, gl: &glow::Context) {
102        unsafe {
103            if self.vao.is_some() {
104                gl.bind_vertex_array(None);
105            } else {
106                gl.bind_buffer(glow::ARRAY_BUFFER, None);
107                for attribute in &self.buffer_infos {
108                    gl.disable_vertex_attrib_array(attribute.location);
109                }
110            }
111        }
112    }
113}
114
115// ----------------------------------------------------------------------------
116
117fn supports_vao(gl: &glow::Context) -> bool {
118    const WEBGL_PREFIX: &str = "WebGL ";
119    const OPENGL_ES_PREFIX: &str = "OpenGL ES ";
120
121    let version_string = unsafe { gl.get_parameter_string(glow::VERSION) };
122    log::debug!("GL version: {:?}.", version_string);
123
124    // Examples:
125    // * "WebGL 2.0 (OpenGL ES 3.0 Chromium)"
126    // * "WebGL 2.0"
127
128    if let Some(pos) = version_string.rfind(WEBGL_PREFIX) {
129        let version_str = &version_string[pos + WEBGL_PREFIX.len()..];
130        if version_str.contains("1.0") {
131            // need to test OES_vertex_array_object .
132            let supported_extensions = gl.supported_extensions();
133            log::debug!("Supported OpenGL extensions: {:?}", supported_extensions);
134            supported_extensions.contains("OES_vertex_array_object")
135                || supported_extensions.contains("GL_OES_vertex_array_object")
136        } else {
137            true
138        }
139    } else if version_string.contains(OPENGL_ES_PREFIX) {
140        // glow targets es2.0+ so we don't concern about OpenGL ES-CM,OpenGL ES-CL
141        if version_string.contains("2.0") {
142            // need to test OES_vertex_array_object .
143            let supported_extensions = gl.supported_extensions();
144            log::debug!("Supported OpenGL extensions: {:?}", supported_extensions);
145            supported_extensions.contains("OES_vertex_array_object")
146                || supported_extensions.contains("GL_OES_vertex_array_object")
147        } else {
148            true
149        }
150    } else {
151        // from OpenGL 3 vao into core
152        if version_string.starts_with('2') {
153            // I found APPLE_vertex_array_object , GL_ATI_vertex_array_object ,ARB_vertex_array_object
154            // but APPLE's and ATI's very old extension.
155            let supported_extensions = gl.supported_extensions();
156            log::debug!("Supported OpenGL extensions: {:?}", supported_extensions);
157            supported_extensions.contains("ARB_vertex_array_object")
158                || supported_extensions.contains("GL_ARB_vertex_array_object")
159        } else {
160            true
161        }
162    }
163}