Skip to content

Commit

Permalink
update for bevy 0.15
Browse files Browse the repository at this point in the history
  • Loading branch information
mockersf committed Nov 10, 2024
1 parent d5ec3bb commit ffa61eb
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 154 deletions.
12 changes: 3 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "vleue_kinetoscope"
version = "0.2.0"
version = "0.3.0-rc.1"
edition = "2021"
exclude = ["animated-gif.webp"]
authors = ["François Mockers <[email protected]>"]
Expand All @@ -22,21 +22,15 @@ webp = ["image/webp"]
[dependencies]
image = { version = "0.25", default-features = false }
thiserror = "1.0"
bevy = { version = "0.14.0", default-features = false, features = [
bevy = { version = "0.15.0-rc.3", default-features = false, features = [
"bevy_sprite",
] }

[dev-dependencies]
bevy = { version = "0.14.0", default-features = false, features = [
bevy = { version = "0.15.0-rc.3", default-features = false, features = [
"bevy_sprite",
"bevy_ui",
"bevy_winit",
"default_font",
"x11",
] }

[patch.crates-io]
# For webp support - https://github.com/image-rs/image/pull/2228
image = { git = "https://github.com/image-rs/image" }
# For webp support - https://github.com/image-rs/image-webp/pull/76
image-webp = { git = "https://github.com/image-rs/image-webp" }
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,36 @@ fn main() {

### Play an animated gif

Spawn an entity with the bundle `AnimatedImageBundle`
Spawn an entity with the component `AnimatedImageController`:

```rust
use bevy::prelude::*;
use vleue_kinetoscope::*;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(AnimatedImageBundle {
animated_image: asset_server.load("Geneva_mechanism_6spoke_animation.gif"),
..default()
});
commands.spawn(AnimatedImageController::play(asset_server.load("cube.gif")));
}
```

### WebP Support

Animated WebP is currently broken in release versions of dependencies, and need patches to work properly:
### Play an animated WebP

```toml
[patch.crates-io]
# For webp support - https://github.com/image-rs/image/pull/2228
image = { git = "https://github.com/image-rs/image" }
# For webp support - https://github.com/image-rs/image-webp/pull/76
image-webp = { git = "https://github.com/image-rs/image-webp" }
Spawn an entity with the component `AnimatedImageController`:

```rust
use bevy::prelude::*;
use vleue_kinetoscope::*;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(AnimatedImageController::play(asset_server.load("cube.webp")));
}
```

## Bevy Support

|Bevy|vleue_kinetoscope|
|---|---|
|main|main|
|0.15|0.3|
|0.14|0.2|
|0.13|0.1|
139 changes: 65 additions & 74 deletions examples/animated-image.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy::prelude::*;

use vleue_kinetoscope::{AnimatedImageBundle, AnimatedImageController, AnimatedImagePlugin};
use vleue_kinetoscope::{AnimatedImageController, AnimatedImagePlugin};

fn main() {
App::new()
Expand All @@ -27,7 +27,7 @@ impl std::fmt::Display for Image {
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>, window: Query<&Window>) {
commands.spawn(Camera2dBundle::default());
commands.spawn(Camera2d);

let window_width = window.single().width() / 2.0;

Expand All @@ -36,107 +36,98 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, window: Query<&
.enumerate()
{
commands.spawn((
AnimatedImageBundle {
animated_image: asset_server.load(file),
transform: Transform::from_xyz(
-window_width * ((-1.0 as f32).powi(i as i32)) / 2.0,
-75.0,
0.0,
),
..default()
},
AnimatedImageController::play(asset_server.load(file)),
Transform::from_xyz(
-window_width * ((-1.0 as f32).powi(i as i32)) / 2.0,
-75.0,
0.0,
),
kind,
));

commands
.spawn(NodeBundle {
style: Style {
width: Val::Percent(50.0),
height: Val::Percent(100.0),
top: Val::Percent(10.0),
left: Val::Percent(50.0 * (i as f32)),
align_items: AlignItems::Start,
justify_content: JustifyContent::Center,
..default()
},
.spawn(Node {
width: Val::Percent(50.0),
height: Val::Percent(100.0),
top: Val::Percent(10.0),
left: Val::Percent(50.0 * (i as f32)),
align_items: AlignItems::Start,
justify_content: JustifyContent::Center,
..default()
})
.with_children(|parent| {
parent.spawn((
TextBundle::from_sections(vec![
TextSection {
value: format!("{}\n", kind),
style: TextStyle {
font_size: 60.0,
..default()
},
parent.spawn((Text::default(), kind)).with_children(|text| {
text.spawn((
TextSpan(format!("{}\n", kind)),
TextFont {
font_size: 60.0,
..default()
},
TextSection {
value: "play count: ".to_string(),
style: TextStyle {
font_size: 50.0,
..default()
},
));
text.spawn((
TextSpan("Play Count: ".to_string()),
TextFont {
font_size: 50.0,
..default()
},
TextSection {
value: "0".to_string(),
style: TextStyle {
font_size: 50.0,
..default()
},
));
text.spawn((
TextSpan("0".to_string()),
TextFont {
font_size: 50.0,
..default()
},
TextSection {
value: "\ncurrent frame: ".to_string(),
style: TextStyle {
font_size: 30.0,
..default()
},
));
text.spawn((
TextSpan("\ncurrent frame: ".to_string()),
TextFont {
font_size: 30.0,
..default()
},
TextSection {
value: "0".to_string(),
style: TextStyle {
font_size: 30.0,
..default()
},
));
text.spawn((
TextSpan("0".to_string()),
TextFont {
font_size: 30.0,
..default()
},
TextSection {
value: " / ".to_string(),
style: TextStyle {
font_size: 30.0,
..default()
},
));
text.spawn((
TextSpan("/".to_string()),
TextFont {
font_size: 30.0,
..default()
},
TextSection {
value: "0".to_string(),
style: TextStyle {
font_size: 30.0,
..default()
},
));
text.spawn((
TextSpan("0".to_string()),
TextFont {
font_size: 30.0,
..default()
},
]),
kind,
));
));
});
});
}
}

fn log_updates(
mut texts: Query<(&mut Text, &Image)>,
texts: Query<(Entity, &Image), With<Text>>,
playing_images: Query<(Ref<AnimatedImageController>, &Image)>,
mut text_writer: TextUiWriter,
) {
for (animated_image, image_kind) in &playing_images {
if animated_image.is_changed() {
for (mut text, text_kind) in &mut texts {
for (text, text_kind) in &texts {
if image_kind != text_kind {
continue;
}
text.sections[2].value = format!("{}", animated_image.play_count());
text.sections[4].value = format!("{:>4}", animated_image.current_frame());
text.sections[6].value = format!("{}", animated_image.frame_count() as i32 - 1);
*text_writer.text(text, 3) = format!("{}", animated_image.play_count());
*text_writer.text(text, 5) = format!("{:>4}", animated_image.current_frame());
*text_writer.text(text, 7) = format!("{}", animated_image.frame_count() as i32 - 1);
}
}
}
// let gif = gif.single();
}

fn reset(
Expand Down
45 changes: 15 additions & 30 deletions src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,37 @@ use bevy::prelude::*;
use super::{AnimatedImage, AnimatedImageController};

pub(crate) fn image_driver(
images: Query<(Entity, &Handle<AnimatedImage>)>,
mut playing_images: Query<(
&Handle<AnimatedImage>,
&mut AnimatedImageController,
&mut Handle<Image>,
)>,
mut playing_images: Query<(&mut AnimatedImageController, &mut Sprite)>,
animated_images: Res<Assets<AnimatedImage>>,
time: Res<Time>,
) {
// don't rely on changed or added filter as the asset can be not yet loaded at the time the component is added
for (entity, new_animated_image) in images.iter() {
let Some(animated_image) = animated_images.get(new_animated_image) else {
for (mut controller, mut image) in &mut playing_images {
let Some(animated_image) = animated_images.get(&controller.animated_image) else {
continue;
};

if let Ok((_, mut controller, mut image)) = playing_images.get_mut(entity) {
if controller.current_frame == usize::MAX
|| !animated_image.frames.iter().any(|f| f.image == *image)
{
*controller = AnimatedImageController {
timer: Timer::new(
Duration::from_millis(animated_image.frames[0].delay.0 as u64),
TimerMode::Repeating,
),
current_frame: 0,
play_count: 0,
frame_count: animated_image.frames.len(),
};
*image = animated_image.frames[0].image.clone_weak();
}
if controller.current_frame == usize::MAX
|| !animated_image.frames.iter().any(|f| f.image == image.image)
{
controller.current_frame = 0;
controller.play_count = 0;
controller.timer = Timer::new(
Duration::from_millis(animated_image.frames[0].delay.0 as u64),
TimerMode::Repeating,
);
controller.frame_count = animated_image.frames.len();
image.image = animated_image.frames[0].image.clone_weak();
}
}

for (animated_image, mut controller, mut image) in playing_images.iter_mut() {
if controller.timer.tick(time.delta()).just_finished() {
let Some(animated_image) = animated_images.get(animated_image) else {
continue;
};
let remaining = controller.timer.elapsed();
let new_index = (controller.current_frame + 1) % animated_image.frames.len();
controller.timer = Timer::new(
Duration::from_millis(animated_image.frames[new_index].delay.0 as u64),
TimerMode::Repeating,
);
controller.timer.set_elapsed(remaining);
*image = animated_image.frames[new_index].image.clone_weak();
image.image = animated_image.frames[new_index].image.clone_weak();
controller.current_frame = new_index;
if new_index == 0 {
controller.play_count += 1;
Expand Down
Loading

0 comments on commit ffa61eb

Please sign in to comment.