diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 9433de2f01..3922d2d649 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -84,6 +84,10 @@ impl Assets { self.assets.get_mut(&handle.id) } + pub fn get_or_insert_with(&mut self, handle: Handle, insert_fn: impl FnOnce() -> T) -> &mut T { + self.assets.entry(handle.id).or_insert_with(insert_fn) + } + pub fn iter(&self) -> impl Iterator, &T)> { self.assets.iter().map(|(k, v)| (Handle::from_id(*k), v)) } diff --git a/crates/bevy_render/src/color.rs b/crates/bevy_render/src/color.rs index 183a79caac..4f180f6842 100644 --- a/crates/bevy_render/src/color.rs +++ b/crates/bevy_render/src/color.rs @@ -7,7 +7,7 @@ use std::ops::{Add, AddAssign}; use zerocopy::AsBytes; #[repr(C)] -#[derive(Debug, Default, Clone, Copy, PartialEq, AsBytes)] +#[derive(Debug, Clone, Copy, PartialEq, AsBytes)] pub struct Color { pub r: f32, pub g: f32, @@ -31,6 +31,12 @@ impl Color { } } +impl Default for Color { + fn default() -> Self { + Color::WHITE + } +} + impl AddAssign for Color { fn add_assign(&mut self, rhs: Color) { *self = Color { diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index d02dc96775..8761e346cb 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -9,6 +9,7 @@ bevy_app = { path = "../bevy_app" } bevy_asset = { path = "../bevy_asset" } bevy_core = { path = "../bevy_core" } bevy_derive = { path = "../bevy_derive" } +bevy_text = { path = "../bevy_text" } bevy_transform = { path = "../bevy_transform" } bevy_render = { path = "../bevy_render" } bevy_window = { path = "../bevy_window" } diff --git a/crates/bevy_ui/src/entity.rs b/crates/bevy_ui/src/entity.rs index 035e8e23be..7b4459ac07 100644 --- a/crates/bevy_ui/src/entity.rs +++ b/crates/bevy_ui/src/entity.rs @@ -1,5 +1,7 @@ use super::Node; -use crate::{render::UI_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Rect, QUAD_HANDLE}; +use crate::{ + render::UI_PIPELINE_HANDLE, sprite::Sprite, widget::Label, ColorMaterial, Rect, QUAD_HANDLE, +}; use bevy_asset::Handle; use bevy_derive::EntityArchetype; use bevy_render::{mesh::Mesh, Renderable}; @@ -29,6 +31,34 @@ impl Default for UiEntity { } } +#[derive(EntityArchetype)] +#[module(meta = false)] +pub struct LabelEntity { + pub node: Node, + pub rect: Rect, + pub mesh: Handle, // TODO: maybe abstract this out + pub material: Handle, + pub renderable: Renderable, + pub label: Label, +} + +impl Default for LabelEntity { + fn default() -> Self { + LabelEntity { + node: Default::default(), + rect: Default::default(), + mesh: QUAD_HANDLE, + // NOTE: labels each get their own material. + material: Handle::new(), // TODO: maybe abstract this out + renderable: Renderable { + pipelines: vec![UI_PIPELINE_HANDLE], + ..Default::default() + }, + label: Label::default(), + } + } +} + #[derive(EntityArchetype)] #[module(meta = false)] pub struct SpriteEntity { diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 52eba32964..ea5dfa587e 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -1,6 +1,7 @@ mod anchors; mod color_material; pub mod entity; +pub mod widget; mod margins; mod node; mod rect; @@ -27,6 +28,7 @@ use bevy_render::{ use glam::Vec2; use legion::prelude::IntoSystem; use sprite::sprite_system; +use widget::Label; #[derive(Default)] pub struct UiPlugin; @@ -36,12 +38,13 @@ pub const QUAD_HANDLE: Handle = Handle::from_u128(142404619811301375266013 impl AppPlugin for UiPlugin { fn build(&self, app: &mut AppBuilder) { app.add_asset::() + .add_system_to_stage(stage::POST_UPDATE, sprite_system()) + .add_system_to_stage(stage::POST_UPDATE, ui_update_system()) + .add_system_to_stage(stage::POST_UPDATE, Label::label_system.system()) .add_system_to_stage( stage::POST_UPDATE, asset_shader_def_system::.system(), - ) - .add_system_to_stage(stage::POST_UPDATE, sprite_system()) - .add_system_to_stage(stage::POST_UPDATE, ui_update_system()); + ); let resources = app.resources(); let mut render_graph = resources.get_mut::().unwrap(); diff --git a/crates/bevy_ui/src/widget/label.rs b/crates/bevy_ui/src/widget/label.rs new file mode 100644 index 0000000000..586a355338 --- /dev/null +++ b/crates/bevy_ui/src/widget/label.rs @@ -0,0 +1,51 @@ +use crate::{ColorMaterial, Rect, Res, ResMut}; +use bevy_asset::{Assets, Handle}; +use bevy_render::{texture::Texture, Color}; +use bevy_text::Font; +use legion::prelude::Com; + +pub struct Label { + pub text: String, + pub color: Color, + pub font_size: f32, + pub font: Handle, +} + +impl Default for Label { + fn default() -> Self { + Label { + text: String::new(), + color: Color::WHITE, + font_size: 12.0, + font: Handle::default(), + } + } +} + +impl Label { + // PERF: this is horrendously inefficient. (1) new texture every frame (2) no atlas (3) new texture for every label + pub fn label_system( + mut color_materials: ResMut>, + mut textures: ResMut>, + fonts: Res>, + label: Com