#text in 3d scene with wasm support

8 messages · Page 1 of 1 (latest)

analog moon
#

is there a built-in or recommended crate for drawing text in the scene? i saw bevy_text_mesh, but unfortunately it doesn't support WASM.

worldly timber
#

Your question reminded me of a new crate that popped up: textmesh that I think could replace the backend of bevy_text_mesh and make it work on mac/wasm.

Opened an issue here: https://github.com/blaind/bevy_text_mesh/issues/20

Does your text actually need to be a 3d mesh? It seems like it should be relatively doable to get bevy_text working in 3d, even as a third party plugin but I'm not aware of anything existing.

analog moon
#

thank you for opening that! it doesn't need to be a mesh, i really just need to render it in 3d "space". i was going to try render-to-texture

analog moon
#

i was able to get something working using fontdue + image

rich forge
#

Im in the same boat, do you have anything to share?

analog moon
#

i based my code off of this: https://cs.github.com/mayabyte/caveripper/blob/d3d4754fa79dfc911f78e6ff2335f8beb76c79a6/caveripper/src/render.rs?q="color.0[0].saturating_add"#L848

which ends up being:

fn render_text(mut image_assets: &mut Assets<Image>) -> Handle<Image> {
    use fontdue::{
        layout::{CoordinateSystem, Layout, LayoutSettings, TextStyle},
        Font,
    };
    use image::{buffer::ConvertBuffer, DynamicImage, ImageBuffer};

    let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
    layout.reset(&LayoutSettings {
        ..Default::default()
    });
    let size = 64.0;
    {
        let fonts = &[ARIAL.deref()];
        layout.append(fonts, &TextStyle::new("hello", size, 0));
    }
    let glyphs = layout.glyphs();

    let width = layout
        .glyphs()
        .iter()
        .map(|g| g.x as usize + g.width)
        .max()
        .unwrap_or(0) as u32;
    let height = layout.height() as u32;
    let mut rgb = ImageBuffer::<image::Rgba<u8>, _>::new(width, height);

    for glyph in glyphs {
        let y_start = glyph.y as u32;
        let x_start = glyph.x as u32;
        let (metrics, bitmap) = ARIAL.rasterize_config(glyph.key);
        let color = image::Rgba::<u8>::from([255, 255, 0, 255]);
        for (i, v) in bitmap.into_iter().enumerate() {
            let x = (i % metrics.width) as i64 + glyph.x as i64;
            let y = (i / metrics.width) as i64 + glyph.y as i64;
            if x >= 0 && x < rgb.width() as i64 && y >= 0 && y < rgb.height() as i64 {
                rgb.put_pixel(
                    x as u32,
                    y as u32,
                    [
                        color.0[0].saturating_add(255 - v),
                        color.0[1].saturating_add(255 - v),
                        color.0[2].saturating_add(255 - v),
                        v,
                    ]
                    .into(),
                );
            }
        }
    }

    let rgb = image::imageops::flip_horizontal(&rgb);

    let rgb = DynamicImage::ImageRgba8(rgb);
    let rgb = Image::from_dynamic(rgb, false);
    let rgb = image_assets.add(rgb);

    rgb
}
rich forge
#

This works! 😄

#

Thank you!