update ColorMaterial when Texture changed (#1461)

fixes #1161, fixes #1243

this adds two systems:
- first is keeping an hashmap of textures and their containing color materials, then listening to events on textures to select color materials that should be updated
- second is chained to send a modified event for all color materials that need updating
This commit is contained in:
François 2021-03-17 19:53:24 +00:00
parent 284889c64b
commit 107dd73687
2 changed files with 102 additions and 1 deletions

View File

@ -1,6 +1,9 @@
use bevy_asset::{self, Handle};
use bevy_app::{EventReader, Events, ManualEventReader};
use bevy_asset::{self, AssetEvent, Assets, Handle};
use bevy_ecs::system::{Local, Res, ResMut};
use bevy_reflect::TypeUuid;
use bevy_render::{color::Color, renderer::RenderResources, shader::ShaderDefs, texture::Texture};
use bevy_utils::{HashMap, HashSet};
#[derive(Debug, RenderResources, ShaderDefs, TypeUuid)]
#[uuid = "506cff92-a9f3-4543-862d-6851c7fdfc99"]
@ -53,3 +56,97 @@ impl From<Handle<Texture>> for ColorMaterial {
ColorMaterial::texture(texture)
}
}
// Temporary solution for sub-assets change handling, see https://github.com/bevyengine/bevy/issues/1161#issuecomment-780467768
// TODO: should be removed when pipelined rendering is done
pub(crate) fn material_texture_detection_system(
mut texture_to_material: Local<HashMap<Handle<Texture>, HashSet<Handle<ColorMaterial>>>>,
mut material_to_texture: Local<HashMap<Handle<ColorMaterial>, Handle<Texture>>>,
materials: Res<Assets<ColorMaterial>>,
mut texture_events: EventReader<AssetEvent<Texture>>,
(mut material_events_reader, mut material_events): (
Local<ManualEventReader<AssetEvent<ColorMaterial>>>,
ResMut<Events<AssetEvent<ColorMaterial>>>,
),
) {
for event in material_events_reader.iter(&material_events) {
match event {
AssetEvent::Created { handle } => {
if let Some(texture) = materials.get(handle).and_then(|mat| mat.texture.as_ref()) {
material_to_texture.insert(handle.clone_weak(), texture.clone_weak());
texture_to_material
.entry(texture.clone_weak())
.or_default()
.insert(handle.clone_weak());
}
}
AssetEvent::Modified { handle } => {
let old_texture = material_to_texture.get(handle).cloned();
match (
materials.get(handle).and_then(|mat| mat.texture.as_ref()),
old_texture,
) {
(None, None) => (),
(Some(texture), None) => {
material_to_texture.insert(handle.clone_weak(), texture.clone_weak());
texture_to_material
.entry(texture.clone_weak())
.or_default()
.insert(handle.clone_weak());
}
(None, Some(texture)) => {
material_to_texture.remove(handle);
texture_to_material
.entry(texture.clone_weak())
.or_default()
.remove(handle);
}
(Some(new_texture), Some(old_texture)) => {
if &old_texture == new_texture {
continue;
}
material_to_texture.insert(handle.clone_weak(), new_texture.clone_weak());
texture_to_material
.entry(new_texture.clone_weak())
.or_default()
.insert(handle.clone_weak());
texture_to_material
.entry(old_texture.clone_weak())
.or_default()
.remove(handle);
}
}
}
AssetEvent::Removed { handle } => {
if let Some(texture) = materials.get(handle).and_then(|mat| mat.texture.as_ref()) {
material_to_texture.remove(handle);
texture_to_material
.entry(texture.clone_weak())
.or_default()
.remove(handle);
}
}
}
}
let mut changed_textures = HashSet::default();
for event in texture_events.iter() {
match event {
AssetEvent::Created { handle }
| AssetEvent::Modified { handle }
| AssetEvent::Removed { handle } => {
changed_textures.insert(handle);
}
}
}
for texture_handle in changed_textures.iter() {
if let Some(materials) = texture_to_material.get(texture_handle) {
for material in materials.iter() {
material_events.send(AssetEvent::Modified {
handle: material.clone_weak(),
});
}
}
}
}

View File

@ -50,6 +50,10 @@ impl Plugin for SpritePlugin {
.register_type::<Sprite>()
.register_type::<SpriteResizeMode>()
.add_system_to_stage(CoreStage::PostUpdate, sprite_system.system())
.add_system_to_stage(
CoreStage::PostUpdate,
material_texture_detection_system.system(),
)
.add_system_to_stage(
CoreStage::PostUpdate,
asset_shader_defs_system::<ColorMaterial>.system(),