better text rendering

This commit is contained in:
2025-11-18 01:05:51 -05:00
parent bc829397c8
commit 6b7719539e

View File

@@ -1,4 +1,6 @@
use cosmic_text::{Attrs, AttrsList, Buffer, Family, FontSystem, Metrics, SwashCache};
use cosmic_text::{
Attrs, AttrsList, Buffer, Family, FontSystem, Metrics, SwashCache, SwashContent,
};
use image::{Rgba, RgbaImage};
use crate::{
@@ -79,7 +81,7 @@ impl TextData {
// should probably do texture packing and things if possible.
// very visible if you add just a couple of wrapping texts and resize window
// should also be timed to figure out exactly what points need to be sped up
let mut pixels = HashMap::default();
let mut pixels = HashMap::<_, [u8; 4]>::default();
let mut min_x = 0;
let mut min_y = 0;
let mut max_x = 0;
@@ -99,20 +101,46 @@ impl TextData {
None => cosmic_color,
};
self.swash_cache.with_pixels(
&mut self.font_system,
physical_glyph.cache_key,
glyph_color,
|x, y, color| {
let x = physical_glyph.x + x;
let y = run.line_y as i32 + physical_glyph.y + y;
min_x = min_x.min(x);
min_y = min_y.min(y);
max_x = max_x.max(x);
max_y = max_y.max(y);
pixels.insert((x, y), Rgba(color.as_rgba()));
},
);
if let Some(img) = self
.swash_cache
.get_image(&mut self.font_system, physical_glyph.cache_key)
{
let mut pos = img.placement;
pos.left += physical_glyph.x;
pos.top = physical_glyph.y + run.line_y as i32 - pos.top;
min_x = min_x.min(pos.left);
min_y = min_y.min(pos.top);
max_x = max_x.max(pos.left + pos.width as i32);
max_y = max_y.max(pos.top + pos.height as i32);
let mut merge = |i, color: [u8; 4]| {
let x = i % pos.width as usize;
let y = i / pos.width as usize;
let pos = (x as i32 + pos.left, y as i32 + pos.top);
if let Some(pixel) = pixels.get_mut(&pos) {
for i in 0..4 {
pixel[i] = color[i].saturating_add(pixel[i]);
}
} else {
pixels.insert(pos, color);
}
};
match img.content {
SwashContent::Mask => {
for (i, a) in img.data.iter().enumerate() {
let mut color = glyph_color.as_rgba();
color[3] = ((color[3] as u32 * *a as u32) / u8::MAX as u32) as u8;
merge(i, color);
}
}
SwashContent::SubpixelMask => todo!(),
SwashContent::Color => {
let (colors, _) = img.data.as_chunks::<4>();
for (i, color) in colors.iter().enumerate() {
merge(i, *color);
}
}
}
}
}
max_width = max_width.max(run.line_w);
height += run.line_height;
@@ -120,10 +148,11 @@ impl TextData {
let img_width = (max_x - min_x + 1) as u32;
let img_height = (max_y - min_y + 1) as u32;
let mut image = RgbaImage::new(img_width, img_height);
for ((x, y), color) in pixels {
let x = (x - min_x) as u32;
let y = (y - min_y) as u32;
image.put_pixel(x, y, color);
image.put_pixel(x, y, Rgba(color));
}
TextTexture {
handle: textures.add(image),