WIP: Start on rendering glyphs
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
co-authored by
Nathan Sobo
parent
43abd96769
commit
764bfba2e2
@@ -4,6 +4,7 @@ mod event;
|
||||
mod geometry;
|
||||
mod renderer;
|
||||
mod runner;
|
||||
mod sprite_cache;
|
||||
mod window;
|
||||
|
||||
use crate::platform;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{ffi::c_void, mem};
|
||||
use std::{collections::HashMap, ffi::c_void, mem};
|
||||
|
||||
use self::shaders::ToUchar4;
|
||||
|
||||
@@ -15,8 +15,10 @@ const INSTANCE_BUFFER_SIZE: usize = 1024 * 1024; // This is an arbitrary decisio
|
||||
pub struct Renderer {
|
||||
quad_pipeline_state: metal::RenderPipelineState,
|
||||
shadow_pipeline_state: metal::RenderPipelineState,
|
||||
sprite_pipeline_state: metal::RenderPipelineState,
|
||||
unit_vertices: metal::Buffer,
|
||||
instances: metal::Buffer,
|
||||
sprite_cache: SpriteCache,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
@@ -60,6 +62,14 @@ impl Renderer {
|
||||
"shadow_fragment",
|
||||
pixel_format,
|
||||
)?,
|
||||
sprite_pipeline_state: build_pipeline_state(
|
||||
device,
|
||||
&library,
|
||||
"sprite",
|
||||
"sprite_vertex",
|
||||
"sprite_fragment",
|
||||
pixel_format,
|
||||
)?,
|
||||
unit_vertices,
|
||||
instances,
|
||||
})
|
||||
@@ -79,6 +89,7 @@ impl Renderer {
|
||||
for layer in scene.layers() {
|
||||
self.render_shadows(scene, layer, &mut offset, ctx);
|
||||
self.render_quads(scene, layer, &mut offset, ctx);
|
||||
self.render_sprites(scene, layer, &mut offset, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +245,71 @@ impl Renderer {
|
||||
layer.quads().len() as u64,
|
||||
);
|
||||
}
|
||||
|
||||
fn render_sprites(
|
||||
&mut self,
|
||||
scene: &Scene,
|
||||
layer: &Layer,
|
||||
offset: &mut usize,
|
||||
ctx: &RenderContext,
|
||||
) {
|
||||
if layer.glyphs().is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
align_offset(offset);
|
||||
let next_offset = *offset + layer.glyphs().len() * mem::size_of::<shaders::GPUISprite>();
|
||||
assert!(
|
||||
next_offset <= INSTANCE_BUFFER_SIZE,
|
||||
"instance buffer exhausted"
|
||||
);
|
||||
|
||||
let mut sprites = HashMap::new();
|
||||
for glyph in layer.glyphs() {
|
||||
let (atlas, bounds) =
|
||||
self.sprite_cache
|
||||
.rasterize_glyph(glyph.font_id, glyph.font_size, glyph.glyph_id);
|
||||
sprites
|
||||
.entry(atlas)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(shaders::GPUISprite {
|
||||
origin: glyph.origin.to_float2(),
|
||||
size: bounds.size().to_float2(),
|
||||
atlas_origin: bounds.origin().to_float2(),
|
||||
color: glyph.color.to_uchar4(),
|
||||
});
|
||||
}
|
||||
|
||||
ctx.command_encoder
|
||||
.set_render_pipeline_state(&self.sprite_pipeline_state);
|
||||
ctx.command_encoder.set_vertex_buffer(
|
||||
shaders::GPUISpriteInputIndex_GPUISpriteInputIndexVertices as u64,
|
||||
Some(&self.unit_vertices),
|
||||
0,
|
||||
);
|
||||
ctx.command_encoder.set_vertex_buffer(
|
||||
shaders::GPUISpriteInputIndex_GPUISpriteInputIndexSprites as u64,
|
||||
Some(&self.instances),
|
||||
*offset as u64,
|
||||
);
|
||||
ctx.command_encoder.set_vertex_bytes(
|
||||
shaders::GPUISpriteInputIndex_GPUISpriteInputIndexUniforms as u64,
|
||||
mem::size_of::<shaders::GPUIUniforms>() as u64,
|
||||
[shaders::GPUIUniforms {
|
||||
viewport_size: ctx.drawable_size.to_float2(),
|
||||
}]
|
||||
.as_ptr() as *const c_void,
|
||||
);
|
||||
|
||||
let buffer_contents = unsafe {
|
||||
(self.instances.contents() as *mut u8).offset(*offset as isize)
|
||||
as *mut shaders::GPUISprite
|
||||
};
|
||||
|
||||
for glyph in layer.glyphs() {
|
||||
let sprite = self.sprite_cache.rasterize_glyph();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn align_offset(offset: &mut usize) {
|
||||
|
||||
@@ -35,3 +35,16 @@ typedef struct {
|
||||
float sigma;
|
||||
vector_uchar4 color;
|
||||
} GPUIShadow;
|
||||
|
||||
typedef enum {
|
||||
GPUISpriteInputIndexVertices = 0,
|
||||
GPUISpriteInputIndexSprites = 1,
|
||||
GPUISpriteInputIndexUniforms = 2,
|
||||
} GPUISpriteInputIndex;
|
||||
|
||||
typedef struct {
|
||||
vector_float2 origin;
|
||||
vector_float2 size;
|
||||
vector_float2 atlas_origin;
|
||||
vector_uchar4 color;
|
||||
} GPUISprite;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
use crate::geometry::vector::Vector2I;
|
||||
use etagere::BucketedAtlasAllocator;
|
||||
|
||||
struct SpriteCache {
|
||||
atlasses: Vec<etagere::BucketedAtlasAllocator>,
|
||||
}
|
||||
|
||||
impl SpriteCache {
|
||||
fn new(size: Vector2I) -> Self {
|
||||
let size = etagere::Size::new(size.x(), size.y());
|
||||
Self {
|
||||
atlasses: vec![BucketedAtlasAllocator::new(size)],
|
||||
}
|
||||
}
|
||||
|
||||
fn render_glyph(&mut self) {
|
||||
self.atlasses.last().unwrap()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user