1use 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
24const GL_ATTRIB_POS: u32 = 0;
26const GL_ATTRIB_TEX: u32 = 1;
28const 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 = "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, 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 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 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 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
193pub struct Shader {
195 program: u32,
197 gradient: bool,
199 graphic: bool,
201 camera: i32,
203 tint: Option<i32>,
205 blending: bool,
207 depth: bool,
209}
210
211pub 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 glBindTexture(GL_TEXTURE_2D, new_texture);
240 gl_assert!("glBindTexture");
241
242 glTexParameteri(
244 GL_TEXTURE_2D,
245 GL_TEXTURE_MIN_FILTER,
246 GL_NEAREST_MIPMAP_LINEAR,
247 );
248 gl_assert!("glTexParameteri#1");
249 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, pixels.as_ptr() as *const _,
263 );
264 gl_assert!("glTexImage2D");
265
266 let mut mipmap_level = 0;
268 let mut offset = width as usize * height as usize * 4;
269 while width > 1 && height > 1 && offset != pixels.len() {
271 width /= 2;
274 height /= 2;
275 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, 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, 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
310pub 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 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 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 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, ((pixels.len() / 4) as i32) / width, 0,
621 GL_RGBA,
622 0x1401, 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, ((self.pixels.len() / 4) as i32) / self.width, 0,
646 GL_RGBA,
647 0x1401, self.pixels.as_ptr() as *const _,
649 );
650 gl_assert!("glTexImage2D");
651 }
652 }
653}
654
655struct ShaderData {
656 dirty_transform: bool, matrix: [[f32; 4]; 4], }
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)] pub(super) fn new(nwin: &mut dyn crate::Nwin) -> Option<Box<dyn Draw>> {
683 let (display, config, context) = unsafe {
684 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 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 let ret = eglBindAPI(0x30A0);
705 debug_assert_eq!(ret, 1);
706
707 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 0x3033,
714 0x04,
715 0x3024, 8,
716 0x3023, 8,
717 0x3022, 8,
718 0x3021, 8, 0x3025, 24, 0x3040,
723 0x0004,
724 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 let context = eglCreateContext(
737 display,
738 config,
739 std::ptr::null_mut(),
740 [
741 0x3098, 2,
742 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; let horizon = 5000.0; 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 DrawHandle::Gl(std::ptr::null_mut())
797 }
798
799 fn connect(&mut self, connection: *mut c_void) {
800 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 unsafe {
822 glEnable(0x0B44 );
823 gl_assert!("glEnable#0");
824 glDisable(0x0BD0 );
825 gl_assert!("glDisable#0");
826 }
827
828 unsafe {
829 glBlendFuncSeparate(
831 0x0302u32,
832 0x0303u32,
833 0x0302u32,
834 0x0304u32,
835 );
836 gl_assert!("glBlendFuncSeparate");
837 }
838
839 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 | 0x0000_0100, );
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, matrix.as_ptr().cast(),
965 );
966 }
967 gl_assert!("glUniformMatrix4fv");
968 shaderdata.dirty_transform = false;
969 }
970
971 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 );
979 gl_assert!("glEnable#Blend");
980 }
981 self.blending = true;
982 } else if !shader.blending() && self.blending {
983 unsafe {
984 glDisable(0x0BE2 );
985 gl_assert!("glDisable#Blend");
986 }
987 self.blending = false;
988 }
989
990 if shader.depth() && !self.depth {
991 unsafe {
992 glEnable(0x0B71 );
993 gl_assert!("glEnable#DEPTH_TEST");
994 }
995 self.depth = true;
996 } else if !shader.depth() && self.depth {
997 unsafe {
998 glDisable(0x0B71 );
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 {
1014 glVertexAttribPointer(
1015 GL_ATTRIB_POS,
1016 if shader.depth() { 3 } else { 2 },
1017 0x1406, 0, stride,
1020 std::ptr::null(),
1021 );
1022 gl_assert!("glVertexAttribPointer#POS");
1023 }
1024
1025 if shader.gradient() {
1027 let ptr: *const f32 = std::ptr::null();
1028 glVertexAttribPointer(
1029 GL_ATTRIB_COL,
1030 3,
1031 0x1406, 0, stride,
1034 ptr.offset(if shader.depth() { 3 } else { 2 }),
1035 );
1036 gl_assert!("glVertexAttribPointer#COL");
1037 }
1038
1039 if shader.graphic() {
1041 let ptr: *const f32 = std::ptr::null();
1042 glVertexAttribPointer(
1043 GL_ATTRIB_TEX,
1044 2,
1045 0x1406, 0, 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 } unsafe {
1059 glDrawElements(
1060 0x0004, shape.len(),
1062 0x1405, 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 if self.graphic != graphic.id() {
1080 unsafe {
1081 glBindTexture(GL_TEXTURE_2D, graphic.id());
1082 }
1083 gl_assert!("glBindTexture");
1084 self.graphic = graphic.id();
1086 }
1087 }
1088
1089 fn camera(&mut self, cam: crate::Transform) {
1090 self.cam = cam;
1091 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 for shader in &mut self.shaders {
1109 shader.1.dirty_transform = true;
1110 }
1111 unsafe {
1113 glViewport(0, 0, width.into(), height.into());
1114 }
1115 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, );
1156 gl_assert!("glBufferData");
1157 }
1158}
1159
1160fn vbo_new<T>(target: u32) -> (u32, Vec<T>) {
1162 unsafe {
1163 let mut buffer = std::mem::MaybeUninit::<u32>::uninit();
1164 glGenBuffers(1 , 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
1174fn create_program(builder: crate::ShaderBuilder) -> Shader {
1176 let frag = create_shader(
1177 builder.opengl_frag.as_ptr() as *const _ as *const _,
1178 0x8B30, );
1180 let vert = create_shader(
1181 builder.opengl_vert.as_ptr() as *const _ as *const _,
1182 0x8B31, );
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 unsafe {
1194 glBindAttribLocation(
1196 program,
1197 GL_ATTRIB_POS,
1198 b"pos\0".as_ptr() as *const _ as *const _,
1199 );
1200 gl_assert!("glBindAttribLocation#pos");
1201 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 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 unsafe {
1224 glUseProgram(program);
1225 gl_assert!(&format!("glUseProgram#0 {}", program));
1226 }
1227 let mut status = std::mem::MaybeUninit::<i32>::uninit();
1229 let status = unsafe {
1230 glGetProgramiv(
1231 program,
1232 0x8B82,
1233 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, 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 {
1328 "vertex"
1329 } else {
1330 "fragment"
1331 },
1332 log
1333 );
1334 }
1335
1336 shader
1337}