ui: remove translation/rotation/scale components (Node serves the same role)

This commit is contained in:
Carter Anderson 2020-07-19 20:33:55 -07:00
parent 726eb37198
commit 9a236f4923
12 changed files with 156 additions and 145 deletions

View file

@ -17,7 +17,7 @@
use core::{
ops::{Deref, DerefMut},
ptr::NonNull,
sync::atomic::{AtomicUsize, Ordering},
sync::atomic::{AtomicUsize, Ordering}, fmt::Debug,
};
use crate::{archetype::Archetype, Component, MissingComponent};
@ -101,6 +101,12 @@ impl<'a, T: Component> Deref for Ref<'a, T> {
}
}
impl<'a, T: Component> Debug for Ref<'a,T> where T: Debug {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.deref().fmt(f)
}
}
/// Unique borrow of an entity's component
pub struct RefMut<'a, T: Component> {
archetype: &'a Archetype,
@ -155,6 +161,12 @@ impl<'a, T: Component> DerefMut for RefMut<'a, T> {
}
}
impl<'a, T: Component> Debug for RefMut<'a,T> where T: Debug {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.deref().fmt(f)
}
}
/// Handle to an entity with any component types
#[derive(Copy, Clone)]
pub struct EntityRef<'a> {

View file

@ -1,8 +1,8 @@
use super::Node;
use crate::{
render::UI_PIPELINE_HANDLE,
widget::{Button, Label},
Click, Hover, FocusPolicy,
widget::{Button, Text},
Click, FocusPolicy, Hover,
};
use bevy_asset::Handle;
use bevy_ecs::Bundle;
@ -12,7 +12,7 @@ use bevy_render::{
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
};
use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
use bevy_transform::{components::LocalTransform, prelude::Transform};
#[derive(Bundle)]
pub struct NodeComponents {
@ -22,9 +22,7 @@ pub struct NodeComponents {
pub draw: Draw,
pub render_pipelines: RenderPipelines,
pub transform: Transform,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
pub local_transform: LocalTransform,
}
impl Default for NodeComponents {
@ -53,29 +51,25 @@ impl Default for NodeComponents {
material: Default::default(),
draw: Default::default(),
transform: Default::default(),
translation: Default::default(),
rotation: Default::default(),
scale: Default::default(),
local_transform: Default::default(),
}
}
}
#[derive(Bundle)]
pub struct LabelComponents {
pub struct TextComponents {
pub node: Node,
pub draw: Draw,
pub label: Label,
pub text: Text,
pub focus_policy: FocusPolicy,
pub transform: Transform,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
pub local_transform: LocalTransform,
}
impl Default for LabelComponents {
impl Default for TextComponents {
fn default() -> Self {
LabelComponents {
label: Label::default(),
TextComponents {
text: Text::default(),
node: Default::default(),
focus_policy: FocusPolicy::Pass,
draw: Draw {
@ -83,9 +77,7 @@ impl Default for LabelComponents {
..Default::default()
},
transform: Default::default(),
translation: Default::default(),
rotation: Default::default(),
scale: Default::default(),
local_transform: Default::default(),
}
}
}
@ -102,9 +94,7 @@ pub struct ButtonComponents {
pub draw: Draw,
pub render_pipelines: RenderPipelines,
pub transform: Transform,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
pub local_transform: LocalTransform,
}
impl Default for ButtonComponents {
@ -137,9 +127,7 @@ impl Default for ButtonComponents {
material: Default::default(),
draw: Default::default(),
transform: Default::default(),
translation: Default::default(),
rotation: Default::default(),
scale: Default::default(),
local_transform: Default::default(),
}
}
}

View file

@ -16,7 +16,7 @@ pub use render::*;
pub mod prelude {
pub use crate::{
entity::*,
widget::{Button, Label},
widget::{Button, Text},
Anchors, Click, Hover, Margins, Node,
};
}
@ -25,7 +25,6 @@ use bevy_app::prelude::*;
use bevy_ecs::IntoQuerySystem;
use bevy_render::render_graph::RenderGraph;
use update::ui_update_system;
use widget::Label;
#[derive(Default)]
pub struct UiPlugin;
@ -34,8 +33,8 @@ impl AppPlugin for UiPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_system_to_stage(stage::PRE_UPDATE, ui_focus_system.system())
.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(bevy_render::stage::DRAW, Label::draw_label_system.system());
.add_system_to_stage(stage::POST_UPDATE, widget::text_system.system())
.add_system_to_stage(bevy_render::stage::DRAW, widget::draw_text_system.system());
let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();

View file

@ -1,7 +1,7 @@
use super::{Anchors, Margins};
use bevy_math::{Vec2, Vec3};
use bevy_math::{Mat4, Vec2, Vec3};
use bevy_render::renderer::RenderResources;
use bevy_transform::prelude::Translation;
use bevy_transform::components::LocalTransform;
#[derive(Debug, Clone)]
enum MarginGrowDirection {
@ -38,7 +38,12 @@ impl Node {
}
}
pub fn update(&mut self, translation: &mut Translation, z_offset: f32, parent_size: Vec2) {
pub fn update(
&mut self,
local_transform: &mut LocalTransform,
z_offset: f32,
parent_size: Vec2,
) {
let (quad_x, quad_width) = Self::compute_dimension_properties(
self.margins.left,
self.margins.right,
@ -55,8 +60,10 @@ impl Node {
);
self.size = Vec2::new(quad_width, quad_height);
translation.0 = self.position.extend(0.0) + Vec3::new(quad_x, quad_y, z_offset)
- (parent_size / 2.0).extend(0.0);
local_transform.0 = Mat4::from_translation(
self.position.extend(z_offset) + Vec3::new(quad_x, quad_y, z_offset)
- (parent_size / 2.0).extend(0.0),
);
}
fn compute_dimension_properties(

View file

@ -3,7 +3,7 @@ use bevy_ecs::{Entity, Query, Res, Without};
use bevy_math::Vec2;
use bevy_transform::{
hierarchy,
prelude::{Children, Parent, Translation},
prelude::{Children, LocalTransform, Parent},
};
use bevy_window::Windows;
@ -17,8 +17,8 @@ pub struct Rect {
pub fn ui_update_system(
windows: Res<Windows>,
mut orphan_node_query: Query<Without<Parent, (Entity, &mut Node, &mut Translation)>>,
mut node_query: Query<(Entity, &mut Node, &mut Translation)>,
mut orphan_node_query: Query<Without<Parent, (Entity, &mut Node, &mut LocalTransform)>>,
mut node_query: Query<(Entity, &mut Node, &mut LocalTransform)>,
children_query: Query<&Children>,
) {
let window_size = if let Some(window) = windows.get_primary() {
@ -53,21 +53,20 @@ pub fn ui_update_system(
}
fn update_node_entity(
node_query: &mut Query<(Entity, &mut Node, &mut Translation)>,
node_query: &mut Query<(Entity, &mut Node, &mut LocalTransform)>,
entity: Entity,
parent_rect: Option<&mut Rect>,
previous_rect: Option<Rect>,
) -> Option<Rect> {
if let Ok(mut node) = node_query.get_mut::<Node>(entity) {
if let Ok(mut translation) = node_query.get_mut::<Translation>(entity) {
if let Ok(mut local_transform) = node_query.get_mut::<LocalTransform>(entity) {
let parent_rect = parent_rect.unwrap();
let mut z = parent_rect.z;
let mut z = UI_Z_STEP;
if let Some(previous_rect) = previous_rect {
z = previous_rect.z
z += previous_rect.z
};
z += UI_Z_STEP;
node.update(&mut translation, z + parent_rect.z, parent_rect.size);
node.update(&mut local_transform, z, parent_rect.size);
return Some(Rect { size: node.size, z });
}
}

View file

@ -1,77 +0,0 @@
use crate::Node;
use bevy_asset::{Assets, Handle};
use bevy_ecs::{Query, Res, ResMut};
use bevy_render::{
draw::{Draw, DrawContext, Drawable},
renderer::{AssetRenderResourceBindings, RenderResourceBindings},
texture::Texture,
};
use bevy_sprite::TextureAtlas;
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
use bevy_transform::prelude::Transform;
#[derive(Default)]
pub struct Label {
pub text: String,
pub font: Handle<Font>,
pub style: TextStyle,
}
impl Label {
pub fn label_system(
mut textures: ResMut<Assets<Texture>>,
fonts: Res<Assets<Font>>,
mut font_atlas_sets: ResMut<Assets<FontAtlasSet>>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
mut query: Query<&Label>,
) {
for label in &mut query.iter() {
let font_atlases = font_atlas_sets
.get_or_insert_with(Handle::from_id(label.font.id), || {
FontAtlasSet::new(label.font)
});
// 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
// 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
// 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.
font_atlases.add_glyphs_to_atlas(
&fonts,
&mut texture_atlases,
&mut textures,
label.style.font_size,
&label.text,
);
}
}
pub fn draw_label_system(
mut draw_context: DrawContext,
fonts: Res<Assets<Font>>,
font_atlas_sets: Res<Assets<FontAtlasSet>>,
texture_atlases: Res<Assets<TextureAtlas>>,
mut render_resource_bindings: ResMut<RenderResourceBindings>,
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
mut query: Query<(&mut Draw, &Label, &Node, &Transform)>,
) {
for (mut draw, label, node, transform) in &mut query.iter() {
let position = transform.value.w_axis().truncate() - (node.size / 2.0).extend(0.0);
let mut drawable_text = DrawableText {
font: fonts.get(&label.font).unwrap(),
font_atlas_set: font_atlas_sets
.get(&label.font.as_handle::<FontAtlasSet>())
.unwrap(),
texture_atlases: &texture_atlases,
render_resource_bindings: &mut render_resource_bindings,
asset_render_resource_bindings: &mut asset_render_resource_bindings,
position,
style: &label.style,
text: &label.text,
container_size: node.size,
};
drawable_text.draw(&mut draw, &mut draw_context).unwrap();
}
}
}

View file

@ -1,5 +1,5 @@
mod button;
mod label;
mod text;
pub use button::*;
pub use label::*;
pub use text::*;

View file

@ -0,0 +1,75 @@
use crate::Node;
use bevy_asset::{Assets, Handle};
use bevy_ecs::{Query, Res, ResMut};
use bevy_render::{
draw::{Draw, DrawContext, Drawable},
renderer::{AssetRenderResourceBindings, RenderResourceBindings},
texture::Texture,
};
use bevy_sprite::TextureAtlas;
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
use bevy_transform::prelude::Transform;
#[derive(Default)]
pub struct Text {
pub value: String,
pub font: Handle<Font>,
pub style: TextStyle,
}
pub fn text_system(
mut textures: ResMut<Assets<Texture>>,
fonts: Res<Assets<Font>>,
mut font_atlas_sets: ResMut<Assets<FontAtlasSet>>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
mut query: Query<&Text>,
) {
for text in &mut query.iter() {
let font_atlases = font_atlas_sets
.get_or_insert_with(Handle::from_id(text.font.id), || {
FontAtlasSet::new(text.font)
});
// 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
// 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
// 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.
font_atlases.add_glyphs_to_atlas(
&fonts,
&mut texture_atlases,
&mut textures,
text.style.font_size,
&text.value,
);
}
}
pub fn draw_text_system(
mut draw_context: DrawContext,
fonts: Res<Assets<Font>>,
font_atlas_sets: Res<Assets<FontAtlasSet>>,
texture_atlases: Res<Assets<TextureAtlas>>,
mut render_resource_bindings: ResMut<RenderResourceBindings>,
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
mut query: Query<(&mut Draw, &Text, &Node, &Transform)>,
) {
for (mut draw, text, node, transform) in &mut query.iter() {
let position = transform.value.w_axis().truncate() - (node.size / 2.0).extend(0.0);
let mut drawable_text = DrawableText {
font: fonts.get(&text.font).unwrap(),
font_atlas_set: font_atlas_sets
.get(&text.font.as_handle::<FontAtlasSet>())
.unwrap(),
texture_atlases: &texture_atlases,
render_resource_bindings: &mut render_resource_bindings,
asset_render_resource_bindings: &mut asset_render_resource_bindings,
position,
style: &text.style,
text: &text.value,
container_size: node.size,
};
drawable_text.draw(&mut draw, &mut draw_context).unwrap();
}
}

View file

@ -64,10 +64,10 @@ fn setup(
velocity: 400.0 * Vec3::new(0.5, -0.5, 0.0).normalize(),
})
// scoreboard
.spawn(LabelComponents {
label: Label {
.spawn(TextComponents {
text: Text {
font: asset_server.load("assets/fonts/FiraSans-Bold.ttf").unwrap(),
text: "Score:".to_string(),
value: "Score:".to_string(),
style: TextStyle {
color: Color::rgb(0.2, 0.2, 0.8).into(),
font_size: 40.0,
@ -180,9 +180,9 @@ fn ball_movement_system(time: Res<Time>, mut ball_query: Query<(&Ball, &mut Tran
}
}
fn scoreboard_system(scoreboard: Res<Scoreboard>, mut query: Query<&mut Label>) {
for mut label in &mut query.iter() {
label.text = format!("Score: {}", scoreboard.score);
fn scoreboard_system(scoreboard: Res<Scoreboard>, mut query: Query<&mut Text>) {
for mut text in &mut query.iter() {
text.value = format!("Score: {}", scoreboard.score);
}
}

View file

@ -50,11 +50,11 @@ fn atlas_render_system(
}
}
fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Query<&mut Label>) {
for mut label in &mut query.iter() {
fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Query<&mut Text>) {
for mut text in &mut query.iter() {
state.timer.tick(time.delta_seconds);
if state.timer.finished {
label.text = format!("{}", rand::random::<u8>() as char);
text.value = format!("{}", rand::random::<u8>() as char);
state.timer.reset();
}
}
@ -67,10 +67,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResM
// 2d camera
.spawn(Camera2dComponents::default())
// texture
.spawn(LabelComponents {
.spawn(TextComponents {
node: Node::new(Anchors::TOP_LEFT, Margins::new(0.0, 250.0, 0.0, 60.0)),
label: Label {
text: "a".to_string(),
text: Text {
value: "a".to_string(),
font: font_handle,
style: TextStyle {
font_size: 60.0,

View file

@ -12,11 +12,11 @@ fn main() {
.run();
}
fn text_update_system(diagnostics: Res<Diagnostics>, mut query: Query<&mut Label>) {
for mut label in &mut query.iter() {
fn text_update_system(diagnostics: Res<Diagnostics>, mut query: Query<&mut Text>) {
for mut text in &mut query.iter() {
if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) {
if let Some(average) = fps.average() {
label.text = format!("FPS: {:.2}", average);
text.value = format!("FPS: {:.2}", average);
}
}
}
@ -28,10 +28,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// 2d camera
.spawn(Camera2dComponents::default())
// texture
.spawn(LabelComponents {
.spawn(TextComponents {
node: Node::new(Anchors::TOP_LEFT, Margins::new(0.0, 250.0, 0.0, 60.0)),
label: Label {
text: "FPS:".to_string(),
text: Text {
value: "FPS:".to_string(),
font: font_handle,
style: TextStyle {
font_size: 60.0,

View file

@ -39,10 +39,10 @@ fn setup(
..Default::default()
})
.with_children(|parent| {
parent.spawn(LabelComponents {
parent.spawn(TextComponents {
node: Node::new(Anchors::TOP_LEFT, Margins::new(10.0, 200.0, 40.0, 10.0)),
label: Label {
text: "Text Label".to_string(),
text: Text {
value: "Text Example".to_string(),
font: font_handle,
style: TextStyle {
font_size: 30.0,
@ -121,6 +121,10 @@ fn setup(
Margins::new(0.0, 100.0, 0.0, 100.0),
),
material: materials.add(Color::rgba(1.0, 0.9, 0.9, 0.4).into()),
draw: Draw {
is_transparent: true,
..Default::default()
},
..Default::default()
})
// texture
@ -130,6 +134,10 @@ fn setup(
Margins::new(-250.0, 250.0, 510.0 * aspect, 10.0),
),
material: materials.add(ColorMaterial::texture(texture_handle)),
draw: Draw {
is_transparent: true,
..Default::default()
},
..Default::default()
});
});