Skip to main content

window/opengl/
mod.rs

1// Window
2// Copyright © 2019-2021 Jeron Aldaron Lau.
3//
4// Licensed under any of:
5// - Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
6// - MIT License (https://mit-license.org/)
7// - Boost Software License, Version 1.0 (https://www.boost.org/LICENSE_1_0.txt)
8// At your choosing (See accompanying files LICENSE_APACHE_2_0.txt,
9// LICENSE_MIT.txt and LICENSE_BOOST_1_0.txt).
10
11use std::cell::Cell;
12use std::collections::HashMap;
13use std::ffi::c_void;
14
15use super::Draw;
16use super::DrawHandle;
17use crate::Ngraphic;
18use crate::Ngroup;
19use crate::Nshader;
20use crate::Transform;
21
22mod platform;
23
24// Position
25const GL_ATTRIB_POS: u32 = 0;
26// Texture Coordinates Begin (May have multiple)
27const GL_ATTRIB_TEX: u32 = 1;
28// Color
29const GL_ATTRIB_COL: u32 = 2;
30
31const GL_RGBA: u32 = 0x1908;
32const GL_TEXTURE_2D: u32 = 0x0DE1;
33
34const GL_ARRAY_BUFFER: u32 = 0x8892;
35const GL_ELEMENT_ARRAY_BUFFER: u32 = 0x8893;
36
37extern "C" {
38    fn glGetError() -> u32;
39}
40
41#[allow(unused)]
42fn _get_error(string: &str) {
43    match unsafe { glGetError() } {
44        0 => println!("GL {}", string),
45        0x0500 => panic!("OpenGL '{}()': Invalid Enum", string),
46        0x0501 => panic!("OpenGL '{}()': Invalid Value", string),
47        0x0502 => panic!("OpenGL '{}()': Invalid Operation", string),
48        0x0503 => panic!("OpenGL '{}()': Invalid Stack Overflow", string),
49        0x0504 => panic!("OpenGL '{}()': Invalid Stack Underflow", string),
50        0x0505 => panic!("OpenGL '{}()': Invalid Out of Memory", string),
51        u => panic!("OpenGL '{}()': Unknown Error {}", string, u),
52    }
53}
54
55#[cfg(feature = "gpu-debugging")]
56macro_rules! gl_assert {
57    ($x:expr) => {
58        _get_error($x);
59    };
60}
61
62#[cfg(not(feature = "gpu-debugging"))]
63macro_rules! gl_assert {
64    ($x:expr) => {};
65}
66
67#[link(name = "EGL")]
68//#[link(name = "GL")]
69#[link(name = "GLESv2")]
70extern "C" {
71    fn eglGetDisplay(
72        native_display: self::platform::NativeDisplayType,
73    ) -> *mut c_void;
74    fn eglInitialize(dpy: *mut c_void, major: *mut i32, minor: *mut i32)
75        -> u32;
76    fn eglBindAPI(api: u32) -> u32;
77    fn eglChooseConfig(
78        dpy: *mut c_void,
79        attrib_list: *const i32,
80        configs: *mut *mut c_void,
81        config_size: i32,
82        num_config: *mut i32,
83    ) -> u32;
84    fn eglCreateContext(
85        dpy: *mut c_void,
86        config: *mut c_void,
87        share_context: *mut c_void,
88        attrib_list: *const i32,
89    ) -> *mut c_void;
90    fn eglCreateWindowSurface(
91        dpy: *mut c_void,
92        config: *mut c_void,
93        win: usize, // EGLNativeWindowType
94        attrib_list: *const i32,
95    ) -> *mut c_void;
96    fn eglMakeCurrent(
97        dpy: *mut c_void,
98        draw: *mut c_void,
99        read: *mut c_void,
100        ctx: *mut c_void,
101    ) -> u32;
102    fn eglTerminate(dpy: *mut c_void) -> u32;
103    fn eglReleaseThread() -> u32;
104    fn eglSwapBuffers(dpy: *mut c_void, surface: *mut c_void) -> u32;
105
106    // OpenGL
107    fn glCreateProgram() -> u32;
108    fn glAttachShader(program: u32, shader: u32);
109    fn glLinkProgram(program: u32);
110    fn glGetProgramiv(program: u32, pname: u32, params: *mut i32);
111    fn glGetProgramInfoLog(
112        program: u32,
113        max_len: i32,
114        length: *mut i32,
115        info_log: *mut i8,
116    );
117    fn glUseProgram(program: u32);
118    fn glBindAttribLocation(program: u32, index: u32, name: *const i8);
119    fn glGetUniformLocation(program: u32, name: *const i8) -> i32;
120    fn glCreateShader(shader_type: u32) -> u32;
121    fn glShaderSource(
122        shader: u32,
123        count: i32,
124        string: *const *const i8,
125        length: *const i32,
126    );
127    fn glCompileShader(shader: u32);
128    fn glGetShaderiv(shader: u32, pname: u32, params: *mut i32);
129    fn glGetShaderInfoLog(
130        shader: u32,
131        max_length: i32,
132        length: *mut i32,
133        infoLog: *mut i8,
134    );
135    //
136    fn glUniformMatrix4fv(
137        location: i32,
138        count: i32,
139        transpose: u8,
140        value: *const c_void,
141    );
142    fn glUniform4f(location: i32, v0: f32, v1: f32, v2: f32, v3: f32);
143    fn glClearColor(red: f32, green: f32, blue: f32, alpha: f32);
144    fn glClear(mask: u32);
145    fn glVertexAttribPointer(
146        indx: u32,
147        size: i32,
148        stype: u32,
149        normalized: u32,
150        stride: i32,
151        ptr: *const f32,
152    );
153    fn glDisable(cap: u32);
154    fn glEnable(cap: u32);
155    fn glEnableVertexAttribArray(index: u32);
156    fn glDisableVertexAttribArray(index: u32);
157    fn glDrawElements(
158        mode: u32,
159        count: i32,
160        draw_type: u32,
161        indices: *const c_void,
162    );
163    fn glGenBuffers(n: i32, buffers: *mut u32);
164    fn glBindBuffer(target: u32, buffer: u32);
165    fn glBufferData(target: u32, size: isize, data: *const c_void, usage: u32);
166    fn glBufferSubData(
167        target: u32,
168        offs: isize,
169        size: isize,
170        data: *const c_void,
171    );
172    fn glDeleteBuffers(n: i32, buffers: *const u32);
173    // fn glGetString(name: u32) -> *const u8;
174    fn glGenTextures(n: u32, textures: *mut u32);
175    fn glBindTexture(target: u32, texture: u32);
176    fn glTexParameteri(target: u32, pname: u32, param: i32);
177    fn glTexImage2D(
178        target: u32,
179        level: i32,
180        internalFormat: i32,
181        width: i32,
182        height: i32,
183        border: i32,
184        format: u32,
185        stype: u32,
186        pixels: *const u8,
187    );
188    fn glGenerateMipmap(target: u32);
189    fn glViewport(x: i32, y: i32, width: i32, height: i32);
190    fn glBlendFuncSeparate(a: u32, b: u32, c: u32, d: u32);
191}
192
193/// A shader.  Shaders are a program that runs on the GPU to render a `Shape`.
194pub struct Shader {
195    // An OpenGL shader program ID.
196    program: u32,
197    // True if OpenGL color vertex attribute exists.
198    gradient: bool,
199    // Some if OpenGL texture uniform exists.
200    graphic: bool,
201    // Some if 3D.
202    camera: i32,
203    // Some if tint.
204    tint: Option<i32>,
205    // True if transparency is allowed.
206    blending: bool,
207    // Z coordinate?
208    depth: bool,
209}
210
211///
212pub struct Graphic {
213    id: u32,
214    pixels: Vec<u8>,
215    width: i32,
216}
217
218impl Graphic {
219    pub fn new(pixels: &[u8], width: usize, height: usize) -> Self {
220        debug_assert!(pixels.len() >= width * height * 4);
221
222        let mut width = width as i32;
223        let mut height = height as i32;
224
225        let new_texture = unsafe {
226            let mut new_texture = std::mem::MaybeUninit::uninit();
227            glGenTextures(1, new_texture.as_mut_ptr());
228            gl_assert!("glGenTextures");
229            new_texture.assume_init()
230        };
231
232        unsafe {
233            const GL_TEXTURE_MAG_FILTER: u32 = 0x2800;
234            const GL_TEXTURE_MIN_FILTER: u32 = 0x2801;
235            const GL_NEAREST: i32 = 0x2600;
236            const GL_NEAREST_MIPMAP_LINEAR: i32 = 0x2702;
237            // const GL_NEAREST_MIPMAP_NEAREST: i32 = 0x2700;
238
239            glBindTexture(GL_TEXTURE_2D, new_texture);
240            gl_assert!("glBindTexture");
241
242            // Rendered smaller than texture
243            glTexParameteri(
244                GL_TEXTURE_2D,
245                GL_TEXTURE_MIN_FILTER,
246                GL_NEAREST_MIPMAP_LINEAR,
247            );
248            gl_assert!("glTexParameteri#1");
249            // Rendered bigger than texture.
250            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
251            gl_assert!("glTexParameteri#2");
252
253            glTexImage2D(
254                GL_TEXTURE_2D,
255                0,
256                GL_RGBA as i32,
257                width,
258                height,
259                0,
260                GL_RGBA,
261                0x1401, /*GL_UNSIGNED_BYTE*/
262                pixels.as_ptr() as *const _,
263            );
264            gl_assert!("glTexImage2D");
265
266            // Generate Mipmaps.
267            let mut mipmap_level = 0;
268            let mut offset = width as usize * height as usize * 4;
269            //            let mut skip = 1;
270            while width > 1 && height > 1 && offset != pixels.len() {
271                // 2 ^ 5
272                // Divide width & height.
273                width /= 2;
274                height /= 2;
275                // Increase mipmap level.
276                mipmap_level += 1;
277
278                glTexImage2D(
279                    GL_TEXTURE_2D,
280                    mipmap_level,
281                    GL_RGBA as i32,
282                    width,
283                    height,
284                    0,
285                    GL_RGBA,
286                    0x1401, /*GL_UNSIGNED_BYTE*/
287                    pixels[offset..].as_ptr() as *const _,
288                );
289                gl_assert!("glTexImage2D");
290
291                offset += width as usize * height as usize * 4;
292            }
293
294            glTexParameteri(
295                GL_TEXTURE_2D,
296                0x813D, /*GL_TEXTURE_MAX_LEVEL*/
297                mipmap_level,
298            );
299            gl_assert!("glTexParameteri#3");
300        }
301
302        Graphic {
303            id: new_texture,
304            pixels: pixels.to_vec(),
305            width,
306        }
307    }
308}
309
310/// A shape.  Shapes are a list of indices into `Vertices`.
311pub struct Group {
312    index_buf: u32,
313    indices: Vec<u32>,
314    vertex_buf: u32,
315    vertices: Vec<f32>,
316    dirty_vertex_size: Cell<bool>,
317    dirty_index_size: Cell<bool>,
318    dirty_data: Cell<bool>,
319}
320
321impl Group {
322    /// Create a new group.
323    pub fn new() -> Group {
324        let (index_buf, indices) = vbo_new::<u32>(GL_ELEMENT_ARRAY_BUFFER);
325        let (vertex_buf, vertices) = vbo_new::<f32>(GL_ARRAY_BUFFER);
326
327        Group {
328            index_buf,
329            indices,
330            vertex_buf,
331            vertices,
332            dirty_vertex_size: Cell::new(false),
333            dirty_index_size: Cell::new(false),
334            dirty_data: Cell::new(false),
335        }
336    }
337}
338
339impl Ngroup for Group {
340    fn len(&self) -> i32 {
341        self.indices.len() as i32
342    }
343
344    fn bind(&self) {
345        if self.dirty_data.get() {
346            if self.dirty_vertex_size.get() {
347                vbo_resize::<f32>(
348                    GL_ARRAY_BUFFER,
349                    self.vertex_buf,
350                    &self.vertices,
351                );
352                self.dirty_vertex_size.set(false);
353            } else {
354                vbo_set::<f32>(
355                    GL_ARRAY_BUFFER,
356                    self.vertex_buf,
357                    0,
358                    self.vertices.len(),
359                    &self.vertices,
360                );
361            }
362            if self.dirty_index_size.get() {
363                vbo_resize::<u32>(
364                    GL_ELEMENT_ARRAY_BUFFER,
365                    self.index_buf,
366                    &self.indices,
367                );
368                self.dirty_index_size.set(false);
369            } else {
370                vbo_set::<u32>(
371                    GL_ELEMENT_ARRAY_BUFFER,
372                    self.index_buf,
373                    0,
374                    self.indices.len(),
375                    &self.indices,
376                );
377            }
378            self.dirty_data.set(false);
379        }
380
381        debug_assert_ne!(self.index_buf, 0);
382        unsafe {
383            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buf);
384            gl_assert!("glBindBuffer#Element");
385        }
386        debug_assert_ne!(self.vertex_buf, 0);
387        unsafe {
388            glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buf);
389            gl_assert!("glBindBuffer");
390        }
391    }
392
393    fn id(&self) -> u32 {
394        self.index_buf
395    }
396
397    fn write(
398        &mut self,
399        location: (usize, usize),
400        shape: &crate::Shape,
401        transform: &crate::Transform,
402    ) -> (usize, usize) {
403        self.write_texcoords(
404            location,
405            shape,
406            transform,
407            ([0.0, 0.0], [1.0, 1.0]),
408        )
409    }
410
411    fn write_texcoords(
412        &mut self,
413        location: (usize, usize),
414        shape: &crate::Shape,
415        transform: &crate::Transform,
416        tex_coords: ([f32; 2], [f32; 2]),
417    ) -> (usize, usize) {
418        let initial_vertex_cap = self.vertices.capacity();
419        let initial_index_cap = self.indices.capacity();
420
421        if self.indices.len() == location.0 && self.vertices.len() == location.1
422        {
423            let vertex_offset = self.vertices.len() as u32 / shape.stride;
424            for index in shape.indices.iter() {
425                self.indices.push(index + vertex_offset);
426            }
427            for i in 0..(shape.vertices.len() / shape.stride as usize) {
428                let offset = i * shape.stride as usize;
429
430                let vector = *transform
431                    * if shape.dimensions == 3 {
432                        [
433                            shape.vertices[offset],
434                            shape.vertices[offset + 1],
435                            shape.vertices[offset + 2],
436                        ]
437                    } else {
438                        [
439                            shape.vertices[offset],
440                            shape.vertices[offset + 1],
441                            0.0,
442                        ]
443                    };
444
445                self.vertices.push(vector[0]);
446                self.vertices.push(vector[1]);
447                if shape.dimensions == 3 {
448                    self.vertices.push(vector[2]);
449                }
450
451                // Check to see if there is extra texture coordinate data.
452                if shape.dimensions + shape.components + 2 == shape.stride {
453                    self.vertices.push(
454                        shape.vertices[offset + shape.dimensions as usize]
455                            * tex_coords.1[0]
456                            + tex_coords.0[0],
457                    );
458                    self.vertices.push(
459                        shape.vertices[offset + shape.dimensions as usize + 1]
460                            * tex_coords.1[1]
461                            + tex_coords.0[1],
462                    );
463                }
464
465                for i in (shape.stride - shape.components)..shape.stride {
466                    self.vertices.push(shape.vertices[offset + i as usize]);
467                }
468            }
469        } else {
470            for (i, index) in shape.indices.iter().enumerate() {
471                self.indices[location.0 + i] = index + location.1 as u32;
472            }
473            for i in 0..(shape.vertices.len() / shape.stride as usize) {
474                let offset = i * shape.stride as usize;
475
476                let vector = *transform
477                    * if shape.dimensions == 3 {
478                        [
479                            shape.vertices[offset],
480                            shape.vertices[offset + 1],
481                            shape.vertices[offset + 2],
482                        ]
483                    } else {
484                        [
485                            shape.vertices[offset],
486                            shape.vertices[offset + 1],
487                            0.0,
488                        ]
489                    };
490
491                let mut j = 0;
492                let ofsj = location.1 + i * shape.stride as usize;
493                self.vertices[ofsj + j] = vector[0];
494                j += 1;
495                self.vertices[ofsj + j] = vector[1];
496                j += 1;
497                if shape.dimensions == 3 {
498                    self.vertices[ofsj + j] = vector[2];
499                    j += 1;
500                }
501
502                // Check to see if there is extra texture coordinate data.
503                if shape.dimensions + shape.components + 2 == shape.stride {
504                    self.vertices[ofsj + j] = shape.vertices
505                        [offset + shape.dimensions as usize]
506                        * tex_coords.1[0]
507                        + tex_coords.0[0];
508                    j += 1;
509                    self.vertices[ofsj + j] = shape.vertices
510                        [offset + shape.dimensions as usize + 1]
511                        * tex_coords.1[1]
512                        + tex_coords.0[1];
513                    j += 1;
514                }
515
516                for i in (shape.stride - shape.components)..shape.stride {
517                    self.vertices[ofsj + j] =
518                        shape.vertices[offset + i as usize];
519                    j += 1;
520                }
521            }
522        }
523
524        if initial_vertex_cap != self.vertices.capacity() {
525            self.dirty_vertex_size.set(true);
526        }
527
528        if initial_index_cap != self.indices.capacity() {
529            self.dirty_index_size.set(true);
530        }
531
532        self.dirty_data.set(true);
533
534        (self.indices.len(), self.vertices.len())
535    }
536}
537
538impl Drop for Group {
539    fn drop(&mut self) {
540        unsafe {
541            glDeleteBuffers(1, &self.index_buf);
542            glDeleteBuffers(1, &self.vertex_buf);
543        }
544    }
545}
546
547impl Shader {
548    pub fn new(builder: crate::ShaderBuilder) -> Self {
549        create_program(builder)
550    }
551}
552
553impl Nshader for Shader {
554    fn tint(&self) -> Option<i32> {
555        self.tint
556    }
557
558    fn depth(&self) -> bool {
559        self.depth
560    }
561
562    fn camera(&self) -> i32 {
563        self.camera
564    }
565
566    fn gradient(&self) -> bool {
567        self.gradient
568    }
569
570    fn graphic(&self) -> bool {
571        self.graphic
572    }
573
574    fn blending(&self) -> bool {
575        self.blending
576    }
577
578    fn bind(&self) {
579        unsafe {
580            debug_assert_ne!(self.program, 0);
581            glUseProgram(self.program);
582            gl_assert!(&format!("glUseProgram {}", self.program));
583        }
584    }
585
586    fn program(&self) -> u32 {
587        self.program
588    }
589}
590
591impl Ngraphic for Graphic {
592    fn id(&self) -> u32 {
593        self.id
594    }
595
596    fn width(&self) -> u16 {
597        self.width as u16
598    }
599
600    fn height(&self) -> u16 {
601        (((self.pixels.len() / 4) as u32) / self.width as u32) as u16
602    }
603
604    fn resize(&mut self, pixels: &[u8], width: usize) {
605        let width = width as i32;
606
607        self.width = width;
608        self.pixels = pixels.to_vec();
609
610        unsafe {
611            glBindTexture(GL_TEXTURE_2D, self.id);
612            gl_assert!("glBindTexture");
613
614            glTexImage2D(
615                GL_TEXTURE_2D,
616                0,
617                GL_RGBA as i32,
618                width,                               // w
619                ((pixels.len() / 4) as i32) / width, // h
620                0,
621                GL_RGBA,
622                0x1401, /*GL_UNSIGNED_BYTE*/
623                pixels.as_ptr() as *const _,
624            );
625            gl_assert!("glTexImage2D");
626
627            glGenerateMipmap(GL_TEXTURE_2D);
628            gl_assert!("glGenerateMipmap");
629        }
630    }
631
632    fn update(&mut self, updater: &mut dyn FnMut(&mut [u8], u16)) {
633        updater(self.pixels.as_mut_slice(), self.width as u16);
634
635        unsafe {
636            glBindTexture(GL_TEXTURE_2D, self.id);
637            gl_assert!("glBindTexture");
638
639            glTexImage2D(
640                GL_TEXTURE_2D,
641                0,
642                GL_RGBA as i32,
643                self.width,                                    // w
644                ((self.pixels.len() / 4) as i32) / self.width, // h
645                0,
646                GL_RGBA,
647                0x1401, /*GL_UNSIGNED_BYTE*/
648                self.pixels.as_ptr() as *const _,
649            );
650            gl_assert!("glTexImage2D");
651        }
652    }
653}
654
655struct ShaderData {
656    dirty_transform: bool, // If matrix needs to be updated.
657    matrix: [[f32; 4]; 4], // Transform matrix, minus coordinate system.
658}
659
660pub struct OpenGL {
661    surface: *mut c_void,
662    display: *mut c_void,
663    context: *mut c_void,
664    config: *mut c_void,
665    graphic: u32,
666    depth: bool,
667    blending: bool,
668    shader: u32,
669    shape_id: u32,
670    vaa_col: bool,
671    vaa_tex: bool,
672    shaders: HashMap<u32, ShaderData>,
673    cam: Transform,
674    height: f32,
675    near: f32,
676    horizon: f32,
677}
678
679impl OpenGL {
680    #[cfg(unix)]
681    #[allow(clippy::new_ret_no_self)] // It's basically Self, in a weird way.
682    pub(super) fn new(nwin: &mut dyn crate::Nwin) -> Option<Box<dyn Draw>> {
683        let (display, config, context) = unsafe {
684            // Get EGL Display from Window.
685            let display = eglGetDisplay(match nwin.handle() {
686                #[cfg(not(any(
687                    target_os = "android",
688                    target_os = "macos",
689                    target_os = "ios"
690                )))]
691                crate::NwinHandle::Wayland(handle) => handle,
692            });
693            debug_assert!(!display.is_null());
694
695            // Initialize EGL Display.
696            let mut major = std::mem::MaybeUninit::uninit();
697            let mut minor = std::mem::MaybeUninit::uninit();
698            let ret =
699                eglInitialize(display, major.as_mut_ptr(), minor.as_mut_ptr());
700            debug_assert_eq!(ret, 1);
701
702            // Connect EGL to either OpenGL or OpenGLES, whichever is available.
703            // TODO: also support /*OPENGL:*/ 0x30A2
704            let ret = eglBindAPI(/*OPENGL_ES:*/ 0x30A0);
705            debug_assert_eq!(ret, 1);
706
707            //
708            let mut config = std::mem::MaybeUninit::<*mut c_void>::uninit();
709            let mut n = std::mem::MaybeUninit::<i32>::uninit();
710            let ret = eglChooseConfig(
711                display,
712                [
713                    /*EGL_SURFACE_TYPE:*/ 0x3033,
714                    /*EGL_WINDOW_BIT:*/ 0x04,
715                    /*EGL_RED_SIZE:*/ 0x3024, 8,
716                    /*EGL_GREEN_SIZE:*/ 0x3023, 8,
717                    /*EGL_BLUE_SIZE:*/ 0x3022, 8,
718                    // A bug in some versions of wayland? or mesa?, means alpha
719                    // should always be set to match R,G,B to avoid crashing.
720                    /*EGL_ALPHA_SIZE:*/
721                    0x3021, 8, /*EGL_DEPTH_SIZE*/
722                    0x3025, 24, /*EGL_RENDERABLE_TYPE:*/ 0x3040,
723                    /*EGL_OPENGL_ES2_BIT:*/ 0x0004,
724                    /*EGL_NONE:*/ 0x3038,
725                ]
726                .as_ptr(),
727                config.as_mut_ptr(),
728                1,
729                n.as_mut_ptr(),
730            );
731            debug_assert_eq!(ret, 1);
732
733            let config = config.assume_init();
734
735            //
736            let context = eglCreateContext(
737                display,
738                config,
739                std::ptr::null_mut(),
740                [
741                    /*EGL_CONTEXT_CLIENT_VERSION:*/ 0x3098, 2,
742                    /*EGL_NONE:*/ 0x3038,
743                ]
744                .as_ptr(),
745            );
746            debug_assert!(!context.is_null());
747
748            (display, config, context)
749        };
750
751        let height = 480.0 / 640.0;
752        let near = 0.01; // 1cm
753        let horizon = 5000.0; // 5km
754
755        let draw: OpenGL = OpenGL {
756            display,
757            config,
758            context,
759            surface: std::ptr::null_mut(),
760            graphic: 0,
761            depth: false,
762            blending: false,
763            shader: 0,
764            shape_id: std::u32::MAX,
765            vaa_col: false,
766            vaa_tex: false,
767            shaders: HashMap::new(),
768            cam: Transform::new(),
769            height,
770            near,
771            horizon,
772        };
773
774        Some(Box::new(draw))
775    }
776}
777
778impl Drop for OpenGL {
779    fn drop(&mut self) {
780        unsafe {
781            eglMakeCurrent(
782                self.display,
783                std::ptr::null_mut(),
784                std::ptr::null_mut(),
785                std::ptr::null_mut(),
786            );
787            eglTerminate(self.display);
788            eglReleaseThread();
789        }
790    }
791}
792
793impl Draw for OpenGL {
794    fn handle(&self) -> DrawHandle {
795        // TODO
796        DrawHandle::Gl(std::ptr::null_mut())
797    }
798
799    fn connect(&mut self, connection: *mut c_void) {
800        // Finish connecting EGL.
801        self.surface = unsafe {
802            eglCreateWindowSurface(
803                self.display,
804                self.config,
805                connection as usize,
806                std::ptr::null(),
807            )
808        };
809        let ret = unsafe {
810            eglMakeCurrent(
811                self.display,
812                self.surface,
813                self.surface,
814                self.context,
815            )
816        };
817        debug_assert_ne!(ret, 0);
818
819        // Configuration (TODO)
820
821        unsafe {
822            glEnable(0x0B44 /*GL_CULL_FACES*/);
823            gl_assert!("glEnable#0");
824            glDisable(0x0BD0 /*GL_DITHER*/);
825            gl_assert!("glDisable#0");
826        }
827
828        unsafe {
829            // Alpha Blending.
830            glBlendFuncSeparate(
831                /* GL_SRC_ALPHA */ 0x0302u32,
832                /* GL_ONE_MINUS_SRC_ALPHA*/ 0x0303u32,
833                /* GL_SRC_ALPHA */ 0x0302u32,
834                /* GL_DST_ALPHA */ 0x0304u32,
835            );
836            gl_assert!("glBlendFuncSeparate");
837        }
838
839        /*        unsafe {
840            let string = glGetString(0x1F03 /*gl extensions*/);
841            let slice = std::ffi::CStr::from_ptr(string as *const _ as *const _);
842            println!("ext: {}", slice.to_str().unwrap().contains("GL_EXT_base_instance"));
843        }*/
844
845        // Set default background for OpenGL.
846        self.background(0.0, 0.0, 1.0);
847    }
848
849    fn background(&mut self, r: f32, g: f32, b: f32) {
850        unsafe {
851            glClearColor(r, g, b, 1.0);
852            gl_assert!("glClearColor");
853        }
854    }
855
856    fn shader_new(
857        &mut self,
858        builder: crate::ShaderBuilder,
859    ) -> Box<dyn Nshader> {
860        let shader = Shader::new(builder);
861        self.shaders.insert(
862            shader.program(),
863            ShaderData {
864                dirty_transform: true,
865                matrix: [
866                    [1.0, 0.0, 0.0, 0.0],
867                    [0.0, 1.0, 0.0, 0.0],
868                    [0.0, 0.0, 1.0, 0.0],
869                    [0.0, 0.0, 0.0, 1.0],
870                ],
871            },
872        );
873        Box::new(shader)
874    }
875
876    fn group_new(&mut self) -> Box<dyn Ngroup> {
877        Box::new(Group::new())
878    }
879
880    fn begin_draw(&mut self) {
881        self.shape_id = std::u32::MAX;
882        unsafe {
883            glClear(
884                0x0000_4000 /*GL_COLOR_BUFFER_BIT*/ | 0x0000_0100, /*GL_DEPTH_BUFFER_BIT*/
885            );
886            gl_assert!("glClear");
887        }
888        unsafe { glEnableVertexAttribArray(GL_ATTRIB_POS) }
889        gl_assert!("glEnableVertexAttribArray#4");
890    }
891
892    fn finish_draw(&mut self) {
893        unsafe { glDisableVertexAttribArray(GL_ATTRIB_POS) }
894        gl_assert!("glDisableVertexAttribArray#4");
895        unsafe {
896            eglSwapBuffers(self.display, self.surface);
897        }
898    }
899
900    fn draw(&mut self, shader: &dyn Nshader, shape: &dyn Ngroup) {
901        if self.bind_shader(shader) {
902            if !self.vaa_col && shader.gradient() {
903                unsafe { glEnableVertexAttribArray(GL_ATTRIB_COL) }
904                gl_assert!("glEnableVertexAttribArray#2");
905                self.vaa_col = true;
906            }
907            if !self.vaa_tex && shader.graphic() {
908                unsafe { glEnableVertexAttribArray(GL_ATTRIB_TEX) }
909                gl_assert!("glEnableVertexAttribArray#3");
910                self.vaa_tex = true;
911            }
912            if self.vaa_col && !shader.gradient() {
913                unsafe { glDisableVertexAttribArray(GL_ATTRIB_COL) }
914                gl_assert!("glDisableVertexAttribArray#2");
915                println!("DISABLE COL");
916                self.vaa_col = false;
917            }
918            if self.vaa_tex && !shader.graphic() {
919                unsafe { glDisableVertexAttribArray(GL_ATTRIB_TEX) }
920                gl_assert!("glDisableVertexAttribArray#3");
921                self.vaa_tex = false;
922            }
923        }
924
925        let perspective = if shader.depth() {
926            Transform::from_mat4([
927                [1.0, 0.0, 0.0, 0.0],
928                [0.0, 1.0 / self.height, 0.0, 0.0],
929                [
930                    0.0,
931                    0.0,
932                    (self.horizon + self.near) / (self.near - self.horizon),
933                    -1.0,
934                ],
935                [
936                    0.0,
937                    0.0,
938                    (2.0 * self.horizon * self.near)
939                        / (self.near - self.horizon),
940                    0.0,
941                ],
942            ])
943        } else {
944            Transform::from_mat4([
945                [1.0, 0.0, 0.0, 0.0],
946                [0.0, 1.0 / self.height, 0.0, 0.0],
947                [0.0, 0.0, 1.0, 0.0],
948                [0.0, 0.0, 0.0, 1.0],
949            ])
950        };
951
952        let shaderdata = self.shaders.get_mut(&shader.program()).unwrap();
953        if shaderdata.dirty_transform {
954            let matrix = (Transform::from_mat4(shaderdata.matrix))
955                .scale(2.0, -2.0, -2.0)
956                .translate(-1.0, self.height, 0.0)
957                * self.cam
958                * perspective;
959            unsafe {
960                glUniformMatrix4fv(
961                    shader.camera(),
962                    1,
963                    0, /*GL_FALSE*/
964                    matrix.as_ptr().cast(),
965                );
966            }
967            gl_assert!("glUniformMatrix4fv");
968            shaderdata.dirty_transform = false;
969        }
970
971        // IF SAME SHAPE
972        let id = shape.id();
973        if self.shape_id != id {
974            self.shape_id = id;
975
976            if shader.blending() && !self.blending {
977                unsafe {
978                    glEnable(0x0BE2 /*BLEND*/);
979                    gl_assert!("glEnable#Blend");
980                }
981                self.blending = true;
982            } else if !shader.blending() && self.blending {
983                unsafe {
984                    glDisable(0x0BE2 /*BLEND*/);
985                    gl_assert!("glDisable#Blend");
986                }
987                self.blending = false;
988            }
989
990            if shader.depth() && !self.depth {
991                unsafe {
992                    glEnable(0x0B71 /*DEPTH_TEST*/);
993                    gl_assert!("glEnable#DEPTH_TEST");
994                }
995                self.depth = true;
996            } else if !shader.depth() && self.depth {
997                unsafe {
998                    glDisable(0x0B71 /*DEPTH_TEST*/);
999                    gl_assert!("glDisable#DEPTH_TEST");
1000                }
1001                self.depth = false;
1002            }
1003
1004            unsafe {
1005                let stride = if shader.depth() { 3 } else { 2 }
1006                    + if shader.gradient() { 3 } else { 0 }
1007                    + if shader.graphic() { 2 } else { 0 };
1008                let stride = (stride * std::mem::size_of::<f32>()) as i32;
1009
1010                shape.bind();
1011
1012                // Always
1013                {
1014                    glVertexAttribPointer(
1015                        GL_ATTRIB_POS,
1016                        if shader.depth() { 3 } else { 2 },
1017                        0x1406, /*GL_FLOAT*/
1018                        0,      /*GL_FALSE*/
1019                        stride,
1020                        std::ptr::null(),
1021                    );
1022                    gl_assert!("glVertexAttribPointer#POS");
1023                }
1024
1025                // Only if Gradient is enabled.
1026                if shader.gradient() {
1027                    let ptr: *const f32 = std::ptr::null();
1028                    glVertexAttribPointer(
1029                        GL_ATTRIB_COL,
1030                        3,
1031                        0x1406, /*GL_FLOAT*/
1032                        0,      /*GL_FALSE*/
1033                        stride,
1034                        ptr.offset(if shader.depth() { 3 } else { 2 }),
1035                    );
1036                    gl_assert!("glVertexAttribPointer#COL");
1037                }
1038
1039                // Only if Texture is enabled.
1040                if shader.graphic() {
1041                    let ptr: *const f32 = std::ptr::null();
1042                    glVertexAttribPointer(
1043                        GL_ATTRIB_TEX,
1044                        2,
1045                        0x1406, /*GL_FLOAT*/
1046                        0,      /*GL_FALSE*/
1047                        stride,
1048                        ptr.offset(
1049                            if shader.depth() { 3 } else { 2 }
1050                                + if shader.gradient() { 3 } else { 0 },
1051                        ),
1052                    );
1053                    gl_assert!("glVertexAttribPointer#TEX");
1054                }
1055            }
1056        } // END IF
1057
1058        unsafe {
1059            glDrawElements(
1060                0x0004, /*GL_TRIANGLES*/
1061                shape.len(),
1062                0x1405, /*GL_UNSIGNED_INT*/
1063                std::ptr::null(),
1064            );
1065        }
1066    }
1067
1068    fn graphic(
1069        &mut self,
1070        pixels: &[u8],
1071        width: usize,
1072        height: usize,
1073    ) -> Box<dyn Ngraphic> {
1074        Box::new(Graphic::new(pixels, width, height))
1075    }
1076
1077    fn bind_graphic(&mut self, graphic: &dyn Ngraphic) {
1078        // Only bind, if it's not already bound.
1079        if self.graphic != graphic.id() {
1080            unsafe {
1081                glBindTexture(GL_TEXTURE_2D, graphic.id());
1082            }
1083            gl_assert!("glBindTexture");
1084            // Update which graphic is bound.
1085            self.graphic = graphic.id();
1086        }
1087    }
1088
1089    fn camera(&mut self, cam: crate::Transform) {
1090        self.cam = cam;
1091        // Mark matrices to be updated with the new transform.
1092        for shader in &mut self.shaders {
1093            shader.1.dirty_transform = true;
1094        }
1095    }
1096
1097    fn tint(&mut self, shader: &dyn Nshader, tint: [f32; 4]) {
1098        if let Some(a) = shader.tint() {
1099            self.bind_shader(shader);
1100            unsafe {
1101                glUniform4f(a, tint[0], tint[1], tint[2], tint[3]);
1102            }
1103        }
1104    }
1105
1106    fn resize(&mut self, width: u16, height: u16) {
1107        // Mark matrices to be updated to new aspect ratio.
1108        for shader in &mut self.shaders {
1109            shader.1.dirty_transform = true;
1110        }
1111        // Update viewport
1112        unsafe {
1113            glViewport(0, 0, width.into(), height.into());
1114        }
1115        //
1116        self.height = height as f32 / width as f32;
1117    }
1118}
1119
1120impl OpenGL {
1121    fn bind_shader(&mut self, shader: &dyn Nshader) -> bool {
1122        let shader_id = shader.program();
1123        if shader_id != self.shader {
1124            shader.bind();
1125            self.shader = shader_id;
1126            return true;
1127        }
1128        false
1129    }
1130}
1131
1132fn vbo_set<T>(target: u32, vbo: u32, start: usize, size: usize, data: &[T]) {
1133    unsafe {
1134        glBindBuffer(target, vbo);
1135        gl_assert!(&format!("glBindBuffer#{:X}", target));
1136        glBufferSubData(
1137            target,
1138            start as isize,
1139            (size * std::mem::size_of::<T>()) as isize,
1140            data.as_ptr() as *const _,
1141        );
1142        gl_assert!("glBufferData");
1143    }
1144}
1145
1146fn vbo_resize<T>(target: u32, vbo: u32, data: &Vec<T>) {
1147    unsafe {
1148        glBindBuffer(target, vbo);
1149        gl_assert!(&format!("glBindBuffer#{:X}", target));
1150        glBufferData(
1151            target,
1152            (data.capacity() * std::mem::size_of::<T>()) as isize,
1153            (*data).as_ptr() as *const _,
1154            0x88E8, /*GL_DYNAMIC_DRAW*/
1155        );
1156        gl_assert!("glBufferData");
1157    }
1158}
1159
1160// Create an OpenGL vertex buffer object.
1161fn vbo_new<T>(target: u32) -> (u32, Vec<T>) {
1162    unsafe {
1163        let mut buffer = std::mem::MaybeUninit::<u32>::uninit();
1164        glGenBuffers(1 /*1 buffer*/, buffer.as_mut_ptr());
1165        gl_assert!("glGenBuffers");
1166        let buffer = buffer.assume_init();
1167
1168        let vector = vec![];
1169        vbo_resize(target, buffer, &vector);
1170        (buffer, vector)
1171    }
1172}
1173
1174/// Create a shader program.
1175fn create_program(builder: crate::ShaderBuilder) -> Shader {
1176    let frag = create_shader(
1177        builder.opengl_frag.as_ptr() as *const _ as *const _,
1178        0x8B30, /*GL_FRAGMENT_SHADER*/
1179    );
1180    let vert = create_shader(
1181        builder.opengl_vert.as_ptr() as *const _ as *const _,
1182        0x8B31, /*GL_VERTEX_SHADER*/
1183    );
1184    let program = unsafe { glCreateProgram() };
1185    gl_assert!("glCreateProgram");
1186    unsafe {
1187        glAttachShader(program, frag);
1188        gl_assert!("glAttachShader#1");
1189        glAttachShader(program, vert);
1190        gl_assert!("glAttachShader#2");
1191    }
1192    // Vertex attributes
1193    unsafe {
1194        // All shader programs have position.
1195        glBindAttribLocation(
1196            program,
1197            GL_ATTRIB_POS,
1198            b"pos\0".as_ptr() as *const _ as *const _,
1199        );
1200        gl_assert!("glBindAttribLocation#pos");
1201        //
1202        if builder.gradient {
1203            glBindAttribLocation(
1204                program,
1205                GL_ATTRIB_COL,
1206                b"col\0".as_ptr() as *const _ as *const _,
1207            );
1208            gl_assert!("glBindAttribLocation#col");
1209        }
1210        //
1211        if builder.graphic {
1212            glBindAttribLocation(
1213                program,
1214                GL_ATTRIB_TEX,
1215                b"texpos\0".as_ptr() as *const _ as *const _,
1216            );
1217            gl_assert!("glBindAttribLocation#texpos");
1218        }
1219        glLinkProgram(program);
1220        gl_assert!("glLinkProgram");
1221    }
1222    // Bind the shader program.
1223    unsafe {
1224        glUseProgram(program);
1225        gl_assert!(&format!("glUseProgram#0 {}", program));
1226    }
1227    // Link status
1228    let mut status = std::mem::MaybeUninit::<i32>::uninit();
1229    let status = unsafe {
1230        glGetProgramiv(
1231            program,
1232            0x8B82,
1233            /*GL_LINK_STATUS*/ status.as_mut_ptr(),
1234        );
1235        gl_assert!("glGetProgramiv");
1236        status.assume_init()
1237    };
1238    if status == 0 {
1239        let mut log = [0u8; 1000];
1240        let mut len = std::mem::MaybeUninit::<i32>::uninit();
1241        unsafe {
1242            glGetProgramInfoLog(
1243                program,
1244                1000,
1245                len.as_mut_ptr(),
1246                log.as_mut_ptr() as *mut _ as *mut _,
1247            );
1248            gl_assert!("glGetProgramInfoLog");
1249        }
1250        let log = String::from_utf8_lossy(&log);
1251        panic!("Error: linking:\n{}", log);
1252    }
1253
1254    let camera = unsafe {
1255        glGetUniformLocation(program, "cam\0".as_ptr() as *const _ as *const _)
1256    };
1257    gl_assert!("glGetUniformLocation#cam");
1258    assert!(camera > -1);
1259
1260    let tint = if builder.tint {
1261        let tint = unsafe {
1262            glGetUniformLocation(
1263                program,
1264                "tint\0".as_ptr() as *const _ as *const _,
1265            )
1266        };
1267        gl_assert!("glGetUniformLocation#tint");
1268        assert!(tint > -1);
1269
1270        Some(tint)
1271    } else {
1272        None
1273    };
1274
1275    let graphic = builder.graphic;
1276
1277    Shader {
1278        program,
1279        gradient: builder.gradient,
1280        graphic,
1281        camera,
1282        tint,
1283        blending: builder.blend,
1284        depth: builder.depth,
1285    }
1286}
1287
1288fn create_shader(source: *const i8, shader_type: u32) -> u32 {
1289    let shader = unsafe { glCreateShader(shader_type) };
1290    gl_assert!("glCreateShader");
1291    debug_assert!(shader != 0);
1292
1293    unsafe {
1294        glShaderSource(shader, 1, [source].as_ptr(), std::ptr::null());
1295        gl_assert!("glShaderSource");
1296        glCompileShader(shader);
1297        gl_assert!("glCompileShader");
1298    }
1299
1300    let mut status = std::mem::MaybeUninit::<i32>::uninit();
1301    let status = unsafe {
1302        glGetShaderiv(
1303            shader,
1304            0x8B81, /*GL_COMPILE_STATUS*/
1305            status.as_mut_ptr(),
1306        );
1307        gl_assert!("glGetShaderiv");
1308        status.assume_init()
1309    };
1310    if status == 0 {
1311        let mut log = [0u8; 1000];
1312        let mut len = std::mem::MaybeUninit::<i32>::uninit();
1313        unsafe {
1314            glGetShaderInfoLog(
1315                shader,
1316                1000,
1317                len.as_mut_ptr(),
1318                log.as_mut_ptr() as *mut _ as *mut _,
1319            );
1320            gl_assert!("glGetShaderInfoLog");
1321        }
1322        let log = String::from_utf8_lossy(&log);
1323        panic!(
1324            "Error: compiling {}: {}\n",
1325            if shader_type == 0x8B31
1326            /*GL_VERTEX_SHADER*/
1327            {
1328                "vertex"
1329            } else {
1330                "fragment"
1331            },
1332            log
1333        );
1334    }
1335
1336    shader
1337}