Skip to main content

Crate klyff

Crate klyff 

Source
Expand description

§Klyff text renderer

A text renderer intended for games, with high customisability. It uses:

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
  1. 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.

  1. 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).

  1. 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.

  1. 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.

  • MeshEncoder decodes Text into the vertex / index buffers, which is then shared across all draw calls. It records a list of DecodedGlyph entry, allowing you to attach per-glyph attributes without re-running layout.

  • MaterialEncoder walks the decoded glyphs and produces a parallel vertex buffer of GlyphMaterial data - drawing instruction consumed by the built-in MSDF shader. One MaterialEncoder corresponds to one draw call / one layer (fill, stroke, glow, shadow, …); the layered effects of TextRenderer are themselves implemented as multiple MaterialEncoders sharing one MeshEncoder.

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§

atlas

Structs§

Color
RGBA color.
CustomGlyph
A custom glyph detected during crate::MeshEncoder::encode.
CustomGlyphFont
Handle to the loaded custom-glyph font.
DecodedGlyph
A glyph that has been processed during crate::MeshEncoder::encode and is available for crate::MaterialEncoders to iterate over in a second pass.
EncoderContext
Resources borrowed during encoding.
Features
Text renderer feature flags.
Glow
GlyphMaterial
How to draw a glyph in a pass.
MaterialEncoder
Encodes GlyphMaterial into GPU buffer, and material attributes for each vertex.
MeshEncoder
Encodes Text into mesh geometry.
MsdfTextPipeline
Renders MSDF glyphs encoded by MeshEncoder + MaterialEncoder.
Outline
RasterizedTextPipeline
Renders rasterized (colour-bitmap) glyphs encoded by MeshEncoder.
Rect
ScreenSizeUniform
Holds the uniform to encode current screen size, necessary for translating glyph to screen space.
Shadow
StyledText
A styled text. Construct one with StyledTextBuilder
StyledTextBuilder
Builder for StyledText.
Text
A low-level view of a text laid out into a cosmic_text::Buffer, suitable for crate::MeshEncoder::encode.
TextRenderer
Text renderer with MSDF.
TextStyle
Styling of texts.

Enums§

GlyphColoring
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_system and return a handle identifying it.

Type Aliases§

GlyphStyleMap