ui: rework so Nodes now use transforms and z-sort happens

This commit is contained in:
Carter Anderson 2020-06-25 10:13:00 -07:00
parent 75429f4639
commit 1ef4fbf005
18 changed files with 185 additions and 168 deletions

View File

@ -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
} }

View File

@ -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(),

View File

@ -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::*;

View File

@ -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,
}

View File

@ -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();

View File

@ -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(),
} }
} }
} }

View File

@ -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());

View File

@ -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,
} }
} }
} }

View File

@ -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);

View File

@ -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() {

View File

@ -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);
} }

View File

@ -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
}

View File

@ -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,
); );

View File

@ -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),
), ),

View File

@ -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),
), ),

View File

@ -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),
), ),

View File

@ -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()
}); });

View File

@ -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::*,