From 163fb786a972f4545b3b17b0c49410fc6cc55649 Mon Sep 17 00:00:00 2001 From: Felix de Maneville Date: Sun, 26 Jun 2022 12:06:51 +0200 Subject: [PATCH 01/10] Texture Atlas rework --- crates/bevy_sprite/src/bundle.rs | 13 ++-- .../src/dynamic_texture_atlas_builder.rs | 7 +- crates/bevy_sprite/src/lib.rs | 2 +- crates/bevy_sprite/src/render/mod.rs | 70 ++++--------------- crates/bevy_sprite/src/texture_atlas.rs | 70 ++++++------------- .../bevy_sprite/src/texture_atlas_builder.rs | 49 ++++++++++--- crates/bevy_text/src/font_atlas.rs | 16 +++-- crates/bevy_text/src/font_atlas_set.rs | 12 +++- crates/bevy_text/src/text2d.rs | 4 +- crates/bevy_ui/src/render/mod.rs | 4 +- examples/2d/sprite_sheet.rs | 20 +++--- examples/2d/texture_atlas.rs | 6 +- examples/ui/font_atlas_debug.rs | 9 +-- 13 files changed, 127 insertions(+), 155 deletions(-) diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index 092e5a302bb8b..caba3ec919b78 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -1,7 +1,4 @@ -use crate::{ - texture_atlas::{TextureAtlas, TextureAtlasSprite}, - Sprite, -}; +use crate::{texture_atlas::TextureAtlas, Sprite, TextureSheetIndex}; use bevy_asset::Handle; use bevy_ecs::bundle::Bundle; use bevy_render::{ @@ -34,14 +31,18 @@ impl Default for SpriteBundle { } } } + /// A Bundle of components for drawing a single sprite from a sprite sheet (also referred /// to as a `TextureAtlas`) #[derive(Bundle, Clone, Default)] pub struct SpriteSheetBundle { - /// The specific sprite from the texture atlas to be drawn, defaulting to the sprite at index 0. - pub sprite: TextureAtlasSprite, + pub sprite: Sprite, + /// The sprite sheet texture + pub texture: Handle, /// A handle to the texture atlas that holds the sprite images pub texture_atlas: Handle, + /// The texture sheet sprite index + pub index: TextureSheetIndex, /// Data pertaining to how the sprite is drawn on the screen pub transform: Transform, pub global_transform: GlobalTransform, diff --git a/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs b/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs index 18dd13a0ed8ff..f8a09552b9bb7 100644 --- a/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs +++ b/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs @@ -1,5 +1,5 @@ -use crate::TextureAtlas; -use bevy_asset::Assets; +use crate::{Rect, TextureAtlas}; +use bevy_asset::{Assets, Handle}; use bevy_math::{IVec2, Rect, Vec2}; use bevy_render::texture::{Image, TextureFormatPixelInfo}; use guillotiere::{size2, Allocation, AtlasAllocator}; @@ -34,13 +34,14 @@ impl DynamicTextureAtlasBuilder { texture_atlas: &mut TextureAtlas, textures: &mut Assets, texture: &Image, + texture_handle: &Handle, ) -> Option { let allocation = self.atlas_allocator.allocate(size2( texture.texture_descriptor.size.width as i32 + self.padding, texture.texture_descriptor.size.height as i32 + self.padding, )); if let Some(allocation) = allocation { - let atlas_texture = textures.get_mut(&texture_atlas.texture).unwrap(); + let atlas_texture = textures.get_mut(texture_handle).unwrap(); self.place_texture(atlas_texture, allocation, texture); let mut rect: Rect = to_rect(allocation.rectangle); rect.max -= self.padding as f32; diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index 403e00722e220..51c3271a35af9 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -15,7 +15,7 @@ pub mod prelude { pub use crate::{ bundle::{SpriteBundle, SpriteSheetBundle}, sprite::Sprite, - texture_atlas::{TextureAtlas, TextureAtlasSprite}, + texture_atlas::{TextureAtlas, TextureSheetIndex}, ColorMaterial, ColorMesh2dBundle, TextureAtlasBuilder, }; } diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 725aab3234df0..c703bdeee63a4 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -1,9 +1,6 @@ use std::cmp::Ordering; -use crate::{ - texture_atlas::{TextureAtlas, TextureAtlasSprite}, - Sprite, SPRITE_SHADER_HANDLE, -}; +use crate::{texture_atlas::TextureAtlas, Rect, Sprite, TextureSheetIndex, SPRITE_SHADER_HANDLE}; use bevy_asset::{AssetEvent, Assets, Handle, HandleId}; use bevy_core_pipeline::{ core_2d::Transparent2d, @@ -348,36 +345,27 @@ pub fn extract_sprite_events( pub fn extract_sprites( mut extracted_sprites: ResMut, texture_atlases: Extract>>, - sprite_query: Extract< - Query<( - Entity, - &ComputedVisibility, - &Sprite, - &GlobalTransform, - &Handle, - )>, - >, - atlas_query: Extract< - Query<( - Entity, - &ComputedVisibility, - &TextureAtlasSprite, - &GlobalTransform, - &Handle, - )>, - >, + sprite_query: Extract)>>, ) { extracted_sprites.sprites.clear(); - for (entity, visibility, sprite, transform, handle) in sprite_query.iter() { - if !visibility.is_visible() { + for (entity, visibility, sprite, transform, handle, atlas, index) in sprite_query.iter() { + if !visibility.is_visible { continue; } + let atlas: Option<&Handle> = atlas; + let rect = atlas.and_then(|h| texture_atlases.get(h)).map(|atlas| { + let index = index.map(|i| i.0).unwrap_or(0); + atlas.textures.get(index).copied().unwrap_or_else(|| { + panic!("TextureAtlas {:?} as no texture at index {}", atlas, index) + }) + }); + // 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.push(ExtractedSprite { entity, color: sprite.color, transform: *transform, - rect: sprite.rect, + rect, // Pass the custom size custom_size: sprite.custom_size, flip_x: sprite.flip_x, @@ -386,38 +374,6 @@ pub fn extract_sprites( anchor: sprite.anchor.as_vec(), }); } - for (entity, visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() { - if !visibility.is_visible() { - continue; - } - if let Some(texture_atlas) = texture_atlases.get(texture_atlas_handle) { - let rect = Some( - *texture_atlas - .textures - .get(atlas_sprite.index) - .unwrap_or_else(|| { - panic!( - "Sprite index {:?} does not exist for texture atlas handle {:?}.", - atlas_sprite.index, - texture_atlas_handle.id(), - ) - }), - ); - extracted_sprites.sprites.push(ExtractedSprite { - entity, - color: atlas_sprite.color, - transform: *transform, - // Select the area in the texture atlas - rect, - // Pass the custom size - custom_size: atlas_sprite.custom_size, - flip_x: atlas_sprite.flip_x, - flip_y: atlas_sprite.flip_y, - image_handle_id: texture_atlas.texture.id(), - anchor: atlas_sprite.anchor.as_vec(), - }); - } - } } #[repr(C)] diff --git a/crates/bevy_sprite/src/texture_atlas.rs b/crates/bevy_sprite/src/texture_atlas.rs index 479e28927e945..685302d068037 100644 --- a/crates/bevy_sprite/src/texture_atlas.rs +++ b/crates/bevy_sprite/src/texture_atlas.rs @@ -1,9 +1,9 @@ -use crate::Anchor; +use crate::Rect; use bevy_asset::Handle; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; -use bevy_math::{Rect, Vec2}; -use bevy_reflect::{FromReflect, Reflect, TypeUuid}; -use bevy_render::{color::Color, texture::Image}; +use bevy_ecs::component::Component; +use bevy_math::Vec2; +use bevy_reflect::{Reflect, TypeUuid}; +use bevy_render::texture::Image; use bevy_utils::HashMap; /// An atlas containing multiple textures (like a spritesheet or a tilemap). @@ -13,8 +13,6 @@ use bevy_utils::HashMap; #[uuid = "7233c597-ccfa-411f-bd59-9af349432ada"] #[reflect(Debug)] pub struct TextureAtlas { - /// The handle to the texture in which the sprites are stored - pub texture: Handle, // TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer pub size: Vec2, /// The specific areas of the atlas where each texture can be found @@ -23,67 +21,44 @@ pub struct TextureAtlas { pub(crate) texture_handles: Option, usize>>, } -#[derive(Component, Debug, Clone, Reflect, FromReflect)] -#[reflect(Component)] -pub struct TextureAtlasSprite { - /// The tint color used to draw the sprite, defaulting to [`Color::WHITE`] - pub color: Color, - /// Texture index in [`TextureAtlas`] - pub index: usize, - /// Whether to flip the sprite in the X axis - pub flip_x: bool, - /// Whether to flip the sprite in the Y axis - pub flip_y: bool, - /// An optional custom size for the sprite that will be used when rendering, instead of the size - /// of the sprite's image in the atlas - pub custom_size: Option, - /// [`Anchor`] point of the sprite in the world - pub anchor: Anchor, -} +#[derive(Component, Default, Debug, Clone, Reflect)] +pub struct TextureSheetIndex(pub usize); -impl Default for TextureAtlasSprite { - fn default() -> Self { - Self { - index: 0, - color: Color::WHITE, - flip_x: false, - flip_y: false, - custom_size: None, - anchor: Anchor::default(), - } +impl TextureSheetIndex { + pub fn new(index: usize) -> Self { + Self(index) } } -impl TextureAtlasSprite { - /// Create a new [`TextureAtlasSprite`] with a sprite index, - /// it should be valid in the corresponding [`TextureAtlas`] - pub fn new(index: usize) -> TextureAtlasSprite { - Self { - index, - ..Default::default() - } +impl From for TextureSheetIndex { + fn from(index: usize) -> Self { + Self(index) } } impl TextureAtlas { /// Create a new [`TextureAtlas`] that has a texture, but does not have /// any individual sprites specified - pub fn new_empty(texture: Handle, dimensions: Vec2) -> Self { + pub fn new_empty(dimensions: Vec2) -> Self { Self { - texture, size: dimensions, texture_handles: None, textures: Vec::new(), } } - /// Generate a [`TextureAtlas`] by splitting a texture into a grid where each + /// Generate a `TextureAtlas` by splitting a texture into a grid where each + /// `tile_size` by `tile_size` grid-cell is one of the textures in the atlas + pub fn from_grid(tile_size: Vec2, columns: usize, rows: usize) -> TextureAtlas { + Self::from_grid_with_padding(tile_size, columns, rows, Vec2::ZERO, Vec2::ZERO) + } + + /// Generate a `TextureAtlas` by splitting a texture into a grid where each /// `tile_size` by `tile_size` grid-cell is one of the textures in the /// atlas. Grid cells are separated by some `padding`, and the grid starts /// at `offset` pixels from the top left corner. The resulting [`TextureAtlas`] is /// indexed left to right, top to bottom. - pub fn from_grid( - texture: Handle, + pub fn from_grid_with_padding( tile_size: Vec2, columns: usize, rows: usize, @@ -120,7 +95,6 @@ impl TextureAtlas { TextureAtlas { size: ((tile_size + current_padding) * grid_size) - current_padding, textures: sprites, - texture, texture_handles: None, } } diff --git a/crates/bevy_sprite/src/texture_atlas_builder.rs b/crates/bevy_sprite/src/texture_atlas_builder.rs index f77e0cce90c31..042b707a0ff8e 100644 --- a/crates/bevy_sprite/src/texture_atlas_builder.rs +++ b/crates/bevy_sprite/src/texture_atlas_builder.rs @@ -136,13 +136,38 @@ impl TextureAtlasBuilder { } } - /// Consumes the builder and returns a result with a new texture atlas. + /// Consumes the builder and returns a result with a new texture atlas and a texture handle. /// /// Internally it copies all rectangles from the textures and copies them /// into a new texture which the texture atlas will use. It is not useful to /// hold a strong handle to the texture afterwards else it will exist twice /// in memory. /// + /// # Usage + /// + /// ```rust + /// # use bevy_sprite::prelude::*; + /// # use bevy_ecs::prelude::*; + /// # use bevy_asset::*; + /// # use bevy_render::prelude::*; + /// + /// fn my_system(mut commands: Commands, mut textures: ResMut>, mut atlases: ResMut>) { + /// // Declare your builder + /// let mut builder = TextureAtlasBuilder::default(); + /// // Customize it + /// // ... + /// // Build your texture + /// let (atlas, texture) = builder.finish(&mut textures).unwrap(); + /// let texture_atlas = atlases.add(atlas); + /// // Spawn your sprite + /// commands.spawn_bundle(SpriteSheetBundle { + /// texture, + /// texture_atlas, + /// ..Default::default() + /// }); + /// } + /// ``` + /// /// # Errors /// /// If there is not enough space in the atlas texture, an error will @@ -150,7 +175,7 @@ impl TextureAtlasBuilder { pub fn finish( self, textures: &mut Assets, - ) -> Result { + ) -> Result<(TextureAtlas, Handle), TextureAtlasBuilderError> { let initial_width = self.initial_size.x as u32; let initial_height = self.initial_size.y as u32; let max_width = self.max_size.x as u32; @@ -227,14 +252,16 @@ impl TextureAtlasBuilder { } self.copy_converted_texture(&mut atlas_texture, texture, packed_location); } - Ok(TextureAtlas { - size: Vec2::new( - atlas_texture.texture_descriptor.size.width as f32, - atlas_texture.texture_descriptor.size.height as f32, - ), - texture: textures.add(atlas_texture), - textures: texture_rects, - texture_handles: Some(texture_handles), - }) + Ok(( + TextureAtlas { + size: Vec2::new( + atlas_texture.texture_descriptor.size.width as f32, + atlas_texture.texture_descriptor.size.height as f32, + ), + textures: texture_rects, + texture_handles: Some(texture_handles), + }, + textures.add(atlas_texture), + )) } } diff --git a/crates/bevy_text/src/font_atlas.rs b/crates/bevy_text/src/font_atlas.rs index be1903c121b36..f1a7413f687fc 100644 --- a/crates/bevy_text/src/font_atlas.rs +++ b/crates/bevy_text/src/font_atlas.rs @@ -43,6 +43,7 @@ pub struct FontAtlas { pub dynamic_texture_atlas_builder: DynamicTextureAtlasBuilder, pub glyph_to_atlas_index: HashMap<(GlyphId, SubpixelOffset), usize>, pub texture_atlas: Handle, + pub texture: Handle, } impl FontAtlas { @@ -51,7 +52,7 @@ impl FontAtlas { texture_atlases: &mut Assets, size: Vec2, ) -> FontAtlas { - let atlas_texture = textures.add(Image::new_fill( + let texture = textures.add(Image::new_fill( Extent3d { width: size.x as u32, height: size.y as u32, @@ -61,11 +62,12 @@ impl FontAtlas { &[0, 0, 0, 0], TextureFormat::Rgba8UnormSrgb, )); - let texture_atlas = TextureAtlas::new_empty(atlas_texture, size); + let texture_atlas = TextureAtlas::new_empty(size); Self { texture_atlas: texture_atlases.add(texture_atlas), glyph_to_atlas_index: HashMap::default(), dynamic_texture_atlas_builder: DynamicTextureAtlasBuilder::new(size, 1), + texture, } } @@ -93,10 +95,12 @@ impl FontAtlas { texture: &Image, ) -> bool { let texture_atlas = texture_atlases.get_mut(&self.texture_atlas).unwrap(); - if let Some(index) = - self.dynamic_texture_atlas_builder - .add_texture(texture_atlas, textures, texture) - { + if let Some(index) = self.dynamic_texture_atlas_builder.add_texture( + texture_atlas, + textures, + texture, + &self.texture, + ) { self.glyph_to_atlas_index .insert((glyph_id, subpixel_offset), index); true diff --git a/crates/bevy_text/src/font_atlas_set.rs b/crates/bevy_text/src/font_atlas_set.rs index b92f664fea22c..23931234a9fbc 100644 --- a/crates/bevy_text/src/font_atlas_set.rs +++ b/crates/bevy_text/src/font_atlas_set.rs @@ -22,6 +22,7 @@ pub struct FontAtlasSet { #[derive(Debug, Clone)] pub struct GlyphAtlasInfo { pub texture_atlas: Handle, + pub texture: Handle, pub glyph_index: usize, } @@ -124,10 +125,17 @@ impl FontAtlasSet { .find_map(|atlas| { atlas .get_glyph_index(glyph_id, position.into()) - .map(|glyph_index| (glyph_index, atlas.texture_atlas.clone_weak())) + .map(|glyph_index| { + ( + glyph_index, + atlas.texture_atlas.clone_weak(), + atlas.texture.clone_weak(), + ) + }) }) - .map(|(glyph_index, texture_atlas)| GlyphAtlasInfo { + .map(|(glyph_index, texture_atlas, texture)| GlyphAtlasInfo { texture_atlas, + texture, glyph_index, }) }) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index a17a1c670950e..f350bd8532bbc 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -123,7 +123,9 @@ pub fn extract_text2d_sprite( color = text.sections[*section_index].style.color.as_rgba_linear(); current_section = *section_index; } - let atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap(); + let atlas = texture_atlases + .get(&text_glyph.atlas_info.texture_atlas) + .unwrap(); extracted_sprites.sprites.push(ExtractedSprite { entity, diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f203c4b227565..1be78b72cbdf4 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -321,7 +321,9 @@ pub fn extract_text_uinodes( color = text.sections[*section_index].style.color.as_rgba_linear(); current_section = *section_index; } - let atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap(); + let atlas = texture_atlases + .get(&text_glyph.atlas_info.texture_atlas) + .unwrap(); let mut rect = atlas.textures[atlas_info.glyph_index]; rect.min *= inverse_scale_factor; diff --git a/examples/2d/sprite_sheet.rs b/examples/2d/sprite_sheet.rs index 66a4095a189cd..d17e3df88815d 100644 --- a/examples/2d/sprite_sheet.rs +++ b/examples/2d/sprite_sheet.rs @@ -25,7 +25,8 @@ fn animate_sprite( mut query: Query<( &AnimationIndices, &mut AnimationTimer, - &mut TextureAtlasSprite, + &mut TextureSheetIndex, + &Handle, )>, ) { for (indices, mut timer, mut sprite) in &mut query { @@ -45,17 +46,16 @@ fn setup( asset_server: Res, mut texture_atlases: ResMut>, ) { - let texture_handle = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png"); - let texture_atlas = - TextureAtlas::from_grid(texture_handle, Vec2::new(24.0, 24.0), 7, 1, None, None); - let texture_atlas_handle = texture_atlases.add(texture_atlas); + let texture = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png"); + let atlas = TextureAtlas::from_grid(Vec2::new(24.0, 24.0), 7, 1); + let texture_atlas = texture_atlases.add(atlas); // Use only the subset of sprites in the sheet that make up the run animation let animation_indices = AnimationIndices { first: 1, last: 6 }; - commands.spawn(Camera2dBundle::default()); - commands.spawn(( - SpriteSheetBundle { - texture_atlas: texture_atlas_handle, - sprite: TextureAtlasSprite::new(animation_indices.first), + commands.spawn_bundle(Camera2dBundle::default()); + commands + .spawn_bundle(SpriteSheetBundle { + texture, + texture_atlas, transform: Transform::from_scale(Vec3::splat(6.0)), ..default() }, diff --git a/examples/2d/texture_atlas.rs b/examples/2d/texture_atlas.rs index b1f6cb21137fc..ca417ad6ecf5c 100644 --- a/examples/2d/texture_atlas.rs +++ b/examples/2d/texture_atlas.rs @@ -63,8 +63,8 @@ fn setup( texture_atlas_builder.add_texture(handle, texture); } - let texture_atlas = texture_atlas_builder.finish(&mut textures).unwrap(); - let texture_atlas_texture = texture_atlas.texture.clone(); + let (texture_atlas, texture_atlas_texture) = + texture_atlas_builder.finish(&mut textures).unwrap(); let vendor_handle = asset_server.get_handle("textures/rpg/chars/vendor/generic-rpg-vendor.png"); let vendor_index = texture_atlas.get_texture_index(&vendor_handle).unwrap(); let atlas_handle = texture_atlases.add(texture_atlas); @@ -78,7 +78,7 @@ fn setup( scale: Vec3::splat(4.0), ..default() }, - sprite: TextureAtlasSprite::new(vendor_index), + index: vendor_index.into(), texture_atlas: atlas_handle, ..default() }); diff --git a/examples/ui/font_atlas_debug.rs b/examples/ui/font_atlas_debug.rs index 54f1fe42f975d..ad70110e120cb 100644 --- a/examples/ui/font_atlas_debug.rs +++ b/examples/ui/font_atlas_debug.rs @@ -34,7 +34,6 @@ fn atlas_render_system( mut commands: Commands, mut state: ResMut, font_atlas_sets: Res>, - texture_atlases: Res>, ) { if let Some(set) = font_atlas_sets.get(&state.handle.cast_weak::()) { if let Some((_size, font_atlas)) = set.iter().next() { @@ -42,12 +41,10 @@ fn atlas_render_system( if state.atlas_count == font_atlas.len() as u32 { return; } - let texture_atlas = texture_atlases - .get(&font_atlas[state.atlas_count as usize].texture_atlas) - .unwrap(); + let font_atlas = &font_atlas[state.atlas_count as usize]; state.atlas_count += 1; - commands.spawn(ImageBundle { - image: texture_atlas.texture.clone().into(), + commands.spawn_bundle(ImageBundle { + image: font_atlas.texture.clone().into(), style: Style { position_type: PositionType::Absolute, top: Val::Px(0.0), From c18c9e40af720ded12e7d480e46ae9d90cde718f Mon Sep 17 00:00:00 2001 From: Felix de Maneville Date: Sat, 10 Dec 2022 18:18:46 +0100 Subject: [PATCH 02/10] Unify SpriteBundle and SpriteSheetBundle Co-authored-by: Alice Cecile --- crates/bevy_sprite/src/bundle.rs | 18 +-- .../src/dynamic_texture_atlas_builder.rs | 4 +- crates/bevy_sprite/src/lib.rs | 10 +- crates/bevy_sprite/src/render/mod.rs | 27 ++-- crates/bevy_sprite/src/texture_atlas.rs | 150 ++++-------------- .../bevy_sprite/src/texture_atlas_builder.rs | 19 ++- .../bevy_sprite/src/texture_atlas_layout.rs | 104 ++++++++++++ crates/bevy_text/src/font_atlas.rs | 10 +- crates/bevy_text/src/font_atlas_set.rs | 6 +- crates/bevy_text/src/glyph_brush.rs | 4 +- crates/bevy_text/src/pipeline.rs | 4 +- crates/bevy_text/src/text2d.rs | 6 +- crates/bevy_ui/src/render/mod.rs | 4 +- crates/bevy_ui/src/widget/text.rs | 4 +- examples/2d/sprite_sheet.rs | 18 ++- examples/2d/texture_atlas.rs | 8 +- .../stress_tests/many_animated_sprites.rs | 33 ++-- examples/ui/font_atlas_debug.rs | 2 +- 18 files changed, 227 insertions(+), 204 deletions(-) create mode 100644 crates/bevy_sprite/src/texture_atlas_layout.rs diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index caba3ec919b78..f52e0f82bd356 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -1,4 +1,4 @@ -use crate::{texture_atlas::TextureAtlas, Sprite, TextureSheetIndex}; +use crate::{Sprite, TextureAtlas}; use bevy_asset::Handle; use bevy_ecs::bundle::Bundle; use bevy_render::{ @@ -33,19 +33,19 @@ impl Default for SpriteBundle { } /// A Bundle of components for drawing a single sprite from a sprite sheet (also referred -/// to as a `TextureAtlas`) +/// to as a `TextureAtlas`) or for animated sprites. +/// +/// Note: +/// This bundle is identical to [`SpriteBundle`] with an additional [`TextureAtlas`] component. #[derive(Bundle, Clone, Default)] pub struct SpriteSheetBundle { pub sprite: Sprite, - /// The sprite sheet texture - pub texture: Handle, - /// A handle to the texture atlas that holds the sprite images - pub texture_atlas: Handle, - /// The texture sheet sprite index - pub index: TextureSheetIndex, - /// Data pertaining to how the sprite is drawn on the screen pub transform: Transform, pub global_transform: GlobalTransform, + /// The sprite sheet base texture + pub texture: Handle, + /// The sprite sheet texture atlas and the section to draw + pub atlas: TextureAtlas, /// User indication of whether an entity is visible pub visibility: Visibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering diff --git a/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs b/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs index f8a09552b9bb7..a1911fec57a7d 100644 --- a/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs +++ b/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs @@ -1,4 +1,4 @@ -use crate::{Rect, TextureAtlas}; +use crate::TextureAtlasLayout; use bevy_asset::{Assets, Handle}; use bevy_math::{IVec2, Rect, Vec2}; use bevy_render::texture::{Image, TextureFormatPixelInfo}; @@ -31,7 +31,7 @@ impl DynamicTextureAtlasBuilder { /// It is user's responsibility to pass in the correct [`TextureAtlas`] pub fn add_texture( &mut self, - texture_atlas: &mut TextureAtlas, + texture_atlas: &mut TextureAtlasLayout, textures: &mut Assets, texture: &Image, texture_handle: &Handle, diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index 51c3271a35af9..7bfa6519ece81 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -7,6 +7,7 @@ mod render; mod sprite; mod texture_atlas; mod texture_atlas_builder; +mod texture_atlas_layout; pub mod collide_aabb; @@ -15,7 +16,8 @@ pub mod prelude { pub use crate::{ bundle::{SpriteBundle, SpriteSheetBundle}, sprite::Sprite, - texture_atlas::{TextureAtlas, TextureSheetIndex}, + texture_atlas::TextureAtlas, + texture_atlas_layout::TextureAtlasLayout, ColorMaterial, ColorMesh2dBundle, TextureAtlasBuilder, }; } @@ -27,6 +29,7 @@ pub use render::*; pub use sprite::*; pub use texture_atlas::*; pub use texture_atlas_builder::*; +pub use texture_atlas_layout::*; use bevy_app::prelude::*; use bevy_asset::{AddAsset, Assets, Handle, HandleUntyped}; @@ -59,11 +62,12 @@ impl Plugin for SpritePlugin { let mut shaders = app.world.resource_mut::>(); let sprite_shader = Shader::from_wgsl(include_str!("render/sprite.wgsl")); shaders.set_untracked(SPRITE_SHADER_HANDLE, sprite_shader); - app.add_asset::() - .register_asset_reflect::() + app.add_asset::() + .register_asset_reflect::() .register_type::() .register_type::() .register_type::() + .register_type::() .register_type::() .add_plugin(Mesh2dRenderPlugin) .add_plugin(ColorMaterialPlugin) diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index c703bdeee63a4..fcfb22f84127d 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use crate::{texture_atlas::TextureAtlas, Rect, Sprite, TextureSheetIndex, SPRITE_SHADER_HANDLE}; +use crate::{Sprite, TextureAtlas, TextureAtlasLayout, SPRITE_SHADER_HANDLE}; use bevy_asset::{AssetEvent, Assets, Handle, HandleId}; use bevy_core_pipeline::{ core_2d::Transparent2d, @@ -344,21 +344,24 @@ pub fn extract_sprite_events( pub fn extract_sprites( mut extracted_sprites: ResMut, - texture_atlases: Extract>>, - sprite_query: Extract)>>, + texture_atlases: Extract>>, + sprite_query: Extract< + Query<( + Entity, + &ComputedVisibility, + &Sprite, + &GlobalTransform, + &Handle, + Option<&TextureAtlas>, + )>, + >, ) { extracted_sprites.sprites.clear(); - for (entity, visibility, sprite, transform, handle, atlas, index) in sprite_query.iter() { - if !visibility.is_visible { + for (entity, visibility, sprite, transform, handle, sheet) in sprite_query.iter() { + if !visibility.is_visible() { continue; } - let atlas: Option<&Handle> = atlas; - let rect = atlas.and_then(|h| texture_atlases.get(h)).map(|atlas| { - let index = index.map(|i| i.0).unwrap_or(0); - atlas.textures.get(index).copied().unwrap_or_else(|| { - panic!("TextureAtlas {:?} as no texture at index {}", atlas, index) - }) - }); + let rect = sheet.and_then(|s| s.texture_rect(&texture_atlases)); // 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.push(ExtractedSprite { diff --git a/crates/bevy_sprite/src/texture_atlas.rs b/crates/bevy_sprite/src/texture_atlas.rs index 685302d068037..fe0762d05d9e3 100644 --- a/crates/bevy_sprite/src/texture_atlas.rs +++ b/crates/bevy_sprite/src/texture_atlas.rs @@ -1,130 +1,40 @@ -use crate::Rect; -use bevy_asset::Handle; +use crate::TextureAtlasLayout; +use bevy_asset::{Assets, Handle}; use bevy_ecs::component::Component; -use bevy_math::Vec2; -use bevy_reflect::{Reflect, TypeUuid}; -use bevy_render::texture::Image; -use bevy_utils::HashMap; - -/// An atlas containing multiple textures (like a spritesheet or a tilemap). -/// [Example usage animating sprite.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs) -/// [Example usage loading sprite sheet.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs) -#[derive(Reflect, FromReflect, Debug, Clone, TypeUuid)] -#[uuid = "7233c597-ccfa-411f-bd59-9af349432ada"] -#[reflect(Debug)] -pub struct TextureAtlas { - // TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer - pub size: Vec2, - /// The specific areas of the atlas where each texture can be found - pub textures: Vec, - /// Mapping from texture handle to index - pub(crate) texture_handles: Option, usize>>, -} - +use bevy_math::Rect; +use bevy_reflect::Reflect; + +/// Component used to draw a specific section of a texture. +/// +/// It stores a handle to [`TextureAtlasLayout`] and the index of the current section of the atlas. +/// The texture atlas contains various *sections* or *cuts* of a given texture, allowing users to have a single +/// image file for either sprite animation or global mapping. +/// You can change the texture [`index`](Self::index) of the atlas to animate the sprite or to pick a *section* of the texture. +/// +/// Check the following examples for usage: +/// - [`animated sprite sheet example`](https://github.com/bevyengine/bevy/blob/main/examples/2d/sprite_sheet.rs) +/// - [`texture atlas example`](https://github.com/bevyengine/bevy/blob/main/examples/2d/texture_atlas.rs) #[derive(Component, Default, Debug, Clone, Reflect)] -pub struct TextureSheetIndex(pub usize); - -impl TextureSheetIndex { - pub fn new(index: usize) -> Self { - Self(index) - } -} - -impl From for TextureSheetIndex { - fn from(index: usize) -> Self { - Self(index) - } +pub struct TextureAtlas { + /// Texture atlas handle + pub layout: Handle, + /// Texture atlas section index + pub index: usize, } -impl TextureAtlas { - /// Create a new [`TextureAtlas`] that has a texture, but does not have - /// any individual sprites specified - pub fn new_empty(dimensions: Vec2) -> Self { +impl From> for TextureAtlas { + fn from(texture_atlas: Handle) -> Self { Self { - size: dimensions, - texture_handles: None, - textures: Vec::new(), + layout: texture_atlas, + index: 0, } } +} - /// Generate a `TextureAtlas` by splitting a texture into a grid where each - /// `tile_size` by `tile_size` grid-cell is one of the textures in the atlas - pub fn from_grid(tile_size: Vec2, columns: usize, rows: usize) -> TextureAtlas { - Self::from_grid_with_padding(tile_size, columns, rows, Vec2::ZERO, Vec2::ZERO) - } - - /// Generate a `TextureAtlas` by splitting a texture into a grid where each - /// `tile_size` by `tile_size` grid-cell is one of the textures in the - /// atlas. Grid cells are separated by some `padding`, and the grid starts - /// at `offset` pixels from the top left corner. The resulting [`TextureAtlas`] is - /// indexed left to right, top to bottom. - pub fn from_grid_with_padding( - tile_size: Vec2, - columns: usize, - rows: usize, - padding: Option, - offset: Option, - ) -> TextureAtlas { - let padding = padding.unwrap_or_default(); - let offset = offset.unwrap_or_default(); - let mut sprites = Vec::new(); - let mut current_padding = Vec2::ZERO; - - for y in 0..rows { - if y > 0 { - current_padding.y = padding.y; - } - for x in 0..columns { - if x > 0 { - current_padding.x = padding.x; - } - - let cell = Vec2::new(x as f32, y as f32); - - let rect_min = (tile_size + current_padding) * cell + offset; - - sprites.push(Rect { - min: rect_min, - max: rect_min + tile_size, - }); - } - } - - let grid_size = Vec2::new(columns as f32, rows as f32); - - TextureAtlas { - size: ((tile_size + current_padding) * grid_size) - current_padding, - textures: sprites, - texture_handles: None, - } - } - - /// Add a sprite to the list of textures in the [`TextureAtlas`] - /// returns an index to the texture which can be used with [`TextureAtlasSprite`] - /// - /// # Arguments - /// - /// * `rect` - The section of the atlas that contains the texture to be added, - /// from the top-left corner of the texture to the bottom-right corner - pub fn add_texture(&mut self, rect: Rect) -> usize { - self.textures.push(rect); - self.textures.len() - 1 - } - - /// The number of textures in the [`TextureAtlas`] - pub fn len(&self) -> usize { - self.textures.len() - } - - /// Returns `true` if there are no textures in the [`TextureAtlas`] - pub fn is_empty(&self) -> bool { - self.textures.is_empty() - } - - /// Returns the index of the texture corresponding to the given image handle in the [`TextureAtlas`] - pub fn get_texture_index(&self, texture: &Handle) -> Option { - self.texture_handles - .as_ref() - .and_then(|texture_handles| texture_handles.get(texture).cloned()) +impl TextureAtlas { + /// Retrieves the current texture [`Rect`] of the sprite sheet according to the section `index` + pub fn texture_rect(&self, texture_atlases: &Assets) -> Option { + let atlas = texture_atlases.get(&self.layout)?; + atlas.textures.get(self.index).copied() } } diff --git a/crates/bevy_sprite/src/texture_atlas_builder.rs b/crates/bevy_sprite/src/texture_atlas_builder.rs index 042b707a0ff8e..37840c5daccba 100644 --- a/crates/bevy_sprite/src/texture_atlas_builder.rs +++ b/crates/bevy_sprite/src/texture_atlas_builder.rs @@ -12,7 +12,7 @@ use rectangle_pack::{ }; use thiserror::Error; -use crate::texture_atlas::TextureAtlas; +use crate::TextureAtlasLayout; #[derive(Debug, Error)] pub enum TextureAtlasBuilderError { @@ -151,18 +151,21 @@ impl TextureAtlasBuilder { /// # use bevy_asset::*; /// # use bevy_render::prelude::*; /// - /// fn my_system(mut commands: Commands, mut textures: ResMut>, mut atlases: ResMut>) { + /// fn my_system(mut commands: Commands, mut textures: ResMut>, mut layouts: ResMut>) { /// // Declare your builder /// let mut builder = TextureAtlasBuilder::default(); /// // Customize it /// // ... /// // Build your texture - /// let (atlas, texture) = builder.finish(&mut textures).unwrap(); - /// let texture_atlas = atlases.add(atlas); + /// let (atlas_layout, texture) = builder.finish(&mut textures).unwrap(); + /// let layout = layouts.add(atlas_layout); /// // Spawn your sprite - /// commands.spawn_bundle(SpriteSheetBundle { + /// commands.spawn(SpriteSheetBundle { /// texture, - /// texture_atlas, + /// atlas: TextureAtlas { + /// layout, + /// index: 0 + /// }, /// ..Default::default() /// }); /// } @@ -175,7 +178,7 @@ impl TextureAtlasBuilder { pub fn finish( self, textures: &mut Assets, - ) -> Result<(TextureAtlas, Handle), TextureAtlasBuilderError> { + ) -> Result<(TextureAtlasLayout, Handle), TextureAtlasBuilderError> { let initial_width = self.initial_size.x as u32; let initial_height = self.initial_size.y as u32; let max_width = self.max_size.x as u32; @@ -253,7 +256,7 @@ impl TextureAtlasBuilder { self.copy_converted_texture(&mut atlas_texture, texture, packed_location); } Ok(( - TextureAtlas { + TextureAtlasLayout { size: Vec2::new( atlas_texture.texture_descriptor.size.width as f32, atlas_texture.texture_descriptor.size.height as f32, diff --git a/crates/bevy_sprite/src/texture_atlas_layout.rs b/crates/bevy_sprite/src/texture_atlas_layout.rs new file mode 100644 index 0000000000000..9f0f685c1bd43 --- /dev/null +++ b/crates/bevy_sprite/src/texture_atlas_layout.rs @@ -0,0 +1,104 @@ +use bevy_asset::Handle; +use bevy_math::{Rect, Vec2}; +use bevy_reflect::{FromReflect, Reflect, TypeUuid}; +use bevy_render::texture::Image; +use bevy_utils::HashMap; + +/// An atlas containing multiple textures (like a spritesheet or a tilemap). +/// [Example usage animating sprite.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs) +/// [Example usage loading sprite sheet.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs) +#[derive(Reflect, FromReflect, Debug, Clone, TypeUuid)] +#[uuid = "7233c597-ccfa-411f-bd59-9af349432ada"] +#[reflect(Debug)] +pub struct TextureAtlasLayout { + // TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer + pub size: Vec2, + /// The specific areas of the atlas where each texture can be found + pub textures: Vec, + pub texture_handles: Option, usize>>, +} + +impl TextureAtlasLayout { + /// Create a new `TextureAtlas` that has a texture, but does not have + /// any individual sprites specified + pub fn new_empty(dimensions: Vec2) -> Self { + Self { + size: dimensions, + texture_handles: None, + textures: Vec::new(), + } + } + + /// Generate a `TextureAtlas` by splitting a texture into a grid where each + /// `tile_size` by `tile_size` grid-cell is one of the textures in the + /// atlas. Grid cells are separated by some `padding`, and the grid starts + /// at `offset` pixels from the top left corner. Resulting `TextureAtlas` is + /// indexed left to right, top to bottom. + pub fn from_grid( + tile_size: Vec2, + columns: usize, + rows: usize, + padding: Option, + offset: Option, + ) -> Self { + let padding = padding.unwrap_or_default(); + let offset = offset.unwrap_or_default(); + let mut sprites = Vec::new(); + let mut current_padding = Vec2::ZERO; + + for y in 0..rows { + if y > 0 { + current_padding.y = padding.y; + } + for x in 0..columns { + if x > 0 { + current_padding.x = padding.x; + } + + let cell = Vec2::new(x as f32, y as f32); + + let rect_min = (tile_size + current_padding) * cell + offset; + + sprites.push(Rect { + min: rect_min, + max: rect_min + tile_size, + }); + } + } + + let grid_size = Vec2::new(columns as f32, rows as f32); + + Self { + size: ((tile_size + current_padding) * grid_size) - current_padding, + textures: sprites, + texture_handles: None, + } + } + + /// Add a sprite to the list of textures in the `TextureAtlas` + /// returns an index to the texture which can be used with `TextureAtlasSprite` + /// + /// # Arguments + /// + /// * `rect` - The section of the atlas that contains the texture to be added, + /// from the top-left corner of the texture to the bottom-right corner + pub fn add_texture(&mut self, rect: Rect) -> usize { + self.textures.push(rect); + self.textures.len() - 1 + } + + /// How many textures are in the `TextureAtlas` + pub fn len(&self) -> usize { + self.textures.len() + } + + pub fn is_empty(&self) -> bool { + self.textures.is_empty() + } + + pub fn get_texture_index(&self, texture: &Handle) -> Option { + self.texture_handles + .as_ref() + .and_then(|texture_handles| texture_handles.get(texture).cloned()) + } +} diff --git a/crates/bevy_text/src/font_atlas.rs b/crates/bevy_text/src/font_atlas.rs index f1a7413f687fc..38c71a1614b7f 100644 --- a/crates/bevy_text/src/font_atlas.rs +++ b/crates/bevy_text/src/font_atlas.rs @@ -5,7 +5,7 @@ use bevy_render::{ render_resource::{Extent3d, TextureDimension, TextureFormat}, texture::Image, }; -use bevy_sprite::{DynamicTextureAtlasBuilder, TextureAtlas}; +use bevy_sprite::{DynamicTextureAtlasBuilder, TextureAtlasLayout}; use bevy_utils::HashMap; #[cfg(feature = "subpixel_glyph_atlas")] @@ -42,14 +42,14 @@ impl From for SubpixelOffset { pub struct FontAtlas { pub dynamic_texture_atlas_builder: DynamicTextureAtlasBuilder, pub glyph_to_atlas_index: HashMap<(GlyphId, SubpixelOffset), usize>, - pub texture_atlas: Handle, + pub texture_atlas: Handle, pub texture: Handle, } impl FontAtlas { pub fn new( textures: &mut Assets, - texture_atlases: &mut Assets, + texture_atlases: &mut Assets, size: Vec2, ) -> FontAtlas { let texture = textures.add(Image::new_fill( @@ -62,7 +62,7 @@ impl FontAtlas { &[0, 0, 0, 0], TextureFormat::Rgba8UnormSrgb, )); - let texture_atlas = TextureAtlas::new_empty(size); + let texture_atlas = TextureAtlasLayout::new_empty(size); Self { texture_atlas: texture_atlases.add(texture_atlas), glyph_to_atlas_index: HashMap::default(), @@ -89,7 +89,7 @@ impl FontAtlas { pub fn add_glyph( &mut self, textures: &mut Assets, - texture_atlases: &mut Assets, + texture_atlases: &mut Assets, glyph_id: GlyphId, subpixel_offset: SubpixelOffset, texture: &Image, diff --git a/crates/bevy_text/src/font_atlas_set.rs b/crates/bevy_text/src/font_atlas_set.rs index 23931234a9fbc..acf4f746d8e52 100644 --- a/crates/bevy_text/src/font_atlas_set.rs +++ b/crates/bevy_text/src/font_atlas_set.rs @@ -4,7 +4,7 @@ use bevy_asset::{Assets, Handle}; use bevy_math::Vec2; use bevy_reflect::TypeUuid; use bevy_render::texture::Image; -use bevy_sprite::TextureAtlas; +use bevy_sprite::TextureAtlasLayout; use bevy_utils::FloatOrd; use bevy_utils::HashMap; @@ -21,7 +21,7 @@ pub struct FontAtlasSet { #[derive(Debug, Clone)] pub struct GlyphAtlasInfo { - pub texture_atlas: Handle, + pub texture_atlas: Handle, pub texture: Handle, pub glyph_index: usize, } @@ -52,7 +52,7 @@ impl FontAtlasSet { pub fn add_glyph_to_atlas( &mut self, - texture_atlases: &mut Assets, + texture_atlases: &mut Assets, textures: &mut Assets, outlined_glyph: OutlinedGlyph, ) -> Result { diff --git a/crates/bevy_text/src/glyph_brush.rs b/crates/bevy_text/src/glyph_brush.rs index 9b17f09a7b910..2f830702fa426 100644 --- a/crates/bevy_text/src/glyph_brush.rs +++ b/crates/bevy_text/src/glyph_brush.rs @@ -2,7 +2,7 @@ use ab_glyph::{Font as _, FontArc, Glyph, ScaleFont as _}; use bevy_asset::{Assets, Handle}; use bevy_math::Vec2; use bevy_render::texture::Image; -use bevy_sprite::TextureAtlas; +use bevy_sprite::TextureAtlasLayout; use bevy_utils::tracing::warn; use glyph_brush_layout::{ BuiltInLineBreaker, FontId, GlyphPositioner, Layout, SectionGeometry, SectionGlyph, @@ -59,7 +59,7 @@ impl GlyphBrush { sections: &[SectionText], font_atlas_set_storage: &mut Assets, fonts: &Assets, - texture_atlases: &mut Assets, + texture_atlases: &mut Assets, textures: &mut Assets, text_settings: &TextSettings, font_atlas_warning: &mut FontAtlasWarning, diff --git a/crates/bevy_text/src/pipeline.rs b/crates/bevy_text/src/pipeline.rs index e71e49c030e67..82edfecd0e029 100644 --- a/crates/bevy_text/src/pipeline.rs +++ b/crates/bevy_text/src/pipeline.rs @@ -4,7 +4,7 @@ use bevy_ecs::component::Component; use bevy_ecs::system::Resource; use bevy_math::Vec2; use bevy_render::texture::Image; -use bevy_sprite::TextureAtlas; +use bevy_sprite::TextureAtlasLayout; use bevy_utils::HashMap; use glyph_brush_layout::{FontId, GlyphPositioner, SectionGeometry, SectionText}; @@ -48,7 +48,7 @@ impl TextPipeline { linebreak_behavior: BreakLineOn, bounds: Vec2, font_atlas_set_storage: &mut Assets, - texture_atlases: &mut Assets, + texture_atlases: &mut Assets, textures: &mut Assets, text_settings: &TextSettings, font_atlas_warning: &mut FontAtlasWarning, diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index f350bd8532bbc..d9c3bbbacd1c3 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -17,7 +17,7 @@ use bevy_render::{ view::{ComputedVisibility, Visibility}, Extract, }; -use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas}; +use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlasLayout}; use bevy_transform::prelude::{GlobalTransform, Transform}; use bevy_utils::HashSet; use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged}; @@ -78,7 +78,7 @@ pub struct Text2dBundle { pub fn extract_text2d_sprite( mut extracted_sprites: ResMut, - texture_atlases: Extract>>, + texture_atlases: Extract>>, windows: Extract>>, text2d_query: Extract< Query<( @@ -159,7 +159,7 @@ pub fn update_text2d_layout( mut font_atlas_warning: ResMut, windows: Query<&Window, With>, mut scale_factor_changed: EventReader, - mut texture_atlases: ResMut>, + mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, mut text_query: Query<(Entity, Ref, Ref, &mut TextLayoutInfo)>, diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 1be78b72cbdf4..ecf65c17c77e7 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -29,7 +29,7 @@ use bevy_render::{ }; use bevy_sprite::SpriteAssetEvents; #[cfg(feature = "bevy_text")] -use bevy_sprite::TextureAtlas; +use bevy_sprite::{TextureAtlas, TextureAtlasLayout}; #[cfg(feature = "bevy_text")] use bevy_text::{PositionedGlyph, Text, TextLayoutInfo}; use bevy_transform::components::GlobalTransform; @@ -275,7 +275,7 @@ pub fn extract_default_ui_camera_view( #[cfg(feature = "bevy_text")] pub fn extract_text_uinodes( mut extracted_uinodes: ResMut, - texture_atlases: Extract>>, + texture_atlases: Extract>>, windows: Extract>>, ui_stack: Extract>, uinode_query: Extract< diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index c56ae98bc5997..4aa2e65125f4c 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ use bevy_math::Vec2; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::texture::Image; -use bevy_sprite::TextureAtlas; +use bevy_sprite::TextureAtlasLayout; use bevy_text::{ Font, FontAtlasSet, FontAtlasWarning, Text, TextError, TextLayoutInfo, TextMeasureInfo, TextPipeline, TextSettings, YAxisOrientation, @@ -221,7 +221,7 @@ pub fn text_system( text_settings: Res, mut font_atlas_warning: ResMut, ui_scale: Res, - mut texture_atlases: ResMut>, + mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, mut text_query: Query<(Ref, &Text, &mut TextLayoutInfo, &mut TextFlags)>, diff --git a/examples/2d/sprite_sheet.rs b/examples/2d/sprite_sheet.rs index d17e3df88815d..098dddeb08206 100644 --- a/examples/2d/sprite_sheet.rs +++ b/examples/2d/sprite_sheet.rs @@ -25,17 +25,16 @@ fn animate_sprite( mut query: Query<( &AnimationIndices, &mut AnimationTimer, - &mut TextureSheetIndex, - &Handle, + &mut TextureAtlas, )>, ) { - for (indices, mut timer, mut sprite) in &mut query { + for (indices, mut timer, mut atlas) in &mut query { timer.tick(time.delta()); if timer.just_finished() { - sprite.index = if sprite.index == indices.last { + atlas.index = if atlas.index == indices.last { indices.first } else { - sprite.index + 1 + atlas.index + 1 }; } } @@ -44,10 +43,10 @@ fn animate_sprite( fn setup( mut commands: Commands, asset_server: Res, - mut texture_atlases: ResMut>, + mut texture_atlases: ResMut>, ) { let texture = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png"); - let atlas = TextureAtlas::from_grid(Vec2::new(24.0, 24.0), 7, 1); + let atlas = TextureAtlasLayout::from_grid(Vec2::new(24.0, 24.0), 7, 1, None, None); let texture_atlas = texture_atlases.add(atlas); // Use only the subset of sprites in the sheet that make up the run animation let animation_indices = AnimationIndices { first: 1, last: 6 }; @@ -55,7 +54,10 @@ fn setup( commands .spawn_bundle(SpriteSheetBundle { texture, - texture_atlas, + atlas: TextureAtlas { + layout: texture_atlas, + index: 0, + }, transform: Transform::from_scale(Vec3::splat(6.0)), ..default() }, diff --git a/examples/2d/texture_atlas.rs b/examples/2d/texture_atlas.rs index ca417ad6ecf5c..f52561f175ca0 100644 --- a/examples/2d/texture_atlas.rs +++ b/examples/2d/texture_atlas.rs @@ -48,7 +48,7 @@ fn setup( mut commands: Commands, rpg_sprite_handles: Res, asset_server: Res, - mut texture_atlases: ResMut>, + mut texture_atlases: ResMut>, mut textures: ResMut>, ) { // Build a `TextureAtlas` using the individual sprites @@ -78,8 +78,10 @@ fn setup( scale: Vec3::splat(4.0), ..default() }, - index: vendor_index.into(), - texture_atlas: atlas_handle, + atlas: TextureAtlas { + index: vendor_index, + layout: atlas_handle, + }, ..default() }); // draw the atlas itself diff --git a/examples/stress_tests/many_animated_sprites.rs b/examples/stress_tests/many_animated_sprites.rs index e6286c39c7f0c..a693cf8d720e9 100644 --- a/examples/stress_tests/many_animated_sprites.rs +++ b/examples/stress_tests/many_animated_sprites.rs @@ -44,7 +44,7 @@ fn main() { fn setup( mut commands: Commands, assets: Res, - mut texture_atlases: ResMut>, + mut texture_atlases: ResMut>, ) { warn!(include_str!("warning_string.txt")); @@ -57,8 +57,7 @@ fn setup( let half_y = (map_size.y / 2.0) as i32; let texture_handle = assets.load("textures/rpg/chars/gabe/gabe-idle-run.png"); - let texture_atlas = - TextureAtlas::from_grid(texture_handle, Vec2::new(24.0, 24.0), 7, 1, None, None); + let texture_atlas = TextureAtlasLayout::from_grid(Vec2::new(24.0, 24.0), 7, 1, None, None); let texture_atlas_handle = texture_atlases.add(texture_atlas); // Spawns the camera @@ -77,13 +76,17 @@ fn setup( commands.spawn(( SpriteSheetBundle { - texture_atlas: texture_atlas_handle.clone(), + texture: texture_handle.clone(), + atlas: TextureAtlas { + layout: texture_atlas_handle.clone(), + ..Default::default() + }, transform: Transform { translation, rotation, scale, }, - sprite: TextureAtlasSprite { + sprite: Sprite { custom_size: Some(tile_size), ..default() }, @@ -108,18 +111,14 @@ struct AnimationTimer(Timer); fn animate_sprite( time: Res