1use bevy_asset::{Assets, Handle, RenderAssetUsages};
2use bevy_image::{prelude::*, ImageSampler, ToExtents};
3use bevy_math::{IVec2, UVec2};
4use bevy_platform::collections::HashMap;
5use wgpu_types::{TextureDimension, TextureFormat};
6
7use crate::{FontSmoothing, GlyphAtlasLocation, TextError};
8
9pub struct FontAtlas {
22 pub dynamic_texture_atlas_builder: DynamicTextureAtlasBuilder,
24 pub glyph_to_atlas_index: HashMap<cosmic_text::CacheKey, GlyphAtlasLocation>,
26 pub texture_atlas: Handle<TextureAtlasLayout>,
28 pub texture: Handle<Image>,
30}
31
32impl FontAtlas {
33 pub fn new(
35 textures: &mut Assets<Image>,
36 texture_atlases_layout: &mut Assets<TextureAtlasLayout>,
37 size: UVec2,
38 font_smoothing: FontSmoothing,
39 ) -> FontAtlas {
40 let mut image = Image::new_fill(
41 size.to_extents(),
42 TextureDimension::D2,
43 &[0, 0, 0, 0],
44 TextureFormat::Rgba8UnormSrgb,
45 RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD,
47 );
48 if font_smoothing == FontSmoothing::None {
49 image.sampler = ImageSampler::nearest();
50 }
51 let texture = textures.add(image);
52 let texture_atlas = texture_atlases_layout.add(TextureAtlasLayout::new_empty(size));
53 Self {
54 texture_atlas,
55 glyph_to_atlas_index: HashMap::default(),
56 dynamic_texture_atlas_builder: DynamicTextureAtlasBuilder::new(size, 1),
57 texture,
58 }
59 }
60
61 pub fn get_glyph_index(&self, cache_key: cosmic_text::CacheKey) -> Option<GlyphAtlasLocation> {
63 self.glyph_to_atlas_index.get(&cache_key).copied()
64 }
65
66 pub fn has_glyph(&self, cache_key: cosmic_text::CacheKey) -> bool {
68 self.glyph_to_atlas_index.contains_key(&cache_key)
69 }
70
71 pub fn add_glyph(
83 &mut self,
84 textures: &mut Assets<Image>,
85 atlas_layouts: &mut Assets<TextureAtlasLayout>,
86 cache_key: cosmic_text::CacheKey,
87 texture: &Image,
88 offset: IVec2,
89 ) -> Result<(), TextError> {
90 let atlas_layout = atlas_layouts.get_mut(&self.texture_atlas).unwrap();
91 let atlas_texture = textures.get_mut(&self.texture).unwrap();
92
93 if let Ok(glyph_index) =
94 self.dynamic_texture_atlas_builder
95 .add_texture(atlas_layout, texture, atlas_texture)
96 {
97 self.glyph_to_atlas_index.insert(
98 cache_key,
99 GlyphAtlasLocation {
100 glyph_index,
101 offset,
102 },
103 );
104 Ok(())
105 } else {
106 Err(TextError::FailedToAddGlyph(cache_key.glyph_id))
107 }
108 }
109}
110
111impl core::fmt::Debug for FontAtlas {
112 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113 f.debug_struct("FontAtlas")
114 .field("glyph_to_atlas_index", &self.glyph_to_atlas_index)
115 .field("texture_atlas", &self.texture_atlas)
116 .field("texture", &self.texture)
117 .field("dynamic_texture_atlas_builder", &"[...]")
118 .finish()
119 }
120}