From 75614f50844880194eb56b360eef3eeab42ebe66 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Wed, 6 May 2020 13:49:07 -0700 Subject: [PATCH] Ui depth from parent (falls back to insertion order for orphans), do ui rect size offsets before rendering, --- crates/bevy_core/src/transform/hierarchy.rs | 22 ++++-- crates/bevy_ui/src/node.rs | 32 ++++----- crates/bevy_ui/src/render/mod.rs | 4 +- crates/bevy_ui/src/render/ui.vert | 2 +- crates/bevy_ui/src/ui_update_system.rs | 45 ++++++++---- examples/ui/ui.rs | 79 +++++++++++---------- 6 files changed, 105 insertions(+), 79 deletions(-) diff --git a/crates/bevy_core/src/transform/hierarchy.rs b/crates/bevy_core/src/transform/hierarchy.rs index 9fc89fefbe..2c4d6e659b 100644 --- a/crates/bevy_core/src/transform/hierarchy.rs +++ b/crates/bevy_core/src/transform/hierarchy.rs @@ -32,7 +32,7 @@ pub fn run_on_hierarchy_mut( ) where T: Copy, { - // TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocactions? + // TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocations? let children = match world.get_component::(entity) { Some(children) => Some( children @@ -78,11 +78,12 @@ pub fn run_on_hierarchy_subworld_mut( world: &mut SubWorld, entity: Entity, input: T, - func: &mut dyn FnMut(&mut SubWorld, Entity, T) -> Option, -) where + run: &mut dyn FnMut(&mut SubWorld, Entity, T) -> Option, + child_result_action: &mut dyn FnMut(T, T) -> T, +) -> Option where T: Copy, { - // TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocactions? + // TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocations? let children = match world.get_component::(entity) { Some(children) => Some( children @@ -93,13 +94,20 @@ pub fn run_on_hierarchy_subworld_mut( None => None, }; - let result = func(world, entity, input); + let result = run(world, entity, input); - if let Some(result) = result { + if let Some(mut result) = result { if let Some(children) = children { for child in children { - run_on_hierarchy_subworld_mut(world, child, result, func); + let child_result = run_on_hierarchy_subworld_mut(world, child, result, run, child_result_action); + if let Some(child_result) = child_result { + result = child_result_action(result, child_result) + } } } + + Some(result) + } else { + None } } diff --git a/crates/bevy_ui/src/node.rs b/crates/bevy_ui/src/node.rs index 38d2c0b2cf..bf0fadabd7 100644 --- a/crates/bevy_ui/src/node.rs +++ b/crates/bevy_ui/src/node.rs @@ -3,7 +3,7 @@ use crate::Rect; use glam::Vec2; #[derive(Debug, Clone)] -enum GrowDirection { +enum MarginGrowDirection { Negative, Positive, } @@ -37,7 +37,7 @@ impl Node { pub fn update( &mut self, rect: &mut Rect, - parent_dimensions: Vec2, + parent_size: Vec2, parent_position: Vec2, z_index: f32, ) { @@ -47,7 +47,7 @@ impl Node { self.margins.right, self.anchors.left, self.anchors.right, - parent_dimensions.x(), + parent_size.x(), ); let (rect_y, rect_height) = Self::compute_dimension_properties( self.position.y(), @@ -55,7 +55,7 @@ impl Node { self.margins.top, self.anchors.bottom, self.anchors.top, - parent_dimensions.y(), + parent_size.y(), ); rect.size = Vec2::new(rect_width, rect_height); @@ -75,37 +75,33 @@ impl Node { let anchor_p1 = anchor1 * length; let p0_grow_direction = if anchor_p0 <= 0.5 { - GrowDirection::Positive + MarginGrowDirection::Positive } else { - GrowDirection::Negative + MarginGrowDirection::Negative }; - let p1_grow_direction = if anchor_p1 < 0.5 { - GrowDirection::Positive + let p1_grow_direction = if anchor_p1 <= 0.5 { + MarginGrowDirection::Positive } else { - GrowDirection::Negative + MarginGrowDirection::Negative }; let p0 = Self::compute_rect_position(offset, margin0, anchor_p0, p0_grow_direction); let p1 = Self::compute_rect_position(offset, margin1, anchor_p1, p1_grow_direction); let final_width = p1 - p0; - let mut p = (p0 + p1) / 2.0; - - // move position to "origin" in bottom left hand corner - p = p - final_width / 2.0; - - (p, final_width) + let p = (p0 + p1) / 2.0; + (p, final_width.abs()) } fn compute_rect_position( position: f32, margin: f32, anchor_position: f32, - grow_direction: GrowDirection, + grow_direction: MarginGrowDirection, ) -> f32 { match grow_direction { - GrowDirection::Negative => position + anchor_position - margin, - GrowDirection::Positive => position + anchor_position + margin, + MarginGrowDirection::Negative => position + anchor_position - margin, + MarginGrowDirection::Positive => position + anchor_position + margin, } } } diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 144b99fefa..2a6d9a6d24 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -27,8 +27,8 @@ pub fn build_ui_pipeline(shaders: &mut AssetStorage) -> PipelineDescript }), depth_stencil_state: Some(DepthStencilStateDescriptor { format: TextureFormat::Depth32Float, - depth_write_enabled: false, - depth_compare: CompareFunction::Always, + depth_write_enabled: true, + depth_compare: CompareFunction::Less, stencil_front: StencilStateFaceDescriptor::IGNORE, stencil_back: StencilStateFaceDescriptor::IGNORE, stencil_read_mask: 0, diff --git a/crates/bevy_ui/src/render/ui.vert b/crates/bevy_ui/src/render/ui.vert index e18da08a0c..b4a3b334a7 100644 --- a/crates/bevy_ui/src/render/ui.vert +++ b/crates/bevy_ui/src/render/ui.vert @@ -19,6 +19,6 @@ layout(set = 1, binding = 0) uniform Rect { void main() { v_Uv = Vertex_Uv; vec3 position = Vertex_Position * vec3(Rect_Size, 0.0); - position = position + vec3(Rect_Position + Rect_Size / 2.0, -Rect_ZIndex); + position = position + vec3(Rect_Position, -Rect_ZIndex); gl_Position = ViewProj * vec4(position, 1.0); } \ No newline at end of file diff --git a/crates/bevy_ui/src/ui_update_system.rs b/crates/bevy_ui/src/ui_update_system.rs index 8960c6f720..c2dc062419 100644 --- a/crates/bevy_ui/src/ui_update_system.rs +++ b/crates/bevy_ui/src/ui_update_system.rs @@ -6,6 +6,8 @@ use bevy_window::Windows; use glam::Vec2; use legion::{prelude::*, systems::SubWorld}; +pub const UI_Z_STEP: f32 = 0.0001; + pub fn ui_update_system() -> Box { SystemBuilder::new("ui_update") .read_resource::() @@ -15,39 +17,58 @@ pub fn ui_update_system() -> Box { .read_component::() .build(move |_, world, windows, node_query| { if let Some(window) = windows.get_primary() { - let parent_size = glam::vec2(window.width as f32, window.height as f32); - let parent_position = glam::vec2(0.0, 0.0); + let mut window_rect = Rect { + size: Vec2::new(window.width as f32, window.height as f32), + position: Vec2::new(0.0, 0.0), + z_index: 0.9999, + }; for entity in node_query .iter_entities(world) .map(|(e, _)| e) .collect::>() { - run_on_hierarchy_subworld_mut( + let result = run_on_hierarchy_subworld_mut( world, entity, - (parent_size, parent_position, 0.9999), + window_rect.clone(), &mut update_node_entity, + &mut process_child_result, ); + + if let Some(result) = result { + window_rect.z_index = result.z_index; + } } } }) } -fn update_node_entity( - world: &mut SubWorld, - entity: Entity, - parent_properties: (Vec2, Vec2, f32), -) -> Option<(Vec2, Vec2, f32)> { - let (parent_size, parent_position, z_index) = parent_properties; +fn update_node_entity(world: &mut SubWorld, entity: Entity, parent_rect: Rect) -> Option { // TODO: Somehow remove this unsafe unsafe { if let Some(mut node) = world.get_component_mut_unchecked::(entity) { if let Some(mut rect) = world.get_component_mut_unchecked::(entity) { - node.update(&mut rect, parent_size, parent_position, z_index); - return Some((rect.size, rect.position, z_index - 0.0001)); + node.update( + &mut rect, + parent_rect.size, + parent_rect.position, + parent_rect.z_index, + ); + return Some(Rect { + size: rect.size, + position: rect.position - rect.size / 2.0, + z_index: rect.z_index - UI_Z_STEP, + }); } } } None } + +fn process_child_result(_parent_result: Rect, child_result: Rect) -> Rect { + // "earlier" children are sorted behind "later" children + let mut result = child_result.clone(); + result.z_index -= UI_Z_STEP; + result +} diff --git a/examples/ui/ui.rs b/examples/ui/ui.rs index 06ed3e42b2..eee4775d14 100644 --- a/examples/ui/ui.rs +++ b/examples/ui/ui.rs @@ -8,15 +8,16 @@ fn main() { } fn setup(world: &mut World, resources: &mut Resources) { - let mut mesh_storage = resources.get_mut::>().unwrap(); - let mut material_storage = resources - .get_mut::>() - .unwrap(); - let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); - let cube_material_handle = material_storage.add(StandardMaterial { - albedo: Color::rgb(0.5, 0.3, 0.3), - ..Default::default() - }); + // TODO: "background" 3D temporarily disabled until depth mismatch is fixed + // let mut mesh_storage = resources.get_mut::>().unwrap(); + // let mut material_storage = resources + // .get_mut::>() + // .unwrap(); + // let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); + // let cube_material_handle = material_storage.add(StandardMaterial { + // albedo: Color::rgb(0.5, 0.4, 0.3), + // ..Default::default() + // }); let mut texture_storage = resources.get_mut::>().unwrap(); let texture_path = concat!( @@ -32,27 +33,27 @@ fn setup(world: &mut World, resources: &mut Resources) { world .build() - // cube - .add_entity(MeshEntity { - mesh: cube_handle, - material: cube_material_handle, - translation: Translation::new(0.0, 0.0, 1.0), - ..Default::default() - }) - // light - .add_entity(LightEntity { - translation: Translation::new(4.0, -4.0, 5.0), - ..Default::default() - }) - // 3d camera - .add_entity(CameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( - Vec3::new(3.0, 8.0, 5.0), - Vec3::new(0.0, 0.0, 0.0), - Vec3::new(0.0, 0.0, 1.0), - )), - ..Default::default() - }) + // // cube + // .add_entity(MeshEntity { + // mesh: cube_handle, + // material: cube_material_handle, + // translation: Translation::new(0.0, 0.0, 1.0), + // ..Default::default() + // }) + // // light + // .add_entity(LightEntity { + // translation: Translation::new(4.0, -4.0, 5.0), + // ..Default::default() + // }) + // // 3d camera + // .add_entity(CameraEntity { + // local_to_world: LocalToWorld(Mat4::look_at_rh( + // Vec3::new(3.0, 8.0, 5.0), + // Vec3::new(0.0, 0.0, 0.0), + // Vec3::new(0.0, 0.0, 1.0), + // )), + // ..Default::default() + // }) // 2d camera .add_entity(Camera2dEntity::default()) // left vertical fill @@ -78,7 +79,7 @@ fn setup(world: &mut World, resources: &mut Resources) { // render order test: reddest in the back, whitest in the front .add_entity(UiEntity { node: Node::new( - math::vec2(75.0, 75.0), + math::vec2(75.0, 60.0), Anchors::CENTER, Margins::new(0.0, 100.0, 0.0, 100.0), ), @@ -87,7 +88,7 @@ fn setup(world: &mut World, resources: &mut Resources) { }) .add_entity(UiEntity { node: Node::new( - math::vec2(50.0, 50.0), + math::vec2(50.0, 35.0), Anchors::CENTER, Margins::new(0.0, 100.0, 0.0, 100.0), ), @@ -96,7 +97,7 @@ fn setup(world: &mut World, resources: &mut Resources) { }) .add_entity(UiEntity { node: Node::new( - math::vec2(100.0, 100.0), + math::vec2(100.0, 85.0), Anchors::CENTER, Margins::new(0.0, 100.0, 0.0, 100.0), ), @@ -105,7 +106,7 @@ fn setup(world: &mut World, resources: &mut Resources) { }) .add_entity(UiEntity { node: Node::new( - math::vec2(150.0, 150.0), + math::vec2(150.0, 135.0), Anchors::CENTER, Margins::new(0.0, 100.0, 0.0, 100.0), ), @@ -115,9 +116,9 @@ fn setup(world: &mut World, resources: &mut Resources) { // parenting .add_entity(UiEntity { node: Node::new( - math::vec2(210.0, 10.0), + math::vec2(210.0, 0.0), Anchors::BOTTOM_LEFT, - Margins::new(0.0, 200.0, 0.0, 200.0), + Margins::new(0.0, 200.0, 10.0, 210.0), ), material: color_materials.add(Color::rgb(0.1, 0.1, 1.0).into()), ..Default::default() @@ -136,7 +137,7 @@ fn setup(world: &mut World, resources: &mut Resources) { // alpha test .add_entity(UiEntity { node: Node::new( - math::vec2(200.0, 200.0), + math::vec2(200.0, 185.0), Anchors::CENTER, Margins::new(0.0, 100.0, 0.0, 100.0), ), @@ -147,8 +148,8 @@ fn setup(world: &mut World, resources: &mut Resources) { .add_entity(UiEntity { node: Node::new( math::vec2(0.0, 0.0), - Anchors::CENTER_BOTTOM, - Margins::new(0.0, 500.0, 10.0, 10.0 + 500.0 * aspect), + Anchors::CENTER_TOP, + Margins::new(-250.0, 250.0, 510.0 * aspect, 10.0), ), material: color_materials.add(ColorMaterial::texture(texture_handle)), ..Default::default()