
# Objective This adds support for using texture atlas sprites in UI. From discussions today in the ui-dev discord it seems this is a much wanted feature. This was previously attempted in #5070 by @ManevilleF however that was blocked #5103. This work can be easily modified to support #5103 changes after that merges. ## Solution I created a new UI bundle that reuses the existing texture atlas infrastructure. I create a new atlas image component to prevent it from being drawn by the existing non-UI systems and to remove unused parameters. In extract I added new system to calculate the required values for the texture atlas image, this extracts into the same resource as the existing UI Image and Text components. This should have minimal performance impact because if texture atlas is not present then the exact same code path is followed. Also there should be no unintended behavior changes because without the new components the existing systems write the extract same resulting data. I also added an example showing the sprite working and a system to advance the animation on space bar presses. Naming is hard and I would accept any feedback on the bundle name! --- ## Changelog > Added TextureAtlasImageBundle --------- Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
133 lines
3.9 KiB
Rust
133 lines
3.9 KiB
Rust
use crate::{
|
|
measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiTextureAtlasImage,
|
|
};
|
|
use bevy_asset::{Assets, Handle};
|
|
#[cfg(feature = "bevy_text")]
|
|
use bevy_ecs::query::Without;
|
|
use bevy_ecs::{
|
|
prelude::Component,
|
|
query::With,
|
|
reflect::ReflectComponent,
|
|
system::{Query, Res},
|
|
};
|
|
use bevy_math::Vec2;
|
|
use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect, ReflectFromReflect};
|
|
use bevy_render::texture::Image;
|
|
use bevy_sprite::TextureAtlas;
|
|
#[cfg(feature = "bevy_text")]
|
|
use bevy_text::Text;
|
|
|
|
/// The size of the image in physical pixels
|
|
///
|
|
/// This field is set automatically by `update_image_calculated_size_system`
|
|
#[derive(Component, Debug, Copy, Clone, Default, Reflect, FromReflect)]
|
|
#[reflect(Component, Default, FromReflect)]
|
|
pub struct UiImageSize {
|
|
size: Vec2,
|
|
}
|
|
|
|
impl UiImageSize {
|
|
pub fn size(&self) -> Vec2 {
|
|
self.size
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct ImageMeasure {
|
|
// target size of the image
|
|
size: Vec2,
|
|
}
|
|
|
|
impl Measure for ImageMeasure {
|
|
fn measure(
|
|
&self,
|
|
width: Option<f32>,
|
|
height: Option<f32>,
|
|
_: AvailableSpace,
|
|
_: AvailableSpace,
|
|
) -> Vec2 {
|
|
let mut size = self.size;
|
|
match (width, height) {
|
|
(None, None) => {}
|
|
(Some(width), None) => {
|
|
size.y = width * size.y / size.x;
|
|
size.x = width;
|
|
}
|
|
(None, Some(height)) => {
|
|
size.x = height * size.x / size.y;
|
|
size.y = height;
|
|
}
|
|
(Some(width), Some(height)) => {
|
|
size.x = width;
|
|
size.y = height;
|
|
}
|
|
}
|
|
size
|
|
}
|
|
}
|
|
|
|
/// Updates content size of the node based on the image provided
|
|
pub fn update_image_content_size_system(
|
|
textures: Res<Assets<Image>>,
|
|
#[cfg(feature = "bevy_text")] mut query: Query<
|
|
(&mut ContentSize, &UiImage, &mut UiImageSize),
|
|
(With<Node>, Without<Text>),
|
|
>,
|
|
#[cfg(not(feature = "bevy_text"))] mut query: Query<
|
|
(&mut ContentSize, &UiImage, &mut UiImageSize),
|
|
With<Node>,
|
|
>,
|
|
) {
|
|
for (mut content_size, image, mut image_size) in &mut query {
|
|
if let Some(texture) = textures.get(&image.texture) {
|
|
let size = Vec2::new(
|
|
texture.texture_descriptor.size.width as f32,
|
|
texture.texture_descriptor.size.height as f32,
|
|
);
|
|
// Update only if size has changed to avoid needless layout calculations
|
|
if size != image_size.size {
|
|
image_size.size = size;
|
|
content_size.set(ImageMeasure { size });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Updates content size of the node based on the texture atlas sprite
|
|
pub fn update_atlas_content_size_system(
|
|
atlases: Res<Assets<TextureAtlas>>,
|
|
#[cfg(feature = "bevy_text")] mut atlas_query: Query<
|
|
(
|
|
&mut ContentSize,
|
|
&Handle<TextureAtlas>,
|
|
&UiTextureAtlasImage,
|
|
&mut UiImageSize,
|
|
),
|
|
(With<Node>, Without<Text>, Without<UiImage>),
|
|
>,
|
|
#[cfg(not(feature = "bevy_text"))] mut atlas_query: Query<
|
|
(
|
|
&mut ContentSize,
|
|
&Handle<TextureAtlas>,
|
|
&UiTextureAtlasImage,
|
|
&mut UiImageSize,
|
|
),
|
|
(With<Node>, Without<UiImage>),
|
|
>,
|
|
) {
|
|
for (mut content_size, atlas, atlas_image, mut image_size) in &mut atlas_query {
|
|
if let Some(atlas) = atlases.get(atlas) {
|
|
let texture_rect = atlas.textures[atlas_image.index];
|
|
let size = Vec2::new(
|
|
texture_rect.max.x - texture_rect.min.x,
|
|
texture_rect.max.y - texture_rect.min.y,
|
|
);
|
|
// Update only if size has changed to avoid needless layout calculations
|
|
if size != image_size.size {
|
|
image_size.size = size;
|
|
content_size.set(ImageMeasure { size });
|
|
}
|
|
}
|
|
}
|
|
}
|