ui: rework so Nodes now use transforms and z-sort happens
This commit is contained in:
parent
75429f4639
commit
1ef4fbf005
@ -77,14 +77,12 @@ pub fn run_on_hierarchy_subworld<T>(
|
|||||||
pub fn run_on_hierarchy_subworld_mut<T>(
|
pub fn run_on_hierarchy_subworld_mut<T>(
|
||||||
world: &mut SubWorld,
|
world: &mut SubWorld,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
input: T,
|
parent_result: Option<&mut T>,
|
||||||
run: &mut dyn FnMut(&mut SubWorld, Entity, T) -> Option<T>,
|
mut previous_result: Option<T>,
|
||||||
child_result_action: &mut dyn FnMut(T, T) -> T,
|
run: &mut dyn FnMut(&mut SubWorld, Entity, Option<&mut T>, Option<T>) -> Option<T>,
|
||||||
) -> Option<T>
|
) -> Option<T> where T: Clone {
|
||||||
where
|
|
||||||
T: Copy,
|
|
||||||
{
|
|
||||||
// TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocations?
|
// TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocations?
|
||||||
|
// TODO: the problem above might be resolvable with world splitting
|
||||||
let children = match world.get_component::<Children>(entity) {
|
let children = match world.get_component::<Children>(entity) {
|
||||||
Some(children) => Some(
|
Some(children) => Some(
|
||||||
children
|
children
|
||||||
@ -95,21 +93,21 @@ where
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = run(world, entity, input);
|
let mut parent_result = run(world, entity, parent_result, previous_result);
|
||||||
|
previous_result = None;
|
||||||
if let Some(mut result) = result {
|
if let Some(children) = children {
|
||||||
if let Some(children) = children {
|
for child in children {
|
||||||
for child in children {
|
previous_result = run_on_hierarchy_subworld_mut(
|
||||||
let child_result =
|
world,
|
||||||
run_on_hierarchy_subworld_mut(world, child, result, run, child_result_action);
|
child,
|
||||||
if let Some(child_result) = child_result {
|
parent_result.as_mut(),
|
||||||
result = child_result_action(result, child_result)
|
previous_result,
|
||||||
}
|
run,
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(result)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
previous_result = parent_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
previous_result
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ impl OrthographicCameraEntity {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
orthographic_projection: OrthographicProjection {
|
orthographic_projection: OrthographicProjection {
|
||||||
window_origin: WindowOrigin::BottomLeft,
|
window_origin: WindowOrigin::Center,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
visible_entities: Default::default(),
|
visible_entities: Default::default(),
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
mod color_material;
|
mod color_material;
|
||||||
mod dynamic_texture_atlas_builder;
|
mod dynamic_texture_atlas_builder;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
mod quad;
|
|
||||||
mod rect;
|
mod rect;
|
||||||
mod render;
|
mod render;
|
||||||
mod sprite;
|
mod sprite;
|
||||||
@ -10,7 +9,6 @@ mod texture_atlas_builder;
|
|||||||
|
|
||||||
pub use color_material::*;
|
pub use color_material::*;
|
||||||
pub use dynamic_texture_atlas_builder::*;
|
pub use dynamic_texture_atlas_builder::*;
|
||||||
pub use quad::*;
|
|
||||||
pub use rect::*;
|
pub use rect::*;
|
||||||
pub use render::*;
|
pub use render::*;
|
||||||
pub use sprite::*;
|
pub use sprite::*;
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
use bevy_core::bytes::Bytes;
|
|
||||||
use bevy_render::render_resource::{RenderResource, RenderResources};
|
|
||||||
use glam::Vec2;
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Default, Clone, Copy, Debug, RenderResources, RenderResource, Bytes)]
|
|
||||||
#[render_resources(from_self)]
|
|
||||||
pub struct Quad {
|
|
||||||
pub position: Vec2,
|
|
||||||
pub size: Vec2,
|
|
||||||
pub z_index: f32,
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::{ColorMaterial, Quad, TextureAtlas, TextureAtlasSprite, Sprite};
|
use crate::{ColorMaterial, TextureAtlas, TextureAtlasSprite, Sprite};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
@ -110,7 +110,6 @@ pub fn build_sprite_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor
|
|||||||
|
|
||||||
pub mod node {
|
pub mod node {
|
||||||
pub const COLOR_MATERIAL: &'static str = "color_material";
|
pub const COLOR_MATERIAL: &'static str = "color_material";
|
||||||
pub const QUAD: &'static str = "quad";
|
|
||||||
pub const SPRITE: &'static str = "sprite";
|
pub const SPRITE: &'static str = "sprite";
|
||||||
pub const SPRITE_SHEET: &'static str = "sprite_sheet";
|
pub const SPRITE_SHEET: &'static str = "sprite_sheet";
|
||||||
pub const SPRITE_SHEET_SPRITE: &'static str = "sprite_sheet_sprite";
|
pub const SPRITE_SHEET_SPRITE: &'static str = "sprite_sheet_sprite";
|
||||||
@ -129,9 +128,6 @@ impl SpriteRenderGraphBuilder for RenderGraph {
|
|||||||
self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS)
|
self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
self.add_system_node(node::QUAD, RenderResourcesNode::<Quad>::new(false));
|
|
||||||
self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS)
|
|
||||||
.unwrap();
|
|
||||||
self.add_system_node(node::SPRITE, RenderResourcesNode::<Sprite>::new(true));
|
self.add_system_node(node::SPRITE, RenderResourcesNode::<Sprite>::new(true));
|
||||||
self.add_node_edge(node::SPRITE, base_render_graph::node::MAIN_PASS)
|
self.add_node_edge(node::SPRITE, base_render_graph::node::MAIN_PASS)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@ -2,28 +2,52 @@ use super::Node;
|
|||||||
use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
|
use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_derive::EntityArchetype;
|
use bevy_derive::EntityArchetype;
|
||||||
use bevy_render::{draw::Draw, mesh::Mesh, pipeline::RenderPipelines};
|
use bevy_render::{draw::Draw, mesh::Mesh, pipeline::{PipelineSpecialization, RenderPipelines, DynamicBinding, RenderPipeline}};
|
||||||
use bevy_sprite::{ColorMaterial, Quad, QUAD_HANDLE};
|
use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
|
||||||
|
use bevy_transform::prelude::{Translation, Transform, Rotation, Scale};
|
||||||
|
|
||||||
#[derive(EntityArchetype)]
|
#[derive(EntityArchetype)]
|
||||||
pub struct UiEntity {
|
pub struct UiEntity {
|
||||||
pub node: Node,
|
pub node: Node,
|
||||||
pub quad: Quad,
|
|
||||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||||
pub material: Handle<ColorMaterial>,
|
pub material: Handle<ColorMaterial>,
|
||||||
pub draw: Draw,
|
pub draw: Draw,
|
||||||
pub render_pipelines: RenderPipelines,
|
pub render_pipelines: RenderPipelines,
|
||||||
|
pub transform: Transform,
|
||||||
|
pub translation: Translation,
|
||||||
|
pub rotation: Rotation,
|
||||||
|
pub scale: Scale,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UiEntity {
|
impl Default for UiEntity {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
UiEntity {
|
UiEntity {
|
||||||
mesh: QUAD_HANDLE,
|
mesh: QUAD_HANDLE,
|
||||||
render_pipelines: RenderPipelines::from_handles(&[UI_PIPELINE_HANDLE]),
|
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
|
||||||
|
UI_PIPELINE_HANDLE,
|
||||||
|
PipelineSpecialization {
|
||||||
|
dynamic_bindings: vec![
|
||||||
|
// Transform
|
||||||
|
DynamicBinding {
|
||||||
|
bind_group: 1,
|
||||||
|
binding: 0,
|
||||||
|
},
|
||||||
|
// Node_size
|
||||||
|
DynamicBinding {
|
||||||
|
bind_group: 1,
|
||||||
|
binding: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)]),
|
||||||
node: Default::default(),
|
node: Default::default(),
|
||||||
quad: Default::default(),
|
|
||||||
material: Default::default(),
|
material: Default::default(),
|
||||||
draw: Default::default(),
|
draw: Default::default(),
|
||||||
|
transform: Default::default(),
|
||||||
|
translation: Default::default(),
|
||||||
|
rotation: Default::default(),
|
||||||
|
scale: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,9 +55,12 @@ impl Default for UiEntity {
|
|||||||
#[derive(EntityArchetype)]
|
#[derive(EntityArchetype)]
|
||||||
pub struct LabelEntity {
|
pub struct LabelEntity {
|
||||||
pub node: Node,
|
pub node: Node,
|
||||||
pub quad: Quad,
|
|
||||||
pub draw: Draw,
|
pub draw: Draw,
|
||||||
pub label: Label,
|
pub label: Label,
|
||||||
|
pub transform: Transform,
|
||||||
|
pub translation: Translation,
|
||||||
|
pub rotation: Rotation,
|
||||||
|
pub scale: Scale,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LabelEntity {
|
impl Default for LabelEntity {
|
||||||
@ -41,8 +68,14 @@ impl Default for LabelEntity {
|
|||||||
LabelEntity {
|
LabelEntity {
|
||||||
label: Label::default(),
|
label: Label::default(),
|
||||||
node: Default::default(),
|
node: Default::default(),
|
||||||
quad: Default::default(),
|
draw: Draw {
|
||||||
draw: Default::default(),
|
is_transparent: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
transform: Default::default(),
|
||||||
|
translation: Default::default(),
|
||||||
|
rotation: Default::default(),
|
||||||
|
scale: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub struct UiPlugin;
|
|||||||
|
|
||||||
impl AppPlugin for UiPlugin {
|
impl AppPlugin for UiPlugin {
|
||||||
fn build(&self, app: &mut AppBuilder) {
|
fn build(&self, app: &mut AppBuilder) {
|
||||||
app.add_system_to_stage(stage::POST_UPDATE, ui_update_system())
|
app.add_system_to_stage(stage::POST_UPDATE, ui_update_system.system())
|
||||||
.add_system_to_stage(stage::POST_UPDATE, Label::label_system.system())
|
.add_system_to_stage(stage::POST_UPDATE, Label::label_system.system())
|
||||||
.add_system_to_stage(bevy_render::stage::DRAW, Label::draw_label_system.system());
|
.add_system_to_stage(bevy_render::stage::DRAW, Label::draw_label_system.system());
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use super::{Anchors, Margins};
|
use super::{Anchors, Margins};
|
||||||
use bevy_sprite::Quad;
|
use bevy_transform::prelude::Translation;
|
||||||
use glam::Vec2;
|
use bevy_render::render_resource::RenderResources;
|
||||||
|
use glam::{Vec2, Vec3};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum MarginGrowDirection {
|
enum MarginGrowDirection {
|
||||||
@ -8,41 +9,37 @@ enum MarginGrowDirection {
|
|||||||
Positive,
|
Positive,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default, RenderResources)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
|
pub size: Vec2,
|
||||||
|
#[render_resources(ignore)]
|
||||||
pub position: Vec2,
|
pub position: Vec2,
|
||||||
|
#[render_resources(ignore)]
|
||||||
pub anchors: Anchors,
|
pub anchors: Anchors,
|
||||||
|
#[render_resources(ignore)]
|
||||||
pub margins: Margins,
|
pub margins: Margins,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Node {
|
impl Node {
|
||||||
fn default() -> Self {
|
pub fn new(anchors: Anchors, margins: Margins) -> Self {
|
||||||
Node {
|
Node {
|
||||||
position: Vec2::default(),
|
anchors,
|
||||||
anchors: Anchors::default(),
|
margins,
|
||||||
margins: Margins::default(),
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Node {
|
pub fn positioned(position: Vec2, anchors: Anchors, margins: Margins) -> Self {
|
||||||
pub fn new(position: Vec2, anchors: Anchors, margins: Margins) -> Self {
|
|
||||||
Node {
|
Node {
|
||||||
position,
|
position,
|
||||||
anchors,
|
anchors,
|
||||||
margins,
|
margins,
|
||||||
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(
|
pub fn update(&mut self, translation: &mut Translation, z_offset: f32, parent_size: Vec2) {
|
||||||
&mut self,
|
|
||||||
quad: &mut Quad,
|
|
||||||
parent_size: Vec2,
|
|
||||||
parent_position: Vec2,
|
|
||||||
z_index: f32,
|
|
||||||
) {
|
|
||||||
let (quad_x, quad_width) = Self::compute_dimension_properties(
|
let (quad_x, quad_width) = Self::compute_dimension_properties(
|
||||||
self.position.x(),
|
|
||||||
self.margins.left,
|
self.margins.left,
|
||||||
self.margins.right,
|
self.margins.right,
|
||||||
self.anchors.left,
|
self.anchors.left,
|
||||||
@ -50,7 +47,6 @@ impl Node {
|
|||||||
parent_size.x(),
|
parent_size.x(),
|
||||||
);
|
);
|
||||||
let (quad_y, quad_height) = Self::compute_dimension_properties(
|
let (quad_y, quad_height) = Self::compute_dimension_properties(
|
||||||
self.position.y(),
|
|
||||||
self.margins.bottom,
|
self.margins.bottom,
|
||||||
self.margins.top,
|
self.margins.top,
|
||||||
self.anchors.bottom,
|
self.anchors.bottom,
|
||||||
@ -58,13 +54,11 @@ impl Node {
|
|||||||
parent_size.y(),
|
parent_size.y(),
|
||||||
);
|
);
|
||||||
|
|
||||||
quad.size = Vec2::new(quad_width, quad_height);
|
self.size = Vec2::new(quad_width, quad_height);
|
||||||
quad.position = Vec2::new(quad_x, quad_y) + parent_position;
|
translation.0 = self.position.extend(0.0) + Vec3::new(quad_x, quad_y, z_offset) - (parent_size / 2.0).extend(0.0);
|
||||||
quad.z_index = z_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_dimension_properties(
|
fn compute_dimension_properties(
|
||||||
offset: f32,
|
|
||||||
margin0: f32,
|
margin0: f32,
|
||||||
margin1: f32,
|
margin1: f32,
|
||||||
anchor0: f32,
|
anchor0: f32,
|
||||||
@ -85,23 +79,22 @@ impl Node {
|
|||||||
MarginGrowDirection::Negative
|
MarginGrowDirection::Negative
|
||||||
};
|
};
|
||||||
|
|
||||||
let p0 = Self::compute_quad_position(offset, margin0, anchor_p0, p0_grow_direction);
|
let p0 = Self::compute_anchored_position(margin0, anchor_p0, p0_grow_direction);
|
||||||
let p1 = Self::compute_quad_position(offset, margin1, anchor_p1, p1_grow_direction);
|
let p1 = Self::compute_anchored_position(margin1, anchor_p1, p1_grow_direction);
|
||||||
|
|
||||||
let final_width = p1 - p0;
|
let final_width = p1 - p0;
|
||||||
let p = (p0 + p1) / 2.0;
|
let p = (p0 + p1) / 2.0;
|
||||||
(p, final_width.abs())
|
(p, final_width.abs())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_quad_position(
|
fn compute_anchored_position(
|
||||||
position: f32,
|
|
||||||
margin: f32,
|
margin: f32,
|
||||||
anchor_position: f32,
|
anchor_position: f32,
|
||||||
grow_direction: MarginGrowDirection,
|
grow_direction: MarginGrowDirection,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
match grow_direction {
|
match grow_direction {
|
||||||
MarginGrowDirection::Negative => position + anchor_position - margin,
|
MarginGrowDirection::Negative => anchor_position - margin,
|
||||||
MarginGrowDirection::Positive => position + anchor_position + margin,
|
MarginGrowDirection::Positive => anchor_position + margin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,12 @@ use bevy_asset::{Assets, Handle};
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
base_render_graph,
|
base_render_graph,
|
||||||
pipeline::{state_descriptors::*, PipelineDescriptor},
|
pipeline::{state_descriptors::*, PipelineDescriptor},
|
||||||
render_graph::{nodes::{PassNode, CameraNode}, RenderGraph},
|
render_graph::{nodes::{PassNode, CameraNode, RenderResourcesNode}, RenderGraph},
|
||||||
shader::{Shader, ShaderStage, ShaderStages},
|
shader::{Shader, ShaderStage, ShaderStages},
|
||||||
texture::TextureFormat, ActiveCameras,
|
texture::TextureFormat, ActiveCameras,
|
||||||
};
|
};
|
||||||
use legion::prelude::Resources;
|
use legion::prelude::Resources;
|
||||||
|
use crate::Node;
|
||||||
|
|
||||||
pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
|
pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
|
||||||
Handle::from_u128(323432002226399387835192542539754486265);
|
Handle::from_u128(323432002226399387835192542539754486265);
|
||||||
@ -58,6 +59,7 @@ pub fn build_ui_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
|
|||||||
|
|
||||||
pub mod node {
|
pub mod node {
|
||||||
pub const UI_CAMERA: &'static str = "ui_camera";
|
pub const UI_CAMERA: &'static str = "ui_camera";
|
||||||
|
pub const NODE: &'static str = "node";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod camera {
|
pub mod camera {
|
||||||
@ -78,6 +80,9 @@ impl UiRenderGraphBuilder for RenderGraph {
|
|||||||
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
|
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
|
||||||
self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS)
|
self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
self.add_system_node(node::NODE, RenderResourcesNode::<Node>::new(true));
|
||||||
|
self.add_node_edge(node::NODE, base_render_graph::node::MAIN_PASS)
|
||||||
|
.unwrap();
|
||||||
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
|
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
|
||||||
let main_pass_node: &mut PassNode = self.get_node_mut(base_render_graph::node::MAIN_PASS).unwrap();
|
let main_pass_node: &mut PassNode = self.get_node_mut(base_render_graph::node::MAIN_PASS).unwrap();
|
||||||
main_pass_node.add_camera(camera::UI_CAMERA);
|
main_pass_node.add_camera(camera::UI_CAMERA);
|
||||||
|
|||||||
@ -9,8 +9,8 @@ layout(set = 2, binding = 0) uniform ColorMaterial_color {
|
|||||||
};
|
};
|
||||||
|
|
||||||
# ifdef COLORMATERIAL_TEXTURE
|
# ifdef COLORMATERIAL_TEXTURE
|
||||||
layout(set = 3, binding = 0) uniform texture2D ColorMaterial_texture;
|
layout(set = 2, binding = 1) uniform texture2D ColorMaterial_texture;
|
||||||
layout(set = 3, binding = 1) uniform sampler ColorMaterial_texture_sampler;
|
layout(set = 2, binding = 2) uniform sampler ColorMaterial_texture_sampler;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|||||||
@ -10,15 +10,15 @@ layout(set = 0, binding = 0) uniform UiCamera {
|
|||||||
mat4 ViewProj;
|
mat4 ViewProj;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(set = 1, binding = 0) uniform Quad {
|
layout(set = 1, binding = 0) uniform Transform {
|
||||||
vec2 Quad_Position;
|
mat4 Object;
|
||||||
vec2 Quad_Size;
|
};
|
||||||
float Quad_ZIndex;
|
layout(set = 1, binding = 1) uniform Node_size {
|
||||||
|
vec2 NodeSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
v_Uv = Vertex_Uv;
|
v_Uv = Vertex_Uv;
|
||||||
vec3 position = Vertex_Position * vec3(Quad_Size, 0.0);
|
vec3 position = Vertex_Position * vec3(NodeSize, 0.0);
|
||||||
position = position + vec3(Quad_Position, Quad_ZIndex);
|
gl_Position = ViewProj * Object * vec4(position, 1.0);
|
||||||
gl_Position = ViewProj * vec4(position, 1.0);
|
|
||||||
}
|
}
|
||||||
@ -1,74 +1,81 @@
|
|||||||
use super::Node;
|
use super::Node;
|
||||||
use bevy_core::transform::run_on_hierarchy_subworld_mut;
|
use bevy_core::transform::run_on_hierarchy_subworld_mut;
|
||||||
use bevy_sprite::Quad;
|
use bevy_transform::prelude::{Children, Parent, Translation};
|
||||||
use bevy_transform::prelude::{Children, Parent};
|
|
||||||
use bevy_window::Windows;
|
use bevy_window::Windows;
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use legion::{prelude::*, systems::SubWorld};
|
use legion::{prelude::*, systems::SubWorld};
|
||||||
|
|
||||||
pub const UI_Z_STEP: f32 = 0.001;
|
pub const UI_Z_STEP: f32 = 0.001;
|
||||||
|
|
||||||
pub fn ui_update_system() -> Box<dyn Schedulable> {
|
#[derive(Clone)]
|
||||||
SystemBuilder::new("ui_update")
|
pub struct Rect {
|
||||||
.read_resource::<Windows>()
|
pub z: f32,
|
||||||
.with_query(<Read<Node>>::query().filter(!component::<Parent>()))
|
pub size: Vec2,
|
||||||
.write_component::<Node>()
|
|
||||||
.write_component::<Quad>()
|
|
||||||
.read_component::<Children>()
|
|
||||||
.build(move |_, world, windows, node_query| {
|
|
||||||
if let Some(window) = windows.get_primary() {
|
|
||||||
let mut window_quad = Quad {
|
|
||||||
size: Vec2::new(window.width as f32, window.height as f32),
|
|
||||||
position: Vec2::new(0.0, 0.0),
|
|
||||||
z_index: 999.0,
|
|
||||||
};
|
|
||||||
for entity in node_query
|
|
||||||
.iter_entities(world)
|
|
||||||
.map(|(e, _)| e)
|
|
||||||
.collect::<Vec<Entity>>()
|
|
||||||
{
|
|
||||||
let result = run_on_hierarchy_subworld_mut(
|
|
||||||
world,
|
|
||||||
entity,
|
|
||||||
window_quad.clone(),
|
|
||||||
&mut update_node_entity,
|
|
||||||
&mut process_child_result,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(result) = result {
|
|
||||||
window_quad.z_index = result.z_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_node_entity(world: &mut SubWorld, entity: Entity, parent_quad: Quad) -> Option<Quad> {
|
pub fn ui_update_system(
|
||||||
|
world: &mut SubWorld,
|
||||||
|
windows: Res<Windows>,
|
||||||
|
node_query: &mut Query<(Write<Node>, Write<Translation>)>,
|
||||||
|
_parent_query: &mut Query<Read<Parent>>,
|
||||||
|
_children_query: &mut Query<Read<Children>>,
|
||||||
|
) {
|
||||||
|
let window_size = if let Some(window) = windows.get_primary() {
|
||||||
|
Vec2::new(window.width as f32, window.height as f32)
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let orphan_nodes = node_query
|
||||||
|
.iter_entities_mut(world)
|
||||||
|
// TODO: replace this filter with a legion query filter (when SimpleQuery gets support for filters)
|
||||||
|
.filter(|(entity, _)| world.get_component::<Parent>(*entity).is_none())
|
||||||
|
.map(|(e, _)| e)
|
||||||
|
.collect::<Vec<Entity>>();
|
||||||
|
let mut window_rect = Rect {
|
||||||
|
z: 0.0,
|
||||||
|
size: window_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut previous_sibling_result = Some(Rect {
|
||||||
|
z: 999.0,
|
||||||
|
size: window_size,
|
||||||
|
});
|
||||||
|
for entity in orphan_nodes {
|
||||||
|
previous_sibling_result = run_on_hierarchy_subworld_mut(
|
||||||
|
world,
|
||||||
|
entity,
|
||||||
|
Some(&mut window_rect),
|
||||||
|
previous_sibling_result,
|
||||||
|
&mut update_node_entity,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_node_entity(world: &mut SubWorld, entity: Entity, parent_rect: Option<&mut Rect>, previous_rect: Option<Rect>) -> Option<Rect> {
|
||||||
// TODO: Somehow remove this unsafe
|
// TODO: Somehow remove this unsafe
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(mut node) = world.get_component_mut_unchecked::<Node>(entity) {
|
if let Some(mut node) = world.get_component_mut_unchecked::<Node>(entity) {
|
||||||
if let Some(mut quad) = world.get_component_mut_unchecked::<Quad>(entity) {
|
if let Some(mut translation) = world.get_component_mut_unchecked::<Translation>(entity)
|
||||||
|
{
|
||||||
|
let parent_rect = parent_rect.unwrap();
|
||||||
|
let mut z = parent_rect.z;
|
||||||
|
if let Some(previous_rect) = previous_rect {
|
||||||
|
z = previous_rect.z
|
||||||
|
};
|
||||||
|
|
||||||
|
z -= UI_Z_STEP;
|
||||||
node.update(
|
node.update(
|
||||||
&mut quad,
|
&mut translation,
|
||||||
parent_quad.size,
|
z - parent_rect.z,
|
||||||
parent_quad.position,
|
parent_rect.size,
|
||||||
parent_quad.z_index,
|
|
||||||
);
|
);
|
||||||
return Some(Quad {
|
return Some(Rect {
|
||||||
size: quad.size,
|
size: node.size,
|
||||||
position: quad.position - quad.size / 2.0,
|
z,
|
||||||
z_index: quad.z_index - UI_Z_STEP,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_child_result(_parent_result: Quad, child_result: Quad) -> Quad {
|
|
||||||
// "earlier" children are sorted behind "later" children
|
|
||||||
let mut result = child_result.clone();
|
|
||||||
result.z_index -= UI_Z_STEP;
|
|
||||||
result
|
|
||||||
}
|
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::Node;
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
draw::{Draw, DrawContext, Drawable},
|
draw::{Draw, DrawContext, Drawable},
|
||||||
@ -5,9 +6,9 @@ use bevy_render::{
|
|||||||
texture::Texture,
|
texture::Texture,
|
||||||
Color,
|
Color,
|
||||||
};
|
};
|
||||||
use bevy_sprite::{ComMut, Quad, TextureAtlas};
|
use bevy_sprite::{ComMut, TextureAtlas};
|
||||||
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
|
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
|
||||||
use glam::Vec3;
|
use bevy_transform::prelude::Transform;
|
||||||
use legion::prelude::{Com, Res, ResMut};
|
use legion::prelude::{Com, Res, ResMut};
|
||||||
|
|
||||||
pub struct Label {
|
pub struct Label {
|
||||||
@ -44,7 +45,7 @@ impl Label {
|
|||||||
});
|
});
|
||||||
// TODO: this call results in one or more TextureAtlases, whose render resources are created in the RENDER_GRAPH_SYSTEMS
|
// TODO: this call results in one or more TextureAtlases, whose render resources are created in the RENDER_GRAPH_SYSTEMS
|
||||||
// stage. That logic runs _before_ the DRAW stage, which means we cant call add_glyphs_to_atlas in the draw stage
|
// stage. That logic runs _before_ the DRAW stage, which means we cant call add_glyphs_to_atlas in the draw stage
|
||||||
// without or render resources being a frame behind. Therefore glyph atlasing either needs its own system or the TextureAtlas
|
// without our render resources being a frame behind. Therefore glyph atlasing either needs its own system or the TextureAtlas
|
||||||
// resource generation needs to happen AFTER the render graph systems. maybe draw systems should execute within the
|
// resource generation needs to happen AFTER the render graph systems. maybe draw systems should execute within the
|
||||||
// render graph so ordering like this can be taken into account? Maybe the RENDER_GRAPH_SYSTEMS stage should be removed entirely
|
// render graph so ordering like this can be taken into account? Maybe the RENDER_GRAPH_SYSTEMS stage should be removed entirely
|
||||||
// in favor of node.update()? Regardless, in the immediate short term the current approach is fine.
|
// in favor of node.update()? Regardless, in the immediate short term the current approach is fine.
|
||||||
@ -66,9 +67,12 @@ impl Label {
|
|||||||
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
|
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
|
||||||
mut draw: ComMut<Draw>,
|
mut draw: ComMut<Draw>,
|
||||||
label: Com<Label>,
|
label: Com<Label>,
|
||||||
quad: Com<Quad>,
|
node: Com<Node>,
|
||||||
|
transform: Com<Transform>,
|
||||||
) {
|
) {
|
||||||
let position = quad.position - quad.size / 2.0;
|
// let position = transform.0 - quad.size / 2.0;
|
||||||
|
let position = transform.value.w_axis().truncate() - (node.size / 2.0).extend(0.0);
|
||||||
|
|
||||||
let mut drawable_text = DrawableText::new(
|
let mut drawable_text = DrawableText::new(
|
||||||
fonts.get(&label.font).unwrap(),
|
fonts.get(&label.font).unwrap(),
|
||||||
font_atlas_sets
|
font_atlas_sets
|
||||||
@ -77,7 +81,7 @@ impl Label {
|
|||||||
&texture_atlases,
|
&texture_atlases,
|
||||||
&mut render_resource_bindings,
|
&mut render_resource_bindings,
|
||||||
&mut asset_render_resource_bindings,
|
&mut asset_render_resource_bindings,
|
||||||
Vec3::new(position.x(), position.y(), quad.z_index),
|
position,
|
||||||
&label.style,
|
&label.style,
|
||||||
&label.text,
|
&label.text,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -73,7 +73,6 @@ fn setup(
|
|||||||
// texture
|
// texture
|
||||||
.add_entity(LabelEntity {
|
.add_entity(LabelEntity {
|
||||||
node: Node::new(
|
node: Node::new(
|
||||||
math::vec2(0.0, 0.0),
|
|
||||||
Anchors::TOP_LEFT,
|
Anchors::TOP_LEFT,
|
||||||
Margins::new(0.0, 250.0, 0.0, 60.0),
|
Margins::new(0.0, 250.0, 0.0, 60.0),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -29,7 +29,6 @@ fn setup(command_buffer: &mut CommandBuffer, asset_server: Res<AssetServer>) {
|
|||||||
// texture
|
// texture
|
||||||
.add_entity(LabelEntity {
|
.add_entity(LabelEntity {
|
||||||
node: Node::new(
|
node: Node::new(
|
||||||
math::vec2(0.0, 0.0),
|
|
||||||
Anchors::TOP_LEFT,
|
Anchors::TOP_LEFT,
|
||||||
Margins::new(0.0, 250.0, 0.0, 60.0),
|
Margins::new(0.0, 250.0, 0.0, 60.0),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -60,7 +60,6 @@ fn setup(
|
|||||||
// left vertical fill
|
// left vertical fill
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::new(
|
||||||
math::vec2(0.0, 0.0),
|
|
||||||
Anchors::LEFT_FULL,
|
Anchors::LEFT_FULL,
|
||||||
Margins::new(10.0, 200.0, 10.0, 10.0),
|
Margins::new(10.0, 200.0, 10.0, 10.0),
|
||||||
),
|
),
|
||||||
@ -70,7 +69,6 @@ fn setup(
|
|||||||
.add_children(|builder| {
|
.add_children(|builder| {
|
||||||
builder.add_entity(LabelEntity {
|
builder.add_entity(LabelEntity {
|
||||||
node: Node::new(
|
node: Node::new(
|
||||||
math::vec2(0.0, 0.0),
|
|
||||||
Anchors::TOP_LEFT,
|
Anchors::TOP_LEFT,
|
||||||
Margins::new(10.0, 200.0, 40.0, 10.0),
|
Margins::new(10.0, 200.0, 40.0, 10.0),
|
||||||
),
|
),
|
||||||
@ -88,7 +86,6 @@ fn setup(
|
|||||||
// right vertical fill
|
// right vertical fill
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::new(
|
||||||
math::vec2(0.0, 0.0),
|
|
||||||
Anchors::RIGHT_FULL,
|
Anchors::RIGHT_FULL,
|
||||||
Margins::new(10.0, 100.0, 100.0, 100.0),
|
Margins::new(10.0, 100.0, 100.0, 100.0),
|
||||||
),
|
),
|
||||||
@ -97,7 +94,7 @@ fn setup(
|
|||||||
})
|
})
|
||||||
// render order test: reddest in the back, whitest in the front
|
// render order test: reddest in the back, whitest in the front
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::positioned(
|
||||||
math::vec2(75.0, 60.0),
|
math::vec2(75.0, 60.0),
|
||||||
Anchors::CENTER,
|
Anchors::CENTER,
|
||||||
Margins::new(0.0, 100.0, 0.0, 100.0),
|
Margins::new(0.0, 100.0, 0.0, 100.0),
|
||||||
@ -106,7 +103,7 @@ fn setup(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::positioned(
|
||||||
math::vec2(50.0, 35.0),
|
math::vec2(50.0, 35.0),
|
||||||
Anchors::CENTER,
|
Anchors::CENTER,
|
||||||
Margins::new(0.0, 100.0, 0.0, 100.0),
|
Margins::new(0.0, 100.0, 0.0, 100.0),
|
||||||
@ -115,7 +112,7 @@ fn setup(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::positioned(
|
||||||
math::vec2(100.0, 85.0),
|
math::vec2(100.0, 85.0),
|
||||||
Anchors::CENTER,
|
Anchors::CENTER,
|
||||||
Margins::new(0.0, 100.0, 0.0, 100.0),
|
Margins::new(0.0, 100.0, 0.0, 100.0),
|
||||||
@ -124,7 +121,7 @@ fn setup(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::positioned(
|
||||||
math::vec2(150.0, 135.0),
|
math::vec2(150.0, 135.0),
|
||||||
Anchors::CENTER,
|
Anchors::CENTER,
|
||||||
Margins::new(0.0, 100.0, 0.0, 100.0),
|
Margins::new(0.0, 100.0, 0.0, 100.0),
|
||||||
@ -134,7 +131,7 @@ fn setup(
|
|||||||
})
|
})
|
||||||
// parenting
|
// parenting
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::positioned(
|
||||||
math::vec2(210.0, 0.0),
|
math::vec2(210.0, 0.0),
|
||||||
Anchors::BOTTOM_LEFT,
|
Anchors::BOTTOM_LEFT,
|
||||||
Margins::new(0.0, 200.0, 10.0, 210.0),
|
Margins::new(0.0, 200.0, 10.0, 210.0),
|
||||||
@ -145,7 +142,6 @@ fn setup(
|
|||||||
.add_children(|builder| {
|
.add_children(|builder| {
|
||||||
builder.add_entity(UiEntity {
|
builder.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::new(
|
||||||
math::vec2(0.0, 0.0),
|
|
||||||
Anchors::FULL,
|
Anchors::FULL,
|
||||||
Margins::new(20.0, 20.0, 20.0, 20.0),
|
Margins::new(20.0, 20.0, 20.0, 20.0),
|
||||||
),
|
),
|
||||||
@ -155,7 +151,7 @@ fn setup(
|
|||||||
})
|
})
|
||||||
// alpha test
|
// alpha test
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::positioned(
|
||||||
math::vec2(200.0, 185.0),
|
math::vec2(200.0, 185.0),
|
||||||
Anchors::CENTER,
|
Anchors::CENTER,
|
||||||
Margins::new(0.0, 100.0, 0.0, 100.0),
|
Margins::new(0.0, 100.0, 0.0, 100.0),
|
||||||
@ -166,7 +162,6 @@ fn setup(
|
|||||||
// texture
|
// texture
|
||||||
.add_entity(UiEntity {
|
.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node::new(
|
||||||
math::vec2(0.0, 0.0),
|
|
||||||
Anchors::CENTER_TOP,
|
Anchors::CENTER_TOP,
|
||||||
Margins::new(-250.0, 250.0, 510.0 * aspect, 10.0),
|
Margins::new(-250.0, 250.0, 510.0 * aspect, 10.0),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -29,13 +29,14 @@ fn setup(command_buffer: &mut CommandBuffer, mut materials: ResMut<Assets<ColorM
|
|||||||
let count = 1000;
|
let count = 1000;
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
// 2d camera
|
// 2d camera
|
||||||
let cur = Vec2::new(1.0, 1.0) * 1.0 + prev;
|
let cur = Vec2::new(1.0, 1.0) + prev;
|
||||||
builder.add_entity(UiEntity {
|
builder.add_entity(UiEntity {
|
||||||
node: Node::new(
|
node: Node {
|
||||||
math::vec2(75.0, 75.0) + cur,
|
position: Vec2::new(75.0, 75.0) + cur,
|
||||||
Anchors::new(0.5, 0.5, 0.5, 0.5),
|
anchors: Anchors::new(0.5, 0.5, 0.5, 0.5),
|
||||||
Margins::new(0.0, 100.0, 0.0, 100.0),
|
margins: Margins::new(0.0, 100.0, 0.0, 100.0),
|
||||||
),
|
..Default::default()
|
||||||
|
},
|
||||||
material: materials.add(Color::rgb(0.0 + i as f32 / count as f32, 0.1, 0.1).into()),
|
material: materials.add(Color::rgb(0.0 + i as f32 / count as f32, 0.1, 0.1).into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|||||||
@ -33,7 +33,7 @@ pub use crate::{
|
|||||||
scene::{Scene, SceneSpawner},
|
scene::{Scene, SceneSpawner},
|
||||||
sprite::{
|
sprite::{
|
||||||
entity::{SpriteEntity, SpriteSheetEntity},
|
entity::{SpriteEntity, SpriteSheetEntity},
|
||||||
ColorMaterial, Quad, Sprite, TextureAtlas, TextureAtlasSprite,
|
ColorMaterial, Sprite, TextureAtlas, TextureAtlasSprite,
|
||||||
},
|
},
|
||||||
text::{Font, TextStyle},
|
text::{Font, TextStyle},
|
||||||
transform::prelude::*,
|
transform::prelude::*,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user