mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 14:20:04 -04:00
Make the font atlas use a color image (#7298)
* [x] I have followed the instructions in the PR template Splitting this out from the Parley work as requested. This removes `FontImage` and makes the font atlas use a `ColorImage`. It converts alpha to coverage at glyph-drawing time, not at delta-upload time. This doesn't do much now, but will allow for color emoji rendering once we start using Parley. I've changed things around so that we pass in `text_alpha_to_coverage` to the `Fonts` the same way we do with `pixels_per_point` and `max_texture_side`, reusing the existing code to check if the setting differs and recreating the font atlas if so. I'm not quite sure why this wasn't done in the first place. I've left `ImageData` as an enum for now, in case we want to add support for more texture pixel formats in the future (which I personally think would be worthwhile). If you'd like, I can just remove that enum entirely.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use ecolor::Color32;
|
||||
use emath::{Rect, remap_clamp};
|
||||
|
||||
use crate::{FontImage, ImageDelta};
|
||||
use crate::{AlphaFromCoverage, ColorImage, ImageDelta};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
struct Rectu {
|
||||
@@ -57,7 +58,7 @@ pub struct PreparedDisc {
|
||||
/// More characters can be added, possibly expanding the texture.
|
||||
#[derive(Clone)]
|
||||
pub struct TextureAtlas {
|
||||
image: FontImage,
|
||||
image: ColorImage,
|
||||
|
||||
/// What part of the image that is dirty
|
||||
dirty: Rectu,
|
||||
@@ -72,18 +73,22 @@ pub struct TextureAtlas {
|
||||
|
||||
/// pre-rasterized discs of radii `2^i`, where `i` is the index.
|
||||
discs: Vec<PrerasterizedDisc>,
|
||||
|
||||
/// Controls how to convert glyph coverage to alpha.
|
||||
pub(crate) text_alpha_from_coverage: AlphaFromCoverage,
|
||||
}
|
||||
|
||||
impl TextureAtlas {
|
||||
pub fn new(size: [usize; 2]) -> Self {
|
||||
pub fn new(size: [usize; 2], text_alpha_from_coverage: AlphaFromCoverage) -> Self {
|
||||
assert!(size[0] >= 1024, "Tiny texture atlas");
|
||||
let mut atlas = Self {
|
||||
image: FontImage::new(size),
|
||||
image: ColorImage::filled(size, Color32::TRANSPARENT),
|
||||
dirty: Rectu::EVERYTHING,
|
||||
cursor: (0, 0),
|
||||
row_height: 0,
|
||||
overflowed: false,
|
||||
discs: vec![], // will be filled in below
|
||||
text_alpha_from_coverage,
|
||||
};
|
||||
|
||||
// Make the top left pixel fully white for `WHITE_UV`, i.e. painting something with solid color:
|
||||
@@ -93,7 +98,7 @@ impl TextureAtlas {
|
||||
(0, 0),
|
||||
"Expected the first allocation to be at (0, 0), but was at {pos:?}"
|
||||
);
|
||||
image[pos] = 1.0;
|
||||
image[pos] = Color32::WHITE;
|
||||
|
||||
// Allocate a series of anti-aliased discs used to render small filled circles:
|
||||
// TODO(emilk): these circles can be packed A LOT better.
|
||||
@@ -116,7 +121,7 @@ impl TextureAtlas {
|
||||
let coverage =
|
||||
remap_clamp(distance_to_center, (r - 0.5)..=(r + 0.5), 1.0..=0.0);
|
||||
image[((x as i32 + hw + dx) as usize, (y as i32 + hw + dy) as usize)] =
|
||||
coverage;
|
||||
text_alpha_from_coverage.color_from_coverage(coverage);
|
||||
}
|
||||
}
|
||||
atlas.discs.push(PrerasterizedDisc {
|
||||
@@ -184,7 +189,7 @@ impl TextureAtlas {
|
||||
|
||||
/// The full font atlas image.
|
||||
#[inline]
|
||||
pub fn image(&self) -> &FontImage {
|
||||
pub fn image(&self) -> &ColorImage {
|
||||
&self.image
|
||||
}
|
||||
|
||||
@@ -200,14 +205,14 @@ impl TextureAtlas {
|
||||
} else {
|
||||
let pos = [dirty.min_x, dirty.min_y];
|
||||
let size = [dirty.max_x - dirty.min_x, dirty.max_y - dirty.min_y];
|
||||
let region = self.image.region(pos, size);
|
||||
let region = self.image.region_by_pixels(pos, size);
|
||||
Some(ImageDelta::partial(pos, region, texture_options))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the coordinates of where the rect ended up,
|
||||
/// and invalidates the region.
|
||||
pub fn allocate(&mut self, (w, h): (usize, usize)) -> ((usize, usize), &mut FontImage) {
|
||||
pub fn allocate(&mut self, (w, h): (usize, usize)) -> ((usize, usize), &mut ColorImage) {
|
||||
/// On some low-precision GPUs (my old iPad) characters get muddled up
|
||||
/// if we don't add some empty pixels between the characters.
|
||||
/// On modern high-precision GPUs this is not needed.
|
||||
@@ -254,13 +259,15 @@ impl TextureAtlas {
|
||||
}
|
||||
}
|
||||
|
||||
fn resize_to_min_height(image: &mut FontImage, required_height: usize) -> bool {
|
||||
fn resize_to_min_height(image: &mut ColorImage, required_height: usize) -> bool {
|
||||
while required_height >= image.height() {
|
||||
image.size[1] *= 2; // double the height
|
||||
}
|
||||
|
||||
if image.width() * image.height() > image.pixels.len() {
|
||||
image.pixels.resize(image.width() * image.height(), 0.0);
|
||||
image
|
||||
.pixels
|
||||
.resize(image.width() * image.height(), Color32::TRANSPARENT);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user