Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Font rendering fails to draw characters on screen #607

Closed
Tracked by #552
rodya-mirov opened this issue May 16, 2020 · 14 comments · Fixed by #642
Closed
Tracked by #552

Font rendering fails to draw characters on screen #607

rodya-mirov opened this issue May 16, 2020 · 14 comments · Fixed by #642
Labels
bug Some API breaks the contract it establishes subsystem-graphics

Comments

@rodya-mirov
Copy link

rodya-mirov commented May 16, 2020

Text issue

Right. I'm starting to understand.

I have a new problem -- this may actually be a bug with the font renderer.

I have a font (mononoki) which worked well with the 0.3 branch. When I attempt the layout_glyphs function on the string "Hello, Quicksilver", with font size 72, the returned vector is (643,16). 16 here is much too small; it looks like this is returning the amount of whitespace above the text (???). If I try it with another font (square) it works even worse -- the returned height is 0. This returned value is the same as if I use draw.

This appears to be a real issue -- if I just attempt to render the text directly with the font, it still comes up as nothing. The only way I can tell the render is even being attempted is that the tiny image above really is being created (and if I gfx.clear it to a different color before flushing, I can see that color). So it does look like the font rendering is doing something wrong with the height (the width looks plausible).


Original issue

Describe the bug
I'm looking at the 0.4 branch, basically because it looks great and because working with lots of Asset in the 0.3 branch is ... rough. Not a fan.

But look at https://github.com/ryanisaacg/quicksilver/blob/master/examples/07_text.rs
If you use quicksilver = "0.4.0-alpha0.3" in Cargo.toml, you'll see that doesn't compile. Most of the imports can be fixed (although how did this even happen?); Settings is under lifecycle, and so on. prelude seems to be gone completely, which is rough.

But the real killer is that the examples show you moving the plot along by doing while let Some(foo) = input.next_event().await { /* stuff */ }.

This looks like a great API; however, there is no Input type anywhere in the docs that I can find!

To Reproduce
Steps: pull latest cargo branch, copy paste example, hit compile
Expected: code compiles
Actual: code does not compile

Environment and versions (please complete the following information):

  • Environment: macOS Catalina
  • Rust compiler version: 1.41.1
  • Quicksilver verison: 0.4.0-alpha0.3
@rodya-mirov
Copy link
Author

I see now that the published 0.4.0-alpha0.3 is not current with master. But still not sure what is intended here.

I do realize "alpha" means "not ready" so if filing these issues is annoying instead of helpful I can close it. I'm excited about 0.4!

@lenscas
Copy link
Contributor

lenscas commented May 16, 2020

the lifecycle vs input has to do with #604

In short: the name changed because input is a better fit

@ryanisaacg
Copy link
Owner

@rodya-mirov Definitely file any issues you run into, even if you're not sure if the problem is on your end or the project's. In this case, there has been a breaking change since the last release. I'll make a new release soon to correct this.

The equivalent for prelude in 0.4 is just glob importing use quicksilver::*;. The crate root (in the upcoming release, that is) will contain run, Settings, Graphics, Input, Window, etc.

@rodya-mirov
Copy link
Author

Great, thank you!

By the way -- I was working from the roguelike tutorial you linked in the docs, as a starting place (code only works in 0.3). In the old way it was clear how to use a Font to render to an image, which is nice if you need to redraw it frequently. But there doesn't seem to be a way to do that with the new API. Did I miss something?

@lenscas
Copy link
Contributor

lenscas commented May 16, 2020

In the 0.4 way you can render text to a texture using Graphics::set_surface(). You can also get every glyph (together with where they should go, how big they are, etc,etc) using FontRenderer:layout_glyphs.

However, as you ask specifically about that being nice for when you need to redraw it a lot of times. If I understand the current system correctly, then this caching is already done for you. From the docs

A FontRenderer pairs a font source (typically a VectorFont or bitmap font) and a GPU cache for efficient rendering

Instead of uploading glyphs to the GPU every time they're drawn, this method allows for future draws to reference these glyphs multiple times.

@rodya-mirov rodya-mirov changed the title Examples do not compile in 4.0 branch; no obvious "Input" exists Examples do not compile in 0.4.0 branch; no obvious "Input" exists May 16, 2020
@rodya-mirov
Copy link
Author

rodya-mirov commented May 16, 2020

@lenscas I'm looking through the docs for Surface now and I'm certainly confused. It doesn't seem to be as simple as you say (just calling a method). I see that I can create a new Surface and somehow attach a Texture to it, but I don't see how to create a Texture without already having a Context, which I can only get by consuming the Graphics object, or by creating a new one somehow ...

At the moment I'm writing a bunch of text to an image then slicing it up into subimages so I can get an image for each character (basically a quick-and-dirty tileset). At this point it's probably simpler to just make a proper tileset (but, bleh).

Edit: I came up with this. I still feel like I'm holding it wrong. Is this the intended use of the APIs?

    // TODO: persist this renderer since constructing it was probably expensive
    let mut renderer = VectorFont::load(FONT_MONONOKI_PATH)
        .await?
        .to_renderer(gfx, size)?;

    let size: Vector = renderer.layout_glyphs(gfx, text, None, |_, _| {})?;

    let img: Image = Image::from_raw(gfx, None, size.x as u32, size.y as u32, PixelFormat::RGBA);
    let surface: Surface = Surface::new(gfx, img);

    gfx.fit_to_surface(&surface)?;
    renderer.draw(gfx, text, color, (0, 0).into())?;

    gfx.flush(Some(&surface))?;

    let img = surface.detach().expect("We attached an image, so one had better come back out");

    Ok(img)

@ryanisaacg
Copy link
Owner

You're essentially doing what the Font API now does for you. If you render the string "Hello world!", a texture on the GPU is updated to contain "Helowrd!" Each FontRenderer retains (within reason) every glyph rendered through it, so you don't need to write all the glyphs into a texture for safekeeping.

However, you are holding the Surface API right in this example.

@rodya-mirov
Copy link
Author

Okay -- but would there be a way to use the Font API to render to a surface?

@ryanisaacg
Copy link
Owner

Rendering to a Surface is the same as rendering to a Graphics instance; your code above works, but isn't needed if you're just worried about performance.

@rodya-mirov
Copy link
Author

Right. I'm starting to understand.

I have a new problem -- this may actually be a bug with the font renderer.

I have a font (mononoki) which worked well with the 0.3 branch. When I attempt the layout_glyphs function on the string "Hello, Quicksilver", with font size 72, the returned vector is (643,16). 16 here is much too small; it looks like this is returning the amount of whitespace above the text (???). If I try it with another font (square) it works even worse -- the returned height is 0. This returned value is the same as if I use draw.

This appears to be a real issue -- if I just attempt to render the text directly with the font, it still comes up as nothing. The only way I can tell the render is even being attempted is that the tiny image above really is being created (and if I gfx.clear it to a different color before flushing, I can see that color). So it does look like the font rendering is doing something wrong with the height (the width looks plausible).

@ryanisaacg
Copy link
Owner

Hm. Is this font open-source (e.g. can you link to a TTF I can try?)

@lenscas
Copy link
Contributor

lenscas commented May 17, 2020

I'm guessing it is https://madmalik.github.io/mononoki/

@rodya-mirov
Copy link
Author

It is, yes. I don't have laptop access handy at the moment but the case with Square (where the height came out to be zero) was even more egregious and so may be easier to debug. It was also linked in the roguelike tutorial that your docs link.

@ryanisaacg ryanisaacg changed the title Examples do not compile in 0.4.0 branch; no obvious "Input" exists Font rendering fails to draw characters on screen May 17, 2020
@ryanisaacg ryanisaacg added bug Some API breaks the contract it establishes subsystem-graphics labels May 17, 2020
@ryanisaacg
Copy link
Owner

ryanisaacg commented Jun 2, 2020

Sorry that I've taken a little while to address this, but I have no trouble rendering "Hello, Quicksilver" with mononoki on windows:

image

or on macOS Mojave:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Some API breaks the contract it establishes subsystem-graphics
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants