diff --git a/crates/bevy_math/src/geometry.rs b/crates/bevy_math/src/geometry.rs index 27a0073c1c..96ebedd7dd 100644 --- a/crates/bevy_math/src/geometry.rs +++ b/crates/bevy_math/src/geometry.rs @@ -1,6 +1,6 @@ use bevy_reflect::Reflect; use glam::Vec2; -use std::ops::{Add, AddAssign}; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; /// A two dimensional "size" as defined by a width and height #[derive(Copy, Clone, PartialEq, Debug, Reflect)] @@ -81,3 +81,102 @@ where self.height += rhs.y; } } + +impl Sub for Size +where + T: Sub, +{ + type Output = Size; + + fn sub(self, rhs: Vec2) -> Self::Output { + Self { + width: self.width - rhs.x, + height: self.height - rhs.y, + } + } +} + +impl SubAssign for Size +where + T: SubAssign, +{ + fn sub_assign(&mut self, rhs: Vec2) { + self.width -= rhs.x; + self.height -= rhs.y; + } +} + +impl Mul for Size +where + T: Mul, +{ + type Output = Size; + + fn mul(self, rhs: f32) -> Self::Output { + Self::Output { + width: self.width * rhs, + height: self.height * rhs, + } + } +} + +impl MulAssign for Size +where + T: MulAssign, +{ + fn mul_assign(&mut self, rhs: f32) { + self.width *= rhs; + self.height *= rhs; + } +} + +impl Div for Size +where + T: Div, +{ + type Output = Size; + + fn div(self, rhs: f32) -> Self::Output { + Self::Output { + width: self.width / rhs, + height: self.height / rhs, + } + } +} + +impl DivAssign for Size +where + T: DivAssign, +{ + fn div_assign(&mut self, rhs: f32) { + self.width /= rhs; + self.height /= rhs; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn size_ops() { + type SizeF = Size; + + assert_eq!( + SizeF::new(10., 10.) + Vec2::new(10., 10.), + SizeF::new(20., 20.) + ); + assert_eq!( + SizeF::new(20., 20.) - Vec2::new(10., 10.), + SizeF::new(10., 10.) + ); + assert_eq!(SizeF::new(10., 10.) * 2., SizeF::new(20., 20.)); + assert_eq!(SizeF::new(20., 20.) / 2., SizeF::new(10., 10.)); + + let mut size = SizeF::new(10., 10.); + + size += Vec2::new(10., 10.); + + assert_eq!(size, SizeF::new(20., 20.)); + } +} diff --git a/crates/bevy_text/src/draw.rs b/crates/bevy_text/src/draw.rs index c92aa889d2..e516f4890d 100644 --- a/crates/bevy_text/src/draw.rs +++ b/crates/bevy_text/src/draw.rs @@ -48,6 +48,7 @@ impl Default for TextStyle { pub struct DrawableText<'a> { pub render_resource_bindings: &'a mut RenderResourceBindings, pub position: Vec3, + pub scale_factor: f32, pub style: &'a TextStyle, pub text_glyphs: &'a Vec, pub msaa: &'a Msaa, @@ -105,7 +106,20 @@ impl<'a> Drawable for DrawableText<'a> { color: self.style.color, }; - let transform = Mat4::from_translation(self.position + tv.position.extend(0.)); + // To get the rendering right for non-one scaling factors, we need + // the sprite to be drawn in "physical" coordinates. This is because + // the shader uses the size of the sprite to control the size on + // screen. To accomplish this we make the sprite transform + // convert from physical coordinates to logical coordinates in + // addition to altering the origin. Since individual glyphs will + // already be in physical coordinates, we just need to convert the + // overall position to physical coordinates to get the sprites + // physical position. + + let transform = Mat4::from_scale(Vec3::splat(1. / self.scale_factor)) + * Mat4::from_translation( + self.position * self.scale_factor + tv.position.extend(0.), + ); let transform_buffer = context.get_uniform_buffer(&transform).unwrap(); let sprite_buffer = context.get_uniform_buffer(&sprite).unwrap(); diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index c0e6bb4177..f9ce25aab7 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -99,6 +99,7 @@ pub fn draw_text2d_system( msaa: &msaa, text_glyphs: &text_glyphs.glyphs, font_quad_vertex_descriptor: &vertex_buffer_descriptor, + scale_factor: 1., style: &text.style, }; @@ -121,8 +122,8 @@ pub fn text2d_system( mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, mut text_queries: QuerySet<( - Query>, - Query<(&Text, &mut CalculatedSize)>, + Query, Changed)>, + Query<(&Text, &mut CalculatedSize), With>, )>, ) { // Adds all entities where the text or the style has changed to the local queue diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 392aff801b..cf9cb2a52d 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -14,31 +14,38 @@ use bevy_text::{ CalculatedSize, DefaultTextPipeline, DrawableText, Font, FontAtlasSet, Text, TextError, }; use bevy_transform::prelude::GlobalTransform; +use bevy_window::Windows; #[derive(Debug, Default)] pub struct QueuedText { entities: Vec, } +fn scale_value(value: f32, factor: f64) -> f32 { + (value as f64 * factor) as f32 +} + /// Defines how min_size, size, and max_size affects the bounds of a text /// 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, scale_factor: f64) -> f32 { // Needs support for percentages match (min_size, size, max_size) { - (_, _, Val::Px(max)) => max, - (Val::Px(min), _, _) => min, - (Val::Undefined, Val::Px(size), Val::Undefined) => size, - (Val::Auto, Val::Px(size), Val::Auto) => size, + (_, _, Val::Px(max)) => scale_value(max, scale_factor), + (Val::Px(min), _, _) => scale_value(min, scale_factor), + (Val::Undefined, Val::Px(size), Val::Undefined) => scale_value(size, scale_factor), + (Val::Auto, Val::Px(size), Val::Auto) => scale_value(size, scale_factor), _ => f32::MAX, } } /// Computes the size of a text block and updates the TextGlyphs with the /// new computed glyphs from the layout +#[allow(clippy::too_many_arguments)] pub fn text_system( mut queued_text: Local, mut textures: ResMut>, fonts: Res>, + windows: Res, mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, @@ -47,6 +54,14 @@ pub fn text_system( Query<(&Text, &Style, &mut CalculatedSize)>, )>, ) { + let scale_factor = if let Some(window) = windows.get_primary() { + window.scale_factor() + } else { + 1. + }; + + let inv_scale_factor = 1. / scale_factor; + // 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); @@ -62,11 +77,17 @@ pub fn text_system( for entity in queued_text.entities.drain(..) { if let Ok((text, style, mut calculated_size)) = query.get_mut(entity) { let node_size = Size::new( - text_constraint(style.min_size.width, style.size.width, style.max_size.width), + text_constraint( + style.min_size.width, + style.size.width, + style.max_size.width, + scale_factor, + ), text_constraint( style.min_size.height, style.size.height, style.max_size.height, + scale_factor, ), ); @@ -75,7 +96,7 @@ pub fn text_system( text.font.clone(), &fonts, &text.value, - text.style.font_size, + scale_value(text.style.font_size, scale_factor), text.style.alignment, node_size, &mut *font_atlas_set_storage, @@ -93,7 +114,10 @@ pub fn text_system( 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; + calculated_size.size = Size { + width: scale_value(text_layout_info.size.width, inv_scale_factor), + height: scale_value(text_layout_info.size.height, inv_scale_factor), + }; } } } @@ -106,11 +130,18 @@ pub fn text_system( pub fn draw_text_system( mut context: DrawContext, msaa: Res, + windows: Res, meshes: Res>, mut render_resource_bindings: ResMut, text_pipeline: Res, mut query: Query<(Entity, &mut Draw, &Visible, &Text, &Node, &GlobalTransform)>, ) { + let scale_factor = if let Some(window) = windows.get_primary() { + window.scale_factor() + } else { + 1. + }; + let font_quad = meshes.get(&QUAD_HANDLE).unwrap(); let vertex_buffer_descriptor = font_quad.get_vertex_buffer_descriptor(); @@ -125,6 +156,7 @@ pub fn draw_text_system( let mut drawable_text = DrawableText { render_resource_bindings: &mut render_resource_bindings, position, + scale_factor: scale_factor as f32, msaa: &msaa, text_glyphs: &text_glyphs.glyphs, font_quad_vertex_descriptor: &vertex_buffer_descriptor,