easy_imgui_opengl/
lib.rs

1/*!
2* Helper module to wrap calls to `glow` OpenGL functions.
3*/
4// Too many unsafes ahead
5#![allow(clippy::missing_safety_doc)]
6
7/// Re-export glow
8pub use glow;
9
10use std::rc::Rc;
11use std::{cell::Cell, marker::PhantomData};
12
13use glow::{HasContext, UniformLocation};
14use smallvec::SmallVec;
15
16#[derive(Debug, Clone)]
17pub struct GLError(u32);
18
19impl std::error::Error for GLError {}
20impl std::fmt::Display for GLError {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        write!(f, "{:x}", self.0)
23    }
24}
25
26pub type Result<T> = std::result::Result<T, GLError>;
27
28/// A shareable OpenGL context.
29pub type GlContext = Rc<glow::Context>;
30
31pub fn check_gl(gl: &GlContext) -> std::result::Result<(), GLError> {
32    let err = unsafe { gl.get_error() };
33    if err == glow::NO_ERROR {
34        Ok(())
35    } else {
36        Err(GLError(err))
37    }
38}
39
40pub fn to_gl_err(gl: &GlContext) -> GLError {
41    unsafe { GLError(gl.get_error()) }
42}
43
44pub struct Texture {
45    gl: GlContext,
46    id: glow::Texture,
47}
48
49impl Drop for Texture {
50    fn drop(&mut self) {
51        unsafe {
52            self.gl.delete_texture(self.id);
53        }
54    }
55}
56
57impl Texture {
58    pub fn gl(&self) -> &GlContext {
59        &self.gl
60    }
61    pub fn generate(gl: &GlContext) -> Result<Texture> {
62        unsafe {
63            let id = gl.create_texture().map_err(|_| to_gl_err(gl))?;
64            Ok(Texture { gl: gl.clone(), id })
65        }
66    }
67    pub fn id(&self) -> glow::Texture {
68        self.id
69    }
70    pub fn into_id(self) -> glow::Texture {
71        let id = self.id;
72        std::mem::forget(self);
73        id
74    }
75}
76
77pub struct EnablerVertexAttribArray {
78    gl: GlContext,
79    id: u32,
80}
81
82impl EnablerVertexAttribArray {
83    fn enable(gl: &GlContext, id: u32) -> EnablerVertexAttribArray {
84        unsafe {
85            gl.enable_vertex_attrib_array(id);
86        }
87        EnablerVertexAttribArray { gl: gl.clone(), id }
88    }
89}
90
91impl Drop for EnablerVertexAttribArray {
92    fn drop(&mut self) {
93        unsafe {
94            self.gl.disable_vertex_attrib_array(self.id);
95        }
96    }
97}
98
99pub struct PushViewport {
100    gl: GlContext,
101    prev: [i32; 4],
102}
103
104impl PushViewport {
105    pub fn new(gl: &GlContext) -> PushViewport {
106        unsafe {
107            let mut prev = [0; 4];
108            gl.get_parameter_i32_slice(glow::VIEWPORT, &mut prev);
109            PushViewport {
110                gl: gl.clone(),
111                prev,
112            }
113        }
114    }
115    pub fn push(gl: &GlContext, x: i32, y: i32, width: i32, height: i32) -> PushViewport {
116        let pv = Self::new(gl);
117        pv.viewport(x, y, width, height);
118        pv
119    }
120    pub fn viewport(&self, x: i32, y: i32, width: i32, height: i32) {
121        unsafe {
122            self.gl.viewport(x, y, width, height);
123        }
124    }
125}
126
127impl Drop for PushViewport {
128    fn drop(&mut self) {
129        unsafe {
130            self.gl
131                .viewport(self.prev[0], self.prev[1], self.prev[2], self.prev[3]);
132        }
133    }
134}
135
136pub struct Program {
137    gl: GlContext,
138    id: glow::Program,
139    uniforms: Vec<Uniform>,
140    attribs: Vec<Attribute>,
141}
142
143impl Drop for Program {
144    fn drop(&mut self) {
145        unsafe {
146            self.gl.delete_program(self.id);
147        }
148    }
149}
150
151impl Program {
152    pub fn from_source(
153        gl: &GlContext,
154        vertex: &str,
155        fragment: &str,
156        geometry: Option<&str>,
157    ) -> Result<Program> {
158        unsafe {
159            // Purge error status
160            gl.get_error();
161            let vsh = Shader::compile(gl, glow::VERTEX_SHADER, vertex)?;
162            let fsh = Shader::compile(gl, glow::FRAGMENT_SHADER, fragment)?;
163            let gsh = match geometry {
164                Some(source) => Some(Shader::compile(gl, glow::GEOMETRY_SHADER, source)?),
165                None => None,
166            };
167            let id = gl.create_program().map_err(|_| to_gl_err(gl))?;
168            let mut prg = Program {
169                gl: gl.clone(),
170                id,
171                uniforms: Vec::new(),
172                attribs: Vec::new(),
173            };
174            gl.attach_shader(prg.id, vsh.id);
175            gl.attach_shader(prg.id, fsh.id);
176            if let Some(g) = gsh {
177                gl.attach_shader(prg.id, g.id);
178            }
179            gl.link_program(prg.id);
180
181            let st = gl.get_program_link_status(prg.id);
182            if !st {
183                let msg = gl.get_program_info_log(prg.id);
184                log::error!("{msg}");
185                return Err(GLError(gl.get_error()));
186            }
187
188            let nu = gl.get_active_uniforms(prg.id);
189            prg.uniforms = Vec::with_capacity(nu as usize);
190            for u in 0..nu {
191                let Some(ac) = gl.get_active_uniform(prg.id, u) else {
192                    continue;
193                };
194                let Some(location) = gl.get_uniform_location(prg.id, &ac.name) else {
195                    continue;
196                };
197
198                let u = Uniform {
199                    name: ac.name,
200                    location,
201                    _size: ac.size,
202                    _type: ac.utype,
203                };
204                prg.uniforms.push(u);
205            }
206            let na = gl.get_active_attributes(prg.id);
207            prg.attribs = Vec::with_capacity(na as usize);
208            for a in 0..na {
209                let Some(aa) = gl.get_active_attribute(prg.id, a) else {
210                    continue;
211                };
212                let Some(location) = gl.get_attrib_location(prg.id, &aa.name) else {
213                    continue;
214                };
215
216                let a = Attribute {
217                    name: aa.name,
218                    location,
219                    _size: aa.size,
220                    _type: aa.atype,
221                };
222                prg.attribs.push(a);
223            }
224
225            Ok(prg)
226        }
227    }
228    pub fn id(&self) -> glow::Program {
229        self.id
230    }
231    pub fn attrib_by_name(&self, name: &str) -> Option<&Attribute> {
232        self.attribs.iter().find(|a| a.name == name)
233    }
234    pub fn uniform_by_name(&self, name: &str) -> Option<&Uniform> {
235        self.uniforms.iter().find(|u| u.name == name)
236    }
237    pub unsafe fn draw_func<U, AS>(&self, uniforms: &U, attribs: AS, f_draw: impl FnOnce())
238    where
239        U: UniformProvider,
240        AS: AttribProviderList,
241    {
242        if attribs.is_empty() {
243            return;
244        }
245        unsafe {
246            self.gl.use_program(Some(self.id));
247
248            for u in &self.uniforms {
249                uniforms.apply(&self.gl, u);
250            }
251
252            let _bufs = attribs.bind(glow::ARRAY_BUFFER, self);
253            f_draw();
254            if let Err(e) = check_gl(&self.gl) {
255                log::error!("Error {e:?}");
256            }
257        }
258    }
259    pub fn draw<U, AS>(&self, uniforms: &U, attribs: AS, primitive: u32)
260    where
261        U: UniformProvider,
262        AS: AttribProviderList,
263    {
264        let len = attribs.len() as i32;
265        unsafe {
266            self.draw_func(uniforms, attribs, || self.gl.draw_arrays(primitive, 0, len));
267        }
268    }
269}
270
271struct Shader {
272    gl: GlContext,
273    id: glow::Shader,
274}
275
276impl Drop for Shader {
277    fn drop(&mut self) {
278        unsafe {
279            self.gl.delete_shader(self.id);
280        }
281    }
282}
283
284impl Shader {
285    fn compile(gl: &GlContext, ty: u32, source: &str) -> Result<Shader> {
286        unsafe {
287            let id = gl.create_shader(ty).map_err(|_| to_gl_err(gl))?;
288            let sh = Shader { gl: gl.clone(), id };
289            //multiline
290            gl.shader_source(sh.id, source);
291            gl.compile_shader(sh.id);
292            let st = gl.get_shader_compile_status(sh.id);
293            if !st {
294                //TODO: get errors
295                let msg = gl.get_shader_info_log(sh.id);
296                log::error!("{msg}");
297                return Err(GLError(gl.get_error()));
298            }
299            Ok(sh)
300        }
301    }
302}
303
304#[derive(Copy, Clone, Debug)]
305#[repr(C)]
306pub struct Rgba {
307    pub r: f32,
308    pub g: f32,
309    pub b: f32,
310    pub a: f32,
311}
312
313impl Rgba {
314    pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Rgba {
315        Rgba { r, g, b, a }
316    }
317}
318
319#[derive(Debug)]
320pub struct Uniform {
321    name: String,
322    location: glow::UniformLocation,
323    _size: i32,
324    _type: u32,
325}
326
327impl Uniform {
328    pub fn name(&self) -> &str {
329        &self.name
330    }
331    pub fn location(&self) -> glow::UniformLocation {
332        // UniformLocation is usually Copy, but not for WebAssembly, for some reason
333        #[allow(clippy::clone_on_copy)]
334        self.location.clone()
335    }
336}
337
338#[derive(Debug)]
339pub struct Attribute {
340    name: String,
341    location: u32,
342    _size: i32,
343    _type: u32,
344}
345
346impl Attribute {
347    pub fn name(&self) -> &str {
348        &self.name
349    }
350    pub fn location(&self) -> u32 {
351        self.location
352    }
353}
354
355pub trait UniformProvider {
356    fn apply(&self, gl: &GlContext, u: &Uniform);
357}
358
359impl UniformProvider for () {
360    fn apply(&self, _gl: &GlContext, _u: &Uniform) {}
361}
362
363/// # Safety
364///
365/// This trait returns offsets from Self that will be used to index the raw memory of a
366/// VertexAttribBuffer. Better implemented using the `attrib!` macro.
367pub unsafe trait AttribProvider: Copy {
368    fn apply(gl: &GlContext, a: &Attribute) -> Option<(usize, u32, usize)>;
369}
370
371pub trait AttribProviderList {
372    type KeepType;
373    fn len(&self) -> usize;
374    fn bind(&self, target: u32, p: &Program) -> Self::KeepType;
375    fn is_empty(&self) -> bool {
376        self.len() == 0
377    }
378}
379
380/// This vertex attrib provides the given count of vertices, but without data.
381///
382/// It is useful if all the vertex data is included in the shader and anly the gl_VertexID is
383/// needed.
384#[derive(Debug, Copy, Clone)]
385pub struct NilVertexAttrib(pub usize);
386
387impl AttribProviderList for NilVertexAttrib {
388    type KeepType = ();
389    fn len(&self) -> usize {
390        self.0
391    }
392    fn bind(&self, _target: u32, _p: &Program) {}
393}
394
395/// Uses a normal array as attrib provider.
396///
397/// This is quite inefficient, but easy to use.
398impl<A: AttribProvider> AttribProviderList for &[A] {
399    type KeepType = (Buffer, SmallVec<[EnablerVertexAttribArray; 8]>);
400
401    fn len(&self) -> usize {
402        <[A]>::len(self)
403    }
404    fn bind(&self, target: u32, p: &Program) -> (Buffer, SmallVec<[EnablerVertexAttribArray; 8]>) {
405        let buf = Buffer::generate(&p.gl).unwrap();
406        let mut vas = SmallVec::new();
407        unsafe {
408            p.gl.bind_buffer(target, Some(buf.id()));
409            p.gl.buffer_data_u8_slice(target, as_u8_slice(self), glow::STATIC_DRAW);
410            for a in &p.attribs {
411                if let Some((size, ty, offs)) = A::apply(&p.gl, a) {
412                    let loc = a.location();
413                    vas.push(EnablerVertexAttribArray::enable(&p.gl, loc));
414                    p.gl.vertex_attrib_pointer_f32(
415                        loc,
416                        size as i32,
417                        ty,
418                        false,
419                        std::mem::size_of::<A>() as i32,
420                        offs as i32,
421                    );
422                }
423            }
424        }
425        (buf, vas)
426    }
427}
428
429/// # Safety
430///
431/// Returned information will be used to index the raw memory of a VertexAttribBuffer. Returning
432/// wrong information will cause seg faults.
433pub unsafe trait AttribField {
434    fn detail() -> (usize, u32);
435}
436
437unsafe impl AttribField for f32 {
438    fn detail() -> (usize, u32) {
439        (1, glow::FLOAT)
440    }
441}
442unsafe impl AttribField for u8 {
443    fn detail() -> (usize, u32) {
444        (1, glow::UNSIGNED_BYTE)
445    }
446}
447unsafe impl AttribField for i8 {
448    fn detail() -> (usize, u32) {
449        (1, glow::BYTE)
450    }
451}
452unsafe impl AttribField for u16 {
453    fn detail() -> (usize, u32) {
454        (1, glow::UNSIGNED_SHORT)
455    }
456}
457unsafe impl AttribField for i16 {
458    fn detail() -> (usize, u32) {
459        (1, glow::SHORT)
460    }
461}
462unsafe impl AttribField for u32 {
463    fn detail() -> (usize, u32) {
464        (1, glow::UNSIGNED_INT)
465    }
466}
467unsafe impl AttribField for i32 {
468    fn detail() -> (usize, u32) {
469        (1, glow::INT)
470    }
471}
472unsafe impl AttribField for Rgba {
473    fn detail() -> (usize, u32) {
474        (4, glow::FLOAT)
475    }
476}
477unsafe impl<F: AttribField, const N: usize> AttribField for [F; N] {
478    fn detail() -> (usize, u32) {
479        let (d, t) = F::detail();
480        (N * d, t)
481    }
482}
483unsafe impl<F: AttribField> AttribField for cgmath::Vector2<F> {
484    fn detail() -> (usize, u32) {
485        let (d, t) = F::detail();
486        (2 * d, t)
487    }
488}
489unsafe impl<F: AttribField> AttribField for cgmath::Vector3<F> {
490    fn detail() -> (usize, u32) {
491        let (d, t) = F::detail();
492        (3 * d, t)
493    }
494}
495unsafe impl<F: AttribField> AttribField for cgmath::Vector4<F> {
496    fn detail() -> (usize, u32) {
497        let (d, t) = F::detail();
498        (4 * d, t)
499    }
500}
501
502/// # Safety
503///
504/// This trait returns pointers and size information to OpenGL, if it is wrong it will read out of bounds
505pub unsafe trait UniformField {
506    fn apply(&self, gl: &GlContext, location: UniformLocation) {
507        unsafe {
508            self.apply_array(gl, 1, location);
509        }
510    }
511    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation);
512}
513
514unsafe impl UniformField for cgmath::Matrix4<f32> {
515    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
516        unsafe {
517            let slice: &[f32; 16] = self.as_ref();
518            let slice = std::slice::from_raw_parts(slice.as_ptr(), slice.len() * count);
519            gl.uniform_matrix_4_f32_slice(Some(&location), false, slice);
520        }
521    }
522}
523
524unsafe impl UniformField for cgmath::Matrix3<f32> {
525    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
526        unsafe {
527            let slice: &[f32; 9] = self.as_ref();
528            let slice = std::slice::from_raw_parts(slice.as_ptr(), slice.len() * count);
529            gl.uniform_matrix_3_f32_slice(Some(&location), false, slice);
530        }
531    }
532}
533
534unsafe impl UniformField for cgmath::Vector2<f32> {
535    fn apply(&self, gl: &GlContext, location: UniformLocation) {
536        unsafe {
537            gl.uniform_2_f32(Some(&location), self.x, self.y);
538        }
539    }
540    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
541        unsafe {
542            let slice: &[f32; 2] = self.as_ref();
543            let slice = std::slice::from_raw_parts(slice.as_ptr(), slice.len() * count);
544            gl.uniform_2_f32_slice(Some(&location), slice);
545        }
546    }
547}
548
549unsafe impl UniformField for cgmath::Vector3<f32> {
550    fn apply(&self, gl: &GlContext, location: UniformLocation) {
551        unsafe {
552            gl.uniform_3_f32(Some(&location), self.x, self.y, self.z);
553        }
554    }
555    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
556        unsafe {
557            let slice: &[f32; 3] = self.as_ref();
558            let slice = std::slice::from_raw_parts(slice.as_ptr(), slice.len() * count);
559            gl.uniform_3_f32_slice(Some(&location), slice);
560        }
561    }
562}
563
564unsafe impl UniformField for cgmath::Vector4<f32> {
565    fn apply(&self, gl: &GlContext, location: UniformLocation) {
566        unsafe {
567            gl.uniform_4_f32(Some(&location), self.x, self.y, self.z, self.w);
568        }
569    }
570    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
571        unsafe {
572            let slice: &[f32; 4] = self.as_ref();
573            let slice = std::slice::from_raw_parts(slice.as_ptr(), slice.len() * count);
574            gl.uniform_4_f32_slice(Some(&location), slice);
575        }
576    }
577}
578
579unsafe impl UniformField for i32 {
580    fn apply(&self, gl: &GlContext, location: UniformLocation) {
581        unsafe {
582            gl.uniform_1_i32(Some(&location), *self);
583        }
584    }
585    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
586        unsafe {
587            let slice = std::slice::from_raw_parts(self, count);
588            gl.uniform_1_i32_slice(Some(&location), slice);
589        }
590    }
591}
592
593unsafe impl UniformField for f32 {
594    fn apply(&self, gl: &GlContext, location: UniformLocation) {
595        unsafe {
596            gl.uniform_1_f32(Some(&location), *self);
597        }
598    }
599    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
600        unsafe {
601            let slice = std::slice::from_raw_parts(self, count);
602            gl.uniform_1_f32_slice(Some(&location), slice);
603        }
604    }
605}
606
607unsafe impl UniformField for Rgba {
608    fn apply(&self, gl: &GlContext, location: UniformLocation) {
609        unsafe {
610            gl.uniform_4_f32(Some(&location), self.r, self.g, self.b, self.a);
611        }
612    }
613    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
614        unsafe {
615            let slice = std::slice::from_raw_parts(&self.r, 4 * count);
616            gl.uniform_4_f32_slice(Some(&location), slice);
617        }
618    }
619}
620
621unsafe impl<T: UniformField, const N: usize> UniformField for [T; N] {
622    unsafe fn apply_array(&self, gl: &GlContext, count: usize, location: UniformLocation) {
623        unsafe {
624            self[0].apply_array(gl, N * count, location);
625        }
626    }
627}
628
629macro_rules! impl_attrib_provider_list {
630    ($($An:ident)*) => {
631        #[allow(non_snake_case)]
632        impl<$($An: AttribProviderList),*> AttribProviderList for ($($An),*) {
633            type KeepType = ($($An::KeepType),*);
634            fn len(&self) -> usize {
635                let ($($An),*) = self;
636                impl_attrib_provider_list!(@MINLEN $($An)*)
637            }
638            fn bind(&self, target: u32, p: &Program) -> Self::KeepType {
639                let ($($An),*) = self;
640                $(
641                    let $An = $An.bind(target, p);
642                )*
643                ($($An),*)
644            }
645        }
646    };
647
648    (@MINLEN $A0:ident) =>  { $A0.len() };
649    (@MINLEN $A0:ident $($An:ident)*) =>  { $A0.len().min(impl_attrib_provider_list!(@MINLEN $($An)*)) };
650}
651
652impl_attrib_provider_list! {A0 A1}
653impl_attrib_provider_list! {A0 A1 A2}
654impl_attrib_provider_list! {A0 A1 A2 A3}
655impl_attrib_provider_list! {A0 A1 A2 A3 A4}
656impl_attrib_provider_list! {A0 A1 A2 A3 A4 A5}
657
658pub struct DynamicVertexArray<A> {
659    data: Vec<A>,
660    buf: Buffer,
661    buf_len: Cell<usize>,
662    dirty: Cell<bool>,
663}
664
665impl<A: Copy> DynamicVertexArray<A> {
666    pub fn new(gl: &GlContext) -> Result<Self> {
667        Self::from_data(gl, Vec::new())
668    }
669    pub fn gl(&self) -> &GlContext {
670        &self.buf.gl
671    }
672    pub fn from_data(gl: &GlContext, data: Vec<A>) -> Result<Self> {
673        Ok(DynamicVertexArray {
674            data,
675            buf: Buffer::generate(gl)?,
676            buf_len: Cell::new(0),
677            dirty: Cell::new(true),
678        })
679    }
680    pub fn is_empty(&self) -> bool {
681        self.data.is_empty()
682    }
683    pub fn len(&self) -> usize {
684        self.data.len()
685    }
686    pub fn set(&mut self, data: impl Into<Vec<A>>) {
687        self.dirty.set(true);
688        self.data = data.into();
689    }
690    pub fn data(&self) -> &[A] {
691        &self.data[..]
692    }
693    pub fn data_mut(&mut self) -> &mut Vec<A> {
694        self.dirty.set(true);
695        &mut self.data
696    }
697    pub fn sub(&self, range: std::ops::Range<usize>) -> DynamicVertexArraySub<'_, A> {
698        DynamicVertexArraySub { array: self, range }
699    }
700    pub fn bind_buffer(&self, target: u32) {
701        if self.data.is_empty() {
702            return;
703        }
704        unsafe {
705            self.buf.gl.bind_buffer(target, Some(self.buf.id()));
706            if self.dirty.get() {
707                if self.data.len() > self.buf_len.get() {
708                    self.buf.gl.buffer_data_u8_slice(
709                        target,
710                        as_u8_slice(&self.data),
711                        glow::DYNAMIC_DRAW,
712                    );
713                    self.buf_len.set(self.data.len());
714                } else {
715                    self.buf
716                        .gl
717                        .buffer_sub_data_u8_slice(target, 0, as_u8_slice(&self.data));
718                }
719                self.dirty.set(false);
720            }
721        }
722    }
723}
724
725impl<A: Copy> std::ops::Index<usize> for DynamicVertexArray<A> {
726    type Output = A;
727
728    fn index(&self, index: usize) -> &A {
729        &self.data[index]
730    }
731}
732
733impl<A: Copy> std::ops::IndexMut<usize> for DynamicVertexArray<A> {
734    fn index_mut(&mut self, index: usize) -> &mut A {
735        self.dirty.set(true);
736        &mut self.data[index]
737    }
738}
739
740impl<A: AttribProvider> AttribProviderList for &DynamicVertexArray<A> {
741    type KeepType = SmallVec<[EnablerVertexAttribArray; 8]>;
742
743    fn len(&self) -> usize {
744        self.data.len()
745    }
746
747    fn bind(&self, target: u32, p: &Program) -> SmallVec<[EnablerVertexAttribArray; 8]> {
748        let mut vas = SmallVec::new();
749        unsafe {
750            self.bind_buffer(target);
751            for a in &p.attribs {
752                if let Some((size, ty, offs)) = A::apply(&p.gl, a) {
753                    let loc = a.location();
754                    vas.push(EnablerVertexAttribArray::enable(&p.gl, loc));
755                    p.gl.vertex_attrib_pointer_f32(
756                        loc,
757                        size as i32,
758                        ty,
759                        false,
760                        std::mem::size_of::<A>() as i32,
761                        offs as i32,
762                    );
763                }
764            }
765        }
766        vas
767    }
768}
769
770pub struct DynamicVertexArraySub<'a, A: Copy> {
771    array: &'a DynamicVertexArray<A>,
772    range: std::ops::Range<usize>,
773}
774
775impl<A: AttribProvider> AttribProviderList for DynamicVertexArraySub<'_, A> {
776    type KeepType = SmallVec<[EnablerVertexAttribArray; 8]>;
777
778    fn len(&self) -> usize {
779        self.range.len()
780    }
781
782    fn bind(&self, target: u32, p: &Program) -> Self::KeepType {
783        let mut vas = SmallVec::new();
784        unsafe {
785            self.array.bind_buffer(target);
786            for a in &p.attribs {
787                if let Some((size, ty, offs)) = A::apply(&p.gl, a) {
788                    let loc = a.location();
789                    vas.push(EnablerVertexAttribArray::enable(&p.gl, loc));
790                    let offs = offs + std::mem::size_of::<A>() * self.range.start;
791                    p.gl.vertex_attrib_pointer_f32(
792                        loc,
793                        size as i32,
794                        ty,
795                        false,
796                        std::mem::size_of::<A>() as i32,
797                        offs as i32,
798                    );
799                }
800            }
801        }
802        vas
803    }
804}
805
806pub struct Buffer {
807    gl: GlContext,
808    id: glow::Buffer,
809}
810
811impl Drop for Buffer {
812    fn drop(&mut self) {
813        unsafe {
814            self.gl.delete_buffer(self.id);
815        }
816    }
817}
818
819impl Buffer {
820    pub fn generate(gl: &GlContext) -> Result<Buffer> {
821        unsafe {
822            let id = gl.create_buffer().map_err(|_| to_gl_err(gl))?;
823            Ok(Buffer { gl: gl.clone(), id })
824        }
825    }
826    pub fn id(&self) -> glow::Buffer {
827        self.id
828    }
829}
830
831pub struct VertexArray {
832    gl: GlContext,
833    id: glow::VertexArray,
834}
835
836impl Drop for VertexArray {
837    fn drop(&mut self) {
838        unsafe {
839            self.gl.delete_vertex_array(self.id);
840        }
841    }
842}
843
844impl VertexArray {
845    pub fn generate(gl: &GlContext) -> Result<VertexArray> {
846        unsafe {
847            let id = gl.create_vertex_array().map_err(|_| to_gl_err(gl))?;
848            Ok(VertexArray { gl: gl.clone(), id })
849        }
850    }
851    pub fn id(&self) -> glow::VertexArray {
852        self.id
853    }
854}
855
856pub struct Renderbuffer {
857    gl: GlContext,
858    id: glow::Renderbuffer,
859}
860
861impl Drop for Renderbuffer {
862    fn drop(&mut self) {
863        unsafe {
864            self.gl.delete_renderbuffer(self.id);
865        }
866    }
867}
868
869impl Renderbuffer {
870    pub fn generate(gl: &GlContext) -> Result<Renderbuffer> {
871        unsafe {
872            let id = gl.create_renderbuffer().map_err(|_| to_gl_err(gl))?;
873            Ok(Renderbuffer { gl: gl.clone(), id })
874        }
875    }
876    pub fn id(&self) -> glow::Renderbuffer {
877        self.id
878    }
879}
880
881pub struct BinderRenderbuffer(GlContext);
882
883impl BinderRenderbuffer {
884    pub fn none(gl: &GlContext) -> BinderRenderbuffer {
885        BinderRenderbuffer(gl.clone())
886    }
887    pub fn bind(rb: &Renderbuffer) -> BinderRenderbuffer {
888        unsafe {
889            rb.gl.bind_renderbuffer(glow::RENDERBUFFER, Some(rb.id));
890        }
891        BinderRenderbuffer(rb.gl.clone())
892    }
893    pub fn target(&self) -> u32 {
894        glow::RENDERBUFFER
895    }
896    pub fn rebind(&self, rb: &Renderbuffer) {
897        unsafe {
898            rb.gl.bind_renderbuffer(glow::RENDERBUFFER, Some(rb.id));
899        }
900    }
901}
902impl Drop for BinderRenderbuffer {
903    fn drop(&mut self) {
904        unsafe {
905            self.0.bind_renderbuffer(glow::RENDERBUFFER, None);
906        }
907    }
908}
909
910pub struct Framebuffer {
911    gl: GlContext,
912    id: glow::Framebuffer,
913}
914
915impl Drop for Framebuffer {
916    fn drop(&mut self) {
917        unsafe {
918            self.gl.delete_framebuffer(self.id);
919        }
920    }
921}
922
923impl Framebuffer {
924    pub fn generate(gl: &GlContext) -> Result<Framebuffer> {
925        unsafe {
926            let id = gl.create_framebuffer().map_err(|_| to_gl_err(gl))?;
927            Ok(Framebuffer { gl: gl.clone(), id })
928        }
929    }
930    pub fn id(&self) -> glow::Framebuffer {
931        self.id
932    }
933}
934
935pub trait BinderFBOTarget {
936    const TARGET: u32;
937    const GET_BINDING: u32;
938}
939
940pub struct BinderFramebufferT<TGT: BinderFBOTarget> {
941    gl: GlContext,
942    id: Option<glow::Framebuffer>,
943    _pd: PhantomData<TGT>,
944}
945
946impl<TGT: BinderFBOTarget> BinderFramebufferT<TGT> {
947    pub fn none(gl: &GlContext) -> Self {
948        BinderFramebufferT {
949            gl: gl.clone(),
950            id: None,
951            _pd: PhantomData,
952        }
953    }
954    pub fn new(gl: &GlContext) -> Self {
955        #[cfg(not(target_arch = "wasm32"))]
956        let id = unsafe {
957            let id = gl.get_parameter_i32(TGT::GET_BINDING) as u32;
958            std::num::NonZeroU32::new(id).map(glow::NativeFramebuffer)
959        };
960        #[cfg(target_arch = "wasm32")]
961        let id = None;
962        BinderFramebufferT {
963            gl: gl.clone(),
964            id,
965            _pd: PhantomData,
966        }
967    }
968    pub fn target(&self) -> u32 {
969        TGT::TARGET
970    }
971    pub fn bind(fb: &Framebuffer) -> Self {
972        unsafe {
973            fb.gl.bind_framebuffer(TGT::TARGET, Some(fb.id));
974        }
975        BinderFramebufferT {
976            gl: fb.gl.clone(),
977            id: None,
978            _pd: PhantomData,
979        }
980    }
981    pub fn rebind(&self, fb: &Framebuffer) {
982        unsafe {
983            fb.gl.bind_framebuffer(TGT::TARGET, Some(fb.id));
984        }
985    }
986}
987
988impl<TGT: BinderFBOTarget> Drop for BinderFramebufferT<TGT> {
989    fn drop(&mut self) {
990        unsafe {
991            self.gl.bind_framebuffer(TGT::TARGET, self.id);
992        }
993    }
994}
995
996pub struct BinderFBO;
997
998impl BinderFBOTarget for BinderFBO {
999    const TARGET: u32 = glow::FRAMEBUFFER;
1000    const GET_BINDING: u32 = glow::FRAMEBUFFER_BINDING;
1001}
1002
1003pub type BinderFramebuffer = BinderFramebufferT<BinderFBO>;
1004
1005pub struct BinderFBODraw;
1006
1007impl BinderFBOTarget for BinderFBODraw {
1008    const TARGET: u32 = glow::DRAW_FRAMEBUFFER;
1009    const GET_BINDING: u32 = glow::DRAW_FRAMEBUFFER_BINDING;
1010}
1011
1012pub type BinderDrawFramebuffer = BinderFramebufferT<BinderFBODraw>;
1013
1014pub struct BinderFBORead;
1015
1016impl BinderFBOTarget for BinderFBORead {
1017    const TARGET: u32 = glow::READ_FRAMEBUFFER;
1018    const GET_BINDING: u32 = glow::READ_FRAMEBUFFER_BINDING;
1019}
1020
1021pub type BinderReadFramebuffer = BinderFramebufferT<BinderFBORead>;
1022
1023pub unsafe fn as_u8_slice<T>(data: &[T]) -> &[u8] {
1024    unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(data)) }
1025}
1026
1027#[macro_export]
1028macro_rules! uniform {
1029    (
1030        $(
1031            $(#[$a:meta])* $v:vis struct $name:ident {
1032                $(
1033                    $fv:vis $f:ident : $ft:tt
1034                ),*
1035                $(,)?
1036            }
1037        )*
1038    ) => {
1039        $(
1040            $(#[$a])* $v struct $name {
1041                $(
1042                    $fv $f: $ft ,
1043                )*
1044            }
1045            impl $crate::UniformProvider for $name {
1046                fn apply(&self, gl: &$crate::GlContext, u: &$crate::Uniform) {
1047                    let name = u.name();
1048                    $(
1049                        if name == $crate::uniform!{ @NAME $f: $ft }  {
1050                            self.$f.apply(gl, u.location());
1051                            return;
1052                        }
1053                    )*
1054                }
1055            }
1056        )*
1057    };
1058    (@NAME $f:ident : [ $ft:ty; $n:literal ]) => { concat!(stringify!($f), "[0]") };
1059    (@NAME $f:ident : $ft:ty) => { stringify!($f) };
1060}
1061
1062#[macro_export]
1063macro_rules! attrib {
1064    (
1065        $(
1066            $(#[$a:meta])* $v:vis struct $name:ident {
1067                $(
1068                    $fv:vis $f:ident : $ft:ty
1069                ),*
1070                $(,)?
1071            }
1072        )*
1073    ) => {
1074        $(
1075            $(#[$a])* $v struct $name {
1076                $(
1077                    $fv $f: $ft ,
1078                )*
1079            }
1080            unsafe impl $crate::AttribProvider for $name {
1081                fn apply(gl: &$crate::GlContext, a: &$crate::Attribute) -> Option<(usize, u32, usize)> {
1082                    let name = a.name();
1083                    $(
1084                        if name == stringify!($f) {
1085                            let (n, t) = <$ft as $crate::AttribField>::detail();
1086                            return Some((n, t, std::mem::offset_of!($name, $f)));
1087                        }
1088                    )*
1089                    None
1090                }
1091            }
1092        )*
1093    }
1094}