From 4a1645bb8a543ef40db2b792551958f5adeb4dc3 Mon Sep 17 00:00:00 2001 From: s-puig <39652109+s-puig@users.noreply.github.com> Date: Mon, 30 Sep 2024 19:03:31 +0200 Subject: [PATCH] Fix bevy_picking sprite backend panic in out of bounds atlas index (#15202) # Objective - Fix panic when atlas index is out of bounds - Took the chance to clean it up a bit ## Solution - Use texture dimensions like rendering pipeline. Dropped atlas layouts and indexes out of bounds are shown as a sprite. ## Testing Used sprite_picking example, drop layout and/or use indexes out of bounds. --- crates/bevy_sprite/src/picking_backend.rs | 49 +++++++++-------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/crates/bevy_sprite/src/picking_backend.rs b/crates/bevy_sprite/src/picking_backend.rs index baf06d1a14..7199d7875d 100644 --- a/crates/bevy_sprite/src/picking_backend.rs +++ b/crates/bevy_sprite/src/picking_backend.rs @@ -29,18 +29,15 @@ pub fn sprite_picking( primary_window: Query>, images: Res>, texture_atlas_layout: Res>, - sprite_query: Query< - ( - Entity, - Option<&Sprite>, - Option<&TextureAtlas>, - Option<&Handle>, - &GlobalTransform, - Option<&Pickable>, - &ViewVisibility, - ), - Or<(With, With)>, - >, + sprite_query: Query<( + Entity, + &Sprite, + Option<&TextureAtlas>, + &Handle, + &GlobalTransform, + Option<&Pickable>, + &ViewVisibility, + )>, mut output: EventWriter, ) { let mut sorted_sprites: Vec<_> = sprite_query @@ -87,24 +84,18 @@ pub fn sprite_picking( } // Hit box in sprite coordinate system - let (extents, anchor) = if let Some((sprite, atlas)) = sprite.zip(atlas) { - let extents = sprite.custom_size.or_else(|| { - texture_atlas_layout - .get(&atlas.layout) - .map(|f| f.textures[atlas.index].size().as_vec2()) - })?; - let anchor = sprite.anchor.as_vec(); - (extents, anchor) - } else if let Some((sprite, image)) = sprite.zip(image) { - let extents = sprite - .custom_size - .or_else(|| images.get(image).map(|f| f.size().as_vec2()))?; - let anchor = sprite.anchor.as_vec(); - (extents, anchor) - } else { - return None; + let extents = match (sprite.custom_size, atlas) { + (Some(custom_size), _) => custom_size, + (None, None) => images.get(image)?.size().as_vec2(), + (None, Some(atlas)) => texture_atlas_layout + .get(&atlas.layout) + .and_then(|layout| layout.textures.get(atlas.index)) + // Dropped atlas layouts and indexes out of bounds are rendered as a sprite + .map_or(images.get(image)?.size().as_vec2(), |rect| { + rect.size().as_vec2() + }), }; - + let anchor = sprite.anchor.as_vec(); let center = -anchor * extents; let rect = Rect::from_center_half_size(center, extents / 2.0);