Skip to content

Commit

Permalink
TextureAtlasBuilder padding (#9494)
Browse files Browse the repository at this point in the history
# Objective

`TextureAtlas` supports pregenerated texture atlases with padding, but
`TextureAtlasBuilder` can't add padding when it creates a new atlas.

fixes #8150

## Solution

Add a method `padding` to `TextureAtlasBuilder` that sets the amount of
padding to add around each texture.

When queueing the textures to be copied, add the padding value to the
size of each source texture. Then when copying the source textures to
the output atlas texture subtract the same padding value from the sizes
of the target rects.

unpadded:
<img width="961" alt="texture_atlas_example"
src="https://github.com/bevyengine/bevy/assets/27962798/8cf02442-dc3e-4429-90f1-543bc9270d8b">

padded:
<img width="961" alt="texture_atlas_example_with_padding"
src="https://github.com/bevyengine/bevy/assets/27962798/da347bcc-b083-4650-ba0c-86883853764f">


---

## Changelog
`TextureAtlasBuilder`
* Added support for building texture atlases with padding.
* Adds a `padding` method to `TextureAtlasBuilder` that can be used to
set an amount of padding to add between the sprites of the generated
texture atlas.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
  • Loading branch information
ickshonpe and alice-i-cecile authored Sep 8, 2023
1 parent 73447b6 commit e663d45
Showing 1 changed file with 26 additions and 9 deletions.
35 changes: 26 additions & 9 deletions crates/bevy_sprite/src/texture_atlas_builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy_asset::{AssetId, Assets};
use bevy_log::{debug, error, warn};
use bevy_math::{Rect, Vec2};
use bevy_math::{Rect, UVec2, Vec2};
use bevy_render::{
render_resource::{Extent3d, TextureDimension, TextureFormat},
texture::{Image, TextureFormatPixelInfo},
Expand Down Expand Up @@ -38,6 +38,8 @@ pub struct TextureAtlasBuilder {
format: TextureFormat,
/// Enable automatic format conversion for textures if they are not in the atlas format.
auto_format_conversion: bool,
/// The amount of padding in pixels to add along the right and bottom edges of the texture rects.
padding: UVec2,
}

impl Default for TextureAtlasBuilder {
Expand All @@ -48,6 +50,7 @@ impl Default for TextureAtlasBuilder {
max_size: Vec2::new(2048., 2048.),
format: TextureFormat::Rgba8UnormSrgb,
auto_format_conversion: true,
padding: UVec2::ZERO,
}
}
}
Expand Down Expand Up @@ -85,20 +88,29 @@ impl TextureAtlasBuilder {
image_id,
None,
RectToInsert::new(
texture.texture_descriptor.size.width,
texture.texture_descriptor.size.height,
texture.texture_descriptor.size.width + self.padding.x,
texture.texture_descriptor.size.height + self.padding.y,
1,
),
);
}

/// Sets the amount of padding in pixels to add between the textures in the texture atlas.
///
/// The `x` value provide will be added to the right edge, while the `y` value will be added to the bottom edge.
pub fn padding(mut self, padding: UVec2) -> Self {
self.padding = padding;
self
}

fn copy_texture_to_atlas(
atlas_texture: &mut Image,
texture: &Image,
packed_location: &PackedLocation,
padding: UVec2,
) {
let rect_width = packed_location.width() as usize;
let rect_height = packed_location.height() as usize;
let rect_width = (packed_location.width() - padding.x) as usize;
let rect_height = (packed_location.height() - padding.y) as usize;
let rect_x = packed_location.x() as usize;
let rect_y = packed_location.y() as usize;
let atlas_width = atlas_texture.texture_descriptor.size.width as usize;
Expand All @@ -121,13 +133,18 @@ impl TextureAtlasBuilder {
packed_location: &PackedLocation,
) {
if self.format == texture.texture_descriptor.format {
Self::copy_texture_to_atlas(atlas_texture, texture, packed_location);
Self::copy_texture_to_atlas(atlas_texture, texture, packed_location, self.padding);
} else if let Some(converted_texture) = texture.convert(self.format) {
debug!(
"Converting texture from '{:?}' to '{:?}'",
texture.texture_descriptor.format, self.format
);
Self::copy_texture_to_atlas(atlas_texture, &converted_texture, packed_location);
Self::copy_texture_to_atlas(
atlas_texture,
&converted_texture,
packed_location,
self.padding,
);
} else {
error!(
"Error converting texture from '{:?}' to '{:?}', ignoring",
Expand Down Expand Up @@ -213,8 +230,8 @@ impl TextureAtlasBuilder {
let min = Vec2::new(packed_location.x() as f32, packed_location.y() as f32);
let max = min
+ Vec2::new(
packed_location.width() as f32,
packed_location.height() as f32,
(packed_location.width() - self.padding.x) as f32,
(packed_location.height() - self.padding.y) as f32,
);
texture_ids.insert(*image_id, texture_rects.len());
texture_rects.push(Rect { min, max });
Expand Down

0 comments on commit e663d45

Please sign in to comment.