Skip to content

Commit

Permalink
fix: bug fixes, demo updates
Browse files Browse the repository at this point in the history
  • Loading branch information
simbleau committed Jan 27, 2024
1 parent ccbc36e commit 788aa5a
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 55 deletions.
111 changes: 74 additions & 37 deletions demo/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use bevy::{asset::AssetMetaCheck, prelude::*, render::color};
use bevy::{asset::AssetMetaCheck, prelude::*};
use bevy_egui::{egui, EguiContexts, EguiPlugin};
use bevy_vello::{
debug::DebugVisualizations, AnimationDirection, AnimationLoopBehavior, AnimationState,
AnimationTransition, ColorPaletteSwap, LottiePlayer, PlaybackSettings, Vector, VelloAsset,
VelloAssetBundle, VelloPlugin, VelloText, VelloTextBundle,
debug::DebugVisualizations, vello_svg::usvg::strict_num::Ulps, AnimationDirection,
AnimationState, AnimationTransition, ColorPaletteSwap, LottiePlayer, PlaybackSettings, Vector,
VelloAsset, VelloAssetBundle, VelloPlugin, VelloText, VelloTextBundle,
};

fn main() {
Expand All @@ -25,28 +25,29 @@ fn setup_vector_graphics(mut commands: Commands, asset_server: ResMut<AssetServe
.spawn(VelloAssetBundle {
origin: bevy_vello::Origin::Center,
vector: asset_server.load("../assets/squid.json"),
transform: Transform::from_scale(Vec3::splat(0.5)),
debug_visualizations: DebugVisualizations::Visible,
..default()
})
.insert(ColorPaletteSwap::default())
.insert(
LottiePlayer::new("rev")
LottiePlayer::new("Normal")
.with_state(
AnimationState::new("rev")
.with_transition(AnimationTransition::OnMouseEnter { state: "fwd" })
AnimationState::new("Normal")
.with_playback_settings(PlaybackSettings {
speed: 0.2,
direction: AnimationDirection::Reverse,
..default()
}),
})
.with_transition(AnimationTransition::OnMouseEnter { state: "Reverse" }),
)
.with_state(
AnimationState::new("fwd")
AnimationState::new("Reverse")
.with_transition(AnimationTransition::OnMouseLeave { state: "Normal" })
.with_playback_settings(PlaybackSettings {
speed: 0.2,
direction: AnimationDirection::Reverse,
..default()
})
.with_transition(AnimationTransition::OnMouseLeave { state: "rev" }),
}),
),
);
commands.spawn(VelloTextBundle {
Expand Down Expand Up @@ -147,26 +148,49 @@ fn ui(
else {
return;
};
let window = egui::Window::new("Character Builder")
let window = egui::Window::new("Controls")
.resizable(false)
.title_bar(true)
.collapsible(true);

let asset = assets.get(handle.id()).unwrap() else {
let asset = assets.get(handle.id()).unwrap();
let metadata = asset.metadata().unwrap();
let Vector::Lottie {
composition,
first_frame: _,
rendered_frames: _,
} = &asset.data
else {
return;
};
let metadata = asset.metadata().unwrap();

window.show(contexts.ctx_mut(), |ui| {
ui.heading("Animation Controls");

let mut playhead = asset.calculate_playhead(playback_settings).unwrap();
ui.horizontal(|ui| {
ui.label("Playhead");
ui.add(egui::Slider::new(
&mut playhead,
playback_settings.segments.start..=playback_settings.segments.end,
));
if ui
.add(
egui::Slider::new(
&mut playhead,
playback_settings
.segments
.start
.max(composition.frames.start)
..=playback_settings
.segments
.end
.min(composition.frames.end)
.prev(),
)
.integer(),
)
.changed()
{
player.pause();
player.seek(playhead);
};
});

ui.horizontal_wrapped(|ui| {
Expand All @@ -189,39 +213,52 @@ fn ui(

ui.heading("States");
let mut transition = None;
for state in player.states() {
if ui.button(state.id).clicked() {
transition.replace(state.id);
ui.horizontal_wrapped(|ui| {
for state in player.states() {
if ui.button(state.id).clicked() {
transition.replace(state.id);
}
}
}
});
if let Some(transition) = transition {
player.transition(transition);
}

ui.separator();

ui.heading("State");
ui.heading("Current State");
ui.label(format!("Autplay: {}", playback_settings.autoplay));
ui.label(format!("Diration: {:?}", playback_settings.direction));
ui.label(format!("Intermission: {}", playback_settings.intermission));
ui.label(format!("Loops: {:?}", playback_settings.looping));
ui.label(format!("Play mode: {:?}", playback_settings.play_mode));
ui.label(format!("Segments: {:?}", playback_settings.segments));
ui.label(format!("Speed: {}", playback_settings.speed));

ui.collapsing(
format!("Transitions: {}", player.state().transitions.len()),
|ui| {
for transition in player.state().transitions.iter() {
ui.label(format!("{transition:?}"));
}
},
);
ui.separator();

ui.heading("Color Remapping");
for layer in metadata.get_layers() {
let color = color_swaps.get_mut(layer).cloned().unwrap_or_default();
let mut color_edit = [color.r(), color.g(), color.b()];
ui.horizontal(|ui| {
if ui.color_edit_button_rgb(&mut color_edit).changed() {
let [r, g, b] = color_edit;
color_swaps.edit(layer, Color::rgb(r, g, b));
};
ui.label(layer);
});
}
ui.collapsing("Color Remapping", |ui| {
for layer in metadata.get_layers() {
let color = color_swaps.get_mut(layer).cloned().unwrap_or_default();
let mut color_edit = [color.r(), color.g(), color.b(), color.a()];
ui.horizontal(|ui| {
if ui
.color_edit_button_rgba_unmultiplied(&mut color_edit)
.changed()
{
let [r, g, b, a] = color_edit;
color_swaps.edit(layer, Color::rgba(r, g, b, a));
};
ui.label(layer);
});
}
});
});
}
50 changes: 32 additions & 18 deletions src/animation_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ use crate::{
AnimationDirection, PlaybackSettings, VelloAsset,
};
use bevy::{prelude::*, utils::hashbrown::HashMap};
use vello_svg::usvg::strict_num::Ulps;
use vellottie::Composition;

#[derive(Component, Default, Debug)]
pub struct LottiePlayer {
Expand Down Expand Up @@ -110,6 +108,18 @@ impl LottiePlayer {
pub fn stop(&mut self) {
self.stopped = true;
}

pub fn is_playing(&self) -> bool {
self.playing
}

pub fn is_paused(&self) -> bool {
self.stopped || !self.playing
}

pub fn is_stopped(&self) -> bool {
self.stopped
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -216,7 +226,7 @@ pub struct AnimationControllerPlugin;
impl Plugin for AnimationControllerPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(
Update,
PostUpdate,
(
systems::apply_player_inputs,
systems::advance_playheads,
Expand Down Expand Up @@ -257,7 +267,7 @@ pub mod systems {
continue;
};

if let Some(direction) = player.pending_direction {
if let Some(direction) = player.pending_direction.take() {
for playback_settings in player
.states
.values_mut()
Expand All @@ -267,7 +277,7 @@ pub mod systems {
playback_settings.direction = direction;
}
}
if let Some(intermission) = player.pending_intermission {
if let Some(intermission) = player.pending_intermission.take() {
// Adjust to the new intermission
let loops_played = *rendered_frames
/ (composition.frames.end - composition.frames.start
Expand All @@ -285,7 +295,7 @@ pub mod systems {
playback_settings.intermission = intermission;
}
}
if let Some(loop_behavior) = player.pending_loop_behavior {
if let Some(loop_behavior) = player.pending_loop_behavior.take() {
// Apply
for playback_settings in player
.states
Expand All @@ -296,7 +306,7 @@ pub mod systems {
playback_settings.looping = loop_behavior;
}
}
if let Some(play_mode) = player.pending_play_mode {
if let Some(play_mode) = player.pending_play_mode.take() {
// Apply
for playback_settings in player
.states
Expand All @@ -307,19 +317,23 @@ pub mod systems {
playback_settings.play_mode = play_mode;
}
}
if let Some(seek_frame) = player.pending_seek_frame {
if let Some(seek_frame) = player.pending_seek_frame.take() {
let start_frame = playback_settings
.segments
.start
.max(composition.frames.start);
let end_frame = playback_settings.segments.end.min(composition.frames.end);
// FIXME: This should keep the correct number of loops. This resets the loops played!
// Bound the seek frame
let seek_frame = seek_frame.clamp(composition.frames.start, composition.frames.end);
// Get the frame local to this loop
let local_frame = *rendered_frames
% (composition.frames.end - composition.frames.start
+ playback_settings.intermission);
// Bound the seek frame within the composition
let local_seek_frame =
seek_frame % (composition.frames.end - composition.frames.start);
*rendered_frames = *rendered_frames - local_frame + local_seek_frame;
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)
}
};
*rendered_frames = seek_frame;
}
if let Some(speed) = player.pending_speed {
if let Some(speed) = player.pending_speed.take() {
// Apply
for playback_settings in player
.states
Expand Down

0 comments on commit 788aa5a

Please sign in to comment.