Extract UI nodes into a Vec (#17618)
# Objective Extract UI nodes into a `Vec` instead of an `EntityHashMap`. ## Solution Extract UI nodes into a `Vec` instead of an `EntityHashMap`. Store an index into the `Vec` in each transparent UI item. Compare both the index and render entity in prepare so there aren't any collisions. ## Showcase Yellow this PR, Red main ``` cargo run --example many_buttons --release --features trace_tracy ``` `extract_uinode_background_colors` <img width="448" alt="extract_uinode_background_colors" src="https://github.com/user-attachments/assets/09c0f434-ab4f-4c0f-956a-cf31e9060061" /> `extract_uinode_images` <img width="587" alt="extract_uinode_images" src="https://github.com/user-attachments/assets/43246d7f-d22c-46d0-9a07-7e13d5379f56" /> `prepare_uinodes` <img width="441" alt="prepare_uinodes_vec" src="https://github.com/user-attachments/assets/cc9a7eac-60e9-42fa-8093-bce833a1c153" />
This commit is contained in:
		
							parent
							
								
									59697f9ccc
								
							
						
					
					
						commit
						ba1b0092e5
					
				| @ -12,7 +12,6 @@ use bevy_color::{Alpha, ColorToComponents, LinearRgba}; | |||||||
| use bevy_ecs::prelude::*; | use bevy_ecs::prelude::*; | ||||||
| use bevy_ecs::{ | use bevy_ecs::{ | ||||||
|     prelude::Component, |     prelude::Component, | ||||||
|     storage::SparseSet, |  | ||||||
|     system::{ |     system::{ | ||||||
|         lifetimeless::{Read, SRes}, |         lifetimeless::{Read, SRes}, | ||||||
|         *, |         *, | ||||||
| @ -225,12 +224,13 @@ pub struct ExtractedBoxShadow { | |||||||
|     pub blur_radius: f32, |     pub blur_radius: f32, | ||||||
|     pub size: Vec2, |     pub size: Vec2, | ||||||
|     pub main_entity: MainEntity, |     pub main_entity: MainEntity, | ||||||
|  |     pub render_entity: Entity, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// List of extracted shadows to be sorted and queued for rendering
 | /// List of extracted shadows to be sorted and queued for rendering
 | ||||||
| #[derive(Resource, Default)] | #[derive(Resource, Default)] | ||||||
| pub struct ExtractedBoxShadows { | pub struct ExtractedBoxShadows { | ||||||
|     pub box_shadows: SparseSet<Entity, ExtractedBoxShadow>, |     pub box_shadows: Vec<ExtractedBoxShadow>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn extract_shadows( | pub fn extract_shadows( | ||||||
| @ -311,22 +311,19 @@ pub fn extract_shadows( | |||||||
|                 bottom_right: uinode.border_radius.bottom_right * spread_ratio, |                 bottom_right: uinode.border_radius.bottom_right * spread_ratio, | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             extracted_box_shadows.box_shadows.insert( |             extracted_box_shadows.box_shadows.push(ExtractedBoxShadow { | ||||||
|                 commands.spawn(TemporaryRenderEntity).id(), |                 render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|                 ExtractedBoxShadow { |                 stack_index: uinode.stack_index, | ||||||
|                     stack_index: uinode.stack_index, |                 transform: transform.compute_matrix() * Mat4::from_translation(offset.extend(0.)), | ||||||
|                     transform: transform.compute_matrix() |                 color: drop_shadow.color.into(), | ||||||
|                         * Mat4::from_translation(offset.extend(0.)), |                 bounds: shadow_size + 6. * blur_radius, | ||||||
|                     color: drop_shadow.color.into(), |                 clip: clip.map(|clip| clip.clip), | ||||||
|                     bounds: shadow_size + 6. * blur_radius, |                 extracted_camera_entity, | ||||||
|                     clip: clip.map(|clip| clip.clip), |                 radius, | ||||||
|                     extracted_camera_entity, |                 blur_radius, | ||||||
|                     radius, |                 size: shadow_size, | ||||||
|                     blur_radius, |                 main_entity: entity.into(), | ||||||
|                     size: shadow_size, |             }); | ||||||
|                     main_entity: entity.into(), |  | ||||||
|                 }, |  | ||||||
|             ); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -346,7 +343,8 @@ pub fn queue_shadows( | |||||||
|     draw_functions: Res<DrawFunctions<TransparentUi>>, |     draw_functions: Res<DrawFunctions<TransparentUi>>, | ||||||
| ) { | ) { | ||||||
|     let draw_function = draw_functions.read().id::<DrawBoxShadows>(); |     let draw_function = draw_functions.read().id::<DrawBoxShadows>(); | ||||||
|     for (entity, extracted_shadow) in extracted_box_shadows.box_shadows.iter() { |     for (index, extracted_shadow) in extracted_box_shadows.box_shadows.iter().enumerate() { | ||||||
|  |         let entity = extracted_shadow.render_entity; | ||||||
|         let Ok((default_camera_view, shadow_samples)) = |         let Ok((default_camera_view, shadow_samples)) = | ||||||
|             render_views.get_mut(extracted_shadow.extracted_camera_entity) |             render_views.get_mut(extracted_shadow.extracted_camera_entity) | ||||||
|         else { |         else { | ||||||
| @ -374,13 +372,14 @@ pub fn queue_shadows( | |||||||
|         transparent_phase.add(TransparentUi { |         transparent_phase.add(TransparentUi { | ||||||
|             draw_function, |             draw_function, | ||||||
|             pipeline, |             pipeline, | ||||||
|             entity: (*entity, extracted_shadow.main_entity), |             entity: (entity, extracted_shadow.main_entity), | ||||||
|             sort_key: ( |             sort_key: ( | ||||||
|                 FloatOrd(extracted_shadow.stack_index as f32 + stack_z_offsets::BOX_SHADOW), |                 FloatOrd(extracted_shadow.stack_index as f32 + stack_z_offsets::BOX_SHADOW), | ||||||
|                 entity.index(), |                 entity.index(), | ||||||
|             ), |             ), | ||||||
|             batch_range: 0..0, |             batch_range: 0..0, | ||||||
|             extra_index: PhaseItemExtraIndex::None, |             extra_index: PhaseItemExtraIndex::None, | ||||||
|  |             index, | ||||||
|             indexed: true, |             indexed: true, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| @ -417,11 +416,13 @@ pub fn prepare_shadows( | |||||||
|         let mut indices_index = 0; |         let mut indices_index = 0; | ||||||
| 
 | 
 | ||||||
|         for ui_phase in phases.values_mut() { |         for ui_phase in phases.values_mut() { | ||||||
|             let mut item_index = 0; |             for item_index in 0..ui_phase.items.len() { | ||||||
| 
 |  | ||||||
|             while item_index < ui_phase.items.len() { |  | ||||||
|                 let item = &mut ui_phase.items[item_index]; |                 let item = &mut ui_phase.items[item_index]; | ||||||
|                 if let Some(box_shadow) = extracted_shadows.box_shadows.get(item.entity()) { |                 if let Some(box_shadow) = extracted_shadows | ||||||
|  |                     .box_shadows | ||||||
|  |                     .get(item.index) | ||||||
|  |                     .filter(|n| item.entity() == n.render_entity) | ||||||
|  |                 { | ||||||
|                     let rect_size = box_shadow.bounds.extend(1.0); |                     let rect_size = box_shadow.bounds.extend(1.0); | ||||||
| 
 | 
 | ||||||
|                     // Specify the corners of the node
 |                     // Specify the corners of the node
 | ||||||
| @ -532,7 +533,6 @@ pub fn prepare_shadows( | |||||||
|                     *ui_phase.items[item_index].batch_range_mut() = |                     *ui_phase.items[item_index].batch_range_mut() = | ||||||
|                         item_index as u32..item_index as u32 + 1; |                         item_index as u32..item_index as u32 + 1; | ||||||
|                 } |                 } | ||||||
|                 item_index += 1; |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         ui_meta.vertices.write_buffer(&render_device, &render_queue); |         ui_meta.vertices.write_buffer(&render_device, &render_queue); | ||||||
|  | |||||||
| @ -85,34 +85,30 @@ pub fn extract_debug_overlay( | |||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         // Extract a border box to display an outline for every UI Node in the layout
 |         // Extract a border box to display an outline for every UI Node in the layout
 | ||||||
|         extracted_uinodes.uinodes.insert( |         extracted_uinodes.uinodes.push(ExtractedUiNode { | ||||||
|             commands.spawn(TemporaryRenderEntity).id(), |             render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|             ExtractedUiNode { |             // Add a large number to the UI node's stack index so that the overlay is always drawn on top
 | ||||||
|                 // Add a large number to the UI node's stack index so that the overlay is always drawn on top
 |             stack_index: uinode.stack_index + u32::MAX / 2, | ||||||
|                 stack_index: uinode.stack_index + u32::MAX / 2, |             color: Hsla::sequential_dispersed(entity.index()).into(), | ||||||
|                 color: Hsla::sequential_dispersed(entity.index()).into(), |             rect: Rect { | ||||||
|                 rect: Rect { |                 min: Vec2::ZERO, | ||||||
|                     min: Vec2::ZERO, |                 max: uinode.size, | ||||||
|                     max: uinode.size, |  | ||||||
|                 }, |  | ||||||
|                 clip: maybe_clip |  | ||||||
|                     .filter(|_| !debug_options.show_clipped) |  | ||||||
|                     .map(|clip| clip.clip), |  | ||||||
|                 image: AssetId::default(), |  | ||||||
|                 extracted_camera_entity, |  | ||||||
|                 item: ExtractedUiItem::Node { |  | ||||||
|                     atlas_scaling: None, |  | ||||||
|                     transform: transform.compute_matrix(), |  | ||||||
|                     flip_x: false, |  | ||||||
|                     flip_y: false, |  | ||||||
|                     border: BorderRect::all( |  | ||||||
|                         debug_options.line_width / uinode.inverse_scale_factor(), |  | ||||||
|                     ), |  | ||||||
|                     border_radius: uinode.border_radius(), |  | ||||||
|                     node_type: NodeType::Border, |  | ||||||
|                 }, |  | ||||||
|                 main_entity: entity.into(), |  | ||||||
|             }, |             }, | ||||||
|         ); |             clip: maybe_clip | ||||||
|  |                 .filter(|_| !debug_options.show_clipped) | ||||||
|  |                 .map(|clip| clip.clip), | ||||||
|  |             image: AssetId::default(), | ||||||
|  |             extracted_camera_entity, | ||||||
|  |             item: ExtractedUiItem::Node { | ||||||
|  |                 atlas_scaling: None, | ||||||
|  |                 transform: transform.compute_matrix(), | ||||||
|  |                 flip_x: false, | ||||||
|  |                 flip_y: false, | ||||||
|  |                 border: BorderRect::all(debug_options.line_width / uinode.inverse_scale_factor()), | ||||||
|  |                 border_radius: uinode.border_radius(), | ||||||
|  |                 node_type: NodeType::Border, | ||||||
|  |             }, | ||||||
|  |             main_entity: entity.into(), | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,7 +18,6 @@ use bevy_color::{Alpha, ColorToComponents, LinearRgba}; | |||||||
| use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d}; | use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d}; | ||||||
| use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; | use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; | ||||||
| use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; | use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; | ||||||
| use bevy_ecs::entity::hash_map::EntityHashMap; |  | ||||||
| use bevy_ecs::prelude::*; | use bevy_ecs::prelude::*; | ||||||
| use bevy_ecs::system::SystemParam; | use bevy_ecs::system::SystemParam; | ||||||
| use bevy_image::prelude::*; | use bevy_image::prelude::*; | ||||||
| @ -203,6 +202,7 @@ pub struct ExtractedUiNode { | |||||||
|     pub extracted_camera_entity: Entity, |     pub extracted_camera_entity: Entity, | ||||||
|     pub item: ExtractedUiItem, |     pub item: ExtractedUiItem, | ||||||
|     pub main_entity: MainEntity, |     pub main_entity: MainEntity, | ||||||
|  |     pub render_entity: Entity, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// The type of UI node.
 | /// The type of UI node.
 | ||||||
| @ -241,7 +241,7 @@ pub struct ExtractedGlyph { | |||||||
| 
 | 
 | ||||||
| #[derive(Resource, Default)] | #[derive(Resource, Default)] | ||||||
| pub struct ExtractedUiNodes { | pub struct ExtractedUiNodes { | ||||||
|     pub uinodes: EntityHashMap<ExtractedUiNode>, |     pub uinodes: Vec<ExtractedUiNode>, | ||||||
|     pub glyphs: Vec<ExtractedGlyph>, |     pub glyphs: Vec<ExtractedGlyph>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -358,30 +358,28 @@ pub fn extract_uinode_background_colors( | |||||||
|             continue; |             continue; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         extracted_uinodes.uinodes.insert( |         extracted_uinodes.uinodes.push(ExtractedUiNode { | ||||||
|             commands.spawn(TemporaryRenderEntity).id(), |             render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|             ExtractedUiNode { |             stack_index: uinode.stack_index, | ||||||
|                 stack_index: uinode.stack_index, |             color: background_color.0.into(), | ||||||
|                 color: background_color.0.into(), |             rect: Rect { | ||||||
|                 rect: Rect { |                 min: Vec2::ZERO, | ||||||
|                     min: Vec2::ZERO, |                 max: uinode.size, | ||||||
|                     max: uinode.size, |  | ||||||
|                 }, |  | ||||||
|                 clip: clip.map(|clip| clip.clip), |  | ||||||
|                 image: AssetId::default(), |  | ||||||
|                 extracted_camera_entity, |  | ||||||
|                 item: ExtractedUiItem::Node { |  | ||||||
|                     atlas_scaling: None, |  | ||||||
|                     transform: transform.compute_matrix(), |  | ||||||
|                     flip_x: false, |  | ||||||
|                     flip_y: false, |  | ||||||
|                     border: uinode.border(), |  | ||||||
|                     border_radius: uinode.border_radius(), |  | ||||||
|                     node_type: NodeType::Rect, |  | ||||||
|                 }, |  | ||||||
|                 main_entity: entity.into(), |  | ||||||
|             }, |             }, | ||||||
|         ); |             clip: clip.map(|clip| clip.clip), | ||||||
|  |             image: AssetId::default(), | ||||||
|  |             extracted_camera_entity, | ||||||
|  |             item: ExtractedUiItem::Node { | ||||||
|  |                 atlas_scaling: None, | ||||||
|  |                 transform: transform.compute_matrix(), | ||||||
|  |                 flip_x: false, | ||||||
|  |                 flip_y: false, | ||||||
|  |                 border: uinode.border(), | ||||||
|  |                 border_radius: uinode.border_radius(), | ||||||
|  |                 node_type: NodeType::Rect, | ||||||
|  |             }, | ||||||
|  |             main_entity: entity.into(), | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -447,27 +445,25 @@ pub fn extract_uinode_images( | |||||||
|             None |             None | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         extracted_uinodes.uinodes.insert( |         extracted_uinodes.uinodes.push(ExtractedUiNode { | ||||||
|             commands.spawn(TemporaryRenderEntity).id(), |             render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|             ExtractedUiNode { |             stack_index: uinode.stack_index, | ||||||
|                 stack_index: uinode.stack_index, |             color: image.color.into(), | ||||||
|                 color: image.color.into(), |             rect, | ||||||
|                 rect, |             clip: clip.map(|clip| clip.clip), | ||||||
|                 clip: clip.map(|clip| clip.clip), |             image: image.image.id(), | ||||||
|                 image: image.image.id(), |             extracted_camera_entity, | ||||||
|                 extracted_camera_entity, |             item: ExtractedUiItem::Node { | ||||||
|                 item: ExtractedUiItem::Node { |                 atlas_scaling, | ||||||
|                     atlas_scaling, |                 transform: transform.compute_matrix(), | ||||||
|                     transform: transform.compute_matrix(), |                 flip_x: image.flip_x, | ||||||
|                     flip_x: image.flip_x, |                 flip_y: image.flip_y, | ||||||
|                     flip_y: image.flip_y, |                 border: uinode.border, | ||||||
|                     border: uinode.border, |                 border_radius: uinode.border_radius, | ||||||
|                     border_radius: uinode.border_radius, |                 node_type: NodeType::Rect, | ||||||
|                     node_type: NodeType::Rect, |  | ||||||
|                 }, |  | ||||||
|                 main_entity: entity.into(), |  | ||||||
|             }, |             }, | ||||||
|         ); |             main_entity: entity.into(), | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -515,30 +511,28 @@ pub fn extract_uinode_borders( | |||||||
|         if computed_node.border() != BorderRect::ZERO { |         if computed_node.border() != BorderRect::ZERO { | ||||||
|             if let Some(border_color) = maybe_border_color.filter(|bc| !bc.0.is_fully_transparent()) |             if let Some(border_color) = maybe_border_color.filter(|bc| !bc.0.is_fully_transparent()) | ||||||
|             { |             { | ||||||
|                 extracted_uinodes.uinodes.insert( |                 extracted_uinodes.uinodes.push(ExtractedUiNode { | ||||||
|                     commands.spawn(TemporaryRenderEntity).id(), |                     stack_index: computed_node.stack_index, | ||||||
|                     ExtractedUiNode { |                     color: border_color.0.into(), | ||||||
|                         stack_index: computed_node.stack_index, |                     rect: Rect { | ||||||
|                         color: border_color.0.into(), |                         max: computed_node.size(), | ||||||
|                         rect: Rect { |                         ..Default::default() | ||||||
|                             max: computed_node.size(), |  | ||||||
|                             ..Default::default() |  | ||||||
|                         }, |  | ||||||
|                         image, |  | ||||||
|                         clip: maybe_clip.map(|clip| clip.clip), |  | ||||||
|                         extracted_camera_entity, |  | ||||||
|                         item: ExtractedUiItem::Node { |  | ||||||
|                             atlas_scaling: None, |  | ||||||
|                             transform: global_transform.compute_matrix(), |  | ||||||
|                             flip_x: false, |  | ||||||
|                             flip_y: false, |  | ||||||
|                             border: computed_node.border(), |  | ||||||
|                             border_radius: computed_node.border_radius(), |  | ||||||
|                             node_type: NodeType::Border, |  | ||||||
|                         }, |  | ||||||
|                         main_entity: entity.into(), |  | ||||||
|                     }, |                     }, | ||||||
|                 ); |                     image, | ||||||
|  |                     clip: maybe_clip.map(|clip| clip.clip), | ||||||
|  |                     extracted_camera_entity, | ||||||
|  |                     item: ExtractedUiItem::Node { | ||||||
|  |                         atlas_scaling: None, | ||||||
|  |                         transform: global_transform.compute_matrix(), | ||||||
|  |                         flip_x: false, | ||||||
|  |                         flip_y: false, | ||||||
|  |                         border: computed_node.border(), | ||||||
|  |                         border_radius: computed_node.border_radius(), | ||||||
|  |                         node_type: NodeType::Border, | ||||||
|  |                     }, | ||||||
|  |                     main_entity: entity.into(), | ||||||
|  |                     render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|  |                 }); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -549,30 +543,28 @@ pub fn extract_uinode_borders( | |||||||
|         if let Some(outline) = maybe_outline.filter(|outline| !outline.color.is_fully_transparent()) |         if let Some(outline) = maybe_outline.filter(|outline| !outline.color.is_fully_transparent()) | ||||||
|         { |         { | ||||||
|             let outline_size = computed_node.outlined_node_size(); |             let outline_size = computed_node.outlined_node_size(); | ||||||
|             extracted_uinodes.uinodes.insert( |             extracted_uinodes.uinodes.push(ExtractedUiNode { | ||||||
|                 commands.spawn(TemporaryRenderEntity).id(), |                 render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|                 ExtractedUiNode { |                 stack_index: computed_node.stack_index, | ||||||
|                     stack_index: computed_node.stack_index, |                 color: outline.color.into(), | ||||||
|                     color: outline.color.into(), |                 rect: Rect { | ||||||
|                     rect: Rect { |                     max: outline_size, | ||||||
|                         max: outline_size, |                     ..Default::default() | ||||||
|                         ..Default::default() |  | ||||||
|                     }, |  | ||||||
|                     image, |  | ||||||
|                     clip: maybe_clip.map(|clip| clip.clip), |  | ||||||
|                     extracted_camera_entity, |  | ||||||
|                     item: ExtractedUiItem::Node { |  | ||||||
|                         transform: global_transform.compute_matrix(), |  | ||||||
|                         atlas_scaling: None, |  | ||||||
|                         flip_x: false, |  | ||||||
|                         flip_y: false, |  | ||||||
|                         border: BorderRect::all(computed_node.outline_width()), |  | ||||||
|                         border_radius: computed_node.outline_radius(), |  | ||||||
|                         node_type: NodeType::Border, |  | ||||||
|                     }, |  | ||||||
|                     main_entity: entity.into(), |  | ||||||
|                 }, |                 }, | ||||||
|             ); |                 image, | ||||||
|  |                 clip: maybe_clip.map(|clip| clip.clip), | ||||||
|  |                 extracted_camera_entity, | ||||||
|  |                 item: ExtractedUiItem::Node { | ||||||
|  |                     transform: global_transform.compute_matrix(), | ||||||
|  |                     atlas_scaling: None, | ||||||
|  |                     flip_x: false, | ||||||
|  |                     flip_y: false, | ||||||
|  |                     border: BorderRect::all(computed_node.outline_width()), | ||||||
|  |                     border_radius: computed_node.outline_radius(), | ||||||
|  |                     node_type: NodeType::Border, | ||||||
|  |                 }, | ||||||
|  |                 main_entity: entity.into(), | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -788,21 +780,17 @@ pub fn extract_text_sections( | |||||||
|             if text_layout_info.glyphs.get(i + 1).is_none_or(|info| { |             if text_layout_info.glyphs.get(i + 1).is_none_or(|info| { | ||||||
|                 info.span_index != current_span || info.atlas_info.texture != atlas_info.texture |                 info.span_index != current_span || info.atlas_info.texture != atlas_info.texture | ||||||
|             }) { |             }) { | ||||||
|                 let id = commands.spawn(TemporaryRenderEntity).id(); |                 extracted_uinodes.uinodes.push(ExtractedUiNode { | ||||||
| 
 |                     render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|                 extracted_uinodes.uinodes.insert( |                     stack_index: uinode.stack_index, | ||||||
|                     id, |                     color, | ||||||
|                     ExtractedUiNode { |                     image: atlas_info.texture.id(), | ||||||
|                         stack_index: uinode.stack_index, |                     clip: clip.map(|clip| clip.clip), | ||||||
|                         color, |                     extracted_camera_entity, | ||||||
|                         image: atlas_info.texture.id(), |                     rect, | ||||||
|                         clip: clip.map(|clip| clip.clip), |                     item: ExtractedUiItem::Glyphs { range: start..end }, | ||||||
|                         extracted_camera_entity, |                     main_entity: entity.into(), | ||||||
|                         rect, |                 }); | ||||||
|                         item: ExtractedUiItem::Glyphs { range: start..end }, |  | ||||||
|                         main_entity: entity.into(), |  | ||||||
|                     }, |  | ||||||
|                 ); |  | ||||||
|                 start = end; |                 start = end; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -885,7 +873,8 @@ pub fn queue_uinodes( | |||||||
|     draw_functions: Res<DrawFunctions<TransparentUi>>, |     draw_functions: Res<DrawFunctions<TransparentUi>>, | ||||||
| ) { | ) { | ||||||
|     let draw_function = draw_functions.read().id::<DrawUi>(); |     let draw_function = draw_functions.read().id::<DrawUi>(); | ||||||
|     for (entity, extracted_uinode) in extracted_uinodes.uinodes.iter() { |     for (index, extracted_uinode) in extracted_uinodes.uinodes.iter().enumerate() { | ||||||
|  |         let entity = extracted_uinode.render_entity; | ||||||
|         let Ok((default_camera_view, ui_anti_alias)) = |         let Ok((default_camera_view, ui_anti_alias)) = | ||||||
|             render_views.get_mut(extracted_uinode.extracted_camera_entity) |             render_views.get_mut(extracted_uinode.extracted_camera_entity) | ||||||
|         else { |         else { | ||||||
| @ -912,11 +901,12 @@ pub fn queue_uinodes( | |||||||
|         transparent_phase.add(TransparentUi { |         transparent_phase.add(TransparentUi { | ||||||
|             draw_function, |             draw_function, | ||||||
|             pipeline, |             pipeline, | ||||||
|             entity: (*entity, extracted_uinode.main_entity), |             entity: (entity, extracted_uinode.main_entity), | ||||||
|             sort_key: ( |             sort_key: ( | ||||||
|                 FloatOrd(extracted_uinode.stack_index as f32 + stack_z_offsets::NODE), |                 FloatOrd(extracted_uinode.stack_index as f32 + stack_z_offsets::NODE), | ||||||
|                 entity.index(), |                 entity.index(), | ||||||
|             ), |             ), | ||||||
|  |             index, | ||||||
|             // batch_range will be calculated in prepare_uinodes
 |             // batch_range will be calculated in prepare_uinodes
 | ||||||
|             batch_range: 0..0, |             batch_range: 0..0, | ||||||
|             extra_index: PhaseItemExtraIndex::None, |             extra_index: PhaseItemExtraIndex::None, | ||||||
| @ -978,7 +968,11 @@ pub fn prepare_uinodes( | |||||||
| 
 | 
 | ||||||
|             for item_index in 0..ui_phase.items.len() { |             for item_index in 0..ui_phase.items.len() { | ||||||
|                 let item = &mut ui_phase.items[item_index]; |                 let item = &mut ui_phase.items[item_index]; | ||||||
|                 if let Some(extracted_uinode) = extracted_uinodes.uinodes.get(&item.entity()) { |                 if let Some(extracted_uinode) = extracted_uinodes | ||||||
|  |                     .uinodes | ||||||
|  |                     .get(item.index) | ||||||
|  |                     .filter(|n| item.entity() == n.render_entity) | ||||||
|  |                 { | ||||||
|                     let mut existing_batch = batches.last_mut(); |                     let mut existing_batch = batches.last_mut(); | ||||||
| 
 | 
 | ||||||
|                     if batch_image_handle == AssetId::invalid() |                     if batch_image_handle == AssetId::invalid() | ||||||
|  | |||||||
| @ -112,6 +112,7 @@ pub struct TransparentUi { | |||||||
|     pub draw_function: DrawFunctionId, |     pub draw_function: DrawFunctionId, | ||||||
|     pub batch_range: Range<u32>, |     pub batch_range: Range<u32>, | ||||||
|     pub extra_index: PhaseItemExtraIndex, |     pub extra_index: PhaseItemExtraIndex, | ||||||
|  |     pub index: usize, | ||||||
|     pub indexed: bool, |     pub indexed: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ use bevy_asset::*; | |||||||
| use bevy_ecs::{ | use bevy_ecs::{ | ||||||
|     prelude::Component, |     prelude::Component, | ||||||
|     query::ROQueryItem, |     query::ROQueryItem, | ||||||
|     storage::SparseSet, |  | ||||||
|     system::{ |     system::{ | ||||||
|         lifetimeless::{Read, SRes}, |         lifetimeless::{Read, SRes}, | ||||||
|         *, |         *, | ||||||
| @ -347,11 +346,12 @@ pub struct ExtractedUiMaterialNode<M: UiMaterial> { | |||||||
|     // Nodes with ambiguous camera will be ignored.
 |     // Nodes with ambiguous camera will be ignored.
 | ||||||
|     pub extracted_camera_entity: Entity, |     pub extracted_camera_entity: Entity, | ||||||
|     pub main_entity: MainEntity, |     pub main_entity: MainEntity, | ||||||
|  |     render_entity: Entity, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Resource)] | #[derive(Resource)] | ||||||
| pub struct ExtractedUiMaterialNodes<M: UiMaterial> { | pub struct ExtractedUiMaterialNodes<M: UiMaterial> { | ||||||
|     pub uinodes: SparseSet<Entity, ExtractedUiMaterialNode<M>>, |     pub uinodes: Vec<ExtractedUiMaterialNode<M>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<M: UiMaterial> Default for ExtractedUiMaterialNodes<M> { | impl<M: UiMaterial> Default for ExtractedUiMaterialNodes<M> { | ||||||
| @ -398,23 +398,21 @@ pub fn extract_ui_material_nodes<M: UiMaterial>( | |||||||
|             continue; |             continue; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         extracted_uinodes.uinodes.insert( |         extracted_uinodes.uinodes.push(ExtractedUiMaterialNode { | ||||||
|             commands.spawn(TemporaryRenderEntity).id(), |             render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|             ExtractedUiMaterialNode { |             stack_index: computed_node.stack_index, | ||||||
|                 stack_index: computed_node.stack_index, |             transform: transform.compute_matrix(), | ||||||
|                 transform: transform.compute_matrix(), |             material: handle.id(), | ||||||
|                 material: handle.id(), |             rect: Rect { | ||||||
|                 rect: Rect { |                 min: Vec2::ZERO, | ||||||
|                     min: Vec2::ZERO, |                 max: computed_node.size(), | ||||||
|                     max: computed_node.size(), |  | ||||||
|                 }, |  | ||||||
|                 border: computed_node.border(), |  | ||||||
|                 border_radius: computed_node.border_radius(), |  | ||||||
|                 clip: clip.map(|clip| clip.clip), |  | ||||||
|                 extracted_camera_entity, |  | ||||||
|                 main_entity: entity.into(), |  | ||||||
|             }, |             }, | ||||||
|         ); |             border: computed_node.border(), | ||||||
|  |             border_radius: computed_node.border_radius(), | ||||||
|  |             clip: clip.map(|clip| clip.clip), | ||||||
|  |             extracted_camera_entity, | ||||||
|  |             main_entity: entity.into(), | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -450,7 +448,11 @@ pub fn prepare_uimaterial_nodes<M: UiMaterial>( | |||||||
| 
 | 
 | ||||||
|             for item_index in 0..ui_phase.items.len() { |             for item_index in 0..ui_phase.items.len() { | ||||||
|                 let item = &mut ui_phase.items[item_index]; |                 let item = &mut ui_phase.items[item_index]; | ||||||
|                 if let Some(extracted_uinode) = extracted_uinodes.uinodes.get(item.entity()) { |                 if let Some(extracted_uinode) = extracted_uinodes | ||||||
|  |                     .uinodes | ||||||
|  |                     .get(item.index) | ||||||
|  |                     .filter(|n| item.entity() == n.render_entity) | ||||||
|  |                 { | ||||||
|                     let mut existing_batch = batches |                     let mut existing_batch = batches | ||||||
|                         .last_mut() |                         .last_mut() | ||||||
|                         .filter(|_| batch_shader_handle == extracted_uinode.material); |                         .filter(|_| batch_shader_handle == extracted_uinode.material); | ||||||
| @ -624,7 +626,7 @@ pub fn queue_ui_material_nodes<M: UiMaterial>( | |||||||
| { | { | ||||||
|     let draw_function = draw_functions.read().id::<DrawUiMaterial<M>>(); |     let draw_function = draw_functions.read().id::<DrawUiMaterial<M>>(); | ||||||
| 
 | 
 | ||||||
|     for (entity, extracted_uinode) in extracted_uinodes.uinodes.iter() { |     for (index, extracted_uinode) in extracted_uinodes.uinodes.iter().enumerate() { | ||||||
|         let Some(material) = render_materials.get(extracted_uinode.material) else { |         let Some(material) = render_materials.get(extracted_uinode.material) else { | ||||||
|             continue; |             continue; | ||||||
|         }; |         }; | ||||||
| @ -660,13 +662,14 @@ pub fn queue_ui_material_nodes<M: UiMaterial>( | |||||||
|         transparent_phase.add(TransparentUi { |         transparent_phase.add(TransparentUi { | ||||||
|             draw_function, |             draw_function, | ||||||
|             pipeline, |             pipeline, | ||||||
|             entity: (*entity, extracted_uinode.main_entity), |             entity: (extracted_uinode.render_entity, extracted_uinode.main_entity), | ||||||
|             sort_key: ( |             sort_key: ( | ||||||
|                 FloatOrd(extracted_uinode.stack_index as f32 + stack_z_offsets::MATERIAL), |                 FloatOrd(extracted_uinode.stack_index as f32 + stack_z_offsets::MATERIAL), | ||||||
|                 entity.index(), |                 extracted_uinode.render_entity.index(), | ||||||
|             ), |             ), | ||||||
|             batch_range: 0..0, |             batch_range: 0..0, | ||||||
|             extra_index: PhaseItemExtraIndex::None, |             extra_index: PhaseItemExtraIndex::None, | ||||||
|  |             index, | ||||||
|             indexed: false, |             indexed: false, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ use bevy_asset::*; | |||||||
| use bevy_color::{Alpha, ColorToComponents, LinearRgba}; | use bevy_color::{Alpha, ColorToComponents, LinearRgba}; | ||||||
| use bevy_ecs::{ | use bevy_ecs::{ | ||||||
|     prelude::Component, |     prelude::Component, | ||||||
|     storage::SparseSet, |  | ||||||
|     system::{ |     system::{ | ||||||
|         lifetimeless::{Read, SRes}, |         lifetimeless::{Read, SRes}, | ||||||
|         *, |         *, | ||||||
| @ -237,11 +236,12 @@ pub struct ExtractedUiTextureSlice { | |||||||
|     pub flip_y: bool, |     pub flip_y: bool, | ||||||
|     pub inverse_scale_factor: f32, |     pub inverse_scale_factor: f32, | ||||||
|     pub main_entity: MainEntity, |     pub main_entity: MainEntity, | ||||||
|  |     pub render_entity: Entity, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Resource, Default)] | #[derive(Resource, Default)] | ||||||
| pub struct ExtractedUiTextureSlices { | pub struct ExtractedUiTextureSlices { | ||||||
|     pub slices: SparseSet<Entity, ExtractedUiTextureSlice>, |     pub slices: Vec<ExtractedUiTextureSlice>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn extract_ui_texture_slices( | pub fn extract_ui_texture_slices( | ||||||
| @ -309,27 +309,25 @@ pub fn extract_ui_texture_slices( | |||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         extracted_ui_slicers.slices.insert( |         extracted_ui_slicers.slices.push(ExtractedUiTextureSlice { | ||||||
|             commands.spawn(TemporaryRenderEntity).id(), |             render_entity: commands.spawn(TemporaryRenderEntity).id(), | ||||||
|             ExtractedUiTextureSlice { |             stack_index: uinode.stack_index, | ||||||
|                 stack_index: uinode.stack_index, |             transform: transform.compute_matrix(), | ||||||
|                 transform: transform.compute_matrix(), |             color: image.color.into(), | ||||||
|                 color: image.color.into(), |             rect: Rect { | ||||||
|                 rect: Rect { |                 min: Vec2::ZERO, | ||||||
|                     min: Vec2::ZERO, |                 max: uinode.size, | ||||||
|                     max: uinode.size, |  | ||||||
|                 }, |  | ||||||
|                 clip: clip.map(|clip| clip.clip), |  | ||||||
|                 image: image.image.id(), |  | ||||||
|                 extracted_camera_entity, |  | ||||||
|                 image_scale_mode, |  | ||||||
|                 atlas_rect, |  | ||||||
|                 flip_x: image.flip_x, |  | ||||||
|                 flip_y: image.flip_y, |  | ||||||
|                 inverse_scale_factor: uinode.inverse_scale_factor, |  | ||||||
|                 main_entity: entity.into(), |  | ||||||
|             }, |             }, | ||||||
|         ); |             clip: clip.map(|clip| clip.clip), | ||||||
|  |             image: image.image.id(), | ||||||
|  |             extracted_camera_entity, | ||||||
|  |             image_scale_mode, | ||||||
|  |             atlas_rect, | ||||||
|  |             flip_x: image.flip_x, | ||||||
|  |             flip_y: image.flip_y, | ||||||
|  |             inverse_scale_factor: uinode.inverse_scale_factor, | ||||||
|  |             main_entity: entity.into(), | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -348,7 +346,7 @@ pub fn queue_ui_slices( | |||||||
|     draw_functions: Res<DrawFunctions<TransparentUi>>, |     draw_functions: Res<DrawFunctions<TransparentUi>>, | ||||||
| ) { | ) { | ||||||
|     let draw_function = draw_functions.read().id::<DrawUiTextureSlices>(); |     let draw_function = draw_functions.read().id::<DrawUiTextureSlices>(); | ||||||
|     for (entity, extracted_slicer) in extracted_ui_slicers.slices.iter() { |     for (index, extracted_slicer) in extracted_ui_slicers.slices.iter().enumerate() { | ||||||
|         let Ok(default_camera_view) = |         let Ok(default_camera_view) = | ||||||
|             render_views.get_mut(extracted_slicer.extracted_camera_entity) |             render_views.get_mut(extracted_slicer.extracted_camera_entity) | ||||||
|         else { |         else { | ||||||
| @ -373,13 +371,14 @@ pub fn queue_ui_slices( | |||||||
|         transparent_phase.add(TransparentUi { |         transparent_phase.add(TransparentUi { | ||||||
|             draw_function, |             draw_function, | ||||||
|             pipeline, |             pipeline, | ||||||
|             entity: (*entity, extracted_slicer.main_entity), |             entity: (extracted_slicer.render_entity, extracted_slicer.main_entity), | ||||||
|             sort_key: ( |             sort_key: ( | ||||||
|                 FloatOrd(extracted_slicer.stack_index as f32 + stack_z_offsets::TEXTURE_SLICE), |                 FloatOrd(extracted_slicer.stack_index as f32 + stack_z_offsets::TEXTURE_SLICE), | ||||||
|                 entity.index(), |                 extracted_slicer.render_entity.index(), | ||||||
|             ), |             ), | ||||||
|             batch_range: 0..0, |             batch_range: 0..0, | ||||||
|             extra_index: PhaseItemExtraIndex::None, |             extra_index: PhaseItemExtraIndex::None, | ||||||
|  |             index, | ||||||
|             indexed: true, |             indexed: true, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| @ -434,7 +433,11 @@ pub fn prepare_ui_slices( | |||||||
| 
 | 
 | ||||||
|             for item_index in 0..ui_phase.items.len() { |             for item_index in 0..ui_phase.items.len() { | ||||||
|                 let item = &mut ui_phase.items[item_index]; |                 let item = &mut ui_phase.items[item_index]; | ||||||
|                 if let Some(texture_slices) = extracted_slices.slices.get(item.entity()) { |                 if let Some(texture_slices) = extracted_slices | ||||||
|  |                     .slices | ||||||
|  |                     .get(item.index) | ||||||
|  |                     .filter(|n| item.entity() == n.render_entity) | ||||||
|  |                 { | ||||||
|                     let mut existing_batch = batches.last_mut(); |                     let mut existing_batch = batches.last_mut(); | ||||||
| 
 | 
 | ||||||
|                     if batch_image_handle == AssetId::invalid() |                     if batch_image_handle == AssetId::invalid() | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 ickshonpe
						ickshonpe