From 55cd8db332f5c143d788e7cc72aee17dfde7a5fe Mon Sep 17 00:00:00 2001 From: "Spencer C. Imbleau" Date: Wed, 31 Jan 2024 21:32:08 -0500 Subject: [PATCH] build: prep for release --- CHANGELOG.md | 3 +- Cargo.toml | 3 +- demo/src/main.rs | 45 ++---------- src/assets/mod.rs | 2 +- src/assets/parser.rs | 6 +- src/assets/vector.rs | 9 +-- src/lib.rs | 14 ++-- ...imation_controller.rs => lottie_player.rs} | 71 +++++-------------- src/plugin.rs | 2 +- src/renderer/extract.rs | 8 +-- src/renderer/render.rs | 6 +- src/rendertarget.rs | 1 - src/{color_swapping.rs => theme.rs} | 11 +-- 13 files changed, 57 insertions(+), 124 deletions(-) rename src/{animation_controller.rs => lottie_player.rs} (90%) rename src/{color_swapping.rs => theme.rs} (95%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eadde9..1961fd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,13 @@ Subheadings to categorize changes are `added, changed, deprecated, removed, fixe ### added -- State machines are now available behind the `animation-controller` cargo feature +- State machines are now available behind the `player` cargo feature - `PlaybackSettings` can now be bundled with `VelloAssetBundle` to augment playback ### changed - `RenderMode` changed to `CoordinateSpace` +- `Vector` has been renamed to `VelloAssetData` - `VelloVector`, anywhere mentioned, has changed to `VelloAsset` - `DebugVisualizations` are now feature-gated behind the `debug` cargo feature - Color swapping now swaps by layer name only and applies to more cases (animated, gradients, etc.) diff --git a/Cargo.toml b/Cargo.toml index a41ba74..04163a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,9 +37,8 @@ repository.workspace = true [lib] [features] -default = ["animation-controller", "debug"] +default = ["debug"] debug = ["bevy/bevy_gizmos"] -animation-controller = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/demo/src/main.rs b/demo/src/main.rs index f0f2a53..6233505 100644 --- a/demo/src/main.rs +++ b/demo/src/main.rs @@ -1,13 +1,12 @@ use bevy::{asset::AssetMetaCheck, log::LogPlugin, prelude::*}; use bevy_egui::{ - egui::{self, Color32}, + egui::{self}, EguiContexts, EguiPlugin, }; use bevy_vello::{ debug::DebugVisualizations, vello_svg::usvg::strict_num::Ulps, AnimationDirection, - AnimationLoopBehavior, AnimationPlayMode, AnimationState, AnimationTransition, - ColorPaletteSwap, LottiePlayer, PlaybackSettings, Vector, VelloAsset, VelloAssetBundle, - VelloPlugin, VelloText, VelloTextBundle, + AnimationLoopBehavior, AnimationState, AnimationTransition, LottiePlayer, PlaybackSettings, + Theme, VelloAsset, VelloAssetBundle, VelloAssetData, VelloPlugin, VelloText, VelloTextBundle, }; fn main() { @@ -44,7 +43,7 @@ fn setup_vector_graphics(mut commands: Commands, asset_server: ResMut, )>, assets: Res>, @@ -128,7 +127,7 @@ fn ui( let asset = assets.get(handle.id()).unwrap(); let metadata = asset.metadata().unwrap(); - let Vector::Lottie { + let VelloAssetData::Lottie { composition, first_frame: _, rendered_frames: _, @@ -209,22 +208,6 @@ fn ui( player.set_intermission(intermission); }; }); - ui.horizontal(|ui| { - ui.colored_label(Color32::YELLOW, "Set Direction"); - let direction = playback_settings.direction; - if ui - .radio(direction == AnimationDirection::Normal, "Normal") - .clicked() - { - player.set_direction(AnimationDirection::Normal); - } - if ui - .radio(direction == AnimationDirection::Reverse, "Reverse") - .clicked() - { - player.set_direction(AnimationDirection::Reverse); - } - }); ui.horizontal(|ui| { ui.label("Set Loop Behavior"); let looping = playback_settings.looping; @@ -241,22 +224,6 @@ fn ui( player.set_loop_behavior(AnimationLoopBehavior::Loop); } }); - ui.horizontal(|ui| { - ui.colored_label(Color32::RED, "Set Play Mode"); - let playmode = playback_settings.play_mode; - if ui - .radio(playmode == AnimationPlayMode::Normal, "Normal") - .clicked() - { - player.set_play_mode(AnimationPlayMode::Normal); - } - if ui - .radio(playmode == AnimationPlayMode::Bounce, "Bounce") - .clicked() - { - player.set_play_mode(AnimationPlayMode::Bounce); - } - }); ui.separator(); diff --git a/src/assets/mod.rs b/src/assets/mod.rs index e44388c..aa2fb97 100644 --- a/src/assets/mod.rs +++ b/src/assets/mod.rs @@ -4,8 +4,8 @@ mod parser; pub(crate) mod vector; pub use asset_loader::VelloAssetLoader; -pub use vector::Vector; pub use vector::VelloAsset; +pub use vector::VelloAssetData; pub(crate) use asset_loader::VectorLoaderError; pub use parser::*; diff --git a/src/assets/parser.rs b/src/assets/parser.rs index f788cfa..434b365 100644 --- a/src/assets/parser.rs +++ b/src/assets/parser.rs @@ -1,5 +1,5 @@ use super::asset_loader::VectorLoaderError; -use crate::{assets::vector::Vector, VelloAsset}; +use crate::{assets::vector::VelloAssetData, VelloAsset}; use bevy::prelude::*; use std::sync::Arc; use vello::{SceneBuilder, SceneFragment}; @@ -20,7 +20,7 @@ pub fn load_svg_from_bytes(bytes: &[u8]) -> Result Result, @@ -29,7 +29,7 @@ pub enum Vector { #[derive(Asset, TypePath, Clone)] pub struct VelloAsset { - pub data: Vector, + pub data: VelloAssetData, pub local_transform_bottom_center: Transform, pub local_transform_center: Transform, pub width: f32, @@ -77,6 +77,7 @@ impl VelloAsset { [min, x_axis, max, y_axis] } + /// Returns the 4 corner points of this vector's bounding box in screen space pub fn bb_in_screen_space(&self, transform: &GlobalTransform) -> [Vec2; 4] { let min = Vec3A::ZERO; let x_axis = Vec3A::new(self.width, 0.0, 0.0); @@ -98,7 +99,7 @@ impl VelloAsset { /// Gets the lottie metadata (if vector is a lottie), an object used for inspecting /// this vector's layers and shapes pub fn metadata(&self) -> Option { - if let Vector::Lottie { composition, .. } = &self.data { + if let VelloAssetData::Lottie { composition, .. } = &self.data { Some(Metadata { composition: composition.clone(), }) @@ -109,7 +110,7 @@ impl VelloAsset { /// Calculate the playhead. Returns `None` is the Vector is an SVG. pub fn calculate_playhead(&self, playback_settings: &PlaybackSettings) -> Option { - let Vector::Lottie { + let VelloAssetData::Lottie { composition, first_frame: _, rendered_frames, diff --git a/src/lib.rs b/src/lib.rs index e46acec..61ff2aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,16 +2,15 @@ // #![deny(missing_docs)] - TODO add before 1.0 //! An integration to render SVG and Lottie assets in Bevy with Vello. -#[cfg(feature = "animation-controller")] -mod animation_controller; mod assets; -mod color_swapping; mod font; +mod lottie_player; mod metadata; mod playback_settings; mod plugin; mod renderer; mod rendertarget; +mod theme; use bevy::prelude::*; use font::VelloFont; @@ -23,20 +22,19 @@ pub use vellottie; #[cfg(feature = "debug")] pub mod debug; -#[cfg(feature = "animation-controller")] -pub use animation_controller::{AnimationState, AnimationTransition, LottiePlayer}; pub use assets::VelloAssetLoader; pub use assets::{ - load_lottie_from_bytes, load_lottie_from_str, load_svg_from_bytes, load_svg_from_str, Vector, - VelloAsset, + load_lottie_from_bytes, load_lottie_from_str, load_svg_from_bytes, load_svg_from_str, + VelloAsset, VelloAssetData, }; -pub use color_swapping::ColorPaletteSwap; pub use font::VelloFontLoader; +pub use lottie_player::{AnimationState, AnimationTransition, LottiePlayer}; pub use playback_settings::{ AnimationDirection, AnimationLoopBehavior, AnimationPlayMode, PlaybackSettings, }; pub use plugin::VelloPlugin; pub use rendertarget::VelloCanvasMaterial; +pub use theme::Theme; #[derive(PartialEq, Eq, PartialOrd, Ord, Component, Default, Copy, Clone, Debug, Reflect)] #[reflect(Component)] diff --git a/src/animation_controller.rs b/src/lottie_player.rs similarity index 90% rename from src/animation_controller.rs rename to src/lottie_player.rs index d0618e2..22fa735 100644 --- a/src/animation_controller.rs +++ b/src/lottie_player.rs @@ -1,9 +1,13 @@ -use crate::{ - playback_settings::{AnimationLoopBehavior, AnimationPlayMode}, - AnimationDirection, PlaybackSettings, VelloAsset, -}; +use crate::{playback_settings::AnimationLoopBehavior, PlaybackSettings, VelloAsset}; use bevy::{prelude::*, utils::hashbrown::HashMap}; +/// A lottie player that closely mirrors the behavior and functionality for dotLottie Interactivity. +/// +/// See: https://docs.lottiefiles.com/dotlottie-js-external/ +/// +/// # Missing features +/// - player.set_playmode +/// - player.set_direction #[derive(Component, Default, Debug)] pub struct LottiePlayer { initial_state: &'static str, @@ -12,14 +16,10 @@ pub struct LottiePlayer { states: HashMap<&'static str, AnimationState>, /// A pending frame to seek to. pending_seek_frame: Option, - /// A pending duration to change to. - pending_direction: Option, /// A pending intermission to change to. pending_intermission: Option, /// A pending loop behavior to change to. pending_loop_behavior: Option, - /// A pending play mode to change to. - pending_play_mode: Option, /// A pending speed to change to. pending_speed: Option, /// Whether the player has started. @@ -64,11 +64,6 @@ impl LottiePlayer { self.pending_seek_frame = Some(frame); } - /// Sets the player direction. Applies to all animations. - pub fn set_direction(&mut self, direction: AnimationDirection) { - self.pending_direction = Some(direction); - } - /// Sets the pause between loops. Applies to all animations. pub fn set_intermission(&mut self, intermission: f32) { self.pending_intermission = Some(intermission); @@ -79,11 +74,6 @@ impl LottiePlayer { self.pending_loop_behavior = Some(loop_behavior); } - /// Sets the play mode. Applies to all animations. - pub fn set_play_mode(&mut self, mode: AnimationPlayMode) { - self.pending_play_mode = Some(mode); - } - /// Sets the animation speed. Applies to all animations. pub fn set_speed(&mut self, speed: f32) { self.pending_speed = Some(speed); @@ -168,10 +158,8 @@ impl LottiePlayer { current_state: initial_state, next_state: Some(initial_state), pending_seek_frame: None, - pending_direction: None, pending_intermission: None, pending_loop_behavior: None, - pending_play_mode: None, pending_speed: None, states: HashMap::new(), started: false, @@ -243,7 +231,7 @@ impl Plugin for AnimationControllerPlugin { pub mod systems { use super::{AnimationTransition, LottiePlayer}; - use crate::{AnimationDirection, PlaybackSettings, Vector, VelloAsset}; + use crate::{AnimationDirection, PlaybackSettings, VelloAsset, VelloAssetData}; use bevy::{prelude::*, utils::Instant}; use vello_svg::usvg::strict_num::Ulps; @@ -259,7 +247,7 @@ pub mod systems { for (mut player, mut playback_settings, asset_handle) in query.iter_mut() { let Some(VelloAsset { data: - Vector::Lottie { + VelloAssetData::Lottie { composition, first_frame: _, rendered_frames, @@ -270,16 +258,6 @@ pub mod systems { continue; }; - if let Some(direction) = player.pending_direction.take() { - for playback_settings in player - .states - .values_mut() - .flat_map(|s| s.playback_settings.as_mut()) - .chain([playback_settings.as_mut()]) - { - playback_settings.direction = direction; - } - } if let Some(intermission) = player.pending_intermission.take() { debug!("changed intermission: {intermission}"); // This math is particularly hairy. Several things are going on: @@ -330,17 +308,6 @@ pub mod systems { playback_settings.looping = loop_behavior; } } - if let Some(play_mode) = player.pending_play_mode.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.play_mode = play_mode; - } - } if let Some(seek_frame) = player.pending_seek_frame.take() { let start_frame = playback_settings .segments @@ -397,7 +364,7 @@ pub mod systems { // Continue, assuming we are currently playing. let Some(VelloAsset { data: - Vector::Lottie { + VelloAssetData::Lottie { composition, first_frame, // Set on render rendered_frames, @@ -458,13 +425,13 @@ pub mod systems { let playhead = asset.calculate_playhead(&playback_settings).unwrap(); // Reset play state match &mut asset.data { - Vector::Svg { + VelloAssetData::Svg { original: _, first_frame, } => { first_frame.take(); } - Vector::Lottie { + VelloAssetData::Lottie { composition, first_frame, rendered_frames, @@ -572,8 +539,8 @@ pub mod systems { match transition { AnimationTransition::OnAfter { state, secs } => { let started = match current_asset.data { - Vector::Svg { first_frame, .. } - | Vector::Lottie { first_frame, .. } => first_frame, + VelloAssetData::Svg { first_frame, .. } + | VelloAssetData::Lottie { first_frame, .. } => first_frame, }; if started.is_some_and(|s| s.elapsed().as_secs_f32() >= *secs) { controller.next_state = Some(state); @@ -582,8 +549,8 @@ pub mod systems { } AnimationTransition::OnComplete { state } => { match ¤t_asset.data { - crate::Vector::Svg {..} => panic!("invalid state: '{}', `OnComplete` is only valid for Lottie files. Use `OnAfter` for SVG.", controller.state().id), - crate::Vector::Lottie { + crate::VelloAssetData::Svg {..} => panic!("invalid state: '{}', `OnComplete` is only valid for Lottie files. Use `OnAfter` for SVG.", controller.state().id), + crate::VelloAssetData::Lottie { composition, rendered_frames, .. } => { @@ -618,8 +585,8 @@ pub mod systems { } AnimationTransition::OnShow { state } => { let first_frame = match current_asset.data { - Vector::Svg { first_frame, .. } - | Vector::Lottie { first_frame, .. } => first_frame, + VelloAssetData::Svg { first_frame, .. } + | VelloAssetData::Lottie { first_frame, .. } => first_frame, }; if first_frame.is_some() { controller.next_state = Some(state); diff --git a/src/plugin.rs b/src/plugin.rs index e39959d..4c71afd 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -37,6 +37,6 @@ impl Plugin for VelloPlugin { ); #[cfg(feature = "animation-controller")] - app.add_plugins(crate::animation_controller::AnimationControllerPlugin); + app.add_plugins(crate::lottie_player::AnimationControllerPlugin); } } diff --git a/src/renderer/extract.rs b/src/renderer/extract.rs index a6034cc..f151e5e 100644 --- a/src/renderer/extract.rs +++ b/src/renderer/extract.rs @@ -1,6 +1,6 @@ use crate::{ - color_swapping::ColorPaletteSwap, font::VelloFont, playback_settings::PlaybackSettings, - CoordinateSpace, Origin, VelloAsset, VelloText, + font::VelloFont, playback_settings::PlaybackSettings, theme::Theme, CoordinateSpace, Origin, + VelloAsset, VelloText, }; use bevy::{ prelude::*, @@ -15,7 +15,7 @@ pub struct ExtractedRenderVector { pub render_mode: CoordinateSpace, pub origin: Origin, pub playback_settings: PlaybackSettings, - pub color_swaps: Option, + pub color_swaps: Option, pub ui_node: Option, } @@ -28,7 +28,7 @@ pub fn vector_instances( Option<&Origin>, &GlobalTransform, Option<&PlaybackSettings>, - Option<&ColorPaletteSwap>, + Option<&Theme>, Option<&Node>, &ViewVisibility, &InheritedVisibility, diff --git a/src/renderer/render.rs b/src/renderer/render.rs index 340279d..d37262e 100644 --- a/src/renderer/render.rs +++ b/src/renderer/render.rs @@ -3,7 +3,7 @@ use super::{ prepare::PreparedAffine, BevyVelloRenderer, LottieRenderer, SSRenderTarget, }; -use crate::{assets::vector::Vector, font::VelloFont, CoordinateSpace}; +use crate::{assets::vector::VelloAssetData, font::VelloFont, CoordinateSpace}; use bevy::{ prelude::*, render::{ @@ -83,12 +83,12 @@ pub fn render_scene( color_swaps, .. }) => match &asset.data { - Vector::Svg { + VelloAssetData::Svg { original: fragment, .. } => { builder.append(fragment, Some(affine)); } - Vector::Lottie { + VelloAssetData::Lottie { composition, rendered_frames, first_frame: _, diff --git a/src/rendertarget.rs b/src/rendertarget.rs index 0991415..e1b9555 100644 --- a/src/rendertarget.rs +++ b/src/rendertarget.rs @@ -88,7 +88,6 @@ pub fn setup_ss_rendertarget( mut images: ResMut>, mut custom_materials: ResMut>, windows: Query<&Window>, - // query_vectors: Query>>, mut render_target_mesh_handle: Local>>, ) { let Ok(window) = windows.get_single() else { diff --git a/src/color_swapping.rs b/src/theme.rs similarity index 95% rename from src/color_swapping.rs rename to src/theme.rs index 5396005..6dc72f8 100644 --- a/src/color_swapping.rs +++ b/src/theme.rs @@ -6,16 +6,16 @@ use vellottie::{ #[derive(PartialEq, Component, Default, Clone, Debug, Reflect)] #[reflect(Component)] -/// Add this component to a `VelloVectorBundle` entity to enable runtime color editing. +/// Add this component to a `VelloAssetBundle` entity to enable runtime color editing. /// This interface allows swapping colors in a lottie composition by selecting the desired layer /// and shape and overriding the original color with a new color. /// /// Only works for layer shapes with fill or stroke elements. -pub struct ColorPaletteSwap { +pub struct Theme { pub(crate) colors: HashMap, } -impl ColorPaletteSwap { +impl Theme { pub fn empty() -> Self { Self { colors: HashMap::default(), @@ -43,7 +43,7 @@ impl ColorPaletteSwap { } } -impl ColorPaletteSwap { +impl Theme { pub fn recolor(&self, composition: &Composition) -> Composition { let mut composition = composition.clone(); 'layers: for layer in composition.layers.iter_mut() { @@ -72,6 +72,7 @@ impl ColorPaletteSwap { } } +/// A helper method to recolor a shape with a target color. fn recolor_shape(shape: &mut Shape, target_color: vello::peniko::Color) { match shape { vellottie::runtime::model::Shape::Group(shapes, _) => { @@ -87,7 +88,7 @@ fn recolor_shape(shape: &mut Shape, target_color: vello::peniko::Color) { } } -/// A helper method to recolor a brush with a target color. +/// A helper method to recolor a brush with a target color. fn recolor_brush(brush: &mut Brush, target_color: vello::peniko::Color) { match brush { vellottie::runtime::model::Brush::Fixed(brush) => match brush {