Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move TextureAtlas into UiImage and remove impl Component for TextureAtlas #16072

Merged
merged 1 commit into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions crates/bevy_sprite/src/texture_atlas.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use bevy_asset::{Asset, AssetId, Assets, Handle};
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_math::{URect, UVec2};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
#[cfg(feature = "serialize")]
Expand Down Expand Up @@ -152,7 +151,7 @@ impl TextureAtlasLayout {
}
}

/// Component used to draw a specific section of a texture.
/// An index into a [`TextureAtlasLayout`], which corresponds to 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* of a given texture, allowing users to have a single
Expand All @@ -164,8 +163,8 @@ impl TextureAtlasLayout {
/// - [`animated sprite sheet example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs)
/// - [`sprite animation event example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_animation.rs)
/// - [`texture atlas example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs)
#[derive(Component, Default, Debug, Clone, Reflect)]
#[reflect(Component, Default, Debug)]
#[derive(Default, Debug, Clone, Reflect)]
#[reflect(Default, Debug)]
pub struct TextureAtlas {
/// Texture atlas layout handle
pub layout: Handle<TextureAtlasLayout>,
Expand Down
13 changes: 7 additions & 6 deletions crates/bevy_ui/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use bevy_render::{
ExtractSchedule, Render,
};
use bevy_sprite::TextureAtlasLayout;
use bevy_sprite::{BorderRect, ImageScaleMode, SpriteAssetEvents, TextureAtlas};
use bevy_sprite::{BorderRect, ImageScaleMode, SpriteAssetEvents};

use bevy_text::{ComputedTextBlock, PositionedGlyph, TextColor, TextLayoutInfo};
use bevy_transform::components::GlobalTransform;
Expand Down Expand Up @@ -316,14 +316,13 @@ pub fn extract_uinode_images(
Option<&CalculatedClip>,
Option<&TargetCamera>,
&UiImage,
Option<&TextureAtlas>,
),
Without<ImageScaleMode>,
>,
>,
mapping: Extract<Query<RenderEntity>>,
) {
for (entity, uinode, transform, view_visibility, clip, camera, image, atlas) in &uinode_query {
for (entity, uinode, transform, view_visibility, clip, camera, image) in &uinode_query {
let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get())
else {
continue;
Expand All @@ -336,12 +335,14 @@ pub fn extract_uinode_images(
// Skip invisible images
if !view_visibility.get()
|| image.color.is_fully_transparent()
|| image.texture.id() == TRANSPARENT_IMAGE_HANDLE.id()
|| image.image.id() == TRANSPARENT_IMAGE_HANDLE.id()
{
continue;
}

let atlas_rect = atlas
let atlas_rect = image
.texture_atlas
.as_ref()
.and_then(|s| s.texture_rect(&texture_atlases))
.map(|r| r.as_rect());

Expand Down Expand Up @@ -375,7 +376,7 @@ pub fn extract_uinode_images(
color: image.color.into(),
rect,
clip: clip.map(|clip| clip.clip),
image: image.texture.id(),
image: image.image.id(),
camera_entity: render_camera_entity,
item: ExtractedUiItem::Node {
atlas_scaling,
Expand Down
25 changes: 8 additions & 17 deletions crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ use bevy_render::{
Extract, ExtractSchedule, Render, RenderSet,
};
use bevy_sprite::{
ImageScaleMode, SliceScaleMode, SpriteAssetEvents, TextureAtlas, TextureAtlasLayout,
TextureSlicer,
ImageScaleMode, SliceScaleMode, SpriteAssetEvents, TextureAtlasLayout, TextureSlicer,
};
use bevy_transform::prelude::GlobalTransform;
use bevy_utils::HashMap;
Expand Down Expand Up @@ -258,22 +257,12 @@ pub fn extract_ui_texture_slices(
Option<&TargetCamera>,
&UiImage,
&ImageScaleMode,
Option<&TextureAtlas>,
)>,
>,
mapping: Extract<Query<RenderEntity>>,
) {
for (
entity,
uinode,
transform,
view_visibility,
clip,
camera,
image,
image_scale_mode,
atlas,
) in &slicers_query
for (entity, uinode, transform, view_visibility, clip, camera, image, image_scale_mode) in
&slicers_query
{
let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get())
else {
Expand All @@ -287,12 +276,14 @@ pub fn extract_ui_texture_slices(
// Skip invisible images
if !view_visibility.get()
|| image.color.is_fully_transparent()
|| image.texture.id() == TRANSPARENT_IMAGE_HANDLE.id()
|| image.image.id() == TRANSPARENT_IMAGE_HANDLE.id()
{
continue;
}

let atlas_rect = atlas
let atlas_rect = image
.texture_atlas
.as_ref()
.and_then(|s| s.texture_rect(&texture_atlases))
.map(|r| r.as_rect());

Expand All @@ -318,7 +309,7 @@ pub fn extract_ui_texture_slices(
max: uinode.calculated_size,
},
clip: clip.map(|clip| clip.clip),
image: image.texture.id(),
image: image.image.id(),
camera_entity,
image_scale_mode: image_scale_mode.clone(),
atlas_rect,
Expand Down
27 changes: 20 additions & 7 deletions crates/bevy_ui/src/ui_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bevy_render::{
texture::{Image, TRANSPARENT_IMAGE_HANDLE},
view::Visibility,
};
use bevy_sprite::BorderRect;
use bevy_sprite::{BorderRect, TextureAtlas};
use bevy_transform::components::Transform;
use bevy_utils::warn_once;
use bevy_window::{PrimaryWindow, WindowRef};
Expand Down Expand Up @@ -2053,15 +2053,17 @@ pub struct UiImage {
/// Handle to the texture.
///
/// This defaults to a [`TRANSPARENT_IMAGE_HANDLE`], which points to a fully transparent 1x1 texture.
pub texture: Handle<Image>,
pub image: Handle<Image>,
/// The (optional) texture atlas used to render the image
pub texture_atlas: Option<TextureAtlas>,
/// Whether the image should be flipped along its x-axis
pub flip_x: bool,
/// Whether the image should be flipped along its y-axis
pub flip_y: bool,
/// An optional rectangle representing the region of the image to render, instead of rendering
/// the full image. This is an easy one-off alternative to using a [`TextureAtlas`](bevy_sprite::TextureAtlas).
/// the full image. This is an easy one-off alternative to using a [`TextureAtlas`].
///
/// When used with a [`TextureAtlas`](bevy_sprite::TextureAtlas), the rect
/// When used with a [`TextureAtlas`], the rect
/// is offset by the atlas's minimal (top-left) corner position.
pub rect: Option<Rect>,
}
Expand All @@ -2079,8 +2081,9 @@ impl Default for UiImage {
// This should be white because the tint is multiplied with the image,
// so if you set an actual image with default tint you'd want its original colors
color: Color::WHITE,
texture_atlas: None,
// This texture needs to be transparent by default, to avoid covering the background color
texture: TRANSPARENT_IMAGE_HANDLE,
image: TRANSPARENT_IMAGE_HANDLE,
flip_x: false,
flip_y: false,
rect: None,
Expand All @@ -2092,7 +2095,7 @@ impl UiImage {
/// Create a new [`UiImage`] with the given texture.
pub fn new(texture: Handle<Image>) -> Self {
Self {
texture,
image: texture,
color: Color::WHITE,
..Default::default()
}
Expand All @@ -2103,14 +2106,24 @@ impl UiImage {
/// This is primarily useful for debugging / mocking the extents of your image.
pub fn solid_color(color: Color) -> Self {
Self {
texture: Handle::default(),
image: Handle::default(),
color,
flip_x: false,
flip_y: false,
texture_atlas: None,
rect: None,
}
}

/// Create a [`UiImage`] from an image, with an associated texture atlas
pub fn from_atlas_image(image: Handle<Image>, atlas: TextureAtlas) -> Self {
Self {
image,
texture_atlas: Some(atlas),
..Default::default()
}
}

/// Set the color tint
#[must_use]
pub const fn with_color(mut self, color: Color) -> Self {
Expand Down
18 changes: 5 additions & 13 deletions crates/bevy_ui/src/widget/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bevy_ecs::prelude::*;
use bevy_math::{UVec2, Vec2};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::texture::Image;
use bevy_sprite::{TextureAtlas, TextureAtlasLayout};
use bevy_sprite::TextureAtlasLayout;
use bevy_window::{PrimaryWindow, Window};
use taffy::{MaybeMath, MaybeResolve};

Expand Down Expand Up @@ -97,26 +97,18 @@ pub fn update_image_content_size_system(
textures: Res<Assets<Image>>,

atlases: Res<Assets<TextureAtlasLayout>>,
mut query: Query<
(
&mut ContentSize,
&UiImage,
&mut UiImageSize,
Option<&TextureAtlas>,
),
UpdateImageFilter,
>,
mut query: Query<(&mut ContentSize, &UiImage, &mut UiImageSize), UpdateImageFilter>,
) {
let combined_scale_factor = windows
.get_single()
.map(|window| window.resolution.scale_factor())
.unwrap_or(1.)
* ui_scale.0;

for (mut content_size, image, mut image_size, atlas_image) in &mut query {
if let Some(size) = match atlas_image {
for (mut content_size, image, mut image_size) in &mut query {
if let Some(size) = match &image.texture_atlas {
Some(atlas) => atlas.texture_rect(&atlases).map(|t| t.size()),
None => textures.get(&image.texture).map(Image::size),
None => textures.get(&image.image).map(Image::size),
} {
// Update only if size or scale factor has changed to avoid needless layout calculations
if size != image_size.size
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/auto_exposure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ fn setup(

commands.spawn((
UiImage {
texture: metering_mask,
image: metering_mask,
..default()
},
Node {
Expand Down
13 changes: 8 additions & 5 deletions examples/stress_tests/many_animated_sprites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ fn setup(
commands.spawn((
Sprite {
image: texture_handle.clone(),
texture_atlas: Some(TextureAtlas::from(texture_atlas_handle.clone())),
custom_size: Some(tile_size),
..default()
},
Expand All @@ -92,7 +93,6 @@ fn setup(
rotation,
scale,
},
TextureAtlas::from(texture_atlas_handle.clone()),
AnimationTimer(timer),
));
}
Expand All @@ -112,13 +112,16 @@ struct AnimationTimer(Timer);
fn animate_sprite(
time: Res<Time>,
texture_atlases: Res<Assets<TextureAtlasLayout>>,
mut query: Query<(&mut AnimationTimer, &mut TextureAtlas)>,
mut query: Query<(&mut AnimationTimer, &mut Sprite)>,
) {
for (mut timer, mut sheet) in query.iter_mut() {
for (mut timer, mut sprite) in query.iter_mut() {
timer.tick(time.delta());
if timer.just_finished() {
let texture_atlas = texture_atlases.get(&sheet.layout).unwrap();
sheet.index = (sheet.index + 1) % texture_atlas.textures.len();
let Some(atlas) = &mut sprite.texture_atlas else {
continue;
};
let texture_atlas = texture_atlases.get(&atlas.layout).unwrap();
atlas.index = (atlas.index + 1) % texture_atlas.textures.len();
}
}
}
Expand Down
14 changes: 6 additions & 8 deletions examples/ui/ui_texture_atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,13 @@ fn setup(
})
.with_children(|parent| {
parent.spawn((
UiImage::new(texture_handle),
UiImage::from_atlas_image(texture_handle, TextureAtlas::from(texture_atlas_handle)),
Node {
width: Val::Px(256.),
height: Val::Px(256.),
..default()
},
BackgroundColor(ANTIQUE_WHITE.into()),
TextureAtlas::from(texture_atlas_handle),
Outline::new(Val::Px(8.0), Val::ZERO, CRIMSON.into()),
));
parent
Expand All @@ -65,13 +64,12 @@ fn setup(
});
}

fn increment_atlas_index(
mut atlas_images: Query<&mut TextureAtlas>,
keyboard: Res<ButtonInput<KeyCode>>,
) {
fn increment_atlas_index(mut ui_images: Query<&mut UiImage>, keyboard: Res<ButtonInput<KeyCode>>) {
if keyboard.just_pressed(KeyCode::Space) {
for mut atlas_image in &mut atlas_images {
atlas_image.index = (atlas_image.index + 1) % 6;
for mut ui_image in &mut ui_images {
if let Some(atlas) = &mut ui_image.texture_atlas {
atlas.index = (atlas.index + 1) % 6;
}
}
}
}
20 changes: 12 additions & 8 deletions examples/ui/ui_texture_atlas_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ fn main() {

fn button_system(
mut interaction_query: Query<
(&Interaction, &mut TextureAtlas, &Children, &mut UiImage),
(&Interaction, &Children, &mut UiImage),
(Changed<Interaction>, With<Button>),
>,
mut text_query: Query<&mut Text>,
) {
for (interaction, mut atlas, children, mut image) in &mut interaction_query {
for (interaction, children, mut image) in &mut interaction_query {
let mut text = text_query.get_mut(children[0]).unwrap();
match *interaction {
Interaction::Pressed => {
**text = "Press".to_string();
atlas.index = (atlas.index + 1) % 30;
if let Some(atlas) = &mut image.texture_atlas {
atlas.index = (atlas.index + 1) % 30;
}
image.color = GOLD.into();
}
Interaction::Hovered => {
Expand Down Expand Up @@ -79,7 +81,13 @@ fn setup(
parent
.spawn((
Button,
UiImage::new(texture_handle.clone()),
UiImage::from_atlas_image(
texture_handle.clone(),
TextureAtlas {
index: idx,
layout: atlas_layout_handle.clone(),
},
),
Node {
width: Val::Px(w),
height: Val::Px(h),
Expand All @@ -91,10 +99,6 @@ fn setup(
..default()
},
ImageScaleMode::Sliced(slicer.clone()),
TextureAtlas {
index: idx,
layout: atlas_layout_handle.clone(),
},
))
.with_children(|parent| {
parent.spawn((
Expand Down
2 changes: 1 addition & 1 deletion examples/ui/ui_texture_slice_flip_and_tile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
] {
parent.spawn((
UiImage {
texture: image.clone(),
image: image.clone(),
flip_x,
flip_y,
..default()
Expand Down