bevy/crates
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
..
bevy_a11y Bump accesskit to 0.19 and accesskit_winit to 0.27 (#19160) 2025-05-26 17:48:36 +00:00
bevy_animation Adopt consistent FooSystems naming convention for system sets (#18900) 2025-05-06 15:18:03 +00:00
bevy_anti_aliasing Remove Shader weak_handles from bevy_anti_aliasing. (#19391) 2025-05-27 03:14:55 +00:00
bevy_app Mention in .add_observer() docs that first parameter must be a Trigger (#19315) 2025-05-26 20:06:08 +00:00
bevy_asset Fix missing meta files breaking Bevy on itch (#19268) 2025-05-30 20:33:47 +00:00
bevy_audio Allow restricting audio playback to a custom region (#19400) 2025-05-29 18:45:37 +00:00
bevy_color More uninlined_format_args fixes (#19396) 2025-05-28 02:35:18 +00:00
bevy_core_pipeline Remove Shader weak_handles from bevy_core_pipeline (except two). (#19395) 2025-05-27 22:32:27 +00:00
bevy_derive Remove upcasting methods + Cleanup interned label code (#18984) 2025-05-26 15:38:12 +00:00
bevy_dev_tools Improve visibility of debug picking node (#18990) 2025-05-26 15:39:49 +00:00
bevy_diagnostic Rename Timer::finished and Timer::paused to is_finished and is_paused (#19386) 2025-05-27 22:24:18 +00:00
bevy_dylib don't disable std in bevy_dylib (#18807) 2025-04-11 18:44:53 +00:00
bevy_ecs Remove invalid entity locations (#19433) 2025-05-31 16:34:33 +00:00
bevy_encase_derive Internalize BevyManifest logic. Switch to RwLock (#18263) 2025-03-12 00:46:01 +00:00
bevy_gilrs refactor(utils): move SyncCell and SyncUnsafeCell to bevy_platform (#19305) 2025-05-27 04:57:26 +00:00
bevy_gizmos Remove Shader weak_handles from bevy_gizmos. (#19394) 2025-05-27 22:32:32 +00:00
bevy_gltf Make sure that serde_json::Map::into_values exists (#19229) 2025-05-26 19:38:28 +00:00
bevy_image Add resize_in_place to Image (#19410) 2025-05-31 21:55:11 +00:00
bevy_input Simplify bevy_utils Features (#19090) 2025-05-24 01:46:11 +00:00
bevy_input_focus Navigate through TabGroups in order. (#19218) 2025-05-26 19:32:10 +00:00
bevy_internal Simplify bevy_utils Features (#19090) 2025-05-24 01:46:11 +00:00
bevy_log refactor(utils): move SyncCell and SyncUnsafeCell to bevy_platform (#19305) 2025-05-27 04:57:26 +00:00
bevy_macro_utils Better macro errors for get_struct_fields (#17639) 2025-05-26 16:57:03 +00:00
bevy_math More uninlined_format_args fixes (#19396) 2025-05-28 02:35:18 +00:00
bevy_mesh Rename bevy_platform_support to bevy_platform (#18813) 2025-04-11 23:13:28 +00:00
bevy_mikktspace fix new nightly lint on mikktspace (#18988) 2025-04-30 05:19:01 +00:00
bevy_pbr Fixed memory leak in bindless material (#19041) 2025-05-30 19:36:56 +00:00
bevy_picking Updating mesh_picking doc to include RenderAssetUsages (#19413) 2025-05-29 18:44:50 +00:00
bevy_platform refactor(utils): move SyncCell and SyncUnsafeCell to bevy_platform (#19305) 2025-05-27 04:57:26 +00:00
bevy_ptr moved Debug from derive to impl_ptr in bevy_ptr (#18042) 2025-02-28 02:54:46 +00:00
bevy_reflect More uninlined_format_args fixes (#19396) 2025-05-28 02:35:18 +00:00
bevy_remote Make sure that serde_json::Map::into_values exists (#19229) 2025-05-26 19:38:28 +00:00
bevy_render Unrequire VisibilityClass from Node (#17918) 2025-05-31 08:18:01 +00:00
bevy_scene Fix #19219 by moving observer triggers out of resource_scope (#19221) 2025-05-30 19:33:47 +00:00
bevy_sprite Remove Shader weak_handles from bevy_sprite. (#19392) 2025-05-27 04:01:34 +00:00
bevy_state Refactor state scoped events to match entities. (#19435) 2025-05-31 20:14:14 +00:00
bevy_tasks Rename bevy_platform_support to bevy_platform (#18813) 2025-04-11 23:13:28 +00:00
bevy_text Remove apostrophes in possessive its (#19244) 2025-05-26 19:53:14 +00:00
bevy_time Rename Timer::finished and Timer::paused to is_finished and is_paused (#19386) 2025-05-27 22:24:18 +00:00
bevy_transform Simplify bevy_utils Features (#19090) 2025-05-24 01:46:11 +00:00
bevy_ui Unrequire VisibilityClass from Node (#17918) 2025-05-31 08:18:01 +00:00
bevy_utils fix reference in example usage comments (#19434) 2025-05-29 19:12:55 +00:00
bevy_window Allow unfocused window creation (#19237) 2025-05-26 20:05:33 +00:00
bevy_winit Allow unfocused window creation (#19237) 2025-05-26 20:05:33 +00:00