1#![allow(unused_variables)]
5use alloc::{
6 boxed::Box,
7 rc::Rc,
8 string::{String, ToString},
9 vec::Vec,
10};
11use core::{
12 ffi, fmt,
13 hash::{Hash, Hasher},
14 mem::ManuallyDrop,
15 sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
16};
17
18use azul_css::{
19 props::{
20 basic::{ColorF, ColorU},
21 style::StyleTransformVec,
22 },
23 AzString, OptionI32, OptionU32, OptionUsize, StringVec, U8Vec,
24};
25pub use gl_context_loader::{
26 ctypes::*, gl, GLeglImageOES, GLsync, GLvoid, GenericGlContext, GlType as GlContextGlType,
27};
28
29pub use crate::glconst::*;
30use crate::{
31 geom::PhysicalSizeU32,
32 hit_test::DocumentId,
33 resources::{
34 Brush, Epoch, ExternalImageId, ImageDescriptor, ImageDescriptorFlags, RawImage,
35 RawImageData, RawImageFormat,
36 },
37 svg::{TessellatedGPUSvgNode, TessellatedSvgNode},
38 window::RendererType,
39 OrderedMap,
40};
41
42pub type GLuint = u32;
43pub type GLint = i32;
44pub type GLint64 = i64;
45pub type GLuint64 = u64;
46pub type GLenum = u32;
47pub type GLintptr = isize;
48pub type GLboolean = u8;
49pub type GLsizeiptr = isize;
50pub type GLbitfield = u32;
51pub type GLsizei = i32;
52pub type GLclampf = f32;
53pub type GLfloat = f32;
54
55pub const GL_RESTART_INDEX: u32 = core::u32::MAX;
56
57#[repr(C)]
60#[derive(Debug)]
61pub struct GlVoidPtrConst {
62 pub ptr: *const GLvoid,
63 pub run_destructor: bool,
64}
65
66impl Clone for GlVoidPtrConst {
67 fn clone(&self) -> Self {
68 Self {
69 ptr: self.ptr,
70 run_destructor: true,
71 }
72 }
73}
74
75impl Drop for GlVoidPtrConst {
76 fn drop(&mut self) {
77 self.run_destructor = false;
78 }
79}
80
81#[repr(C)]
86#[derive(Debug)]
87pub struct GlVoidPtrMut {
88 pub ptr: *mut GLvoid,
89}
90
91impl Clone for GlVoidPtrMut {
92 fn clone(&self) -> Self {
93 Self { ptr: self.ptr }
94 }
95}
96
97#[repr(C)]
99pub struct Refstr {
100 pub ptr: *const u8,
101 pub len: usize,
102}
103
104impl Clone for Refstr {
105 fn clone(&self) -> Self {
106 Self {
107 ptr: self.ptr,
108 len: self.len,
109 }
110 }
111}
112
113impl fmt::Debug for Refstr {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 self.as_str().fmt(f)
116 }
117}
118
119impl Refstr {
120 #[must_use]
121 pub const fn as_str(&self) -> &str {
122 if self.ptr.is_null() || self.len == 0 {
126 return "";
127 }
128 unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(self.ptr, self.len)) }
129 }
130}
131
132impl From<&str> for Refstr {
133 fn from(s: &str) -> Self {
134 Self {
135 ptr: s.as_ptr(),
136 len: s.len(),
137 }
138 }
139}
140
141#[repr(C)]
143pub struct RefstrVecRef {
144 pub ptr: *const Refstr,
145 pub len: usize,
146}
147
148impl Clone for RefstrVecRef {
149 fn clone(&self) -> Self {
150 Self {
151 ptr: self.ptr,
152 len: self.len,
153 }
154 }
155}
156
157impl fmt::Debug for RefstrVecRef {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 self.as_slice().fmt(f)
160 }
161}
162
163impl RefstrVecRef {
164 #[must_use]
165 pub const fn as_slice(&self) -> &[Refstr] {
166 if self.ptr.is_null() || self.len == 0 {
168 return &[];
169 }
170 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
171 }
172}
173
174impl From<&[Refstr]> for RefstrVecRef {
175 fn from(s: &[Refstr]) -> Self {
176 Self {
177 ptr: s.as_ptr(),
178 len: s.len(),
179 }
180 }
181}
182
183#[repr(C)]
185pub struct GLint64VecRefMut {
186 pub ptr: *mut i64,
187 pub len: usize,
188}
189
190impl Clone for GLint64VecRefMut {
191 fn clone(&self) -> Self {
192 Self {
193 ptr: self.ptr,
194 len: self.len,
195 }
196 }
197}
198
199impl fmt::Debug for GLint64VecRefMut {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 self.as_slice().fmt(f)
202 }
203}
204
205impl From<&mut [GLint64]> for GLint64VecRefMut {
206 fn from(s: &mut [GLint64]) -> Self {
207 Self {
208 ptr: s.as_mut_ptr(),
209 len: s.len(),
210 }
211 }
212}
213
214impl GLint64VecRefMut {
215 #[must_use]
216 pub const fn as_slice(&self) -> &[GLint64] {
217 if self.ptr.is_null() || self.len == 0 {
219 return &[];
220 }
221 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
222 }
223 const fn as_mut_slice(&mut self) -> &mut [GLint64] {
224 if self.ptr.is_null() || self.len == 0 {
226 return &mut [];
227 }
228 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
229 }
230}
231
232#[repr(C)]
234pub struct GLfloatVecRefMut {
235 pub ptr: *mut f32,
236 pub len: usize,
237}
238
239impl Clone for GLfloatVecRefMut {
240 fn clone(&self) -> Self {
241 Self {
242 ptr: self.ptr,
243 len: self.len,
244 }
245 }
246}
247
248impl fmt::Debug for GLfloatVecRefMut {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 self.as_slice().fmt(f)
251 }
252}
253
254impl From<&mut [GLfloat]> for GLfloatVecRefMut {
255 fn from(s: &mut [GLfloat]) -> Self {
256 Self {
257 ptr: s.as_mut_ptr(),
258 len: s.len(),
259 }
260 }
261}
262
263impl GLfloatVecRefMut {
264 #[must_use]
265 pub const fn as_slice(&self) -> &[GLfloat] {
266 if self.ptr.is_null() || self.len == 0 {
268 return &[];
269 }
270 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
271 }
272 const fn as_mut_slice(&mut self) -> &mut [GLfloat] {
273 if self.ptr.is_null() || self.len == 0 {
275 return &mut [];
276 }
277 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
278 }
279}
280
281#[repr(C)]
283pub struct GLintVecRefMut {
284 pub ptr: *mut i32,
285 pub len: usize,
286}
287
288impl Clone for GLintVecRefMut {
289 fn clone(&self) -> Self {
290 Self {
291 ptr: self.ptr,
292 len: self.len,
293 }
294 }
295}
296
297impl fmt::Debug for GLintVecRefMut {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 self.as_slice().fmt(f)
300 }
301}
302
303impl From<&mut [GLint]> for GLintVecRefMut {
304 fn from(s: &mut [GLint]) -> Self {
305 Self {
306 ptr: s.as_mut_ptr(),
307 len: s.len(),
308 }
309 }
310}
311
312impl GLintVecRefMut {
313 #[must_use]
314 pub const fn as_slice(&self) -> &[GLint] {
315 if self.ptr.is_null() || self.len == 0 {
317 return &[];
318 }
319 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
320 }
321 const fn as_mut_slice(&mut self) -> &mut [GLint] {
322 if self.ptr.is_null() || self.len == 0 {
324 return &mut [];
325 }
326 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
327 }
328}
329
330#[repr(C)]
332pub struct GLuintVecRef {
333 pub ptr: *const u32,
334 pub len: usize,
335}
336
337impl Clone for GLuintVecRef {
338 fn clone(&self) -> Self {
339 Self {
340 ptr: self.ptr,
341 len: self.len,
342 }
343 }
344}
345
346impl fmt::Debug for GLuintVecRef {
347 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348 self.as_slice().fmt(f)
349 }
350}
351
352impl From<&[GLuint]> for GLuintVecRef {
353 fn from(s: &[GLuint]) -> Self {
354 Self {
355 ptr: s.as_ptr(),
356 len: s.len(),
357 }
358 }
359}
360
361impl GLuintVecRef {
362 #[must_use]
363 pub const fn as_slice(&self) -> &[GLuint] {
364 if self.ptr.is_null() || self.len == 0 {
366 return &[];
367 }
368 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
369 }
370}
371
372#[repr(C)]
374pub struct GLenumVecRef {
375 pub ptr: *const u32,
376 pub len: usize,
377}
378
379impl Clone for GLenumVecRef {
380 fn clone(&self) -> Self {
381 Self {
382 ptr: self.ptr,
383 len: self.len,
384 }
385 }
386}
387
388impl fmt::Debug for GLenumVecRef {
389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390 self.as_slice().fmt(f)
391 }
392}
393
394impl From<&[GLenum]> for GLenumVecRef {
395 fn from(s: &[GLenum]) -> Self {
396 Self {
397 ptr: s.as_ptr(),
398 len: s.len(),
399 }
400 }
401}
402
403impl GLenumVecRef {
404 #[must_use]
405 pub const fn as_slice(&self) -> &[GLenum] {
406 if self.ptr.is_null() || self.len == 0 {
408 return &[];
409 }
410 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
411 }
412}
413
414#[repr(C)]
416pub struct U8VecRef {
417 pub ptr: *const u8,
418 pub len: usize,
419}
420
421impl Clone for U8VecRef {
422 fn clone(&self) -> Self {
423 Self {
424 ptr: self.ptr,
425 len: self.len,
426 }
427 }
428}
429
430impl From<&[u8]> for U8VecRef {
431 fn from(s: &[u8]) -> Self {
432 Self {
433 ptr: s.as_ptr(),
434 len: s.len(),
435 }
436 }
437}
438
439impl U8VecRef {
440 #[must_use]
441 pub const fn as_slice(&self) -> &[u8] {
442 if self.ptr.is_null() || self.len == 0 {
444 return &[];
445 }
446 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
447 }
448}
449
450impl fmt::Debug for U8VecRef {
451 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452 self.as_slice().fmt(f)
453 }
454}
455
456impl PartialOrd for U8VecRef {
457 fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
458 self.as_slice().partial_cmp(rhs.as_slice())
459 }
460}
461
462impl Ord for U8VecRef {
463 fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
464 self.as_slice().cmp(rhs.as_slice())
465 }
466}
467
468impl PartialEq for U8VecRef {
469 fn eq(&self, rhs: &Self) -> bool {
470 self.as_slice().eq(rhs.as_slice())
471 }
472}
473
474impl Eq for U8VecRef {}
475
476impl Hash for U8VecRef {
477 fn hash<H>(&self, state: &mut H)
478 where
479 H: Hasher,
480 {
481 self.as_slice().hash(state);
482 }
483}
484
485#[repr(C)]
487pub struct F32VecRef {
488 pub ptr: *const f32,
489 pub len: usize,
490}
491
492impl Clone for F32VecRef {
493 fn clone(&self) -> Self {
494 Self {
495 ptr: self.ptr,
496 len: self.len,
497 }
498 }
499}
500
501impl fmt::Debug for F32VecRef {
502 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
503 self.as_slice().fmt(f)
504 }
505}
506
507impl From<&[f32]> for F32VecRef {
508 fn from(s: &[f32]) -> Self {
509 Self {
510 ptr: s.as_ptr(),
511 len: s.len(),
512 }
513 }
514}
515
516impl F32VecRef {
517 #[must_use]
518 pub const fn as_slice(&self) -> &[f32] {
519 if self.ptr.is_null() || self.len == 0 {
521 return &[];
522 }
523 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
524 }
525}
526
527#[repr(C)]
529pub struct I32VecRef {
530 pub ptr: *const i32,
531 pub len: usize,
532}
533
534impl Clone for I32VecRef {
535 fn clone(&self) -> Self {
536 Self {
537 ptr: self.ptr,
538 len: self.len,
539 }
540 }
541}
542
543impl fmt::Debug for I32VecRef {
544 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
545 self.as_slice().fmt(f)
546 }
547}
548
549impl From<&[i32]> for I32VecRef {
550 fn from(s: &[i32]) -> Self {
551 Self {
552 ptr: s.as_ptr(),
553 len: s.len(),
554 }
555 }
556}
557
558impl I32VecRef {
559 #[must_use]
560 pub const fn as_slice(&self) -> &[i32] {
561 if self.ptr.is_null() || self.len == 0 {
563 return &[];
564 }
565 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
566 }
567}
568
569#[repr(C)]
571pub struct GLbooleanVecRefMut {
572 pub ptr: *mut u8,
573 pub len: usize,
574}
575
576impl Clone for GLbooleanVecRefMut {
577 fn clone(&self) -> Self {
578 Self {
579 ptr: self.ptr,
580 len: self.len,
581 }
582 }
583}
584
585impl fmt::Debug for GLbooleanVecRefMut {
586 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587 self.as_slice().fmt(f)
588 }
589}
590
591impl From<&mut [GLboolean]> for GLbooleanVecRefMut {
592 fn from(s: &mut [GLboolean]) -> Self {
593 Self {
594 ptr: s.as_mut_ptr(),
595 len: s.len(),
596 }
597 }
598}
599
600impl GLbooleanVecRefMut {
601 #[must_use]
602 pub const fn as_slice(&self) -> &[GLboolean] {
603 if self.ptr.is_null() || self.len == 0 {
605 return &[];
606 }
607 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
608 }
609 const fn as_mut_slice(&mut self) -> &mut [GLboolean] {
610 if self.ptr.is_null() || self.len == 0 {
612 return &mut [];
613 }
614 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
615 }
616}
617
618#[repr(C)]
620pub struct U8VecRefMut {
621 pub ptr: *mut u8,
622 pub len: usize,
623}
624
625impl Clone for U8VecRefMut {
626 fn clone(&self) -> Self {
627 Self {
628 ptr: self.ptr,
629 len: self.len,
630 }
631 }
632}
633
634impl fmt::Debug for U8VecRefMut {
635 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
636 self.as_slice().fmt(f)
637 }
638}
639
640impl From<&mut [u8]> for U8VecRefMut {
641 fn from(s: &mut [u8]) -> Self {
642 Self {
643 ptr: s.as_mut_ptr(),
644 len: s.len(),
645 }
646 }
647}
648
649impl U8VecRefMut {
650 #[must_use]
651 pub const fn as_slice(&self) -> &[u8] {
652 if self.ptr.is_null() || self.len == 0 {
654 return &[];
655 }
656 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
657 }
658 const fn as_mut_slice(&mut self) -> &mut [u8] {
659 if self.ptr.is_null() || self.len == 0 {
661 return &mut [];
662 }
663 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
664 }
665}
666
667impl_option!(
668 U8VecRef,
669 OptionU8VecRef,
670 copy = false,
671 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
672);
673
674#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
675#[repr(C)]
676pub struct DebugMessage {
677 pub message: AzString,
678 pub source: GLenum,
679 pub ty: GLenum,
680 pub id: GLenum,
681 pub severity: GLenum,
682}
683
684impl_option!(
685 DebugMessage,
686 OptionDebugMessage,
687 copy = false,
688 [Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash]
689);
690
691impl_vec!(
692 DebugMessage,
693 DebugMessageVec,
694 DebugMessageVecDestructor,
695 DebugMessageVecDestructorType,
696 DebugMessageVecSlice,
697 OptionDebugMessage
698);
699impl_vec_debug!(DebugMessage, DebugMessageVec);
700impl_vec_partialord!(DebugMessage, DebugMessageVec);
701impl_vec_ord!(DebugMessage, DebugMessageVec);
702impl_vec_clone!(DebugMessage, DebugMessageVec, DebugMessageVecDestructor);
703impl_vec_partialeq!(DebugMessage, DebugMessageVec);
704impl_vec_eq!(DebugMessage, DebugMessageVec);
705impl_vec_hash!(DebugMessage, DebugMessageVec);
706
707impl_vec!(
708 GLint,
709 GLintVec,
710 GLintVecDestructor,
711 GLintVecDestructorType,
712 GLintVecSlice,
713 OptionI32
714);
715impl_vec_debug!(GLint, GLintVec);
716impl_vec_partialord!(GLint, GLintVec);
717impl_vec_ord!(GLint, GLintVec);
718impl_vec_clone!(GLint, GLintVec, GLintVecDestructor);
719impl_vec_partialeq!(GLint, GLintVec);
720impl_vec_eq!(GLint, GLintVec);
721impl_vec_hash!(GLint, GLintVec);
722
723impl_vec!(
724 GLuint,
725 GLuintVec,
726 GLuintVecDestructor,
727 GLuintVecDestructorType,
728 GLuintVecSlice,
729 OptionU32
730);
731impl_vec_debug!(GLuint, GLuintVec);
732impl_vec_partialord!(GLuint, GLuintVec);
733impl_vec_ord!(GLuint, GLuintVec);
734impl_vec_clone!(GLuint, GLuintVec, GLuintVecDestructor);
735impl_vec_partialeq!(GLuint, GLuintVec);
736impl_vec_eq!(GLuint, GLuintVec);
737impl_vec_hash!(GLuint, GLuintVec);
738
739#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
740#[repr(C)]
741pub enum GlType {
742 Gl,
743 Gles,
744}
745
746impl From<GlContextGlType> for GlType {
747 fn from(a: GlContextGlType) -> Self {
748 match a {
749 GlContextGlType::Gl => Self::Gl,
750 GlContextGlType::GlEs => Self::Gles,
751 }
752 }
753}
754
755#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
757#[repr(C)]
758#[allow(clippy::pub_underscore_fields)]
760pub struct GetProgramBinaryReturn {
761 pub _0: U8Vec,
762 pub _1: u32,
763}
764
765#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
767#[repr(C)]
768#[allow(clippy::pub_underscore_fields)]
770pub struct GetActiveAttribReturn {
771 pub _0: i32,
772 pub _1: u32,
773 pub _2: AzString,
774}
775
776#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
778#[repr(C)]
779#[allow(clippy::pub_underscore_fields)]
781pub struct GetActiveUniformReturn {
782 pub _0: i32,
783 pub _1: u32,
784 pub _2: AzString,
785}
786
787#[repr(C)]
788pub struct GLsyncPtr {
789 pub ptr: *const c_void, pub run_destructor: bool,
791}
792
793impl Clone for GLsyncPtr {
794 fn clone(&self) -> Self {
795 Self {
796 ptr: self.ptr,
797 run_destructor: true,
798 }
799 }
800}
801
802impl fmt::Debug for GLsyncPtr {
803 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
804 write!(f, "0x{:0x}", self.ptr as usize)
805 }
806}
807
808impl GLsyncPtr {
809 #[must_use]
810 pub const fn new(p: GLsync) -> Self {
811 Self {
812 ptr: p,
813 run_destructor: true,
814 }
815 }
816 #[must_use]
817 pub fn get(self) -> GLsync {
818 self.ptr as GLsync
819 }
820}
821
822impl Drop for GLsyncPtr {
823 fn drop(&mut self) {
824 self.run_destructor = false;
825 }
826}
827
828pub type GlTextureStorage = OrderedMap<Epoch, OrderedMap<ExternalImageId, Texture>>;
831
832static mut ACTIVE_GL_TEXTURES: Option<OrderedMap<DocumentId, GlTextureStorage>> = None;
849
850#[inline]
861#[allow(clippy::deref_addrof)] fn active_gl_textures() -> &'static mut Option<OrderedMap<DocumentId, GlTextureStorage>> {
863 unsafe { &mut *(&raw mut ACTIVE_GL_TEXTURES) }
866}
867
868#[must_use]
877pub fn insert_into_active_gl_textures(
878 document_id: DocumentId,
879 epoch: Epoch,
880 texture: Texture,
881) -> ExternalImageId {
882 let external_image_id = ExternalImageId::new();
883
884 let active = active_gl_textures();
885 if active.is_none() {
886 *active = Some(OrderedMap::new());
887 }
888 let active_textures = active.as_mut().unwrap();
889 let active_epochs = active_textures.entry(document_id).or_default();
890 let active_textures_for_epoch = active_epochs.entry(epoch).or_default();
891 active_textures_for_epoch.insert(external_image_id, texture);
892
893 external_image_id
894}
895
896pub fn gl_textures_remove_epochs_from_pipeline(document_id: &DocumentId, epoch: Epoch) {
899 let Some(active_textures) = active_gl_textures().as_mut() else {
901 return;
902 };
903
904 let Some(active_epochs) = active_textures.get_mut(document_id) else {
905 return;
906 };
907
908 let mut epochs_to_remove = Vec::new();
911
912 for (gl_texture_epoch, _) in active_epochs.iter() {
913 if *gl_texture_epoch < epoch {
914 epochs_to_remove.push(*gl_texture_epoch);
915 }
916 }
917
918 for epoch in epochs_to_remove {
919 active_epochs.remove(&epoch);
920 }
921}
922
923#[must_use]
925pub fn remove_single_texture_from_active_gl_textures(
926 document_id: &DocumentId,
927 epoch: &Epoch,
928 external_image_id: &ExternalImageId,
929) -> Option<()> {
930 let active_textures = active_gl_textures().as_mut()?;
931 let epochs = active_textures.get_mut(document_id)?;
932 let images_in_epoch = epochs.get_mut(epoch)?;
933 images_in_epoch.remove(external_image_id);
934 Some(())
935}
936
937pub fn gl_textures_remove_active_pipeline(document_id: &DocumentId) {
939 let Some(active_textures) = active_gl_textures().as_mut() else {
940 return;
941 };
942 active_textures.remove(document_id);
943}
944
945#[allow(clippy::cast_precision_loss)] pub fn gl_textures_clear_opengl_cache() {
948 *active_gl_textures() = None;
949}
950
951#[allow(clippy::cast_precision_loss)] #[must_use]
963pub fn get_opengl_texture(image_key: &ExternalImageId) -> Option<(GLuint, (f32, f32))> {
964 let active_textures = active_gl_textures().as_ref()?;
965 active_textures
966 .values()
967 .flat_map(|active_document| active_document.values())
968 .find_map(|active_epoch| active_epoch.get(image_key))
969 .map(|tex| {
970 (
971 tex.texture_id,
972 (tex.size.width as f32, tex.size.height as f32),
973 )
974 })
975}
976
977#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd)]
979#[repr(C)]
980#[allow(clippy::pub_underscore_fields)]
982pub struct GlShaderPrecisionFormatReturn {
983 pub _0: GLint,
984 pub _1: GLint,
985 pub _2: GLint,
986}
987
988#[repr(C)]
989pub struct GlContextPtr {
990 pub ptr: ManuallyDrop<Box<Rc<GlContextPtrInner>>>,
999 pub renderer_type: RendererType,
1001 pub run_destructor: bool,
1002}
1003
1004impl Clone for GlContextPtr {
1005 fn clone(&self) -> Self {
1006 Self {
1007 ptr: ManuallyDrop::new((*self.ptr).clone()),
1008 renderer_type: self.renderer_type,
1009 run_destructor: true,
1010 }
1011 }
1012}
1013
1014impl Drop for GlContextPtr {
1015 fn drop(&mut self) {
1016 if self.run_destructor {
1021 self.run_destructor = false;
1022 unsafe {
1023 ManuallyDrop::drop(&mut self.ptr);
1024 }
1025 }
1026 }
1027}
1028
1029impl GlContextPtr {
1030 #[must_use]
1031 pub fn get_svg_shader(&self) -> GLuint {
1032 self.ptr.svg_shader
1033 }
1034 #[must_use]
1040 pub fn is_gl_usable(&self) -> bool {
1041 self.ptr.svg_shader != 0
1042 }
1043 #[must_use]
1047 pub fn get_usable_glsl_version(&self) -> AzString {
1048 self.ptr.glsl_version.clone()
1049 }
1050 #[must_use]
1052 pub fn get_brush_shader(&self) -> GLuint {
1053 self.ptr.brush_shader
1054 }
1055 #[must_use]
1056 pub fn get_fxaa_shader(&self) -> GLuint {
1057 self.ptr.fxaa_shader
1058 }
1059}
1060
1061#[repr(C)]
1062pub struct GlContextPtrInner {
1063 pub ptr: Rc<GenericGlContext>,
1064 pub svg_shader: GLuint,
1066 pub svg_multicolor_shader: GLuint,
1068 pub fxaa_shader: GLuint,
1070 pub brush_shader: GLuint,
1072 pub glsl_version: AzString,
1075}
1076
1077impl fmt::Debug for GlContextPtrInner {
1078 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1080 f.debug_struct("GlContextPtrInner")
1081 .field("svg_shader", &self.svg_shader)
1082 .field("svg_multicolor_shader", &self.svg_multicolor_shader)
1083 .field("fxaa_shader", &self.fxaa_shader)
1084 .field("brush_shader", &self.brush_shader)
1085 .field("glsl_version", &self.glsl_version)
1086 .finish_non_exhaustive()
1087 }
1088}
1089
1090impl Drop for GlContextPtrInner {
1091 fn drop(&mut self) {
1092 self.ptr.delete_program(self.svg_shader);
1093 self.ptr.delete_program(self.svg_multicolor_shader);
1094 self.ptr.delete_program(self.fxaa_shader);
1095 if self.brush_shader != 0 {
1096 self.ptr.delete_program(self.brush_shader);
1097 }
1098 }
1099}
1100
1101impl_option!(
1102 GlContextPtr,
1103 OptionGlContextPtr,
1104 copy = false,
1105 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord]
1106);
1107
1108impl fmt::Debug for GlContextPtr {
1109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1110 write!(f, "0x{:0x}", self.as_usize())
1111 }
1112}
1113
1114static SVG_VERTEX_SHADER: &[u8] = b"#version 150
1115
1116#if __VERSION__ != 100
1117 #define varying out
1118 #define attribute in
1119#endif
1120
1121uniform vec2 vBboxSize;
1122uniform mat4 vTransformMatrix;
1123
1124attribute vec2 vAttrXY;
1125
1126void main() {
1127 vec4 vTransposed = vec4(vAttrXY, 1.0, 1.0) * vTransformMatrix;
1128 vec2 vTransposedInScreen = vTransposed.xy / vBboxSize;
1129 vec2 vCalcFinal = (vTransposedInScreen * vec2(2.0)) - vec2(1.0);
1130 gl_Position = vec4(vCalcFinal, 1.0, 1.0);
1131}";
1132
1133static SVG_FRAGMENT_SHADER: &[u8] = b"#version 150
1134
1135precision highp float;
1136
1137uniform vec4 fDrawColor;
1138
1139#if __VERSION__ == 100
1140 #define oFragColor gl_FragColor
1141#else
1142 out vec4 oFragColor;
1143#endif
1144
1145void main() {
1146 oFragColor = fDrawColor;
1147}";
1148
1149static SVG_MULTICOLOR_VERTEX_SHADER: &[u8] = b"#version 150
1150
1151#if __VERSION__ != 100
1152 #define varying out
1153 #define attribute in
1154#endif
1155
1156uniform vec2 vBboxSize;
1157uniform mat4 vTransformMatrix;
1158
1159attribute vec3 vAttrXY;
1160attribute vec4 vColor;
1161varying vec4 fColor;
1162
1163void main() {
1164 vec4 vTransposed = vec4(vAttrXY.xy, 1.0, 1.0) * vTransformMatrix;
1165 vec2 vTransposedInScreen = vTransposed.xy / vBboxSize;
1166 vec2 vCalcFinal = (vTransposedInScreen * vec2(2.0)) - vec2(1.0);
1167 gl_Position = vec4(vCalcFinal, vAttrXY.z, 1.0);
1168 fColor = vColor;
1169}";
1170
1171static SVG_MULTICOLOR_FRAGMENT_SHADER: &[u8] = b"#version 150
1172
1173precision highp float;
1174
1175#if __VERSION__ != 100
1176 #define varying in
1177#endif
1178
1179#if __VERSION__ == 100
1180 #define oFragColor gl_FragColor
1181#else
1182 out vec4 oFragColor;
1183#endif
1184
1185varying vec4 fColor;
1186
1187void main() {
1188 oFragColor = fColor;
1189}";
1190
1191static BRUSH_VERTEX_SHADER: &[u8] = b"#version 150
1196
1197#if __VERSION__ != 100
1198 #define varying out
1199 #define attribute in
1200#endif
1201
1202attribute vec2 aPos;
1203attribute vec2 aUv;
1204varying vec2 vUv;
1205
1206void main() {
1207 vUv = aUv;
1208 gl_Position = vec4(aPos, 0.0, 1.0);
1209}";
1210
1211static BRUSH_FRAGMENT_SHADER: &[u8] = b"#version 150
1212
1213precision highp float;
1214
1215#if __VERSION__ != 100
1216 #define varying in
1217#endif
1218
1219#if __VERSION__ == 100
1220 #define oFragColor gl_FragColor
1221#else
1222 out vec4 oFragColor;
1223#endif
1224
1225uniform vec4 uColor; // rgb + alpha (alpha already folds in flow * color.a)
1226uniform float uHardness; // 0 = soft .. 1 = hard edge
1227
1228varying vec2 vUv;
1229
1230void main() {
1231 float d = length(vUv);
1232 if (d > 1.0) { discard; }
1233 float edge0 = clamp(uHardness, 0.0, 1.0);
1234 float x = clamp((d - edge0) / max(1.0 - edge0, 1.0e-4), 0.0, 1.0);
1235 float cov = 1.0 - (x * x * (3.0 - 2.0 * x));
1236 oFragColor = vec4(uColor.rgb, uColor.a * cov);
1237}";
1238
1239#[allow(dead_code)]
1243#[allow(clippy::used_underscore_binding)] #[allow(clippy::cast_possible_wrap)] fn check_shader_compile(gl_context: &GenericGlContext, shader: GLuint, _label: &str) {
1246 let mut status = [0_i32];
1247 unsafe { gl_context.get_shader_iv(shader, gl::COMPILE_STATUS, &mut status) };
1248 if status[0] != gl::TRUE as i32 {
1249 #[cfg(feature = "std")]
1250 {
1251 let log = gl_context.get_shader_info_log(shader);
1252 eprintln!("azul: {_label} shader compile error: {log}");
1253 }
1254 }
1255}
1256
1257#[allow(dead_code)]
1259#[allow(clippy::used_underscore_binding)] #[allow(clippy::cast_possible_wrap)] fn check_program_link(gl_context: &GenericGlContext, program: GLuint, _label: &str) {
1262 let mut status = [0_i32];
1263 unsafe { gl_context.get_program_iv(program, gl::LINK_STATUS, &mut status) };
1264 if status[0] != gl::TRUE as i32 {
1265 #[cfg(feature = "std")]
1266 {
1267 let log = gl_context.get_program_info_log(program);
1268 eprintln!("azul: {_label} program link error: {log}");
1269 }
1270 }
1271}
1272
1273#[cfg(feature = "std")]
1277fn shader_with_glsl_version(src: &[u8], version_line: &[u8]) -> Vec<u8> {
1278 let body_start = src.iter().position(|&b| b == b'\n').map_or(0, |i| i + 1);
1279 let mut out = Vec::with_capacity(version_line.len() + src.len() - body_start);
1280 out.extend_from_slice(version_line);
1281 out.extend_from_slice(&src[body_start..]);
1282 out
1283}
1284
1285#[cfg(feature = "std")]
1292#[allow(clippy::cast_possible_wrap)]
1294fn try_compile_program(
1295 gl_context: &GenericGlContext,
1296 vert_src: &[u8],
1297 frag_src: &[u8],
1298 version_line: &[u8],
1299 attribs: &[(u32, &str)],
1300) -> Option<GLuint> {
1301 let vs = gl_context.create_shader(gl::VERTEX_SHADER);
1302 gl_context.shader_source(
1303 vs,
1304 &[shader_with_glsl_version(vert_src, version_line).as_slice()],
1305 );
1306 gl_context.compile_shader(vs);
1307 let fs = gl_context.create_shader(gl::FRAGMENT_SHADER);
1308 gl_context.shader_source(
1309 fs,
1310 &[shader_with_glsl_version(frag_src, version_line).as_slice()],
1311 );
1312 gl_context.compile_shader(fs);
1313
1314 let mut s = [0_i32];
1315 unsafe { gl_context.get_shader_iv(vs, gl::COMPILE_STATUS, &mut s) };
1316 let vs_ok = s[0] == gl::TRUE as i32;
1317 unsafe { gl_context.get_shader_iv(fs, gl::COMPILE_STATUS, &mut s) };
1318 let fs_ok = s[0] == gl::TRUE as i32;
1319 if !vs_ok || !fs_ok {
1320 gl_context.delete_shader(vs);
1321 gl_context.delete_shader(fs);
1322 return None;
1323 }
1324
1325 let prog = gl_context.create_program();
1326 gl_context.attach_shader(prog, vs);
1327 gl_context.attach_shader(prog, fs);
1328 for (loc, name) in attribs {
1329 gl_context.bind_attrib_location(prog, *loc, name);
1330 }
1331 gl_context.link_program(prog);
1332 gl_context.delete_shader(vs);
1333 gl_context.delete_shader(fs);
1334
1335 let mut l = [0_i32];
1336 unsafe { gl_context.get_program_iv(prog, gl::LINK_STATUS, &mut l) };
1337 if l[0] == gl::TRUE as i32 {
1338 Some(prog)
1339 } else {
1340 gl_context.delete_program(prog);
1341 None
1342 }
1343}
1344
1345const fn glsl_version_candidates(gl_type: GlType) -> &'static [&'static [u8]] {
1348 match gl_type {
1349 GlType::Gl => &[b"#version 150\n", b"#version 330\n", b"#version 140\n"],
1350 GlType::Gles => &[b"#version 300 es\n", b"#version 100\n"],
1351 }
1352}
1353
1354impl GlContextPtr {
1355 #[must_use]
1356 pub fn new(renderer_type: RendererType, gl_context: Rc<GenericGlContext>) -> Self {
1357 #[cfg(feature = "std")]
1368 let (
1369 svg_program_id,
1370 svg_multicolor_program_id,
1371 fxaa_program_id,
1372 brush_program_id,
1373 glsl_version,
1374 ) = if matches!(renderer_type, RendererType::Hardware) {
1375 use crate::gl_fxaa::{FXAA_FRAGMENT_SHADER, FXAA_VERTEX_SHADER};
1376 let gl_type: GlType = gl_context.get_type().into();
1377 let mut svg = 0;
1379 let mut chosen: Option<&'static [u8]> = None;
1380 for ver in glsl_version_candidates(gl_type) {
1381 if let Some(p) = try_compile_program(
1382 &gl_context,
1383 SVG_VERTEX_SHADER,
1384 SVG_FRAGMENT_SHADER,
1385 ver,
1386 &[(0, "vAttrXY")],
1387 ) {
1388 svg = p;
1389 chosen = Some(ver);
1390 break;
1391 }
1392 }
1393 chosen.map_or_else(|| {
1394 eprintln!(
1395 "azul: GL context UNUSABLE -- no GLSL version ({gl_type:?}) compiled the SVG \
1396 shaders; the window should fall back to CPU rendering (is_gl_usable()=false)"
1397 );
1398 (0, 0, 0, 0, AzString::from_const_str(""))
1399 }, |ver| {
1400 let ver_str: AzString = core::str::from_utf8(ver)
1402 .unwrap_or("")
1403 .trim()
1404 .trim_start_matches("#version ")
1405 .into();
1406 eprintln!(
1407 "azul: GL usable -- shaders compiled at GLSL {} ({:?})",
1408 ver_str.as_str(),
1409 gl_type
1410 );
1411 let mc = try_compile_program(
1412 &gl_context, SVG_MULTICOLOR_VERTEX_SHADER, SVG_MULTICOLOR_FRAGMENT_SHADER,
1413 ver, &[(0, "vAttrXY"), (1, "vColor")],
1414 ).unwrap_or(0);
1415 let fxaa = try_compile_program(
1416 &gl_context, FXAA_VERTEX_SHADER, FXAA_FRAGMENT_SHADER, ver, &[(0, "vAttrXY")],
1417 ).unwrap_or(0);
1418 let brush = try_compile_program(
1419 &gl_context, BRUSH_VERTEX_SHADER, BRUSH_FRAGMENT_SHADER, ver,
1420 &[(0, "aPos"), (1, "aUv")],
1421 ).unwrap_or(0);
1422 (svg, mc, fxaa, brush, ver_str)
1423 })
1424 } else {
1425 (0, 0, 0, 0, AzString::from_const_str(""))
1426 };
1427 #[cfg(not(feature = "std"))]
1429 let (
1430 svg_program_id,
1431 svg_multicolor_program_id,
1432 fxaa_program_id,
1433 brush_program_id,
1434 glsl_version,
1435 ) = (0u32, 0u32, 0u32, 0u32, AzString::from_const_str(""));
1436
1437 Self {
1438 ptr: ManuallyDrop::new(Box::new(Rc::new(GlContextPtrInner {
1439 svg_shader: svg_program_id,
1440 svg_multicolor_shader: svg_multicolor_program_id,
1441 fxaa_shader: fxaa_program_id,
1442 brush_shader: brush_program_id,
1443 glsl_version,
1444 ptr: gl_context,
1445 }))),
1446 renderer_type,
1447 run_destructor: true,
1448 }
1449 }
1450
1451 #[must_use]
1452 pub fn get(&self) -> &Rc<GenericGlContext> {
1453 &self.ptr.ptr
1454 }
1455 fn as_usize(&self) -> usize {
1456 (Rc::as_ptr(&self.ptr.ptr) as *const c_void) as usize
1457 }
1458}
1459
1460#[allow(clippy::needless_pass_by_value)]
1465impl GlContextPtr {
1466 #[must_use]
1467 pub fn get_type(&self) -> GlType {
1468 self.get().get_type().into()
1469 }
1470 pub fn buffer_data_untyped(
1471 &self,
1472 target: GLenum,
1473 size: GLsizeiptr,
1474 data: GlVoidPtrConst,
1475 usage: GLenum,
1476 ) {
1477 self.get()
1478 .buffer_data_untyped(target, size, data.ptr, usage);
1479 }
1480 pub fn buffer_sub_data_untyped(
1481 &self,
1482 target: GLenum,
1483 offset: isize,
1484 size: GLsizeiptr,
1485 data: GlVoidPtrConst,
1486 ) {
1487 self.get()
1488 .buffer_sub_data_untyped(target, offset, size, data.ptr);
1489 }
1490 #[must_use]
1491 pub fn map_buffer(&self, target: GLenum, access: GLbitfield) -> GlVoidPtrMut {
1492 GlVoidPtrMut {
1493 ptr: self.get().map_buffer(target, access),
1494 }
1495 }
1496 #[must_use]
1497 pub fn map_buffer_range(
1498 &self,
1499 target: GLenum,
1500 offset: GLintptr,
1501 length: GLsizeiptr,
1502 access: GLbitfield,
1503 ) -> GlVoidPtrMut {
1504 GlVoidPtrMut {
1505 ptr: self.get().map_buffer_range(target, offset, length, access),
1506 }
1507 }
1508 #[must_use]
1509 pub fn unmap_buffer(&self, target: GLenum) -> GLboolean {
1510 self.get().unmap_buffer(target)
1511 }
1512 pub fn tex_buffer(&self, target: GLenum, internal_format: GLenum, buffer: GLuint) {
1513 self.get().tex_buffer(target, internal_format, buffer);
1514 }
1515 pub fn shader_source(&self, shader: GLuint, strings: StringVec) {
1516 fn str_to_bytes(input: &str) -> Vec<u8> {
1517 let mut v: Vec<u8> = input.into();
1518 v.push(0);
1519 v
1520 }
1521 let shaders_as_bytes = strings
1522 .iter()
1523 .map(|s| str_to_bytes(s.as_str()))
1524 .collect::<Vec<_>>();
1525 let shaders_as_bytes = shaders_as_bytes
1526 .iter()
1527 .map(AsRef::as_ref)
1528 .collect::<Vec<_>>();
1529 self.get().shader_source(shader, &shaders_as_bytes);
1530 }
1531 pub fn read_buffer(&self, mode: GLenum) {
1532 self.get().read_buffer(mode);
1533 }
1534 pub fn read_pixels_into_buffer(
1535 &self,
1536 x: GLint,
1537 y: GLint,
1538 width: GLsizei,
1539 height: GLsizei,
1540 format: GLenum,
1541 pixel_type: GLenum,
1542 mut dst_buffer: U8VecRefMut,
1543 ) {
1544 self.get().read_pixels_into_buffer(
1545 x,
1546 y,
1547 width,
1548 height,
1549 format,
1550 pixel_type,
1551 dst_buffer.as_mut_slice(),
1552 );
1553 }
1554 #[must_use]
1555 pub fn read_pixels(
1556 &self,
1557 x: GLint,
1558 y: GLint,
1559 width: GLsizei,
1560 height: GLsizei,
1561 format: GLenum,
1562 pixel_type: GLenum,
1563 ) -> U8Vec {
1564 let channels: usize = match format {
1571 0x1903 | 0x1906 | 0x1909 | 0x1902 | 0x1901 | 0x8D94 => 1,
1573 0x8227 | 0x190A | 0x8228 | 0x84F9 => 2,
1575 0x1907 | 0x80E0 | 0x8D98 => 3,
1577 _ => 4,
1579 };
1580 let bytes_per_component: usize = match pixel_type {
1581 0x1400 | 0x1401 => 1, 0x1402 | 0x1403 | 0x140B => 2, _ => 4, };
1585 #[allow(clippy::cast_sign_loss)]
1587 let len = (width.max(0) as usize)
1588 .saturating_mul(height.max(0) as usize)
1589 .saturating_mul(channels)
1590 .saturating_mul(bytes_per_component);
1591 let mut buf = vec![0u8; len];
1592 self.get().read_pixels_into_buffer(
1593 x,
1594 y,
1595 width,
1596 height,
1597 format,
1598 pixel_type,
1599 buf.as_mut_slice(),
1600 );
1601 buf.into()
1602 }
1603 pub fn read_pixels_into_pbo(
1604 &self,
1605 x: GLint,
1606 y: GLint,
1607 width: GLsizei,
1608 height: GLsizei,
1609 format: GLenum,
1610 pixel_type: GLenum,
1611 ) {
1612 unsafe {
1613 self.get()
1614 .read_pixels_into_pbo(x, y, width, height, format, pixel_type);
1615 }
1616 }
1617 pub fn sample_coverage(&self, value: GLclampf, invert: bool) {
1618 self.get().sample_coverage(value, invert);
1619 }
1620 pub fn polygon_offset(&self, factor: GLfloat, units: GLfloat) {
1621 self.get().polygon_offset(factor, units);
1622 }
1623 pub fn pixel_store_i(&self, name: GLenum, param: GLint) {
1624 self.get().pixel_store_i(name, param);
1625 }
1626 #[must_use]
1627 pub fn gen_buffers(&self, n: GLsizei) -> GLuintVec {
1628 self.get().gen_buffers(n).into()
1629 }
1630 #[must_use]
1631 pub fn gen_renderbuffers(&self, n: GLsizei) -> GLuintVec {
1632 self.get().gen_renderbuffers(n).into()
1633 }
1634 #[must_use]
1635 pub fn gen_framebuffers(&self, n: GLsizei) -> GLuintVec {
1636 self.get().gen_framebuffers(n).into()
1637 }
1638 #[must_use]
1639 pub fn gen_textures(&self, n: GLsizei) -> GLuintVec {
1640 self.get().gen_textures(n).into()
1641 }
1642 #[must_use]
1643 pub fn gen_vertex_arrays(&self, n: GLsizei) -> GLuintVec {
1644 self.get().gen_vertex_arrays(n).into()
1645 }
1646 #[must_use]
1647 pub fn gen_queries(&self, n: GLsizei) -> GLuintVec {
1648 self.get().gen_queries(n).into()
1649 }
1650 pub fn begin_query(&self, target: GLenum, id: GLuint) {
1651 self.get().begin_query(target, id);
1652 }
1653 pub fn end_query(&self, target: GLenum) {
1654 self.get().end_query(target);
1655 }
1656 pub fn query_counter(&self, id: GLuint, target: GLenum) {
1657 self.get().query_counter(id, target);
1658 }
1659 #[must_use]
1660 pub fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 {
1661 self.get().get_query_object_iv(id, pname)
1662 }
1663 #[must_use]
1664 pub fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 {
1665 self.get().get_query_object_uiv(id, pname)
1666 }
1667 #[must_use]
1668 pub fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 {
1669 self.get().get_query_object_i64v(id, pname)
1670 }
1671 #[must_use]
1672 pub fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 {
1673 self.get().get_query_object_ui64v(id, pname)
1674 }
1675 pub fn delete_queries(&self, queries: GLuintVecRef) {
1676 self.get().delete_queries(queries.as_slice());
1677 }
1678 pub fn delete_vertex_arrays(&self, vertex_arrays: GLuintVecRef) {
1679 self.get().delete_vertex_arrays(vertex_arrays.as_slice());
1680 }
1681 pub fn delete_buffers(&self, buffers: GLuintVecRef) {
1682 self.get().delete_buffers(buffers.as_slice());
1683 }
1684 pub fn delete_renderbuffers(&self, renderbuffers: GLuintVecRef) {
1685 self.get().delete_renderbuffers(renderbuffers.as_slice());
1686 }
1687 pub fn delete_framebuffers(&self, framebuffers: GLuintVecRef) {
1688 self.get().delete_framebuffers(framebuffers.as_slice());
1689 }
1690 pub fn delete_textures(&self, textures: GLuintVecRef) {
1691 self.get().delete_textures(textures.as_slice());
1692 }
1693 pub fn framebuffer_renderbuffer(
1694 &self,
1695 target: GLenum,
1696 attachment: GLenum,
1697 renderbuffertarget: GLenum,
1698 renderbuffer: GLuint,
1699 ) {
1700 self.get()
1701 .framebuffer_renderbuffer(target, attachment, renderbuffertarget, renderbuffer);
1702 }
1703 pub fn renderbuffer_storage(
1704 &self,
1705 target: GLenum,
1706 internalformat: GLenum,
1707 width: GLsizei,
1708 height: GLsizei,
1709 ) {
1710 self.get()
1711 .renderbuffer_storage(target, internalformat, width, height);
1712 }
1713 pub fn depth_func(&self, func: GLenum) {
1714 self.get().depth_func(func);
1715 }
1716 pub fn active_texture(&self, texture: GLenum) {
1717 self.get().active_texture(texture);
1718 }
1719 pub fn attach_shader(&self, program: GLuint, shader: GLuint) {
1720 self.get().attach_shader(program, shader);
1721 }
1722 pub fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
1723 self.get().bind_attrib_location(program, index, name);
1724 }
1725 pub fn get_uniform_iv(&self, program: GLuint, location: GLint, mut result: GLintVecRefMut) {
1726 unsafe {
1727 self.get()
1728 .get_uniform_iv(program, location, result.as_mut_slice());
1729 }
1730 }
1731 pub fn get_uniform_fv(&self, program: GLuint, location: GLint, mut result: GLfloatVecRefMut) {
1732 unsafe {
1733 self.get()
1734 .get_uniform_fv(program, location, result.as_mut_slice());
1735 }
1736 }
1737 #[must_use]
1738 pub fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
1739 self.get().get_uniform_block_index(program, name)
1740 }
1741 #[must_use]
1742 pub fn get_uniform_indices(&self, program: GLuint, names: RefstrVecRef) -> GLuintVec {
1743 let names_vec = names
1744 .as_slice()
1745 .iter()
1746 .map(Refstr::as_str)
1747 .collect::<Vec<_>>();
1748 self.get().get_uniform_indices(program, &names_vec).into()
1749 }
1750 pub fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) {
1751 self.get().bind_buffer_base(target, index, buffer);
1752 }
1753 pub fn bind_buffer_range(
1754 &self,
1755 target: GLenum,
1756 index: GLuint,
1757 buffer: GLuint,
1758 offset: GLintptr,
1759 size: GLsizeiptr,
1760 ) {
1761 self.get()
1762 .bind_buffer_range(target, index, buffer, offset, size);
1763 }
1764 pub fn uniform_block_binding(
1765 &self,
1766 program: GLuint,
1767 uniform_block_index: GLuint,
1768 uniform_block_binding: GLuint,
1769 ) {
1770 self.get()
1771 .uniform_block_binding(program, uniform_block_index, uniform_block_binding);
1772 }
1773 pub fn bind_buffer(&self, target: GLenum, buffer: GLuint) {
1774 self.get().bind_buffer(target, buffer);
1775 }
1776 pub fn bind_vertex_array(&self, vao: GLuint) {
1777 self.get().bind_vertex_array(vao);
1778 }
1779 pub fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) {
1780 self.get().bind_renderbuffer(target, renderbuffer);
1781 }
1782 pub fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) {
1783 self.get().bind_framebuffer(target, framebuffer);
1784 }
1785 pub fn bind_texture(&self, target: GLenum, texture: GLuint) {
1786 self.get().bind_texture(target, texture);
1787 }
1788 pub fn draw_buffers(&self, bufs: GLenumVecRef) {
1789 self.get().draw_buffers(bufs.as_slice());
1790 }
1791 pub fn tex_image_2d(
1792 &self,
1793 target: GLenum,
1794 level: GLint,
1795 internal_format: GLint,
1796 width: GLsizei,
1797 height: GLsizei,
1798 border: GLint,
1799 format: GLenum,
1800 ty: GLenum,
1801 opt_data: OptionU8VecRef,
1802 ) {
1803 let opt_data = opt_data.as_option();
1804 let opt_data: Option<&[u8]> = opt_data.map(U8VecRef::as_slice);
1805 self.get().tex_image_2d(
1806 target,
1807 level,
1808 internal_format,
1809 width,
1810 height,
1811 border,
1812 format,
1813 ty,
1814 opt_data,
1815 );
1816 }
1817 pub fn compressed_tex_image_2d(
1818 &self,
1819 target: GLenum,
1820 level: GLint,
1821 internal_format: GLenum,
1822 width: GLsizei,
1823 height: GLsizei,
1824 border: GLint,
1825 data: U8VecRef,
1826 ) {
1827 self.get().compressed_tex_image_2d(
1828 target,
1829 level,
1830 internal_format,
1831 width,
1832 height,
1833 border,
1834 data.as_slice(),
1835 );
1836 }
1837 pub fn compressed_tex_sub_image_2d(
1838 &self,
1839 target: GLenum,
1840 level: GLint,
1841 xoffset: GLint,
1842 yoffset: GLint,
1843 width: GLsizei,
1844 height: GLsizei,
1845 format: GLenum,
1846 data: U8VecRef,
1847 ) {
1848 self.get().compressed_tex_sub_image_2d(
1849 target,
1850 level,
1851 xoffset,
1852 yoffset,
1853 width,
1854 height,
1855 format,
1856 data.as_slice(),
1857 );
1858 }
1859 pub fn tex_image_3d(
1860 &self,
1861 target: GLenum,
1862 level: GLint,
1863 internal_format: GLint,
1864 width: GLsizei,
1865 height: GLsizei,
1866 depth: GLsizei,
1867 border: GLint,
1868 format: GLenum,
1869 ty: GLenum,
1870 opt_data: OptionU8VecRef,
1871 ) {
1872 let opt_data = opt_data.as_option();
1873 let opt_data: Option<&[u8]> = opt_data.map(U8VecRef::as_slice);
1874 self.get().tex_image_3d(
1875 target,
1876 level,
1877 internal_format,
1878 width,
1879 height,
1880 depth,
1881 border,
1882 format,
1883 ty,
1884 opt_data,
1885 );
1886 }
1887 pub fn copy_tex_image_2d(
1888 &self,
1889 target: GLenum,
1890 level: GLint,
1891 internal_format: GLenum,
1892 x: GLint,
1893 y: GLint,
1894 width: GLsizei,
1895 height: GLsizei,
1896 border: GLint,
1897 ) {
1898 self.get()
1899 .copy_tex_image_2d(target, level, internal_format, x, y, width, height, border);
1900 }
1901 pub fn copy_tex_sub_image_2d(
1902 &self,
1903 target: GLenum,
1904 level: GLint,
1905 xoffset: GLint,
1906 yoffset: GLint,
1907 x: GLint,
1908 y: GLint,
1909 width: GLsizei,
1910 height: GLsizei,
1911 ) {
1912 self.get()
1913 .copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height);
1914 }
1915 pub fn copy_tex_sub_image_3d(
1916 &self,
1917 target: GLenum,
1918 level: GLint,
1919 xoffset: GLint,
1920 yoffset: GLint,
1921 zoffset: GLint,
1922 x: GLint,
1923 y: GLint,
1924 width: GLsizei,
1925 height: GLsizei,
1926 ) {
1927 self.get().copy_tex_sub_image_3d(
1928 target, level, xoffset, yoffset, zoffset, x, y, width, height,
1929 );
1930 }
1931 pub fn tex_sub_image_2d(
1932 &self,
1933 target: GLenum,
1934 level: GLint,
1935 xoffset: GLint,
1936 yoffset: GLint,
1937 width: GLsizei,
1938 height: GLsizei,
1939 format: GLenum,
1940 ty: GLenum,
1941 data: U8VecRef,
1942 ) {
1943 self.get().tex_sub_image_2d(
1944 target,
1945 level,
1946 xoffset,
1947 yoffset,
1948 width,
1949 height,
1950 format,
1951 ty,
1952 data.as_slice(),
1953 );
1954 }
1955 pub fn tex_sub_image_2d_pbo(
1956 &self,
1957 target: GLenum,
1958 level: GLint,
1959 xoffset: GLint,
1960 yoffset: GLint,
1961 width: GLsizei,
1962 height: GLsizei,
1963 format: GLenum,
1964 ty: GLenum,
1965 offset: usize,
1966 ) {
1967 self.get().tex_sub_image_2d_pbo(
1968 target, level, xoffset, yoffset, width, height, format, ty, offset,
1969 );
1970 }
1971 pub fn tex_sub_image_3d(
1972 &self,
1973 target: GLenum,
1974 level: GLint,
1975 xoffset: GLint,
1976 yoffset: GLint,
1977 zoffset: GLint,
1978 width: GLsizei,
1979 height: GLsizei,
1980 depth: GLsizei,
1981 format: GLenum,
1982 ty: GLenum,
1983 data: U8VecRef,
1984 ) {
1985 self.get().tex_sub_image_3d(
1986 target,
1987 level,
1988 xoffset,
1989 yoffset,
1990 zoffset,
1991 width,
1992 height,
1993 depth,
1994 format,
1995 ty,
1996 data.as_slice(),
1997 );
1998 }
1999 pub fn tex_sub_image_3d_pbo(
2000 &self,
2001 target: GLenum,
2002 level: GLint,
2003 xoffset: GLint,
2004 yoffset: GLint,
2005 zoffset: GLint,
2006 width: GLsizei,
2007 height: GLsizei,
2008 depth: GLsizei,
2009 format: GLenum,
2010 ty: GLenum,
2011 offset: usize,
2012 ) {
2013 self.get().tex_sub_image_3d_pbo(
2014 target, level, xoffset, yoffset, zoffset, width, height, depth, format, ty, offset,
2015 );
2016 }
2017 pub fn tex_storage_2d(
2018 &self,
2019 target: GLenum,
2020 levels: GLint,
2021 internal_format: GLenum,
2022 width: GLsizei,
2023 height: GLsizei,
2024 ) {
2025 self.get()
2026 .tex_storage_2d(target, levels, internal_format, width, height);
2027 }
2028 pub fn tex_storage_3d(
2029 &self,
2030 target: GLenum,
2031 levels: GLint,
2032 internal_format: GLenum,
2033 width: GLsizei,
2034 height: GLsizei,
2035 depth: GLsizei,
2036 ) {
2037 self.get()
2038 .tex_storage_3d(target, levels, internal_format, width, height, depth);
2039 }
2040 pub fn get_tex_image_into_buffer(
2041 &self,
2042 target: GLenum,
2043 level: GLint,
2044 format: GLenum,
2045 ty: GLenum,
2046 mut output: U8VecRefMut,
2047 ) {
2048 self.get()
2049 .get_tex_image_into_buffer(target, level, format, ty, output.as_mut_slice());
2050 }
2051 pub fn copy_image_sub_data(
2052 &self,
2053 src_name: GLuint,
2054 src_target: GLenum,
2055 src_level: GLint,
2056 src_x: GLint,
2057 src_y: GLint,
2058 src_z: GLint,
2059 dst_name: GLuint,
2060 dst_target: GLenum,
2061 dst_level: GLint,
2062 dst_x: GLint,
2063 dst_y: GLint,
2064 dst_z: GLint,
2065 src_width: GLsizei,
2066 src_height: GLsizei,
2067 src_depth: GLsizei,
2068 ) {
2069 unsafe {
2070 self.get().copy_image_sub_data(
2071 src_name, src_target, src_level, src_x, src_y, src_z, dst_name, dst_target,
2072 dst_level, dst_x, dst_y, dst_z, src_width, src_height, src_depth,
2073 );
2074 }
2075 }
2076 pub fn invalidate_framebuffer(&self, target: GLenum, attachments: GLenumVecRef) {
2077 self.get()
2078 .invalidate_framebuffer(target, attachments.as_slice());
2079 }
2080 pub fn invalidate_sub_framebuffer(
2081 &self,
2082 target: GLenum,
2083 attachments: GLenumVecRef,
2084 xoffset: GLint,
2085 yoffset: GLint,
2086 width: GLsizei,
2087 height: GLsizei,
2088 ) {
2089 self.get().invalidate_sub_framebuffer(
2090 target,
2091 attachments.as_slice(),
2092 xoffset,
2093 yoffset,
2094 width,
2095 height,
2096 );
2097 }
2098 pub fn get_integer_v(&self, name: GLenum, mut result: GLintVecRefMut) {
2099 unsafe { self.get().get_integer_v(name, result.as_mut_slice()) }
2100 }
2101 pub fn get_integer_64v(&self, name: GLenum, mut result: GLint64VecRefMut) {
2102 unsafe { self.get().get_integer_64v(name, result.as_mut_slice()) }
2103 }
2104 pub fn get_integer_iv(&self, name: GLenum, index: GLuint, mut result: GLintVecRefMut) {
2105 unsafe {
2106 self.get()
2107 .get_integer_iv(name, index, result.as_mut_slice());
2108 }
2109 }
2110 pub fn get_integer_64iv(&self, name: GLenum, index: GLuint, mut result: GLint64VecRefMut) {
2111 unsafe {
2112 self.get()
2113 .get_integer_64iv(name, index, result.as_mut_slice());
2114 }
2115 }
2116 pub fn get_boolean_v(&self, name: GLenum, mut result: GLbooleanVecRefMut) {
2117 unsafe { self.get().get_boolean_v(name, result.as_mut_slice()) }
2118 }
2119 pub fn get_float_v(&self, name: GLenum, mut result: GLfloatVecRefMut) {
2120 unsafe { self.get().get_float_v(name, result.as_mut_slice()) }
2121 }
2122 #[must_use]
2123 pub fn get_framebuffer_attachment_parameter_iv(
2124 &self,
2125 target: GLenum,
2126 attachment: GLenum,
2127 pname: GLenum,
2128 ) -> GLint {
2129 self.get()
2130 .get_framebuffer_attachment_parameter_iv(target, attachment, pname)
2131 }
2132 #[must_use]
2133 pub fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
2134 self.get().get_renderbuffer_parameter_iv(target, pname)
2135 }
2136 #[must_use]
2137 pub fn get_tex_parameter_iv(&self, target: GLenum, name: GLenum) -> GLint {
2138 self.get().get_tex_parameter_iv(target, name)
2139 }
2140 #[must_use]
2141 pub fn get_tex_parameter_fv(&self, target: GLenum, name: GLenum) -> GLfloat {
2142 self.get().get_tex_parameter_fv(target, name)
2143 }
2144 pub fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
2145 self.get().tex_parameter_i(target, pname, param);
2146 }
2147 pub fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
2148 self.get().tex_parameter_f(target, pname, param);
2149 }
2150 pub fn framebuffer_texture_2d(
2151 &self,
2152 target: GLenum,
2153 attachment: GLenum,
2154 textarget: GLenum,
2155 texture: GLuint,
2156 level: GLint,
2157 ) {
2158 self.get()
2159 .framebuffer_texture_2d(target, attachment, textarget, texture, level);
2160 }
2161 pub fn framebuffer_texture_layer(
2162 &self,
2163 target: GLenum,
2164 attachment: GLenum,
2165 texture: GLuint,
2166 level: GLint,
2167 layer: GLint,
2168 ) {
2169 self.get()
2170 .framebuffer_texture_layer(target, attachment, texture, level, layer);
2171 }
2172 #[allow(clippy::similar_names)] pub fn blit_framebuffer(
2174 &self,
2175 src_x0: GLint,
2176 src_y0: GLint,
2177 src_x1: GLint,
2178 src_y1: GLint,
2179 dst_x0: GLint,
2180 dst_y0: GLint,
2181 dst_x1: GLint,
2182 dst_y1: GLint,
2183 mask: GLbitfield,
2184 filter: GLenum,
2185 ) {
2186 self.get().blit_framebuffer(
2187 src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
2188 );
2189 }
2190 pub fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
2191 self.get().vertex_attrib_4f(index, x, y, z, w);
2192 }
2193 pub fn vertex_attrib_pointer_f32(
2194 &self,
2195 index: GLuint,
2196 size: GLint,
2197 normalized: bool,
2198 stride: GLsizei,
2199 offset: GLuint,
2200 ) {
2201 self.get()
2202 .vertex_attrib_pointer_f32(index, size, normalized, stride, offset);
2203 }
2204 pub fn vertex_attrib_pointer(
2205 &self,
2206 index: GLuint,
2207 size: GLint,
2208 type_: GLenum,
2209 normalized: bool,
2210 stride: GLsizei,
2211 offset: GLuint,
2212 ) {
2213 self.get()
2214 .vertex_attrib_pointer(index, size, type_, normalized, stride, offset);
2215 }
2216 pub fn vertex_attrib_i_pointer(
2217 &self,
2218 index: GLuint,
2219 size: GLint,
2220 type_: GLenum,
2221 stride: GLsizei,
2222 offset: GLuint,
2223 ) {
2224 self.get()
2225 .vertex_attrib_i_pointer(index, size, type_, stride, offset);
2226 }
2227 pub fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) {
2228 self.get().vertex_attrib_divisor(index, divisor);
2229 }
2230 pub fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
2231 self.get().viewport(x, y, width, height);
2232 }
2233 pub fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
2234 self.get().scissor(x, y, width, height);
2235 }
2236 pub fn line_width(&self, width: GLfloat) {
2237 self.get().line_width(width);
2238 }
2239 pub fn use_program(&self, program: GLuint) {
2240 self.get().use_program(program);
2241 }
2242 pub fn validate_program(&self, program: GLuint) {
2243 self.get().validate_program(program);
2244 }
2245 pub fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
2246 self.get().draw_arrays(mode, first, count);
2247 }
2248 pub fn draw_arrays_instanced(
2249 &self,
2250 mode: GLenum,
2251 first: GLint,
2252 count: GLsizei,
2253 primcount: GLsizei,
2254 ) {
2255 self.get()
2256 .draw_arrays_instanced(mode, first, count, primcount);
2257 }
2258 pub fn draw_elements(
2259 &self,
2260 mode: GLenum,
2261 count: GLsizei,
2262 element_type: GLenum,
2263 indices_offset: GLuint,
2264 ) {
2265 self.get()
2266 .draw_elements(mode, count, element_type, indices_offset);
2267 }
2268 pub fn draw_elements_instanced(
2269 &self,
2270 mode: GLenum,
2271 count: GLsizei,
2272 element_type: GLenum,
2273 indices_offset: GLuint,
2274 primcount: GLsizei,
2275 ) {
2276 self.get()
2277 .draw_elements_instanced(mode, count, element_type, indices_offset, primcount);
2278 }
2279 pub fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
2280 self.get().blend_color(r, g, b, a);
2281 }
2282 pub fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) {
2283 self.get().blend_func(sfactor, dfactor);
2284 }
2285 pub fn blend_func_separate(
2286 &self,
2287 src_rgb: GLenum,
2288 dest_rgb: GLenum,
2289 src_alpha: GLenum,
2290 dest_alpha: GLenum,
2291 ) {
2292 self.get()
2293 .blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha);
2294 }
2295 pub fn blend_equation(&self, mode: GLenum) {
2296 self.get().blend_equation(mode);
2297 }
2298 pub fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) {
2299 self.get().blend_equation_separate(mode_rgb, mode_alpha);
2300 }
2301 #[allow(clippy::fn_params_excessive_bools)]
2304 pub fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
2305 self.get().color_mask(r, g, b, a);
2306 }
2307 pub fn cull_face(&self, mode: GLenum) {
2308 self.get().cull_face(mode);
2309 }
2310 pub fn front_face(&self, mode: GLenum) {
2311 self.get().front_face(mode);
2312 }
2313 pub fn enable(&self, cap: GLenum) {
2314 self.get().enable(cap);
2315 }
2316 pub fn disable(&self, cap: GLenum) {
2317 self.get().disable(cap);
2318 }
2319 pub fn hint(&self, param_name: GLenum, param_val: GLenum) {
2320 self.get().hint(param_name, param_val);
2321 }
2322 #[must_use]
2323 pub fn is_enabled(&self, cap: GLenum) -> GLboolean {
2324 self.get().is_enabled(cap)
2325 }
2326 #[must_use]
2327 pub fn is_shader(&self, shader: GLuint) -> GLboolean {
2328 self.get().is_shader(shader)
2329 }
2330 #[must_use]
2331 pub fn is_texture(&self, texture: GLenum) -> GLboolean {
2332 self.get().is_texture(texture)
2333 }
2334 #[must_use]
2335 pub fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean {
2336 self.get().is_framebuffer(framebuffer)
2337 }
2338 #[must_use]
2339 pub fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean {
2340 self.get().is_renderbuffer(renderbuffer)
2341 }
2342 #[must_use]
2343 pub fn check_frame_buffer_status(&self, target: GLenum) -> GLenum {
2344 self.get().check_frame_buffer_status(target)
2345 }
2346 pub fn enable_vertex_attrib_array(&self, index: GLuint) {
2347 self.get().enable_vertex_attrib_array(index);
2348 }
2349 pub fn disable_vertex_attrib_array(&self, index: GLuint) {
2350 self.get().disable_vertex_attrib_array(index);
2351 }
2352 pub fn uniform_1f(&self, location: GLint, v0: GLfloat) {
2353 self.get().uniform_1f(location, v0);
2354 }
2355 pub fn uniform_1fv(&self, location: GLint, values: F32VecRef) {
2356 self.get().uniform_1fv(location, values.as_slice());
2357 }
2358 pub fn uniform_1i(&self, location: GLint, v0: GLint) {
2359 self.get().uniform_1i(location, v0);
2360 }
2361 pub fn uniform_1iv(&self, location: GLint, values: I32VecRef) {
2362 self.get().uniform_1iv(location, values.as_slice());
2363 }
2364 pub fn uniform_1ui(&self, location: GLint, v0: GLuint) {
2365 self.get().uniform_1ui(location, v0);
2366 }
2367 pub fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) {
2368 self.get().uniform_2f(location, v0, v1);
2369 }
2370 pub fn uniform_2fv(&self, location: GLint, values: F32VecRef) {
2371 self.get().uniform_2fv(location, values.as_slice());
2372 }
2373 pub fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) {
2374 self.get().uniform_2i(location, v0, v1);
2375 }
2376 pub fn uniform_2iv(&self, location: GLint, values: I32VecRef) {
2377 self.get().uniform_2iv(location, values.as_slice());
2378 }
2379 pub fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) {
2380 self.get().uniform_2ui(location, v0, v1);
2381 }
2382 pub fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
2383 self.get().uniform_3f(location, v0, v1, v2);
2384 }
2385 pub fn uniform_3fv(&self, location: GLint, values: F32VecRef) {
2386 self.get().uniform_3fv(location, values.as_slice());
2387 }
2388 pub fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) {
2389 self.get().uniform_3i(location, v0, v1, v2);
2390 }
2391 pub fn uniform_3iv(&self, location: GLint, values: I32VecRef) {
2392 self.get().uniform_3iv(location, values.as_slice());
2393 }
2394 pub fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
2395 self.get().uniform_3ui(location, v0, v1, v2);
2396 }
2397 pub fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
2398 self.get().uniform_4f(location, x, y, z, w);
2399 }
2400 pub fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
2401 self.get().uniform_4i(location, x, y, z, w);
2402 }
2403 pub fn uniform_4iv(&self, location: GLint, values: I32VecRef) {
2404 self.get().uniform_4iv(location, values.as_slice());
2405 }
2406 pub fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
2407 self.get().uniform_4ui(location, x, y, z, w);
2408 }
2409 pub fn uniform_4fv(&self, location: GLint, values: F32VecRef) {
2410 self.get().uniform_4fv(location, values.as_slice());
2411 }
2412 pub fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2413 self.get()
2414 .uniform_matrix_2fv(location, transpose, value.as_slice());
2415 }
2416 pub fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2417 self.get()
2418 .uniform_matrix_3fv(location, transpose, value.as_slice());
2419 }
2420 pub fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2421 self.get()
2422 .uniform_matrix_4fv(location, transpose, value.as_slice());
2423 }
2424 pub fn depth_mask(&self, flag: bool) {
2425 self.get().depth_mask(flag);
2426 }
2427 pub fn depth_range(&self, near: f64, far: f64) {
2428 self.get().depth_range(near, far);
2429 }
2430 #[must_use]
2431 pub fn get_active_attrib(&self, program: GLuint, index: GLuint) -> GetActiveAttribReturn {
2432 let r = self.get().get_active_attrib(program, index);
2433 GetActiveAttribReturn {
2434 _0: r.0,
2435 _1: r.1,
2436 _2: r.2.into(),
2437 }
2438 }
2439 #[must_use]
2440 pub fn get_active_uniform(&self, program: GLuint, index: GLuint) -> GetActiveUniformReturn {
2441 let r = self.get().get_active_uniform(program, index);
2442 GetActiveUniformReturn {
2443 _0: r.0,
2444 _1: r.1,
2445 _2: r.2.into(),
2446 }
2447 }
2448 #[must_use]
2449 pub fn get_active_uniforms_iv(
2450 &self,
2451 program: GLuint,
2452 indices: GLuintVec,
2453 pname: GLenum,
2454 ) -> GLintVec {
2455 self.get()
2456 .get_active_uniforms_iv(program, indices.into_library_owned_vec(), pname)
2457 .into()
2458 }
2459 #[must_use]
2460 pub fn get_active_uniform_block_i(
2461 &self,
2462 program: GLuint,
2463 index: GLuint,
2464 pname: GLenum,
2465 ) -> GLint {
2466 self.get().get_active_uniform_block_i(program, index, pname)
2467 }
2468 #[must_use]
2469 pub fn get_active_uniform_block_iv(
2470 &self,
2471 program: GLuint,
2472 index: GLuint,
2473 pname: GLenum,
2474 ) -> GLintVec {
2475 self.get()
2476 .get_active_uniform_block_iv(program, index, pname)
2477 .into()
2478 }
2479 #[must_use]
2480 pub fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> AzString {
2481 self.get()
2482 .get_active_uniform_block_name(program, index)
2483 .into()
2484 }
2485 #[must_use]
2486 pub fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int {
2487 self.get().get_attrib_location(program, name)
2488 }
2489 #[must_use]
2490 pub fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int {
2491 self.get().get_frag_data_location(program, name)
2492 }
2493 #[must_use]
2494 pub fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
2495 self.get().get_uniform_location(program, name)
2496 }
2497 #[must_use]
2498 pub fn get_program_info_log(&self, program: GLuint) -> AzString {
2499 self.get().get_program_info_log(program).into()
2500 }
2501 pub fn get_program_iv(&self, program: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2502 unsafe {
2503 self.get()
2504 .get_program_iv(program, pname, result.as_mut_slice());
2505 }
2506 }
2507 #[must_use]
2508 pub fn get_program_binary(&self, program: GLuint) -> GetProgramBinaryReturn {
2509 let r = self.get().get_program_binary(program);
2510 GetProgramBinaryReturn {
2511 _0: r.0.into(),
2512 _1: r.1,
2513 }
2514 }
2515 pub fn program_binary(&self, program: GLuint, format: GLenum, binary: U8VecRef) {
2516 self.get()
2517 .program_binary(program, format, binary.as_slice());
2518 }
2519 pub fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) {
2520 self.get().program_parameter_i(program, pname, value);
2521 }
2522 pub fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2523 unsafe {
2524 self.get()
2525 .get_vertex_attrib_iv(index, pname, result.as_mut_slice());
2526 }
2527 }
2528 pub fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, mut result: GLfloatVecRefMut) {
2529 unsafe {
2530 self.get()
2531 .get_vertex_attrib_fv(index, pname, result.as_mut_slice());
2532 }
2533 }
2534 #[must_use]
2535 pub fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr {
2536 self.get().get_vertex_attrib_pointer_v(index, pname)
2537 }
2538 #[must_use]
2539 pub fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
2540 self.get().get_buffer_parameter_iv(target, pname)
2541 }
2542 #[must_use]
2543 pub fn get_shader_info_log(&self, shader: GLuint) -> AzString {
2544 self.get().get_shader_info_log(shader).into()
2545 }
2546 #[must_use]
2547 pub fn get_string(&self, which: GLenum) -> AzString {
2548 self.get().get_string(which).into()
2549 }
2550 #[must_use]
2551 pub fn get_string_i(&self, which: GLenum, index: GLuint) -> AzString {
2552 self.get().get_string_i(which, index).into()
2553 }
2554 pub fn get_shader_iv(&self, shader: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2555 unsafe {
2556 self.get()
2557 .get_shader_iv(shader, pname, result.as_mut_slice());
2558 }
2559 }
2560 #[must_use]
2561 pub fn get_shader_precision_format(
2562 &self,
2563 shader_type: GLuint,
2564 precision_type: GLuint,
2565 ) -> GlShaderPrecisionFormatReturn {
2566 let r = self
2567 .get()
2568 .get_shader_precision_format(shader_type, precision_type);
2569 GlShaderPrecisionFormatReturn {
2570 _0: r.0,
2571 _1: r.1,
2572 _2: r.2,
2573 }
2574 }
2575 pub fn compile_shader(&self, shader: GLuint) {
2576 self.get().compile_shader(shader);
2577 }
2578 #[must_use]
2579 pub fn create_program(&self) -> GLuint {
2580 self.get().create_program()
2581 }
2582 pub fn delete_program(&self, program: GLuint) {
2583 self.get().delete_program(program);
2584 }
2585 #[must_use]
2586 pub fn create_shader(&self, shader_type: GLenum) -> GLuint {
2587 self.get().create_shader(shader_type)
2588 }
2589 pub fn delete_shader(&self, shader: GLuint) {
2590 self.get().delete_shader(shader);
2591 }
2592 pub fn detach_shader(&self, program: GLuint, shader: GLuint) {
2593 self.get().detach_shader(program, shader);
2594 }
2595 pub fn link_program(&self, program: GLuint) {
2596 self.get().link_program(program);
2597 }
2598 pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
2599 self.get().clear_color(r, g, b, a);
2600 }
2601 pub fn clear(&self, buffer_mask: GLbitfield) {
2602 self.get().clear(buffer_mask);
2603 }
2604 pub fn clear_depth(&self, depth: f64) {
2605 self.get().clear_depth(depth);
2606 }
2607 pub fn clear_stencil(&self, s: GLint) {
2608 self.get().clear_stencil(s);
2609 }
2610 pub fn flush(&self) {
2611 self.get().flush();
2612 }
2613 pub fn finish(&self) {
2614 self.get().finish();
2615 }
2616 #[must_use]
2617 pub fn get_error(&self) -> GLenum {
2618 self.get().get_error()
2619 }
2620 pub fn stencil_mask(&self, mask: GLuint) {
2621 self.get().stencil_mask(mask);
2622 }
2623 pub fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) {
2624 self.get().stencil_mask_separate(face, mask);
2625 }
2626 pub fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint) {
2627 self.get().stencil_func(func, ref_, mask);
2628 }
2629 pub fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint) {
2630 self.get().stencil_func_separate(face, func, ref_, mask);
2631 }
2632 pub fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
2633 self.get().stencil_op(sfail, dpfail, dppass);
2634 }
2635 pub fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
2636 self.get().stencil_op_separate(face, sfail, dpfail, dppass);
2637 }
2638 pub fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GlVoidPtrConst) {
2639 self.get()
2640 .egl_image_target_texture2d_oes(target, image.ptr as *const c_void);
2641 }
2642 pub fn generate_mipmap(&self, target: GLenum) {
2643 self.get().generate_mipmap(target);
2644 }
2645 pub fn insert_event_marker_ext(&self, message: &str) {
2646 self.get().insert_event_marker_ext(message);
2647 }
2648 pub fn push_group_marker_ext(&self, message: &str) {
2649 self.get().push_group_marker_ext(message);
2650 }
2651 pub fn pop_group_marker_ext(&self) {
2652 self.get().pop_group_marker_ext();
2653 }
2654 pub fn debug_message_insert_khr(
2655 &self,
2656 source: GLenum,
2657 type_: GLenum,
2658 id: GLuint,
2659 severity: GLenum,
2660 message: &str,
2661 ) {
2662 self.get()
2663 .debug_message_insert_khr(source, type_, id, severity, message);
2664 }
2665 pub fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str) {
2666 self.get().push_debug_group_khr(source, id, message);
2667 }
2668 pub fn pop_debug_group_khr(&self) {
2669 self.get().pop_debug_group_khr();
2670 }
2671 #[must_use]
2672 pub fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsyncPtr {
2673 GLsyncPtr::new(self.get().fence_sync(condition, flags))
2674 }
2675 #[must_use]
2676 pub fn client_wait_sync(&self, sync: GLsyncPtr, flags: GLbitfield, timeout: GLuint64) -> u32 {
2677 self.get().client_wait_sync(sync.get(), flags, timeout)
2678 }
2679 pub fn wait_sync(&self, sync: GLsyncPtr, flags: GLbitfield, timeout: GLuint64) {
2680 self.get().wait_sync(sync.get(), flags, timeout);
2681 }
2682 pub fn delete_sync(&self, sync: GLsyncPtr) {
2683 self.get().delete_sync(sync.get());
2684 }
2685 pub fn texture_range_apple(&self, target: GLenum, data: U8VecRef) {
2686 self.get().texture_range_apple(target, data.as_slice());
2687 }
2688 #[must_use]
2689 pub fn gen_fences_apple(&self, n: GLsizei) -> GLuintVec {
2690 self.get().gen_fences_apple(n).into()
2691 }
2692 pub fn delete_fences_apple(&self, fences: GLuintVecRef) {
2693 self.get().delete_fences_apple(fences.as_slice());
2694 }
2695 pub fn set_fence_apple(&self, fence: GLuint) {
2696 self.get().set_fence_apple(fence);
2697 }
2698 pub fn finish_fence_apple(&self, fence: GLuint) {
2699 self.get().finish_fence_apple(fence);
2700 }
2701 pub fn test_fence_apple(&self, fence: GLuint) {
2702 self.get().test_fence_apple(fence);
2703 }
2704 #[must_use]
2705 pub fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean {
2706 self.get().test_object_apple(object, name)
2707 }
2708 pub fn finish_object_apple(&self, object: GLenum, name: GLuint) {
2709 self.get().finish_object_apple(object, name);
2710 }
2711 #[must_use]
2712 pub fn get_frag_data_index(&self, program: GLuint, name: &str) -> GLint {
2713 self.get().get_frag_data_index(program, name)
2714 }
2715 pub fn blend_barrier_khr(&self) {
2716 self.get().blend_barrier_khr();
2717 }
2718 pub fn bind_frag_data_location_indexed(
2719 &self,
2720 program: GLuint,
2721 color_number: GLuint,
2722 index: GLuint,
2723 name: &str,
2724 ) {
2725 self.get()
2726 .bind_frag_data_location_indexed(program, color_number, index, name);
2727 }
2728 #[must_use]
2729 pub fn get_debug_messages(&self) -> DebugMessageVec {
2730 let dmv: Vec<DebugMessage> = self
2731 .get()
2732 .get_debug_messages()
2733 .into_iter()
2734 .map(|d| DebugMessage {
2735 message: d.message.into(),
2736 source: d.source,
2737 ty: d.ty,
2738 id: d.id,
2739 severity: d.severity,
2740 })
2741 .collect();
2742 dmv.into()
2743 }
2744 pub fn provoking_vertex_angle(&self, mode: GLenum) {
2745 self.get().provoking_vertex_angle(mode);
2746 }
2747 #[must_use]
2748 pub fn gen_vertex_arrays_apple(&self, n: GLsizei) -> GLuintVec {
2749 self.get().gen_vertex_arrays_apple(n).into()
2750 }
2751 pub fn bind_vertex_array_apple(&self, vao: GLuint) {
2752 self.get().bind_vertex_array_apple(vao);
2753 }
2754 pub fn delete_vertex_arrays_apple(&self, vertex_arrays: GLuintVecRef) {
2755 self.get()
2756 .delete_vertex_arrays_apple(vertex_arrays.as_slice());
2757 }
2758 pub fn copy_texture_chromium(
2759 &self,
2760 source_id: GLuint,
2761 source_level: GLint,
2762 dest_target: GLenum,
2763 dest_id: GLuint,
2764 dest_level: GLint,
2765 internal_format: GLint,
2766 dest_type: GLenum,
2767 unpack_flip_y: GLboolean,
2768 unpack_premultiply_alpha: GLboolean,
2769 unpack_unmultiply_alpha: GLboolean,
2770 ) {
2771 self.get().copy_texture_chromium(
2772 source_id,
2773 source_level,
2774 dest_target,
2775 dest_id,
2776 dest_level,
2777 internal_format,
2778 dest_type,
2779 unpack_flip_y,
2780 unpack_premultiply_alpha,
2781 unpack_unmultiply_alpha,
2782 );
2783 }
2784 pub fn copy_sub_texture_chromium(
2785 &self,
2786 source_id: GLuint,
2787 source_level: GLint,
2788 dest_target: GLenum,
2789 dest_id: GLuint,
2790 dest_level: GLint,
2791 x_offset: GLint,
2792 y_offset: GLint,
2793 x: GLint,
2794 y: GLint,
2795 width: GLsizei,
2796 height: GLsizei,
2797 unpack_flip_y: GLboolean,
2798 unpack_premultiply_alpha: GLboolean,
2799 unpack_unmultiply_alpha: GLboolean,
2800 ) {
2801 self.get().copy_sub_texture_chromium(
2802 source_id,
2803 source_level,
2804 dest_target,
2805 dest_id,
2806 dest_level,
2807 x_offset,
2808 y_offset,
2809 x,
2810 y,
2811 width,
2812 height,
2813 unpack_flip_y,
2814 unpack_premultiply_alpha,
2815 unpack_unmultiply_alpha,
2816 );
2817 }
2818 pub fn egl_image_target_renderbuffer_storage_oes(&self, target: u32, image: GlVoidPtrConst) {
2819 self.get()
2820 .egl_image_target_renderbuffer_storage_oes(target, image.ptr as *const c_void);
2821 }
2822 pub fn copy_texture_3d_angle(
2823 &self,
2824 source_id: GLuint,
2825 source_level: GLint,
2826 dest_target: GLenum,
2827 dest_id: GLuint,
2828 dest_level: GLint,
2829 internal_format: GLint,
2830 dest_type: GLenum,
2831 unpack_flip_y: GLboolean,
2832 unpack_premultiply_alpha: GLboolean,
2833 unpack_unmultiply_alpha: GLboolean,
2834 ) {
2835 self.get().copy_texture_3d_angle(
2836 source_id,
2837 source_level,
2838 dest_target,
2839 dest_id,
2840 dest_level,
2841 internal_format,
2842 dest_type,
2843 unpack_flip_y,
2844 unpack_premultiply_alpha,
2845 unpack_unmultiply_alpha,
2846 );
2847 }
2848 pub fn copy_sub_texture_3d_angle(
2849 &self,
2850 source_id: GLuint,
2851 source_level: GLint,
2852 dest_target: GLenum,
2853 dest_id: GLuint,
2854 dest_level: GLint,
2855 x_offset: GLint,
2856 y_offset: GLint,
2857 z_offset: GLint,
2858 x: GLint,
2859 y: GLint,
2860 z: GLint,
2861 width: GLsizei,
2862 height: GLsizei,
2863 depth: GLsizei,
2864 unpack_flip_y: GLboolean,
2865 unpack_premultiply_alpha: GLboolean,
2866 unpack_unmultiply_alpha: GLboolean,
2867 ) {
2868 self.get().copy_sub_texture_3d_angle(
2869 source_id,
2870 source_level,
2871 dest_target,
2872 dest_id,
2873 dest_level,
2874 x_offset,
2875 y_offset,
2876 z_offset,
2877 x,
2878 y,
2879 z,
2880 width,
2881 height,
2882 depth,
2883 unpack_flip_y,
2884 unpack_premultiply_alpha,
2885 unpack_unmultiply_alpha,
2886 );
2887 }
2888 pub fn buffer_storage(
2889 &self,
2890 target: GLenum,
2891 size: GLsizeiptr,
2892 data: GlVoidPtrConst,
2893 flags: GLbitfield,
2894 ) {
2895 self.get().buffer_storage(target, size, data.ptr, flags);
2896 }
2897 pub fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr) {
2898 self.get().flush_mapped_buffer_range(target, offset, length);
2899 }
2900}
2901
2902impl PartialEq for GlContextPtr {
2903 fn eq(&self, rhs: &Self) -> bool {
2904 self.as_usize().eq(&rhs.as_usize())
2905 }
2906}
2907
2908impl Eq for GlContextPtr {}
2909
2910impl PartialOrd for GlContextPtr {
2911 fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
2912 self.as_usize().partial_cmp(&rhs.as_usize())
2913 }
2914}
2915
2916impl Ord for GlContextPtr {
2917 fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
2918 self.as_usize().cmp(&rhs.as_usize())
2919 }
2920}
2921
2922#[allow(clippy::struct_field_names)]
2928struct GlStateSave {
2929 current_multisample: [u8; 1],
2930 current_index_buffer: [i32; 1],
2931 current_vertex_buffer: [i32; 1],
2932 current_vertex_array_object: [i32; 1],
2933 current_program: [i32; 1],
2934 current_framebuffers: [i32; 1],
2935 current_renderbuffers: [i32; 1],
2936 current_texture_2d: [i32; 1],
2937}
2938
2939impl GlStateSave {
2940 fn save(gl_context: &GlContextPtr) -> Self {
2941 let mut s = Self {
2942 current_multisample: [0],
2943 current_index_buffer: [0],
2944 current_vertex_buffer: [0],
2945 current_vertex_array_object: [0],
2946 current_program: [0],
2947 current_framebuffers: [0],
2948 current_renderbuffers: [0],
2949 current_texture_2d: [0],
2950 };
2951
2952 gl_context.get_boolean_v(gl::MULTISAMPLE, (&mut s.current_multisample[..]).into());
2953 gl_context.get_integer_v(
2954 gl::ARRAY_BUFFER_BINDING,
2955 (&mut s.current_vertex_buffer[..]).into(),
2956 );
2957 gl_context.get_integer_v(
2958 gl::ELEMENT_ARRAY_BUFFER_BINDING,
2959 (&mut s.current_index_buffer[..]).into(),
2960 );
2961 gl_context.get_integer_v(gl::CURRENT_PROGRAM, (&mut s.current_program[..]).into());
2962 gl_context.get_integer_v(
2963 gl::VERTEX_ARRAY_BINDING,
2964 (&mut s.current_vertex_array_object[..]).into(),
2965 );
2966 gl_context.get_integer_v(gl::RENDERBUFFER, (&mut s.current_renderbuffers[..]).into());
2967 gl_context.get_integer_v(gl::FRAMEBUFFER, (&mut s.current_framebuffers[..]).into());
2968 gl_context.get_integer_v(gl::TEXTURE_2D, (&mut s.current_texture_2d[..]).into());
2969
2970 s
2971 }
2972
2973 #[allow(clippy::cast_sign_loss)]
2975 fn restore(&self, gl_context: &GlContextPtr) {
2976 if u32::from(self.current_multisample[0]) == gl::TRUE {
2977 gl_context.enable(gl::MULTISAMPLE);
2978 }
2979 gl_context.bind_framebuffer(gl::FRAMEBUFFER, self.current_framebuffers[0] as u32);
2980 gl_context.bind_texture(gl::TEXTURE_2D, self.current_texture_2d[0] as u32);
2981 gl_context.bind_buffer(gl::RENDERBUFFER, self.current_renderbuffers[0] as u32);
2982 gl_context.bind_vertex_array(self.current_vertex_array_object[0] as u32);
2983 gl_context.bind_buffer(
2984 gl::ELEMENT_ARRAY_BUFFER,
2985 self.current_index_buffer[0] as u32,
2986 );
2987 gl_context.bind_buffer(gl::ARRAY_BUFFER, self.current_vertex_buffer[0] as u32);
2988 gl_context.use_program(self.current_program[0] as u32);
2989 }
2990}
2991
2992struct FboRboGuard<'a> {
2998 gl_context: &'a GlContextPtr,
2999 framebuffer_id: GLuint,
3000 renderbuffer_id: GLuint,
3001}
3002
3003impl Drop for FboRboGuard<'_> {
3004 fn drop(&mut self) {
3005 if self.framebuffer_id != 0 {
3006 self.gl_context
3007 .delete_framebuffers((&[self.framebuffer_id])[..].into());
3008 }
3009 if self.renderbuffer_id != 0 {
3010 self.gl_context
3011 .delete_renderbuffers((&[self.renderbuffer_id])[..].into());
3012 }
3013 }
3014}
3015
3016#[repr(C)]
3018pub struct Texture {
3019 pub gl_context: GlContextPtr,
3022 pub texture_id: GLuint,
3024 pub refcount: *const AtomicUsize,
3026 pub size: PhysicalSizeU32,
3028 pub format: RawImageFormat,
3030 pub background_color: ColorU,
3032 pub flags: TextureFlags,
3034 pub run_destructor: bool,
3035}
3036
3037impl Clone for Texture {
3038 #[allow(clippy::cast_sign_loss)] fn clone(&self) -> Self {
3040 unsafe {
3041 (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst);
3042 }
3043 Self {
3044 gl_context: self.gl_context.clone(),
3045 texture_id: self.texture_id,
3046 refcount: self.refcount,
3047 size: self.size,
3048 format: self.format,
3049 background_color: self.background_color,
3050 flags: self.flags,
3051 run_destructor: true,
3052 }
3053 }
3054}
3055
3056impl_option!(
3057 Texture,
3058 OptionTexture,
3059 copy = false,
3060 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3061);
3062
3063impl Texture {
3064 #[must_use]
3065 pub fn create(
3066 texture_id: GLuint,
3067 flags: TextureFlags,
3068 size: PhysicalSizeU32,
3069 background_color: ColorU,
3070 gl_context: GlContextPtr,
3071 format: RawImageFormat,
3072 ) -> Self {
3073 Self {
3074 texture_id,
3075 flags,
3076 size,
3077 background_color,
3078 gl_context,
3079 format,
3080 refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
3081 run_destructor: true,
3082 }
3083 }
3084
3085 #[allow(clippy::cast_possible_wrap)]
3089 #[allow(clippy::cast_sign_loss)] #[must_use]
3091 pub fn allocate_rgba8(
3092 gl_context: GlContextPtr,
3093 size: PhysicalSizeU32,
3094 background: ColorU,
3095 ) -> Self {
3096 let textures = gl_context.gen_textures(1);
3097 let texture_id = textures.as_ref()[0];
3098
3099 let mut current_texture_2d = [0_i32];
3100 gl_context.get_integer_v(gl::TEXTURE_2D, (&mut current_texture_2d[..]).into());
3101
3102 gl_context.bind_texture(gl::TEXTURE_2D, texture_id);
3103 gl_context.tex_image_2d(
3104 gl::TEXTURE_2D,
3105 0,
3106 gl::RGBA as i32,
3107 size.width as i32,
3108 size.height as i32,
3109 0,
3110 gl::RGBA,
3111 gl::UNSIGNED_BYTE,
3112 None.into(),
3113 );
3114 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
3115 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
3116 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
3117 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
3118 gl_context.bind_texture(gl::TEXTURE_2D, current_texture_2d[0] as u32);
3119
3120 Self::create(
3121 texture_id,
3122 TextureFlags {
3123 is_opaque: false,
3124 is_video_texture: false,
3125 },
3126 size,
3127 background,
3128 gl_context,
3129 RawImageFormat::BGRA8,
3131 )
3132 }
3133
3134 #[allow(clippy::cast_possible_wrap)]
3140 pub fn clear(&mut self) {
3141 let saved = GlStateSave::save(&self.gl_context);
3142
3143 let framebuffers = self.gl_context.gen_framebuffers(1);
3144 let framebuffer_id = *framebuffers.get(0).unwrap();
3145 let mut fbo_rbo_guard = FboRboGuard {
3148 gl_context: &self.gl_context,
3149 framebuffer_id,
3150 renderbuffer_id: 0,
3151 };
3152 self.gl_context
3153 .bind_framebuffer(gl::FRAMEBUFFER, framebuffer_id);
3154
3155 let depthbuffers = self.gl_context.gen_renderbuffers(1);
3156 let depthbuffer_id = *depthbuffers.get(0).unwrap();
3157 fbo_rbo_guard.renderbuffer_id = depthbuffer_id;
3158
3159 self.gl_context
3160 .bind_texture(gl::TEXTURE_2D, self.texture_id);
3161 self.gl_context.tex_image_2d(
3162 gl::TEXTURE_2D,
3163 0,
3164 gl::RGBA as i32, self.size.width as i32,
3166 self.size.height as i32,
3167 0,
3168 gl::RGBA, gl::UNSIGNED_BYTE,
3170 None.into(),
3171 );
3172 self.gl_context
3173 .tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
3174 self.gl_context
3175 .tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
3176 self.gl_context.tex_parameter_i(
3177 gl::TEXTURE_2D,
3178 gl::TEXTURE_WRAP_S,
3179 gl::CLAMP_TO_EDGE as i32,
3180 );
3181 self.gl_context.tex_parameter_i(
3182 gl::TEXTURE_2D,
3183 gl::TEXTURE_WRAP_T,
3184 gl::CLAMP_TO_EDGE as i32,
3185 );
3186
3187 self.gl_context
3188 .bind_renderbuffer(gl::RENDERBUFFER, depthbuffer_id);
3189 self.gl_context.renderbuffer_storage(
3190 gl::RENDERBUFFER,
3191 gl::DEPTH_COMPONENT,
3192 self.size.width as i32,
3193 self.size.height as i32,
3194 );
3195 self.gl_context.framebuffer_renderbuffer(
3196 gl::FRAMEBUFFER,
3197 gl::DEPTH_ATTACHMENT,
3198 gl::RENDERBUFFER,
3199 depthbuffer_id,
3200 );
3201
3202 self.gl_context.framebuffer_texture_2d(
3203 gl::FRAMEBUFFER,
3204 gl::COLOR_ATTACHMENT0,
3205 gl::TEXTURE_2D,
3206 self.texture_id,
3207 0,
3208 );
3209 self.gl_context
3210 .draw_buffers([gl::COLOR_ATTACHMENT0][..].into());
3211
3212 let clear_color: ColorF = self.background_color.into();
3213 self.gl_context
3214 .clear_color(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
3215 self.gl_context.clear_depth(0.0);
3216 self.gl_context
3217 .clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
3218
3219 saved.restore(&self.gl_context);
3223 drop(fbo_rbo_guard);
3224 }
3225
3226 #[must_use]
3227 pub fn get_descriptor(&self) -> ImageDescriptor {
3228 ImageDescriptor {
3229 format: self.format,
3230 width: self.size.width as usize,
3231 height: self.size.height as usize,
3232 stride: None.into(),
3233 offset: 0,
3234 flags: ImageDescriptorFlags {
3235 is_opaque: self.flags.is_opaque,
3236 allow_mipmaps: false,
3238 },
3239 }
3240 }
3241
3242 pub fn draw_tesselated_svg_gpu_node(
3244 &mut self,
3245 node: &TessellatedGPUSvgNode,
3246 size: PhysicalSizeU32,
3247 color: ColorU,
3248 transforms: StyleTransformVec,
3249 ) -> bool {
3250 node.draw(self, size, color, transforms)
3251 }
3252
3253 pub fn draw_tesselated_colored_svg_gpu_node(
3255 &mut self,
3256 node: &crate::svg::TessellatedColoredGPUSvgNode,
3257 size: PhysicalSizeU32,
3258 transforms: StyleTransformVec,
3259 ) -> bool {
3260 node.draw(self, size, transforms)
3261 }
3262}
3263
3264#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3265#[repr(C)]
3266pub struct TextureFlags {
3267 pub is_opaque: bool,
3269 pub is_video_texture: bool,
3271}
3272
3273impl ::core::fmt::Display for Texture {
3274 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3275 write!(
3276 f,
3277 "Texture {{ id: {}, {}x{} }}",
3278 self.texture_id, self.size.width, self.size.height
3279 )
3280 }
3281}
3282
3283macro_rules! impl_traits_for_gl_object {
3284 ($struct_name:ident, $gl_id_field:ident) => {
3285 impl ::core::fmt::Debug for $struct_name {
3286 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3287 write!(f, "{}", self)
3288 }
3289 }
3290
3291 impl Hash for $struct_name {
3292 fn hash<H: Hasher>(&self, state: &mut H) {
3293 self.$gl_id_field.hash(state);
3294 }
3295 }
3296
3297 impl PartialEq for $struct_name {
3298 fn eq(&self, other: &$struct_name) -> bool {
3299 self.$gl_id_field == other.$gl_id_field
3300 }
3301 }
3302
3303 impl Eq for $struct_name {}
3304
3305 impl PartialOrd for $struct_name {
3306 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
3307 Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
3308 }
3309 }
3310
3311 impl Ord for $struct_name {
3312 fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
3313 (self.$gl_id_field).cmp(&(other.$gl_id_field))
3314 }
3315 }
3316 };
3317}
3318
3319impl Texture {
3320 pub fn paint_dot(&mut self, cx: f32, cy: f32, brush: Brush) {
3325 self.paint_stroke(cx, cy, cx, cy, brush);
3326 }
3327
3328 #[allow(clippy::suboptimal_flops)] #[allow(
3333 clippy::cast_possible_truncation,
3334 clippy::cast_possible_wrap,
3335 clippy::cast_precision_loss,
3336 clippy::cast_sign_loss
3337 )] #[allow(clippy::many_single_char_names)] pub fn paint_stroke(&mut self, x0: f32, y0: f32, x1: f32, y1: f32, brush: Brush) {
3340 let gl = self.gl_context.clone();
3341 let prog = gl.get_brush_shader();
3342 let (tw, th) = (self.size.width as f32, self.size.height as f32);
3343 #[allow(clippy::neg_cmp_op_on_partial_ord)]
3345 if prog == 0 || self.texture_id == 0 || !(brush.radius > 0.0) || tw <= 0.0 || th <= 0.0 {
3346 return;
3347 }
3348
3349 let fbo = gl.gen_framebuffers(1).get(0).copied().unwrap_or(0);
3350 let vbo = gl.gen_buffers(1).get(0).copied().unwrap_or(0);
3351 if fbo == 0 || vbo == 0 {
3352 if fbo != 0 {
3353 gl.delete_framebuffers((&[fbo][..]).into());
3354 }
3355 if vbo != 0 {
3356 gl.delete_buffers((&[vbo][..]).into());
3357 }
3358 return;
3359 }
3360
3361 gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
3362 gl.framebuffer_texture_2d(
3363 gl::FRAMEBUFFER,
3364 gl::COLOR_ATTACHMENT0,
3365 gl::TEXTURE_2D,
3366 self.texture_id,
3367 0,
3368 );
3369 gl.viewport(0, 0, self.size.width as i32, self.size.height as i32);
3370 gl.enable(gl::BLEND);
3371 gl.blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
3372 gl.use_program(prog);
3373
3374 let a = (f32::from(brush.color.a) / 255.0) * brush.flow.clamp(0.0, 1.0);
3375 gl.uniform_4f(
3376 gl.get_uniform_location(prog, "uColor"),
3377 f32::from(brush.color.r) / 255.0,
3378 f32::from(brush.color.g) / 255.0,
3379 f32::from(brush.color.b) / 255.0,
3380 a,
3381 );
3382 gl.uniform_1f(gl.get_uniform_location(prog, "uHardness"), brush.hardness);
3383
3384 gl.bind_buffer(gl::ARRAY_BUFFER, vbo);
3385 gl.enable_vertex_attrib_array(0);
3386 gl.enable_vertex_attrib_array(1);
3387 gl.vertex_attrib_pointer_f32(0, 2, false, 16, 0);
3388 gl.vertex_attrib_pointer_f32(1, 2, false, 16, 8);
3389
3390 let dx = x1 - x0;
3391 let dy = y1 - y0;
3392 let len = dx.hypot(dy);
3393 let step = (brush.radius * brush.spacing.max(0.01)).max(0.5);
3394 let n = ((len / step).floor() as i32).max(0);
3395 let r = brush.radius;
3396 for i in 0..=n {
3397 let t = if n == 0 { 1.0 } else { i as f32 / n as f32 };
3398 let px = x0 + dx * t;
3399 let py = y0 + dy * t;
3400 let nx = |x: f32| (x / tw) * 2.0 - 1.0;
3402 let ny = |y: f32| 1.0 - (y / th) * 2.0;
3403 let (l, rr, tp, bt) = (nx(px - r), nx(px + r), ny(py - r), ny(py + r));
3404 let verts: [f32; 16] = [
3406 l, tp, -1.0, -1.0, l, bt, -1.0, 1.0, rr, tp, 1.0, -1.0, rr, bt, 1.0, 1.0,
3407 ];
3408 gl.buffer_data_untyped(
3409 gl::ARRAY_BUFFER,
3410 (verts.len() * size_of::<f32>()) as isize,
3411 GlVoidPtrConst {
3412 ptr: verts.as_ptr() as *const GLvoid,
3413 run_destructor: false,
3414 },
3415 gl::STREAM_DRAW,
3416 );
3417 gl.draw_arrays(gl::TRIANGLE_STRIP, 0, 4);
3418 }
3419
3420 gl.disable_vertex_attrib_array(0);
3421 gl.disable_vertex_attrib_array(1);
3422 gl.bind_buffer(gl::ARRAY_BUFFER, 0);
3423 gl.disable(gl::BLEND);
3424 gl.bind_framebuffer(gl::FRAMEBUFFER, 0);
3425 gl.delete_buffers((&[vbo][..]).into());
3426 gl.delete_framebuffers((&[fbo][..]).into());
3427 }
3428
3429 #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)] #[must_use]
3433 pub fn copy_to_raw_image(&self) -> RawImage {
3434 let gl = self.gl_context.clone();
3435 let (w, h) = (self.size.width as i32, self.size.height as i32);
3436 if self.texture_id == 0 || w <= 0 || h <= 0 {
3437 return RawImage::null_image();
3438 }
3439 let fbo = gl.gen_framebuffers(1).get(0).copied().unwrap_or(0);
3440 if fbo == 0 {
3441 return RawImage::null_image();
3442 }
3443 gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
3444 gl.framebuffer_texture_2d(
3445 gl::FRAMEBUFFER,
3446 gl::COLOR_ATTACHMENT0,
3447 gl::TEXTURE_2D,
3448 self.texture_id,
3449 0,
3450 );
3451 let pixels = gl.read_pixels(0, 0, w, h, gl::RGBA, gl::UNSIGNED_BYTE);
3452 gl.bind_framebuffer(gl::FRAMEBUFFER, 0);
3453 gl.delete_framebuffers((&[fbo][..]).into());
3454
3455 let mut bytes = pixels.into_library_owned_vec();
3457 let row = (w as usize) * 4;
3458 let hh = h as usize;
3459 if row > 0 && bytes.len() >= row * hh {
3460 for y in 0..hh / 2 {
3461 let yi = y * row;
3462 let yo = (hh - 1 - y) * row;
3463 for k in 0..row {
3464 bytes.swap(yi + k, yo + k);
3465 }
3466 }
3467 }
3468 RawImage {
3469 pixels: RawImageData::U8(bytes.into()),
3470 width: w as usize,
3471 height: h as usize,
3472 premultiplied_alpha: true,
3473 data_format: RawImageFormat::RGBA8,
3474 tag: Vec::new().into(),
3475 }
3476 }
3477}
3478
3479impl_traits_for_gl_object!(Texture, texture_id);
3480
3481impl Drop for Texture {
3482 fn drop(&mut self) {
3483 if !self.run_destructor {
3489 return;
3490 }
3491 self.run_destructor = false;
3492 let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3493 if copies == 1 {
3494 drop(unsafe { Box::from_raw(self.refcount.cast_mut()) });
3495 self.gl_context
3496 .delete_textures((&[self.texture_id])[..].into());
3497 }
3498 }
3499}
3500
3501#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3503#[repr(C)]
3504pub struct VertexLayout {
3505 pub fields: VertexAttributeVec,
3506}
3507
3508impl_vec!(
3509 VertexAttribute,
3510 VertexAttributeVec,
3511 VertexAttributeVecDestructor,
3512 VertexAttributeVecDestructorType,
3513 VertexAttributeVecSlice,
3514 OptionVertexAttribute
3515);
3516impl_vec_debug!(VertexAttribute, VertexAttributeVec);
3517impl_vec_partialord!(VertexAttribute, VertexAttributeVec);
3518impl_vec_ord!(VertexAttribute, VertexAttributeVec);
3519impl_vec_clone!(
3520 VertexAttribute,
3521 VertexAttributeVec,
3522 VertexAttributeVecDestructor
3523);
3524impl_vec_partialeq!(VertexAttribute, VertexAttributeVec);
3525impl_vec_eq!(VertexAttribute, VertexAttributeVec);
3526impl_vec_hash!(VertexAttribute, VertexAttributeVec);
3527
3528impl VertexLayout {
3529 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
3533 #[allow(clippy::cast_possible_wrap)] pub fn bind(&self, gl_context: &Rc<GenericGlContext>, program_id: GLuint) {
3535 const VERTICES_ARE_NORMALIZED: bool = false;
3536
3537 let mut offset = 0;
3538
3539 let stride_between_vertices: usize =
3540 self.fields.iter().map(VertexAttribute::get_stride).sum();
3541
3542 for vertex_attribute in &self.fields {
3543 let attribute_location = vertex_attribute.layout_location.as_option().map_or_else(
3544 || gl_context.get_attrib_location(program_id, vertex_attribute.va_name.as_str()),
3545 |ll| *ll as i32,
3546 );
3547
3548 gl_context.vertex_attrib_pointer(
3549 attribute_location as u32,
3550 vertex_attribute.item_count as i32,
3551 vertex_attribute.attribute_type.get_gl_id(),
3552 VERTICES_ARE_NORMALIZED,
3553 stride_between_vertices as i32,
3554 offset as u32,
3555 );
3556 gl_context.enable_vertex_attrib_array(attribute_location as u32);
3557 offset += vertex_attribute.get_stride();
3558 }
3559 }
3560
3561 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] #[allow(clippy::cast_possible_wrap)] pub fn unbind(&self, gl_context: &Rc<GenericGlContext>, program_id: GLuint) {
3565 for vertex_attribute in &self.fields {
3566 let attribute_location = vertex_attribute.layout_location.as_option().map_or_else(
3567 || gl_context.get_attrib_location(program_id, vertex_attribute.va_name.as_str()),
3568 |ll| *ll as i32,
3569 );
3570 gl_context.disable_vertex_attrib_array(attribute_location as u32);
3571 }
3572 }
3573}
3574
3575#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3576#[repr(C)]
3577pub struct VertexAttribute {
3578 pub va_name: AzString,
3580 pub layout_location: OptionUsize,
3583 pub attribute_type: VertexAttributeType,
3586 pub item_count: usize,
3589}
3590
3591impl_option!(
3592 VertexAttribute,
3593 OptionVertexAttribute,
3594 copy = false,
3595 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3596);
3597
3598impl VertexAttribute {
3599 #[must_use]
3600 pub const fn get_stride(&self) -> usize {
3601 self.attribute_type.get_mem_size() * self.item_count
3602 }
3603}
3604
3605#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3606#[repr(C)]
3607pub enum VertexAttributeType {
3608 Float,
3610 Double,
3612 UnsignedByte,
3614 UnsignedShort,
3616 UnsignedInt,
3618}
3619
3620impl VertexAttributeType {
3621 #[must_use]
3624 pub const fn get_gl_id(&self) -> GLuint {
3625 use self::VertexAttributeType::{Double, Float, UnsignedByte, UnsignedInt, UnsignedShort};
3626 match self {
3627 Float => gl::FLOAT,
3628 Double => gl::DOUBLE,
3629 UnsignedByte => gl::UNSIGNED_BYTE,
3630 UnsignedShort => gl::UNSIGNED_SHORT,
3631 UnsignedInt => gl::UNSIGNED_INT,
3632 }
3633 }
3634
3635 #[must_use]
3636 pub const fn get_mem_size(&self) -> usize {
3637 use core::mem;
3638
3639 use self::VertexAttributeType::{Double, Float, UnsignedByte, UnsignedInt, UnsignedShort};
3640 match self {
3641 Float => size_of::<f32>(),
3642 Double => size_of::<f64>(),
3643 UnsignedByte => size_of::<u8>(),
3644 UnsignedShort => size_of::<u16>(),
3645 UnsignedInt => size_of::<u32>(),
3646 }
3647 }
3648}
3649
3650pub trait VertexLayoutDescription {
3651 fn get_description() -> VertexLayout;
3652}
3653
3654#[derive(Debug, PartialEq, Eq, PartialOrd)]
3655#[repr(C)]
3656pub struct VertexArrayObject {
3657 pub vertex_layout: VertexLayout,
3658 pub vao_id: GLuint,
3659 pub gl_context: GlContextPtr,
3660 pub refcount: *const AtomicUsize,
3661 pub run_destructor: bool,
3662}
3663
3664impl VertexArrayObject {
3665 #[must_use]
3666 pub fn new(vertex_layout: VertexLayout, vao_id: GLuint, gl_context: GlContextPtr) -> Self {
3667 Self {
3668 vertex_layout,
3669 vao_id,
3670 gl_context,
3671 refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
3672 run_destructor: true,
3673 }
3674 }
3675}
3676
3677impl Clone for VertexArrayObject {
3678 fn clone(&self) -> Self {
3679 unsafe { (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst) };
3680 Self {
3681 vertex_layout: self.vertex_layout.clone(),
3682 vao_id: self.vao_id,
3683 gl_context: self.gl_context.clone(),
3684 refcount: self.refcount,
3685 run_destructor: true,
3686 }
3687 }
3688}
3689
3690impl Drop for VertexArrayObject {
3691 fn drop(&mut self) {
3692 if !self.run_destructor {
3695 return;
3696 }
3697 self.run_destructor = false;
3698 let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3699 if copies == 1 {
3700 drop(unsafe { Box::from_raw(self.refcount.cast_mut()) });
3701 self.gl_context
3702 .delete_vertex_arrays((&[self.vao_id])[..].into());
3703 }
3704 }
3705}
3706
3707#[repr(C)]
3708pub struct VertexBuffer {
3709 pub vao: VertexArrayObject,
3710 pub vertex_buffer_id: GLuint,
3711 pub vertex_buffer_len: usize,
3712 pub index_buffer_id: GLuint,
3713 pub index_buffer_len: usize,
3714 pub refcount: *const AtomicUsize,
3715 pub index_buffer_format: IndexBufferFormat,
3716 pub run_destructor: bool,
3717}
3718
3719impl fmt::Display for VertexBuffer {
3720 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3721 write!(
3722 f,
3723 "VertexBuffer {{ buffer: {} (length: {}) }}",
3724 self.vertex_buffer_id, self.vertex_buffer_len
3725 )
3726 }
3727}
3728
3729impl_traits_for_gl_object!(VertexBuffer, vertex_buffer_id);
3730
3731impl Clone for VertexBuffer {
3732 fn clone(&self) -> Self {
3733 unsafe { (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst) };
3734 Self {
3735 vao: self.vao.clone(),
3736 vertex_buffer_id: self.vertex_buffer_id,
3737 vertex_buffer_len: self.vertex_buffer_len,
3738 index_buffer_id: self.index_buffer_id,
3739 index_buffer_len: self.index_buffer_len,
3740 refcount: self.refcount,
3741 index_buffer_format: self.index_buffer_format,
3742 run_destructor: true,
3743 }
3744 }
3745}
3746
3747impl Drop for VertexBuffer {
3748 fn drop(&mut self) {
3749 if !self.run_destructor {
3752 return;
3753 }
3754 self.run_destructor = false;
3755 let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3756 if copies == 1 {
3757 self.vao.vertex_layout = VertexLayout {
3758 fields: VertexAttributeVec::from_const_slice(&[]),
3759 };
3760 drop(unsafe { Box::from_raw(self.refcount.cast_mut()) });
3761 self.vao
3762 .gl_context
3763 .delete_buffers((&[self.vertex_buffer_id, self.index_buffer_id])[..].into());
3764 }
3765 }
3766}
3767
3768impl VertexBuffer {
3769 #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
3776 #[allow(clippy::cast_possible_truncation)] pub fn new<T: VertexLayoutDescription>(
3778 gl_context: GlContextPtr,
3779 shader_program_id: GLuint,
3780 vertices: &[T],
3781 indices: &[u32],
3782 index_buffer_format: IndexBufferFormat,
3783 ) -> Self {
3784 use core::mem;
3785
3786 let mut current_vertex_array = [0_i32];
3788
3789 gl_context.get_integer_v(gl::VERTEX_ARRAY, (&mut current_vertex_array[..]).into());
3790
3791 let vertex_array_object = gl_context.gen_vertex_arrays(1);
3792 let vertex_array_object = vertex_array_object.get(0).unwrap();
3793
3794 let vertex_buffer_id = gl_context.gen_buffers(1);
3795 let vertex_buffer_id = vertex_buffer_id.get(0).unwrap();
3796
3797 let index_buffer_id = gl_context.gen_buffers(1);
3798 let index_buffer_id = index_buffer_id.get(0).unwrap();
3799
3800 gl_context.bind_vertex_array(*vertex_array_object);
3801
3802 gl_context.bind_buffer(gl::ARRAY_BUFFER, *vertex_buffer_id);
3804 gl_context.buffer_data_untyped(
3805 gl::ARRAY_BUFFER,
3806 size_of_val(vertices) as isize,
3807 GlVoidPtrConst {
3808 ptr: vertices.as_ptr() as *const core::ffi::c_void,
3809 run_destructor: true,
3810 },
3811 gl::STATIC_DRAW,
3812 );
3813
3814 gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, *index_buffer_id);
3816 gl_context.buffer_data_untyped(
3817 gl::ELEMENT_ARRAY_BUFFER,
3818 size_of_val(indices) as isize,
3819 GlVoidPtrConst {
3820 ptr: indices.as_ptr() as *const core::ffi::c_void,
3821 run_destructor: true,
3822 },
3823 gl::STATIC_DRAW,
3824 );
3825
3826 let vertex_description = T::get_description();
3827 vertex_description.bind(&gl_context.ptr.ptr, shader_program_id);
3828
3829 gl_context.bind_vertex_array(current_vertex_array[0] as u32);
3831
3832 Self::new_raw(
3833 *vertex_buffer_id,
3834 vertices.len(),
3835 VertexArrayObject::new(vertex_description, *vertex_array_object, gl_context),
3836 *index_buffer_id,
3837 indices.len(),
3838 index_buffer_format,
3839 )
3840 }
3841
3842 #[must_use]
3843 pub fn new_raw(
3844 vertex_buffer_id: GLuint,
3845 vertex_buffer_len: usize,
3846 vao: VertexArrayObject,
3847 index_buffer_id: GLuint,
3848 index_buffer_len: usize,
3849 index_buffer_format: IndexBufferFormat,
3850 ) -> Self {
3851 Self {
3852 vertex_buffer_id,
3853 vertex_buffer_len,
3854 vao,
3855 index_buffer_id,
3856 index_buffer_len,
3857 index_buffer_format,
3858 refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
3859 run_destructor: true,
3860 }
3861 }
3862}
3863
3864#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3865pub enum GlApiVersion {
3866 Gl { major: usize, minor: usize },
3867 GlEs { major: usize, minor: usize },
3868}
3869
3870impl GlApiVersion {
3871 #[allow(clippy::cast_sign_loss)] #[must_use]
3874 pub fn get(gl_context: &GlContextPtr) -> Self {
3875 let mut major = [0];
3876 gl_context.get_integer_v(gl::MAJOR_VERSION, (&mut major[..]).into());
3877 let mut minor = [0];
3878 gl_context.get_integer_v(gl::MINOR_VERSION, (&mut minor[..]).into());
3879
3880 let major = major[0] as usize;
3881 let minor = minor[0] as usize;
3882
3883 match gl_context.get_type() {
3884 GlType::Gl => Self::Gl { major, minor },
3885 GlType::Gles => Self::GlEs { major, minor },
3886 }
3887 }
3888}
3889
3890#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3891#[repr(C)]
3892pub enum IndexBufferFormat {
3893 Points,
3894 Lines,
3895 LineStrip,
3896 Triangles,
3897 TriangleStrip,
3898 TriangleFan,
3899}
3900
3901impl IndexBufferFormat {
3902 #[must_use]
3904 pub const fn get_gl_id(&self) -> GLuint {
3905 use self::IndexBufferFormat::{
3906 LineStrip, Lines, Points, TriangleFan, TriangleStrip, Triangles,
3907 };
3908 match self {
3909 Points => gl::POINTS,
3910 Lines => gl::LINES,
3911 LineStrip => gl::LINE_STRIP,
3912 Triangles => gl::TRIANGLES,
3913 TriangleStrip => gl::TRIANGLE_STRIP,
3914 TriangleFan => gl::TRIANGLE_FAN,
3915 }
3916 }
3917}
3918
3919#[derive(Debug, Clone, PartialEq, PartialOrd)]
3920#[repr(C)]
3921pub struct Uniform {
3922 pub uniform_name: AzString,
3923 pub uniform_type: UniformType,
3924}
3925
3926impl Uniform {
3927 pub fn create<S: Into<AzString>>(name: S, uniform_type: UniformType) -> Self {
3928 Self {
3929 uniform_name: name.into(),
3930 uniform_type,
3931 }
3932 }
3933}
3934
3935#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
3936#[repr(C, u8)]
3937pub enum UniformType {
3938 Float(f32),
3939 FloatVec2([f32; 2]),
3940 FloatVec3([f32; 3]),
3941 FloatVec4([f32; 4]),
3942 Int(i32),
3943 IntVec2([i32; 2]),
3944 IntVec3([i32; 3]),
3945 IntVec4([i32; 4]),
3946 UnsignedInt(u32),
3947 UnsignedIntVec2([u32; 2]),
3948 UnsignedIntVec3([u32; 3]),
3949 UnsignedIntVec4([u32; 4]),
3950 Matrix2 {
3951 transpose: bool,
3952 matrix: [f32; 2 * 2],
3953 },
3954 Matrix3 {
3955 transpose: bool,
3956 matrix: [f32; 3 * 3],
3957 },
3958 Matrix4 {
3959 transpose: bool,
3960 matrix: [f32; 4 * 4],
3961 },
3962}
3963
3964impl UniformType {
3965 pub fn set(self, gl_context: &Rc<GenericGlContext>, location: GLint) {
3967 use self::UniformType::{
3968 Float, FloatVec2, FloatVec3, FloatVec4, Int, IntVec2, IntVec3, IntVec4, Matrix2,
3969 Matrix3, Matrix4, UnsignedInt, UnsignedIntVec2, UnsignedIntVec3, UnsignedIntVec4,
3970 };
3971 match self {
3972 Float(r) => gl_context.uniform_1f(location, r),
3973 FloatVec2([r, g]) => gl_context.uniform_2f(location, r, g),
3974 FloatVec3([r, g, b]) => gl_context.uniform_3f(location, r, g, b),
3975 FloatVec4([r, g, b, a]) => gl_context.uniform_4f(location, r, g, b, a),
3976 Int(r) => gl_context.uniform_1i(location, r),
3977 IntVec2([r, g]) => gl_context.uniform_2i(location, r, g),
3978 IntVec3([r, g, b]) => gl_context.uniform_3i(location, r, g, b),
3979 IntVec4([r, g, b, a]) => gl_context.uniform_4i(location, r, g, b, a),
3980 UnsignedInt(r) => gl_context.uniform_1ui(location, r),
3981 UnsignedIntVec2([r, g]) => gl_context.uniform_2ui(location, r, g),
3982 UnsignedIntVec3([r, g, b]) => gl_context.uniform_3ui(location, r, g, b),
3983 UnsignedIntVec4([r, g, b, a]) => gl_context.uniform_4ui(location, r, g, b, a),
3984 Matrix2 { transpose, matrix } => {
3985 gl_context.uniform_matrix_2fv(location, transpose, &matrix[..]);
3986 }
3987 Matrix3 { transpose, matrix } => {
3988 gl_context.uniform_matrix_3fv(location, transpose, &matrix[..]);
3989 }
3990 Matrix4 { transpose, matrix } => {
3991 gl_context.uniform_matrix_4fv(location, transpose, &matrix[..]);
3992 }
3993 }
3994 }
3995}
3996
3997#[repr(C)]
3998pub struct GlShader {
3999 pub program_id: GLuint,
4000 pub gl_context: GlContextPtr,
4001 pub run_destructor: bool,
4005}
4006
4007impl ::core::fmt::Display for GlShader {
4008 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4009 write!(f, "GlShader {{ program_id: {} }}", self.program_id)
4010 }
4011}
4012
4013impl_traits_for_gl_object!(GlShader, program_id);
4014
4015impl Drop for GlShader {
4016 fn drop(&mut self) {
4017 if !self.run_destructor {
4020 return;
4021 }
4022 self.run_destructor = false;
4023 self.gl_context.delete_program(self.program_id);
4024 }
4025}
4026
4027#[repr(C)]
4028#[derive(Clone)]
4029pub struct VertexShaderCompileError {
4030 pub error_id: i32,
4031 pub info_log: AzString,
4032}
4033
4034impl_traits_for_gl_object!(VertexShaderCompileError, error_id);
4035
4036impl ::core::fmt::Display for VertexShaderCompileError {
4037 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4038 write!(f, "E{}: {}", self.error_id, self.info_log)
4039 }
4040}
4041
4042#[repr(C)]
4043#[derive(Clone)]
4044pub struct FragmentShaderCompileError {
4045 pub error_id: i32,
4046 pub info_log: AzString,
4047}
4048
4049impl_traits_for_gl_object!(FragmentShaderCompileError, error_id);
4050
4051impl ::core::fmt::Display for FragmentShaderCompileError {
4052 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4053 write!(f, "E{}: {}", self.error_id, self.info_log)
4054 }
4055}
4056
4057#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
4058pub enum GlShaderCompileError {
4059 Vertex(VertexShaderCompileError),
4060 Fragment(FragmentShaderCompileError),
4061}
4062
4063impl ::core::fmt::Display for GlShaderCompileError {
4064 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4065 use self::GlShaderCompileError::{Fragment, Vertex};
4066 match self {
4067 Vertex(vert_err) => write!(f, "Failed to compile vertex shader: {vert_err}"),
4068 Fragment(frag_err) => write!(f, "Failed to compile fragment shader: {frag_err}"),
4069 }
4070 }
4071}
4072
4073impl ::core::fmt::Debug for GlShaderCompileError {
4074 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4075 write!(f, "{self}")
4076 }
4077}
4078
4079#[repr(C)]
4080#[derive(Clone)]
4081pub struct GlShaderLinkError {
4082 pub error_id: i32,
4083 pub info_log: AzString,
4084}
4085
4086impl_traits_for_gl_object!(GlShaderLinkError, error_id);
4087
4088impl ::core::fmt::Display for GlShaderLinkError {
4089 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4090 write!(f, "E{}: {}", self.error_id, self.info_log)
4091 }
4092}
4093
4094#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
4095pub enum GlShaderCreateError {
4096 Compile(GlShaderCompileError),
4097 Link(GlShaderLinkError),
4098 NoShaderCompiler,
4099}
4100
4101impl ::core::fmt::Display for GlShaderCreateError {
4102 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4103 use self::GlShaderCreateError::{Compile, Link, NoShaderCompiler};
4104 match self {
4105 Compile(compile_err) => write!(f, "Shader compile error: {compile_err}"),
4106 Link(link_err) => write!(f, "Shader linking error: {link_err}"),
4107 NoShaderCompiler => {
4108 write!(f, "OpenGL implementation doesn't include a shader compiler")
4109 }
4110 }
4111 }
4112}
4113
4114impl ::core::fmt::Debug for GlShaderCreateError {
4115 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4116 write!(f, "{self}")
4117 }
4118}
4119
4120impl GlShader {
4121 #[allow(clippy::cast_possible_truncation)] pub fn new(
4131 gl_context: &GlContextPtr,
4132 vertex_shader: &str,
4133 fragment_shader: &str,
4134 ) -> Result<Self, GlShaderCreateError> {
4135 let mut shader_compiler_supported = [gl::FALSE as u8];
4137 gl_context.get_boolean_v(
4138 gl::SHADER_COMPILER,
4139 (&mut shader_compiler_supported[..]).into(),
4140 );
4141 if u32::from(shader_compiler_supported[0]) == gl::FALSE {
4142 return Err(GlShaderCreateError::NoShaderCompiler);
4144 }
4145
4146 let vertex_shader_object = gl_context.create_shader(gl::VERTEX_SHADER);
4149 gl_context.shader_source(
4150 vertex_shader_object,
4151 vec![AzString::from(vertex_shader.to_string())].into(),
4152 );
4153 gl_context.compile_shader(vertex_shader_object);
4154
4155 if let Some(error_id) = get_gl_shader_error(gl_context, vertex_shader_object) {
4156 let info_log = gl_context.get_shader_info_log(vertex_shader_object);
4157 gl_context.delete_shader(vertex_shader_object);
4158 return Err(GlShaderCreateError::Compile(GlShaderCompileError::Vertex(
4159 VertexShaderCompileError { error_id, info_log },
4160 )));
4161 }
4162
4163 let fragment_shader_object = gl_context.create_shader(gl::FRAGMENT_SHADER);
4166 gl_context.shader_source(
4167 fragment_shader_object,
4168 vec![AzString::from(fragment_shader.to_string())].into(),
4169 );
4170 gl_context.compile_shader(fragment_shader_object);
4171
4172 if let Some(error_id) = get_gl_shader_error(gl_context, fragment_shader_object) {
4173 let info_log = gl_context.get_shader_info_log(fragment_shader_object);
4174 gl_context.delete_shader(vertex_shader_object);
4175 gl_context.delete_shader(fragment_shader_object);
4176 return Err(GlShaderCreateError::Compile(
4177 GlShaderCompileError::Fragment(FragmentShaderCompileError { error_id, info_log }),
4178 ));
4179 }
4180
4181 let program_id = gl_context.create_program();
4184 gl_context.attach_shader(program_id, vertex_shader_object);
4185 gl_context.attach_shader(program_id, fragment_shader_object);
4186 gl_context.link_program(program_id);
4187
4188 if let Some(error_id) = get_gl_program_error(gl_context, program_id) {
4189 let info_log = gl_context.get_program_info_log(program_id);
4190 gl_context.delete_shader(vertex_shader_object);
4191 gl_context.delete_shader(fragment_shader_object);
4192 gl_context.delete_program(program_id);
4193 return Err(GlShaderCreateError::Link(GlShaderLinkError {
4194 error_id,
4195 info_log,
4196 }));
4197 }
4198
4199 gl_context.delete_shader(vertex_shader_object);
4200 gl_context.delete_shader(fragment_shader_object);
4201
4202 Ok(Self {
4203 program_id,
4204 gl_context: gl_context.clone(),
4205 run_destructor: true,
4206 })
4207 }
4208
4209 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] #[allow(clippy::too_many_lines)] pub fn draw(
4217 shader_program_id: GLuint,
4219 texture: &mut Texture,
4221 buffers: &[(&VertexBuffer, &[Uniform])],
4223 ) {
4224 use alloc::collections::btree_map::BTreeMap;
4225
4226 const INDEX_TYPE: GLuint = gl::UNSIGNED_INT;
4227
4228 let texture_size = texture.size;
4229
4230 let gl_context = &texture.gl_context;
4231
4232 let saved = GlStateSave::save(gl_context);
4233
4234 let mut current_blend_enabled = [0_u8];
4236 let mut current_primitive_restart_enabled = [0_u8];
4237 gl_context.get_boolean_v(gl::BLEND, (&mut current_blend_enabled[..]).into());
4238 gl_context.get_boolean_v(
4239 gl::PRIMITIVE_RESTART,
4240 (&mut current_primitive_restart_enabled[..]).into(),
4241 );
4242
4243 let framebuffers = gl_context.gen_framebuffers(1);
4245 let framebuffer_id = *framebuffers.get(0).unwrap();
4246 let mut fbo_rbo_guard = FboRboGuard {
4250 gl_context,
4251 framebuffer_id,
4252 renderbuffer_id: 0,
4253 };
4254 gl_context.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_id);
4255
4256 let depthbuffers = gl_context.gen_renderbuffers(1);
4257 let depthbuffer_id = *depthbuffers.get(0).unwrap();
4258 fbo_rbo_guard.renderbuffer_id = depthbuffer_id;
4259
4260 gl_context.bind_texture(gl::TEXTURE_2D, texture.texture_id);
4261 gl_context.tex_image_2d(
4262 gl::TEXTURE_2D,
4263 0,
4264 gl::RGBA as i32, texture_size.width as i32,
4266 texture_size.height as i32,
4267 0,
4268 gl::RGBA, gl::UNSIGNED_BYTE,
4270 None.into(),
4271 );
4272 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
4273 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
4274 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
4275 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
4276
4277 gl_context.bind_renderbuffer(gl::RENDERBUFFER, depthbuffer_id);
4278 gl_context.renderbuffer_storage(
4279 gl::RENDERBUFFER,
4280 gl::DEPTH_COMPONENT,
4281 texture_size.width as i32,
4282 texture_size.height as i32,
4283 );
4284 gl_context.framebuffer_renderbuffer(
4285 gl::FRAMEBUFFER,
4286 gl::DEPTH_ATTACHMENT,
4287 gl::RENDERBUFFER,
4288 depthbuffer_id,
4289 );
4290
4291 gl_context.framebuffer_texture_2d(
4292 gl::FRAMEBUFFER,
4293 gl::COLOR_ATTACHMENT0,
4294 gl::TEXTURE_2D,
4295 texture.texture_id,
4296 0,
4297 );
4298 gl_context.draw_buffers([gl::COLOR_ATTACHMENT0][..].into());
4299
4300 #[cfg(feature = "std")]
4301 {
4302 let fb_check = gl_context.check_frame_buffer_status(gl::FRAMEBUFFER);
4303 match fb_check {
4304 gl::FRAMEBUFFER_COMPLETE => {}
4305 gl::FRAMEBUFFER_UNDEFINED => {
4306 println!("GL_FRAMEBUFFER_UNDEFINED");
4307 }
4308 gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => {
4309 println!("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
4310 }
4311 gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
4312 println!("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
4313 }
4314 gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => {
4315 println!("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
4316 }
4317 gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => {
4318 println!("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
4319 }
4320 gl::FRAMEBUFFER_UNSUPPORTED => {
4321 println!("GL_FRAMEBUFFER_UNSUPPORTED");
4322 }
4323 gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => {
4324 println!("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE");
4325 }
4326 gl::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => {
4327 println!("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS");
4328 }
4329 o => {
4330 println!("glFramebufferStatus returned unknown return code: {o}");
4331 }
4332 }
4333 }
4334
4335 gl_context.viewport(0, 0, texture_size.width as i32, texture_size.height as i32);
4336 gl_context.enable(gl::BLEND);
4337 gl_context.enable(gl::PRIMITIVE_RESTART);
4340 unsafe {
4341 let gl = gl_context.get();
4342 if !gl.glPrimitiveRestartIndex.is_null() {
4343 let func: extern "system" fn(u32) =
4344 core::mem::transmute(gl.glPrimitiveRestartIndex);
4345 func(GL_RESTART_INDEX); }
4347 }
4348 gl_context.disable(gl::MULTISAMPLE);
4349 gl_context.blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); gl_context.use_program(shader_program_id);
4351
4352 let mut uniform_locations: BTreeMap<AzString, i32> = BTreeMap::new();
4354 let mut max_uniform_len = 0;
4355 for (_, uniforms) in buffers {
4356 for uniform in *uniforms {
4357 if !uniform_locations.contains_key(&uniform.uniform_name) {
4358 uniform_locations.insert(
4359 uniform.uniform_name.clone(),
4360 gl_context
4361 .get_uniform_location(shader_program_id, uniform.uniform_name.as_str()),
4362 );
4363 }
4364 }
4365 max_uniform_len = max_uniform_len.max(uniforms.len());
4366 }
4367 let mut current_uniforms = vec![None; max_uniform_len];
4368
4369 for (vertex_index_buffer, uniforms) in buffers {
4374 gl_context.bind_vertex_array(vertex_index_buffer.vao.vao_id);
4375 gl_context.bind_buffer(gl::ARRAY_BUFFER, vertex_index_buffer.vertex_buffer_id);
4376 gl_context.bind_buffer(
4377 gl::ELEMENT_ARRAY_BUFFER,
4378 vertex_index_buffer.index_buffer_id,
4379 );
4380
4381 for (uniform_index, uniform) in uniforms.iter().enumerate() {
4383 if current_uniforms[uniform_index] != Some(uniform.uniform_type) {
4384 let uniform_location = uniform_locations[&uniform.uniform_name];
4385 uniform.uniform_type.set(gl_context.get(), uniform_location);
4386 current_uniforms[uniform_index] = Some(uniform.uniform_type);
4387 }
4388 }
4389
4390 gl_context.draw_elements(
4391 vertex_index_buffer.index_buffer_format.get_gl_id(),
4392 vertex_index_buffer.index_buffer_len as i32,
4393 INDEX_TYPE,
4394 0,
4395 );
4396 }
4397
4398 if u32::from(current_blend_enabled[0]) == gl::FALSE {
4400 gl_context.disable(gl::BLEND);
4401 }
4402 if u32::from(current_primitive_restart_enabled[0]) == gl::FALSE {
4403 gl_context.disable(gl::PRIMITIVE_RESTART);
4404 }
4405
4406 saved.restore(gl_context);
4412 drop(fbo_rbo_guard);
4413
4414 texture.format = RawImageFormat::RGBA8;
4415 texture.flags = TextureFlags {
4416 is_opaque: false,
4417 is_video_texture: false,
4418 };
4419 }
4420}
4421
4422#[allow(clippy::cast_possible_wrap)] fn get_gl_shader_error(context: &GlContextPtr, shader_object: GLuint) -> Option<i32> {
4424 let mut err = [0];
4425 context.get_shader_iv(shader_object, gl::COMPILE_STATUS, (&mut err[..]).into());
4426 let err_code = err[0];
4427 if err_code == gl::TRUE as i32 {
4428 None
4429 } else {
4430 Some(err_code)
4431 }
4432}
4433
4434#[allow(clippy::cast_possible_wrap)] fn get_gl_program_error(context: &GlContextPtr, shader_object: GLuint) -> Option<i32> {
4436 let mut err = [0];
4437 context.get_program_iv(shader_object, gl::LINK_STATUS, (&mut err[..]).into());
4438 let err_code = err[0];
4439 if err_code == gl::TRUE as i32 {
4440 None
4441 } else {
4442 Some(err_code)
4443 }
4444}
4445
4446#[cfg(test)]
4447#[path = "gl_test.rs"]
4448mod gl_test;