kitgit

tirbofish/dropbear · diff

9115981 · Thribhu K

skinned animation officially works now (hooray!!!)

Unverified

diff --git a/crates/dropbear-engine/src/animation.rs b/crates/dropbear-engine/src/animation.rs
index de27737..70da035 100644
--- a/crates/dropbear-engine/src/animation.rs
+++ b/crates/dropbear-engine/src/animation.rs
@@ -321,7 +321,6 @@ impl AnimationComponent {
         }
     }
 
-    /// Recursively calculates and caches the global world matrix for a node.
     fn resolve_global_transform(
         &self,
         node_idx: usize,
diff --git a/crates/dropbear-engine/src/model.rs b/crates/dropbear-engine/src/model.rs
index 977d384..0b9bd26 100644
--- a/crates/dropbear-engine/src/model.rs
+++ b/crates/dropbear-engine/src/model.rs
@@ -1164,6 +1164,7 @@ pub trait DrawModel<'a> {
         model: &'a Model,
         camera_bind_group: &'a wgpu::BindGroup,
         light_bind_group: &'a wgpu::BindGroup,
+        skin_bind_group: Option<&'a wgpu::BindGroup>,
     );
     fn draw_model_instanced(
         &mut self,
@@ -1171,6 +1172,7 @@ pub trait DrawModel<'a> {
         instances: Range<u32>,
         camera_bind_group: &'a wgpu::BindGroup,
         light_bind_group: &'a wgpu::BindGroup,
+        skin_bind_group: Option<&'a wgpu::BindGroup>,
     );
 }
 
@@ -1216,8 +1218,9 @@ where
         model: &'b Model,
         camera_bind_group: &'b wgpu::BindGroup,
         light_bind_group: &'a wgpu::BindGroup,
+        skin_bind_group: Option<&'a wgpu::BindGroup>,
     ) {
-        self.draw_model_instanced(model, 0..1, camera_bind_group, light_bind_group);
+        self.draw_model_instanced(model, 0..1, camera_bind_group, light_bind_group, skin_bind_group);
     }
 
     fn draw_model_instanced(
@@ -1226,6 +1229,7 @@ where
         instances: Range<u32>,
         camera_bind_group: &'b wgpu::BindGroup,
         light_bind_group: &'a wgpu::BindGroup,
+        skin_bind_group: Option<&'a wgpu::BindGroup>,
     ) {
         for mesh in &model.meshes {
             let material = &model.materials[mesh.material];
@@ -1235,7 +1239,7 @@ where
                 instances.clone(),
                 camera_bind_group,
                 light_bind_group,
-                None, // Provide an AnimationComponent if available in a future update
+                skin_bind_group,
             );
         }
     }
diff --git a/crates/eucalyptus-editor/src/editor/scene.rs b/crates/eucalyptus-editor/src/editor/scene.rs
index 94b7231..1f47f1e 100644
--- a/crates/eucalyptus-editor/src/editor/scene.rs
+++ b/crates/eucalyptus-editor/src/editor/scene.rs
@@ -5,6 +5,7 @@ use glam::{DMat4, Mat4};
 use wgpu::util::DeviceExt;
 use std::collections::HashMap;
 use std::sync::Arc;
+use std::{fs, path::{Path, PathBuf}};
 use super::*;
 use crate::signal::SignalController;
 use crate::spawn::PendingSpawnController;
@@ -19,7 +20,7 @@ use dropbear_engine::{
 use eucalyptus_core::states::{Label, WorldLoadingStatus};
 use log;
 use parking_lot::Mutex;
-use winit::{event_loop::ActiveEventLoop, keyboard::KeyCode};
+use winit::{event::WindowEvent, event_loop::ActiveEventLoop, keyboard::KeyCode};
 use eucalyptus_core::physics::collider::ColliderGroup;
 use eucalyptus_core::physics::collider::ColliderShapeKey;
 use eucalyptus_core::physics::collider::shader::{ColliderInstanceRaw, create_wireframe_geometry};
@@ -532,17 +533,13 @@ impl Scene for Editor {
                 }
                 render_pass.set_bind_group(3, globals_bind_group, &[]);
 
-                for mesh in &model.meshes {
-                    let material = &model.materials[mesh.material];
-                    render_pass.draw_mesh_instanced(
-                        mesh,
-                        material,
-                        0..instance_count,
-                        &camera.bind_group,
-                        lcp.bind_group(),
-                        Some(default_skinning_bind_group),
-                    );
-                }
+                render_pass.draw_model_instanced(
+                    model,
+                    0..instance_count,
+                    &camera.bind_group,
+                    lcp.bind_group(),
+                    Some(default_skinning_bind_group),
+                );
             }
         }
 
@@ -599,17 +596,13 @@ impl Scene for Editor {
                 render_pass.set_vertex_buffer(1, instance_buffer.slice(1));
                 render_pass.set_bind_group(3, globals_bind_group, &[]);
 
-                for mesh in &model.meshes {
-                    let material = &model.materials[mesh.material];
-                    render_pass.draw_mesh_instanced(
-                        mesh,
-                        material,
-                        0..1,
-                        &camera.bind_group,
-                        lcp.bind_group(),
-                        Some(&skin_bind_group),
-                    );
-                }
+                render_pass.draw_model_instanced(
+                    model,
+                    0..1,
+                    &camera.bind_group,
+                    lcp.bind_group(),
+                    Some(&skin_bind_group),
+                );
             }
         }
 
@@ -798,12 +791,123 @@ impl Scene for Editor {
 
     fn exit(&mut self, _event_loop: &ActiveEventLoop) {}
 
+    fn handle_event(&mut self, event: &WindowEvent) {
+        match event {
+            WindowEvent::DroppedFile(path) => {
+                log::debug!("Dropped file: {}", path.display());
+                self.handle_file_drop(path);
+            },
+            WindowEvent::HoveredFile(path_buf) => {
+                log_once::debug_once!("Hovering file: {}", path_buf.display());
+            },
+            WindowEvent::HoveredFileCancelled => {
+                log_once::debug_once!("Hover cancelled");
+            }
+            _ => {}
+        }
+    }
+
     fn run_command(&mut self) -> SceneCommand {
         std::mem::replace(&mut self.scene_command, SceneCommand::None)
     }
 }
 
 impl Editor {
+    fn handle_file_drop(&mut self, path: &PathBuf) {
+        let project_root = { PROJECT.read().project_path.clone() };
+        if project_root.as_os_str().is_empty() {
+            log::warn!("Drop ignored: no project loaded");
+            return;
+        }
+
+        if !path.exists() {
+            log::warn!("Drop ignored: '{}' does not exist", path.display());
+            return;
+        }
+
+        if path.is_dir() {
+            log::warn!("Drop ignored: '{}' is a directory", path.display());
+            return;
+        }
+
+        let extension = path
+            .extension()
+            .and_then(|ext| ext.to_str())
+            .map(|ext| ext.to_ascii_lowercase());
+
+        let target_dir = match extension.as_deref() {
+            Some("kt") => Self::script_drop_dir(&project_root),
+            Some("eucp") | Some("eucs") => project_root.join("scenes"),
+            _ => project_root.join("resources"),
+        };
+
+        if let Err(err) = fs::create_dir_all(&target_dir) {
+            log::warn!(
+                "Drop failed: unable to create '{}' ({})",
+                target_dir.display(),
+                err
+            );
+            return;
+        }
+
+        let Some(file_name) = path.file_name() else {
+            log::warn!("Drop ignored: invalid file name for '{}'", path.display());
+            return;
+        };
+
+        let target_path = Self::unique_drop_target(&target_dir, file_name);
+        if let Err(err) = fs::copy(path, &target_path) {
+            log::warn!(
+                "Drop failed: unable to copy '{}' to '{}' ({})",
+                path.display(),
+                target_path.display(),
+                err
+            );
+        } else {
+            log::info!("Dropped asset copied to '{}'", target_path.display());
+        }
+    }
+
+    fn script_drop_dir(project_root: &Path) -> PathBuf {
+        let src_root = project_root.join("src");
+        let main_kotlin = src_root.join("main").join("kotlin");
+        if main_kotlin.exists() {
+            return main_kotlin;
+        }
+
+        if src_root.exists() {
+            return main_kotlin;
+        }
+
+        main_kotlin
+    }
+
+    fn unique_drop_target(base_dir: &Path, file_name: &std::ffi::OsStr) -> PathBuf {
+        let mut candidate = base_dir.join(file_name);
+        if !candidate.exists() {
+            return candidate;
+        }
+
+        let stem = Path::new(file_name)
+            .file_stem()
+            .and_then(|s| s.to_str())
+            .unwrap_or("file");
+        let ext = Path::new(file_name).extension().and_then(|e| e.to_str());
+
+        let mut index = 1;
+        loop {
+            let file_name = match ext {
+                Some(ext) => format!("{}-{}.{}", stem, index, ext),
+                None => format!("{}-{}", stem, index),
+            };
+            candidate = base_dir.join(file_name);
+            if !candidate.exists() {
+                return candidate;
+            }
+            index += 1;
+        }
+    }
+
     fn editor_specific_render(&mut self, graphics: &Arc<SharedGraphicsContext>) {
         self.size = graphics.viewport_texture.size;
         self.texture_id = Some(*graphics.texture_id.clone());
diff --git a/crates/redback-runtime/src/scene.rs b/crates/redback-runtime/src/scene.rs
index dcd141a..9ae847b 100644
--- a/crates/redback-runtime/src/scene.rs
+++ b/crates/redback-runtime/src/scene.rs
@@ -806,17 +806,13 @@ impl Scene for PlayMode {
                 }
                 render_pass.set_bind_group(3, globals_bind_group, &[]);
 
-                for mesh in &model.meshes {
-                    let material = &model.materials[mesh.material];
-                    render_pass.draw_mesh_instanced(
-                        mesh,
-                        material,
-                        0..instance_count,
-                        &camera.bind_group,
-                        lcp.bind_group(),
-                        Some(default_skinning_bind_group),
-                    );
-                }
+                render_pass.draw_model_instanced(
+                    model,
+                    0..instance_count,
+                    &camera.bind_group,
+                    lcp.bind_group(),
+                    Some(default_skinning_bind_group),
+                );
             }
         }
 
@@ -873,17 +869,13 @@ impl Scene for PlayMode {
                 render_pass.set_vertex_buffer(1, instance_buffer.slice(1));
                 render_pass.set_bind_group(3, globals_bind_group, &[]);
 
-                for mesh in &model.meshes {
-                    let material = &model.materials[mesh.material];
-                    render_pass.draw_mesh_instanced(
-                        mesh,
-                        material,
-                        0..1,
-                        &camera.bind_group,
-                        lcp.bind_group(),
-                        Some(&skin_bind_group),
-                    );
-                }
+                render_pass.draw_model_instanced(
+                    model,
+                    0..1,
+                    &camera.bind_group,
+                    lcp.bind_group(),
+                    Some(&skin_bind_group),
+                );
             }
         }