diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index a5db0e5c32da44..01b704959f9585 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -13,10 +13,9 @@ pub mod prelude { #[doc(hidden)] pub use crate::{ bundle::{SpriteBundle, SpriteSheetBundle}, - rect::{BorderRect, Rect}, sprite::{Sprite, SpriteDrawMode}, texture_atlas::{TextureAtlas, TextureAtlasSprite}, - texture_slice::{SliceScaleMode, TextureSlicer}, + texture_slice::{BorderRect, SliceScaleMode, TextureSlicer}, ColorMaterial, ColorMesh2dBundle, TextureAtlasBuilder, }; } diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 7bd8c39fed5bad..f3d7b27df8e3e1 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -2,7 +2,7 @@ use std::cmp::Ordering; use crate::{ texture_atlas::{TextureAtlas, TextureAtlasSprite}, - Rect, Sprite, SpriteDrawMode, TextureSlice, SPRITE_SHADER_HANDLE, + Sprite, SpriteDrawMode, TextureSlice, SPRITE_SHADER_HANDLE, }; use bevy_asset::{AssetEvent, Assets, Handle, HandleId}; use bevy_core_pipeline::{core_2d::Transparent2d, tonemapping::Tonemapping}; @@ -30,7 +30,7 @@ use bevy_render::{ }, Extract, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::components::{GlobalTransform, Transform}; use bevy_utils::FloatOrd; use bevy_utils::HashMap; use bytemuck::{Pod, Zeroable}; @@ -343,7 +343,8 @@ pub fn extract_sprites( } if let SpriteDrawMode::Simple = sprite.draw_mode { // PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive - extracted_sprites.sprites.alloc().init(ExtractedSprite { + extracted_sprites.sprites.push(ExtractedSprite { + entity, color: sprite.color, transform: *transform, // Use the full texture @@ -351,7 +352,7 @@ pub fn extract_sprites( custom_size: sprite.custom_size, flip_x: sprite.flip_x, flip_y: sprite.flip_y, - image_handle_id: handle.id, + image_handle_id: handle.id(), anchor: sprite.anchor.as_vec(), }); continue; @@ -391,8 +392,9 @@ pub fn extract_sprites( }; for slice in slices { let mut transform: GlobalTransform = *transform; - transform.translation = transform.mul_vec3(slice.offset.extend(0.0)); - extracted_sprites.sprites.alloc().init(ExtractedSprite { + transform = + transform.mul_transform(Transform::from_translation(slice.offset.extend(0.0))); + extracted_sprites.sprites.push(ExtractedSprite { entity, color: sprite.color, transform, @@ -400,7 +402,7 @@ pub fn extract_sprites( custom_size: Some(slice.draw_size), flip_x: sprite.flip_x, flip_y: sprite.flip_y, - image_handle_id: handle.id, + image_handle_id: handle.id(), anchor: sprite.anchor.as_vec(), }); } diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 07cf7a0290c602..3998854d7626f3 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -65,6 +65,8 @@ pub enum Anchor { } impl Anchor { + #[inline] + #[must_use] pub fn as_vec(&self) -> Vec2 { match self { Anchor::Center => Vec2::ZERO, diff --git a/crates/bevy_sprite/src/texture_slice.rs b/crates/bevy_sprite/src/texture_slice.rs index 35695dc89d2bf2..099e78b068bb1d 100644 --- a/crates/bevy_sprite/src/texture_slice.rs +++ b/crates/bevy_sprite/src/texture_slice.rs @@ -1,6 +1,63 @@ -use crate::{BorderRect, Rect}; -use bevy_math::Vec2; -use bevy_reflect::Reflect; +use bevy_math::{Rect, Vec2}; +use bevy_reflect::{FromReflect, Reflect}; + +/// Struct defining a [`Sprite`](crate::Sprite) border with padding values +#[derive(Default, Clone, Copy, Debug, Reflect, FromReflect)] +pub struct BorderRect { + /// Pixel padding to the left + pub left: f32, + /// Pixel padding to the right + pub right: f32, + /// Pixel padding to the top + pub top: f32, + /// Pixel padding to the bottom + pub bottom: f32, +} + +impl BorderRect { + /// Creates a new border as a square, with identical pixel padding values on every direction + #[must_use] + #[inline] + pub const fn square(value: f32) -> Self { + Self { + left: value, + right: value, + top: value, + bottom: value, + } + } + + /// Creates a new border as a rectangle, with: + /// - `horizontal` for left and right pixel padding + /// - `vertical` for top and bottom pixel padding + #[must_use] + #[inline] + pub const fn rectangle(horizontal: f32, vertical: f32) -> Self { + Self { + left: horizontal, + right: horizontal, + top: vertical, + bottom: vertical, + } + } +} + +impl From for BorderRect { + fn from(v: f32) -> Self { + Self::square(v) + } +} + +impl From<[f32; 4]> for BorderRect { + fn from([left, right, top, bottom]: [f32; 4]) -> Self { + Self { + left, + right, + top, + bottom, + } + } +} /// Slices a texture using the **9-slicing** technique. This allows to reuse an image at various sizes /// without needing to prepare multiple assets. The associated texture will be split into nine portions, @@ -10,7 +67,7 @@ use bevy_reflect::Reflect; /// sections will be scaled or tiled. /// /// See [9-sliced](https://en.wikipedia.org/wiki/9-slice_scaling) textures. -#[derive(Debug, Clone, Reflect)] +#[derive(Debug, Clone, Reflect, FromReflect)] pub struct TextureSlicer { /// The sprite borders, defining the 9 sections of the image pub border: BorderRect, @@ -23,7 +80,7 @@ pub struct TextureSlicer { } /// Defines how a texture slice scales when resized -#[derive(Debug, Copy, Clone, Default, Reflect)] +#[derive(Debug, Copy, Clone, Default, Reflect, FromReflect)] pub enum SliceScaleMode { /// The slice will be stretched to fit the area #[default] diff --git a/examples/2d/sprite_slice.rs b/examples/2d/sprite_slice.rs index 7f02f1d34f5308..e61f99a0d552ca 100644 --- a/examples/2d/sprite_slice.rs +++ b/examples/2d/sprite_slice.rs @@ -4,12 +4,14 @@ use bevy::prelude::*; fn main() { App::new() - .insert_resource(WindowDescriptor { - width: 1350.0, - height: 700.0, + .add_plugins(DefaultPlugins.set(WindowPlugin { + window: WindowDescriptor { + width: 1350.0, + height: 700.0, + ..default() + }, ..default() - }) - .add_plugins(DefaultPlugins) + })) .add_startup_system(setup) .run(); } @@ -21,7 +23,7 @@ fn spawn_sprites( slice_border: f32, ) { // Reference sprite - commands.spawn_bundle(SpriteBundle { + commands.spawn(SpriteBundle { transform: Transform::from_translation(base_pos), texture: texture_handle.clone(), sprite: Sprite { @@ -32,7 +34,7 @@ fn spawn_sprites( }); // Scaled regular sprite - commands.spawn_bundle(SpriteBundle { + commands.spawn(SpriteBundle { transform: Transform::from_translation(base_pos + Vec3::X * 150.0), texture: texture_handle.clone(), sprite: Sprite { @@ -43,7 +45,7 @@ fn spawn_sprites( }); // Stretched Scaled sliced sprite - commands.spawn_bundle(SpriteBundle { + commands.spawn(SpriteBundle { transform: Transform::from_translation(base_pos + Vec3::X * 300.0), texture: texture_handle.clone(), sprite: Sprite { @@ -59,7 +61,7 @@ fn spawn_sprites( }); // Scaled sliced sprite - commands.spawn_bundle(SpriteBundle { + commands.spawn(SpriteBundle { transform: Transform::from_translation(base_pos + Vec3::X * 450.0), texture: texture_handle.clone(), sprite: Sprite { @@ -76,7 +78,7 @@ fn spawn_sprites( }); // Scaled sliced sprite horizontally - commands.spawn_bundle(SpriteBundle { + commands.spawn(SpriteBundle { transform: Transform::from_translation(base_pos + Vec3::X * 700.0), texture: texture_handle.clone(), sprite: Sprite { @@ -93,7 +95,7 @@ fn spawn_sprites( }); // Scaled sliced sprite horizontally with max scale - commands.spawn_bundle(SpriteBundle { + commands.spawn(SpriteBundle { transform: Transform::from_translation(base_pos + Vec3::X * 1050.0), texture: texture_handle, sprite: Sprite { @@ -111,7 +113,7 @@ fn spawn_sprites( } fn setup(mut commands: Commands, asset_server: Res) { - commands.spawn_bundle(Camera2dBundle::default()); + commands.spawn(Camera2dBundle::default()); // Load textures let handle_1 = asset_server.load("textures/slice_square.png"); let handle_2 = asset_server.load("textures/slice_square_2.png");