kitgit

tirbofish/dropbear · diff

479c490 · Thribhu K

feature: TRS (translation, rotation, scale) animation implemented fix: use string id instead of typeid for storing editor tab IDs

Unverified

diff --git a/crates/dropbear-engine/src/bind_groups.rs b/crates/dropbear-engine/src/bind_groups.rs
index 762605a..0304090 100644
--- a/crates/dropbear-engine/src/bind_groups.rs
+++ b/crates/dropbear-engine/src/bind_groups.rs
@@ -40,6 +40,7 @@ impl SceneGlobalsBindGroup {
         globals_buffer: &UniformBuffer<Globals>,
         camera_buffer: &Buffer,
     ) {
+        puffin::profile_function!();
         self.bind_group = graphics
             .device
             .create_bind_group(&wgpu::BindGroupDescriptor {
diff --git a/crates/dropbear-engine/src/entity.rs b/crates/dropbear-engine/src/entity.rs
index 3591582..605e45f 100644
--- a/crates/dropbear-engine/src/entity.rs
+++ b/crates/dropbear-engine/src/entity.rs
@@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
 use std::{collections::HashMap, path::Path, sync::Arc};
 
 use crate::asset::Handle;
-use crate::model::Material;
+use crate::model::{Material, NodeTransform};
 use crate::{
     asset::ASSET_REGISTRY,
     graphics::{Instance, SharedGraphicsContext},
@@ -69,6 +69,13 @@ impl EntityTransform {
             scale: self.world.scale * self.local.scale,
         }
     }
+
+    /// Applies a node transform for TRS animation as an absolute local transform.
+    pub fn apply_animation(&mut self, node_transform: &NodeTransform) {
+        self.local.position = node_transform.translation.as_dvec3();
+        self.local.rotation = node_transform.rotation.as_dquat();
+        self.local.scale = node_transform.scale.as_dvec3();
+    }
 }
 
 /// A type that represents a position, rotation and scale of an entity
diff --git a/crates/dropbear-engine/src/pipelines/hdr.rs b/crates/dropbear-engine/src/pipelines/hdr.rs
index 085951b..2a67108 100644
--- a/crates/dropbear-engine/src/pipelines/hdr.rs
+++ b/crates/dropbear-engine/src/pipelines/hdr.rs
@@ -146,6 +146,7 @@ impl HdrPipeline {
     /// This renders the internal HDR texture to the [TextureView]
     /// supplied as parameter.
     pub fn process(&self, encoder: &mut wgpu::CommandEncoder, output: &wgpu::TextureView) {
+        puffin::profile_function!();
         let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
             label: Some("Hdr::process"),
             color_attachments: &[Some(wgpu::RenderPassColorAttachment {
diff --git a/crates/eucalyptus-core/src/animation.rs b/crates/eucalyptus-core/src/animation.rs
index 7b7b136..59018cd 100644
--- a/crates/eucalyptus-core/src/animation.rs
+++ b/crates/eucalyptus-core/src/animation.rs
@@ -4,7 +4,7 @@ use crate::scripting::native::DropbearNativeError;
 use crate::scripting::result::DropbearNativeResult;
 use dropbear_engine::animation::{AnimationComponent, AnimationSettings};
 use dropbear_engine::asset::ASSET_REGISTRY;
-use dropbear_engine::entity::MeshRenderer;
+use dropbear_engine::entity::{EntityTransform, MeshRenderer};
 use dropbear_engine::graphics::SharedGraphicsContext;
 use egui::{CollapsingHeader, ComboBox, Ui};
 use hecs::{Entity, World};
@@ -57,6 +57,20 @@ impl Component for AnimationComponent {
 
         self.update(dt, model);
 
+        let target_node = self
+            .active_animation_index
+            .and_then(|index| model.animations.get(index))
+            .and_then(|animation| animation.channels.first())
+            .map(|channel| channel.target_node);
+
+        if let Some(node_idx) = target_node {
+            if let Some(node_transform) = self.local_pose.get(&node_idx) {
+                if let Ok(mut entity_transform) = world.get::<&mut EntityTransform>(entity) {
+                    entity_transform.apply_animation(node_transform);
+                }
+            }
+        }
+
         self.prepare_gpu_resources(graphics.clone());
     }
 
diff --git a/crates/eucalyptus-editor/Cargo.toml b/crates/eucalyptus-editor/Cargo.toml
index 4a57944..92a90a1 100644
--- a/crates/eucalyptus-editor/Cargo.toml
+++ b/crates/eucalyptus-editor/Cargo.toml
@@ -56,6 +56,7 @@ semver.workspace = true
 serde.workspace = true
 bitflags.workspace = true
 downcast-rs.workspace = true
+puffin.workspace = true
 
 [target.'cfg(unix)'.dependencies]
 daemonize = "0.5.0"
diff --git a/crates/eucalyptus-editor/src/editor/asset_viewer.rs b/crates/eucalyptus-editor/src/editor/asset_viewer.rs
index dc25844..433c7a3 100644
--- a/crates/eucalyptus-editor/src/editor/asset_viewer.rs
+++ b/crates/eucalyptus-editor/src/editor/asset_viewer.rs
@@ -1372,6 +1372,7 @@ pub struct AssetViewerDock;
 impl EditorTabDock for AssetViewerDock {
     fn desc() -> EditorTabDockDescriptor {
         EditorTabDockDescriptor {
+            id: "asset_viewer",
             title: "Asset Viewer".to_string(),
         }
     }
diff --git a/crates/eucalyptus-editor/src/editor/build_console.rs b/crates/eucalyptus-editor/src/editor/build_console.rs
index ab423df..6e2daa8 100644
--- a/crates/eucalyptus-editor/src/editor/build_console.rs
+++ b/crates/eucalyptus-editor/src/editor/build_console.rs
@@ -147,8 +147,7 @@ pub struct BuildConsoleDock;
 
 impl EditorTabDock for BuildConsoleDock {
     fn desc() -> EditorTabDockDescriptor {
-        EditorTabDockDescriptor {
-            title: "Build Output".to_string(),
+        EditorTabDockDescriptor {            id: "build_console",            title: "Build Output".to_string(),
         }
     }
 
diff --git a/crates/eucalyptus-editor/src/editor/dock.rs b/crates/eucalyptus-editor/src/editor/dock.rs
index e52b57e..270d112 100644
--- a/crates/eucalyptus-editor/src/editor/dock.rs
+++ b/crates/eucalyptus-editor/src/editor/dock.rs
@@ -1,7 +1,7 @@
 use super::*;
 use crate::editor::ViewportMode;
 use std::hash::Hasher;
-use std::{any::TypeId, collections::HashMap, hash::Hash, path::PathBuf, sync::LazyLock};
+use std::{collections::HashMap, hash::Hash, path::PathBuf, sync::LazyLock};
 use crate::editor::console::EucalyptusConsole;
 use crate::plugin::PluginRegistry;
 use dropbear_engine::entity::{EntityTransform, Transform};
@@ -169,7 +169,7 @@ impl EditorTabRegistry {
         D: EditorTabDock + Send + Sync + 'static,
     {
         let desc = D::desc();
-        let id = Self::id_for_type::<D>();
+        let id = Self::id_for_desc(&desc);
 
         self.title_to_id.insert(desc.title.to_string(), id);
         self.descriptors.insert(id, desc);
@@ -200,13 +200,9 @@ impl EditorTabRegistry {
         true
     }
 
-    fn id_for_type<T: 'static>() -> EditorTabId {
-        Self::numeric_id(TypeId::of::<T>())
-    }
-
-    fn numeric_id(type_id: TypeId) -> EditorTabId {
+    fn id_for_desc(desc: &EditorTabDockDescriptor) -> EditorTabId {
         let mut hasher = std::collections::hash_map::DefaultHasher::new();
-        type_id.hash(&mut hasher);
+        desc.id.hash(&mut hasher);
         Self::normalize_id(hasher.finish())
     }
 
@@ -227,6 +223,7 @@ impl Default for EditorTabRegistry {
 
 
 pub struct EditorTabDockDescriptor {
+    pub id: &'static str,
     pub title: String,
 }
 
@@ -348,6 +345,7 @@ pub struct ConsoleDock;
 impl EditorTabDock for ConsoleDock {
     fn desc() -> EditorTabDockDescriptor {
         EditorTabDockDescriptor {
+            id: "console",
             title: "Console".to_string(),
         }
     }
diff --git a/crates/eucalyptus-editor/src/editor/entity_list.rs b/crates/eucalyptus-editor/src/editor/entity_list.rs
index 9466d4d..e1ea33c 100644
--- a/crates/eucalyptus-editor/src/editor/entity_list.rs
+++ b/crates/eucalyptus-editor/src/editor/entity_list.rs
@@ -209,8 +209,7 @@ pub struct EntityListDock;
 
 impl EditorTabDock for EntityListDock {
     fn desc() -> EditorTabDockDescriptor {
-        EditorTabDockDescriptor {
-            title: "Model/Entity List".to_string(),
+        EditorTabDockDescriptor {            id: "entity_list",            title: "Model/Entity List".to_string(),
         }
     }
 
diff --git a/crates/eucalyptus-editor/src/editor/resource.rs b/crates/eucalyptus-editor/src/editor/resource.rs
index fcb8234..f77fafb 100644
--- a/crates/eucalyptus-editor/src/editor/resource.rs
+++ b/crates/eucalyptus-editor/src/editor/resource.rs
@@ -89,8 +89,7 @@ pub struct ResourceInspectorDock;
 
 impl EditorTabDock for ResourceInspectorDock {
     fn desc() -> EditorTabDockDescriptor {
-        EditorTabDockDescriptor {
-            title: "Resource Inspector".to_string(),
+        EditorTabDockDescriptor {            id: "inspector",            title: "Resource Inspector".to_string(),
         }
     }
 
diff --git a/crates/eucalyptus-editor/src/editor/scene.rs b/crates/eucalyptus-editor/src/editor/scene.rs
index c5cef9a..e48c243 100644
--- a/crates/eucalyptus-editor/src/editor/scene.rs
+++ b/crates/eucalyptus-editor/src/editor/scene.rs
@@ -333,6 +333,7 @@ impl Scene for Editor {
         log_once::debug_once!("Pipeline ready");
 
         {
+            puffin::profile_scope!("Clearing viewport");
             let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                 label: Some("viewport clear pass"),
                 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
@@ -367,6 +368,7 @@ impl Scene for Editor {
         }
 
         let lights = {
+            puffin::profile_scope!("Locating lights");
             let mut lights = Vec::new();
             let mut query = self.world.query::<&Light>();
             for light in query.iter() {
@@ -376,6 +378,7 @@ impl Scene for Editor {
         };
 
         if let Some(globals) = &mut self.shader_globals {
+            puffin::profile_scope!("Fetching globals");
             let enabled_count = lights
                 .iter()
                 .filter(|light| light.component.enabled)
@@ -388,6 +391,7 @@ impl Scene for Editor {
         let mut animated_instances: Vec<(u64, InstanceRaw, wgpu::Buffer)> = Vec::new();
 
         {
+            puffin::profile_scope!("Locating all renderers and animation components");
             let mut query = self
                 .world
                 .query::<(&MeshRenderer, Option<&AnimationComponent>)>();
@@ -410,6 +414,7 @@ impl Scene for Editor {
         let registry = ASSET_REGISTRY.read();
         let mut prepared_models = Vec::new();
         for (handle, instances) in static_batches {
+            puffin::profile_scope!("preparing models");
             let Some(model) = registry.get_model(Handle::new(handle)) else {
                 log_once::error_once!("Missing model handle {} in registry", handle);
                 continue;
@@ -429,6 +434,7 @@ impl Scene for Editor {
         }
 
         {
+            puffin::profile_scope!("light cube render pass");
             let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                 label: Some("light cube render pass"),
                 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
@@ -519,6 +525,7 @@ impl Scene for Editor {
         let scene_globals_bind_group = self.scene_globals_bind_group.as_ref().unwrap();
         
         if let Some(lcp) = &self.light_cube_pipeline {
+            puffin::profile_scope!("model render pass");
             for (model, handle, instance_count) in prepared_models {
                 let light_skin_bind_group =
                     graphics
@@ -578,6 +585,7 @@ impl Scene for Editor {
         }
 
         if let Some(lcp) = &self.light_cube_pipeline {
+            puffin::profile_scope!("animated model render pass");
             for (handle, instance, skin_buffer) in animated_instances {
                 let Some(model) = registry.get_model(Handle::new(handle)) else {
                     log_once::error_once!("Missing model handle {} in registry", handle);
@@ -649,6 +657,7 @@ impl Scene for Editor {
         }
 
         if let Some(sky) = &self.sky_pipeline {
+            puffin::profile_scope!("sky render pass");
             let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                 label: Some("sky render pass"),
                 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
@@ -693,6 +702,7 @@ impl Scene for Editor {
                 .unwrap_or(false);
 
             if show_hitboxes {
+                puffin::profile_scope!("collider wireframe pipeline");
                 if let Some(collider_pipeline) = &self.collider_wireframe_pipeline {
                     log_once::debug_once!("Found collider wireframe pipeline");
                     let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
diff --git a/crates/eucalyptus-editor/src/editor/viewport.rs b/crates/eucalyptus-editor/src/editor/viewport.rs
index c12f82c..6c02e31 100644
--- a/crates/eucalyptus-editor/src/editor/viewport.rs
+++ b/crates/eucalyptus-editor/src/editor/viewport.rs
@@ -268,6 +268,7 @@ pub struct ViewportDock;
 impl EditorTabDock for ViewportDock {
     fn desc() -> EditorTabDockDescriptor {
         EditorTabDockDescriptor {
+            id: "viewport",
             title: "Viewport".to_string(),
         }
     }