diff --git a/demo/src/main.rs b/demo/src/main.rs index b6a7794..d971d91 100644 --- a/demo/src/main.rs +++ b/demo/src/main.rs @@ -189,7 +189,7 @@ fn ui( ui.separator(); ui.heading("Player Operations"); - ui.label("Note: Player operations apply to ALL states!"); + ui.label("Note: Player operations only affect current playback!"); ui.horizontal(|ui| { ui.label("Set Speed"); let mut speed = playback_settings.speed; @@ -207,22 +207,6 @@ fn ui( player.set_intermission(intermission); }; }); - ui.horizontal(|ui| { - ui.label("Set Loop Behavior"); - let looping = playback_settings.looping; - if ui - .radio(looping == AnimationLoopBehavior::None, "None") - .clicked() - { - player.set_loop_behavior(AnimationLoopBehavior::None); - } - if ui - .radio(looping == AnimationLoopBehavior::Loop, "Loop") - .clicked() - { - player.set_loop_behavior(AnimationLoopBehavior::Loop); - } - }); ui.separator(); diff --git a/src/lib.rs b/src/lib.rs index 558f91f..0795142 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,9 +29,7 @@ pub use assets::{ }; pub use font::VelloFontLoader; pub use lottie_player::{AnimationState, AnimationTransition, LottiePlayer}; -pub use playback_settings::{ - AnimationDirection, AnimationLoopBehavior, AnimationPlayMode, PlaybackSettings, -}; +pub use playback_settings::{AnimationDirection, AnimationLoopBehavior, PlaybackSettings}; pub use plugin::VelloPlugin; pub use rendertarget::VelloCanvasMaterial; pub use theme::Theme; diff --git a/src/lottie_player.rs b/src/lottie_player.rs index 1f2a50a..815267d 100644 --- a/src/lottie_player.rs +++ b/src/lottie_player.rs @@ -1,4 +1,4 @@ -use crate::{playback_settings::AnimationLoopBehavior, PlaybackSettings, Theme, VelloAsset}; +use crate::{PlaybackSettings, Theme, VelloAsset}; use bevy::{prelude::*, utils::hashbrown::HashMap}; /// A lottie player that closely mirrors the behavior and functionality for dotLottie Interactivity. @@ -18,8 +18,6 @@ pub struct LottiePlayer { pending_seek_frame: Option, /// A pending intermission to change to. pending_intermission: Option, - /// A pending loop behavior to change to. - pending_loop_behavior: Option, /// A pending speed to change to. pending_speed: Option, /// Whether the player has started. @@ -31,19 +29,26 @@ pub struct LottiePlayer { } impl LottiePlayer { - /// The current state. + /// Retrieve an immutable reference to the current state. pub fn state(&self) -> &AnimationState { self.states .get(self.current_state) .unwrap_or_else(|| panic!("state not found: '{}'", self.current_state)) } - /// The states in the player + /// Retrieve a mutable reference to the current state. + pub fn state_mut(&mut self) -> &mut AnimationState { + self.states + .get_mut(self.current_state) + .unwrap_or_else(|| panic!("state not found: '{}'", self.current_state)) + } + + /// Returns an immutable iterator of the states for this player. pub fn states(&self) -> impl Iterator { self.states.values() } - /// The states in the player + /// Returns a mutable iterator of the states for this player. pub fn states_mut(&mut self) -> impl Iterator { self.states.values_mut() } @@ -64,17 +69,11 @@ impl LottiePlayer { self.pending_seek_frame = Some(frame); } - /// Sets the pause between loops. Applies to all animations. + /// Sets the pause between loops. Applies only to the current playback, not any underlying states. pub fn set_intermission(&mut self, intermission: f32) { self.pending_intermission = Some(intermission); } - - /// Sets the loop behavior. Applies to all animations. - pub fn set_loop_behavior(&mut self, loop_behavior: AnimationLoopBehavior) { - self.pending_loop_behavior = Some(loop_behavior); - } - - /// Sets the animation speed. Applies to all animations. + /// Sets the animation speed. Applies only to the current playback, not any underlying states. pub fn set_speed(&mut self, speed: f32) { self.pending_speed = Some(speed); } @@ -121,7 +120,6 @@ impl LottiePlayer { next_state: Some(initial_state), pending_seek_frame: None, pending_intermission: None, - pending_loop_behavior: None, pending_speed: None, states: HashMap::new(), started: false, @@ -266,7 +264,6 @@ pub mod systems { }; if let Some(intermission) = player.pending_intermission.take() { - debug!("changed intermission: {intermission}"); // This math is particularly hairy. Several things are going on: // 1) Preserve the loops completed thus far // 2) Do not jump frames @@ -285,35 +282,13 @@ pub mod systems { && *rendered_frames >= loops_completed * length && *rendered_frames < loops_completed * length + playback_settings.intermission; if in_intermission { - debug!("in intermission, resetting to {intermission}"); *rendered_frames = (loops_completed * (length + intermission)).prev(); } else { - debug!("not in intermission, applying delta to {intermission}"); let dt_intermission = intermission - playback_settings.intermission; let dt_frames = dt_intermission * loops_completed; - debug!("loops: {loops_completed}, dt_intermission: {dt_intermission}, dt_frames: {dt_frames}"); *rendered_frames = (*rendered_frames + dt_frames).max(0.0); } - // Apply - for playback_settings in player - .states - .values_mut() - .flat_map(|s| s.playback_settings.as_mut()) - .chain([playback_settings.as_mut()]) - { - playback_settings.intermission = intermission; - } - } - if let Some(loop_behavior) = player.pending_loop_behavior.take() { - // Apply - for playback_settings in player - .states - .values_mut() - .flat_map(|s| s.playback_settings.as_mut()) - .chain([playback_settings.as_mut()]) - { - playback_settings.looping = loop_behavior; - } + playback_settings.intermission = intermission; } if let Some(seek_frame) = player.pending_seek_frame.take() { let start_frame = playback_settings @@ -321,12 +296,10 @@ pub mod systems { .start .max(composition.frames.start); let end_frame = playback_settings.segments.end.min(composition.frames.end); - // Bound the seek frame + let bounded_frame = seek_frame.clamp(start_frame, end_frame.prev()); let seek_frame = match playback_settings.direction { - AnimationDirection::Normal => seek_frame.clamp(start_frame, end_frame), - AnimationDirection::Reverse => { - end_frame - seek_frame.clamp(start_frame, end_frame) - } + AnimationDirection::Normal => bounded_frame, + AnimationDirection::Reverse => end_frame - bounded_frame, }; // Preserve the current number of loops when seeking. let length = end_frame - start_frame + playback_settings.intermission; @@ -334,41 +307,24 @@ pub mod systems { *rendered_frames = loops_completed * length + seek_frame; } if let Some(speed) = player.pending_speed.take() { - // Apply - for playback_settings in player - .states - .values_mut() - .flat_map(|s| s.playback_settings.as_mut()) - .chain([playback_settings.as_mut()]) - { - playback_settings.speed = speed; - error!("{}", playback_settings.speed); - } + playback_settings.speed = speed; } } } /// Advance all the playheads in the scene pub fn advance_playheads( - mut query: Query<(&mut LottiePlayer, &PlaybackSettings, &Handle)>, + mut query: Query<( + &Handle, + Option<&mut LottiePlayer>, + Option<&PlaybackSettings>, + )>, mut assets: ResMut>, time: Res