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