From 5fe73be2b560f3d95abcc5aa9e9730436e2f794a Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Wed, 1 Dec 2021 23:09:31 +0000 Subject: [PATCH] Sprite change image (#3207) # Objective - Changing the underlying image would not update a sprite ## Solution - 'Detect' if the underlying image changes to update the sprite Currently, we don't support change detection on `RenderAssets`, so we have to manually check it. This method at least maintains the bind groups when the image isn't changing. They were cached, so I assume that's important. This gives us correct behaviour here. Co-authored-by: Carter Anderson --- pipelined/bevy_render2/src/render_asset.rs | 5 +-- pipelined/bevy_sprite2/src/lib.rs | 2 + pipelined/bevy_sprite2/src/render/mod.rs | 43 +++++++++++++++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/pipelined/bevy_render2/src/render_asset.rs b/pipelined/bevy_render2/src/render_asset.rs index 6b259efd7180c..9d9cd099fd43e 100644 --- a/pipelined/bevy_render2/src/render_asset.rs +++ b/pipelined/bevy_render2/src/render_asset.rs @@ -102,9 +102,8 @@ fn extract_render_asset( changed_assets.insert(handle); } AssetEvent::Removed { handle } => { - if !changed_assets.remove(handle) { - removed.push(handle.clone_weak()); - } + changed_assets.remove(handle); + removed.push(handle.clone_weak()); } } } diff --git a/pipelined/bevy_sprite2/src/lib.rs b/pipelined/bevy_sprite2/src/lib.rs index 27d36548c8ba3..cd3bb5babac83 100644 --- a/pipelined/bevy_sprite2/src/lib.rs +++ b/pipelined/bevy_sprite2/src/lib.rs @@ -43,7 +43,9 @@ impl Plugin for SpritePlugin { .init_resource::>() .init_resource::() .init_resource::() + .init_resource::() .add_system_to_stage(RenderStage::Extract, render::extract_sprites) + .add_system_to_stage(RenderStage::Extract, render::extract_sprite_events) .add_system_to_stage(RenderStage::Prepare, render::prepare_sprites) .add_system_to_stage(RenderStage::Queue, queue_sprites); diff --git a/pipelined/bevy_sprite2/src/render/mod.rs b/pipelined/bevy_sprite2/src/render/mod.rs index eb330900034af..41fa90b419be4 100644 --- a/pipelined/bevy_sprite2/src/render/mod.rs +++ b/pipelined/bevy_sprite2/src/render/mod.rs @@ -4,7 +4,7 @@ use crate::{ texture_atlas::{TextureAtlas, TextureAtlasSprite}, Rect, Sprite, SPRITE_SHADER_HANDLE, }; -use bevy_asset::{Assets, Handle}; +use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_core::FloatOrd; use bevy_core_pipeline::Transparent2d; use bevy_ecs::{ @@ -172,6 +172,37 @@ pub struct ExtractedSprites { sprites: Vec, } +#[derive(Default)] +pub struct SpriteAssetEvents { + images: Vec>, +} + +pub fn extract_sprite_events( + mut render_world: ResMut, + mut image_events: EventReader>, +) { + let mut events = render_world + .get_resource_mut::() + .unwrap(); + let SpriteAssetEvents { ref mut images } = *events; + images.clear(); + + for image in image_events.iter() { + // AssetEvent: !Clone + images.push(match image { + AssetEvent::Created { handle } => AssetEvent::Created { + handle: handle.clone_weak(), + }, + AssetEvent::Modified { handle } => AssetEvent::Modified { + handle: handle.clone_weak(), + }, + AssetEvent::Removed { handle } => AssetEvent::Removed { + handle: handle.clone_weak(), + }, + }); + } +} + pub fn extract_sprites( mut render_world: ResMut, images: Res>, @@ -453,7 +484,17 @@ pub fn queue_sprites( gpu_images: Res>, mut sprite_batches: Query<(Entity, &SpriteBatch)>, mut views: Query<&mut RenderPhase>, + events: Res, ) { + // If an image has changed, the GpuImage has (probably) changed + for event in &events.images { + match event { + AssetEvent::Created { .. } => None, + AssetEvent::Modified { handle } => image_bind_groups.values.remove(handle), + AssetEvent::Removed { handle } => image_bind_groups.values.remove(handle), + }; + } + if let Some(view_binding) = view_uniforms.uniforms.binding() { sprite_meta.view_bind_group = Some(render_device.create_bind_group(&BindGroupDescriptor { entries: &[BindGroupEntry {