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 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}