grr_glyph/
lib.rs

1use glyph_brush::VariedSection;
2use glyph_brush::rusttype::{Font, SharedBytes, Rect, point};
3use std::borrow::Cow;
4
5const IDENTITY_MATRIX4: [[f32; 4]; 4] = [
6    [1.0, 0.0, 0.0, 0.0],
7    [0.0, 1.0, 0.0, 0.0],
8    [0.0, 0.0, 1.0, 0.0],
9    [0.0, 0.0, 0.0, 1.0],
10];
11
12pub struct GlyphBrushBuilder<'a, H = glyph_brush::DefaultSectionHasher> {
13	inner: glyph_brush::GlyphBrushBuilder<'a, H>,
14}
15
16impl<'a> GlyphBrushBuilder<'a> {
17    #[inline]
18    pub fn using_font_bytes<F: Into<SharedBytes<'a>>>(font: F) -> Self {
19		Self::using_font(Font::from_bytes(font).unwrap())
20    }
21
22    #[inline]
23    pub fn using_fonts_bytes<B, V>(font_data: V) -> Self
24    where
25        B: Into<SharedBytes<'a>>,
26        V: Into<Vec<B>>,
27    {
28        Self::using_fonts(
29            font_data
30                .into()
31                .into_iter()
32                .map(|data| Font::from_bytes(data).unwrap())
33                .collect::<Vec<_>>(),
34        )
35    }
36
37    #[inline]
38    pub fn using_font(font_0: Font<'a>) -> Self {
39        Self::using_fonts(vec![font_0])
40    }
41
42    pub fn using_fonts<V: Into<Vec<Font<'a>>>>(fonts: V) -> Self {
43        GlyphBrushBuilder {
44            inner: glyph_brush::GlyphBrushBuilder::using_fonts(fonts),
45        }
46    }
47}
48impl<'a, H: std::hash::BuildHasher> GlyphBrushBuilder<'a, H> {
49    glyph_brush::delegate_glyph_brush_builder_fns!(inner);
50
51    pub fn build<'g>(self, grr: &'g grr::Device) -> GlyphBrush<'a, 'g, H> {
52        let vs = grr.create_shader(grr::ShaderStage::Vertex, include_bytes!("shaders/vert.glsl")).unwrap();
53        let fs = grr.create_shader(grr::ShaderStage::Fragment, include_bytes!("shaders/frag.glsl")).unwrap();
54        let pipeline = grr.create_graphics_pipeline(grr::GraphicsPipelineDesc {
55            vertex_shader: &vs,
56            tessellation_control_shader: None,
57            tessellation_evaluation_shader: None,
58            geometry_shader: None,
59            fragment_shader: Some(&fs),
60        }).unwrap();
61        grr.delete_shaders(&[vs, fs]);
62
63        let vertex_array = grr.create_vertex_array(&[
64            // left top
65            grr::VertexAttributeDesc {
66                location: 0,
67                binding: 0,
68                format: grr::VertexFormat::Xyz32Float,
69                offset: 0,
70            },
71            // right bottom
72            grr::VertexAttributeDesc {
73                location: 1,
74                binding: 0,
75                format: grr::VertexFormat::Xy32Float,
76                offset: (3 * std::mem::size_of::<f32>()) as _,
77            },
78            // left top (tex)
79            grr::VertexAttributeDesc {
80                location: 2,
81                binding: 0,
82                format: grr::VertexFormat::Xy32Float,
83                offset: (5 * std::mem::size_of::<f32>()) as _,
84            },
85            // right bottom (tex)
86            grr::VertexAttributeDesc {
87                location: 3,
88                binding: 0,
89                format: grr::VertexFormat::Xy32Float,
90                offset: (7 * std::mem::size_of::<f32>()) as _,
91            },
92            // color
93            grr::VertexAttributeDesc {
94                location: 4,
95                binding: 0,
96                format: grr::VertexFormat::Xyzw32Float,
97                offset: (9 * std::mem::size_of::<f32>()) as _,
98            },
99        ]).unwrap();
100
101        let sampler = grr.create_sampler(grr::SamplerDesc {
102            min_filter: grr::Filter::Linear,
103            mag_filter: grr::Filter::Linear,
104            mip_map: Some(grr::Filter::Linear),
105            address: (
106                grr::SamplerAddress::ClampEdge,
107                grr::SamplerAddress::ClampEdge,
108                grr::SamplerAddress::ClampEdge,
109            ),
110            lod_bias: 0.0,
111            lod: 0.0..1024.0,
112            compare: None,
113            border_color: [0.0, 0.0, 0.0, 1.0],
114        }).unwrap();
115
116        let brush = self.inner.build();
117
118        let glyph_image = {
119            let (width, height) = brush.texture_dimensions();
120            grr.create_image(grr::ImageType::D2 { width, height, layers: 1, samples: 1 }, grr::Format::R8_UNORM, 1).unwrap()
121        };
122        let glyph_image_view = grr.create_image_view(
123            &glyph_image,
124            grr::ImageViewType::D2,
125            grr::Format::R8_UNORM,
126            grr::SubresourceRange {
127                layers: 0..1,
128                levels: 0..1,
129            },
130        ).unwrap();
131
132        GlyphBrush {
133            inner: brush,
134            glyph_cache: GlyphCache {
135                image: glyph_image,
136                view: glyph_image_view,
137            },
138            grr,
139            pipeline,
140            vertex_array,
141            sampler,
142            draw: None,
143        }
144    }
145}
146
147struct DrawCommand {
148    buffer: grr::Buffer,
149    vertices: u32,
150}
151
152struct GlyphCache {
153    image: grr::Image,
154    view: grr::ImageView,
155}
156
157pub struct GlyphBrush<'font, 'grr, H = glyph_brush::DefaultSectionHasher> {
158    inner: glyph_brush::GlyphBrush<'font, H>,
159    grr: &'grr grr::Device,
160    pipeline: grr::Pipeline,
161    vertex_array: grr::VertexArray,
162    sampler: grr::Sampler,
163    glyph_cache: GlyphCache,
164    draw: Option<DrawCommand>,
165}
166
167impl<'font, 'grr> GlyphBrush<'font, 'grr> {
168    #[inline]
169    pub fn queue_custom_layout<'a, S, G>(&mut self, section: S, custom_layout: &G)
170    where
171        G: glyph_brush::GlyphPositioner,
172        S: Into<Cow<'a, VariedSection<'a>>>,
173    {
174        self.inner.queue_custom_layout(section, custom_layout)
175    }
176
177    #[inline]
178    pub fn queue<'a, S>(&mut self, section: S)
179    where
180        S: Into<Cow<'a, VariedSection<'a>>>,
181    {
182        self.inner.queue(section)
183    }
184
185    #[inline]
186    pub fn keep_cached_custom_layout<'a, S, G>(&mut self, section: S, custom_layout: &G)
187    where
188        G: glyph_brush::GlyphPositioner,
189        S: Into<Cow<'a, VariedSection<'a>>>,
190    {
191        self.inner.keep_cached_custom_layout(section, custom_layout)
192    }
193
194    #[inline]
195    pub fn keep_cached<'a, S>(&mut self, section: S)
196    where
197        S: Into<Cow<'a, VariedSection<'a>>>,
198    {
199        self.inner.keep_cached(section)
200    }
201
202    #[inline]
203    pub fn draw_queued(
204        &mut self,
205        dims: (u32, u32),
206    ) -> Result<(), String> {
207        self.draw_queued_with_transform(IDENTITY_MATRIX4, dims)
208    }
209
210    pub fn draw_queued_with_transform(
211        &mut self,
212        transform: [[f32; 4]; 4],
213        dims: (u32, u32),
214    ) -> Result<(), String> {
215        let mut brush_action;
216        loop {
217            let grr = self.grr;
218            let glyph_cache = &self.glyph_cache;
219            brush_action = self.inner.process_queued(
220                dims,
221                |rect, tex_data| {
222                    grr.copy_host_to_image(
223                        &glyph_cache.image,
224                        grr::SubresourceLevel {
225                            level: 0,
226                            layers: 0..1,
227                        },
228                        grr::Offset { x: rect.min.x as _, y: rect.min.y as _, z: 0 },
229                        grr::Extent {
230                            width: rect.width(),
231                            height: rect.height(),
232                            depth: 1,
233                        },
234                        &tex_data,
235                        grr::SubresourceLayout {
236                            base_format: grr::BaseFormat::R,
237                            format_layout: grr::FormatLayout::U8,
238                            row_pitch: rect.width(),
239                            image_height: rect.height(),
240                            alignment: 1,
241                        },
242                    );
243                },
244                to_vertex,
245            );
246
247            match brush_action {
248                Ok(_) => break,
249                Err(glyph_brush::BrushError::TextureTooSmall { suggested }) => {
250                    unimplemented!()
251                }
252            }
253        }
254
255        match brush_action.unwrap() {
256            glyph_brush::BrushAction::Draw(verts) => {
257                if let Some(draw) = self.draw.take() {
258                    self.grr.delete_buffer(draw.buffer);
259                }
260
261                if !verts.is_empty() {
262                    self.draw = Some(DrawCommand {
263                        buffer:self.grr.create_buffer_from_host(grr::as_u8_slice(verts.as_slice()), grr::MemoryFlags::empty()).unwrap(),
264                        vertices: verts.len() as _,
265                    });
266                }
267            }
268            glyph_brush::BrushAction::ReDraw => {}
269        };
270
271        if let Some(ref cmd) = self.draw {
272            let color_blend = grr::ColorBlend {
273                attachments: vec![grr::ColorBlendAttachment {
274                    blend_enable: true,
275                    color: grr::BlendChannel {
276                        src_factor: grr::BlendFactor::SrcAlpha,
277                        dst_factor: grr::BlendFactor::OneMinusSrcAlpha,
278                        blend_op: grr::BlendOp::Add,
279                    },
280                    alpha: grr::BlendChannel {
281                        src_factor: grr::BlendFactor::One,
282                        dst_factor: grr::BlendFactor::One,
283                        blend_op: grr::BlendOp::Add,
284                    },
285                }],
286            };
287            let depth_stencil = grr::DepthStencil {
288                depth_test: true,
289                depth_write: true,
290                depth_compare_op: grr::Compare::LessEqual,
291                stencil_test: false,
292                stencil_front: grr::StencilFace::KEEP,
293                stencil_back: grr::StencilFace::KEEP,
294            };
295
296            self.grr.bind_pipeline(&self.pipeline);
297            self.grr.bind_vertex_array(&self.vertex_array);
298            self.grr.bind_vertex_buffers(&self.vertex_array, 0, &[grr::VertexBufferView {
299                buffer: &cmd.buffer,
300                offset: 0,
301                stride: (std::mem::size_of::<f32>() * 13) as _,
302                input_rate: grr::InputRate::Instance { divisor: 1 },
303            }]);
304            self.grr.bind_color_blend_state(&color_blend);
305            self.grr.bind_depth_stencil_state(&depth_stencil);
306            self.grr.bind_samplers(0, &[&self.sampler]);
307            self.grr.bind_image_views(0, &[&self.glyph_cache.view]);
308            self.grr.draw(grr::Primitive::TriangleStrip, 0..4, 0..cmd.vertices as _);
309        }
310
311        Ok(())
312    }
313
314    #[inline]
315    pub fn fonts(&self) -> &[Font<'_>] {
316        self.inner.fonts()
317    }
318
319    pub fn add_font_bytes<'a: 'font, B: Into<SharedBytes<'a>>>(&mut self, font_data: B) -> glyph_brush::FontId {
320        self.inner.add_font_bytes(font_data)
321    }
322
323    pub fn add_font<'a: 'font>(&mut self, font_data: Font<'a>) -> glyph_brush::FontId {
324        self.inner.add_font(font_data)
325    }
326}
327
328type Vertex = [f32; 13];
329
330#[inline]
331fn to_vertex(
332    glyph_brush::GlyphVertex {
333        mut tex_coords,
334        pixel_coords,
335        bounds,
336        screen_dimensions: (screen_w, screen_h),
337        color,
338        z,
339    }: glyph_brush::GlyphVertex,
340) -> Vertex {
341    let gl_bounds = Rect {
342        min: point(
343            2.0 * (bounds.min.x / screen_w - 0.5),
344            2.0 * (0.5 - bounds.min.y / screen_h),
345        ),
346        max: point(
347            2.0 * (bounds.max.x / screen_w - 0.5),
348            2.0 * (0.5 - bounds.max.y / screen_h),
349        ),
350    };
351
352    let mut gl_rect = Rect {
353        min: point(
354            2.0 * (pixel_coords.min.x as f32 / screen_w - 0.5),
355            2.0 * (0.5 - pixel_coords.min.y as f32 / screen_h),
356        ),
357        max: point(
358            2.0 * (pixel_coords.max.x as f32 / screen_w - 0.5),
359            2.0 * (0.5 - pixel_coords.max.y as f32 / screen_h),
360        ),
361    };
362
363    // handle overlapping bounds, modify uv_rect to preserve texture aspect
364    if gl_rect.max.x > gl_bounds.max.x {
365        let old_width = gl_rect.width();
366        gl_rect.max.x = gl_bounds.max.x;
367        tex_coords.max.x = tex_coords.min.x + tex_coords.width() * gl_rect.width() / old_width;
368    }
369    if gl_rect.min.x < gl_bounds.min.x {
370        let old_width = gl_rect.width();
371        gl_rect.min.x = gl_bounds.min.x;
372        tex_coords.min.x = tex_coords.max.x - tex_coords.width() * gl_rect.width() / old_width;
373    }
374    // note: y access is flipped gl compared with screen,
375    // texture is not flipped (ie is a headache)
376    if gl_rect.max.y < gl_bounds.max.y {
377        let old_height = gl_rect.height();
378        gl_rect.max.y = gl_bounds.max.y;
379        tex_coords.max.y = tex_coords.min.y + tex_coords.height() * gl_rect.height() / old_height;
380    }
381    if gl_rect.min.y > gl_bounds.min.y {
382        let old_height = gl_rect.height();
383        gl_rect.min.y = gl_bounds.min.y;
384        tex_coords.min.y = tex_coords.max.y - tex_coords.height() * gl_rect.height() / old_height;
385    }
386
387    [
388        gl_rect.min.x,
389        gl_rect.max.y,
390        z,
391        gl_rect.max.x,
392        gl_rect.min.y,
393        tex_coords.min.x,
394        tex_coords.max.y,
395        tex_coords.max.x,
396        tex_coords.min.y,
397        color[0],
398        color[1],
399        color[2],
400        color[3],
401    ]
402}