bevy/crates/bevy_image/src
Rob Parrett dc4737923c
Add resize_in_place to Image (#19410)
# Objective

Ultimately, I'd like to modify our font atlas creation systems so that
they are able to resize the font atlases as more glyphs are added. At
the moment, they create a new 512x512 atlas every time one fills up.
With large font sizes and many glyphs, your glyphs may end up spread out
across several atlases.

The goal would be to render text more efficiently, because glyphs spread
across fewer textures could benefit more from batching.

`AtlasAllocator` already has support for growing atlases, but we don't
currently have a way of growing a texture while keeping the pixel data
intact.

## Solution

Add a new method to `Image`: `resize_in_place` and a test for it.

## Testing

Ran the new test, and also a little demo comparing this side-by-side
with `resize`.

<details>
<summary>Expand Code</summary>

```rust
//! Testing ground for #19410

use bevy::prelude::*;
use bevy_render::render_resource::Extent3d;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, test)
        .init_resource::<Size>()
        .insert_resource(FillColor(Hsla::hsl(0.0, 1.0, 0.7)))
        .run();
}

#[derive(Resource, Default)]
struct Size(Option<UVec2>);
#[derive(Resource)]
struct FillColor(Hsla);
#[derive(Component)]
struct InPlace;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(Camera2d);

    commands.spawn((
        Transform::from_xyz(220.0, 0.0, 0.0),
        Sprite::from_image(asset_server.load("branding/bevy_bird_dark.png")),
    ));

    commands.spawn((
        InPlace,
        Transform::from_xyz(-220.0, 0.0, 0.0),
        Sprite::from_image(asset_server.load("branding/icon.png")),
    ));
}

fn test(
    sprites: Query<(&Sprite, Has<InPlace>)>,
    mut images: ResMut<Assets<Image>>,
    mut new_size: ResMut<Size>,
    mut dir: Local<IVec2>,
    mut color: ResMut<FillColor>,
) -> Result {
    for (sprite, in_place) in &sprites {
        let image = images.get_mut(&sprite.image).ok_or("Image not found")?;
        let size = new_size.0.get_or_insert(image.size());

        if *dir == IVec2::ZERO {
            *dir = IVec2::splat(1);
        }

        *size = size.saturating_add_signed(*dir);

        if size.x > 400 || size.x < 150 {
            *dir = *dir * -1;
        }

        color.0 = color.0.rotate_hue(1.0);

        if in_place {
            image.resize_in_place_2d(
                Extent3d {
                    width: size.x,
                    height: size.y,
                    ..default()
                },
                &Srgba::from(color.0).to_u8_array(),
            )?;
        } else {
            image.resize(Extent3d {
                width: size.x,
                height: size.y,
                ..default()
            });
        }
    }

    Ok(())
}
```
</details>


https://github.com/user-attachments/assets/6b2d0ec3-6a6e-4da1-98aa-29e7162f16fa

## Alternatives

I think that this might be useful functionality outside of the font
atlas scenario, but we *could* just increase the initial font atlas
size, make it configurable, and/or size font atlases according to device
limits. It's not totally clear to me how to accomplish that last idea.
2025-05-31 21:55:11 +00:00
..
basis.rs Allowed creating uninitialized images (for use as storage textures) (#17760) 2025-02-10 22:22:07 +00:00
compressed_image_saver.rs Allowed creating uninitialized images (for use as storage textures) (#17760) 2025-02-10 22:22:07 +00:00
dds.rs Remove Image::from_buffer name argument (only present in debug "dds" builds) (#18538) 2025-03-25 19:25:01 +00:00
dynamic_texture_atlas_builder.rs Bump typos to 1.30.0 (#18097) 2025-03-02 19:02:23 +00:00
exr_texture_loader.rs Deny derive_more error feature and replace it with thiserror (#16684) 2024-12-06 17:03:55 +00:00
hdr_texture_loader.rs Deny derive_more error feature and replace it with thiserror (#16684) 2024-12-06 17:03:55 +00:00
image_loader.rs Remove Image::from_buffer name argument (only present in debug "dds" builds) (#18538) 2025-03-25 19:25:01 +00:00
image_texture_conversion.rs Allowed creating uninitialized images (for use as storage textures) (#17760) 2025-02-10 22:22:07 +00:00
image.rs Add resize_in_place to Image (#19410) 2025-05-31 21:55:11 +00:00
ktx2.rs Provide physical dimensions to wgpu Device::create_texture_with_data (#19129) 2025-05-26 17:36:47 +00:00
lib.rs Move #![warn(clippy::allow_attributes, clippy::allow_attributes_without_reason)] to the workspace Cargo.toml (#17374) 2025-01-15 01:14:58 +00:00
texture_atlas_builder.rs Rename bevy_platform_support to bevy_platform (#18813) 2025-04-11 23:13:28 +00:00
texture_atlas.rs Add TextureAtlas convenience methods (#19023) 2025-05-04 08:11:59 +00:00