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

Crisp text #263

Closed
rikchilvers opened this issue Jan 23, 2018 · 14 comments
Closed

Crisp text #263

rikchilvers opened this issue Jan 23, 2018 · 14 comments

Comments

@rikchilvers
Copy link

I'm building a roguelike using ggez. So far it's going well but I can't get the text to not be fuzzy. Is it something I'm doing wrong, a current limitation of ggez/rusttype or something else? I'm using a .ttf font – should I use a bitmap one?

Thanks!

@fu5ha
Copy link
Contributor

fu5ha commented Jan 23, 2018

What do you mean by 'fuzzy'? Perhaps a screenshot would help diagnose the issue or find a solution.

@dannyfritz
Copy link
Contributor

dannyfritz commented Jan 23, 2018

Try flooring the pixel values to be integers or integers + 0.5. So if x=1.1, try both 1.0 and 1.5 when you draw it. Haven't tested it, but this usually does the trick.

@icefoxen
Copy link
Contributor

icefoxen commented Jan 23, 2018

You can also make sure the Text FilterMode is set to Nearest, see https://docs.rs/ggez/0.4.0/ggez/graphics/struct.Text.html#method.set_filter , which will keep the texture from being filtered/antialiased as it's scaled up or down.

Rusttype will do a little bit of anti-aliasing for you and I don't think it can be turned off from how ggez currently uses it. This is generally actually what you want; curves and such look awful otherwise. Usually you want to make sure to render the font at the actual size that it's going to be displayed at on the screen, and not rescale it after that.

If you absolutely need pixel-perfect control over font and can't make rusttype do what you want, that's generally what bitmap fonts are for. Still, I would hope you can get good results out of a .ttf font. Screenshots might help us figure something out.

@rikchilvers
Copy link
Author

rikchilvers commented Jan 24, 2018

Thanks for the ideas!

What do you mean by 'fuzzy'?

Yes, sorry for the vagueness. Here's a picture of Brogue and a little bit of my roguelike side-by-side, both are using the Monaco font.
brogue and ggez
I admit the difference is slight. However, in ggez you can see the pixels within the font which are not visible in Brogue. It's particularly apparent on the #. I've zoomed in to show the difference:

brogue

ggez

Try flooring the pixel values to be integers or integers + 0.5.

For the Text's position? Everything is u32's. I've tried setting the position.x/y to + 0.5 and it didn't have any effect.

You can also make sure the Text FilterMode is set to Nearest

So far, I haven't been able to get this to make a difference.

Could it be to do with being on a retina screen?

@icefoxen
Copy link
Contributor

What point size are you rendering the font at?

@rikchilvers
Copy link
Author

rikchilvers commented Jan 24, 2018

13 (my cells are 18x18px but the text comes out too large so I reduce it to fit - 13pt seems to fit well in 18x18px cells).

It gets loaded like this:

pub fn load_font<P>(&mut self, context: &mut Context, path: P)
where
    P: AsRef<path::Path> + fmt::Debug,
{
    // reduce the font size relative to the cell_size so it fits
    if let Ok(font) = graphics::Font::new(context, path, self.cell_size - self.font_fudge) {
        self.font = Some(font);
    }
}

and then rendered like this (I know I shouldn't really create a text object every frame):

fn draw_glyph(
    &self,
    context: &mut Context,
    glyph: char,
    pos: graphics::Point2,
    color: graphics::Color,
) {
    if let Some(ref f) = self.font {
        if let Ok(mut text) = graphics::Text::new(context, &glyph.to_string(), &f) {
            text.set_filter(graphics::FilterMode::Nearest);
            graphics::set_color(context, color).expect("couldn't set color while drawing text");
            graphics::draw(context, &text, position, 0.0).expect("couldn't draw text");
        }
    }
}

@icefoxen
Copy link
Contributor

And if you render it larger and resize it down when drawing, how does it look?

@rikchilvers
Copy link
Author

rikchilvers commented Jan 24, 2018

The text is clearer. This is the text rendered at 42pt –
42
And zoomed in –
42 zoom
And next to the same thing in Word (though I had to set the text size to 62 in Word to get the sizes to roughly match) –
word comparison
ggez is on the right, Word on the left.

@fu5ha
Copy link
Contributor

fu5ha commented Jan 24, 2018

I think part of what you're seeing here is brogue taking advantage of the retina screen on your macbook while ggez is not. I don't really know what the solution is for that (I think there was somone who had, in theory, added support for retina/hidpi displays in the past but I dont know if that has since broken or even exaclty what it did). What happens if you render the font at 42px like you have now and then scale it down appropriately to size when you draw it?

@rikchilvers
Copy link
Author

Ah, that makes sense. Text looks significantly crisper if I render and then resize - good plan! Thanks for all your help.

@icefoxen
Copy link
Contributor

If you want smoother text, you are going to need to tell ggez to render the text with more pixels. You do this by setting the points parameter in Font:new(). This is in units of points, not pixels. 72 points = 1 inch.

ggez will attempt to get what DPI your screen is at and scale the font accordingly to show up at the Right Size, see here: https://github.com/ggez/ggez/blob/master/src/graphics/text.rs#L52-L75 However, this depends on actually having correct information for what your monitor's DPI is, which some systems (Retina for example) may lie about. There's an allow_highdpi option on WindowSetup, so fiddle with that and see if you get different results. Though it disappears down a rabbit-hole of a single SDL call so I don't actually know what it does or how, and can't do a whole lot if it does the wrong thing.

I'd love to actually get this to work properly but I don't have a Retina screen to test on.

Long story short: Create a bigger font until it looks as smooth as it should, then scale it down.

@icefoxen icefoxen reopened this Jan 24, 2018
@rikchilvers
Copy link
Author

Alrighty – with allow_highdpi and doubling the point size and then halving when drawing, the text looks really smooth. Thanks!

A quick bit of googling says that Retina screens have twice the pixel density so this all makes sense now. I wonder if this means all assets need to be 2x?

@icefoxen
Copy link
Contributor

Resolved. 😢 See #587 for basically the reason why.

@jgarvin
Copy link

jgarvin commented Jul 28, 2020

This says "Resolved" but I still see it in 0.5.1 on Linux. The fix to render twice the size font you want and scale it by half when you draw also still works. For future readers, to scale by half when you draw your text object:

        let params = ggez::graphics::DrawParam::default()
            .scale(mint::Vector2 { x: 0.5, y: 0.5 })
            .dest(chunk.position);
        ggez::graphics::draw(ctx, &your_text_object, params)?;

JonathanMurray added a commit to JonathanMurray/chip-8-rs that referenced this issue Apr 1, 2021
JonathanMurray added a commit to JonathanMurray/chip-8-rs that referenced this issue Apr 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants