Skip to content

Commit d4d3501

Browse files
dzhou121Zoxc
authored andcommitted
Add support for atlas cached images
1 parent f12f4b6 commit d4d3501

File tree

6 files changed

+257
-62
lines changed

6 files changed

+257
-62
lines changed

src/atlas.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ struct ImageData {
77
data: Vec<u8>,
88
}
99

10+
pub enum AtlasContent {
11+
Mask,
12+
Color,
13+
}
14+
1015
pub struct Atlas {
1116
packer: Packer,
1217
new_data: Vec<ImageData>,
1318
pub atlas_texture: wgpu::Texture,
1419
area_used: i32,
1520
did_clear: bool,
21+
content: AtlasContent,
1622
}
1723

1824
impl Atlas {
@@ -50,15 +56,37 @@ impl Atlas {
5056
}
5157
}
5258

53-
pub fn new(device: &wgpu::Device) -> Self {
54-
let atlas_texture = device.create_texture(&Self::get_texture_desc());
59+
pub fn new(device: &wgpu::Device, content: AtlasContent) -> Self {
60+
let texture_size = wgpu::Extent3d {
61+
width: Atlas::ATLAS_SIZE,
62+
height: Atlas::ATLAS_SIZE,
63+
depth_or_array_layers: 1,
64+
};
65+
let format = match content {
66+
AtlasContent::Mask => wgpu::TextureFormat::R8Unorm,
67+
AtlasContent::Color => wgpu::TextureFormat::Rgba8Unorm,
68+
};
69+
let desc = wgpu::TextureDescriptor {
70+
size: texture_size,
71+
mip_level_count: 1,
72+
sample_count: 1,
73+
dimension: wgpu::TextureDimension::D2,
74+
format,
75+
usage: wgpu::TextureUsages::COPY_SRC
76+
| wgpu::TextureUsages::COPY_DST
77+
| wgpu::TextureUsages::TEXTURE_BINDING,
78+
label: Some("atlas_texture"),
79+
view_formats: &[format],
80+
};
81+
let atlas_texture = device.create_texture(&desc);
5582

5683
Self {
5784
packer: Packer::new(Atlas::get_packer_config()),
5885
new_data: vec![],
5986
atlas_texture,
6087
area_used: 0,
6188
did_clear: false,
89+
content,
6290
}
6391
}
6492

@@ -78,10 +106,15 @@ impl Atlas {
78106
}
79107

80108
pub fn update(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder) {
109+
let pixels = match self.content {
110+
AtlasContent::Mask => 1,
111+
AtlasContent::Color => 4,
112+
};
113+
81114
if self.did_clear {
82115
// encoder.clear_texture(&self.atlas_texture, &wgpu::ImageSubresourceRange::default());
83116

84-
let sz = Atlas::ATLAS_SIZE as usize;
117+
let sz = Atlas::ATLAS_SIZE as usize * pixels;
85118

86119
let data = vec![0_u8; sz * sz];
87120

@@ -121,14 +154,15 @@ impl Atlas {
121154
for data in &self.new_data {
122155
// Pad data to wgpu::COPY_BYTES_PER_ROW_ALIGNMENT
123156
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as i32;
124-
let padding = (align - data.rect.width % align) % align;
125-
let padded_width = data.rect.width + padding;
157+
let width = data.rect.width * pixels as i32;
158+
let padding = (align - width % align) % align;
159+
let padded_width = width + padding;
126160
let mut padded_data = vec![];
127161
padded_data.reserve((padded_width * data.rect.height) as usize);
128162

129163
let mut i = 0;
130164
for _ in 0..data.rect.height {
131-
for _ in 0..data.rect.width {
165+
for _ in 0..width {
132166
padded_data.push(data.data[i]);
133167
i += 1;
134168
}

src/glyphs.rs

Lines changed: 92 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,110 @@
1-
use crate::atlas::Atlas;
1+
use crate::atlas::{Atlas, AtlasContent};
22
use rect_packer::Rect;
3-
use std::collections::HashMap;
3+
use std::{
4+
collections::HashMap,
5+
hash::{Hash, Hasher},
6+
sync::Arc,
7+
};
48

59
#[derive(Copy, Clone, Debug)]
610
pub struct GlyphInfo {
711
pub rect: Option<Rect>,
812
pub metrics: fontdue::Metrics,
913
}
1014

11-
pub struct GlyphCache {
12-
pub atlas: Atlas,
15+
#[derive(Clone, Eq)]
16+
pub struct ImageId {
17+
id: Arc<bool>,
18+
}
19+
20+
impl ImageId {
21+
pub fn new() -> Self {
22+
Self {
23+
id: Arc::new(false),
24+
}
25+
}
26+
}
27+
28+
impl PartialEq for ImageId {
29+
fn eq(&self, other: &Self) -> bool {
30+
Arc::ptr_eq(&self.id, &other.id)
31+
}
32+
}
33+
34+
impl Hash for ImageId {
35+
fn hash<H>(&self, state: &mut H)
36+
where
37+
H: Hasher,
38+
{
39+
(Arc::as_ptr(&self.id) as usize).hash(state)
40+
}
41+
}
42+
43+
#[derive(Copy, Clone, Debug)]
44+
pub struct AtlasImage {
45+
pub rect: Option<Rect>,
46+
}
47+
48+
pub struct AtlasCache {
49+
pub mask_atlas: Atlas,
50+
pub color_atlas: Atlas,
1351
pub font: fontdue::Font,
14-
info: HashMap<(char, u32), GlyphInfo>,
52+
glyphs: HashMap<(char, u32), GlyphInfo>,
53+
mask_images: HashMap<ImageId, AtlasImage>,
54+
color_images: HashMap<ImageId, AtlasImage>,
1555
}
1656

17-
impl GlyphCache {
57+
impl AtlasCache {
1858
pub fn new(device: &wgpu::Device) -> Self {
1959
let mut settings = fontdue::FontSettings::default();
2060
settings.collection_index = 0;
2161
settings.scale = 100.0;
2262
let font = include_bytes!("fonts/Anodina-Regular.ttf") as &[u8];
2363

2464
Self {
25-
atlas: Atlas::new(device),
65+
mask_atlas: Atlas::new(device, AtlasContent::Mask),
66+
color_atlas: Atlas::new(device, AtlasContent::Color),
2667
font: fontdue::Font::from_bytes(font, settings).unwrap(),
27-
info: HashMap::new(),
68+
glyphs: HashMap::new(),
69+
mask_images: HashMap::new(),
70+
color_images: HashMap::new(),
2871
}
2972
}
3073

74+
pub fn get_mask_image(
75+
&mut self,
76+
id: ImageId,
77+
width: u32,
78+
height: u32,
79+
image: impl FnOnce() -> Vec<u8>,
80+
) -> AtlasImage {
81+
let mask_atlas = &mut self.mask_atlas;
82+
*self.mask_images.entry(id).or_insert_with(|| AtlasImage {
83+
rect: mask_atlas.add_region(&image(), width, height),
84+
})
85+
}
86+
87+
pub fn get_color_image(
88+
&mut self,
89+
id: ImageId,
90+
width: u32,
91+
height: u32,
92+
image: impl FnOnce() -> Vec<u8>,
93+
) -> AtlasImage {
94+
let color_atlas = &mut self.color_atlas;
95+
*self.color_images.entry(id).or_insert_with(|| AtlasImage {
96+
rect: color_atlas.add_region(&image(), width, height),
97+
})
98+
}
99+
31100
pub fn get_glyph(&mut self, c: char, size: f32) -> GlyphInfo {
32101
let factor = 65536.0;
33102

34103
// Convert size to fixed point so we can hash it.
35104
let size_fixed_point = (size * factor) as u32;
36105

37106
// Do we already have a glyph?
38-
match self.info.get(&(c, size_fixed_point)) {
107+
match self.glyphs.get(&(c, size_fixed_point)) {
39108
Some(info) => *info,
40109
None => {
41110
let (metrics, data) = self.font.rasterize(c, size_fixed_point as f32 / factor);
@@ -52,31 +121,31 @@ impl GlyphCache {
52121
*/
53122

54123
let rect =
55-
self.atlas
124+
self.mask_atlas
56125
.add_region(&data, metrics.width as u32, metrics.height as u32);
57126

58127
let info = GlyphInfo { rect, metrics };
59128

60-
self.info.insert((c, size_fixed_point), info);
129+
self.glyphs.insert((c, size_fixed_point), info);
61130
info
62131
}
63132
}
64133
}
65134

66135
pub fn update(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder) {
67-
self.atlas.update(device, encoder);
136+
self.mask_atlas.update(device, encoder);
137+
self.color_atlas.update(device, encoder);
68138
}
69139

70-
pub fn create_view(&self) -> wgpu::TextureView {
71-
self.atlas.create_view()
72-
}
73-
74-
pub fn usage(&self) -> f32 {
75-
self.atlas.usage()
76-
}
77-
78-
pub fn clear(&mut self) {
79-
self.info.clear();
80-
self.atlas.clear();
140+
pub fn check_usage(&mut self) {
141+
if self.mask_atlas.usage() > 0.7 {
142+
self.glyphs.clear();
143+
self.mask_atlas.clear();
144+
self.mask_images.clear();
145+
}
146+
if self.color_atlas.usage() > 0.7 {
147+
self.color_atlas.clear();
148+
self.color_images.clear();
149+
}
81150
}
82151
}

0 commit comments

Comments
 (0)