1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! # Klyff text renderer
//!
//! A text renderer intended for games, with high customisability. It uses:
//! - [`wgpu`] for rendering.
//! - [`cosmic_text`] for shaping and layout.
//! - [`skrifa`] & [`swash`] for font reading.
//! - [`etagere`] for atlas packing.
//! - [`klyff_msdf`] for 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](https://github.com/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.
//!
//! ```rust, no_run
//! 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.
//!
//! 2. 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).
//!
//! 3. 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.
//!
//! 4. 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
//! [`MaterialEncoder`]s sharing one [`MeshEncoder`].
//!
//! If the built-in [`GlyphMaterial`] does not cover your effect, the same pattern still applies:
//! iterate the [`MeshEncoder`]'s [`DecodedGlyph`]s, 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.
pub use ;
pub use cosmic_text;
pub use ;
pub use Features;
pub use fontdb;
pub use ;
pub use TextRenderer;
pub use ;