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        self[0].apply_array(gl, N * count, location);
624    }
625}
626
627macro_rules! impl_attrib_provider_list {
628    ($($An:ident)*) => {
629        #[allow(non_snake_case)]
630        impl<$($An: AttribProviderList),*> AttribProviderList for ($($An),*) {
631            type KeepType = ($($An::KeepType),*);
632            fn len(&self) -> usize {
633                let ($($An),*) = self;
634                impl_attrib_provider_list!(@MINLEN $($An)*)
635            }
636            fn bind(&self, target: u32, p: &Program) -> Self::KeepType {
637                let ($($An),*) = self;
638                $(
639                    let $An = $An.bind(target, p);
640                )*
641                ($($An),*)
642            }
643        }
644    };
645
646    (@MINLEN $A0:ident) =>  { $A0.len() };
647    (@MINLEN $A0:ident $($An:ident)*) =>  { $A0.len().min(impl_attrib_provider_list!(@MINLEN $($An)*)) };
648}
649
650impl_attrib_provider_list! {A0 A1}
651impl_attrib_provider_list! {A0 A1 A2}
652impl_attrib_provider_list! {A0 A1 A2 A3}
653impl_attrib_provider_list! {A0 A1 A2 A3 A4}
654impl_attrib_provider_list! {A0 A1 A2 A3 A4 A5}
655
656pub struct DynamicVertexArray<A> {
657    data: Vec<A>,
658    buf: Buffer,
659    buf_len: Cell<usize>,
660    dirty: Cell<bool>,
661}
662
663impl<A: Copy> DynamicVertexArray<A> {
664    pub fn new(gl: &GlContext) -> Result<Self> {
665        Self::from_data(gl, Vec::new())
666    }
667    pub fn from_data(gl: &GlContext, data: Vec<A>) -> Result<Self> {
668        Ok(DynamicVertexArray {
669            data,
670            buf: Buffer::generate(gl)?,
671            buf_len: Cell::new(0),
672            dirty: Cell::new(true),
673        })
674    }
675    pub fn is_empty(&self) -> bool {
676        self.data.is_empty()
677    }
678    pub fn len(&self) -> usize {
679        self.data.len()
680    }
681    pub fn set(&mut self, data: impl Into<Vec<A>>) {
682        self.dirty.set(true);
683        self.data = data.into();
684    }
685    pub fn data(&self) -> &[A] {
686        &self.data[..]
687    }
688    pub fn data_mut(&mut self) -> &mut Vec<A> {
689        self.dirty.set(true);
690        &mut self.data
691    }
692    pub fn sub(&self, range: std::ops::Range<usize>) -> DynamicVertexArraySub<'_, A> {
693        DynamicVertexArraySub { array: self, range }
694    }
695    pub fn bind_buffer(&self, target: u32) {
696        if self.data.is_empty() {
697            return;
698        }
699        unsafe {
700            self.buf.gl.bind_buffer(target, Some(self.buf.id()));
701            if self.dirty.get() {
702                if self.data.len() > self.buf_len.get() {
703                    self.buf.gl.buffer_data_u8_slice(
704                        target,
705                        as_u8_slice(&self.data),
706                        glow::DYNAMIC_DRAW,
707                    );
708                    self.buf_len.set(self.data.len());
709                } else {
710                    self.buf
711                        .gl
712                        .buffer_sub_data_u8_slice(target, 0, as_u8_slice(&self.data));
713                }
714                self.dirty.set(false);
715            }
716        }
717    }
718}
719
720impl<A: Copy> std::ops::Index<usize> for DynamicVertexArray<A> {
721    type Output = A;
722
723    fn index(&self, index: usize) -> &A {
724        &self.data[index]
725    }
726}
727
728impl<A: Copy> std::ops::IndexMut<usize> for DynamicVertexArray<A> {
729    fn index_mut(&mut self, index: usize) -> &mut A {
730        self.dirty.set(true);
731        &mut self.data[index]
732    }
733}
734
735impl<A: AttribProvider> AttribProviderList for &DynamicVertexArray<A> {
736    type KeepType = SmallVec<[EnablerVertexAttribArray; 8]>;
737
738    fn len(&self) -> usize {
739        self.data.len()
740    }
741
742    fn bind(&self, target: u32, p: &Program) -> SmallVec<[EnablerVertexAttribArray; 8]> {
743        let mut vas = SmallVec::new();
744        unsafe {
745            self.bind_buffer(target);
746            for a in &p.attribs {
747                if let Some((size, ty, offs)) = A::apply(&p.gl, a) {
748                    let loc = a.location();
749                    vas.push(EnablerVertexAttribArray::enable(&p.gl, loc));
750                    p.gl.vertex_attrib_pointer_f32(
751                        loc,
752                        size as i32,
753                        ty,
754                        false,
755                        std::mem::size_of::<A>() as i32,
756                        offs as i32,
757                    );
758                }
759            }
760        }
761        vas
762    }
763}
764
765pub struct DynamicVertexArraySub<'a, A: Copy> {
766    array: &'a DynamicVertexArray<A>,
767    range: std::ops::Range<usize>,
768}
769
770impl<A: AttribProvider> AttribProviderList for DynamicVertexArraySub<'_, A> {
771    type KeepType = SmallVec<[EnablerVertexAttribArray; 8]>;
772
773    fn len(&self) -> usize {
774        self.range.len()
775    }
776
777    fn bind(&self, target: u32, p: &Program) -> Self::KeepType {
778        let mut vas = SmallVec::new();
779        unsafe {
780            self.array.bind_buffer(target);
781            for a in &p.attribs {
782                if let Some((size, ty, offs)) = A::apply(&p.gl, a) {
783                    let loc = a.location();
784                    vas.push(EnablerVertexAttribArray::enable(&p.gl, loc));
785                    let offs = offs + std::mem::size_of::<A>() * self.range.start;
786                    p.gl.vertex_attrib_pointer_f32(
787                        loc,
788                        size as i32,
789                        ty,
790                        false,
791                        std::mem::size_of::<A>() as i32,
792                        offs as i32,
793                    );
794                }
795            }
796        }
797        vas
798    }
799}
800
801pub struct Buffer {
802    gl: GlContext,
803    id: glow::Buffer,
804}
805
806impl Drop for Buffer {
807    fn drop(&mut self) {
808        unsafe {
809            self.gl.delete_buffer(self.id);
810        }
811    }
812}
813
814impl Buffer {
815    pub fn generate(gl: &GlContext) -> Result<Buffer> {
816        unsafe {
817            let id = gl.create_buffer().map_err(|_| to_gl_err(gl))?;
818            Ok(Buffer { gl: gl.clone(), id })
819        }
820    }
821    pub fn id(&self) -> glow::Buffer {
822        self.id
823    }
824}
825
826pub struct VertexArray {
827    gl: GlContext,
828    id: glow::VertexArray,
829}
830
831impl Drop for VertexArray {
832    fn drop(&mut self) {
833        unsafe {
834            self.gl.delete_vertex_array(self.id);
835        }
836    }
837}
838
839impl VertexArray {
840    pub fn generate(gl: &GlContext) -> Result<VertexArray> {
841        unsafe {
842            let id = gl.create_vertex_array().map_err(|_| to_gl_err(gl))?;
843            Ok(VertexArray { gl: gl.clone(), id })
844        }
845    }
846    pub fn id(&self) -> glow::VertexArray {
847        self.id
848    }
849}
850
851pub struct Renderbuffer {
852    gl: GlContext,
853    id: glow::Renderbuffer,
854}
855
856impl Drop for Renderbuffer {
857    fn drop(&mut self) {
858        unsafe {
859            self.gl.delete_renderbuffer(self.id);
860        }
861    }
862}
863
864impl Renderbuffer {
865    pub fn generate(gl: &GlContext) -> Result<Renderbuffer> {
866        unsafe {
867            let id = gl.create_renderbuffer().map_err(|_| to_gl_err(gl))?;
868            Ok(Renderbuffer { gl: gl.clone(), id })
869        }
870    }
871    pub fn id(&self) -> glow::Renderbuffer {
872        self.id
873    }
874}
875
876pub struct BinderRenderbuffer(GlContext);
877
878impl BinderRenderbuffer {
879    pub fn none(gl: &GlContext) -> BinderRenderbuffer {
880        BinderRenderbuffer(gl.clone())
881    }
882    pub fn bind(rb: &Renderbuffer) -> BinderRenderbuffer {
883        unsafe {
884            rb.gl.bind_renderbuffer(glow::RENDERBUFFER, Some(rb.id));
885        }
886        BinderRenderbuffer(rb.gl.clone())
887    }
888    pub fn target(&self) -> u32 {
889        glow::RENDERBUFFER
890    }
891    pub fn rebind(&self, rb: &Renderbuffer) {
892        unsafe {
893            rb.gl.bind_renderbuffer(glow::RENDERBUFFER, Some(rb.id));
894        }
895    }
896}
897impl Drop for BinderRenderbuffer {
898    fn drop(&mut self) {
899        unsafe {
900            self.0.bind_renderbuffer(glow::RENDERBUFFER, None);
901        }
902    }
903}
904
905pub struct Framebuffer {
906    gl: GlContext,
907    id: glow::Framebuffer,
908}
909
910impl Drop for Framebuffer {
911    fn drop(&mut self) {
912        unsafe {
913            self.gl.delete_framebuffer(self.id);
914        }
915    }
916}
917
918impl Framebuffer {
919    pub fn generate(gl: &GlContext) -> Result<Framebuffer> {
920        unsafe {
921            let id = gl.create_framebuffer().map_err(|_| to_gl_err(gl))?;
922            Ok(Framebuffer { gl: gl.clone(), id })
923        }
924    }
925    pub fn id(&self) -> glow::Framebuffer {
926        self.id
927    }
928}
929
930pub trait BinderFBOTarget {
931    const TARGET: u32;
932    const GET_BINDING: u32;
933}
934
935pub struct BinderFramebufferT<TGT: BinderFBOTarget> {
936    gl: GlContext,
937    id: Option<glow::Framebuffer>,
938    _pd: PhantomData<TGT>,
939}
940
941impl<TGT: BinderFBOTarget> BinderFramebufferT<TGT> {
942    pub fn none(gl: &GlContext) -> Self {
943        BinderFramebufferT {
944            gl: gl.clone(),
945            id: None,
946            _pd: PhantomData,
947        }
948    }
949    pub fn new(gl: &GlContext) -> Self {
950        #[cfg(not(target_arch = "wasm32"))]
951        let id = unsafe {
952            let id = gl.get_parameter_i32(TGT::GET_BINDING) as u32;
953            std::num::NonZeroU32::new(id).map(glow::NativeFramebuffer)
954        };
955        #[cfg(target_arch = "wasm32")]
956        let id = None;
957        BinderFramebufferT {
958            gl: gl.clone(),
959            id,
960            _pd: PhantomData,
961        }
962    }
963    pub fn target(&self) -> u32 {
964        TGT::TARGET
965    }
966    pub fn bind(fb: &Framebuffer) -> Self {
967        unsafe {
968            fb.gl.bind_framebuffer(TGT::TARGET, Some(fb.id));
969        }
970        BinderFramebufferT {
971            gl: fb.gl.clone(),
972            id: None,
973            _pd: PhantomData,
974        }
975    }
976    pub fn rebind(&self, fb: &Framebuffer) {
977        unsafe {
978            fb.gl.bind_framebuffer(TGT::TARGET, Some(fb.id));
979        }
980    }
981}
982
983impl<TGT: BinderFBOTarget> Drop for BinderFramebufferT<TGT> {
984    fn drop(&mut self) {
985        unsafe {
986            self.gl.bind_framebuffer(TGT::TARGET, self.id);
987        }
988    }
989}
990
991pub struct BinderFBO;
992
993impl BinderFBOTarget for BinderFBO {
994    const TARGET: u32 = glow::FRAMEBUFFER;
995    const GET_BINDING: u32 = glow::FRAMEBUFFER_BINDING;
996}
997
998pub type BinderFramebuffer = BinderFramebufferT<BinderFBO>;
999
1000pub struct BinderFBODraw;
1001
1002impl BinderFBOTarget for BinderFBODraw {
1003    const TARGET: u32 = glow::DRAW_FRAMEBUFFER;
1004    const GET_BINDING: u32 = glow::DRAW_FRAMEBUFFER_BINDING;
1005}
1006
1007pub type BinderDrawFramebuffer = BinderFramebufferT<BinderFBODraw>;
1008
1009pub struct BinderFBORead;
1010
1011impl BinderFBOTarget for BinderFBORead {
1012    const TARGET: u32 = glow::READ_FRAMEBUFFER;
1013    const GET_BINDING: u32 = glow::READ_FRAMEBUFFER_BINDING;
1014}
1015
1016pub type BinderReadFramebuffer = BinderFramebufferT<BinderFBORead>;
1017
1018pub unsafe fn as_u8_slice<T>(data: &[T]) -> &[u8] {
1019    std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(data))
1020}
1021
1022#[macro_export]
1023macro_rules! uniform {
1024    (
1025        $(
1026            $(#[$a:meta])* $v:vis struct $name:ident {
1027                $(
1028                    $fv:vis $f:ident : $ft:tt
1029                ),*
1030                $(,)?
1031            }
1032        )*
1033    ) => {
1034        $(
1035            $(#[$a])* $v struct $name {
1036                $(
1037                    $fv $f: $ft ,
1038                )*
1039            }
1040            impl $crate::UniformProvider for $name {
1041                fn apply(&self, gl: &$crate::GlContext, u: &$crate::Uniform) {
1042                    let name = u.name();
1043                    $(
1044                        if name == $crate::uniform!{ @NAME $f: $ft }  {
1045                            self.$f.apply(gl, u.location());
1046                            return;
1047                        }
1048                    )*
1049                }
1050            }
1051        )*
1052    };
1053    (@NAME $f:ident : [ $ft:ty; $n:literal ]) => { concat!(stringify!($f), "[0]") };
1054    (@NAME $f:ident : $ft:ty) => { stringify!($f) };
1055}
1056
1057#[macro_export]
1058macro_rules! attrib {
1059    (
1060        $(
1061            $(#[$a:meta])* $v:vis struct $name:ident {
1062                $(
1063                    $fv:vis $f:ident : $ft:ty
1064                ),*
1065                $(,)?
1066            }
1067        )*
1068    ) => {
1069        $(
1070            $(#[$a])* $v struct $name {
1071                $(
1072                    $fv $f: $ft ,
1073                )*
1074            }
1075            unsafe impl $crate::AttribProvider for $name {
1076                fn apply(gl: &$crate::GlContext, a: &$crate::Attribute) -> Option<(usize, u32, usize)> {
1077                    let name = a.name();
1078                    $(
1079                        if name == stringify!($f) {
1080                            let (n, t) = <$ft as $crate::AttribField>::detail();
1081                            return Some((n, t, std::mem::offset_of!($name, $f)));
1082                        }
1083                    )*
1084                    None
1085                }
1086            }
1087        )*
1088    }
1089}