From 2f2df97dcc1bd4c69f01a13fcf1f03d00e881033 Mon Sep 17 00:00:00 2001 From: james7132 Date: Sun, 27 Nov 2022 23:16:34 -0800 Subject: [PATCH 1/9] Getting it working --- crates/bevy_animation/Cargo.toml | 4 + crates/bevy_animation/src/lib.rs | 284 ++++++++++++++-------- crates/bevy_ecs/src/storage/sparse_set.rs | 6 + 3 files changed, 197 insertions(+), 97 deletions(-) diff --git a/crates/bevy_animation/Cargo.toml b/crates/bevy_animation/Cargo.toml index 5079bf057b837..5d5581c2590de 100644 --- a/crates/bevy_animation/Cargo.toml +++ b/crates/bevy_animation/Cargo.toml @@ -19,4 +19,8 @@ bevy_time = { path = "../bevy_time", version = "0.9.0" } bevy_utils = { path = "../bevy_utils", version = "0.9.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.9.0" } bevy_transform = { path = "../bevy_transform", version = "0.9.0" } +bevy_tasks = { path = "../bevy_tasks", version = "0.9.0" } bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.9.0" } + +smallvec = "1.10" +thread_local = "1.1" \ No newline at end of file diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index 0ab68da7c8788..e59bcc8b65f04 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -8,8 +8,10 @@ use bevy_app::{App, CoreStage, Plugin}; use bevy_asset::{AddAsset, Assets, Handle}; use bevy_core::Name; use bevy_ecs::{ + prelude::*, change_detection::DetectChanges, entity::Entity, + storage::SparseSet, prelude::Component, reflect::ReflectComponent, schedule::IntoSystemDescriptor, @@ -21,6 +23,10 @@ use bevy_reflect::{FromReflect, Reflect, TypeUuid}; use bevy_time::Time; use bevy_transform::{prelude::Transform, TransformSystem}; use bevy_utils::{tracing::warn, HashMap}; +use bevy_tasks::{ParallelSlice, ComputeTaskPool}; +use smallvec::{smallvec, SmallVec}; +use thread_local::ThreadLocal; +use std::cell::Cell; #[allow(missing_docs)] pub mod prelude { @@ -63,17 +69,28 @@ pub struct EntityPath { #[derive(Reflect, FromReflect, Clone, TypeUuid, Debug, Default)] #[uuid = "d81b7179-0448-4eb0-89fe-c067222725bf"] pub struct AnimationClip { - curves: HashMap>, + curves: Vec>, + paths: HashMap, duration: f32, } impl AnimationClip { #[inline] /// Hashmap of the [`VariableCurve`]s per [`EntityPath`]. - pub fn curves(&self) -> &HashMap> { + pub fn curves(&self) -> &Vec> { &self.curves } + #[inline] + pub fn get_curves(&self, bone_id: usize) -> Option<&'_ Vec> { + self.curves.get(bone_id) + } + + #[inline] + pub fn get_curves_by_path(&self, path: &EntityPath) -> Option<&'_ Vec> { + self.paths.get(path).and_then(|id| self.curves.get(*id)) + } + /// Duration of the clip, represented in seconds #[inline] pub fn duration(&self) -> f32 { @@ -86,7 +103,13 @@ impl AnimationClip { self.duration = self .duration .max(*curve.keyframe_timestamps.last().unwrap_or(&0.0)); - self.curves.entry(path).or_default().push(curve); + if let Some(bone_id) = self.paths.get(&path) { + self.curves[*bone_id].push(curve); + } else { + let idx = self.curves.len(); + self.curves.push(vec![curve]); + self.paths.insert(path, idx); + } } } @@ -181,117 +204,179 @@ impl AnimationPlayer { } } -/// System that will play all animations, using any entity with a [`AnimationPlayer`] -/// and a [`Handle`] as an animation root -pub fn animation_player( +#[derive(Clone)] +pub struct BoneBinding { + root: Entity, + bone_id: usize, + elapsed: f32, +} + +#[derive(Resource, Default)] +pub struct BoneBindings { + // Entity must be globally unique. + bindings: Vec<(Entity, SmallVec<[BoneBinding; 2]>)>, +} + +fn find_bone(root: Entity, path: &EntityPath, children: &Query<&Children>, names: &Query<&Name>) -> Option { + // PERF: finding the target entity can be optimised + let mut current_entity = root; + // Ignore the first name, it is the root node which we already have + for part in path.parts.iter().skip(1) { + let mut found = false; + let children = children.get(current_entity).ok()?; + for child in children.deref() { + if let Ok(name) = names.get(*child) { + if name == part { + // Found a children with the right name, continue to the next part + current_entity = *child; + found = true; + break; + } + } + } + if !found { + warn!("Entity not found for path {:?} on part {:?}", path, part); + return None; + } + } + Some(current_entity) +} + +pub fn bind_bones( time: Res