diff --git a/crates/bevy_ecs/hecs/src/borrow.rs b/crates/bevy_ecs/hecs/src/borrow.rs index 9dc5cdd33a..1d072a9692 100644 --- a/crates/bevy_ecs/hecs/src/borrow.rs +++ b/crates/bevy_ecs/hecs/src/borrow.rs @@ -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> { diff --git a/crates/bevy_ui/src/entity.rs b/crates/bevy_ui/src/entity.rs index 603e4b79e4..62bc5f8c76 100644 --- a/crates/bevy_ui/src/entity.rs +++ b/crates/bevy_ui/src/entity.rs @@ -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(), } } } diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 7587012b42..cfdebab5ca 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -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::().unwrap(); diff --git a/crates/bevy_ui/src/node.rs b/crates/bevy_ui/src/node.rs index 75d6741b14..b465fe8e9b 100644 --- a/crates/bevy_ui/src/node.rs +++ b/crates/bevy_ui/src/node.rs @@ -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( diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index 6ef70d1661..52415e8548 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -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, - mut orphan_node_query: Query>, - mut node_query: Query<(Entity, &mut Node, &mut Translation)>, + mut orphan_node_query: Query>, + 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, ) -> Option { if let Ok(mut node) = node_query.get_mut::(entity) { - if let Ok(mut translation) = node_query.get_mut::(entity) { + if let Ok(mut local_transform) = node_query.get_mut::(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 }); } } diff --git a/crates/bevy_ui/src/widget/label.rs b/crates/bevy_ui/src/widget/label.rs deleted file mode 100644 index 9d868091a2..0000000000 --- a/crates/bevy_ui/src/widget/label.rs +++ /dev/null @@ -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, - pub style: TextStyle, -} - -impl Label { - pub fn label_system( - mut textures: ResMut>, - fonts: Res>, - mut font_atlas_sets: ResMut>, - mut texture_atlases: ResMut>, - 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>, - font_atlas_sets: Res>, - texture_atlases: Res>, - mut render_resource_bindings: ResMut, - mut asset_render_resource_bindings: ResMut, - 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::()) - .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(); - } - } -} diff --git a/crates/bevy_ui/src/widget/mod.rs b/crates/bevy_ui/src/widget/mod.rs index 48f9c41028..327695e195 100644 --- a/crates/bevy_ui/src/widget/mod.rs +++ b/crates/bevy_ui/src/widget/mod.rs @@ -1,5 +1,5 @@ mod button; -mod label; +mod text; pub use button::*; -pub use label::*; +pub use text::*; diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs new file mode 100644 index 0000000000..d4bb98dfab --- /dev/null +++ b/crates/bevy_ui/src/widget/text.rs @@ -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, + pub style: TextStyle, +} + +pub fn text_system( + mut textures: ResMut>, + fonts: Res>, + mut font_atlas_sets: ResMut>, + mut texture_atlases: ResMut>, + 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>, + font_atlas_sets: Res>, + texture_atlases: Res>, + mut render_resource_bindings: ResMut, + mut asset_render_resource_bindings: ResMut, + 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::()) + .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(); + } +} \ No newline at end of file diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index 222bef5250..cebee9b05e 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -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