mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
parent
c32c78fc66
commit
f574c2c547
15 changed files with 288 additions and 90 deletions
|
@ -102,6 +102,10 @@ path = "examples/2d/texture_atlas.rs"
|
||||||
name = "contributors"
|
name = "contributors"
|
||||||
path = "examples/2d/contributors.rs"
|
path = "examples/2d/contributors.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "text2d"
|
||||||
|
path = "examples/2d/text2d.rs"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "load_gltf"
|
name = "load_gltf"
|
||||||
path = "examples/3d/load_gltf.rs"
|
path = "examples/3d/load_gltf.rs"
|
||||||
|
|
|
@ -14,7 +14,7 @@ use bevy_reflect::{Reflect, ReflectComponent};
|
||||||
use bevy_window::WindowId;
|
use bevy_window::WindowId;
|
||||||
|
|
||||||
/// A component that indicates that an entity should be drawn in the "main pass"
|
/// A component that indicates that an entity should be drawn in the "main pass"
|
||||||
#[derive(Default, Reflect)]
|
#[derive(Clone, Debug, Default, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct MainPass;
|
pub struct MainPass;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub struct PassNode<Q: WorldQuery> {
|
||||||
|
|
||||||
impl<Q: WorldQuery> fmt::Debug for PassNode<Q> {
|
impl<Q: WorldQuery> fmt::Debug for PassNode<Q> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("PassNose")
|
f.debug_struct("PassNode")
|
||||||
.field("descriptor", &self.descriptor)
|
.field("descriptor", &self.descriptor)
|
||||||
.field("inputs", &self.inputs)
|
.field("inputs", &self.inputs)
|
||||||
.field("cameras", &self.cameras)
|
.field("cameras", &self.cameras)
|
||||||
|
|
|
@ -22,6 +22,7 @@ bevy_math = { path = "../bevy_math", version = "0.4.0" }
|
||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.4.0", features = ["bevy"] }
|
bevy_reflect = { path = "../bevy_reflect", version = "0.4.0", features = ["bevy"] }
|
||||||
bevy_render = { path = "../bevy_render", version = "0.4.0" }
|
bevy_render = { path = "../bevy_render", version = "0.4.0" }
|
||||||
bevy_sprite = { path = "../bevy_sprite", version = "0.4.0" }
|
bevy_sprite = { path = "../bevy_sprite", version = "0.4.0" }
|
||||||
|
bevy_transform = { path = "../bevy_transform", version = "0.4.0" }
|
||||||
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
|
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
|
||||||
|
|
||||||
# other
|
# other
|
||||||
|
|
|
@ -6,6 +6,8 @@ mod font_atlas_set;
|
||||||
mod font_loader;
|
mod font_loader;
|
||||||
mod glyph_brush;
|
mod glyph_brush;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
|
mod text;
|
||||||
|
mod text2d;
|
||||||
|
|
||||||
pub use draw::*;
|
pub use draw::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
|
@ -15,15 +17,17 @@ pub use font_atlas_set::*;
|
||||||
pub use font_loader::*;
|
pub use font_loader::*;
|
||||||
pub use glyph_brush::*;
|
pub use glyph_brush::*;
|
||||||
pub use pipeline::*;
|
pub use pipeline::*;
|
||||||
|
pub use text::*;
|
||||||
|
pub use text2d::*;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{Font, TextAlignment, TextError, TextStyle};
|
pub use crate::{Font, Text, Text2dBundle, TextAlignment, TextError, TextStyle};
|
||||||
pub use glyph_brush_layout::{HorizontalAlign, VerticalAlign};
|
pub use glyph_brush_layout::{HorizontalAlign, VerticalAlign};
|
||||||
}
|
}
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_asset::AddAsset;
|
use bevy_asset::AddAsset;
|
||||||
use bevy_ecs::Entity;
|
use bevy_ecs::{Entity, IntoSystem};
|
||||||
|
|
||||||
pub type DefaultTextPipeline = TextPipeline<Entity>;
|
pub type DefaultTextPipeline = TextPipeline<Entity>;
|
||||||
|
|
||||||
|
@ -35,6 +39,11 @@ impl Plugin for TextPlugin {
|
||||||
app.add_asset::<Font>()
|
app.add_asset::<Font>()
|
||||||
.add_asset::<FontAtlasSet>()
|
.add_asset::<FontAtlasSet>()
|
||||||
.init_asset_loader::<FontLoader>()
|
.init_asset_loader::<FontLoader>()
|
||||||
.add_resource(DefaultTextPipeline::default());
|
.add_resource(DefaultTextPipeline::default())
|
||||||
|
.add_system_to_stage(bevy_app::stage::POST_UPDATE, text2d_system.system())
|
||||||
|
.add_system_to_stage(
|
||||||
|
bevy_render::stage::DRAW,
|
||||||
|
text2d::draw_text2d_system.system(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
crates/bevy_text/src/text.rs
Normal file
16
crates/bevy_text/src/text.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use bevy_asset::Handle;
|
||||||
|
use bevy_math::Size;
|
||||||
|
|
||||||
|
use crate::{Font, TextStyle};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct Text {
|
||||||
|
pub value: String,
|
||||||
|
pub font: Handle<Font>,
|
||||||
|
pub style: TextStyle,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Copy, Clone, Debug)]
|
||||||
|
pub struct CalculatedSize {
|
||||||
|
pub size: Size,
|
||||||
|
}
|
172
crates/bevy_text/src/text2d.rs
Normal file
172
crates/bevy_text/src/text2d.rs
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
use bevy_asset::Assets;
|
||||||
|
use bevy_ecs::{Bundle, Changed, Entity, Local, Query, QuerySet, Res, ResMut, With};
|
||||||
|
use bevy_math::{Size, Vec3};
|
||||||
|
use bevy_render::{
|
||||||
|
draw::{DrawContext, Drawable},
|
||||||
|
mesh::Mesh,
|
||||||
|
prelude::{Draw, Msaa, Texture, Visible},
|
||||||
|
render_graph::base::MainPass,
|
||||||
|
renderer::RenderResourceBindings,
|
||||||
|
};
|
||||||
|
use bevy_sprite::{TextureAtlas, QUAD_HANDLE};
|
||||||
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
|
use glyph_brush_layout::{HorizontalAlign, VerticalAlign};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
CalculatedSize, DefaultTextPipeline, DrawableText, Font, FontAtlasSet, Text, TextError,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The bundle of components needed to draw text in a 2D scene via the Camera2dBundle.
|
||||||
|
#[derive(Bundle, Clone, Debug)]
|
||||||
|
pub struct Text2dBundle {
|
||||||
|
pub draw: Draw,
|
||||||
|
pub visible: Visible,
|
||||||
|
pub text: Text,
|
||||||
|
pub transform: Transform,
|
||||||
|
pub global_transform: GlobalTransform,
|
||||||
|
pub main_pass: MainPass,
|
||||||
|
pub calculated_size: CalculatedSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Text2dBundle {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
draw: Draw {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
visible: Visible {
|
||||||
|
is_transparent: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
text: Default::default(),
|
||||||
|
transform: Default::default(),
|
||||||
|
global_transform: Default::default(),
|
||||||
|
main_pass: MainPass {},
|
||||||
|
calculated_size: CalculatedSize {
|
||||||
|
size: Size::default(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// System for drawing text in a 2D scene via the Camera2dBundle. Included in the default
|
||||||
|
/// `TextPlugin`. Position is determined by the `Transform`'s translation, though scale and rotation
|
||||||
|
/// are ignored.
|
||||||
|
pub fn draw_text2d_system(
|
||||||
|
mut context: DrawContext,
|
||||||
|
msaa: Res<Msaa>,
|
||||||
|
meshes: Res<Assets<Mesh>>,
|
||||||
|
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
||||||
|
text_pipeline: Res<DefaultTextPipeline>,
|
||||||
|
mut query: Query<
|
||||||
|
(
|
||||||
|
Entity,
|
||||||
|
&mut Draw,
|
||||||
|
&Visible,
|
||||||
|
&Text,
|
||||||
|
&GlobalTransform,
|
||||||
|
&CalculatedSize,
|
||||||
|
),
|
||||||
|
With<MainPass>,
|
||||||
|
>,
|
||||||
|
) {
|
||||||
|
let font_quad = meshes.get(&QUAD_HANDLE).unwrap();
|
||||||
|
let vertex_buffer_descriptor = font_quad.get_vertex_buffer_descriptor();
|
||||||
|
|
||||||
|
for (entity, mut draw, visible, text, global_transform, calculated_size) in query.iter_mut() {
|
||||||
|
if !visible.is_visible {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (width, height) = (calculated_size.size.width, calculated_size.size.height);
|
||||||
|
|
||||||
|
if let Some(text_glyphs) = text_pipeline.get_glyphs(&entity) {
|
||||||
|
let position = global_transform.translation
|
||||||
|
+ match text.style.alignment.vertical {
|
||||||
|
VerticalAlign::Top => Vec3::zero(),
|
||||||
|
VerticalAlign::Center => Vec3::new(0.0, -height * 0.5, 0.0),
|
||||||
|
VerticalAlign::Bottom => Vec3::new(0.0, -height, 0.0),
|
||||||
|
}
|
||||||
|
+ match text.style.alignment.horizontal {
|
||||||
|
HorizontalAlign::Left => Vec3::new(-width, 0.0, 0.0),
|
||||||
|
HorizontalAlign::Center => Vec3::new(-width * 0.5, 0.0, 0.0),
|
||||||
|
HorizontalAlign::Right => Vec3::zero(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut drawable_text = DrawableText {
|
||||||
|
render_resource_bindings: &mut render_resource_bindings,
|
||||||
|
position,
|
||||||
|
msaa: &msaa,
|
||||||
|
text_glyphs: &text_glyphs.glyphs,
|
||||||
|
font_quad_vertex_descriptor: &vertex_buffer_descriptor,
|
||||||
|
style: &text.style,
|
||||||
|
};
|
||||||
|
|
||||||
|
drawable_text.draw(&mut draw, &mut context).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct QueuedText2d {
|
||||||
|
entities: Vec<Entity>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the TextGlyphs with the new computed glyphs from the layout
|
||||||
|
pub fn text2d_system(
|
||||||
|
mut queued_text: Local<QueuedText2d>,
|
||||||
|
mut textures: ResMut<Assets<Texture>>,
|
||||||
|
fonts: Res<Assets<Font>>,
|
||||||
|
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
||||||
|
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
|
||||||
|
mut text_pipeline: ResMut<DefaultTextPipeline>,
|
||||||
|
mut text_queries: QuerySet<(
|
||||||
|
Query<Entity, Changed<Text>>,
|
||||||
|
Query<(&Text, &mut CalculatedSize)>,
|
||||||
|
)>,
|
||||||
|
) {
|
||||||
|
// Adds all entities where the text or the style has changed to the local queue
|
||||||
|
for entity in text_queries.q0_mut().iter_mut() {
|
||||||
|
queued_text.entities.push(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if queued_text.entities.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes all text in the local queue
|
||||||
|
let mut new_queue = Vec::new();
|
||||||
|
let query = text_queries.q1_mut();
|
||||||
|
for entity in queued_text.entities.drain(..) {
|
||||||
|
if let Ok((text, mut calculated_size)) = query.get_mut(entity) {
|
||||||
|
match text_pipeline.queue_text(
|
||||||
|
entity,
|
||||||
|
text.font.clone(),
|
||||||
|
&fonts,
|
||||||
|
&text.value,
|
||||||
|
text.style.font_size,
|
||||||
|
text.style.alignment,
|
||||||
|
Size::new(f32::MAX, f32::MAX),
|
||||||
|
&mut *font_atlas_set_storage,
|
||||||
|
&mut *texture_atlases,
|
||||||
|
&mut *textures,
|
||||||
|
) {
|
||||||
|
Err(TextError::NoSuchFont) => {
|
||||||
|
// There was an error processing the text layout, let's add this entity to the queue for further processing
|
||||||
|
new_queue.push(entity);
|
||||||
|
}
|
||||||
|
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
||||||
|
panic!("Fatal error when processing text: {}.", e);
|
||||||
|
}
|
||||||
|
Ok(()) => {
|
||||||
|
let text_layout_info = text_pipeline.get_glyphs(&entity).expect(
|
||||||
|
"Failed to get glyphs from the pipeline that have just been computed",
|
||||||
|
);
|
||||||
|
calculated_size.size = text_layout_info.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queued_text.entities = new_queue;
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
use super::Node;
|
use super::Node;
|
||||||
use crate::{
|
use crate::{
|
||||||
render::UI_PIPELINE_HANDLE,
|
render::UI_PIPELINE_HANDLE,
|
||||||
widget::{Button, Image, Text},
|
widget::{Button, Image},
|
||||||
CalculatedSize, FocusPolicy, Interaction, Style,
|
FocusPolicy, Interaction, Style,
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_ecs::Bundle;
|
use bevy_ecs::Bundle;
|
||||||
|
@ -15,6 +15,7 @@ use bevy_render::{
|
||||||
prelude::Visible,
|
prelude::Visible,
|
||||||
};
|
};
|
||||||
use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
|
use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
|
||||||
|
use bevy_text::{CalculatedSize, Text};
|
||||||
use bevy_transform::prelude::{GlobalTransform, Transform};
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
|
|
||||||
#[derive(Bundle, Clone, Debug)]
|
#[derive(Bundle, Clone, Debug)]
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
mod convert;
|
mod convert;
|
||||||
|
|
||||||
use crate::{CalculatedSize, Node, Style};
|
use crate::{Node, Style};
|
||||||
use bevy_ecs::{Changed, Entity, Query, Res, ResMut, With, Without};
|
use bevy_ecs::{Changed, Entity, Query, Res, ResMut, With, Without};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
|
use bevy_text::CalculatedSize;
|
||||||
use bevy_transform::prelude::{Children, Parent, Transform};
|
use bevy_transform::prelude::{Children, Parent, Transform};
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use bevy_window::{Window, WindowId, Windows};
|
use bevy_window::{Window, WindowId, Windows};
|
||||||
|
|
|
@ -16,12 +16,7 @@ pub use node::*;
|
||||||
pub use render::*;
|
pub use render::*;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{entity::*, node::*, widget::Button, Anchors, Interaction, Margins};
|
||||||
entity::*,
|
|
||||||
node::*,
|
|
||||||
widget::{Button, Text},
|
|
||||||
Anchors, Interaction, Margins,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
|
|
|
@ -48,11 +48,6 @@ impl AddAssign<f32> for Val {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Copy, Clone, Debug)]
|
|
||||||
pub struct CalculatedSize {
|
|
||||||
pub size: Size,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Reflect)]
|
#[derive(Clone, PartialEq, Debug, Reflect)]
|
||||||
pub struct Style {
|
pub struct Style {
|
||||||
pub display: Display,
|
pub display: Display,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::CalculatedSize;
|
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_ecs::{Query, Res, With};
|
use bevy_ecs::{Query, Res, With};
|
||||||
use bevy_math::Size;
|
use bevy_math::Size;
|
||||||
use bevy_render::texture::Texture;
|
use bevy_render::texture::Texture;
|
||||||
use bevy_sprite::ColorMaterial;
|
use bevy_sprite::ColorMaterial;
|
||||||
|
use bevy_text::CalculatedSize;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Image {
|
pub enum Image {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{CalculatedSize, Node, Style, Val};
|
use crate::{Node, Style, Val};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::Assets;
|
||||||
use bevy_ecs::{Changed, Entity, Local, Or, Query, QuerySet, Res, ResMut};
|
use bevy_ecs::{Changed, Entity, Local, Or, Query, QuerySet, Res, ResMut};
|
||||||
use bevy_math::Size;
|
use bevy_math::Size;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
@ -10,7 +10,9 @@ use bevy_render::{
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
};
|
};
|
||||||
use bevy_sprite::{TextureAtlas, QUAD_HANDLE};
|
use bevy_sprite::{TextureAtlas, QUAD_HANDLE};
|
||||||
use bevy_text::{DefaultTextPipeline, DrawableText, Font, FontAtlasSet, TextError, TextStyle};
|
use bevy_text::{
|
||||||
|
CalculatedSize, DefaultTextPipeline, DrawableText, Font, FontAtlasSet, Text, TextError,
|
||||||
|
};
|
||||||
use bevy_transform::prelude::GlobalTransform;
|
use bevy_transform::prelude::GlobalTransform;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -18,13 +20,6 @@ pub struct QueuedText {
|
||||||
entities: Vec<Entity>,
|
entities: Vec<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
|
||||||
pub struct Text {
|
|
||||||
pub value: String,
|
|
||||||
pub font: Handle<Font>,
|
|
||||||
pub style: TextStyle,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines how min_size, size, and max_size affects the bounds of a text
|
/// Defines how min_size, size, and max_size affects the bounds of a text
|
||||||
/// block.
|
/// block.
|
||||||
pub fn text_constraint(min_size: Val, size: Val, max_size: Val) -> f32 {
|
pub fn text_constraint(min_size: Val, size: Val, max_size: Val) -> f32 {
|
||||||
|
@ -66,26 +61,40 @@ pub fn text_system(
|
||||||
let query = text_queries.q1_mut();
|
let query = text_queries.q1_mut();
|
||||||
for entity in queued_text.entities.drain(..) {
|
for entity in queued_text.entities.drain(..) {
|
||||||
if let Ok((text, style, mut calculated_size)) = query.get_mut(entity) {
|
if let Ok((text, style, mut calculated_size)) = query.get_mut(entity) {
|
||||||
match add_text_to_pipeline(
|
let node_size = Size::new(
|
||||||
|
text_constraint(style.min_size.width, style.size.width, style.max_size.width),
|
||||||
|
text_constraint(
|
||||||
|
style.min_size.height,
|
||||||
|
style.size.height,
|
||||||
|
style.max_size.height,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
match text_pipeline.queue_text(
|
||||||
entity,
|
entity,
|
||||||
&*text,
|
text.font.clone(),
|
||||||
&*style,
|
&fonts,
|
||||||
&mut *textures,
|
&text.value,
|
||||||
&*fonts,
|
text.style.font_size,
|
||||||
&mut *texture_atlases,
|
text.style.alignment,
|
||||||
|
node_size,
|
||||||
&mut *font_atlas_set_storage,
|
&mut *font_atlas_set_storage,
|
||||||
&mut *text_pipeline,
|
&mut *texture_atlases,
|
||||||
|
&mut *textures,
|
||||||
) {
|
) {
|
||||||
TextPipelineResult::Ok => {
|
Err(TextError::NoSuchFont) => {
|
||||||
|
// There was an error processing the text layout, let's add this entity to the queue for further processing
|
||||||
|
new_queue.push(entity);
|
||||||
|
}
|
||||||
|
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
||||||
|
panic!("Fatal error when processing text: {}.", e);
|
||||||
|
}
|
||||||
|
Ok(()) => {
|
||||||
let text_layout_info = text_pipeline.get_glyphs(&entity).expect(
|
let text_layout_info = text_pipeline.get_glyphs(&entity).expect(
|
||||||
"Failed to get glyphs from the pipeline that have just been computed",
|
"Failed to get glyphs from the pipeline that have just been computed",
|
||||||
);
|
);
|
||||||
calculated_size.size = text_layout_info.size;
|
calculated_size.size = text_layout_info.size;
|
||||||
}
|
}
|
||||||
TextPipelineResult::Reschedule => {
|
|
||||||
// There was an error processing the text layout, let's add this entity to the queue for further processing
|
|
||||||
new_queue.push(entity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,52 +102,6 @@ pub fn text_system(
|
||||||
queued_text.entities = new_queue;
|
queued_text.entities = new_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TextPipelineResult {
|
|
||||||
Ok,
|
|
||||||
Reschedule,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the text layout and stores it in the TextPipeline resource.
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn add_text_to_pipeline(
|
|
||||||
entity: Entity,
|
|
||||||
text: &Text,
|
|
||||||
style: &Style,
|
|
||||||
textures: &mut Assets<Texture>,
|
|
||||||
fonts: &Assets<Font>,
|
|
||||||
texture_atlases: &mut Assets<TextureAtlas>,
|
|
||||||
font_atlas_set_storage: &mut Assets<FontAtlasSet>,
|
|
||||||
text_pipeline: &mut DefaultTextPipeline,
|
|
||||||
) -> TextPipelineResult {
|
|
||||||
let node_size = Size::new(
|
|
||||||
text_constraint(style.min_size.width, style.size.width, style.max_size.width),
|
|
||||||
text_constraint(
|
|
||||||
style.min_size.height,
|
|
||||||
style.size.height,
|
|
||||||
style.max_size.height,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
match text_pipeline.queue_text(
|
|
||||||
entity,
|
|
||||||
text.font.clone(),
|
|
||||||
&fonts,
|
|
||||||
&text.value,
|
|
||||||
text.style.font_size,
|
|
||||||
text.style.alignment,
|
|
||||||
node_size,
|
|
||||||
font_atlas_set_storage,
|
|
||||||
texture_atlases,
|
|
||||||
textures,
|
|
||||||
) {
|
|
||||||
Err(TextError::NoSuchFont) => TextPipelineResult::Reschedule,
|
|
||||||
Err(e @ TextError::FailedToAddGlyph(_)) => {
|
|
||||||
panic!("Fatal error when processing text: {}.", e);
|
|
||||||
}
|
|
||||||
Ok(()) => TextPipelineResult::Ok,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn draw_text_system(
|
pub fn draw_text_system(
|
||||||
mut context: DrawContext,
|
mut context: DrawContext,
|
||||||
|
|
40
examples/2d/text2d.rs
Normal file
40
examples/2d/text2d.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::build()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_startup_system(setup.system())
|
||||||
|
.add_system(animate.system())
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
|
||||||
|
commands
|
||||||
|
// 2d camera
|
||||||
|
.spawn(Camera2dBundle::default())
|
||||||
|
.spawn(Text2dBundle {
|
||||||
|
text: Text {
|
||||||
|
value: "This text is in the 2D scene.".to_string(),
|
||||||
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
||||||
|
style: TextStyle {
|
||||||
|
font_size: 60.0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
alignment: TextAlignment {
|
||||||
|
vertical: VerticalAlign::Center,
|
||||||
|
horizontal: HorizontalAlign::Center,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn animate(time: Res<Time>, mut query: Query<&mut Transform, With<Text>>) {
|
||||||
|
// `Transform.translation` will determine the location of the text.
|
||||||
|
// `Transform.scale` and `Transform.rotation` do not yet affect text (though you can set the
|
||||||
|
// size of the text via `Text.style.font_size`)
|
||||||
|
for mut transform in query.iter_mut() {
|
||||||
|
transform.translation.x = 100.0 * time.seconds_since_startup().sin() as f32;
|
||||||
|
transform.translation.y = 100.0 * time.seconds_since_startup().cos() as f32;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,8 @@ use bevy::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This example illustrates how to create text and update it in a system. It displays the current FPS in the upper left hand corner.
|
/// This example illustrates how to create UI text and update it in a system. It displays the
|
||||||
|
/// current FPS in the upper left hand corner. For text within a scene, please see the text2d example.
|
||||||
fn main() {
|
fn main() {
|
||||||
App::build()
|
App::build()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
|
@ -28,7 +29,7 @@ fn text_update_system(diagnostics: Res<Diagnostics>, mut query: Query<&mut Text,
|
||||||
|
|
||||||
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
|
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
|
||||||
commands
|
commands
|
||||||
// 2d camera
|
// UI camera
|
||||||
.spawn(CameraUiBundle::default())
|
.spawn(CameraUiBundle::default())
|
||||||
// texture
|
// texture
|
||||||
.spawn(TextBundle {
|
.spawn(TextBundle {
|
||||||
|
|
Loading…
Reference in a new issue