diff --git a/studio/src/anim/camera.rs b/studio/src/anim/camera.rs deleted file mode 100644 index 9fff519..0000000 --- a/studio/src/anim/camera.rs +++ /dev/null @@ -1,208 +0,0 @@ -use bevy::prelude::*; -use itertools::Itertools; -use space_editor::space_prefab::editor_registry::EditorRegistryExt; - -use crate::math::{InvLerp, Lerp}; - -use super::timeline_animation::GlobalSeekTime; - -pub struct CameraAnimPlugin; -impl Plugin for CameraAnimPlugin { - fn build(&self, app: &mut App) { - app.register_type::() - .editor_registry::() - .register_type::() - .editor_registry::(); - - app.add_systems(Update, draw_camera_keyframes); - - #[cfg(feature = "wasm")] - app.add_systems( - Update, - ( - wasm::spawn_camera_keyframes, - wasm::notify_keyframe_changes.map(bevy::utils::error), - wasm::process_update_keyframe, - ), - ); - } -} - -#[derive(Component, Clone, Copy, Debug, Default, Deref, DerefMut, Reflect)] -#[reflect(Component)] -pub struct CameraKeyframe(pub f32); - -#[derive(Component, Clone, Copy, Debug, Default, Deref, DerefMut, Reflect)] -#[reflect(Component)] -pub struct CameraTargetKeyframe(pub f32); - -fn draw_camera_keyframes( - mut gizmos: Gizmos, - r_seek_time: Res, - q_cam_keyframe_xforms: Query<&GlobalTransform, With>, - q_cam_target_keyframe_xforms: Query<&GlobalTransform, With>, - q_cam_keyframes: Query<(&CameraKeyframe, &GlobalTransform)>, -) { - if q_cam_keyframes.is_empty() { - return; - } - - for world_xform in q_cam_keyframe_xforms - .iter() - .chain(q_cam_target_keyframe_xforms.iter()) - { - let origin = world_xform.translation(); - let x_axis = world_xform.right() * 0.25; - let y_axis = world_xform.up() * 0.25; - let z_axis = world_xform.back() * 0.25; - - gizmos.line(origin, origin + x_axis, Color::RED); - gizmos.line(origin, origin + y_axis, Color::GREEN); - gizmos.line(origin, origin + z_axis, Color::BLUE); - } - - let seek_time = r_seek_time.time; - let keyframes_sorted = q_cam_keyframes - .iter() - .sorted_by(|(a, _), (b, _)| a.partial_cmp(&b.0).unwrap()) - .collect_vec(); - - let (timestamp_first, xform_first) = keyframes_sorted.first().unwrap(); - let (timestamp_last, xform_last) = keyframes_sorted.last().unwrap(); - - if seek_time <= timestamp_first.0 { - let (_, rot, pos) = xform_first.to_scale_rotation_translation(); - gizmos.sphere(pos, rot, 0.25, Color::WHITE); - } else if seek_time >= timestamp_last.0 { - let (_, rot, pos) = xform_last.to_scale_rotation_translation(); - gizmos.sphere(pos, rot, 0.25, Color::WHITE); - } else if let Some(((timestamp_a, xform_a), (timestamp_b, xform_b))) = keyframes_sorted - .iter() - .tuple_windows() - .find(|((a, _), (b, _))| a.0 <= seek_time && b.0 >= seek_time) - { - let t = seek_time.inv_lerp(timestamp_a.0, timestamp_b.0); - let (_, rot_a, pos_a) = xform_a.to_scale_rotation_translation(); - let (_, rot_b, pos_b) = xform_b.to_scale_rotation_translation(); - let pos = t.lerp(pos_a, pos_b); - let rot = Quat::slerp(rot_a, rot_b, t); - - gizmos.sphere(pos, rot, 0.25, Color::WHITE); - } -} - -#[cfg(feature = "wasm")] -mod wasm { - use std::sync::Arc; - - use bevy::{prelude::*, window::PrimaryWindow}; - use space_editor::prelude::space_undo::{self, AddedEntity}; - use wasm_bindgen::prelude::*; - - use crate::{ - camera_controller::CameraController, - wasm::{self, FromStr, StaticBuffer, WasmMessageBuffer}, - }; - - use super::{CameraKeyframe, CameraTargetKeyframe}; - - static ADD_KEYFRAME: WasmMessageBuffer = WasmMessageBuffer::new(); - static UPDATE_KEYFRAME: WasmMessageBuffer<(Entity, f32)> = WasmMessageBuffer::new(); - - #[wasm_bindgen(js_name = addCameraKeyframe)] - pub fn add_camera_keyframe(timestamp: f32) { - ADD_KEYFRAME.write_message(timestamp); - } - - pub(super) fn spawn_camera_keyframes( - mut cmd: Commands, - mut ew_changes: EventWriter, - q_camera: Query<(&CameraController, &GlobalTransform)>, - ) { - if let Some(timestamp) = ADD_KEYFRAME.take_message() { - let Ok((cam_controller, world_xform)) = q_camera.get_single() else { - return; - }; - - let entity = cmd - .spawn(( - Name::new("Camera Target Keyframe"), - TransformBundle::from_transform(Transform::from_translation( - cam_controller.focus, - )), - CameraTargetKeyframe(timestamp), - )) - .id(); - ew_changes.send(space_undo::NewChange { - change: Arc::new(AddedEntity { entity }), - }); - - let entity = cmd - .spawn(( - Name::new("Camera Keyframe"), - TransformBundle::from_transform(Transform::from(*world_xform)), - CameraKeyframe(timestamp), - )) - .id(); - ew_changes.send(space_undo::NewChange { - change: Arc::new(AddedEntity { entity }), - }); - } - } - - #[wasm_bindgen(js_name = updateKeyframe)] - pub fn update_keyframe(entity: &str, timestamp: f32) { - let entity = Entity::from_str(entity).unwrap(); - UPDATE_KEYFRAME.write_message((entity, timestamp)); - } - - pub(super) fn process_update_keyframe( - mut q_camera_keyframes: Query<&mut CameraKeyframe>, - mut q_camera_target_keyframes: Query<&mut CameraTargetKeyframe>, - ) { - if let Some((ent, timestamp)) = UPDATE_KEYFRAME.take_message() { - if let Ok(mut keyframe) = q_camera_keyframes.get_mut(ent) { - **keyframe = timestamp; - } else if let Ok(mut keyframe) = q_camera_target_keyframes.get_mut(ent) { - **keyframe = timestamp; - } else { - warn!("No matching keyframe found for entity: {ent:?}"); - } - } - } - - #[wasm_bindgen(typescript_custom_section)] - const CAMERA_KEYFRAMES_EVENT: &str = r#" -export interface CameraKeyframesEvent extends CustomEvent { - type: "camera-keyframes"; - detail: Record; -} - -declare global { - export interface GlobalEventHandlersEventMap { - "camera-keyframes": CameraKeyframesEvent; - } -} - "#; - - pub(super) fn notify_keyframe_changes( - mut l_notified: Local>, - q_keyframes: Query<(Entity, &CameraKeyframe)>, - q_window: Query<&Window, With>, - ) -> Result<(), String> { - if l_notified.len() == q_keyframes.iter().count() { - return Ok(()); - } - - let Ok(window) = q_window.get_single() else { - return Ok(()); - }; - - l_notified.clear(); - for (ent, timestamp) in q_keyframes.iter() { - l_notified.insert(format!("{ent:?}"), timestamp.0.into()); - } - - wasm::dispatch_to_js(window, "camera-keyframes", &*l_notified) - } -} diff --git a/studio/src/anim/mod.rs b/studio/src/anim/mod.rs index f246573..f655d3a 100644 --- a/studio/src/anim/mod.rs +++ b/studio/src/anim/mod.rs @@ -9,7 +9,6 @@ use space_editor::space_prefab::editor_registry::EditorRegistryExt; use crate::{hierarchy, scene::SceneElement}; pub use retargeting::*; -mod camera; mod retargeting; pub mod timeline_animation; @@ -33,7 +32,6 @@ impl Plugin for AnimPlugin { app.add_plugins(( retargeting::RetargetingPlugin, - camera::CameraAnimPlugin, timeline_animation::TimelinePlugin, )); } diff --git a/studio/src/anim/timeline_animation.rs b/studio/src/anim/timeline_animation.rs index 95dde1c..c715d37 100644 --- a/studio/src/anim/timeline_animation.rs +++ b/studio/src/anim/timeline_animation.rs @@ -52,7 +52,6 @@ impl Plugin for TimelinePlugin { timeline_bound_component_animator_system::, ), ); - app.add_systems(PostUpdate, generate_transform_animation); @@ -79,6 +78,7 @@ impl Plugin for TimelinePlugin { const MIN_KEYFRAME_DISTANCE: f32 = 0.01; +#[allow(dead_code)] #[derive(Event, Clone, Copy, Debug)] pub enum TimelineInteractionEvent { Play, @@ -86,6 +86,7 @@ pub enum TimelineInteractionEvent { Seek(f32), } +#[allow(dead_code)] #[derive(Event, Clone, Copy, Debug)] pub enum KeyframeInteractionEvent { RecordKeyframe { target: Entity }, @@ -290,8 +291,17 @@ fn process_keyframe_events( fn generate_transform_animation( mut commands: Commands, - changed: Query<&Keyframe, (With, Or<(Changed, Changed)>)>, - keyframes: Query<(&Keyframe, &Transform, &TransformKeyframe, Entity), Without>, + changed: Query< + &Keyframe, + ( + With, + Or<(Changed, Changed)>, + ), + >, + keyframes: Query< + (&Keyframe, &Transform, &TransformKeyframe, Entity), + Without, + >, removed: Query<&Keyframe, With>, ) { let changed_targets = changed @@ -495,11 +505,14 @@ mod wasm { use wasm_bindgen::prelude::*; use crate::{ - interaction::MarkedForDeletion, scene::SceneElement, wasm::{FromStr, StaticBuffer, WasmMessageBuffer} + interaction::MarkedForDeletion, + scene::SceneElement, + wasm::{FromStr, StaticBuffer, WasmMessageBuffer}, }; use super::{ - AnimationTarget, EaseType, GlobalSeekTime, Keyframe, KeyframeInteractionEvent, TimedAnimationClipAsset, TimelineInteractionEvent, TransformKeyframe + AnimationTarget, EaseType, GlobalSeekTime, Keyframe, KeyframeInteractionEvent, + TimedAnimationClipAsset, TimelineInteractionEvent, TransformKeyframe, }; static SEEK_TIME: WasmMessageBuffer = WasmMessageBuffer::new(); diff --git a/studio/src/interaction/selection.rs b/studio/src/interaction/selection.rs index 997996e..b37e881 100644 --- a/studio/src/interaction/selection.rs +++ b/studio/src/interaction/selection.rs @@ -184,10 +184,7 @@ fn process_delete_inputs( } } -fn finalize_delete( - mut cmd: Commands, - q: Query> -) { +fn finalize_delete(mut cmd: Commands, q: Query>) { for entity in &q { cmd.entity(entity).despawn_recursive(); }