1#![allow(clippy::missing_safety_doc)]
6
7pub 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
28pub 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 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 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 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 #[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
363pub 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#[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
395impl<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
429pub 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
502pub 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}