bevy/crates/bevy_text/src/pipeline.rs
Rob Parrett d1528dfbf8 Warn instead of erroring when max_font_atlases is exceeded (#6673)
# Objective

Fixes #6642

In a way that doesn't create any breaking changes, as a possible way to fix the above in a patch release.

## Solution

Don't actually remove font atlases when `max_font_atlases` is exceeded. Add a warning instead.

Keep `TextError::ExceedMaxTextAtlases` and `TextSettings` as-is so we don't break anything.

This is a bit of a cop-out, but the problems revealed by #6642 seem very challenging to fix properly.

Maybe follow up later with something more like https://github.com/rparrett/bevy/commits/remove-max-font-atlases later, if this is the direction we want to go.

## Note

See previous attempt at a "simple fix" that only solved some of the issues: #6666
2022-11-25 23:49:25 +00:00

117 lines
3.7 KiB
Rust

use ab_glyph::{PxScale, ScaleFont};
use bevy_asset::{Assets, Handle, HandleId};
use bevy_ecs::component::Component;
use bevy_ecs::system::Resource;
use bevy_math::Vec2;
use bevy_render::texture::Image;
use bevy_sprite::TextureAtlas;
use bevy_utils::HashMap;
use glyph_brush_layout::{FontId, SectionText};
use crate::{
error::TextError, glyph_brush::GlyphBrush, scale_value, Font, FontAtlasSet, FontAtlasWarning,
PositionedGlyph, TextAlignment, TextSection, TextSettings, YAxisOrientation,
};
#[derive(Default, Resource)]
pub struct TextPipeline {
brush: GlyphBrush,
map_font_id: HashMap<HandleId, FontId>,
}
/// Render information for a corresponding [`Text`](crate::Text) component.
///
/// Contains scaled glyphs and their size. Generated via [`TextPipeline::queue_text`].
#[derive(Component, Clone, Default, Debug)]
pub struct TextLayoutInfo {
pub glyphs: Vec<PositionedGlyph>,
pub size: Vec2,
}
impl TextPipeline {
pub fn get_or_insert_font_id(&mut self, handle: &Handle<Font>, font: &Font) -> FontId {
let brush = &mut self.brush;
*self
.map_font_id
.entry(handle.id())
.or_insert_with(|| brush.add_font(handle.clone(), font.font.clone()))
}
#[allow(clippy::too_many_arguments)]
pub fn queue_text(
&mut self,
fonts: &Assets<Font>,
sections: &[TextSection],
scale_factor: f64,
text_alignment: TextAlignment,
bounds: Vec2,
font_atlas_set_storage: &mut Assets<FontAtlasSet>,
texture_atlases: &mut Assets<TextureAtlas>,
textures: &mut Assets<Image>,
text_settings: &TextSettings,
font_atlas_warning: &mut FontAtlasWarning,
y_axis_orientation: YAxisOrientation,
) -> Result<TextLayoutInfo, TextError> {
let mut scaled_fonts = Vec::new();
let sections = sections
.iter()
.map(|section| {
let font = fonts
.get(&section.style.font)
.ok_or(TextError::NoSuchFont)?;
let font_id = self.get_or_insert_font_id(&section.style.font, font);
let font_size = scale_value(section.style.font_size, scale_factor);
scaled_fonts.push(ab_glyph::Font::as_scaled(&font.font, font_size));
let section = SectionText {
font_id,
scale: PxScale::from(font_size),
text: &section.value,
};
Ok(section)
})
.collect::<Result<Vec<_>, _>>()?;
let section_glyphs = self
.brush
.compute_glyphs(&sections, bounds, text_alignment)?;
if section_glyphs.is_empty() {
return Ok(TextLayoutInfo::default());
}
let mut min_x: f32 = std::f32::MAX;
let mut min_y: f32 = std::f32::MAX;
let mut max_x: f32 = std::f32::MIN;
let mut max_y: f32 = std::f32::MIN;
for sg in &section_glyphs {
let scaled_font = scaled_fonts[sg.section_index];
let glyph = &sg.glyph;
min_x = min_x.min(glyph.position.x);
min_y = min_y.min(glyph.position.y - scaled_font.ascent());
max_x = max_x.max(glyph.position.x + scaled_font.h_advance(glyph.id));
max_y = max_y.max(glyph.position.y - scaled_font.descent());
}
let size = Vec2::new(max_x - min_x, max_y - min_y);
let glyphs = self.brush.process_glyphs(
section_glyphs,
&sections,
font_atlas_set_storage,
fonts,
texture_atlases,
textures,
text_settings,
font_atlas_warning,
y_axis_orientation,
)?;
Ok(TextLayoutInfo { glyphs, size })
}
}