//! Shows how to modify texture assets after spawning.12use bevy::{3asset::RenderAssetUsages, image::ImageLoaderSettings,4input::common_conditions::input_just_pressed, prelude::*,5};67fn main() {8App::new()9.add_plugins(DefaultPlugins)10.add_systems(Startup, (setup, spawn_text))11.add_systems(12Update,13alter_handle.run_if(input_just_pressed(KeyCode::Space)),14)15.add_systems(16Update,17alter_asset.run_if(input_just_pressed(KeyCode::Enter)),18)19.run();20}2122#[derive(Component, Debug)]23enum Bird {24Normal,25Logo,26}2728impl Bird {29fn get_texture_path(&self) -> String {30match self {31Bird::Normal => "branding/bevy_bird_dark.png".into(),32Bird::Logo => "branding/bevy_logo_dark.png".into(),33}34}3536fn set_next_variant(&mut self) {37*self = match self {38Bird::Normal => Bird::Logo,39Bird::Logo => Bird::Normal,40}41}42}4344#[derive(Component, Debug)]45struct Left;4647fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {48let bird_left = Bird::Normal;49let bird_right = Bird::Normal;50commands.spawn(Camera2d);5152let texture_left = asset_server.load_with_settings(53bird_left.get_texture_path(),54// `RenderAssetUsages::all()` is already the default, so the line below could be omitted.55// It's helpful to know it exists, however.56//57// `RenderAssetUsages` tell Bevy whether to keep the data around:58// - for the GPU (`RenderAssetUsages::RENDER_WORLD`),59// - for the CPU (`RenderAssetUsages::MAIN_WORLD`),60// - or both.61// `RENDER_WORLD` is necessary to render the image, `MAIN_WORLD` is necessary to inspect62// and modify the image (via `ResMut<Assets<Image>>`).63//64// Since most games will not need to modify textures at runtime, many developers opt to pass65// only `RENDER_WORLD`. This is more memory efficient, as we don't need to keep the image in66// RAM. For this example however, this would not work, as we need to inspect and modify the67// image at runtime.68|settings: &mut ImageLoaderSettings| settings.asset_usage = RenderAssetUsages::all(),69);7071commands.spawn((72Name::new("Bird Left"),73// This marker component ensures we can easily find either of the Birds by using With and74// Without query filters.75Left,76Sprite::from_image(texture_left),77Transform::from_xyz(-200.0, 0.0, 0.0),78bird_left,79));8081commands.spawn((82Name::new("Bird Right"),83// In contrast to the above, here we rely on the default `RenderAssetUsages` loader setting84Sprite::from_image(asset_server.load(bird_right.get_texture_path())),85Transform::from_xyz(200.0, 0.0, 0.0),86bird_right,87));88}8990fn spawn_text(mut commands: Commands) {91commands.spawn((92Name::new("Instructions"),93Text::new(94"Space: swap the right sprite's image handle\n\95Return: modify the image Asset of the left sprite, affecting all uses of it",96),97Node {98position_type: PositionType::Absolute,99top: px(12),100left: px(12),101..default()102},103));104}105106fn alter_handle(107asset_server: Res<AssetServer>,108right_bird: Single<(&mut Bird, &mut Sprite), Without<Left>>,109) {110// Image handles, like other parts of the ECS, can be queried as mutable and modified at111// runtime. We only spawned one bird without the `Left` marker component.112let (mut bird, mut sprite) = right_bird.into_inner();113114// Switch to a new Bird variant115bird.set_next_variant();116117// Modify the handle associated with the Bird on the right side. Note that we will only118// have to load the same path from storage media once: repeated attempts will re-use the119// asset.120sprite.image = asset_server.load(bird.get_texture_path());121}122123fn alter_asset(mut images: ResMut<Assets<Image>>, left_bird: Single<&Sprite, With<Left>>) {124// Obtain a mutable reference to the Image asset.125let Some(image) = images.get_mut(&left_bird.image) else {126return;127};128129for pixel in image.data.as_mut().unwrap() {130// Directly modify the asset data, which will affect all users of this asset. By131// contrast, mutating the handle (as we did above) affects only one copy. In this case,132// we'll just invert the colors, by way of demonstration. Notice that both uses of the133// asset show the change, not just the one on the left.134*pixel = 255 - *pixel;135}136}137138139