Skip to content
4 changes: 1 addition & 3 deletions examples/render-opengl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,7 @@ impl App for Inox2dOpenglExampleApp {
// Just that physics simulation will run for the provided time, which may be big and causes a startup delay.
puppet.end_frame(scene_ctrl.dt());

renderer.on_begin_draw(puppet);
renderer.draw(puppet);
renderer.on_end_draw(puppet);
renderer.draw(puppet).expect("successful draw");
}

fn handle_window_event(&mut self, event: WindowEvent, elwt: &EventLoopWindowTarget<()>) {
Expand Down
4 changes: 1 addition & 3 deletions examples/render-webgl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,7 @@ async fn run() -> Result<(), Box<dyn std::error::Error>> {
// Just that physics simulation will run for the provided time, which may be big and causes a startup delay.
puppet.end_frame(scene_ctrl.borrow().dt());

renderer.borrow().on_begin_draw(&puppet);
renderer.borrow().draw(&puppet);
renderer.borrow().on_end_draw(&puppet);
renderer.borrow_mut().draw(&puppet);
}

request_animation_frame(anim_loop_f.borrow().as_ref().unwrap());
Expand Down
184 changes: 98 additions & 86 deletions inox2d-opengl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod shaders;
pub mod texture;

use std::cell::RefCell;
use std::error::Error;
use std::mem;
use std::ops::Deref;

Expand All @@ -18,7 +19,7 @@ use inox2d::node::{
InoxNodeUuid,
};
use inox2d::puppet::Puppet;
use inox2d::render::{CompositeRenderCtx, InoxRenderer, TexturedMeshRenderCtx};
use inox2d::render::{CompositeRenderCtx, DrawSession, InoxRenderer, TexturedMeshRenderCtx};
use inox2d::texture::{decode_model_textures, TextureId};

use self::shader::ShaderCompileError;
Expand Down Expand Up @@ -410,11 +411,55 @@ impl OpenglRenderer {
}

impl InoxRenderer for OpenglRenderer {
fn on_begin_masks(&self, masks: &Masks) {
self.push_debug_group("inox2d - begin masks");
type Draw<'a>
= OpenGlSession<'a>
where
Self: 'a;

/// Update the renderer with latest puppet data.
fn on_begin_draw<'a>(&'a mut self, puppet: &Puppet) -> Result<Self::Draw<'a>, Box<dyn Error>> {
self.push_debug_group("inox2d - begin draw");

let gl = &self.gl;

// TODO: calculate this matrix only once per draw pass.
// let matrix = self.camera.matrix(self.viewport.as_vec2());

unsafe {
gl.bind_vertex_array(Some(self.vao));
upload_deforms_to_gl(
gl,
puppet
.render_ctx
.as_ref()
.expect("Rendering for a puppet must be initialized by now.")
.vertex_buffers
.deforms
.as_slice(),
self.deform_buffer,
);
gl.enable(glow::BLEND);
gl.disable(glow::DEPTH_TEST);
}

self.pop_debug_group();

self.push_debug_group("inox2d - draw");

Ok(OpenGlSession { render: self })
}
}

pub struct OpenGlSession<'a> {
render: &'a mut OpenglRenderer,
}

impl<'a> DrawSession<'a> for OpenGlSession<'a> {
fn on_begin_masks(&mut self, masks: &Masks) {
self.render.push_debug_group("inox2d - begin masks");

let gl = &self.render.gl;

unsafe {
gl.enable(glow::STENCIL_TEST);
gl.clear_stencil(!masks.has_masks() as i32);
Expand All @@ -425,57 +470,57 @@ impl InoxRenderer for OpenglRenderer {
gl.stencil_mask(0xff);
}

let part_mask_shader = &self.part_mask_shader;
self.bind_shader(part_mask_shader);
let part_mask_shader = &self.render.part_mask_shader;
self.render.bind_shader(part_mask_shader);
part_mask_shader.set_threshold(gl, masks.threshold.clamp(0.0, 1.0));

self.pop_debug_group();
self.render.pop_debug_group();
}

fn on_begin_mask(&self, mask: &Mask) {
self.push_debug_group("inox2d - begin mask");
fn on_begin_mask(&mut self, mask: &Mask) {
self.render.push_debug_group("inox2d - begin mask");

let gl = &self.gl;
let gl = &self.render.gl;
unsafe {
gl.stencil_func(glow::ALWAYS, (mask.mode == MaskMode::Mask) as i32, 0xff);
}
}

fn on_begin_masked_content(&self) {
self.push_debug_group("inox2d - begin masked content");
fn on_begin_masked_content(&mut self) {
self.render.push_debug_group("inox2d - begin masked content");

let gl = &self.gl;
let gl = &self.render.gl;
unsafe {
gl.stencil_func(glow::EQUAL, 1, 0xff);
gl.stencil_mask(0x00);

gl.color_mask(true, true, true, true);
}

self.pop_debug_group();
self.render.pop_debug_group();
}

fn on_end_mask(&self) {
let gl = &self.gl;
fn on_end_mask(&mut self) {
let gl = &self.render.gl;
unsafe {
gl.stencil_mask(0xff);
gl.stencil_func(glow::ALWAYS, 1, 0xff);
gl.disable(glow::STENCIL_TEST);
}
self.pop_debug_group();

self.render.pop_debug_group();
}

fn draw_textured_mesh_content(
&self,
&mut self,
as_mask: bool,
components: &TexturedMeshComponents,
render_ctx: &TexturedMeshRenderCtx,
_id: InoxNodeUuid,
) {
self.push_debug_group("inox2d - draw textured content");
self.render.push_debug_group("inox2d - draw textured content");

let gl = &self.gl;
let gl = &self.render.gl;

// TODO: plain masks, meshes as masks without textures
/*
Expand All @@ -495,21 +540,21 @@ impl InoxRenderer for OpenglRenderer {
glDisableVertexAttribArray(0);
*/

self.bind_part_textures(components.texture);
self.set_blend_mode(components.drawable.blending.mode);
self.render.bind_part_textures(components.texture);
self.render.set_blend_mode(components.drawable.blending.mode);

let mvp = self.camera.matrix(self.viewport.as_vec2()) * *components.transform;
let mvp = self.render.camera.matrix(self.render.viewport.as_vec2()) * *components.transform;

if as_mask {
// if as_mask is set, in .on_begin_masks():
// - part_mask_shader must have been bound and prepared.
// - mask threshold must have been uploaded.

// vert uniforms
self.part_mask_shader.set_mvp(gl, mvp);
self.render.part_mask_shader.set_mvp(gl, mvp);
} else {
let part_shader = &self.part_shader;
self.bind_shader(part_shader);
let part_shader = &self.render.part_shader;
self.render.bind_shader(part_shader);

// vert uniforms
part_shader.set_mvp(gl, mvp);
Expand All @@ -529,23 +574,23 @@ impl InoxRenderer for OpenglRenderer {
);
}

self.pop_debug_group();
self.render.pop_debug_group();
}

fn begin_composite_content(
&self,
&mut self,
_as_mask: bool,
_components: &CompositeComponents,
_render_ctx: &CompositeRenderCtx,
_id: InoxNodeUuid,
) {
self.push_debug_group("inox2d - begin composite content");
self.render.push_debug_group("inox2d - begin composite content");

self.clear_texture_cache();
self.render.clear_texture_cache();

let gl = &self.gl;
let gl = &self.render.gl;
unsafe {
gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.composite_framebuffer));
gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.render.composite_framebuffer));
gl.disable(glow::DEPTH_TEST);
gl.draw_buffers(&[
glow::COLOR_ATTACHMENT0,
Expand All @@ -560,25 +605,25 @@ impl InoxRenderer for OpenglRenderer {
gl.blend_func(glow::ONE, glow::ONE_MINUS_SRC_ALPHA);
}

self.pop_debug_group();
self.render.pop_debug_group();

self.push_debug_group("inox2d - composite content");
self.render.push_debug_group("inox2d - composite content");
}

fn finish_composite_content(
&self,
&mut self,
as_mask: bool,
components: &CompositeComponents,
_render_ctx: &CompositeRenderCtx,
_id: InoxNodeUuid,
) {
self.pop_debug_group();
self.render.pop_debug_group();

self.push_debug_group("inox2d - finish composite content");
self.render.push_debug_group("inox2d - finish composite content");

let gl = &self.gl;
let gl = &self.render.gl;

self.clear_texture_cache();
self.render.clear_texture_cache();
unsafe {
gl.bind_framebuffer(glow::FRAMEBUFFER, None);
}
Expand All @@ -595,21 +640,21 @@ impl InoxRenderer for OpenglRenderer {
} else {
unsafe {
gl.active_texture(glow::TEXTURE0);
gl.bind_texture(glow::TEXTURE_2D, Some(self.cf_albedo));
gl.bind_texture(glow::TEXTURE_2D, Some(self.render.cf_albedo));
gl.active_texture(glow::TEXTURE1);
gl.bind_texture(glow::TEXTURE_2D, Some(self.cf_emissive));
gl.bind_texture(glow::TEXTURE_2D, Some(self.render.cf_emissive));
gl.active_texture(glow::TEXTURE2);
gl.bind_texture(glow::TEXTURE_2D, Some(self.cf_bump));
gl.bind_texture(glow::TEXTURE_2D, Some(self.render.cf_bump));
}

self.set_blend_mode(blending.mode);
self.render.set_blend_mode(blending.mode);

let opacity = blending.opacity.clamp(0.0, 1.0);
let tint = blending.tint.clamp(Vec3::ZERO, Vec3::ONE);
let screen_tint = blending.screen_tint.clamp(Vec3::ZERO, Vec3::ONE);

let composite_shader = &self.composite_shader;
self.bind_shader(composite_shader);
let composite_shader = &self.render.composite_shader;
self.render.bind_shader(composite_shader);
composite_shader.set_opacity(gl, opacity);
composite_shader.set_mult_color(gl, tint);
composite_shader.set_screen_color(gl, screen_tint);
Expand All @@ -619,53 +664,20 @@ impl InoxRenderer for OpenglRenderer {
gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0);
}

self.pop_debug_group();
}
}

impl OpenglRenderer {
/// Update the renderer with latest puppet data.
pub fn on_begin_draw(&self, puppet: &Puppet) {
self.push_debug_group("inox2d - begin draw");

let gl = &self.gl;

// TODO: calculate this matrix only once per draw pass.
// let matrix = self.camera.matrix(self.viewport.as_vec2());

unsafe {
gl.bind_vertex_array(Some(self.vao));
upload_deforms_to_gl(
gl,
puppet
.render_ctx
.as_ref()
.expect("Rendering for a puppet must be initialized by now.")
.vertex_buffers
.deforms
.as_slice(),
self.deform_buffer,
);
gl.enable(glow::BLEND);
gl.disable(glow::DEPTH_TEST);
}

self.pop_debug_group();

self.push_debug_group("inox2d - draw");
self.render.pop_debug_group();
}

/// Renderer cleaning up after one frame.
pub fn on_end_draw(&self, _puppet: &Puppet) {
self.pop_debug_group();
fn on_end_draw(self, _puppet: &Puppet) {
self.render.pop_debug_group();

self.push_debug_group("inox2d - end draw");
let gl = &self.gl;
self.render.push_debug_group("inox2d - end draw");

let gl = &self.render.gl;
unsafe {
gl.bind_vertex_array(None);
}
self.pop_debug_group();

self.render.pop_debug_group();
}
}
4 changes: 2 additions & 2 deletions inox2d/src/node/drawables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::puppet::World;
/// Future spec extensions go here.
/// For user-defined custom nodes that can be rendered, as long as a subset of their components matches one of these variants,
/// they will be picked up and enter the regular rendering pipeline.
pub(crate) enum DrawableKind<'comps> {
pub enum DrawableKind<'comps> {
TexturedMesh(TexturedMeshComponents<'comps>),
Composite(CompositeComponents<'comps>),
}
Expand All @@ -38,7 +38,7 @@ impl<'comps> DrawableKind<'comps> {
/// `None` if node not renderable.
///
/// If `check`, will send a warning to `tracing` if component combination non-standard for a supposed-to-be Drawable node.
pub(crate) fn new(id: InoxNodeUuid, comps: &'comps World, check: bool) -> Option<Self> {
pub fn new(id: InoxNodeUuid, comps: &'comps World, check: bool) -> Option<Self> {
let drawable = match comps.get::<Drawable>(id) {
Some(drawable) => drawable,
None => return None,
Expand Down
Loading
Loading