Use 4 channel atlas for emojis
This commit is contained in:
parent
47fa03d079
commit
cb68955045
4 changed files with 37 additions and 13 deletions
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue