Expand description
§Klyff text renderer
A text renderer intended for games, with high customisability. It uses:
wgpufor rendering.cosmic_textfor shaping and layout.skrifa&swashfor font reading.etagerefor atlas packing.klyff_msdffor MSDF generation (done entirely on the GPU with wgpu).
Because glyphs are rendered with MSDF, glyphs can be scaled up infinitely and still preserves sharp corners. This is a pure rust reimplementation of this technique, originally invented by Chlumsky: msdfgen.
This crate features two layers: a convenient high level API, and a low level API for more customisability (such as custom shaders).
§High level API
The high level API mainly involves TextRenderer and StyledText.
First, create a TextRenderer with TextRenderer::new() for a basic renderer drawing
only the glyph’s body, or TextRenderer::with_styling() to draw texts with additional
styling such as shadow, outline or glow. Each styling type is drawn with a separate draw call,
so disable what you don’t need in the Features parameter.
use klyff::{
EncoderContext, Rect, StyledTextBuilder, TextRenderer, TextStyle, TextureAtlas,
TextureAtlasDescriptor,
cosmic_text::{Attrs, Family, FontSystem, Metrics},
};
// Dependencies
let device: wgpu::Device = todo!("Obtain a device from wgpu");
let queue: wgpu::Queue = todo!("Obtain a device from wgpu");
let surface_format: wgpu::TextureFormat = todo!("Define your surface format");
let view: wgpu::TextureView = todo!("Obtain your render target");
let mut font_system: FontSystem = todo!("Obtain a font system from cosmic_text");
let (width, height) = (800u32, 600u32);
// One-time setup: a renderer for the swapchain format, and an atlas to cache glyphs.
let mut renderer = TextRenderer::new(&device, surface_format);
let mut atlas = TextureAtlas::new(&device, TextureAtlasDescriptor::default());
// Build a `StyledText` for the given bounding box. Each call to `push_text` adds a run.
let attrs = Attrs::new().family(Family::Name("Open Sans"));
let mut text_builder = StyledTextBuilder::new(
Rect::from_xywh(0.0, 0.0, width as f32, height as f32),
&mut font_system,
Metrics::new(48.0, 60.0));
text_builder.push_text("Hello, world!", &attrs, TextStyle::default())
let text = text_builder.finish(&mut font_system, &attrs);
// Per frame: prepare uploads glyphs into the atlas and writes vertex buffers.
let mut cmd_encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
renderer.prepare(
EncoderContext {
atlas: &mut atlas,
device: &device,
queue: &queue,
cmd_encoder: &mut cmd_encoder,
font_system: &mut font_system,
},
(width, height),
std::slice::from_ref(&text),
);
// Then issue the draw inside any render pass that targets `surface_format`.
let mut pass = cmd_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
depth_slice: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
renderer.render(&mut pass, &atlas);See the full setup at the hello_world and all_features examples.
§Features
- Styling
Styling is done through StyledText. Each text can hold multiple chunks of text, each with its
own styling. Build styled text with StyledTextBuilder.
When styling is enabled, each effect is drawn as a separate draw call in back-to-front order (shadow - outer glow - outer stroke - fill - inner glow - inner stroke) to avoid overlap between different glyphs and proper alpha blending.
Beyond this, TextRenderer allows you to further modify styling per glyph, and position of
each emitted vertex with TextRenderer::prepare_with_glyph_transform, which is useful for
text animations.
- Rasterized glyphs
Glyphs that are incompatible with MSDF rendering (such as colored glyphs, bitmap glyphs) are rasterized as is into the atlas, and rendered with a separate pipeline. Currently, styling is not supported for these glyphs (though it is feasible to implement in the future).
- Custom glyphs
StyledText supports injecting custom glyphs into text. They are represented with an empty
glyph in the Private Use Area (PUA) defined by a custom font. You can set it up by calling
setup_custom_glyph_font.
Klyff does not handle rendering custom glyphs, instead it stores the processed glyphs and
their position in a Vec which can be read back and rendered later by application code. Both
TextRenderer and MeshEncoder supports this operation.
- Custom pipeline
TextRenderer supports passing in custom pipeline for MSDF and rasterized glyphs through
TextRenderer::with_custom_pipeline. This is intended for use cases such as specifying
depth-stencil state, custom blend ops, or otherwise modifying the pipeline while still using
the built-in shader and pipeline layout.
Modifying the pipeline layout or the shader module may create an invalid pipeline and panic at runtime, so do be careful. If you need to use custom shaders then the low level API is recommended for more flexibility.
§Low level API
For renderers that need full shader control, klyff splits the work into composable encoders.
-
MeshEncoderdecodesTextinto the vertex / index buffers, which is then shared across all draw calls. It records a list ofDecodedGlyphentry, allowing you to attach per-glyph attributes without re-running layout. -
MaterialEncoderwalks the decoded glyphs and produces a parallel vertex buffer ofGlyphMaterialdata - drawing instruction consumed by the built-in MSDF shader. OneMaterialEncodercorresponds to one draw call / one layer (fill, stroke, glow, shadow, …); the layered effects ofTextRendererare themselves implemented as multipleMaterialEncoders sharing oneMeshEncoder.
If the built-in GlyphMaterial does not cover your effect, the same pattern still applies:
iterate the MeshEncoder’s DecodedGlyphs, emit your own parallel vertex buffer and bind
it alongside the mesh buffer in your own pipeline.
You can see an example of these patterns in the custom_pipeline example crate.
§Glyph atlas
The generated distance fields / rasterized glyphs are cached on a texture atlas. By default
this atlas is generated at runtime as new glyphs are drawn. With the serde feature you can
also generate the atlas offline and save it with [TextureAtlas::bake()], then reload it on
startup with [TextureAtlas::from_baked()].
If you do not want new glyphs to be generated into the atlas during runtime, call
TextureAtlas::freeze(); TextureAtlas::unfreeze() re-enables generation.
See the prebaked_atlas example for demonstration of this feature.
§Versioning
This crate follows semver. In addition to standard rust’s API backward compatibility guarantee, any change to vertex buffer layout or bind group layout will be considered a breaking change.
Re-exports§
pub use atlas::AtlasRegion;pub use atlas::AtlasSize;pub use atlas::CachedGlyph;pub use atlas::FontData;pub use atlas::GlyphKey;pub use atlas::TextureAtlas;pub use atlas::TextureAtlasDescriptor;pub use atlas::WriteGlyphError;pub use cosmic_text;pub use fontdb;
Modules§
Structs§
- Color
- RGBA color.
- Custom
Glyph - A custom glyph detected during
crate::MeshEncoder::encode. - Custom
Glyph Font - Handle to the loaded custom-glyph font.
- Decoded
Glyph - A glyph that has been processed during
crate::MeshEncoder::encodeand is available forcrate::MaterialEncoders to iterate over in a second pass. - Encoder
Context - Resources borrowed during encoding.
- Features
- Text renderer feature flags.
- Glow
- Glyph
Material - How to draw a glyph in a pass.
- Material
Encoder - Encodes
GlyphMaterialinto GPU buffer, and material attributes for each vertex. - Mesh
Encoder - Encodes
Textinto mesh geometry. - Msdf
Text Pipeline - Renders MSDF glyphs encoded by
MeshEncoder+MaterialEncoder. - Outline
- Rasterized
Text Pipeline - Renders rasterized (colour-bitmap) glyphs encoded by
MeshEncoder. - Rect
- Screen
Size Uniform - Holds the uniform to encode current screen size, necessary for translating glyph to screen space.
- Shadow
- Styled
Text - A styled text. Construct one with
StyledTextBuilder - Styled
Text Builder - Builder for
StyledText. - Text
- A low-level view of a text laid out into a
cosmic_text::Buffer, suitable forcrate::MeshEncoder::encode. - Text
Renderer - Text renderer with MSDF.
- Text
Style - Styling of texts.
Enums§
- Glyph
Coloring - How a glyph is colored.
Constants§
- CUSTOM_
GLYPH_ CHAR - The Private Use Area codepoint that represents a custom glyph.
Functions§
- setup_
custom_ glyph_ font - Load the bundled PUA font into
font_systemand return a handle identifying it.