Skip to content

Commit

Permalink
Split VelloAsset into VelloSvg and VelloLottie (#90)
Browse files Browse the repository at this point in the history
Builds upon #87. Merge that first.

Closes #89.

---------

Co-authored-by: Elie Génard <[email protected]>
  • Loading branch information
simbleau and egenard authored Feb 6, 2025
1 parent 6a2d483 commit 08ca628
Show file tree
Hide file tree
Showing 31 changed files with 1,051 additions and 649 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ This release supports Bevy version 0.14 and has an [MSRV][] of 1.80.
### Changed

- bevy_vello now uses Bevy 0.15
- `VelloAsset` assets have been separated into `VelloSvg` and `VelloLottie`
- `VelloAssetBundle` has been separated into `VelloSvgBundle` and `VelloLottieBundle`
- `Handle<VelloAsset>` has been separated into `VelloSvgHandle` and `VelloLottieHandle`
- `VelloAssetAnchor` has been separated into `VelloSvgAnchor` and `VelloLottieAnchor`
- The license on bevy_vello no longer includes OFL 1.1

### Fixed
Expand Down Expand Up @@ -265,4 +269,4 @@ This release supports Bevy version 0.13 and has an [MSRV][] of 1.77.
[0.1.1]: https://github.com/linebender/bevy_vello/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/linebender/bevy_vello/releases/tag/v0.1.0

[MSRV]: README.md#minimum-supported-rust-version-msrv
[MSRV]: README.md#minimum-supported-rust-version-msrv
21 changes: 8 additions & 13 deletions examples/demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ fn main() {
fn setup_vector_graphics(mut commands: Commands, asset_server: ResMut<AssetServer>) {
commands.spawn((Camera2d, bevy_pancam::PanCam::default()));
commands
.spawn(VelloAssetBundle {
asset: VelloAssetHandle(
asset_server.load::<VelloAsset>("embedded://demo/assets/calendar.json"),
),
.spawn(VelloLottieBundle {
asset: VelloLottieHandle(asset_server.load("embedded://demo/assets/calendar.json")),
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0))
.with_scale(Vec3::splat(20.0)),
debug_visualizations: DebugVisualizations::Visible,
Expand Down Expand Up @@ -74,19 +72,16 @@ fn setup_vector_graphics(mut commands: Commands, asset_server: ResMut<AssetServe
}

fn print_metadata(
mut asset_ev: EventReader<AssetEvent<VelloAsset>>,
assets: Res<Assets<VelloAsset>>,
mut asset_ev: EventReader<AssetEvent<VelloLottie>>,
assets: Res<Assets<VelloLottie>>,
) {
for ev in asset_ev.read() {
if let AssetEvent::LoadedWithDependencies { id } = ev {
let asset = assets.get(*id).unwrap();
#[allow(irrefutable_let_patterns)]
if let VectorFile::Lottie(composition) = &asset.file {
info!(
"Animated asset loaded. Layers:\n{:#?}",
composition.as_ref().get_layers().collect::<Vec<_>>()
);
}
info!(
"Animated asset loaded. Layers:\n{:#?}",
asset.composition.as_ref().get_layers().collect::<Vec<_>>()
);
}
}
}
12 changes: 4 additions & 8 deletions examples/demo/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,17 @@ pub fn controls_ui(
&mut Playhead,
&mut PlaybackOptions,
&mut Theme,
&VelloAssetHandle,
&VelloLottieHandle,
)>,
assets: Res<Assets<VelloAsset>>,
assets: Res<Assets<VelloLottie>>,
) {
let Ok((mut player, mut playhead, mut options, mut theme, handle)) = player.get_single_mut()
else {
return;
};

let asset = assets.get(handle.id()).unwrap();
#[allow(irrefutable_let_patterns)]
let VectorFile::Lottie(composition) = &asset.file
else {
return;
};
let composition = asset.composition.as_ref();

let window = egui::Window::new("Controls")
.resizable(false)
Expand Down Expand Up @@ -250,7 +246,7 @@ pub fn controls_ui(
});

ui.heading("Theme");
for layer in composition.as_ref().get_layers() {
for layer in composition.get_layers() {
let color = theme.get_mut(layer).cloned().unwrap_or_default();
let color = color.to_srgba().to_u8_array();
let mut color32 =
Expand Down
39 changes: 29 additions & 10 deletions examples/drag_n_drop/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use bevy::{
prelude::*,
};
use bevy_vello::{prelude::*, VelloPlugin};
use std::ffi::OsStr;

fn main() {
let mut app = App::new();
Expand All @@ -19,10 +20,9 @@ fn main() {

fn setup_vector_graphics(mut commands: Commands, asset_server: ResMut<AssetServer>) {
commands.spawn(Camera2d);
commands.spawn(VelloAssetBundle {
asset: VelloAssetHandle(
asset_server.load::<VelloAsset>("embedded://drag_n_drop/assets/fountain.svg"),
),

commands.spawn(VelloSvgBundle {
asset: VelloSvgHandle(asset_server.load("embedded://drag_n_drop/assets/fountain.svg")),
debug_visualizations: DebugVisualizations::Visible,
transform: Transform::from_scale(Vec3::splat(5.0)),
..default()
Expand All @@ -32,18 +32,37 @@ fn setup_vector_graphics(mut commands: Commands, asset_server: ResMut<AssetServe
/// Drag and drop any SVG or Lottie JSON asset into the window and change the
/// displayed asset
fn drag_and_drop(
mut query: Query<&mut VelloAssetHandle>,
mut commands: Commands,
query_lottie: Option<Single<Entity, With<VelloLottieHandle>>>,
query_svg: Option<Single<Entity, With<VelloSvgHandle>>>,
asset_server: ResMut<AssetServer>,
mut dnd_evr: EventReader<FileDragAndDrop>,
) {
let Ok(mut asset) = query.get_single_mut() else {
return;
};
for ev in dnd_evr.read() {
if let Some(ref svg) = query_svg {
commands.entity(**svg).despawn();
}
if let Some(ref lottie) = query_lottie {
commands.entity(**lottie).despawn();
}
let FileDragAndDrop::DroppedFile { path_buf, .. } = ev else {
continue;
};
let new_handle = VelloAssetHandle(asset_server.load(path_buf.clone()));
*asset = new_handle;
let Some(ext) = path_buf.extension() else {
continue;
};
let svg_ext = OsStr::new("svg");
let lottie_ext = OsStr::new("json");
if ext == svg_ext {
commands.spawn(VelloSvgBundle {
asset: VelloSvgHandle(asset_server.load(path_buf.clone())),
..default()
});
} else if ext == lottie_ext {
commands.spawn(VelloLottieBundle {
asset: VelloLottieHandle(asset_server.load(path_buf.clone())),
..default()
});
}
}
}
4 changes: 2 additions & 2 deletions examples/lottie/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ fn load_lottie(mut commands: Commands, asset_server: ResMut<AssetServer>) {
commands.spawn(Camera2d);

// Yes, it's this simple.
commands.spawn(VelloAssetBundle {
asset: VelloAssetHandle(asset_server.load("embedded://lottie/assets/Tiger.json")),
commands.spawn(VelloLottieBundle {
asset: VelloLottieHandle(asset_server.load("embedded://lottie/assets/Tiger.json")),
debug_visualizations: DebugVisualizations::Visible,
transform: Transform::from_scale(Vec3::splat(0.5)),
..default()
Expand Down
4 changes: 2 additions & 2 deletions examples/svg/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ fn load_svg(mut commands: Commands, asset_server: ResMut<AssetServer>) {
commands.spawn(Camera2d);

// Yes, it's this simple.
commands.spawn(VelloAssetBundle {
asset: VelloAssetHandle(asset_server.load("embedded://svg/assets/fountain.svg")),
commands.spawn(VelloSvgBundle {
asset: VelloSvgHandle(asset_server.load("embedded://svg/assets/fountain.svg")),
debug_visualizations: DebugVisualizations::Visible,
transform: Transform::from_scale(Vec3::splat(5.0)),
..default()
Expand Down
92 changes: 80 additions & 12 deletions src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//! Logic for rendering debug visualizations
use crate::{
text::VelloTextAnchor, CoordinateSpace, VelloAsset, VelloAssetAnchor, VelloAssetHandle,
VelloFont, VelloTextSection,
};
use crate::prelude::*;
use bevy::{color::palettes::css, math::Vec3Swizzles, prelude::*};

const RED_X_SIZE: f32 = 8.0;
Expand All @@ -11,7 +8,15 @@ pub struct DebugVisualizationsPlugin;

impl Plugin for DebugVisualizationsPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, (render_asset_debug, render_text_debug));
// TODO: Would be great if we could render scene debug, but Vello doesn't tell us the AABB or BB.

app.add_systems(Update, render_text_debug);

#[cfg(feature = "svg")]
app.add_systems(Update, render_svg_debug);

#[cfg(feature = "lottie")]
app.add_systems(Update, render_lottie_debug);
}
}

Expand All @@ -23,19 +28,81 @@ pub enum DebugVisualizations {
Visible,
}

/// A system to render debug visualizations for `VelloAsset`.
fn render_asset_debug(
#[cfg(feature = "svg")]
/// A system to render debug visualizations for SVGs.
fn render_svg_debug(
query_vectors: Query<
(
&VelloSvgHandle,
&VelloSvgAnchor,
&GlobalTransform,
&CoordinateSpace,
&DebugVisualizations,
),
Without<Node>,
>,
assets: Res<Assets<VelloSvg>>,
query_cam: Query<(&Camera, &GlobalTransform, &OrthographicProjection), With<Camera2d>>,
mut gizmos: Gizmos,
) {
let Ok((camera, view, projection)) = query_cam.get_single() else {
return;
};

// Show vectors
for (asset, asset_anchor, gtransform, space, _) in query_vectors
.iter()
.filter(|(_, _, _, _, d)| **d == DebugVisualizations::Visible)
{
if let Some(asset) = assets.get(asset.id()) {
match space {
CoordinateSpace::WorldSpace => {
// Origin
let origin = gtransform.translation().xy();
draw_origin(&mut gizmos, projection, origin);
// Bounding box
let gtransform = &asset_anchor.compute(asset.width, asset.height, gtransform);
let rect_center = gtransform.translation().xy();
let rect = asset.bb_in_world_space(gtransform);
draw_bounding_box(&mut gizmos, rect_center, rect.size());
}
CoordinateSpace::ScreenSpace => {
// Origin
let origin = gtransform.translation().xy();
let Ok(origin) = camera.viewport_to_world_2d(view, origin) else {
continue;
};
draw_origin(&mut gizmos, projection, origin);
// Bounding box
let gtransform = &asset_anchor.compute(asset.width, asset.height, gtransform);
let rect_center = gtransform.translation().xy();
let Ok(rect_center) = camera.viewport_to_world_2d(view, rect_center) else {
continue;
};
let Some(rect) = asset.bb_in_screen_space(gtransform, camera, view) else {
continue;
};
draw_bounding_box(&mut gizmos, rect_center, rect.size());
}
}
}
}
}

#[cfg(feature = "lottie")]
/// A system to render debug visualizations for SVGs.
fn render_lottie_debug(
query_vectors: Query<
(
&VelloAssetHandle,
&VelloAssetAnchor,
&VelloLottieHandle,
&VelloLottieAnchor,
&GlobalTransform,
&CoordinateSpace,
&DebugVisualizations,
),
Without<Node>,
>,
assets: Res<Assets<VelloAsset>>,
assets: Res<Assets<VelloLottie>>,
query_cam: Query<(&Camera, &GlobalTransform, &OrthographicProjection), With<Camera2d>>,
mut gizmos: Gizmos,
) {
Expand All @@ -55,7 +122,7 @@ fn render_asset_debug(
let origin = gtransform.translation().xy();
draw_origin(&mut gizmos, projection, origin);
// Bounding box
let gtransform = &asset_anchor.compute(asset, gtransform);
let gtransform = &asset_anchor.compute(asset.width, asset.height, gtransform);
let rect_center = gtransform.translation().xy();
let rect = asset.bb_in_world_space(gtransform);
draw_bounding_box(&mut gizmos, rect_center, rect.size());
Expand All @@ -68,7 +135,7 @@ fn render_asset_debug(
};
draw_origin(&mut gizmos, projection, origin);
// Bounding box
let gtransform = &asset_anchor.compute(asset, gtransform);
let gtransform = &asset_anchor.compute(asset.width, asset.height, gtransform);
let rect_center = gtransform.translation().xy();
let Ok(rect_center) = camera.viewport_to_world_2d(view, rect_center) else {
continue;
Expand Down Expand Up @@ -222,6 +289,7 @@ fn draw_origin(gizmos: &mut Gizmos, projection: &OrthographicProjection, origin:
gizmos.line_2d(from, to, css::RED);
}

#[cfg(any(feature = "svg", feature = "lottie"))]
/// A helper method to draw the bounding box
fn draw_bounding_box(gizmos: &mut Gizmos, position: Vec2, size: Vec2) {
gizmos.rect_2d(
Expand Down
Loading

0 comments on commit 08ca628

Please sign in to comment.