azul_core/
gl.rs

1#![allow(unused_variables)]
2use std::{
3    rc::Rc,
4    hash::{Hasher, Hash},
5    ffi::c_void,
6    marker::PhantomData,
7    os::raw::c_int,
8};
9use gleam::gl::{self, Gl, GlType, DebugMessage, types::*};
10use crate::{
11    FastHashMap,
12    window::LogicalSize,
13    app_resources::{Epoch, ExternalImageId},
14    callbacks::PipelineId,
15};
16use azul_css::{ColorU, ColorF};
17
18/// Typedef for an OpenGL handle
19pub type GLuint = u32;
20pub type GLint = i32;
21
22/// Each pipeline (window) has its own OpenGL textures. GL Textures can technically
23/// be shared across pipelines, however this turns out to be very difficult in practice.
24pub(crate) type GlTextureStorage = FastHashMap<Epoch, FastHashMap<ExternalImageId, Texture>>;
25
26/// Non-cleaned up textures. When a GlTexture is registered, it has to stay active as long
27/// as WebRender needs it for drawing. To transparently do this, we store the epoch that the
28/// texture was originally created with, and check, **after we have drawn the frame**,
29/// if there are any textures that need cleanup.
30///
31/// Because the Texture2d is wrapped in an Rc, the destructor (which cleans up the OpenGL
32/// texture) does not run until we remove the textures
33///
34/// Note: Because textures could be used after the current draw call (ex. for scrolling),
35/// the ACTIVE_GL_TEXTURES are indexed by their epoch. Use `renderer.flush_pipeline_info()`
36/// to see which textures are still active and which ones can be safely removed.
37///
38/// See: https://github.com/servo/webrender/issues/2940
39///
40/// WARNING: Not thread-safe (however, the Texture itself is thread-unsafe, so it's unlikely to ever be misused)
41static mut ACTIVE_GL_TEXTURES: Option<FastHashMap<PipelineId, GlTextureStorage>> = None;
42
43/// Inserts a new texture into the OpenGL texture cache, returns a new image ID
44/// for the inserted texture
45///
46/// This function exists so azul doesn't have to use `lazy_static` as a dependency
47pub fn insert_into_active_gl_textures(pipeline_id: PipelineId, epoch: Epoch, texture: Texture) -> ExternalImageId {
48
49    let external_image_id = ExternalImageId::new();
50
51    unsafe {
52        if ACTIVE_GL_TEXTURES.is_none() {
53            ACTIVE_GL_TEXTURES = Some(FastHashMap::new());
54        }
55        let active_textures = ACTIVE_GL_TEXTURES.as_mut().unwrap();
56        let active_epochs = active_textures.entry(pipeline_id).or_insert_with(|| FastHashMap::new());
57        let active_textures_for_epoch = active_epochs.entry(epoch).or_insert_with(|| FastHashMap::new());
58        active_textures_for_epoch.insert(external_image_id, texture);
59    }
60
61    external_image_id
62}
63
64// Search all epoch hash maps for the given key
65// There does not seem to be a way to get the epoch for the key,
66// so we simply have to search all active epochs
67//
68// NOTE: Invalid textures can be generated on minimize / maximize
69// Luckily, webrender simply ignores an invalid texture, so we don't
70// need to check whether a window is maximized or minimized - if
71// we encounter an invalid ID, webrender simply won't draw anything,
72// but at least it won't crash. Usually invalid textures are also 0x0
73// pixels large - so it's not like we had anything to draw anyway.
74pub fn get_opengl_texture(image_key: &ExternalImageId) -> Option<(GLuint, (f32, f32))> {
75    let active_textures = unsafe { ACTIVE_GL_TEXTURES.as_ref()? };
76    active_textures.values()
77    .flat_map(|active_pipeline| active_pipeline.values())
78    .find_map(|active_epoch| active_epoch.get(image_key))
79    .map(|tex| (tex.texture_id, (tex.size.width as f32, tex.size.height as f32)))
80}
81
82pub fn gl_textures_remove_active_pipeline(pipeline_id: &PipelineId) {
83    unsafe {
84        let active_textures = match ACTIVE_GL_TEXTURES.as_mut() {
85            Some(s) => s,
86            None => return,
87        };
88        active_textures.remove(pipeline_id);
89    }
90}
91
92/// Destroys all textures from the pipeline `pipeline_id` where the texture is
93/// **older** than the given `epoch`.
94pub fn gl_textures_remove_epochs_from_pipeline(pipeline_id: &PipelineId, epoch: Epoch) {
95    // TODO: Handle overflow of Epochs correctly (low priority)
96    unsafe {
97        let active_textures = match ACTIVE_GL_TEXTURES.as_mut() {
98            Some(s) => s,
99            None => return,
100        };
101        let active_epochs = match active_textures.get_mut(pipeline_id) {
102            Some(s) => s,
103            None => return,
104        };
105        active_epochs.retain(|gl_texture_epoch, _| *gl_texture_epoch > epoch);
106    }
107}
108
109/// Destroys all textures, usually done before destroying the OpenGL context
110pub fn gl_textures_clear_opengl_cache() {
111    unsafe { ACTIVE_GL_TEXTURES = None; }
112}
113
114
115/// Virtual OpenGL "driver", that simply stores all the OpenGL
116/// calls and can replay them at a later stage.
117///
118/// This makes it easier to debug OpenGL calls, to
119/// sandbox / analyze / optimize and replay them (so that they don't interfere)
120/// with other rendering tasks
121pub struct VirtualGlDriver {
122    // TODO: create a "virtual" driver that only stores and replays OpenGL calls
123    // - the VirtualGlDriver doesn't actually do anything, except store the OpenGL calls
124    // and the replay them at a later date.
125}
126
127impl VirtualGlDriver {
128    pub fn new() -> Self {
129        Self { }
130    }
131}
132
133impl Gl for VirtualGlDriver {
134    fn get_type(&self) -> GlType {
135        unimplemented()
136    }
137
138    fn buffer_data_untyped(&self, target: GLenum, size: GLsizeiptr, data: *const GLvoid, usage: GLenum) {
139        unimplemented()
140    }
141
142    fn buffer_sub_data_untyped(&self, target: GLenum, offset: isize, size: GLsizeiptr, data: *const GLvoid) {
143        unimplemented()
144    }
145
146    fn map_buffer(&self, target: GLenum, access: GLbitfield) -> *mut c_void {
147        unimplemented()
148    }
149
150    fn map_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr, access: GLbitfield) -> *mut c_void {
151        unimplemented()
152    }
153
154    fn unmap_buffer(&self, target: GLenum) -> GLboolean {
155        unimplemented()
156    }
157
158    fn tex_buffer(&self, target: GLenum, internal_format: GLenum, buffer: GLuint) {
159        unimplemented()
160    }
161
162    fn shader_source(&self, shader: GLuint, strings: &[&[u8]]) {
163        unimplemented()
164    }
165
166    fn read_buffer(&self, mode: GLenum) {
167        unimplemented()
168    }
169
170    fn read_pixels_into_buffer(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum, dst_buffer: &mut [u8]) {
171        unimplemented()
172    }
173
174    fn read_pixels(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum) -> Vec<u8> {
175        unimplemented()
176    }
177
178    unsafe fn read_pixels_into_pbo(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum) {
179        unimplemented()
180    }
181
182    fn sample_coverage(&self, value: GLclampf, invert: bool) {
183        unimplemented()
184    }
185
186    fn polygon_offset(&self, factor: GLfloat, units: GLfloat) {
187        unimplemented()
188    }
189
190    fn pixel_store_i(&self, name: GLenum, param: GLint) {
191        unimplemented()
192    }
193
194    fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> {
195        unimplemented()
196    }
197
198    fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> {
199        unimplemented()
200    }
201
202    fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> {
203        unimplemented()
204    }
205
206    fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> {
207        unimplemented()
208    }
209
210    fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> {
211        unimplemented()
212    }
213
214    fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> {
215        unimplemented()
216    }
217
218    fn begin_query(&self, target: GLenum, id: GLuint) {
219        unimplemented()
220    }
221
222    fn end_query(&self, target: GLenum) {
223        unimplemented()
224    }
225
226    fn query_counter(&self, id: GLuint, target: GLenum) {
227        unimplemented()
228    }
229
230    fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 {
231        unimplemented()
232    }
233
234    fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 {
235        unimplemented()
236    }
237
238    fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 {
239        unimplemented()
240    }
241
242    fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 {
243        unimplemented()
244    }
245
246    fn delete_queries(&self, queries: &[GLuint]) {
247        unimplemented()
248    }
249
250    fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]) {
251        unimplemented()
252    }
253
254    fn delete_buffers(&self, buffers: &[GLuint]) {
255        unimplemented()
256    }
257
258    fn delete_renderbuffers(&self, renderbuffers: &[GLuint]) {
259        unimplemented()
260    }
261
262    fn delete_framebuffers(&self, framebuffers: &[GLuint]) {
263        unimplemented()
264    }
265
266    fn delete_textures(&self, textures: &[GLuint]) {
267        unimplemented()
268    }
269
270    fn framebuffer_renderbuffer(&self, target: GLenum, attachment: GLenum, renderbuffertarget: GLenum, renderbuffer: GLuint) {
271        unimplemented()
272    }
273
274    fn renderbuffer_storage(&self, target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei) {
275        unimplemented()
276    }
277
278    fn depth_func(&self, func: GLenum) {
279        unimplemented()
280    }
281
282    fn active_texture(&self, texture: GLenum) {
283        unimplemented()
284    }
285
286    fn attach_shader(&self, program: GLuint, shader: GLuint) {
287        unimplemented()
288    }
289
290    fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
291        unimplemented()
292    }
293
294    unsafe fn get_uniform_iv(&self, program: GLuint, location: GLint, result: &mut [GLint]) {
295        unimplemented()
296    }
297
298    unsafe fn get_uniform_fv(&self, program: GLuint, location: GLint, result: &mut [GLfloat]) {
299        unimplemented()
300    }
301
302    fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
303        unimplemented()
304    }
305
306    fn get_uniform_indices(&self,  program: GLuint, names: &[&str]) -> Vec<GLuint> {
307        unimplemented()
308    }
309
310    fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) {
311        unimplemented()
312    }
313
314    fn bind_buffer_range(&self, target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr, size: GLsizeiptr) {
315        unimplemented()
316    }
317
318    fn uniform_block_binding(&self, program: GLuint, uniform_block_index: GLuint, uniform_block_binding: GLuint) {
319        unimplemented()
320    }
321
322    fn bind_buffer(&self, target: GLenum, buffer: GLuint) {
323        unimplemented()
324    }
325
326    fn bind_vertex_array(&self, vao: GLuint) {
327        unimplemented()
328    }
329
330    fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) {
331        unimplemented()
332    }
333
334    fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) {
335        unimplemented()
336    }
337
338    fn bind_texture(&self, target: GLenum, texture: GLuint) {
339        unimplemented()
340    }
341
342    fn draw_buffers(&self, bufs: &[GLenum]) {
343        unimplemented()
344    }
345
346    fn tex_image_2d(&self, target: GLenum, level: GLint, internal_format: GLint, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, ty: GLenum, opt_data: Option<&[u8]>) {
347        unimplemented()
348    }
349
350    fn compressed_tex_image_2d(&self, target: GLenum, level: GLint, internal_format: GLenum, width: GLsizei, height: GLsizei, border: GLint, data: &[u8]) {
351        unimplemented()
352    }
353
354    fn compressed_tex_sub_image_2d(&self, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, data: &[u8]) {
355        unimplemented()
356    }
357
358    fn tex_image_3d(&self, target: GLenum, level: GLint, internal_format: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, border: GLint, format: GLenum, ty: GLenum, opt_data: Option<&[u8]>) {
359        unimplemented()
360    }
361
362    fn copy_tex_image_2d(&self, target: GLenum, level: GLint, internal_format: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei, border: GLint) {
363        unimplemented()
364    }
365
366    fn copy_tex_sub_image_2d(&self, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
367        unimplemented()
368    }
369
370    fn copy_tex_sub_image_3d(&self, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
371        unimplemented()
372    }
373
374    fn tex_sub_image_2d(&self, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, ty: GLenum, data: &[u8]) {
375        unimplemented()
376    }
377
378    fn tex_sub_image_2d_pbo(&self, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei, format: GLenum, ty: GLenum, offset: usize) {
379        unimplemented()
380    }
381
382    fn tex_sub_image_3d(&self, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, ty: GLenum, data: &[u8]) {
383        unimplemented()
384    }
385
386    fn tex_sub_image_3d_pbo(&self, target: GLenum, level: GLint, xoffset: GLint, yoffset: GLint, zoffset: GLint, width: GLsizei, height: GLsizei, depth: GLsizei, format: GLenum, ty: GLenum, offset: usize) {
387        unimplemented()
388    }
389
390    fn tex_storage_2d(&self, target: GLenum, levels: GLint, internal_format: GLenum, width: GLsizei, height: GLsizei) {
391        unimplemented()
392    }
393
394    fn tex_storage_3d(&self, target: GLenum, levels: GLint, internal_format: GLenum, width: GLsizei, height: GLsizei, depth: GLsizei) {
395        unimplemented()
396    }
397
398    fn get_tex_image_into_buffer(&self, target: GLenum, level: GLint, format: GLenum, ty: GLenum, output: &mut [u8]) {
399        unimplemented()
400    }
401
402    unsafe fn copy_image_sub_data(&self, src_name: GLuint, src_target: GLenum, src_level: GLint, src_x: GLint, src_y: GLint, src_z: GLint, dst_name: GLuint, dst_target: GLenum, dst_level: GLint, dst_x: GLint, dst_y: GLint, dst_z: GLint, src_width: GLsizei, src_height: GLsizei, src_depth: GLsizei) {
403        unimplemented()
404    }
405
406    fn invalidate_framebuffer(&self, target: GLenum, attachments: &[GLenum]) {
407        unimplemented()
408    }
409
410    fn invalidate_sub_framebuffer(&self, target: GLenum, attachments: &[GLenum], xoffset: GLint, yoffset: GLint, width: GLsizei, height: GLsizei) {
411        unimplemented()
412    }
413
414    unsafe fn get_integer_v(&self, name: GLenum, result: &mut [GLint]) {
415        unimplemented()
416    }
417
418    unsafe fn get_integer_64v(&self, name: GLenum, result: &mut [GLint64]) {
419        unimplemented()
420    }
421
422    unsafe fn get_integer_iv(&self, name: GLenum, index: GLuint, result: &mut [GLint]) {
423        unimplemented()
424    }
425
426    unsafe fn get_integer_64iv(&self, name: GLenum, index: GLuint, result: &mut [GLint64]) {
427        unimplemented()
428    }
429
430    unsafe fn get_boolean_v(&self, name: GLenum, result: &mut [GLboolean]) {
431        unimplemented()
432    }
433
434    unsafe fn get_float_v(&self, name: GLenum, result: &mut [GLfloat]) {
435        unimplemented()
436    }
437
438    fn get_framebuffer_attachment_parameter_iv(&self, target: GLenum, attachment: GLenum, pname: GLenum) -> GLint {
439        unimplemented()
440    }
441
442    fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
443        unimplemented()
444    }
445
446    fn get_tex_parameter_iv(&self, target: GLenum, name: GLenum) -> GLint {
447        unimplemented()
448    }
449
450    fn get_tex_parameter_fv(&self, target: GLenum, name: GLenum) -> GLfloat {
451        unimplemented()
452    }
453
454    fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
455        unimplemented()
456    }
457
458    fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
459        unimplemented()
460    }
461
462    fn framebuffer_texture_2d(&self, target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLuint, level: GLint) {
463        unimplemented()
464    }
465
466    fn framebuffer_texture_layer(&self, target: GLenum, attachment: GLenum, texture: GLuint, level: GLint, layer: GLint) {
467        unimplemented()
468    }
469
470    fn blit_framebuffer(&self, src_x0: GLint, src_y0: GLint, src_x1: GLint, src_y1: GLint, dst_x0: GLint, dst_y0: GLint, dst_x1: GLint, dst_y1: GLint, mask: GLbitfield, filter: GLenum) {
471        unimplemented()
472    }
473
474    fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
475        unimplemented()
476    }
477
478    fn vertex_attrib_pointer_f32(&self, index: GLuint, size: GLint, normalized: bool, stride: GLsizei, offset: GLuint) {
479        unimplemented()
480    }
481
482    fn vertex_attrib_pointer(&self, index: GLuint, size: GLint, type_: GLenum, normalized: bool, stride: GLsizei, offset: GLuint) {
483        unimplemented()
484    }
485
486    fn vertex_attrib_i_pointer(&self, index: GLuint, size: GLint, type_: GLenum, stride: GLsizei, offset: GLuint) {
487        unimplemented()
488    }
489
490    fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) {
491        unimplemented()
492    }
493
494    fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
495        unimplemented()
496    }
497
498    fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
499        unimplemented()
500    }
501
502    fn line_width(&self, width: GLfloat) {
503        unimplemented()
504    }
505
506    fn use_program(&self, program: GLuint) {
507        unimplemented()
508    }
509
510    fn validate_program(&self, program: GLuint) {
511        unimplemented()
512    }
513
514    fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
515        unimplemented()
516    }
517
518    fn draw_arrays_instanced(&self, mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei) {
519        unimplemented()
520    }
521
522    fn draw_elements(&self, mode: GLenum, count: GLsizei, element_type: GLenum, indices_offset: GLuint) {
523        unimplemented()
524    }
525
526    fn draw_elements_instanced(&self, mode: GLenum, count: GLsizei, element_type: GLenum, indices_offset: GLuint, primcount: GLsizei) {
527        unimplemented()
528    }
529
530    fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
531        unimplemented()
532    }
533
534    fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) {
535        unimplemented()
536    }
537
538    fn blend_func_separate(&self, src_rgb: GLenum, dest_rgb: GLenum, src_alpha: GLenum, dest_alpha: GLenum) {
539        unimplemented()
540    }
541
542    fn blend_equation(&self, mode: GLenum) {
543        unimplemented()
544    }
545
546    fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) {
547        unimplemented()
548    }
549
550    fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
551        unimplemented()
552    }
553
554    fn cull_face(&self, mode: GLenum) {
555        unimplemented()
556    }
557
558    fn front_face(&self, mode: GLenum) {
559        unimplemented()
560    }
561
562    fn enable(&self, cap: GLenum) {
563        unimplemented()
564    }
565
566    fn disable(&self, cap: GLenum) {
567        unimplemented()
568    }
569
570    fn hint(&self, param_name: GLenum, param_val: GLenum) {
571        unimplemented()
572    }
573
574    fn is_enabled(&self, cap: GLenum) -> GLboolean {
575        unimplemented()
576    }
577
578    fn is_shader(&self, shader: GLuint) -> GLboolean {
579        unimplemented()
580    }
581
582    fn is_texture(&self, texture: GLenum) -> GLboolean {
583        unimplemented()
584    }
585
586    fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean {
587        unimplemented()
588    }
589
590    fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean {
591        unimplemented()
592    }
593
594    fn check_frame_buffer_status(&self, target: GLenum) -> GLenum {
595        unimplemented()
596    }
597
598    fn enable_vertex_attrib_array(&self, index: GLuint) {
599        unimplemented()
600    }
601
602    fn disable_vertex_attrib_array(&self, index: GLuint) {
603        unimplemented()
604    }
605
606    fn uniform_1f(&self, location: GLint, v0: GLfloat) {
607        unimplemented()
608    }
609
610    fn uniform_1fv(&self, location: GLint, values: &[f32]) {
611        unimplemented()
612    }
613
614    fn uniform_1i(&self, location: GLint, v0: GLint) {
615        unimplemented()
616    }
617
618    fn uniform_1iv(&self, location: GLint, values: &[i32]) {
619        unimplemented()
620    }
621
622    fn uniform_1ui(&self, location: GLint, v0: GLuint) {
623        unimplemented()
624    }
625
626    fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) {
627        unimplemented()
628    }
629
630    fn uniform_2fv(&self, location: GLint, values: &[f32]) {
631        unimplemented()
632    }
633
634    fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) {
635        unimplemented()
636    }
637
638    fn uniform_2iv(&self, location: GLint, values: &[i32]) {
639        unimplemented()
640    }
641
642    fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) {
643        unimplemented()
644    }
645
646    fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
647        unimplemented()
648    }
649
650    fn uniform_3fv(&self, location: GLint, values: &[f32]) {
651        unimplemented()
652    }
653
654    fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) {
655        unimplemented()
656    }
657
658    fn uniform_3iv(&self, location: GLint, values: &[i32]) {
659        unimplemented()
660    }
661
662    fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
663        unimplemented()
664    }
665
666    fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
667        unimplemented()
668    }
669
670    fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
671        unimplemented()
672    }
673
674    fn uniform_4iv(&self, location: GLint, values: &[i32]) {
675        unimplemented()
676    }
677
678    fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
679        unimplemented()
680    }
681
682    fn uniform_4fv(&self, location: GLint, values: &[f32]) {
683        unimplemented()
684    }
685
686    fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]) {
687        unimplemented()
688    }
689
690    fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]) {
691        unimplemented()
692    }
693
694    fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]) {
695        unimplemented()
696    }
697
698    fn depth_mask(&self, flag: bool) {
699        unimplemented()
700    }
701
702    fn depth_range(&self, near: f64, far: f64) {
703        unimplemented()
704    }
705
706    fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
707        unimplemented()
708    }
709
710    fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
711        unimplemented()
712    }
713
714    fn get_active_uniforms_iv(&self, program: GLuint, indices: Vec<GLuint>, pname: GLenum) -> Vec<GLint> {
715        unimplemented()
716    }
717
718    fn get_active_uniform_block_i(&self, program: GLuint, index: GLuint, pname: GLenum) -> GLint {
719        unimplemented()
720    }
721
722    fn get_active_uniform_block_iv(&self, program: GLuint, index: GLuint, pname: GLenum) -> Vec<GLint> {
723        unimplemented()
724    }
725
726    fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> String {
727        unimplemented()
728    }
729
730    fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int {
731        unimplemented()
732    }
733
734    fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int {
735        unimplemented()
736    }
737
738    fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
739        unimplemented()
740    }
741
742    fn get_program_info_log(&self, program: GLuint) -> String {
743        unimplemented()
744    }
745
746    unsafe fn get_program_iv(&self, program: GLuint, pname: GLenum, result: &mut [GLint]) {
747        unimplemented()
748    }
749
750    fn get_program_binary(&self, program: GLuint) -> (Vec<u8>, GLenum) {
751        unimplemented()
752    }
753
754    fn program_binary(&self, program: GLuint, format: GLenum, binary: &[u8]) {
755        unimplemented()
756    }
757
758    fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) {
759        unimplemented()
760    }
761
762    unsafe fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, result: &mut [GLint]) {
763        unimplemented()
764    }
765
766    unsafe fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, result: &mut [GLfloat]) {
767        unimplemented()
768    }
769
770    fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr {
771        unimplemented()
772    }
773
774    fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
775        unimplemented()
776    }
777
778    fn get_shader_info_log(&self, shader: GLuint) -> String {
779        unimplemented()
780    }
781
782    fn get_string(&self, which: GLenum) -> String {
783        unimplemented()
784    }
785
786    fn get_string_i(&self, which: GLenum, index: GLuint) -> String {
787        unimplemented()
788    }
789
790    unsafe fn get_shader_iv(&self, shader: GLuint, pname: GLenum, result: &mut [GLint]) {
791        unimplemented()
792    }
793
794    fn get_shader_precision_format(&self, shader_type: GLuint, precision_type: GLuint) -> (GLint, GLint, GLint) {
795        unimplemented()
796    }
797
798    fn compile_shader(&self, shader: GLuint) {
799        unimplemented()
800    }
801
802    fn create_program(&self) -> GLuint {
803        unimplemented()
804    }
805
806    fn delete_program(&self, program: GLuint) {
807        unimplemented()
808    }
809
810    fn create_shader(&self, shader_type: GLenum) -> GLuint {
811        unimplemented()
812    }
813
814    fn delete_shader(&self, shader: GLuint) {
815        unimplemented()
816    }
817
818    fn detach_shader(&self, program: GLuint, shader: GLuint) {
819        unimplemented()
820    }
821
822    fn link_program(&self, program: GLuint) {
823        unimplemented()
824    }
825
826    fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
827        unimplemented()
828    }
829
830    fn clear(&self, buffer_mask: GLbitfield) {
831        unimplemented()
832    }
833
834    fn clear_depth(&self, depth: f64) {
835        unimplemented()
836    }
837
838    fn clear_stencil(&self, s: GLint) {
839        unimplemented()
840    }
841
842    fn flush(&self) {
843        unimplemented()
844    }
845
846    fn finish(&self) {
847        unimplemented()
848    }
849
850    fn get_error(&self) -> GLenum {
851        unimplemented()
852    }
853
854    fn stencil_mask(&self, mask: GLuint) {
855        unimplemented()
856    }
857
858    fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) {
859        unimplemented()
860    }
861
862    fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint) {
863        unimplemented()
864    }
865
866    fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint) {
867        unimplemented()
868    }
869
870    fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
871        unimplemented()
872    }
873
874    fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
875        unimplemented()
876    }
877
878    fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES) {
879        unimplemented()
880    }
881
882    fn generate_mipmap(&self, target: GLenum) {
883        unimplemented()
884    }
885
886    fn insert_event_marker_ext(&self, message: &str) {
887        unimplemented()
888    }
889
890    fn push_group_marker_ext(&self, message: &str) {
891        unimplemented()
892    }
893
894    fn pop_group_marker_ext(&self) {
895        unimplemented()
896    }
897
898    fn debug_message_insert_khr(&self, source: GLenum, type_: GLenum, id: GLuint, severity: GLenum, message: &str) {
899        unimplemented()
900    }
901
902    fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str) {
903        unimplemented()
904    }
905
906    fn pop_debug_group_khr(&self) {
907        unimplemented()
908    }
909
910    fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsync {
911        unimplemented()
912    }
913
914    fn client_wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) {
915        unimplemented()
916    }
917
918    fn wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) {
919        unimplemented()
920    }
921
922    fn delete_sync(&self, sync: GLsync) {
923        unimplemented()
924    }
925
926    fn texture_range_apple(&self, target: GLenum, data: &[u8]) {
927        unimplemented()
928    }
929
930    fn gen_fences_apple(&self, n: GLsizei) -> Vec<GLuint> {
931        unimplemented()
932    }
933
934    fn delete_fences_apple(&self, fences: &[GLuint]) {
935        unimplemented()
936    }
937
938    fn set_fence_apple(&self, fence: GLuint) {
939        unimplemented()
940    }
941
942    fn finish_fence_apple(&self, fence: GLuint) {
943        unimplemented()
944    }
945
946    fn test_fence_apple(&self, fence: GLuint) {
947        unimplemented()
948    }
949
950    fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean {
951        unimplemented()
952    }
953
954    fn finish_object_apple(&self, object: GLenum, name: GLuint) {
955        unimplemented()
956    }
957
958    fn get_frag_data_index( &self, program: GLuint, name: &str) -> GLint {
959        unimplemented()
960    }
961
962    fn blend_barrier_khr(&self) {
963        unimplemented()
964    }
965
966    fn bind_frag_data_location_indexed( &self, program: GLuint, color_number: GLuint, index: GLuint, name: &str) {
967        unimplemented()
968    }
969
970    fn get_debug_messages(&self) -> Vec<DebugMessage> {
971        unimplemented()
972    }
973
974    fn provoking_vertex_angle(&self, mode: GLenum) {
975        unimplemented()
976    }
977
978    // -- gleam: 0.8
979
980    fn gen_vertex_arrays_apple(&self, n: GLsizei) -> Vec<GLuint> {
981        unimplemented()
982    }
983
984    fn bind_vertex_array_apple(&self, vao: GLuint) {
985        unimplemented()
986    }
987
988    fn delete_vertex_arrays_apple(&self, vertex_arrays: &[GLuint]) {
989        unimplemented()
990    }
991
992    fn copy_texture_chromium(
993        &self,
994        source_id: GLuint,
995        source_level: GLint,
996        dest_target: GLenum,
997        dest_id: GLuint,
998        dest_level: GLint,
999        internal_format: GLint,
1000        dest_type: GLenum,
1001        unpack_flip_y: GLboolean,
1002        unpack_premultiply_alpha: GLboolean,
1003        unpack_unmultiply_alpha: GLboolean
1004    ) {
1005        unimplemented()
1006    }
1007
1008    fn copy_sub_texture_chromium(
1009        &self,
1010        source_id: GLuint,
1011        source_level: GLint,
1012        dest_target: GLenum,
1013        dest_id: GLuint,
1014        dest_level: GLint,
1015        x_offset: GLint,
1016        y_offset: GLint,
1017        x: GLint,
1018        y: GLint,
1019        width: GLsizei,
1020        height: GLsizei,
1021        unpack_flip_y: GLboolean,
1022        unpack_premultiply_alpha: GLboolean,
1023        unpack_unmultiply_alpha: GLboolean
1024    ) {
1025        unimplemented()
1026    }
1027
1028    // -- gleam: 0.11
1029
1030    fn egl_image_target_renderbuffer_storage_oes(&self, target: u32, image: *const c_void) {
1031        unimplemented()
1032    }
1033
1034    fn copy_texture_3d_angle(
1035        &self,
1036        source_id: GLuint,
1037        source_level: GLint,
1038        dest_target: GLenum,
1039        dest_id: GLuint,
1040        dest_level: GLint,
1041        internal_format: GLint,
1042        dest_type: GLenum,
1043        unpack_flip_y: GLboolean,
1044        unpack_premultiply_alpha: GLboolean,
1045        unpack_unmultiply_alpha: GLboolean
1046    ) {
1047        unimplemented()
1048    }
1049
1050    fn copy_sub_texture_3d_angle(
1051        &self,
1052        source_id: GLuint,
1053        source_level: GLint,
1054        dest_target: GLenum,
1055        dest_id: GLuint,
1056        dest_level: GLint,
1057        x_offset: GLint,
1058        y_offset: GLint,
1059        z_offset: GLint,
1060        x: GLint,
1061        y: GLint,
1062        z: GLint,
1063        width: GLsizei,
1064        height: GLsizei,
1065        depth: GLsizei,
1066        unpack_flip_y: GLboolean,
1067        unpack_premultiply_alpha: GLboolean,
1068        unpack_unmultiply_alpha: GLboolean
1069    ) {
1070        unimplemented()
1071    }
1072}
1073
1074fn unimplemented() -> ! {
1075    panic!("You cannot call OpenGL functions on the VirtualGlDriver");
1076}
1077
1078/// OpenGL texture, use `ReadOnlyWindow::create_texture` to create a texture
1079pub struct Texture {
1080    /// Raw OpenGL texture ID
1081    pub texture_id: GLuint,
1082    /// Hints and flags for optimization purposes
1083    pub flags: TextureFlags,
1084    /// Size of this texture (in pixels)
1085    pub size: LogicalSize,
1086    /// A reference-counted pointer to the OpenGL context (so that the texture can be deleted in the destructor)
1087    pub gl_context: Rc<dyn Gl>,
1088}
1089
1090#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1091pub struct TextureFlags {
1092    /// Whether this texture contains an alpha component
1093    pub is_opaque: bool,
1094    /// Optimization: use the compositor instead of OpenGL for energy optimization
1095    pub is_video_texture: bool,
1096}
1097
1098impl ::std::fmt::Display for Texture {
1099    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1100        write!(f, "Texture {{ id: {}, {}x{} }}", self.texture_id, self.size.width, self.size.height)
1101    }
1102}
1103
1104macro_rules! impl_traits_for_gl_object {
1105    ($struct_name:ident, $gl_id_field:ident) => {
1106
1107        impl ::std::fmt::Debug for $struct_name {
1108            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1109                write!(f, "{}", self)
1110            }
1111        }
1112
1113        impl Hash for $struct_name {
1114            fn hash<H: Hasher>(&self, state: &mut H) {
1115                self.$gl_id_field.hash(state);
1116            }
1117        }
1118
1119        impl PartialEq for $struct_name {
1120            fn eq(&self, other: &$struct_name) -> bool {
1121                self.$gl_id_field == other.$gl_id_field
1122            }
1123        }
1124
1125        impl Eq for $struct_name { }
1126
1127        impl PartialOrd for $struct_name {
1128            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
1129                Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
1130            }
1131        }
1132
1133        impl Ord for $struct_name {
1134            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
1135                (self.$gl_id_field).cmp(&(other.$gl_id_field))
1136            }
1137        }
1138    };
1139    ($struct_name:ident<$lt:lifetime>, $gl_id_field:ident) => {
1140        impl<$lt> ::std::fmt::Debug for $struct_name<$lt> {
1141            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1142                write!(f, "{}", self)
1143            }
1144        }
1145
1146        impl<$lt> Hash for $struct_name<$lt> {
1147            fn hash<H: Hasher>(&self, state: &mut H) {
1148                self.$gl_id_field.hash(state);
1149            }
1150        }
1151
1152        impl<$lt>PartialEq for $struct_name<$lt> {
1153            fn eq(&self, other: &$struct_name) -> bool {
1154                self.$gl_id_field == other.$gl_id_field
1155            }
1156        }
1157
1158        impl<$lt> Eq for $struct_name<$lt> { }
1159
1160        impl<$lt> PartialOrd for $struct_name<$lt> {
1161            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
1162                Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
1163            }
1164        }
1165
1166        impl<$lt> Ord for $struct_name<$lt> {
1167            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
1168                (self.$gl_id_field).cmp(&(other.$gl_id_field))
1169            }
1170        }
1171    };
1172    ($struct_name:ident<$t:ident: $constraint:ident>, $gl_id_field:ident) => {
1173        impl<$t: $constraint> ::std::fmt::Debug for $struct_name<$t> {
1174            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1175                write!(f, "{}", self)
1176            }
1177        }
1178
1179        impl<$t: $constraint> Hash for $struct_name<$t> {
1180            fn hash<H: Hasher>(&self, state: &mut H) {
1181                self.$gl_id_field.hash(state);
1182            }
1183        }
1184
1185        impl<$t: $constraint>PartialEq for $struct_name<$t> {
1186            fn eq(&self, other: &$struct_name<$t>) -> bool {
1187                self.$gl_id_field == other.$gl_id_field
1188            }
1189        }
1190
1191        impl<$t: $constraint> Eq for $struct_name<$t> { }
1192
1193        impl<$t: $constraint> PartialOrd for $struct_name<$t> {
1194            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
1195                Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
1196            }
1197        }
1198
1199        impl<$t: $constraint> Ord for $struct_name<$t> {
1200            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
1201                (self.$gl_id_field).cmp(&(other.$gl_id_field))
1202            }
1203        }
1204    };
1205}
1206
1207impl_traits_for_gl_object!(Texture, texture_id);
1208
1209impl Drop for Texture {
1210    fn drop(&mut self) {
1211        self.gl_context.delete_textures(&[self.texture_id]);
1212    }
1213}
1214
1215/// Describes the vertex layout and offsets
1216#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1217pub struct VertexLayout {
1218    pub fields: Vec<VertexAttribute>,
1219}
1220
1221impl VertexLayout {
1222
1223    /// Submits the vertex buffer description to OpenGL
1224    pub fn bind(&self, shader: &GlShader) {
1225
1226        const VERTICES_ARE_NORMALIZED: bool = false;
1227
1228        let gl_context = &*shader.gl_context;
1229
1230        let mut offset = 0;
1231
1232        let stride_between_vertices: usize = self.fields.iter().map(VertexAttribute::get_stride).sum();
1233
1234        for vertex_attribute in self.fields.iter() {
1235
1236            let attribute_location = vertex_attribute.layout_location
1237                .map(|ll| ll as i32)
1238                .unwrap_or_else(|| gl_context.get_attrib_location(shader.program_id, &vertex_attribute.name));
1239
1240            gl_context.vertex_attrib_pointer(
1241                attribute_location as u32,
1242                vertex_attribute.item_count as i32,
1243                vertex_attribute.attribute_type.get_gl_id(),
1244                VERTICES_ARE_NORMALIZED,
1245                stride_between_vertices as i32,
1246                offset as u32,
1247            );
1248            gl_context.enable_vertex_attrib_array(attribute_location as u32);
1249            offset += vertex_attribute.get_stride();
1250        }
1251    }
1252
1253    /// Unsets the vertex buffer description
1254    pub fn unbind(&self, shader: &GlShader) {
1255        let gl_context = &*shader.gl_context;
1256        for vertex_attribute in self.fields.iter() {
1257            let attribute_location = vertex_attribute.layout_location
1258                .map(|ll| ll as i32)
1259                .unwrap_or_else(|| gl_context.get_attrib_location(shader.program_id, &vertex_attribute.name));
1260            gl_context.disable_vertex_attrib_array(attribute_location as u32);
1261        }
1262    }
1263}
1264
1265#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1266pub struct VertexAttribute {
1267    /// Attribute name of the vertex attribute in the vertex shader, i.e. `"vAttrXY"`
1268    pub name: &'static str,
1269    /// If the vertex shader has a specific location, (like `layout(location = 2) vAttrXY`),
1270    /// use this instead of the name to look up the uniform location.
1271    pub layout_location: Option<usize>,
1272    /// Type of items of this attribute (i.e. for a `FloatVec2`, would be `VertexAttributeType::Float`)
1273    pub attribute_type: VertexAttributeType,
1274    /// Number of items of this attribute (i.e. for a `FloatVec2`, would be `2` (= 2 consecutive f32 values))
1275    pub item_count: usize,
1276}
1277
1278impl VertexAttribute {
1279    pub fn get_stride(&self) -> usize {
1280        self.attribute_type.get_mem_size() * self.item_count
1281    }
1282}
1283
1284#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1285pub enum VertexAttributeType {
1286    /// Vertex attribute has type `f32`
1287    Float,
1288    /// Vertex attribute has type `f64`
1289    Double,
1290    /// Vertex attribute has type `u8`
1291    UnsignedByte,
1292    /// Vertex attribute has type `u16`
1293    UnsignedShort,
1294    /// Vertex attribute has type `u32`
1295    UnsignedInt,
1296}
1297
1298impl VertexAttributeType {
1299
1300    /// Returns the OpenGL id for the vertex attribute type, ex. `gl::UNSIGNED_BYTE` for `VertexAttributeType::UnsignedByte`.
1301    pub fn get_gl_id(&self) -> GLuint {
1302        use self::VertexAttributeType::*;
1303        match self {
1304            Float => gl::FLOAT,
1305            Double => gl::DOUBLE,
1306            UnsignedByte => gl::UNSIGNED_BYTE,
1307            UnsignedShort => gl::UNSIGNED_SHORT,
1308            UnsignedInt => gl::UNSIGNED_INT,
1309        }
1310    }
1311
1312    pub fn get_mem_size(&self) -> usize {
1313        use std::mem;
1314        use self::VertexAttributeType::*;
1315        match self {
1316            Float => mem::size_of::<f32>(),
1317            Double => mem::size_of::<f64>(),
1318            UnsignedByte => mem::size_of::<u8>(),
1319            UnsignedShort => mem::size_of::<u16>(),
1320            UnsignedInt => mem::size_of::<u32>(),
1321        }
1322    }
1323}
1324
1325pub trait VertexLayoutDescription {
1326    fn get_description() -> VertexLayout;
1327}
1328
1329pub struct VertexArrayObject {
1330    pub vertex_layout: VertexLayout,
1331    pub vao_id: GLuint,
1332    pub gl_context: Rc<dyn Gl>,
1333}
1334
1335impl Drop for VertexArrayObject {
1336    fn drop(&mut self) {
1337        self.gl_context.delete_vertex_arrays(&[self.vao_id]);
1338    }
1339}
1340
1341pub struct VertexBuffer<T: VertexLayoutDescription> {
1342    pub vertex_buffer_id: GLuint,
1343    pub vertex_buffer_len: usize,
1344    pub gl_context: Rc<dyn Gl>,
1345    pub vao: VertexArrayObject,
1346    pub vertex_buffer_type: PhantomData<T>,
1347
1348    // Since vertex buffer + index buffer have to be created together (because of the VAO), s
1349    pub index_buffer_id: GLuint,
1350    pub index_buffer_len: usize,
1351    pub index_buffer_format: IndexBufferFormat,
1352}
1353
1354impl<T: VertexLayoutDescription> ::std::fmt::Display for VertexBuffer<T> {
1355    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1356        write!(f,
1357            "VertexBuffer {{ buffer: {} (length: {}) }})",
1358            self.vertex_buffer_id, self.vertex_buffer_len
1359        )
1360    }
1361}
1362
1363impl_traits_for_gl_object!(VertexBuffer<T: VertexLayoutDescription>, vertex_buffer_id);
1364
1365impl<T: VertexLayoutDescription> Drop for VertexBuffer<T> {
1366    fn drop(&mut self) {
1367        self.gl_context.delete_buffers(&[self.vertex_buffer_id, self.index_buffer_id]);
1368    }
1369}
1370
1371impl<T: VertexLayoutDescription> VertexBuffer<T> {
1372    pub fn new(shader: &GlShader, vertices: &[T], indices: &[u32], index_buffer_format: IndexBufferFormat) -> Self {
1373
1374        use std::mem;
1375
1376        let gl_context = shader.gl_context.clone();
1377
1378        // Save the OpenGL state
1379        let mut current_vertex_array = [0_i32];
1380        let mut current_vertex_buffer = [0_i32];
1381        let mut current_index_buffer = [0_i32];
1382
1383        unsafe { gl_context.get_integer_v(gl::VERTEX_ARRAY, &mut current_vertex_array) };
1384        unsafe { gl_context.get_integer_v(gl::ARRAY_BUFFER, &mut current_vertex_buffer) };
1385        unsafe { gl_context.get_integer_v(gl::ELEMENT_ARRAY_BUFFER, &mut current_index_buffer) };
1386
1387        let vertex_array_object = gl_context.gen_vertex_arrays(1);
1388        let vertex_array_object = vertex_array_object[0];
1389
1390        let vertex_buffer_id = gl_context.gen_buffers(1);
1391        let vertex_buffer_id = vertex_buffer_id[0];
1392
1393        let index_buffer_id = gl_context.gen_buffers(1);
1394        let index_buffer_id = index_buffer_id[0];
1395
1396        gl_context.bind_vertex_array(vertex_array_object);
1397
1398        // Upload vertex data to GPU
1399        gl_context.bind_buffer(gl::ARRAY_BUFFER, vertex_buffer_id);
1400        gl_context.buffer_data_untyped(
1401            gl::ARRAY_BUFFER,
1402            (mem::size_of::<T>() * vertices.len()) as isize,
1403            vertices.as_ptr() as *const c_void,
1404            gl::STATIC_DRAW
1405        );
1406
1407        // Generate the index buffer + upload data
1408        gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_id);
1409        gl_context.buffer_data_untyped(
1410            gl::ELEMENT_ARRAY_BUFFER,
1411            (mem::size_of::<u32>() * indices.len()) as isize,
1412            indices.as_ptr() as *const c_void,
1413            gl::STATIC_DRAW
1414        );
1415
1416        let vertex_description = T::get_description();
1417        vertex_description.bind(shader);
1418
1419        // Reset the OpenGL state
1420        gl_context.bind_buffer(gl::ARRAY_BUFFER, current_vertex_buffer[0] as u32);
1421        gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, current_index_buffer[0] as u32);
1422        gl_context.bind_vertex_array(current_vertex_array[0] as u32);
1423
1424        Self {
1425            vertex_buffer_id,
1426            vertex_buffer_len: vertices.len(),
1427            gl_context: gl_context.clone(),
1428            vao: VertexArrayObject {
1429                vertex_layout: vertex_description,
1430                vao_id: vertex_array_object,
1431                gl_context,
1432            },
1433            vertex_buffer_type: PhantomData,
1434            index_buffer_id,
1435            index_buffer_len: indices.len(),
1436            index_buffer_format,
1437        }
1438    }
1439}
1440
1441#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1442pub enum GlApiVersion {
1443    Gl { major: usize, minor: usize },
1444    GlEs { major: usize, minor: usize },
1445}
1446
1447impl GlApiVersion {
1448    /// Returns the OpenGL version of the context
1449    pub fn get(gl_context: &dyn Gl) -> Self {
1450        let mut major = [0];
1451        unsafe { gl_context.get_integer_v(gl::MAJOR_VERSION, &mut major) };
1452        let mut minor = [0];
1453        unsafe { gl_context.get_integer_v(gl::MINOR_VERSION, &mut minor) };
1454
1455        GlApiVersion::Gl { major: major[0] as usize, minor: minor[0] as usize }
1456    }
1457}
1458
1459#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1460pub enum IndexBufferFormat {
1461    Points,
1462    Lines,
1463    LineStrip,
1464    Triangles,
1465    TriangleStrip,
1466    TriangleFan,
1467}
1468
1469impl IndexBufferFormat {
1470    /// Returns the `gl::TRIANGLE_STRIP` / `gl::POINTS`, etc.
1471    pub fn get_gl_id(&self) -> GLuint {
1472        use self::IndexBufferFormat::*;
1473        match self {
1474            Points => gl::POINTS,
1475            Lines => gl::LINES,
1476            LineStrip => gl::LINE_STRIP,
1477            Triangles => gl::TRIANGLES,
1478            TriangleStrip => gl::TRIANGLE_STRIP,
1479            TriangleFan => gl::TRIANGLE_FAN,
1480        }
1481    }
1482}
1483
1484#[derive(Debug, Clone, PartialEq, PartialOrd)]
1485pub struct Uniform {
1486    pub name: String,
1487    pub uniform_type: UniformType,
1488}
1489
1490impl Uniform {
1491    pub fn new<S: Into<String>>(name: S, uniform_type: UniformType) -> Self {
1492        Self { name: name.into(), uniform_type }
1493    }
1494}
1495
1496#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1497pub enum UniformType {
1498    Float(f32),
1499    FloatVec2([f32;2]),
1500    FloatVec3([f32;3]),
1501    FloatVec4([f32;4]),
1502    Int(i32),
1503    IntVec2([i32;2]),
1504    IntVec3([i32;3]),
1505    IntVec4([i32;4]),
1506    UnsignedInt(u32),
1507    UnsignedIntVec2([u32;2]),
1508    UnsignedIntVec3([u32;3]),
1509    UnsignedIntVec4([u32;4]),
1510    Matrix2 { transpose: bool, matrix: [f32;2*2] },
1511    Matrix3 { transpose: bool, matrix: [f32;3*3] },
1512    Matrix4 { transpose: bool, matrix: [f32;4*4] },
1513}
1514
1515impl UniformType {
1516    /// Set a specific uniform
1517    pub fn set(self, gl_context: &dyn Gl, location: GLint) {
1518        use self::UniformType::*;
1519        match self {
1520            Float(r) => gl_context.uniform_1f(location, r),
1521            FloatVec2([r,g]) => gl_context.uniform_2f(location, r, g),
1522            FloatVec3([r,g,b]) => gl_context.uniform_3f(location, r, g, b),
1523            FloatVec4([r,g,b,a]) => gl_context.uniform_4f(location, r, g, b, a),
1524            Int(r) => gl_context.uniform_1i(location, r),
1525            IntVec2([r,g]) => gl_context.uniform_2i(location, r, g),
1526            IntVec3([r,g,b]) => gl_context.uniform_3i(location, r, g, b),
1527            IntVec4([r,g,b,a]) => gl_context.uniform_4i(location, r, g, b, a),
1528            UnsignedInt(r) => gl_context.uniform_1ui(location, r),
1529            UnsignedIntVec2([r,g]) => gl_context.uniform_2ui(location, r, g),
1530            UnsignedIntVec3([r,g,b]) => gl_context.uniform_3ui(location, r, g, b),
1531            UnsignedIntVec4([r,g,b,a]) => gl_context.uniform_4ui(location, r, g, b, a),
1532            Matrix2 { transpose, matrix } => gl_context.uniform_matrix_2fv(location, transpose, &matrix[..]),
1533            Matrix3 { transpose, matrix } => gl_context.uniform_matrix_2fv(location, transpose, &matrix[..]),
1534            Matrix4 { transpose, matrix } => gl_context.uniform_matrix_2fv(location, transpose, &matrix[..]),
1535        }
1536    }
1537}
1538
1539pub struct GlShader {
1540    pub program_id: GLuint,
1541    pub gl_context: Rc<dyn Gl>,
1542}
1543
1544impl ::std::fmt::Display for GlShader {
1545    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1546        write!(f, "GlShader {{ program_id: {} }}", self.program_id)
1547    }
1548}
1549
1550impl_traits_for_gl_object!(GlShader, program_id);
1551
1552impl Drop for GlShader {
1553    fn drop(&mut self) {
1554        self.gl_context.delete_program(self.program_id);
1555    }
1556}
1557
1558#[derive(Clone)]
1559pub struct VertexShaderCompileError {
1560    pub error_id: i32,
1561    pub info_log: String
1562}
1563
1564impl_traits_for_gl_object!(VertexShaderCompileError, error_id);
1565
1566impl ::std::fmt::Display for VertexShaderCompileError {
1567    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1568        write!(f, "E{}: {}", self.error_id, self.info_log)
1569    }
1570}
1571
1572#[derive(Clone)]
1573pub struct FragmentShaderCompileError {
1574    pub error_id: i32,
1575    pub info_log: String
1576}
1577
1578impl_traits_for_gl_object!(FragmentShaderCompileError, error_id);
1579
1580impl ::std::fmt::Display for FragmentShaderCompileError {
1581    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1582        write!(f, "E{}: {}", self.error_id, self.info_log)
1583    }
1584}
1585
1586#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
1587pub enum GlShaderCompileError {
1588    Vertex(VertexShaderCompileError),
1589    Fragment(FragmentShaderCompileError),
1590}
1591
1592impl ::std::fmt::Display for GlShaderCompileError {
1593    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1594        use self::GlShaderCompileError::*;
1595        match self {
1596            Vertex(vert_err) => write!(f, "Failed to compile vertex shader: {}", vert_err),
1597            Fragment(frag_err) => write!(f, "Failed to compile fragment shader: {}", frag_err),
1598        }
1599    }
1600}
1601
1602impl ::std::fmt::Debug for GlShaderCompileError {
1603    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1604        write!(f, "{}", self)
1605    }
1606}
1607
1608#[derive(Clone)]
1609pub struct GlShaderLinkError {
1610    pub error_id: i32,
1611    pub info_log: String
1612}
1613
1614impl_traits_for_gl_object!(GlShaderLinkError, error_id);
1615
1616impl ::std::fmt::Display for GlShaderLinkError {
1617    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1618        write!(f, "E{}: {}", self.error_id, self.info_log)
1619    }
1620}
1621
1622#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
1623pub enum GlShaderCreateError {
1624    Compile(GlShaderCompileError),
1625    Link(GlShaderLinkError),
1626    NoShaderCompiler,
1627}
1628
1629impl ::std::fmt::Display for GlShaderCreateError {
1630    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1631        use self::GlShaderCreateError::*;
1632        match self {
1633            Compile(compile_err) => write!(f, "Shader compile error: {}", compile_err),
1634            Link(link_err) => write!(f, "Shader linking error: {}", link_err),
1635            NoShaderCompiler => write!(f, "OpenGL implementation doesn't include a shader compiler"),
1636        }
1637    }
1638}
1639
1640impl ::std::fmt::Debug for GlShaderCreateError {
1641    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1642        write!(f, "{}", self)
1643    }
1644}
1645
1646impl GlShader {
1647
1648    /// Compiles and creates a new OpenGL shader, created from a vertex and a fragment shader string.
1649    ///
1650    /// If the shader fails to compile, the shader object gets automatically deleted, no cleanup necessary.
1651    pub fn new(gl_context: Rc<dyn Gl>, vertex_shader: &str, fragment_shader: &str) -> Result<Self, GlShaderCreateError> {
1652
1653        // Check whether the OpenGL implementation supports a shader compiler...
1654        let mut shader_compiler_supported = [gl::FALSE];
1655        unsafe { gl_context.get_boolean_v(gl::SHADER_COMPILER, &mut shader_compiler_supported) };
1656        if shader_compiler_supported[0] == gl::FALSE {
1657            // Implementation only supports binary shaders
1658            return Err(GlShaderCreateError::NoShaderCompiler);
1659        }
1660
1661        fn str_to_bytes(input: &str) -> Vec<u8> {
1662            let mut v: Vec<u8> = input.into();
1663            v.push(0);
1664            v
1665        }
1666
1667        let vertex_shader_source = str_to_bytes(vertex_shader);
1668        let fragment_shader_source = str_to_bytes(fragment_shader);
1669
1670        // Compile vertex shader
1671
1672        let vertex_shader_object = gl_context.create_shader(gl::VERTEX_SHADER);
1673        gl_context.shader_source(vertex_shader_object, &[&vertex_shader_source]);
1674        gl_context.compile_shader(vertex_shader_object);
1675
1676        #[cfg(debug_assertions)] {
1677            if let Some(error_id) = get_gl_shader_error(&*gl_context, vertex_shader_object) {
1678                let info_log = gl_context.get_shader_info_log(vertex_shader_object);
1679                gl_context.delete_shader(vertex_shader_object);
1680                return Err(GlShaderCreateError::Compile(GlShaderCompileError::Vertex(VertexShaderCompileError { error_id, info_log })));
1681            }
1682        }
1683
1684        // Compile fragment shader
1685
1686        let fragment_shader_object = gl_context.create_shader(gl::FRAGMENT_SHADER);
1687        gl_context.shader_source(fragment_shader_object, &[&fragment_shader_source]);
1688        gl_context.compile_shader(fragment_shader_object);
1689
1690        #[cfg(debug_assertions)] {
1691            if let Some(error_id) = get_gl_shader_error(&*gl_context, fragment_shader_object) {
1692                let info_log = gl_context.get_shader_info_log(fragment_shader_object);
1693                gl_context.delete_shader(vertex_shader_object);
1694                gl_context.delete_shader(fragment_shader_object);
1695                return Err(GlShaderCreateError::Compile(GlShaderCompileError::Fragment(FragmentShaderCompileError { error_id, info_log })));
1696            }
1697        }
1698
1699        // Link program
1700
1701        let program_id = gl_context.create_program();
1702        gl_context.attach_shader(program_id, vertex_shader_object);
1703        gl_context.attach_shader(program_id, fragment_shader_object);
1704        gl_context.link_program(program_id);
1705
1706        #[cfg(debug_assertions)] {
1707            if let Some(error_id) = get_gl_program_error(&*gl_context, program_id) {
1708                let info_log = gl_context.get_program_info_log(program_id);
1709                gl_context.delete_shader(vertex_shader_object);
1710                gl_context.delete_shader(fragment_shader_object);
1711                gl_context.delete_program(program_id);
1712                return Err(GlShaderCreateError::Link(GlShaderLinkError { error_id, info_log }));
1713            }
1714        }
1715
1716        gl_context.delete_shader(vertex_shader_object);
1717        gl_context.delete_shader(fragment_shader_object);
1718
1719        Ok(GlShader { program_id, gl_context })
1720    }
1721
1722    /// Draws vertex buffers, index buffers + uniforms to the currently bound framebuffer
1723    ///
1724    /// **NOTE: `FrameBuffer::bind()` and `VertexBuffer::bind()` have to be called first!**
1725    pub fn draw<T: VertexLayoutDescription>(
1726        &mut self,
1727        buffers: &[(Rc<VertexBuffer<T>>, Vec<Uniform>)],
1728        clear_color: Option<ColorU>,
1729        texture_size: LogicalSize,
1730    ) -> Texture {
1731
1732        use std::ops::Deref;
1733        use std::collections::HashMap;
1734
1735        const INDEX_TYPE: GLuint = gl::UNSIGNED_INT;
1736
1737        let gl_context = &*self.gl_context;
1738
1739        // save the OpenGL state
1740        let mut current_multisample = [0_u8];
1741        let mut current_index_buffer = [0_i32];
1742        let mut current_vertex_buffer = [0_i32];
1743        let mut current_vertex_array_object = [0_i32];
1744        let mut current_program = [0_i32];
1745        let mut current_framebuffers = [0_i32];
1746        let mut current_renderbuffers = [0_i32];
1747        let mut current_texture_2d = [0_i32];
1748
1749        unsafe { gl_context.get_boolean_v(gl::MULTISAMPLE, &mut current_multisample) };
1750        unsafe { gl_context.get_integer_v(gl::ARRAY_BUFFER_BINDING, &mut current_vertex_buffer) };
1751        unsafe { gl_context.get_integer_v(gl::ELEMENT_ARRAY_BUFFER_BINDING, &mut current_index_buffer) };
1752        unsafe { gl_context.get_integer_v(gl::CURRENT_PROGRAM, &mut current_program) };
1753        unsafe { gl_context.get_integer_v(gl::VERTEX_ARRAY_BINDING, &mut current_vertex_array_object) };
1754        unsafe { gl_context.get_integer_v(gl::RENDERBUFFER, &mut current_renderbuffers) };
1755        unsafe { gl_context.get_integer_v(gl::FRAMEBUFFER, &mut current_framebuffers) };
1756        unsafe { gl_context.get_integer_v(gl::TEXTURE_2D, &mut current_texture_2d) };
1757
1758        // 1. Create the texture + framebuffer
1759
1760        let textures = gl_context.gen_textures(1);
1761        let texture_id = textures[0];
1762        let framebuffers = gl_context.gen_framebuffers(1);
1763        let framebuffer_id = framebuffers[0];
1764        gl_context.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_id);
1765
1766        let depthbuffers = gl_context.gen_renderbuffers(1);
1767        let depthbuffer_id = depthbuffers[0];
1768
1769        gl_context.bind_texture(gl::TEXTURE_2D, texture_id);
1770        gl_context.tex_image_2d(gl::TEXTURE_2D, 0, gl::RGBA as i32, texture_size.width as i32, texture_size.height as i32, 0, gl::RGBA, gl::UNSIGNED_BYTE, None);
1771        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
1772        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
1773        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
1774        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
1775
1776        gl_context.bind_renderbuffer(gl::RENDERBUFFER, depthbuffer_id);
1777        gl_context.renderbuffer_storage(gl::RENDERBUFFER, gl::DEPTH_COMPONENT, texture_size.width as i32, texture_size.height as i32);
1778        gl_context.framebuffer_renderbuffer(gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, gl::RENDERBUFFER, depthbuffer_id);
1779
1780        gl_context.framebuffer_texture_2d(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, texture_id, 0);
1781        gl_context.draw_buffers(&[gl::COLOR_ATTACHMENT0]);
1782        gl_context.viewport(0, 0, texture_size.width as i32, texture_size.height as i32);
1783
1784        debug_assert!(gl_context.check_frame_buffer_status(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE);
1785
1786        gl_context.use_program(self.program_id);
1787        gl_context.disable(gl::MULTISAMPLE);
1788
1789        // Avoid multiple calls to get_uniform_location by caching the uniform locations
1790        let mut uniform_locations: HashMap<String, i32> = HashMap::new();
1791        let mut max_uniform_len = 0;
1792        for (_, uniforms) in buffers {
1793            for uniform in uniforms.iter() {
1794                if !uniform_locations.contains_key(&uniform.name) {
1795                    uniform_locations.insert(uniform.name.clone(), gl_context.get_uniform_location(self.program_id, &uniform.name));
1796                }
1797            }
1798            max_uniform_len = max_uniform_len.max(uniforms.len());
1799        }
1800        let mut current_uniforms = vec![None;max_uniform_len];
1801
1802        // Since the description of the vertex buffers is always the same, only the first layer needs to bind its VAO
1803
1804
1805        if let Some(clear_color) = clear_color {
1806            let clear_color: ColorF = clear_color.into();
1807            gl_context.clear_color(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
1808        }
1809
1810        gl_context.clear_depth(0.0);
1811        gl_context.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
1812
1813        // Draw the actual layers
1814        for (vi, uniforms) in buffers {
1815
1816            let vertex_buffer = vi.deref();
1817
1818            gl_context.bind_vertex_array(vertex_buffer.vao.vao_id);
1819            // NOTE: Technically not required, but some drivers...
1820            gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, vertex_buffer.index_buffer_id);
1821
1822            // Only set the uniform if the value has changed
1823            for (uniform_index, uniform) in uniforms.iter().enumerate() {
1824                if current_uniforms[uniform_index] != Some(uniform.uniform_type) {
1825                    let uniform_location = uniform_locations[&uniform.name];
1826                    uniform.uniform_type.set(gl_context, uniform_location);
1827                    current_uniforms[uniform_index] = Some(uniform.uniform_type);
1828                }
1829            }
1830
1831            gl_context.draw_elements(vertex_buffer.index_buffer_format.get_gl_id(), vertex_buffer.index_buffer_len as i32, INDEX_TYPE, 0);
1832        }
1833
1834        // Reset the OpenGL state to what it was before
1835        if current_multisample[0] == gl::TRUE { gl_context.enable(gl::MULTISAMPLE); }
1836        gl_context.bind_vertex_array(current_vertex_array_object[0] as u32);
1837        gl_context.bind_framebuffer(gl::FRAMEBUFFER, current_framebuffers[0] as u32);
1838        gl_context.bind_texture(gl::TEXTURE_2D, current_texture_2d[0] as u32);
1839        gl_context.bind_texture(gl::RENDERBUFFER, current_renderbuffers[0] as u32);
1840        gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, current_index_buffer[0] as u32);
1841        gl_context.bind_buffer(gl::ARRAY_BUFFER, current_vertex_buffer[0] as u32);
1842        gl_context.use_program(current_program[0] as u32);
1843
1844        gl_context.delete_framebuffers(&[framebuffer_id]);
1845        gl_context.delete_renderbuffers(&[depthbuffer_id]);
1846
1847        Texture {
1848            texture_id,
1849            size: texture_size,
1850            flags: TextureFlags {
1851                is_opaque: true,
1852                is_video_texture: false,
1853            },
1854            gl_context: self.gl_context.clone(),
1855        }
1856    }
1857}
1858
1859#[cfg(debug_assertions)]
1860fn get_gl_shader_error(context: &dyn Gl, shader_object: GLuint) -> Option<i32> {
1861    let mut err = [0];
1862    unsafe { context.get_shader_iv(shader_object, gl::COMPILE_STATUS, &mut err) };
1863    let err_code = err[0];
1864    if err_code == gl::TRUE as i32 { None } else { Some(err_code) }
1865}
1866
1867#[cfg(debug_assertions)]
1868fn get_gl_program_error(context: &dyn Gl, shader_object: GLuint) -> Option<i32> {
1869    let mut err = [0];
1870    unsafe { context.get_program_iv(shader_object, gl::LINK_STATUS, &mut err) };
1871    let err_code = err[0];
1872    if err_code == gl::TRUE as i32 { None } else { Some(err_code) }
1873}