Prefer UVec2 when working with texture dimensions (#11698)
# Objective
The physical width and height (pixels) of an image is always integers,
but for `GpuImage` bevy currently stores them as `Vec2` (`f32`).
Switching to `UVec2` makes this more consistent with the [underlying
texture data](https://docs.rs/wgpu/latest/wgpu/struct.Extent3d.html).
I'm not sure if this is worth the change in the surface level API. If
not, feel free to close this PR.
## Solution
- Replace uses of `Vec2` with `UVec2` when referring to texture
dimensions.
- Use integer types for the texture atlas dimensions and sections.
[`Sprite::rect`](a81a2d1da3/crates/bevy_sprite/src/sprite.rs (L29))
remains unchanged, so manually specifying a sub-pixel region of an image
is still possible.
---
## Changelog
- `GpuImage` now stores its size as `UVec2` instead of `Vec2`.
- Texture atlases store their size and sections as `UVec2` and `URect`
respectively.
- `UiImageSize` stores its size as `UVec2`.
## Migration Guide
- Change floating point types (`Vec2`, `Rect`) to their respective
unsigned integer versions (`UVec2`, `URect`) when using `GpuImage`,
`TextureAtlasLayout`, `TextureAtlasBuilder`,
`DynamicAtlasTextureBuilder` or `FontAtlas`.
This commit is contained in:
parent
14042b1e34
commit
a7be8a2655
@ -398,7 +398,7 @@ impl FromWorld for MeshPipeline {
|
|||||||
texture_view,
|
texture_view,
|
||||||
texture_format: image.texture_descriptor.format,
|
texture_format: image.texture_descriptor.format,
|
||||||
sampler,
|
sampler,
|
||||||
size: image.size_f32(),
|
size: image.size(),
|
||||||
mip_level_count: image.texture_descriptor.mip_level_count,
|
mip_level_count: image.texture_descriptor.mip_level_count,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -121,7 +121,7 @@ fn fallback_image_new(
|
|||||||
texture_view,
|
texture_view,
|
||||||
texture_format: image.texture_descriptor.format,
|
texture_format: image.texture_descriptor.format,
|
||||||
sampler,
|
sampler,
|
||||||
size: image.size_f32(),
|
size: image.size(),
|
||||||
mip_level_count: image.texture_descriptor.mip_level_count,
|
mip_level_count: image.texture_descriptor.mip_level_count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -822,7 +822,7 @@ pub struct GpuImage {
|
|||||||
pub texture_view: TextureView,
|
pub texture_view: TextureView,
|
||||||
pub texture_format: TextureFormat,
|
pub texture_format: TextureFormat,
|
||||||
pub sampler: Sampler,
|
pub sampler: Sampler,
|
||||||
pub size: Vec2,
|
pub size: UVec2,
|
||||||
pub mip_level_count: u32,
|
pub mip_level_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -851,16 +851,13 @@ impl RenderAsset for Image {
|
|||||||
&self.data,
|
&self.data,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let size = self.size();
|
||||||
let texture_view = texture.create_view(
|
let texture_view = texture.create_view(
|
||||||
self.texture_view_descriptor
|
self.texture_view_descriptor
|
||||||
.or_else(|| Some(TextureViewDescriptor::default()))
|
.or_else(|| Some(TextureViewDescriptor::default()))
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
let size = Vec2::new(
|
|
||||||
self.texture_descriptor.size.width as f32,
|
|
||||||
self.texture_descriptor.size.height as f32,
|
|
||||||
);
|
|
||||||
let sampler = match self.sampler {
|
let sampler = match self.sampler {
|
||||||
ImageSampler::Default => (***default_sampler).clone(),
|
ImageSampler::Default => (***default_sampler).clone(),
|
||||||
ImageSampler::Descriptor(descriptor) => {
|
ImageSampler::Descriptor(descriptor) => {
|
||||||
@ -939,7 +936,6 @@ impl CompressedImageFormats {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::render_asset::RenderAssetUsages;
|
use crate::render_asset::RenderAssetUsages;
|
||||||
|
|
||||||
@ -962,9 +958,11 @@ mod test {
|
|||||||
image.size_f32()
|
image.size_f32()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn image_default_size() {
|
fn image_default_size() {
|
||||||
let image = Image::default();
|
let image = Image::default();
|
||||||
|
assert_eq!(UVec2::ONE, image.size());
|
||||||
assert_eq!(Vec2::ONE, image.size_f32());
|
assert_eq!(Vec2::ONE, image.size_f32());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::TextureAtlasLayout;
|
use crate::TextureAtlasLayout;
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_math::{IVec2, Rect, Vec2};
|
use bevy_math::{URect, UVec2};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
render_asset::{RenderAsset, RenderAssetUsages},
|
render_asset::{RenderAsset, RenderAssetUsages},
|
||||||
texture::{Image, TextureFormatPixelInfo},
|
texture::{Image, TextureFormatPixelInfo},
|
||||||
@ -13,7 +13,7 @@ use guillotiere::{size2, Allocation, AtlasAllocator};
|
|||||||
/// e.g: in a font glyph [`TextureAtlasLayout`], only add the [`Image`] texture for letters to be rendered.
|
/// e.g: in a font glyph [`TextureAtlasLayout`], only add the [`Image`] texture for letters to be rendered.
|
||||||
pub struct DynamicTextureAtlasBuilder {
|
pub struct DynamicTextureAtlasBuilder {
|
||||||
atlas_allocator: AtlasAllocator,
|
atlas_allocator: AtlasAllocator,
|
||||||
padding: i32,
|
padding: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicTextureAtlasBuilder {
|
impl DynamicTextureAtlasBuilder {
|
||||||
@ -23,7 +23,7 @@ impl DynamicTextureAtlasBuilder {
|
|||||||
///
|
///
|
||||||
/// * `size` - total size for the atlas
|
/// * `size` - total size for the atlas
|
||||||
/// * `padding` - gap added between textures in the atlas, both in x axis and y axis
|
/// * `padding` - gap added between textures in the atlas, both in x axis and y axis
|
||||||
pub fn new(size: Vec2, padding: i32) -> Self {
|
pub fn new(size: UVec2, padding: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
atlas_allocator: AtlasAllocator::new(to_size2(size)),
|
atlas_allocator: AtlasAllocator::new(to_size2(size)),
|
||||||
padding,
|
padding,
|
||||||
@ -50,8 +50,8 @@ impl DynamicTextureAtlasBuilder {
|
|||||||
atlas_texture_handle: &Handle<Image>,
|
atlas_texture_handle: &Handle<Image>,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
let allocation = self.atlas_allocator.allocate(size2(
|
let allocation = self.atlas_allocator.allocate(size2(
|
||||||
texture.width() as i32 + self.padding,
|
(texture.width() + self.padding).try_into().unwrap(),
|
||||||
texture.height() as i32 + self.padding,
|
(texture.height() + self.padding).try_into().unwrap(),
|
||||||
));
|
));
|
||||||
if let Some(allocation) = allocation {
|
if let Some(allocation) = allocation {
|
||||||
let atlas_texture = textures.get_mut(atlas_texture_handle).unwrap();
|
let atlas_texture = textures.get_mut(atlas_texture_handle).unwrap();
|
||||||
@ -63,8 +63,8 @@ impl DynamicTextureAtlasBuilder {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.place_texture(atlas_texture, allocation, texture);
|
self.place_texture(atlas_texture, allocation, texture);
|
||||||
let mut rect: Rect = to_rect(allocation.rectangle);
|
let mut rect: URect = to_rect(allocation.rectangle);
|
||||||
rect.max -= self.padding as f32;
|
rect.max = rect.max.saturating_sub(UVec2::splat(self.padding));
|
||||||
Some(atlas_layout.add_texture(rect))
|
Some(atlas_layout.add_texture(rect))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -78,8 +78,8 @@ impl DynamicTextureAtlasBuilder {
|
|||||||
texture: &Image,
|
texture: &Image,
|
||||||
) {
|
) {
|
||||||
let mut rect = allocation.rectangle;
|
let mut rect = allocation.rectangle;
|
||||||
rect.max.x -= self.padding;
|
rect.max.x -= self.padding as i32;
|
||||||
rect.max.y -= self.padding;
|
rect.max.y -= self.padding as i32;
|
||||||
let atlas_width = atlas_texture.width() as usize;
|
let atlas_width = atlas_texture.width() as usize;
|
||||||
let rect_width = rect.width() as usize;
|
let rect_width = rect.width() as usize;
|
||||||
let format_size = atlas_texture.texture_descriptor.format.pixel_size();
|
let format_size = atlas_texture.texture_descriptor.format.pixel_size();
|
||||||
@ -95,13 +95,19 @@ impl DynamicTextureAtlasBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_rect(rectangle: guillotiere::Rectangle) -> Rect {
|
fn to_rect(rectangle: guillotiere::Rectangle) -> URect {
|
||||||
Rect {
|
URect {
|
||||||
min: IVec2::new(rectangle.min.x, rectangle.min.y).as_vec2(),
|
min: UVec2::new(
|
||||||
max: IVec2::new(rectangle.max.x, rectangle.max.y).as_vec2(),
|
rectangle.min.x.try_into().unwrap(),
|
||||||
|
rectangle.min.y.try_into().unwrap(),
|
||||||
|
),
|
||||||
|
max: UVec2::new(
|
||||||
|
rectangle.max.x.try_into().unwrap(),
|
||||||
|
rectangle.max.y.try_into().unwrap(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_size2(vec2: Vec2) -> guillotiere::Size {
|
fn to_size2(vec2: UVec2) -> guillotiere::Size {
|
||||||
guillotiere::Size::new(vec2.x as i32, vec2.y as i32)
|
guillotiere::Size::new(vec2.x as i32, vec2.y as i32)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -153,7 +153,9 @@ pub fn calculate_bounds_2d(
|
|||||||
// We default to the texture size for regular sprites
|
// We default to the texture size for regular sprites
|
||||||
None => images.get(texture_handle).map(|image| image.size_f32()),
|
None => images.get(texture_handle).map(|image| image.size_f32()),
|
||||||
// We default to the drawn rect for atlas sprites
|
// We default to the drawn rect for atlas sprites
|
||||||
Some(atlas) => atlas.texture_rect(&atlases).map(|rect| rect.size()),
|
Some(atlas) => atlas
|
||||||
|
.texture_rect(&atlases)
|
||||||
|
.map(|rect| rect.size().as_vec2()),
|
||||||
}) {
|
}) {
|
||||||
let aabb = Aabb {
|
let aabb = Aabb {
|
||||||
center: (-sprite.anchor.as_vec() * size).extend(0.0).into(),
|
center: (-sprite.anchor.as_vec() * size).extend(0.0).into(),
|
||||||
|
|||||||
@ -304,7 +304,7 @@ impl FromWorld for Mesh2dPipeline {
|
|||||||
texture_view,
|
texture_view,
|
||||||
texture_format: image.texture_descriptor.format,
|
texture_format: image.texture_descriptor.format,
|
||||||
sampler,
|
sampler,
|
||||||
size: image.size_f32(),
|
size: image.size(),
|
||||||
mip_level_count: image.texture_descriptor.mip_level_count,
|
mip_level_count: image.texture_descriptor.mip_level_count,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -102,7 +102,7 @@ impl FromWorld for SpritePipeline {
|
|||||||
texture_view,
|
texture_view,
|
||||||
texture_format: image.texture_descriptor.format,
|
texture_format: image.texture_descriptor.format,
|
||||||
sampler,
|
sampler,
|
||||||
size: image.size_f32(),
|
size: image.size(),
|
||||||
mip_level_count: image.texture_descriptor.mip_level_count,
|
mip_level_count: image.texture_descriptor.mip_level_count,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -366,10 +366,10 @@ pub fn extract_sprites(
|
|||||||
let rect = match (atlas_rect, sprite.rect) {
|
let rect = match (atlas_rect, sprite.rect) {
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
(None, Some(sprite_rect)) => Some(sprite_rect),
|
(None, Some(sprite_rect)) => Some(sprite_rect),
|
||||||
(Some(atlas_rect), None) => Some(atlas_rect),
|
(Some(atlas_rect), None) => Some(atlas_rect.as_rect()),
|
||||||
(Some(atlas_rect), Some(mut sprite_rect)) => {
|
(Some(atlas_rect), Some(mut sprite_rect)) => {
|
||||||
sprite_rect.min += atlas_rect.min;
|
sprite_rect.min += atlas_rect.min.as_vec2();
|
||||||
sprite_rect.max += atlas_rect.min;
|
sprite_rect.max += atlas_rect.min.as_vec2();
|
||||||
|
|
||||||
Some(sprite_rect)
|
Some(sprite_rect)
|
||||||
}
|
}
|
||||||
@ -618,7 +618,7 @@ pub fn prepare_sprites(
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
batch_image_size = Vec2::new(gpu_image.size.x, gpu_image.size.y);
|
batch_image_size = gpu_image.size.as_vec2();
|
||||||
batch_image_handle = extracted_sprite.image_handle_id;
|
batch_image_handle = extracted_sprite.image_handle_id;
|
||||||
image_bind_groups
|
image_bind_groups
|
||||||
.values
|
.values
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use bevy_asset::{Asset, AssetId, Assets, Handle};
|
use bevy_asset::{Asset, AssetId, Assets, Handle};
|
||||||
use bevy_ecs::component::Component;
|
use bevy_ecs::component::Component;
|
||||||
use bevy_math::{Rect, Vec2};
|
use bevy_math::{URect, UVec2};
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_render::texture::Image;
|
use bevy_render::texture::Image;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
@ -19,9 +19,9 @@ use bevy_utils::HashMap;
|
|||||||
#[reflect(Debug)]
|
#[reflect(Debug)]
|
||||||
pub struct TextureAtlasLayout {
|
pub struct TextureAtlasLayout {
|
||||||
// TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer
|
// TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer
|
||||||
pub size: Vec2,
|
pub size: UVec2,
|
||||||
/// The specific areas of the atlas where each texture can be found
|
/// The specific areas of the atlas where each texture can be found
|
||||||
pub textures: Vec<Rect>,
|
pub textures: Vec<URect>,
|
||||||
/// Maps from a specific image handle to the index in `textures` where they can be found.
|
/// Maps from a specific image handle to the index in `textures` where they can be found.
|
||||||
///
|
///
|
||||||
/// This field is set by [`TextureAtlasBuilder`].
|
/// This field is set by [`TextureAtlasBuilder`].
|
||||||
@ -51,7 +51,7 @@ pub struct TextureAtlas {
|
|||||||
|
|
||||||
impl TextureAtlasLayout {
|
impl TextureAtlasLayout {
|
||||||
/// Create a new empty layout with custom `dimensions`
|
/// Create a new empty layout with custom `dimensions`
|
||||||
pub fn new_empty(dimensions: Vec2) -> Self {
|
pub fn new_empty(dimensions: UVec2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
size: dimensions,
|
size: dimensions,
|
||||||
texture_handles: None,
|
texture_handles: None,
|
||||||
@ -73,16 +73,16 @@ impl TextureAtlasLayout {
|
|||||||
/// * `padding` - Optional padding between cells
|
/// * `padding` - Optional padding between cells
|
||||||
/// * `offset` - Optional global grid offset
|
/// * `offset` - Optional global grid offset
|
||||||
pub fn from_grid(
|
pub fn from_grid(
|
||||||
tile_size: Vec2,
|
tile_size: UVec2,
|
||||||
columns: usize,
|
columns: u32,
|
||||||
rows: usize,
|
rows: u32,
|
||||||
padding: Option<Vec2>,
|
padding: Option<UVec2>,
|
||||||
offset: Option<Vec2>,
|
offset: Option<UVec2>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let padding = padding.unwrap_or_default();
|
let padding = padding.unwrap_or_default();
|
||||||
let offset = offset.unwrap_or_default();
|
let offset = offset.unwrap_or_default();
|
||||||
let mut sprites = Vec::new();
|
let mut sprites = Vec::new();
|
||||||
let mut current_padding = Vec2::ZERO;
|
let mut current_padding = UVec2::ZERO;
|
||||||
|
|
||||||
for y in 0..rows {
|
for y in 0..rows {
|
||||||
if y > 0 {
|
if y > 0 {
|
||||||
@ -93,18 +93,17 @@ impl TextureAtlasLayout {
|
|||||||
current_padding.x = padding.x;
|
current_padding.x = padding.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cell = Vec2::new(x as f32, y as f32);
|
let cell = UVec2::new(x, y);
|
||||||
|
|
||||||
let rect_min = (tile_size + current_padding) * cell + offset;
|
let rect_min = (tile_size + current_padding) * cell + offset;
|
||||||
|
|
||||||
sprites.push(Rect {
|
sprites.push(URect {
|
||||||
min: rect_min,
|
min: rect_min,
|
||||||
max: rect_min + tile_size,
|
max: rect_min + tile_size,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let grid_size = Vec2::new(columns as f32, rows as f32);
|
let grid_size = UVec2::new(columns, rows);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
size: ((tile_size + current_padding) * grid_size) - current_padding,
|
size: ((tile_size + current_padding) * grid_size) - current_padding,
|
||||||
@ -121,7 +120,7 @@ impl TextureAtlasLayout {
|
|||||||
/// * `rect` - The section of the texture to be added
|
/// * `rect` - The section of the texture to be added
|
||||||
///
|
///
|
||||||
/// [`TextureAtlas`]: crate::TextureAtlas
|
/// [`TextureAtlas`]: crate::TextureAtlas
|
||||||
pub fn add_texture(&mut self, rect: Rect) -> usize {
|
pub fn add_texture(&mut self, rect: URect) -> usize {
|
||||||
self.textures.push(rect);
|
self.textures.push(rect);
|
||||||
self.textures.len() - 1
|
self.textures.len() - 1
|
||||||
}
|
}
|
||||||
@ -149,8 +148,8 @@ impl TextureAtlasLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TextureAtlas {
|
impl TextureAtlas {
|
||||||
/// Retrieves the current texture [`Rect`] of the sprite sheet according to the section `index`
|
/// Retrieves the current texture [`URect`] of the sprite sheet according to the section `index`
|
||||||
pub fn texture_rect(&self, texture_atlases: &Assets<TextureAtlasLayout>) -> Option<Rect> {
|
pub fn texture_rect(&self, texture_atlases: &Assets<TextureAtlasLayout>) -> Option<URect> {
|
||||||
let atlas = texture_atlases.get(&self.layout)?;
|
let atlas = texture_atlases.get(&self.layout)?;
|
||||||
atlas.textures.get(self.index).copied()
|
atlas.textures.get(self.index).copied()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use bevy_asset::AssetId;
|
use bevy_asset::AssetId;
|
||||||
use bevy_log::{debug, error, warn};
|
use bevy_log::{debug, error, warn};
|
||||||
use bevy_math::{Rect, UVec2, Vec2};
|
use bevy_math::{URect, UVec2};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
render_asset::RenderAssetUsages,
|
render_asset::RenderAssetUsages,
|
||||||
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
||||||
@ -31,9 +31,9 @@ pub struct TextureAtlasBuilder<'a> {
|
|||||||
/// Collection of texture's asset id (optional) and image data to be packed into an atlas
|
/// Collection of texture's asset id (optional) and image data to be packed into an atlas
|
||||||
textures_to_place: Vec<(Option<AssetId<Image>>, &'a Image)>,
|
textures_to_place: Vec<(Option<AssetId<Image>>, &'a Image)>,
|
||||||
/// The initial atlas size in pixels.
|
/// The initial atlas size in pixels.
|
||||||
initial_size: Vec2,
|
initial_size: UVec2,
|
||||||
/// The absolute maximum size of the texture atlas in pixels.
|
/// The absolute maximum size of the texture atlas in pixels.
|
||||||
max_size: Vec2,
|
max_size: UVec2,
|
||||||
/// The texture format for the textures that will be loaded in the atlas.
|
/// The texture format for the textures that will be loaded in the atlas.
|
||||||
format: TextureFormat,
|
format: TextureFormat,
|
||||||
/// Enable automatic format conversion for textures if they are not in the atlas format.
|
/// Enable automatic format conversion for textures if they are not in the atlas format.
|
||||||
@ -46,8 +46,8 @@ impl Default for TextureAtlasBuilder<'_> {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
textures_to_place: Vec::new(),
|
textures_to_place: Vec::new(),
|
||||||
initial_size: Vec2::new(256., 256.),
|
initial_size: UVec2::splat(256),
|
||||||
max_size: Vec2::new(2048., 2048.),
|
max_size: UVec2::splat(2048),
|
||||||
format: TextureFormat::Rgba8UnormSrgb,
|
format: TextureFormat::Rgba8UnormSrgb,
|
||||||
auto_format_conversion: true,
|
auto_format_conversion: true,
|
||||||
padding: UVec2::ZERO,
|
padding: UVec2::ZERO,
|
||||||
@ -59,13 +59,13 @@ pub type TextureAtlasBuilderResult<T> = Result<T, TextureAtlasBuilderError>;
|
|||||||
|
|
||||||
impl<'a> TextureAtlasBuilder<'a> {
|
impl<'a> TextureAtlasBuilder<'a> {
|
||||||
/// Sets the initial size of the atlas in pixels.
|
/// Sets the initial size of the atlas in pixels.
|
||||||
pub fn initial_size(mut self, size: Vec2) -> Self {
|
pub fn initial_size(mut self, size: UVec2) -> Self {
|
||||||
self.initial_size = size;
|
self.initial_size = size;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the max size of the atlas in pixels.
|
/// Sets the max size of the atlas in pixels.
|
||||||
pub fn max_size(mut self, size: Vec2) -> Self {
|
pub fn max_size(mut self, size: UVec2) -> Self {
|
||||||
self.max_size = size;
|
self.max_size = size;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -189,13 +189,11 @@ impl<'a> TextureAtlasBuilder<'a> {
|
|||||||
/// If there is not enough space in the atlas texture, an error will
|
/// If there is not enough space in the atlas texture, an error will
|
||||||
/// be returned. It is then recommended to make a larger sprite sheet.
|
/// be returned. It is then recommended to make a larger sprite sheet.
|
||||||
pub fn finish(self) -> Result<(TextureAtlasLayout, Image), TextureAtlasBuilderError> {
|
pub fn finish(self) -> Result<(TextureAtlasLayout, Image), TextureAtlasBuilderError> {
|
||||||
let initial_width = self.initial_size.x as u32;
|
let max_width = self.max_size.x;
|
||||||
let initial_height = self.initial_size.y as u32;
|
let max_height = self.max_size.y;
|
||||||
let max_width = self.max_size.x as u32;
|
|
||||||
let max_height = self.max_size.y as u32;
|
|
||||||
|
|
||||||
let mut current_width = initial_width;
|
let mut current_width = self.initial_size.x;
|
||||||
let mut current_height = initial_height;
|
let mut current_height = self.initial_size.y;
|
||||||
let mut rect_placements = None;
|
let mut rect_placements = None;
|
||||||
let mut atlas_texture = Image::default();
|
let mut atlas_texture = Image::default();
|
||||||
let mut rects_to_place = GroupedRectsToPlace::<usize>::new();
|
let mut rects_to_place = GroupedRectsToPlace::<usize>::new();
|
||||||
@ -265,16 +263,13 @@ impl<'a> TextureAtlasBuilder<'a> {
|
|||||||
for (index, (image_id, texture)) in self.textures_to_place.iter().enumerate() {
|
for (index, (image_id, texture)) in self.textures_to_place.iter().enumerate() {
|
||||||
let (_, packed_location) = rect_placements.packed_locations().get(&index).unwrap();
|
let (_, packed_location) = rect_placements.packed_locations().get(&index).unwrap();
|
||||||
|
|
||||||
let min = Vec2::new(packed_location.x() as f32, packed_location.y() as f32);
|
let min = UVec2::new(packed_location.x(), packed_location.y());
|
||||||
let max = min
|
let max =
|
||||||
+ Vec2::new(
|
min + UVec2::new(packed_location.width(), packed_location.height()) - self.padding;
|
||||||
(packed_location.width() - self.padding.x) as f32,
|
|
||||||
(packed_location.height() - self.padding.y) as f32,
|
|
||||||
);
|
|
||||||
if let Some(image_id) = image_id {
|
if let Some(image_id) = image_id {
|
||||||
texture_ids.insert(*image_id, index);
|
texture_ids.insert(*image_id, index);
|
||||||
}
|
}
|
||||||
texture_rects.push(Rect { min, max });
|
texture_rects.push(URect { min, max });
|
||||||
if texture.texture_descriptor.format != self.format && !self.auto_format_conversion {
|
if texture.texture_descriptor.format != self.format && !self.auto_format_conversion {
|
||||||
warn!(
|
warn!(
|
||||||
"Loading a texture of format '{:?}' in an atlas with format '{:?}'",
|
"Loading a texture of format '{:?}' in an atlas with format '{:?}'",
|
||||||
@ -287,7 +282,7 @@ impl<'a> TextureAtlasBuilder<'a> {
|
|||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
TextureAtlasLayout {
|
TextureAtlasLayout {
|
||||||
size: atlas_texture.size_f32(),
|
size: atlas_texture.size(),
|
||||||
textures: texture_rects,
|
textures: texture_rects,
|
||||||
texture_handles: Some(texture_ids),
|
texture_handles: Some(texture_ids),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use ab_glyph::{GlyphId, Point};
|
use ab_glyph::{GlyphId, Point};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::UVec2;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
render_asset::RenderAssetUsages,
|
render_asset::RenderAssetUsages,
|
||||||
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
||||||
@ -51,12 +51,12 @@ impl FontAtlas {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
textures: &mut Assets<Image>,
|
textures: &mut Assets<Image>,
|
||||||
texture_atlases: &mut Assets<TextureAtlasLayout>,
|
texture_atlases: &mut Assets<TextureAtlasLayout>,
|
||||||
size: Vec2,
|
size: UVec2,
|
||||||
) -> FontAtlas {
|
) -> FontAtlas {
|
||||||
let texture = textures.add(Image::new_fill(
|
let texture = textures.add(Image::new_fill(
|
||||||
Extent3d {
|
Extent3d {
|
||||||
width: size.x as u32,
|
width: size.x,
|
||||||
height: size.y as u32,
|
height: size.y,
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
},
|
},
|
||||||
TextureDimension::D2,
|
TextureDimension::D2,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use ab_glyph::{GlyphId, OutlinedGlyph, Point};
|
|||||||
use bevy_asset::{AssetEvent, AssetId};
|
use bevy_asset::{AssetEvent, AssetId};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::Vec2;
|
use bevy_math::UVec2;
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_render::texture::Image;
|
use bevy_render::texture::Image;
|
||||||
use bevy_sprite::TextureAtlasLayout;
|
use bevy_sprite::TextureAtlasLayout;
|
||||||
@ -84,13 +84,7 @@ impl FontAtlasSet {
|
|||||||
let font_atlases = self
|
let font_atlases = self
|
||||||
.font_atlases
|
.font_atlases
|
||||||
.entry(FloatOrd(font_size))
|
.entry(FloatOrd(font_size))
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| vec![FontAtlas::new(textures, texture_atlases, UVec2::splat(512))]);
|
||||||
vec![FontAtlas::new(
|
|
||||||
textures,
|
|
||||||
texture_atlases,
|
|
||||||
Vec2::splat(512.0),
|
|
||||||
)]
|
|
||||||
});
|
|
||||||
|
|
||||||
let glyph_texture = Font::get_outlined_glyph_texture(outlined_glyph);
|
let glyph_texture = Font::get_outlined_glyph_texture(outlined_glyph);
|
||||||
let add_char_to_font_atlas = |atlas: &mut FontAtlas| -> bool {
|
let add_char_to_font_atlas = |atlas: &mut FontAtlas| -> bool {
|
||||||
@ -110,11 +104,11 @@ impl FontAtlasSet {
|
|||||||
.height
|
.height
|
||||||
.max(glyph_texture.width());
|
.max(glyph_texture.width());
|
||||||
// Pick the higher of 512 or the smallest power of 2 greater than glyph_max_size
|
// Pick the higher of 512 or the smallest power of 2 greater than glyph_max_size
|
||||||
let containing = (1u32 << (32 - glyph_max_size.leading_zeros())).max(512) as f32;
|
let containing = (1u32 << (32 - glyph_max_size.leading_zeros())).max(512);
|
||||||
font_atlases.push(FontAtlas::new(
|
font_atlases.push(FontAtlas::new(
|
||||||
textures,
|
textures,
|
||||||
texture_atlases,
|
texture_atlases,
|
||||||
Vec2::new(containing, containing),
|
UVec2::splat(containing),
|
||||||
));
|
));
|
||||||
if !font_atlases.last_mut().unwrap().add_glyph(
|
if !font_atlases.last_mut().unwrap().add_glyph(
|
||||||
textures,
|
textures,
|
||||||
|
|||||||
@ -120,7 +120,7 @@ impl GlyphBrush {
|
|||||||
|
|
||||||
let texture_atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();
|
let texture_atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();
|
||||||
let glyph_rect = texture_atlas.textures[atlas_info.glyph_index];
|
let glyph_rect = texture_atlas.textures[atlas_info.glyph_index];
|
||||||
let size = Vec2::new(glyph_rect.width(), glyph_rect.height());
|
let size = glyph_rect.size().as_vec2();
|
||||||
|
|
||||||
let x = bounds.min.x + size.x / 2.0 - text_bounds.min.x;
|
let x = bounds.min.x + size.x / 2.0 - text_bounds.min.x;
|
||||||
|
|
||||||
|
|||||||
@ -136,7 +136,7 @@ pub fn extract_text2d_sprite(
|
|||||||
ExtractedSprite {
|
ExtractedSprite {
|
||||||
transform: transform * GlobalTransform::from_translation(position.extend(0.)),
|
transform: transform * GlobalTransform::from_translation(position.extend(0.)),
|
||||||
color,
|
color,
|
||||||
rect: Some(atlas.textures[atlas_info.glyph_index]),
|
rect: Some(atlas.textures[atlas_info.glyph_index].as_rect()),
|
||||||
custom_size: None,
|
custom_size: None,
|
||||||
image_handle_id: atlas_info.texture.id(),
|
image_handle_id: atlas_info.texture.id(),
|
||||||
flip_x: false,
|
flip_x: false,
|
||||||
|
|||||||
@ -436,8 +436,8 @@ pub fn extract_uinodes(
|
|||||||
// Atlas not present in assets resource (should this warn the user?)
|
// Atlas not present in assets resource (should this warn the user?)
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let mut atlas_rect = layout.textures[atlas.index];
|
let mut atlas_rect = layout.textures[atlas.index].as_rect();
|
||||||
let mut atlas_size = layout.size;
|
let mut atlas_size = layout.size.as_vec2();
|
||||||
let scale = uinode.size() / atlas_rect.size();
|
let scale = uinode.size() / atlas_rect.size();
|
||||||
atlas_rect.min *= scale;
|
atlas_rect.min *= scale;
|
||||||
atlas_rect.max *= scale;
|
atlas_rect.max *= scale;
|
||||||
@ -613,7 +613,7 @@ pub fn extract_text_uinodes(
|
|||||||
}
|
}
|
||||||
let atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();
|
let atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();
|
||||||
|
|
||||||
let mut rect = atlas.textures[atlas_info.glyph_index];
|
let mut rect = atlas.textures[atlas_info.glyph_index].as_rect();
|
||||||
rect.min *= inverse_scale_factor;
|
rect.min *= inverse_scale_factor;
|
||||||
rect.max *= inverse_scale_factor;
|
rect.max *= inverse_scale_factor;
|
||||||
extracted_uinodes.uinodes.insert(
|
extracted_uinodes.uinodes.insert(
|
||||||
@ -625,7 +625,7 @@ pub fn extract_text_uinodes(
|
|||||||
color,
|
color,
|
||||||
rect,
|
rect,
|
||||||
image: atlas_info.texture.id(),
|
image: atlas_info.texture.id(),
|
||||||
atlas_size: Some(atlas.size * inverse_scale_factor),
|
atlas_size: Some(atlas.size.as_vec2() * inverse_scale_factor),
|
||||||
clip: clip.map(|clip| clip.clip),
|
clip: clip.map(|clip| clip.clip),
|
||||||
flip_x: false,
|
flip_x: false,
|
||||||
flip_y: false,
|
flip_y: false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::{measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiScale};
|
use crate::{measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiScale};
|
||||||
use bevy_asset::Assets;
|
use bevy_asset::Assets;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::Vec2;
|
use bevy_math::{UVec2, Vec2};
|
||||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||||
use bevy_render::texture::Image;
|
use bevy_render::texture::Image;
|
||||||
use bevy_sprite::{TextureAtlas, TextureAtlasLayout};
|
use bevy_sprite::{TextureAtlas, TextureAtlasLayout};
|
||||||
@ -16,12 +16,12 @@ pub struct UiImageSize {
|
|||||||
/// The size of the image's texture
|
/// The size of the image's texture
|
||||||
///
|
///
|
||||||
/// This field is updated automatically by [`update_image_content_size_system`]
|
/// This field is updated automatically by [`update_image_content_size_system`]
|
||||||
size: Vec2,
|
size: UVec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiImageSize {
|
impl UiImageSize {
|
||||||
/// The size of the image's texture
|
/// The size of the image's texture
|
||||||
pub fn size(&self) -> Vec2 {
|
pub fn size(&self) -> UVec2 {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ pub fn update_image_content_size_system(
|
|||||||
for (mut content_size, image, mut image_size, atlas_image) in &mut query {
|
for (mut content_size, image, mut image_size, atlas_image) in &mut query {
|
||||||
if let Some(size) = match atlas_image {
|
if let Some(size) = match atlas_image {
|
||||||
Some(atlas) => atlas.texture_rect(&atlases).map(|t| t.size()),
|
Some(atlas) => atlas.texture_rect(&atlases).map(|t| t.size()),
|
||||||
None => textures.get(&image.texture).map(|t| t.size_f32()),
|
None => textures.get(&image.texture).map(|t| t.size()),
|
||||||
} {
|
} {
|
||||||
// Update only if size or scale factor has changed to avoid needless layout calculations
|
// Update only if size or scale factor has changed to avoid needless layout calculations
|
||||||
if size != image_size.size
|
if size != image_size.size
|
||||||
@ -102,7 +102,7 @@ pub fn update_image_content_size_system(
|
|||||||
image_size.size = size;
|
image_size.size = size;
|
||||||
content_size.set(ImageMeasure {
|
content_size.set(ImageMeasure {
|
||||||
// multiply the image size by the scale factor to get the physical size
|
// multiply the image size by the scale factor to get the physical size
|
||||||
size: size * combined_scale_factor,
|
size: size.as_vec2() * combined_scale_factor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ fn setup(
|
|||||||
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
|
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
|
||||||
) {
|
) {
|
||||||
let texture = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
|
let texture = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
|
||||||
let layout = TextureAtlasLayout::from_grid(Vec2::new(24.0, 24.0), 7, 1, None, None);
|
let layout = TextureAtlasLayout::from_grid(UVec2::splat(24), 7, 1, None, None);
|
||||||
let texture_atlas_layout = texture_atlas_layouts.add(layout);
|
let texture_atlas_layout = texture_atlas_layouts.add(layout);
|
||||||
// Use only the subset of sprites in the sheet that make up the run animation
|
// Use only the subset of sprites in the sheet that make up the run animation
|
||||||
let animation_indices = AnimationIndices { first: 1, last: 6 };
|
let animation_indices = AnimationIndices { first: 1, last: 6 };
|
||||||
|
|||||||
@ -66,7 +66,7 @@ fn setup(
|
|||||||
let half_y = (map_size.y / 2.0) as i32;
|
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_handle = assets.load("textures/rpg/chars/gabe/gabe-idle-run.png");
|
||||||
let texture_atlas = TextureAtlasLayout::from_grid(Vec2::new(24.0, 24.0), 7, 1, None, None);
|
let texture_atlas = TextureAtlasLayout::from_grid(UVec2::splat(24), 7, 1, None, None);
|
||||||
let texture_atlas_handle = texture_atlases.add(texture_atlas);
|
let texture_atlas_handle = texture_atlases.add(texture_atlas);
|
||||||
|
|
||||||
// Spawns the camera
|
// Spawns the camera
|
||||||
|
|||||||
@ -31,7 +31,7 @@ fn setup(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let texture_handle = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
|
let texture_handle = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
|
||||||
let texture_atlas = TextureAtlasLayout::from_grid(Vec2::new(24.0, 24.0), 7, 1, None, None);
|
let texture_atlas = TextureAtlasLayout::from_grid(UVec2::splat(24), 7, 1, None, None);
|
||||||
let texture_atlas_handle = texture_atlases.add(texture_atlas);
|
let texture_atlas_handle = texture_atlases.add(texture_atlas);
|
||||||
|
|
||||||
// root node
|
// root node
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user