diff --git a/Cargo.lock b/Cargo.lock index 925ea0f..c7c50da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1845,7 +1845,9 @@ dependencies = [ "gltf", "image", "infer", + "instant", "lyra-ecs", + "lyra-math", "mime", "notify", "notify-debouncer-full", @@ -3101,7 +3103,6 @@ dependencies = [ "async-std", "fps_counter", "lyra-engine", - "lyra-scripting", "tracing", ] diff --git a/examples/testbed/Cargo.toml b/examples/testbed/Cargo.toml index 877d0b4..79687cc 100644 --- a/examples/testbed/Cargo.toml +++ b/examples/testbed/Cargo.toml @@ -6,8 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -lyra-engine = { path = "../../", version = "0.0.1", features = ["lua_scripting"] } -lyra-scripting = { path = "../../lyra-scripting", features = ["lua", "teal"] } +lyra-engine = { path = "../../", version = "0.0.1" } +#lyra-engine = { path = "../../", version = "0.0.1", features = ["lua_scripting"] } +#lyra-scripting = { path = "../../lyra-scripting", features = ["lua", "teal"] } #lyra-ecs = { path = "../../lyra-ecs"} anyhow = "1.0.75" async-std = "1.12.0" diff --git a/examples/testbed/assets/pos-testing/child-node-cubes.glb b/examples/testbed/assets/pos-testing/child-node-cubes.glb new file mode 100644 index 0000000..eb0be46 Binary files /dev/null and b/examples/testbed/assets/pos-testing/child-node-cubes.glb differ diff --git a/examples/testbed/assets/pos-testing/separate-nodes-two-cubes.glb b/examples/testbed/assets/pos-testing/separate-nodes-two-cubes.glb new file mode 100644 index 0000000..a10cc1a Binary files /dev/null and b/examples/testbed/assets/pos-testing/separate-nodes-two-cubes.glb differ diff --git a/examples/testbed/assets/sponza/.gitignore b/examples/testbed/assets/sponza/.gitignore new file mode 100644 index 0000000..78f4b5c --- /dev/null +++ b/examples/testbed/assets/sponza/.gitignore @@ -0,0 +1,2 @@ +Sponza* +Textures \ No newline at end of file diff --git a/examples/testbed/assets/sponza/README.md b/examples/testbed/assets/sponza/README.md new file mode 100644 index 0000000..dfab197 --- /dev/null +++ b/examples/testbed/assets/sponza/README.md @@ -0,0 +1 @@ +To keep the size of this repository down, the Sponza scene is omitted from this repo. The files were downloaded from https://github.com/toji/sponza-optimized \ No newline at end of file diff --git a/examples/testbed/src/main.rs b/examples/testbed/src/main.rs index cc34877..19179f0 100644 --- a/examples/testbed/src/main.rs +++ b/examples/testbed/src/main.rs @@ -1,7 +1,7 @@ use std::ptr::NonNull; -use lyra_engine::{math::{self, Vec3}, math::Transform, input::{KeyCode, ActionHandler, Action, ActionKind, LayoutId, ActionMapping, ActionSource, ActionMappingId, InputActionPlugin, MouseInput, MouseAxis, CommonActionLabel}, game::Game, render::{window::{CursorGrabMode, WindowOptions}, light::{PointLight, directional::DirectionalLight, SpotLight}}, change_tracker::Ct, ecs::{system::{Criteria, CriteriaSchedule, BatchedSystem, IntoSystem}, World, Component}, DeltaTime, scene::{ModelComponent, CameraComponent}, lua::{LuaScriptingPlugin, LuaScript}, Script, ScriptList}; -use lyra_engine::assets::{ResourceManager, Model}; +use lyra_engine::{assets::gltf::Gltf, ecs::{system::{BatchedSystem, Criteria, CriteriaSchedule, IntoSystem}, Component, World}, game::Game, input::{Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput}, math::{self, Transform, Vec3}, render::light::{directional::DirectionalLight, PointLight, SpotLight}, scene::{CameraComponent, MeshComponent}, DeltaTime}; +use lyra_engine::assets::ResourceManager; mod free_fly_camera; use free_fly_camera::{FreeFlyCameraPlugin, FreeFlyCamera}; @@ -16,6 +16,13 @@ pub enum ActionLabel { LookRoll, } +const ACTLBL_MOVE_UP_DOWN: &str = "MoveUpDown"; +const ACTLBL_MOVE_LEFT_RIGHT: &str = "MoveLeftRight"; +const ACTLBL_MOVE_FORWARD_BACKWARD: &str = "MoveForwardBackward"; +const ACTLBL_LOOK_LEFT_RIGHT: &str = "LookLeftRight"; +const ACTLBL_LOOK_UP_DOWN: &str = "LookUpDown"; +const ACTLBL_LOOK_ROLL: &str = "LookRoll"; + struct FixedTimestep { max_tps: u32, fixed_time: f32, @@ -86,30 +93,45 @@ async fn main() { //let diffuse_texture = resman.request::("assets/happy-tree.png").unwrap(); //let antique_camera_model = resman.request::("assets/AntiqueCamera.glb").unwrap(); //let cube_model = resman.request::("assets/cube-texture-bin.glb").unwrap(); - let cube_model = resman.request::("assets/texture-sep/texture-sep.gltf").unwrap(); - let crate_model = resman.request::("assets/crate/crate.gltf").unwrap(); - //let sponza_model = resman.request::("assets/sponza/Sponza.gltf").unwrap(); + let cube_gltf = resman.request::("assets/texture-sep/texture-sep.gltf").unwrap(); + let crate_gltf = resman.request::("assets/crate/crate.gltf").unwrap(); + + let separate_gltf = resman.request::("assets/pos-testing/separate-nodes-two-cubes.glb").unwrap(); + drop(resman); + + let cube_mesh = &cube_gltf.data_ref() + .unwrap().meshes[0]; + let crate_mesh = &crate_gltf.data_ref() + .unwrap().meshes[0]; + + let separate_scene = &separate_gltf.data_ref() + .unwrap().scenes[0]; + + /* let sponza_model = resman.request::("assets/sponza/Sponza.gltf").unwrap(); drop(resman); - /* world.spawn(( - ModelComponent(antique_camera_model), - Transform::from_xyz(0.0, -5.0, -10.0), - )); */ + let sponza_scene = &sponza_model.data_ref() + .unwrap().scenes[0]; - /* world.spawn(( - ModelComponent(sponza_model), + world.spawn(( + sponza_scene.clone(), Transform::from_xyz(0.0, 0.0, 0.0), )); */ - { - let cube_tran = Transform::from_xyz(-3.5, 0.0, -8.0); + world.spawn(( + separate_scene.clone(), + Transform::from_xyz(0.0, -5.0, -10.0), + )); + + /* { + let cube_tran = Transform::from_xyz(-5.9026427, -1.8953488, -10.0); //cube_tran.rotate_y(math::Angle::Degrees(180.0)); world.spawn(( cube_tran, - ModelComponent(crate_model.clone()), + crate_mesh.clone(), CubeFlag, )); - } + } */ { let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0); @@ -124,11 +146,11 @@ async fn main() { specular: 1.3, }, light_tran, - ModelComponent(cube_model.clone()), + cube_mesh.clone(), )); } - { + /* { let mut light_tran = Transform::from_xyz(-3.5, 0.2, -4.5); light_tran.scale = Vec3::new(0.5, 0.5, 0.5); world.spawn(( @@ -146,9 +168,31 @@ async fn main() { specular: 1.0, }, Transform::from(light_tran), - ModelComponent(cube_model.clone()), + cube_mesh.clone(), )); } + + { + let mut light_tran = Transform::from_xyz(2.0, 2.5, -9.5); + light_tran.scale = Vec3::new(0.5, 0.5, 0.5); + world.spawn(( + PointLight { + color: Vec3::new(0.0, 0.0, 1.0), + + intensity: 3.3, + + constant: 1.0, + linear: 0.09, + quadratic: 0.032, + + ambient: 0.2, + diffuse: 1.0, + specular: 1.3, + }, + Transform::from(light_tran), + cube_mesh.clone(), + )); + } */ /* { let mut light_tran = Transform::from_xyz(-5.0, 2.5, -9.5); @@ -172,28 +216,6 @@ async fn main() { )); } */ - { - let mut light_tran = Transform::from_xyz(2.0, 2.5, -9.5); - light_tran.scale = Vec3::new(0.5, 0.5, 0.5); - world.spawn(( - PointLight { - color: Vec3::new(0.0, 0.0, 1.0), - - intensity: 3.3, - - constant: 1.0, - linear: 0.09, - quadratic: 0.032, - - ambient: 0.2, - diffuse: 1.0, - specular: 1.3, - }, - Transform::from(light_tran), - ModelComponent(cube_model), - )); - } - let mut camera = CameraComponent::new_3d(); camera.transform.translation += math::Vec3::new(0.0, 0.0, 5.5); world.spawn(( camera, FreeFlyCamera::default() )); @@ -211,7 +233,7 @@ async fn main() { Ok(()) }; - let fps_plugin = move |game: &mut Game| { + let _fps_plugin = move |game: &mut Game| { let world = game.world_mut(); world.add_resource(fps_counter::FPSCounter::new()); }; @@ -246,54 +268,54 @@ async fn main() { }; let action_handler_plugin = |game: &mut Game| { - /* let action_handler = ActionHandler::builder() + let action_handler = ActionHandler::builder() .add_layout(LayoutId::from(0)) - .add_action(CommonActionLabel::MoveForwardBackward, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::MoveLeftRight, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::MoveUpDown, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::LookLeftRight, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::LookUpDown, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::LookRoll, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_MOVE_LEFT_RIGHT, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_MOVE_UP_DOWN, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_LOOK_LEFT_RIGHT, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_LOOK_UP_DOWN, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_LOOK_ROLL, Action::new(ActionKind::Axis)) .add_mapping(ActionMapping::builder(LayoutId::from(0), ActionMappingId::from(0)) - .bind(CommonActionLabel::MoveForwardBackward, &[ + .bind(ACTLBL_MOVE_FORWARD_BACKWARD, &[ ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0) ]) - .bind(CommonActionLabel::MoveLeftRight, &[ + .bind(ACTLBL_MOVE_LEFT_RIGHT, &[ ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0) ]) - .bind(CommonActionLabel::MoveUpDown, &[ + .bind(ACTLBL_MOVE_UP_DOWN, &[ ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0) ]) - .bind(CommonActionLabel::LookLeftRight, &[ + .bind(ACTLBL_LOOK_LEFT_RIGHT, &[ ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(), ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0), //ActionSource::Gamepad(GamepadFormat::DualAxis, GamepadInput::Axis(GamepadAxis::RThumbstickX)).into_binding(), ]) - .bind(CommonActionLabel::LookUpDown, &[ + .bind(ACTLBL_LOOK_UP_DOWN, &[ ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(), ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0), //ActionSource::Gamepad(GamepadFormat::DualAxis, GamepadInput::Axis(GamepadAxis::RThumbstickY)).into_binding(), ]) - .bind(CommonActionLabel::LookRoll, &[ + .bind(ACTLBL_LOOK_ROLL, &[ ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0), ]) .finish() - ); + ).finish(); let world = game.world_mut(); - world.add_resource(action_handler); */ + world.add_resource(action_handler); game.with_plugin(InputActionPlugin); }; - let script_test_plugin = |game: &mut Game| { + /* let script_test_plugin = |game: &mut Game| { game.with_plugin(LuaScriptingPlugin); let world = game.world_mut(); @@ -306,13 +328,13 @@ async fn main() { let scripts = ScriptList::new(vec![script]); world.spawn((scripts,)); - }; + }; */ Game::initialize().await .with_plugin(lyra_engine::DefaultPlugins) .with_startup_system(setup_sys.into_system()) .with_plugin(action_handler_plugin) - .with_plugin(script_test_plugin) + //.with_plugin(script_test_plugin) //.with_plugin(fps_plugin) .with_plugin(jiggle_plugin) .with_plugin(FreeFlyCameraPlugin) diff --git a/lyra-game/src/render/material.rs b/lyra-game/src/render/material.rs index dec5b12..b53149b 100755 --- a/lyra-game/src/render/material.rs +++ b/lyra-game/src/render/material.rs @@ -10,11 +10,11 @@ pub struct MaterialSpecular { } impl MaterialSpecular { - pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::Specular) -> Self { - let tex = value.texture.as_ref().map(|t| t.data_ref()) + pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::gltf::Specular) -> Self { + let tex = value.texture.as_ref().and_then(|t| t.data_ref()) .map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), &i.image, None).unwrap()); - let color_tex = value.color_texture.as_ref().map(|t| t.data_ref()) + let color_tex = value.color_texture.as_ref().and_then(|t| t.data_ref()) .map(|i| RenderTexture::from_image(device, queue, bg_layout, &i.image, None).unwrap()); Self { @@ -38,8 +38,8 @@ pub struct Material { } impl Material { - pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::Material) -> Self { - let diffuse_texture = value.base_color_texture.as_ref().map(|t| t.data_ref()) + pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::gltf::Material) -> Self { + let diffuse_texture = value.base_color_texture.as_ref().and_then(|t| t.data_ref()) .map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), &i.image, None).unwrap()); let specular = value.specular.as_ref().map(|s| MaterialSpecular::from_resource(device, queue, bg_layout.clone(), s)); diff --git a/lyra-game/src/render/renderer.rs b/lyra-game/src/render/renderer.rs index 48d77d2..e8cba97 100755 --- a/lyra-game/src/render/renderer.rs +++ b/lyra-game/src/render/renderer.rs @@ -5,10 +5,13 @@ use std::borrow::Cow; use glam::Vec3; use instant::Instant; use itertools::izip; -use lyra_ecs::Entity; +use lyra_ecs::query::filter::{Has, Or}; +use lyra_ecs::{Entity, Tick}; use lyra_ecs::query::{Entities, TickOf}; use lyra_ecs::World; -use tracing::{debug, warn}; +use lyra_resource::gltf::GltfScene; +use tracing::{debug, debug_span, warn}; +use uuid::Uuid; use wgpu::{BindGroupLayout, Limits}; use wgpu::util::DeviceExt; use winit::window::Window; @@ -16,7 +19,7 @@ use winit::window::Window; use crate::math::Transform; use crate::render::material::MaterialUniform; use crate::render::render_buffer::BufferWrapperBuilder; -use crate::scene::{ModelComponent, CameraComponent}; +use crate::scene::CameraComponent; use super::camera::{RenderCamera, CameraUniform}; use super::desc_buf_lay::DescVertexBufferLayout; @@ -28,7 +31,10 @@ use super::transform_buffer_storage::TransformBuffers; use super::vertex::Vertex; use super::{render_pipeline::FullRenderPipeline, render_buffer::BufferStorage, render_job::RenderJob}; -use lyra_resource::Mesh; +use lyra_resource::{gltf::Mesh, ResHandle}; + +type MeshHandle = ResHandle; +type SceneHandle = ResHandle; pub trait Renderer { fn prepare(&mut self, main_world: &mut World); @@ -265,16 +271,19 @@ impl BasicRenderer { s } - fn update_mesh_buffers(&mut self, _entity: Entity, mesh: &Mesh) { - if let Some(buffers) = self.mesh_buffers.get_mut(&mesh.uuid) { + /// Checks if the mesh buffers in the GPU need to be updated. + fn check_mesh_buffers(&mut self, _entity: Entity, meshh: &ResHandle) { + let mesh_uuid = meshh.uuid(); + + if let (Some(mesh), Some(buffers)) = (meshh.data_ref(), self.mesh_buffers.get_mut(&mesh_uuid)) { // check if the buffer sizes dont match. If they dont, completely remake the buffers let vertices = mesh.position().unwrap(); if buffers.buffer_vertex.count() != vertices.len() { - debug!("Recreating buffers for mesh {}", mesh.uuid.to_string()); - let (vert, idx) = self.create_vertex_index_buffers(mesh); + debug!("Recreating buffers for mesh {}", mesh_uuid.to_string()); + let (vert, idx) = self.create_vertex_index_buffers(&mesh); // have to re-get buffers because of borrow checker - let buffers = self.mesh_buffers.get_mut(&mesh.uuid).unwrap(); + let buffers = self.mesh_buffers.get_mut(&mesh_uuid).unwrap(); buffers.buffer_indices = idx; buffers.buffer_vertex = vert; @@ -292,8 +301,8 @@ impl BasicRenderer { if let Some(index_buffer) = buffers.buffer_indices.as_ref() { let aligned_indices = match mesh.indices.as_ref().unwrap() { // U16 indices need to be aligned to u32, for wpgu, which are 4-bytes in size. - lyra_resource::MeshIndices::U16(v) => bytemuck::pod_align_to::(v).1, - lyra_resource::MeshIndices::U32(v) => bytemuck::pod_align_to::(v).1, + lyra_resource::gltf::MeshIndices::U16(v) => bytemuck::pod_align_to::(v).1, + lyra_resource::gltf::MeshIndices::U32(v) => bytemuck::pod_align_to::(v).1, }; let index_buffer = index_buffer.1.buffer(); @@ -327,8 +336,8 @@ impl BasicRenderer { let indices = match mesh.indices.as_ref() { Some(indices) => { let (idx_type, len, contents) = match indices { - lyra_resource::MeshIndices::U16(v) => (wgpu::IndexFormat::Uint16, v.len(), bytemuck::cast_slice(v)), - lyra_resource::MeshIndices::U32(v) => (wgpu::IndexFormat::Uint32, v.len(), bytemuck::cast_slice(v)), + lyra_resource::gltf::MeshIndices::U16(v) => (wgpu::IndexFormat::Uint16, v.len(), bytemuck::cast_slice(v)), + lyra_resource::gltf::MeshIndices::U32(v) => (wgpu::IndexFormat::Uint32, v.len(), bytemuck::cast_slice(v)), }; let index_buffer = self.device.create_buffer_init( @@ -354,7 +363,11 @@ impl BasicRenderer { fn create_mesh_buffers(&mut self, mesh: &Mesh) -> MeshBufferStorage { let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh); - let material = Material::from_resource(&self.device, &self.queue, self.bgl_texture.clone(), &mesh.material()); + let material = mesh.material.as_ref() + .expect("Material resource not loaded yet") + .data_ref() + .unwrap(); + let material = Material::from_resource(&self.device, &self.queue, self.bgl_texture.clone(), &material); let uni = MaterialUniform::from(&material); self.queue.write_buffer(&self.material_buffer.inner_buf, 0, bytemuck::bytes_of(&uni)); debug!("Wrote material to buffer"); @@ -367,7 +380,7 @@ impl BasicRenderer { } /// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed. - fn process_mesh(&mut self, entity: Entity, transform: Transform, mesh: &Mesh) -> bool { + fn process_mesh(&mut self, entity: Entity, transform: Transform, mesh: &Mesh, mesh_uuid: Uuid) -> bool { if self.transform_buffers.should_expand() { self.transform_buffers.expand_buffers(&self.device); } @@ -376,15 +389,48 @@ impl BasicRenderer { entity, || ( transform.calculate_mat4(), glam::Mat3::from_quat(transform.rotation) )); #[allow(clippy::map_entry)] - if !self.mesh_buffers.contains_key(&mesh.uuid) { + if !self.mesh_buffers.contains_key(&mesh_uuid) { // create the mesh's buffers let buffers = self.create_mesh_buffers(mesh); - self.mesh_buffers.insert(mesh.uuid, buffers); - self.entity_meshes.insert(entity, mesh.uuid); + self.mesh_buffers.insert(mesh_uuid, buffers); + self.entity_meshes.insert(entity, mesh_uuid); true } else { false } } + + fn interpolate_transforms(&mut self, now: Instant, last_epoch: Tick, entity: Entity, transform: &Transform, transform_epoch: Tick) -> Transform { + let cached = match self.entity_last_transforms.get_mut(&entity) { + Some(last) if transform_epoch == last_epoch => { + last.from_transform = last.to_transform; + last.to_transform = *transform; + last.last_updated_at = Some(last.cached_at); + last.cached_at = now; + + last.clone() + }, + Some(last) => last.clone(), + None => { + let cached = CachedTransform { + last_updated_at: None, + cached_at: now, + from_transform: *transform, + to_transform: *transform, + }; + self.entity_last_transforms.insert(entity, cached.clone()); + cached + } + }; + + let fixed_time = match cached.last_updated_at { + Some(last_updated_at) => cached.cached_at - last_updated_at, + None => now - cached.cached_at + }.as_secs_f32(); + let accumulator = (now - cached.cached_at).as_secs_f32(); + let alpha = accumulator / fixed_time; + + cached.from_transform.lerp(cached.to_transform, alpha) + } } impl Renderer for BasicRenderer { @@ -395,57 +441,71 @@ impl Renderer for BasicRenderer { let now_inst = Instant::now(); - for (entity, model, model_epoch, transform, transform_epoch) in main_world.view_iter::<(Entities, &ModelComponent, TickOf, &Transform, TickOf)>() { + let view = main_world.filtered_view_iter::<(Entities, &Transform, TickOf), Or, Has>>(); + for (entity, transform, transform_epoch) in view { alive_entities.insert(entity); - let cached = match self.entity_last_transforms.get_mut(&entity) { - Some(last) if transform_epoch == last_epoch => { - last.from_transform = last.to_transform; - last.to_transform = *transform; - last.last_updated_at = Some(last.cached_at); - last.cached_at = now_inst; + let mesh_view = main_world.view_one::<(&MeshHandle, TickOf)>(entity); + if let Some((mesh_han, mesh_epoch)) = mesh_view.get() { + let interop_pos = self.interpolate_transforms(now_inst, last_epoch, entity, &transform, transform_epoch); - last.clone() - }, - Some(last) => last.clone(), - None => { - let cached = CachedTransform { - last_updated_at: None, - cached_at: now_inst, - from_transform: *transform, - to_transform: *transform, - }; - self.entity_last_transforms.insert(entity, cached.clone()); - cached + if let Some(mesh) = mesh_han.data_ref() { + // if process mesh did not just create a new mesh, and the epoch + // shows that the scene has changed, verify that the mesh buffers + // dont need to be resent to the gpu. + if !self.process_mesh(entity, interop_pos, &*mesh, mesh_han.uuid()) + && mesh_epoch == last_epoch { + self.check_mesh_buffers(entity, &mesh_han); + } + + let material = mesh.material.as_ref().unwrap() + .data_ref().unwrap(); + let shader = material.shader_uuid.unwrap_or(0); + let job = RenderJob::new(entity, shader, mesh_han.uuid(), interop_pos); + self.render_jobs.push_back(job); } - }; - //debug!("Transform: {:?}, comp: {:?}", cached.to_transform.translation, transform.transform.translation); - - let fixed_time = match cached.last_updated_at { - Some(last_updated_at) => cached.cached_at - last_updated_at, - None => now_inst - cached.cached_at - }.as_secs_f32(); - let accumulator = (now_inst - cached.cached_at).as_secs_f32(); - let alpha = accumulator / fixed_time; + } - let transform_val = cached.from_transform.lerp(cached.to_transform, alpha); + let scene_view = main_world.view_one::<(&SceneHandle, TickOf)>(entity); + if let Some((scene_han, scene_epoch)) = scene_view.get() { + // TODO: Rendering scenes - let model = model.data_ref(); - for mesh in model.meshes.iter() { - if !self.process_mesh(entity, transform_val, mesh) && model_epoch == last_epoch { - self.update_mesh_buffers(entity, mesh); + let scene_scope = debug_span!("scene", uuid = scene_han.uuid().to_string()); + let _enter = scene_scope.enter(); + + if let Some(scene) = scene_han.data_ref() { + let interop_pos = self.interpolate_transforms(now_inst, last_epoch, entity, &transform, transform_epoch); + let meshes = scene.collect_world_meshes(); + + for (mesh_han, mesh_pos) in meshes.into_iter() { + if let Some(mesh) = mesh_han.data_ref() { + let mesh_interp = interop_pos + mesh_pos; + + let mesh_scope = debug_span!("mesh", uuid = mesh_han.uuid().to_string()); + let _enter = mesh_scope.enter(); + + debug!("mesh at {:?}", mesh_interp.translation); + + // if process mesh did not just create a new mesh, and the epoch + // shows that the scene has changed, verify that the mesh buffers + // dont need to be resent to the gpu. + if !self.process_mesh(entity, mesh_interp, &*mesh, mesh_han.uuid()) + && scene_epoch == last_epoch { + self.check_mesh_buffers(entity, &mesh_han); + debug!("updating mesh buffers"); + } + + let material = mesh.material.as_ref().unwrap() + .data_ref().unwrap(); + let shader = material.shader_uuid.unwrap_or(0); + let job = RenderJob::new(entity, shader, mesh_han.uuid(), interop_pos); + self.render_jobs.push_back(job); + } + } } - - let shader = mesh.material().shader_uuid.unwrap_or(0); - let job = RenderJob::new(entity, shader, mesh.uuid, transform_val); - self.render_jobs.push_back(job); } } - /* for (entity, mesh, mesh_epoch, transform) in main_world.query::<(Entities, &MeshComponent, EpochOf, &TransformComponent)>().iter() { - debug!("TODO: Process MeshComponents"); // TODO: Process MeshComponents - } */ - // collect dead entities self.transform_buffers.tick(); diff --git a/lyra-game/src/render/texture.rs b/lyra-game/src/render/texture.rs index aa99388..0237a23 100755 --- a/lyra-game/src/render/texture.rs +++ b/lyra-game/src/render/texture.rs @@ -5,25 +5,6 @@ use lyra_resource::{ResHandle, Texture}; use super::render_buffer::BindGroupPair; -/* #[derive(Clone)] -pub struct Texture { - texture_id: u32, - pub img: image::DynamicImage, -} - -impl Texture { - pub fn from_bytes(bytes: &[u8]) -> anyhow::Result { - let img = image::load_from_memory(bytes)?; - - Ok(Self { - texture_id: 0, - img, - }) - } -} */ - - - #[allow(dead_code)] pub struct RenderTexture { pub inner_texture: wgpu::Texture, @@ -153,8 +134,12 @@ impl RenderTexture { }) } - pub fn update_texture(&mut self, _device: &wgpu::Device, queue: &wgpu::Queue, texture: &Arc>) { - let texture = &texture.data_ref().image; + /// Updates the texture on the gpu with the provided texture. + /// + /// # Panics + /// Panics if `texture` is not loaded + pub fn update_texture(&mut self, _device: &wgpu::Device, queue: &wgpu::Queue, texture: &ResHandle) { + let texture = &texture.data_ref().unwrap().image; let rgba = texture.to_rgba8(); let dimensions = texture.dimensions(); let size = wgpu::Extent3d { diff --git a/lyra-game/src/scene/mesh.rs b/lyra-game/src/scene/mesh.rs index 7de1ef5..f7c7255 100755 --- a/lyra-game/src/scene/mesh.rs +++ b/lyra-game/src/scene/mesh.rs @@ -1,15 +1,37 @@ use lyra_ecs::Component; -use lyra_resource::Mesh; +use lyra_reflect::Reflect; +use lyra_resource::{gltf::Mesh, ResHandle}; -#[derive(Clone, Component)] +#[derive(Clone, Component, Reflect)] pub struct MeshComponent { - pub mesh: Mesh, + #[reflect(skip)] + pub mesh: ResHandle, +} + +impl From> for MeshComponent { + fn from(value: ResHandle) -> Self { + Self { + mesh: value + } + } +} + +impl std::ops::Deref for MeshComponent { + type Target = ResHandle; + + fn deref(&self) -> &Self::Target { + &self.mesh + } +} + +impl std::ops::DerefMut for MeshComponent { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.mesh + } } impl MeshComponent { - pub fn new(mesh: Mesh) -> Self { - Self { - mesh, - } + pub fn new(mesh: ResHandle) -> Self { + Self::from(mesh) } } \ No newline at end of file diff --git a/lyra-game/src/scene/mod.rs b/lyra-game/src/scene/mod.rs index 47898a1..090ad66 100644 --- a/lyra-game/src/scene/mod.rs +++ b/lyra-game/src/scene/mod.rs @@ -1,9 +1,6 @@ pub mod mesh; pub use mesh::*; -pub mod model; -pub use model::*; - pub mod camera; pub use camera::*; diff --git a/lyra-game/src/scene/model.rs b/lyra-game/src/scene/model.rs deleted file mode 100644 index 2c5a6b3..0000000 --- a/lyra-game/src/scene/model.rs +++ /dev/null @@ -1,41 +0,0 @@ -use lyra_ecs::Component; -use lyra_reflect::Reflect; -use lyra_resource::ResHandle; - -use crate::assets::Model; - -#[derive(Clone, Component, Reflect)] -pub struct ModelComponent(#[reflect(skip)] pub ResHandle); - -impl From> for ModelComponent { - fn from(value: ResHandle) -> Self { - ModelComponent(value) - } -} - -/* impl From for ModelComponent { - -} */ - -impl std::ops::Deref for ModelComponent { - type Target = ResHandle; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::ops::DerefMut for ModelComponent { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/* impl ModelComponent { - pub fn new(model, material: Material) -> Self { - Self { - mesh, - material - } - } -} */ \ No newline at end of file