Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECS Refactor. #86

Merged
merged 35 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a515e22
Foundational block of ECS: type-erased `Vec`.
Richardn2002 Mar 8, 2024
5bef663
Finished readings on provenance.
Richardn2002 Mar 9, 2024
d52f4ff
`World` for hosting all nodes of different comps of a puppet.
Richardn2002 Mar 10, 2024
492c894
Major ECS refactor.
Richardn2002 Mar 13, 2024
ea6d2f7
Absolute transforms of nodes as components.
Richardn2002 Jul 18, 2024
032181f
RenderCtx with components in mind. Init and reading methods.
Richardn2002 Jul 18, 2024
2746a6c
Componentize render contexts and store them in puppets.
Richardn2002 Jul 18, 2024
9bd7c4d
Complete render.rs rewrite.
Richardn2002 Jul 18, 2024
08cccb6
Comments for `render.rs` and lighter interfaces.
Richardn2002 Jul 19, 2024
3cc6f64
Pass `InoxNodeUuid` of the node in question to draw calls in case som…
Richardn2002 Jul 19, 2024
1cfa783
Deformations by parameters.
Richardn2002 Jul 20, 2024
3ffdb23
Components to store zsorts and transforms that are being modified acr…
Richardn2002 Jul 21, 2024
537b75a
zsort and deform update for `RenderCtx`.
Richardn2002 Jul 21, 2024
49111a7
`Param` init and set.
Richardn2002 Jul 26, 2024
e08b1ca
Implement reset methods for puppet to run across frames.
Richardn2002 Jul 28, 2024
54e1098
`render-opengl` compiles.
Richardn2002 Jul 29, 2024
30ecda4
Type annotations for `transmute()` by clippy.
Richardn2002 Jul 29, 2024
6050b79
More comments on `upload_deforms_to_gl()`.
Richardn2002 Jul 29, 2024
fc3ab0d
Fix uninitialized zsort.
Richardn2002 Jul 29, 2024
00725d6
Fix zsort, thus rendering is back for `Aka.inp`.
Richardn2002 Jul 30, 2024
c1ade82
Params (and deforms) back online: Dirty zero check patching for an ol…
Richardn2002 Jul 30, 2024
5e03996
Physics cleanup.
Richardn2002 Jul 31, 2024
d3c3d02
Physics back online.
Richardn2002 Jul 31, 2024
51a2c4a
`DeformSrc` -> `DeformSource`
Richardn2002 Aug 3, 2024
fa1ab36
Put all components into `compoents.rs`.
Richardn2002 Aug 3, 2024
912782d
More direct `VertexBuffers` access.
Richardn2002 Aug 4, 2024
76b03d2
Better safety specifications related to GL buffer operations.
Richardn2002 Aug 4, 2024
e6e399c
Remove `new()` from `trait InoxRenderer`.
Richardn2002 Aug 4, 2024
599090a
Better `on_begin_draw()` `on_end_draw()` `draw()` interfaces.
Richardn2002 Aug 4, 2024
aff042e
`tracing::warn!()` instead of `panic!()` on non-standard component co…
Richardn2002 Aug 4, 2024
69549f9
Do not give `TexturedMesh` that is not going to be deformed by any so…
Richardn2002 Aug 4, 2024
7f4c9c0
Generalize `Mesh` into a standalone component.
Richardn2002 Aug 8, 2024
45f6a36
Move `OpenglRenderer::new` up in impl block
Speykious Aug 11, 2024
fc39a26
Merge branch 'main' into pr/Richardn2002/86
Speykious Sep 24, 2024
21136c2
Fix WebGL example
Speykious Sep 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions examples/render-opengl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{error::Error, fs};

use inox2d::formats::inp::parse_inp;
use inox2d::model::Model;
use inox2d::render::InoxRenderer;
use inox2d::render::InoxRendererExt;
use inox2d_opengl::OpenglRenderer;

use clap::Parser;
Expand Down Expand Up @@ -41,12 +41,18 @@ fn main() -> Result<(), Box<dyn Error>> {
tracing::info!("Parsing puppet");

let data = fs::read(cli.inp_path)?;
let model = parse_inp(data.as_slice())?;
let mut model = parse_inp(data.as_slice())?;
tracing::info!(
"Successfully parsed puppet: {}",
(model.puppet.meta.name.as_deref()).unwrap_or("<no puppet name specified in file>")
);

tracing::info!("Setting up puppet for transforms, params and rendering.");
model.puppet.init_transforms();
model.puppet.init_rendering();
model.puppet.init_params();
model.puppet.init_physics();
Speykious marked this conversation as resolved.
Show resolved Hide resolved

tracing::info!("Setting up windowing and OpenGL");
let app_frame = AppFrame::init(
WindowBuilder::new()
Expand Down Expand Up @@ -81,10 +87,9 @@ impl Inox2dOpenglExampleApp {

impl App for Inox2dOpenglExampleApp {
fn resume_window(&mut self, gl: glow::Context) {
match OpenglRenderer::new(gl) {
match OpenglRenderer::new(gl, &self.model) {
Ok(mut renderer) => {
tracing::info!("Initializing Inox2D renderer");
renderer.prepare(&self.model).unwrap();
renderer.resize(self.width, self.height);
renderer.camera.scale = Vec2::splat(0.15);
tracing::info!("Inox2D renderer initialized");
Expand Down Expand Up @@ -119,12 +124,20 @@ impl App for Inox2dOpenglExampleApp {
renderer.clear();

let puppet = &mut self.model.puppet;
puppet.begin_set_params();
puppet.begin_frame();
let t = scene_ctrl.current_elapsed();
let _ = puppet.set_named_param("Head:: Yaw-Pitch", Vec2::new(t.cos(), t.sin()));
puppet.end_set_params(scene_ctrl.dt());

renderer.render(puppet);
let _ = puppet
.param_ctx
.as_mut()
.unwrap()
.set("Head:: Yaw-Pitch", Vec2::new(t.cos(), t.sin()));
// Actually, not providing 0 for the first frame will not create too big a problem.
// 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);
}

fn handle_window_event(&mut self, event: WindowEvent, elwt: &EventLoopWindowTarget<()>) {
Expand Down
35 changes: 26 additions & 9 deletions examples/render-webgl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ async fn run() -> Result<(), Box<dyn std::error::Error>> {
use std::cell::RefCell;
use std::rc::Rc;

use inox2d::{formats::inp::parse_inp, render::InoxRenderer};
use inox2d::formats::inp::parse_inp;
use inox2d::render::InoxRendererExt;
use inox2d_opengl::OpenglRenderer;

use glam::Vec2;
Expand Down Expand Up @@ -86,13 +87,18 @@ async fn run() -> Result<(), Box<dyn std::error::Error>> {
.await?;

let model_bytes = res.bytes().await?;
let model = parse_inp(model_bytes.as_ref())?;
let mut model = parse_inp(model_bytes.as_ref())?;

tracing::info!("Setting up puppet for transforms, params and rendering.");
model.puppet.init_transforms();
model.puppet.init_rendering();
model.puppet.init_params();
model.puppet.init_physics();

info!("Initializing Inox2D renderer");
let mut renderer = OpenglRenderer::new(gl)?;
let mut renderer = OpenglRenderer::new(gl, &model)?;

info!("Creating buffers and uploading model textures");
renderer.prepare(&model)?;
renderer.camera.scale = Vec2::splat(0.15);
info!("Inox2D renderer initialized");

Expand All @@ -115,15 +121,26 @@ async fn run() -> Result<(), Box<dyn std::error::Error>> {
*anim_loop_g.borrow_mut() = Some(Closure::new(move || {
scene_ctrl.borrow_mut().update(&mut renderer.borrow_mut().camera);

renderer.borrow().clear();
{
renderer.borrow().clear();

let mut puppet = puppet.borrow_mut();
puppet.begin_set_params();
puppet.begin_frame();
let t = scene_ctrl.borrow().current_elapsed();
puppet.set_named_param("Head:: Yaw-Pitch", Vec2::new(t.cos(), t.sin()));
puppet.end_set_params(scene_ctrl.borrow().dt());
let _ = puppet
.param_ctx
.as_mut()
.unwrap()
.set("Head:: Yaw-Pitch", Vec2::new(t.cos(), t.sin()));

// Actually, not providing 0 for the first frame will not create too big a problem.
// 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().render(&puppet.borrow());

request_animation_frame(anim_loop_f.borrow().as_ref().unwrap());
}));
Expand Down
109 changes: 34 additions & 75 deletions inox2d-opengl/src/gl_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,85 +1,44 @@
use glam::Vec2;
use glow::HasContext;

use inox2d::render::RenderCtx;

use super::OpenglRendererError;

unsafe fn upload_array_to_gl<T>(gl: &glow::Context, array: &[T], target: u32, usage: u32) -> glow::Buffer {
/// Create and BIND an OpenGL buffer and upload data.
///
/// # Errors
///
/// This function will return an error if it couldn't create a buffer.
///
/// # Safety
///
/// `target` and `usage` must be valid OpenGL constants.
pub unsafe fn upload_array_to_gl<T>(
gl: &glow::Context,
array: &[T],
target: u32,
usage: u32,
) -> Result<glow::Buffer, OpenglRendererError> {
// Safety:
// - array is already a &[T], satisfying all pointer and size requirements.
// - data only accessed immutably in this function, satisfying lifetime requirements.
let bytes: &[u8] = core::slice::from_raw_parts(array.as_ptr() as *const u8, std::mem::size_of_val(array));
let buffer = gl.create_buffer().unwrap();
let buffer = gl.create_buffer().map_err(OpenglRendererError::Opengl)?;
gl.bind_buffer(target, Some(buffer));
gl.buffer_data_u8_slice(target, bytes, usage);
buffer
}

unsafe fn reupload_array_to_gl<T>(gl: &glow::Context, array: &[T], target: u32, start_idx: usize, end_idx: usize) {
let slice = &array[start_idx..end_idx];
let bytes: &[u8] = core::slice::from_raw_parts(slice.as_ptr() as *const u8, core::mem::size_of_val(slice));
gl.buffer_sub_data_u8_slice(target, start_idx as i32, bytes);
}

pub trait RenderCtxOpenglExt {
unsafe fn setup_gl_buffers(
&self,
gl: &glow::Context,
vao: glow::VertexArray,
) -> Result<glow::Buffer, OpenglRendererError>;
unsafe fn upload_deforms_to_gl(&self, gl: &glow::Context, buffer: glow::Buffer);
Ok(buffer)
}

impl RenderCtxOpenglExt for RenderCtx {
/// Uploads the vertex and index buffers to OpenGL.
///
/// # Errors
///
/// This function will return an error if it couldn't create a vertex array.
///
/// # Safety
///
/// Only call this function once when loading a new puppet.
unsafe fn setup_gl_buffers(
&self,
gl: &glow::Context,
vao: glow::VertexArray,
) -> Result<glow::Buffer, OpenglRendererError> {
gl.bind_vertex_array(Some(vao));

upload_array_to_gl(gl, &self.vertex_buffers.verts, glow::ARRAY_BUFFER, glow::STATIC_DRAW);
gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 0, 0);
gl.enable_vertex_attrib_array(0);

upload_array_to_gl(gl, &self.vertex_buffers.uvs, glow::ARRAY_BUFFER, glow::STATIC_DRAW);
gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, 0, 0);
gl.enable_vertex_attrib_array(1);

let deform_buffer =
upload_array_to_gl(gl, &self.vertex_buffers.deforms, glow::ARRAY_BUFFER, glow::DYNAMIC_DRAW);
gl.vertex_attrib_pointer_f32(2, 2, glow::FLOAT, false, 0, 0);
gl.enable_vertex_attrib_array(2);

upload_array_to_gl(
gl,
&self.vertex_buffers.indices,
glow::ELEMENT_ARRAY_BUFFER,
glow::STATIC_DRAW,
);

Ok(deform_buffer)
}

/// # Safety
///
/// unsafe as initiating GL calls. can be safely called for multiple times,
/// but only needed once after deform update and before rendering.
unsafe fn upload_deforms_to_gl(&self, gl: &glow::Context, buffer: glow::Buffer) {
gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer));

reupload_array_to_gl(
gl,
&self.vertex_buffers.deforms,
glow::ARRAY_BUFFER,
0,
self.vertex_buffers.deforms.len(),
);
}
}
/// Upload full deform buffer content.
///
/// # Safety
///
/// The vertex array object created in `setup_gl_buffers()` must be bound and no new ARRAY_BUFFER is enabled.
pub unsafe fn upload_deforms_to_gl(gl: &glow::Context, deforms: &[Vec2], buffer: glow::Buffer) {
gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer));

// Safety: same as those described in upload_array_to_gl().
let bytes: &[u8] = core::slice::from_raw_parts(deforms.as_ptr() as *const u8, std::mem::size_of_val(deforms));
// if the above preconditions are met, deform is then the currently bound ARRAY_BUFFER.
gl.buffer_sub_data_u8_slice(glow::ARRAY_BUFFER, 0, bytes);
}
Loading
Loading