alexheretic / glyph-brush

Fast GPU cached text rendering
Apache License 2.0
673 stars 52 forks source link

Rendered text has characters in random order #149

Closed zarik5 closed 2 years ago

zarik5 commented 2 years ago

I'm trying to move some text rendering code from Java to Rust. This is what I get with the old code, the expected result: message old

Now I'm trying to rewrite it with glyph_brush, but instead I get a garbled result, the characters get rendered in a random order and it doesn't respect the specified layout: message new

The code used for generating the bitmap is the following:

    let message = format!(
        "ALVR v{}\nhostname: {hostname}\n \n{message}",
        *ALVR_VERSION,
    );

    let ubuntu_font =
        FontArc::try_from_slice(include_bytes!("../resources/Ubuntu-Medium.ttf")).unwrap();

    let mut brush = GlyphBrushBuilder::using_font(ubuntu_font).build();

    brush.queue(
        Section::new()
            .add_text(Text::new(&message).with_scale(50_f32))
            .with_bounds((1280_f32, 720_f32))
            .with_layout(
                Layout::default()
                    .h_align(HorizontalAlign::Center)
                    .v_align(VerticalAlign::Center),
            ),
    );

    // todo: handle "TextureTooSmall" error
    brush
        .process_queued(
            |rect, data| unsafe {
                crate::updateLoadingTexuture(
                    rect.min[0],
                    rect.min[1],
                    rect.max[0] - rect.min[0],
                    rect.max[1] - rect.min[1],
                    data.as_ptr(),
                );
            },
            |vertex| (),
        )
        .ok();

updateLoadingTexuture just queues pixel data for the next rendering cycle. Only one draw command is issued when the text changes, I'm pretty sure the bug is not caused by code external to glyph-brush.

zarik5 commented 2 years ago

Using the same OpenSans-Light.ttf font file from the example will not fix the bug. Removing any \n will also not fix the bug, the characters are swapped also in the same line.

alexheretic commented 2 years ago

It looks like you are rendering the draw cache texture directly. This is not how glyph-brush is designed to work.

GlyphBrush::process_queued can return a BrushAction::Draw(vertices). These are the vertices for each glyph in the layout, each vertex includes draw cache texture coordinates it'll use to render.

You can see this in action in the "draw cache guts" example, cargo run --example draw_cache_guts where both the text & the draw-cache are rendered side-by-side. In the opengl example you can see a more realistic example where the draw cache is not directly rendered at all.

However, if you do want create a single image as described for a given text layout glyph-brush is not the right tool. You can use ab-glyph directly, perhaps alongside glyph-brush-layout, to render each glyph into a large image. The ab-glyph image example is along these lines.

This rendering style is not as optimal as what glyph-brush uses and will, of course, not benefit from the caching & optimisations provided by glyph-brush.

zarik5 commented 2 years ago

Thank you for the in-depth explanation! I should have at least run the example...