diff --git a/demo-player/src/main.rs b/demo-player/src/main.rs index 2eedf11e..6edfb1b2 100644 --- a/demo-player/src/main.rs +++ b/demo-player/src/main.rs @@ -1,4 +1,3 @@ -use std::fs::read_to_string; use std::{env, path, time::Instant}; use dotlottie_player_core::{Config, DotLottiePlayer, Mode}; @@ -46,9 +45,9 @@ fn main() { path.push("src/cartoon.json"); let mut lottie_player: DotLottiePlayer = DotLottiePlayer::new(Config { - mode: Mode::Reverse, + mode: Mode::ReverseBounce, loop_animation: true, - speed: 2.5, + speed: 1.0, use_frame_interpolation: true, autoplay: true, }); diff --git a/dotlottie-ffi/src/dotlottie_player.udl b/dotlottie-ffi/src/dotlottie_player.udl index 330d2048..a7aa1ed6 100644 --- a/dotlottie-ffi/src/dotlottie_player.udl +++ b/dotlottie-ffi/src/dotlottie_player.udl @@ -4,10 +4,15 @@ namespace dotlottie_player { enum Mode { "Forward", "Reverse", - "Bounce", + "ForwardBounce", "ReverseBounce" }; +enum Direction { + "Forward", + "Reverse" +}; + dictionary Config { boolean autoplay; boolean loop_animation; @@ -40,4 +45,5 @@ interface DotLottiePlayer { boolean render(); boolean resize(u32 width, u32 height); void clear(); + Direction direction(); }; \ No newline at end of file diff --git a/dotlottie-rs/src/dotlottie_player.rs b/dotlottie-rs/src/dotlottie_player.rs index a04e3062..c91f96ed 100644 --- a/dotlottie-rs/src/dotlottie_player.rs +++ b/dotlottie-rs/src/dotlottie_player.rs @@ -1,6 +1,6 @@ use std::{sync::RwLock, time::SystemTime}; -use crate::LottieRenderer; +use crate::lottie_renderer::{LottieRenderer, LottieRendererError}; pub enum PlaybackState { Playing, @@ -12,10 +12,16 @@ pub enum PlaybackState { pub enum Mode { Forward, Reverse, - Bounce, + ForwardBounce, ReverseBounce, } +#[derive(PartialEq, Clone, Copy)] +pub enum Direction { + Forward, + Reverse, +} + #[derive(Clone, Copy)] pub struct Config { pub mode: Mode, @@ -32,10 +38,18 @@ struct DotLottieRuntime { start_time: SystemTime, loop_count: u32, config: Config, + direction: Direction, } impl DotLottieRuntime { pub fn new(config: Config) -> Self { + let direction = match config.mode { + Mode::Forward => Direction::Forward, + Mode::Reverse => Direction::Reverse, + Mode::ForwardBounce => Direction::Forward, + Mode::ReverseBounce => Direction::Reverse, + }; + DotLottieRuntime { renderer: LottieRenderer::new(), playback_state: PlaybackState::Stopped, @@ -43,9 +57,14 @@ impl DotLottieRuntime { start_time: SystemTime::now(), loop_count: 0, config, + direction, } } + pub fn direction(&self) -> Direction { + self.direction + } + pub fn is_loaded(&self) -> bool { self.is_loaded } @@ -94,14 +113,16 @@ impl DotLottieRuntime { pub fn stop(&mut self) -> bool { if self.is_loaded { self.playback_state = PlaybackState::Stopped; + let start_frame = 0_f32; + let end_frame = self.total_frames() - 1.0; + match self.config.mode { - Mode::Forward => { - self.set_frame(0_f32); + Mode::Forward | Mode::ForwardBounce => { + self.set_frame(start_frame); } - Mode::Reverse => { - self.set_frame(self.total_frames()); + Mode::Reverse | Mode::ReverseBounce => { + self.set_frame(end_frame); } - _ => {} } true @@ -133,10 +154,10 @@ impl DotLottieRuntime { raw_next_frame.round() }; - let next_frame = match self.config.mode { - Mode::Forward => next_frame, - Mode::Reverse => total_frames - next_frame, - _ => next_frame, + // update the next frame based on the direction + let next_frame = match self.direction { + Direction::Forward => next_frame, + Direction::Reverse => total_frames - next_frame, }; let next_frame = match self.config.mode { @@ -166,7 +187,54 @@ impl DotLottieRuntime { next_frame } } - _ => next_frame, + Mode::ForwardBounce => match self.direction { + Direction::Forward => { + if next_frame >= total_frames { + self.direction = Direction::Reverse; + self.start_time = SystemTime::now(); + total_frames + } else { + next_frame + } + } + Direction::Reverse => { + if next_frame <= 0.0 { + if self.config.loop_animation { + self.loop_count += 1; + self.direction = Direction::Forward; + self.start_time = SystemTime::now(); + } + + 0.0 + } else { + next_frame + } + } + }, + Mode::ReverseBounce => match self.direction { + Direction::Reverse => { + if next_frame <= 0.0 { + self.direction = Direction::Forward; + self.start_time = SystemTime::now(); + 0.0 + } else { + next_frame + } + } + Direction::Forward => { + if next_frame >= total_frames { + if self.config.loop_animation { + self.loop_count += 1; + self.direction = Direction::Reverse; + self.start_time = SystemTime::now(); + } + + total_frames + } else { + next_frame + } + } + }, }; next_frame @@ -216,58 +284,48 @@ impl DotLottieRuntime { self.config = config; } - pub fn load_animation_path(&mut self, animation_path: &str, width: u32, height: u32) -> bool { - let loaded = self - .renderer - .load_path(animation_path, width, height) - .is_ok(); - + fn load_animation_common(&mut self, loader: F, width: u32, height: u32) -> bool + where + F: FnOnce(&mut LottieRenderer, u32, u32) -> Result<(), LottieRendererError>, + { + let loaded = loader(&mut self.renderer, width, height).is_ok(); self.is_loaded = loaded; - let total_frames = self.total_frames(); + let first_frame = 0_f32; + let end_frame = self.total_frames() - 1.0; match self.config.mode { - Mode::Forward => { - self.set_frame(0_f32); + Mode::Forward | Mode::ForwardBounce => { + self.set_frame(first_frame); + self.direction = Direction::Forward; } - Mode::Reverse => { - self.set_frame(total_frames); + Mode::Reverse | Mode::ReverseBounce => { + self.set_frame(end_frame); + self.direction = Direction::Reverse; } - _ => {} } if self.config.autoplay && loaded { - return self.play(); + self.play(); } loaded } pub fn load_animation_data(&mut self, animation_data: &str, width: u32, height: u32) -> bool { - let loaded = self - .renderer - .load_data(animation_data, width, height, false) - .is_ok(); - - self.is_loaded = loaded; - - let total_frames = self.total_frames(); - - match self.config.mode { - Mode::Forward => { - self.set_frame(0_f32); - } - Mode::Reverse => { - self.set_frame(total_frames); - } - _ => {} - } - - if self.config.autoplay && loaded { - return self.play(); - } + self.load_animation_common( + |renderer, w, h| renderer.load_data(animation_data, w, h, false), + width, + height, + ) + } - loaded + pub fn load_animation_path(&mut self, animation_path: &str, width: u32, height: u32) -> bool { + self.load_animation_common( + |renderer, w, h| renderer.load_path(animation_path, w, h), + width, + height, + ) } pub fn resize(&mut self, width: u32, height: u32) -> bool { @@ -391,6 +449,10 @@ impl DotLottiePlayer { pub fn config(&self) -> Config { self.runtime.read().unwrap().config() } + + pub fn direction(&self) -> Direction { + self.runtime.read().unwrap().direction() + } } unsafe impl Send for DotLottiePlayer {} diff --git a/dotlottie-rs/src/main.rs b/dotlottie-rs/src/main.rs deleted file mode 100644 index c1146193..00000000 --- a/dotlottie-rs/src/main.rs +++ /dev/null @@ -1,13 +0,0 @@ -use dotlottie_player_core::LottieRenderer; - -fn main() { - let mut renderer = LottieRenderer::new(); - - let lottie_data = include_str!("./lottie_renderer/fixtures/lottie.json"); - - println!("Loading data..."); - - let result = renderer.load_data(lottie_data, 200, 200, true); - - println!("Result: {:?}", result); -}