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