1mod gl_buffer;
2mod shader;
3mod shaders;
4pub mod texture;
5
6use std::cell::RefCell;
7use std::mem;
8use std::ops::Deref;
9
10use gl_buffer::RenderCtxOpenglExt;
11use glam::{uvec2, Mat4, UVec2, Vec2, Vec3};
12use glow::HasContext;
13use inox2d::texture::{decode_model_textures, TextureId};
14
15use inox2d::math::camera::Camera;
16use inox2d::model::{Model, ModelTexture};
17use inox2d::nodes::node_data::{BlendMode, Composite, Part};
18use inox2d::puppet::Puppet;
19use inox2d::render::{InoxRenderer, InoxRendererCommon, NodeRenderCtx, PartRenderCtx};
20
21use self::shader::ShaderCompileError;
22use self::shaders::{CompositeMaskShader, CompositeShader, PartMaskShader, PartShader};
23use self::texture::{Texture, TextureError};
24
25#[derive(Debug, thiserror::Error)]
26#[error("Could not initialize OpenGL renderer: {0}")]
27pub enum OpenglRendererError {
28 ShaderCompile(#[from] ShaderCompileError),
29 Opengl(String),
30}
31
32#[derive(Default, Clone)]
33pub struct GlCache {
34 pub camera: Option<Camera>,
35 pub viewport: Option<UVec2>,
36 pub blend_mode: Option<BlendMode>,
37 pub program: Option<glow::Program>,
38 pub vao: Option<glow::VertexArray>,
39 pub albedo: Option<TextureId>,
40}
41
42impl GlCache {
43 pub fn update_camera(&mut self, camera: &Camera) -> bool {
44 if let Some(prev_camera) = &mut self.camera {
45 let mut changed = false;
46
47 if prev_camera.position != camera.position {
48 prev_camera.position = camera.position;
49 changed = true;
50 }
51 if prev_camera.rotation != camera.rotation {
52 prev_camera.rotation = camera.rotation;
53 changed = true;
54 }
55 if prev_camera.scale != camera.scale {
56 prev_camera.scale = camera.scale;
57 changed = true;
58 }
59
60 changed
61 } else {
62 self.camera = Some(camera.clone());
63 true
64 }
65 }
66
67 pub fn update_viewport(&mut self, viewport: UVec2) -> bool {
68 if let Some(prev_viewport) = self.viewport.replace(viewport) {
69 prev_viewport != viewport
70 } else {
71 true
72 }
73 }
74
75 pub fn update_blend_mode(&mut self, blend_mode: BlendMode) -> bool {
76 if let Some(prev_mode) = self.blend_mode.replace(blend_mode) {
77 prev_mode != blend_mode
78 } else {
79 true
80 }
81 }
82
83 pub fn update_program(&mut self, program: glow::Program) -> bool {
84 if let Some(prev_program) = self.program.replace(program) {
85 prev_program != program
86 } else {
87 true
88 }
89 }
90
91 pub fn update_vao(&mut self, vao: glow::VertexArray) -> bool {
92 if let Some(prev_vao) = self.vao.replace(vao) {
93 prev_vao != vao
94 } else {
95 true
96 }
97 }
98
99 pub fn update_albedo(&mut self, albedo: TextureId) -> bool {
100 if let Some(prev_texture) = self.albedo.replace(albedo) {
101 prev_texture != albedo
102 } else {
103 true
104 }
105 }
106}
107
108#[allow(unused)]
109pub struct OpenglRenderer {
110 gl: glow::Context,
111 support_debug_extension: bool,
112 pub camera: Camera,
113 pub viewport: UVec2,
114 cache: RefCell<GlCache>,
115
116 vao: glow::VertexArray,
117
118 composite_framebuffer: glow::Framebuffer,
119 cf_albedo: glow::Texture,
120 cf_emissive: glow::Texture,
121 cf_bump: glow::Texture,
122 cf_stencil: glow::Texture,
123
124 part_shader: PartShader,
125 part_mask_shader: PartMaskShader,
126 composite_shader: CompositeShader,
127 composite_mask_shader: CompositeMaskShader,
128
129 textures: Vec<Texture>,
130}
131
132#[allow(unused)]
134impl OpenglRenderer {
135 pub fn new(gl: glow::Context) -> Result<Self, OpenglRendererError> {
136 let vao = unsafe { gl.create_vertex_array().map_err(OpenglRendererError::Opengl)? };
137
138 let composite_framebuffer;
140 let cf_albedo;
141 let cf_emissive;
142 let cf_bump;
143 let cf_stencil;
144 unsafe {
145 cf_albedo = gl.create_texture().map_err(OpenglRendererError::Opengl)?;
146 cf_emissive = gl.create_texture().map_err(OpenglRendererError::Opengl)?;
147 cf_bump = gl.create_texture().map_err(OpenglRendererError::Opengl)?;
148 cf_stencil = gl.create_texture().map_err(OpenglRendererError::Opengl)?;
149
150 composite_framebuffer = gl.create_framebuffer().map_err(OpenglRendererError::Opengl)?;
151 }
152
153 let part_shader = PartShader::new(&gl)?;
155 let part_mask_shader = PartMaskShader::new(&gl)?;
156 let composite_shader = CompositeShader::new(&gl)?;
157 let composite_mask_shader = CompositeMaskShader::new(&gl)?;
158
159 let support_debug_extension = gl.supported_extensions().contains("GL_KHR_debug");
160
161 let renderer = Self {
162 gl,
163 support_debug_extension,
164 camera: Camera::default(),
165 viewport: UVec2::default(),
166 cache: RefCell::new(GlCache::default()),
167
168 vao,
169
170 composite_framebuffer,
171 cf_albedo,
172 cf_emissive,
173 cf_bump,
174 cf_stencil,
175
176 part_shader,
177 part_mask_shader,
178 composite_shader,
179 composite_mask_shader,
180
181 textures: Vec::new(),
182 };
183
184 renderer.bind_shader(&renderer.part_shader);
186 renderer.part_shader.set_emission_strength(&renderer.gl, 1.);
187
188 Ok(renderer)
189 }
190
191 fn upload_model_textures(&mut self, model_textures: &[ModelTexture]) -> Result<(), TextureError> {
192 let shalltexs = decode_model_textures(model_textures.iter());
194
195 for (i, shalltex) in shalltexs.iter().enumerate() {
197 tracing::debug!("Uploading shallow texture {:?}", i);
198 let tex = texture::Texture::from_shallow_texture(&self.gl, shalltex)?;
199 self.textures.push(tex);
200 }
201
202 Ok(())
203 }
204
205 #[inline]
211 fn push_debug_group(&self, name: &str) {
212 if self.support_debug_extension {
213 unsafe {
214 self.gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, 0, name);
215 }
216 }
217 }
218
219 #[inline]
223 fn pop_debug_group(&self) {
224 if self.support_debug_extension {
225 unsafe {
226 self.gl.pop_debug_group();
227 }
228 }
229 }
230
231 fn update_camera(&self) -> bool {
233 {
234 let mut cache = self.cache.borrow_mut();
235 if !cache.update_camera(&self.camera) && !cache.update_viewport(self.viewport) {
236 return false;
237 }
238 }
239
240 let matrix = self.camera.matrix(self.viewport.as_vec2());
241
242 self.bind_shader(&self.composite_shader);
243 self.composite_shader.set_mvp(&self.gl, matrix);
244
245 self.bind_shader(&self.composite_mask_shader);
246 self.composite_mask_shader.set_mvp(&self.gl, matrix);
247
248 true
249 }
250
251 pub fn set_blend_mode(&self, blend_mode: BlendMode) {
253 if !self.cache.borrow_mut().update_blend_mode(blend_mode) {
254 return;
255 }
256
257 let gl = &self.gl;
258 unsafe {
259 match blend_mode {
260 BlendMode::Normal => {
261 gl.blend_equation(glow::FUNC_ADD);
262 gl.blend_func(glow::ONE, glow::ONE_MINUS_SRC_ALPHA);
263 }
264 BlendMode::Multiply => {
265 gl.blend_equation(glow::FUNC_ADD);
266 gl.blend_func(glow::DST_COLOR, glow::ONE_MINUS_SRC_ALPHA);
267 }
268 BlendMode::ColorDodge => {
269 gl.blend_equation(glow::FUNC_ADD);
270 gl.blend_func(glow::DST_COLOR, glow::ONE);
271 }
272 BlendMode::LinearDodge => {
273 gl.blend_equation(glow::FUNC_ADD);
274 gl.blend_func(glow::ONE, glow::ONE);
275 }
276 BlendMode::Screen => {
277 gl.blend_equation(glow::FUNC_ADD);
278 gl.blend_func(glow::ONE, glow::ONE_MINUS_SRC_COLOR);
279 }
280 BlendMode::ClipToLower => {
281 gl.blend_equation(glow::FUNC_ADD);
282 gl.blend_func(glow::DST_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
283 }
284 BlendMode::SliceFromLower => {
285 gl.blend_equation(glow::FUNC_SUBTRACT);
286 gl.blend_func(glow::ONE_MINUS_DST_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
287 }
288 }
289 }
290 }
291
292 fn bind_shader<S: Deref<Target = glow::Program>>(&self, shader: &S) {
293 let program = **shader;
294 if !self.cache.borrow_mut().update_program(program) {
295 return;
296 }
297
298 unsafe { self.gl.use_program(Some(program)) };
299 }
300
301 fn bind_part_textures(&self, part: &Part) {
302 if !self.cache.borrow_mut().update_albedo(part.tex_albedo) {
303 return;
304 }
305
306 let gl = &self.gl;
307 self.textures[part.tex_albedo.raw()].bind_on(gl, 0);
308 self.textures[part.tex_bumpmap.raw()].bind_on(gl, 1);
309 self.textures[part.tex_emissive.raw()].bind_on(gl, 2);
310 }
311
312 pub fn clear_texture_cache(&self) {
315 self.cache.borrow_mut().albedo = None;
316 }
317
318 unsafe fn attach_framebuffer_textures(&self) {
319 let gl = &self.gl;
320 gl.bind_framebuffer(glow::FRAMEBUFFER, Some(self.composite_framebuffer));
321
322 gl.framebuffer_texture_2d(
323 glow::FRAMEBUFFER,
324 glow::COLOR_ATTACHMENT0,
325 glow::TEXTURE_2D,
326 Some(self.cf_albedo),
327 0,
328 );
329 gl.framebuffer_texture_2d(
330 glow::FRAMEBUFFER,
331 glow::COLOR_ATTACHMENT1,
332 glow::TEXTURE_2D,
333 Some(self.cf_emissive),
334 0,
335 );
336 gl.framebuffer_texture_2d(
337 glow::FRAMEBUFFER,
338 glow::COLOR_ATTACHMENT2,
339 glow::TEXTURE_2D,
340 Some(self.cf_bump),
341 0,
342 );
343 gl.framebuffer_texture_2d(
344 glow::FRAMEBUFFER,
345 glow::DEPTH_STENCIL_ATTACHMENT,
346 glow::TEXTURE_2D,
347 Some(self.cf_stencil),
348 0,
349 );
350
351 gl.bind_framebuffer(glow::FRAMEBUFFER, None);
352 }
353}
354
355impl InoxRenderer for OpenglRenderer {
356 type Error = OpenglRendererError;
357
358 fn prepare(&mut self, model: &Model) -> Result<(), Self::Error> {
359 unsafe { model.puppet.render_ctx.setup_gl_buffers(&self.gl, self.vao)? };
360
361 match self.upload_model_textures(&model.textures) {
362 Ok(_) => Ok(()),
363 Err(_) => Err(OpenglRendererError::Opengl("Texture Upload Error.".to_string())),
364 }
365 }
366
367 fn resize(&mut self, w: u32, h: u32) {
368 self.viewport = uvec2(w, h);
369
370 let gl = &self.gl;
371 unsafe {
372 gl.viewport(0, 0, w as i32, h as i32);
373
374 texture::upload_empty(gl, self.cf_albedo, w, h, glow::UNSIGNED_BYTE);
376 texture::upload_empty(gl, self.cf_emissive, w, h, glow::FLOAT);
377 texture::upload_empty(gl, self.cf_bump, w, h, glow::UNSIGNED_BYTE);
378
379 gl.bind_texture(glow::TEXTURE_2D, Some(self.cf_stencil));
380 gl.tex_image_2d(
381 glow::TEXTURE_2D,
382 0,
383 glow::DEPTH24_STENCIL8 as i32,
384 w as i32,
385 h as i32,
386 0,
387 glow::DEPTH_STENCIL,
388 glow::UNSIGNED_INT_24_8,
389 None,
390 );
391
392 self.attach_framebuffer_textures();
393 }
394 self.update_camera();
395 }
396
397 fn clear(&self) {
398 unsafe {
399 self.gl.clear(glow::COLOR_BUFFER_BIT);
400 }
401 }
402
403 fn on_begin_scene(&self) {
411 todo!()
412 }
413
414 fn render(&self, puppet: &Puppet) {
415 let gl = &self.gl;
416 unsafe {
417 puppet.render_ctx.upload_deforms_to_gl(gl);
418 gl.enable(glow::BLEND);
419 gl.disable(glow::DEPTH_TEST);
420 }
421
422 let camera = self
423 .camera
424 .matrix(Vec2::new(self.viewport.x as f32, self.viewport.y as f32));
425 self.draw(&camera, puppet);
426 }
427
428 fn on_end_scene(&self) {
429 todo!()
430 }
431
432 fn draw_scene(&self) {
433 todo!()
434 }
435
436 fn on_begin_mask(&self, has_mask: bool) {
437 let gl = &self.gl;
438 unsafe {
439 gl.enable(glow::STENCIL_TEST);
440 gl.clear_stencil(!has_mask as i32);
441 gl.clear(glow::STENCIL_BUFFER_BIT);
442
443 gl.color_mask(false, false, false, false);
444 gl.stencil_op(glow::KEEP, glow::KEEP, glow::REPLACE);
445 gl.stencil_mask(0xff);
446 }
447 }
448
449 fn set_mask_mode(&self, dodge: bool) {
450 let gl = &self.gl;
451 unsafe {
452 gl.stencil_func(glow::ALWAYS, !dodge as i32, 0xff);
453 }
454 }
455
456 fn on_begin_masked_content(&self) {
457 let gl = &self.gl;
458 unsafe {
459 gl.stencil_func(glow::EQUAL, 1, 0xff);
460 gl.stencil_mask(0x00);
461
462 gl.color_mask(true, true, true, true);
463 }
464 }
465
466 fn on_end_mask(&self) {
467 let gl = &self.gl;
468 unsafe {
469 gl.stencil_mask(0xff);
470 gl.stencil_func(glow::ALWAYS, 1, 0xff);
471 gl.disable(glow::STENCIL_TEST);
472 }
473 }
474
475 fn draw_mesh_self(&self, _as_mask: bool, _camera: &Mat4) {
476 todo!()
495 }
496
497 fn draw_part_self(
498 &self,
499 as_mask: bool,
500 camera: &Mat4,
501 node_render_ctx: &NodeRenderCtx,
502 part: &Part,
503 part_render_ctx: &PartRenderCtx,
504 ) {
505 let gl = &self.gl;
506
507 self.bind_part_textures(part);
508 self.set_blend_mode(part.draw_state.blend_mode);
509
510 let part_shader = &self.part_shader;
511 self.bind_shader(part_shader);
512 let mvp = *camera * node_render_ctx.trans;
514
515 if as_mask {
516 let part_mask_shader = &self.part_mask_shader;
517 self.bind_shader(part_mask_shader);
518
519 part_mask_shader.set_mvp(gl, mvp);
521
522 part_mask_shader.set_threshold(gl, part.draw_state.mask_threshold.clamp(0.0, 1.0));
524 } else {
525 let part_shader = &self.part_shader;
526 self.bind_shader(part_shader);
527
528 part_shader.set_mvp(gl, mvp);
530
531 part_shader.set_opacity(gl, part.draw_state.opacity);
533 part_shader.set_mult_color(gl, part.draw_state.tint);
534 part_shader.set_screen_color(gl, part.draw_state.screen_tint);
535 }
536
537 unsafe {
538 gl.bind_vertex_array(Some(self.vao));
539 gl.draw_elements(
540 glow::TRIANGLES,
541 part.mesh.indices.len() as i32,
542 glow::UNSIGNED_SHORT,
543 part_render_ctx.index_offset as i32 * mem::size_of::<u16>() as i32,
544 );
545 }
546 }
547
548 fn begin_composite_content(&self) {
549 self.clear_texture_cache();
550
551 let gl = &self.gl;
552 unsafe {
553 gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.composite_framebuffer));
554 gl.disable(glow::DEPTH_TEST);
555 gl.draw_buffers(&[
556 glow::COLOR_ATTACHMENT0,
557 glow::COLOR_ATTACHMENT1,
558 glow::COLOR_ATTACHMENT2,
559 ]);
560 gl.clear_color(0.0, 0.0, 0.0, 0.0);
561 gl.clear(glow::COLOR_BUFFER_BIT);
562
563 gl.active_texture(glow::TEXTURE0);
565 gl.blend_func(glow::ONE, glow::ONE_MINUS_SRC_ALPHA);
566 }
567 }
568
569 fn finish_composite_content(&self, as_mask: bool, composite: &Composite) {
570 let gl = &self.gl;
571
572 self.clear_texture_cache();
573 unsafe {
574 gl.bind_framebuffer(glow::FRAMEBUFFER, None);
575 }
576
577 let comp = &composite.draw_state;
578 if as_mask {
579 todo!()
586 } else {
587 unsafe {
588 gl.bind_vertex_array(Some(self.vao));
589
590 gl.active_texture(glow::TEXTURE0);
591 gl.bind_texture(glow::TEXTURE_2D, Some(self.cf_albedo));
592 gl.active_texture(glow::TEXTURE1);
593 gl.bind_texture(glow::TEXTURE_2D, Some(self.cf_emissive));
594 gl.active_texture(glow::TEXTURE2);
595 gl.bind_texture(glow::TEXTURE_2D, Some(self.cf_bump));
596 }
597
598 self.set_blend_mode(comp.blend_mode);
599
600 let opacity = comp.opacity.clamp(0.0, 1.0);
601 let tint = comp.tint.clamp(Vec3::ZERO, Vec3::ONE);
602 let screen_tint = comp.screen_tint.clamp(Vec3::ZERO, Vec3::ONE);
603
604 let composite_shader = &self.composite_shader;
605 self.bind_shader(composite_shader);
606 composite_shader.set_opacity(gl, opacity);
607 composite_shader.set_mult_color(gl, tint);
608 composite_shader.set_screen_color(gl, screen_tint);
609 }
610
611 unsafe {
612 gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_SHORT, 0);
613 }
614 }
615}