Skip to content

Commit

Permalink
Refactor WebpAnimation and example code for improved usability and re…
Browse files Browse the repository at this point in the history
…ndering

- Updated `WebpAnimation` to integrate more naturally with Nannou’s `Draw` interface.
- Added methods `texture`, `width`, and `height` to `WebpAnimation` to provide direct access to the current frame’s texture and dimensions, enabling flexible positioning and sizing.
- Removed rotation and scaling parameters from `draw` method to align with Nannou's texture drawing style.
- Modified example to reflect these changes, simplifying view logic and rendering pipeline.
- Adjusted comments and documentation for clarity and consistency with new design.
  • Loading branch information
haradama committed Nov 14, 2024
1 parent 10553ce commit d2b72e2
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 60 deletions.
26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ struct Model {

fn model(app: &App) -> Model {
// Create a new window
app.new_window().size(800, 600).build().unwrap();
app.new_window().view(view).build().unwrap();

// Load the WEBP animation
let assets = app.assets_path().expect("Failed to find assets directory");
let webp_path = assets.join("animation.webp"); // Place 'animation.webp' in the 'assets' directory

// Initialize the animation
let animation = WebpAnimation::from_file(&webp_path, app)
.expect("Failed to load WEBP animation");
let animation =
WebpAnimation::from_file(&webp_path, app).expect("Failed to load WEBP animation");

Model { animation }
}
Expand All @@ -104,19 +104,29 @@ fn update(_app: &App, model: &mut Model, _update: Update) {

fn view(app: &App, model: &Model, frame: Frame) {
// Clear the frame
let draw = app.draw();
draw.background().color(BLACK);
frame.clear(BLACK);

let win = app.window_rect();

// Draw the animation at the center
model.animation.draw(&draw, pt2(0.0, 0.0), 1.0, 0.0);
// Define the rectangle where the animation will be drawn
let r = Rect::from_w_h(
model.animation.width() as f32,
model.animation.height() as f32,
)
.top_left_of(win);

let draw = app.draw();
draw.texture(model.animation.texture())
.xy(r.xy())
.wh(r.wh());

// Write to the frame
draw.to_frame(app, &frame).unwrap();
}

fn main() {
nannou::app(model).update(update).run();
}

```

Place your animated WebP file named `animation.webp` inside an `assets` directory at the root of your project.
Expand Down
52 changes: 24 additions & 28 deletions examples/basic_example.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,51 @@
use nannou::prelude::*;
use nannou_webp_animation::WebpAnimation;

fn main() {
nannou::app(model).update(update).view(view).run();
}

struct Model {
animation: WebpAnimation,
rotation: f32,
angular_velocity: f32,
scale: f32,
}

fn model(app: &App) -> Model {
// Create a new window
app.new_window().size(800, 600).build().unwrap();
app.new_window().view(view).build().unwrap();

// Load the WEBP animation
let assets = app.assets_path().unwrap();
let webp_path = assets.join("animation.webp"); // Ensure 'animation.webp' is in the assets directory
let assets = app.assets_path().expect("Failed to find assets directory");
let webp_path = assets.join("animation.webp"); // Place 'animation.webp' in the 'assets' directory

// Initialize the animation
let animation =
WebpAnimation::from_file(&webp_path, app).expect("Failed to load WEBP animation");

Model {
animation,
rotation: 0.0,
angular_velocity: 0.01, // Adjust as needed
scale: 1.0,
}
Model { animation }
}

fn update(_app: &App, model: &mut Model, _update: Update) {
// Update the animation frames
// Update the animation
model.animation.update();

// Update rotation
model.rotation += model.angular_velocity;
}

fn view(app: &App, model: &Model, frame: Frame) {
// Prepare to draw
let draw = app.draw();
draw.background().color(WHITE);
// Clear the frame
frame.clear(BLACK);

let win = app.window_rect();

// Draw the animation with rotation and scaling
model
.animation
.draw(&draw, pt2(0.0, 0.0), model.scale, model.rotation);
// Define the rectangle where the animation will be drawn
let r = Rect::from_w_h(
model.animation.width() as f32,
model.animation.height() as f32,
)
.top_left_of(win);

let draw = app.draw();
draw.texture(model.animation.texture())
.xy(r.xy())
.wh(r.wh());

// Render the frame
draw.to_frame(app, &frame).unwrap();
}

fn main() {
nannou::app(model).update(update).run();
}
56 changes: 32 additions & 24 deletions src/animation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::decoder::WebpDecoder;
use crate::frame::WebpFrame;
use nannou::prelude::*;
use nannou::wgpu::Texture;
use std::path::Path;
use std::time::Instant;

Expand All @@ -15,7 +16,7 @@ pub struct WebpAnimation {
/// Indicates whether the animation should loop when it reaches the end.
is_looping: bool,
/// Textures for each frame, generated from the images in the animation.
textures: Vec<wgpu::Texture>,
textures: Vec<Texture>,
}

impl WebpAnimation {
Expand Down Expand Up @@ -44,10 +45,10 @@ impl WebpAnimation {
return Err("No frames found in the animation".to_string());
}

// Create textures from images
let textures: Vec<wgpu::Texture> = frames
// Create textures from images using Nannou's Texture
let textures: Vec<Texture> = frames
.iter()
.map(|frame| wgpu::Texture::from_image(app, &frame.image))
.map(|frame| Texture::from_image(app, &frame.image))
.collect();

Ok(Self {
Expand Down Expand Up @@ -80,31 +81,38 @@ impl WebpAnimation {
}
}

/// Draws the current frame of the animation to the screen.
///
/// # Arguments
///
/// * `draw` - A reference to the Nannou `Draw` instance for rendering.
/// * `position` - Position where the animation should be drawn.
/// * `scale` - Scale factor for the animation size.
/// * `rotation` - Rotation angle (in radians) for the animation.
pub fn draw(&self, draw: &Draw, position: Point2, scale: f32, rotation: f32) {
if let Some(texture) = self.textures.get(self.current_frame_index) {
draw.texture(texture)
.x_y(position.x, position.y)
.w_h(
texture.size()[0] as f32 * scale,
texture.size()[1] as f32 * scale,
)
.rotate(rotation);
}
/// Returns a reference to the current texture.
///
/// # Returns
///
/// A reference to the `Texture` of the current frame.
pub fn texture(&self) -> &Texture {
&self.textures[self.current_frame_index]
}

/// Returns the width of the current frame.
///
/// # Returns
///
/// The width (in pixels) of the current frame's texture.
pub fn width(&self) -> u32 {
self.texture().size()[0]
}

/// Returns the height of the current frame.
///
/// # Returns
///
/// The height (in pixels) of the current frame's texture.
pub fn height(&self) -> u32 {
self.texture().size()[1]
}

/// Sets whether the animation should loop after reaching the final frame.
///
/// # Arguments
/// # Parameters
///
/// * `looping` - If `true`, the animation will loop indefinitely. If `false`, it will stop at the last frame.
/// - `looping`: If `true`, the animation will loop indefinitely. If `false`, it will stop at the last frame.
pub fn set_looping(&mut self, looping: bool) {
self.is_looping = looping;
}
Expand Down

0 comments on commit d2b72e2

Please sign in to comment.