Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement images with layout for TextureAtlasBuilder #13302

Closed
wants to merge 4 commits into from

Conversation

s-puig
Copy link
Contributor

@s-puig s-puig commented May 9, 2024

Objective

Solution

  • Allow TextureAtlasBuilder to accept an atlas layout. Given image is sliced into sub-images to generate the final atlas.

Testing

Example code
use bevy::{asset::LoadedFolder, prelude::*};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) // fallback to nearest sampling
        .init_state::<AppState>()
        .add_systems(OnEnter(AppState::Setup), load_textures)
        .add_systems(Update, check_textures.run_if(in_state(AppState::Setup)))
        .add_systems(OnEnter(AppState::Finished), setup)
        .run();
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, States)]
enum AppState {
    #[default]
    Setup,
    Finished,
}

#[derive(Resource, Default)]
struct RpgSpriteFolder(Handle<LoadedFolder>);

fn load_textures(mut commands: Commands, asset_server: Res<AssetServer>) {
    // load multiple, individual sprites from a folder
    commands.insert_resource(RpgSpriteFolder(asset_server.load_folder("textures/rpg")));
}

fn check_textures(
    mut next_state: ResMut<NextState<AppState>>,
    rpg_sprite_folder: Res<RpgSpriteFolder>,
    mut events: EventReader<AssetEvent<LoadedFolder>>,
) {
    // Advance the `AppState` once all sprite handles have been loaded by the `AssetServer`
    for event in events.read() {
        if event.is_loaded_with_dependencies(&rpg_sprite_folder.0) {
            next_state.set(AppState::Finished);
        }
    }
}

fn setup(
    mut commands: Commands,
    //rpg_sprite_handles: Res<RpgSpriteFolder>,
    asset_server: Res<AssetServer>,
    mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
    //loaded_folders: Res<Assets<LoadedFolder>>,
    mut textures: ResMut<Assets<Image>>,
) {
    let gabe = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
    let mani = asset_server.load("textures/rpg/chars/mani/mani-idle-run.png");

    commands.spawn(Camera2dBundle::default());

    let mut atlas_builder = TextureAtlasBuilder::default().padding(UVec2::splat(0));
    atlas_builder.add_texture_with_layout(
        Some(gabe.id()),
        textures.get(gabe.id()).unwrap(),
        TextureAtlasLayout::from_grid(UVec2::splat(24), 7, 1, None, None),
    );
    atlas_builder.add_texture_with_layout(
        Some(mani.id()),
        textures.get(mani.id()).unwrap(),
        TextureAtlasLayout::from_grid(UVec2::splat(24), 7, 1, None, None),
    );
    let (layout, image) = atlas_builder.finish().unwrap();
    let texture = textures.add(image);
    let gabe_layout = texture_atlases.add(layout.sub_layout(gabe.id()).unwrap());
    //let mani_indexes = layout.get_texture_index(mani.id()).unwrap();
    //let layout_handle = texture_atlases.add(layout.clone());
    commands
        .spawn(SpriteBundle {
            texture: texture.clone(),
            transform: Transform::from_xyz(0.0, 48.0, 0.0),
            ..default()
        })
        .insert(TextureAtlas {
            layout: gabe_layout,
            index: 6,
        });

    commands.spawn(SpriteBundle {
        texture,
        ..default()
    });
}

Changelog

Added

  • Image::try_sub_image

Generates a subimage based on the texture and the given rectangular region.

  • TextureAtlasBuilder::add_texture_with_layout

Iterates over each rectangle defined in the layout and attempts to extract sub-images from the provided image based on the layout. The sub-images are then added to the textures to place in the texture atlas builder.

  • TextureAtlasLayout::sub_layout

Generates the TextureAtlasLayout from the given Asset in the method above.

Changed

- get_texture_index(&self, texture: impl Into<AssetId<Image>>) -> Option<usize>
+ get_texture_index(&self, texture: impl Into<AssetId<Image>>) -> Option<&[usize]>

Migration Guide

let image_id: AssetId<Image>
let layout: TextureAtlasLayout
- let layout_index = layout.get_texture_index(image_id);
+ let layout_index = layout.get_texture_index(image_id)[0];

@s-puig s-puig changed the title Implement images with layout to TextureAtlasBuilder Implement images with layout for TextureAtlasBuilder May 9, 2024
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen X-Uncontroversial This work is generally agreed upon D-Straightforward Simple bug fixes and API improvements, docs, test and examples labels May 9, 2024
Co-authored-by: IceSentry <[email protected]>
@janhohenheim janhohenheim added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Jul 17, 2024
@s-puig s-puig marked this pull request as draft September 19, 2024 18:38
@BenjaminBrienen BenjaminBrienen added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Sep 25, 2024
@s-puig
Copy link
Contributor Author

s-puig commented Oct 12, 2024

Closing this.

I will try another approach more in line with #15365

@s-puig s-puig closed this Oct 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged X-Uncontroversial This work is generally agreed upon
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Combine multiple sprites into a single texture atlas
5 participants