Refactor tonemapping example's image viewer update into two systems (#11519)

# Objective

Alternative to #11515.

Fixes change detection being triggered on the "image viewer image
material" every frame.

## Solution

- Split the megasystem into two separate systems: one to handle drop
events, and one to handle asset change events.
- Move the event reader iteration "outside." so that we're only doing
stuff when there are events.
- Flatten some of the more extreme nesting
- Other bits of cleanup, removing an unnecessary clone and unused
variable.

I think these systems can even run in parallel now, not that it
particularly matters.
This commit is contained in:
Rob Parrett 2024-01-27 09:06:34 -07:00 committed by GitHub
parent 45e920c2e1
commit 7da144bc3d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -40,7 +40,8 @@ fn main() {
.add_systems(
Update,
(
update_image_viewer,
drag_drop_image,
resize_image,
toggle_scene,
toggle_tonemapping_method,
update_color_grading_settings,
@ -292,58 +293,68 @@ fn setup_image_viewer_scene(
// ----------------------------------------------------------------------------
#[allow(clippy::too_many_arguments)]
fn update_image_viewer(
image_mesh: Query<(&Handle<StandardMaterial>, &Handle<Mesh>), With<HDRViewer>>,
fn drag_drop_image(
image_mat: Query<&Handle<StandardMaterial>, With<HDRViewer>>,
text: Query<Entity, (With<Text>, With<SceneNumber>)>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
images: Res<Assets<Image>>,
mut drop_events: EventReader<FileDragAndDrop>,
mut drop_hovered: Local<bool>,
asset_server: Res<AssetServer>,
mut image_events: EventReader<AssetEvent<Image>>,
mut commands: Commands,
) {
let mut new_image: Option<Handle<Image>> = None;
let Some(new_image) = drop_events.read().find_map(|e| match e {
FileDragAndDrop::DroppedFile { path_buf, .. } => {
Some(asset_server.load(path_buf.to_string_lossy().to_string()))
}
_ => None,
}) else {
return;
};
for event in drop_events.read() {
match event {
FileDragAndDrop::DroppedFile { path_buf, .. } => {
new_image = Some(asset_server.load(&path_buf.to_string_lossy().to_string()));
*drop_hovered = false;
for mat_h in &image_mat {
if let Some(mat) = materials.get_mut(mat_h) {
mat.base_color_texture = Some(new_image.clone());
// Despawn the image viewer instructions
if let Ok(text_entity) = text.get_single() {
commands.entity(text_entity).despawn();
}
FileDragAndDrop::HoveredFile { .. } => *drop_hovered = true,
FileDragAndDrop::HoveredFileCanceled { .. } => *drop_hovered = false,
}
}
}
for (mat_h, mesh_h) in &image_mesh {
if let Some(mat) = materials.get_mut(mat_h) {
if let Some(ref new_image) = new_image {
mat.base_color_texture = Some(new_image.clone());
fn resize_image(
image_mesh: Query<(&Handle<StandardMaterial>, &Handle<Mesh>), With<HDRViewer>>,
materials: Res<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
images: Res<Assets<Image>>,
mut image_events: EventReader<AssetEvent<Image>>,
) {
for event in image_events.read() {
let (AssetEvent::Added { id } | AssetEvent::Modified { id }) = event else {
continue;
};
if let Ok(text_entity) = text.get_single() {
commands.entity(text_entity).despawn();
}
}
for (mat_h, mesh_h) in &image_mesh {
let Some(mat) = materials.get(mat_h) else {
continue;
};
for event in image_events.read() {
let image_changed_id = *match event {
AssetEvent::Added { id } | AssetEvent::Modified { id } => id,
_ => continue,
};
if let Some(base_color_texture) = mat.base_color_texture.clone() {
if image_changed_id == base_color_texture.id() {
if let Some(image_changed) = images.get(image_changed_id) {
let size = image_changed.size_f32().normalize_or_zero() * 1.4;
// Resize Mesh
let quad = Mesh::from(shape::Quad::new(size));
meshes.insert(mesh_h, quad);
}
}
}
}
let Some(ref base_color_texture) = mat.base_color_texture else {
continue;
};
if *id != base_color_texture.id() {
continue;
};
let Some(image_changed) = images.get(*id) else {
continue;
};
let size = image_changed.size_f32().normalize_or_zero() * 1.4;
// Resize Mesh
let quad = Mesh::from(shape::Quad::new(size));
meshes.insert(mesh_h, quad);
}
}
}