Use 4 channel atlas for emojis

This commit is contained in:
grovesNL 2022-10-26 00:21:14 -02:30 committed by Josh Groves
parent 47fa03d079
commit cb68955045
4 changed files with 37 additions and 13 deletions

View file

@ -3,7 +3,8 @@ use glyphon::{Color, HasColor, Resolution, TextAtlas, TextRenderer};
use wgpu::{ use wgpu::{
Backends, CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance, Backends, CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance,
Limits, LoadOp, Operations, PresentMode, RenderPassColorAttachment, RenderPassDescriptor, Limits, LoadOp, Operations, PresentMode, RenderPassColorAttachment, RenderPassDescriptor,
RequestAdapterOptions, SurfaceConfiguration, TextureUsages, TextureViewDescriptor, RequestAdapterOptions, SurfaceConfiguration, TextureFormat, TextureUsages,
TextureViewDescriptor,
}; };
use winit::{ use winit::{
event::{Event, WindowEvent}, event::{Event, WindowEvent},
@ -53,7 +54,8 @@ async fn run() {
let window = Window::new(&event_loop).unwrap(); let window = Window::new(&event_loop).unwrap();
let surface = unsafe { instance.create_surface(&window) }; let surface = unsafe { instance.create_surface(&window) };
let size = window.inner_size(); let size = window.inner_size();
let swapchain_format = surface.get_supported_formats(&adapter)[0]; // TODO: handle srgb
let swapchain_format = TextureFormat::Bgra8Unorm;
let mut config = SurfaceConfiguration { let mut config = SurfaceConfiguration {
usage: TextureUsages::RENDER_ATTACHMENT, usage: TextureUsages::RENDER_ATTACHMENT,
format: swapchain_format, format: swapchain_format,

View file

@ -77,5 +77,5 @@ fn vs_main(in_vert: VertexInput) -> VertexOutput {
@fragment @fragment
fn fs_main(in_frag: VertexOutput) -> @location(0) vec4<f32> { fn fs_main(in_frag: VertexOutput) -> @location(0) vec4<f32> {
return in_frag.color * textureSample(atlas_texture, atlas_sampler, in_frag.uv).x; return in_frag.color * textureSample(atlas_texture, atlas_sampler, in_frag.uv);
} }

View file

@ -13,6 +13,8 @@ use wgpu::{
use crate::{GlyphDetails, GlyphToRender, Params, RecentlyUsedMap, Resolution}; use crate::{GlyphDetails, GlyphToRender, Params, RecentlyUsedMap, Resolution};
pub(crate) const NUM_ATLAS_CHANNELS: usize = 4usize;
/// An atlas containing a cache of rasterized glyphs that can be rendered. /// An atlas containing a cache of rasterized glyphs that can be rendered.
pub struct TextAtlas { pub struct TextAtlas {
pub(crate) texture_pending: Vec<u8>, pub(crate) texture_pending: Vec<u8>,
@ -35,8 +37,9 @@ impl TextAtlas {
let height = max_texture_dimension_2d; let height = max_texture_dimension_2d;
let packer = BucketedAtlasAllocator::new(size2(width as i32, height as i32)); let packer = BucketedAtlasAllocator::new(size2(width as i32, height as i32));
// Create a texture to use for our atlas // Create a texture to use for our atlas
let texture_pending = vec![0; (width * height) as usize]; let texture_pending = vec![0; (width * height) as usize * NUM_ATLAS_CHANNELS];
let texture = device.create_texture(&TextureDescriptor { let texture = device.create_texture(&TextureDescriptor {
label: Some("glyphon atlas"), label: Some("glyphon atlas"),
size: Extent3d { size: Extent3d {
@ -47,7 +50,7 @@ impl TextAtlas {
mip_level_count: 1, mip_level_count: 1,
sample_count: 1, sample_count: 1,
dimension: TextureDimension::D2, dimension: TextureDimension::D2,
format: TextureFormat::R8Unorm, format: TextureFormat::Rgba8Unorm,
usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST, usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
}); });
let texture_view = texture.create_view(&TextureViewDescriptor::default()); let texture_view = texture.create_view(&TextureViewDescriptor::default());

View file

@ -1,4 +1,4 @@
use cosmic_text::{CacheKey, SwashCache, TextBuffer}; use cosmic_text::{CacheKey, SwashCache, SwashContent, TextBuffer};
use etagere::{size2, Allocation}; use etagere::{size2, Allocation};
use std::{collections::HashSet, iter, mem::size_of, num::NonZeroU32, slice}; use std::{collections::HashSet, iter, mem::size_of, num::NonZeroU32, slice};
@ -8,8 +8,8 @@ use wgpu::{
}; };
use crate::{ use crate::{
GlyphDetails, GlyphToRender, GpuCache, Params, PrepareError, RenderError, Resolution, text_atlas::NUM_ATLAS_CHANNELS, GlyphDetails, GlyphToRender, GpuCache, Params, PrepareError,
TextAtlas, TextOverflow, RenderError, Resolution, TextAtlas, TextOverflow,
}; };
/// A text renderer that uses cached glyphs to render text into an existing render pass. /// A text renderer that uses cached glyphs to render text into an existing render pass.
@ -110,7 +110,23 @@ impl TextRenderer {
.swash_cache .swash_cache
.get_image_uncached(&buffer.font_matches, glyph.cache_key) .get_image_uncached(&buffer.font_matches, glyph.cache_key)
.unwrap(); .unwrap();
let bitmap = image.data.as_slice(); let mut bitmap = image.data;
match image.content {
SwashContent::Color => {}
SwashContent::Mask => {
// Technically only one channel is needed, but store the mask in every
// for now.
bitmap = bitmap
.iter()
.flat_map(|color| iter::repeat(*color).take(NUM_ATLAS_CHANNELS))
.collect();
}
SwashContent::SubpixelMask => {
// Not implemented yet, but don't panic if this happens.
}
}
let width = image.placement.width as usize; let width = image.placement.width as usize;
let height = image.placement.height as usize; let height = image.placement.height as usize;
@ -129,8 +145,10 @@ impl TextRenderer {
let y_offset = atlas_min.y as usize; let y_offset = atlas_min.y as usize;
let x_offset = let x_offset =
(y_offset + row) * atlas.width as usize + atlas_min.x as usize; (y_offset + row) * atlas.width as usize + atlas_min.x as usize;
let bitmap_row = &bitmap[row * width..(row + 1) * width]; let bitmap_row = &bitmap[row * width * NUM_ATLAS_CHANNELS
atlas.texture_pending[x_offset..x_offset + width] ..(row + 1) * width * NUM_ATLAS_CHANNELS];
atlas.texture_pending[x_offset * NUM_ATLAS_CHANNELS
..(x_offset + width) * NUM_ATLAS_CHANNELS]
.copy_from_slice(bitmap_row); .copy_from_slice(bitmap_row);
} }
@ -194,7 +212,7 @@ impl TextRenderer {
&atlas.texture_pending[ub.y_min * atlas.width as usize + ub.x_min..], &atlas.texture_pending[ub.y_min * atlas.width as usize + ub.x_min..],
ImageDataLayout { ImageDataLayout {
offset: 0, offset: 0,
bytes_per_row: NonZeroU32::new(atlas.width), bytes_per_row: NonZeroU32::new(atlas.width * NUM_ATLAS_CHANNELS as u32),
rows_per_image: NonZeroU32::new(atlas.height), rows_per_image: NonZeroU32::new(atlas.height),
}, },
Extent3d { Extent3d {
@ -284,7 +302,8 @@ impl TextRenderer {
pos: [x as i32, y as i32], pos: [x as i32, y as i32],
dim: [width as u16, height as u16], dim: [width as u16, height as u16],
uv: [atlas_x, atlas_y], uv: [atlas_x, atlas_y],
color: [255, 0, 255, 255], // TODO
color: [255, 255, 255, 255],
}) })
.take(4), .take(4),
); );