libGDX, BitmapFont, and OrthographicCamera

I think this question must have been asked and answered somewhere, but I can’t find it!

I’m using libGDX (mainly because of his Android painless portability). I have setup a OrthographicCamera so my OpenGL coordinates are from -1f to 1f in the Y direction and from -ar to ar in the X direction (ar is a float with the aspect ratio of the screen resolution). Some code:

@Override
public void resize(int width, int height)
{
    float ar = (float) width / (float) height;
    camera = new OrthographicCamera(2f*ar, 2f);
}

In the game create() overridden method I setup a font using BitmapFont.

@Override
public void create()
{
    sb = new SpriteBatch();
    font = new BitmapFont(Gdx.files.internal("menuFont.fnt"), Gdx.files.internal("menuFont.png"), false);
}

Finally, in the render() method I update the camera, update the projection matrix in the SpriteBatch, and draw the font:

@Override
public void render()
{
    camera.update();
    camera.apply(Gdx.gl10);
    sb.setProjectionMatrix(camera.combined);    // HERE

    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

    sb.begin();
        font.draw(sb, "Hola mundo", -100f, 10f);
    sb.end();
}

This way, the font gets huge on the screen! (I could only see part of a letter).

What I want to do is to use OpenGL coordinates to position the text on the screen, but without any annoying scaling. I can disable the font scaling not passing the projection matrix to the SpirteBatch, i.e., commenting line with the “// HERE” comment. But can’t use OpenGL coordinates.

This must be a misconception I bear, but can’t figure it out!

Thanks in advance for any comment :slight_smile:

If you want to use openGl coords why you pass -100,10 coordinates?
Another point is that you don’t set the size of the font anywhere.

That’s just to see something on screen. If I use -.5f, .5f I see nothing, but that’s the coordinate system I want to use.

You mean with BitmapFont.setScale(float) method?

Hmm, I guessed that since BitmapFont produces text by packing the font glyphs from a texture, it behaves like a texture. Following the “Projection, Viewport, and Camera” tutorial on libGDX, it seemed to me that you don’t need to do scalings on the texture.

Defaul size is the pixel perfect size that is readed from .fnt
So I bet yout font size is something like 32 and its not gonna show with openGL coordibnates properly.

Can I ask why you want to use openGL coordinates for fonts?

Thanks for your time!

Why I want to use OpenGL coordinates? Good question.

It all boils down to placing text and sprites in a fixed coordinate system which is easy for me to understand. For example, using the OpenGL coordinate system from -.5f to .5f I can easily calculate the middle (.25f), quarter (.125f), etc. positions without having to access to the screen resolution (ScreenSettings.WIDTH/2f, for example). In addition, my idea is to adjust the viewport to the OpenGL scene, so multiple screen resolutions have the same appearance.

This mustn’t be a good way to achieve that, but can’t think of a better way to support multiple resolutions without having to hardcode them ony by one.

Do you have any suggestions?

The glyph positions in the BitmapFont use pixel units. Eg, it is going to draw a glyph 14 units wide and 24 units high. If your camera is setup to map 1:1 with pixels, it will render at the size you expect.

You could try setting the scale on the BitmapFont so the units it uses are appropriate for your camera. You don’t want your font scaled at all though, or it will look bad!

You could use a camera that maps 1:1 with screen pixels. Your model could use whatever coordinate system you like, and you would convert to pixels only for drawing.

You could use scene2d and layout stuff using Table, which can give you layouts that work at different resolutions.

I allways use meters size with my camera becouse I allways use box2d with my games. So in game my camera size is something like 25x15 but I dont use that camera for my UI or HUD’s becouse I want static camera for my text and buttons. I also dont want to scale fonts much becouse then it look crappy. I have two solutions for this either is that I use pixel perfect matrix for UI. This work great if I only want draw simple text on left corner eg fps counter. But for ui where I have to do positioning etc I allways use 800x480 projection. Then I can desing UI using these coordinates but it will work also for every screensize. Font don’t look super crappy If I use linear filtering and only scaled 0.5-1.5 its base size.


Matrix4 normalProjection = new Matrix4().setToOrtho2D(0, 0, 800,480);

//setting linear filtering
font.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);

I think I was dealing with two problems at the same time:

  • Displaying the same scene in different resolutions with the same aspect ratio.
  • Displaying fonts positioned using openGL space.

I have dealt with the first problem using a fixed camera for a fixed (virtual) resolution, and modifying the viewport for each (physical) resolution. I’ll try to make a blog post about this, because I think it’s complicated to explain in words, but could be interesting for others (or for me if anyone thinks it’s not the best way to accomplish it).

About the second problem, thanks for your insightful comments.

That sounds like what I want to do. When you say “you convert to pixels only for drawing” you mean I could set my sprites/fontCaches positions in my coordinates and then, in render() convert them using an custom utility class especially crafted for that? Or is there something more optimized (less custom)?

Yes, I’m thinking on working on 480x320 coordinates (that’s what’s called “pixel perfect” coordinates? I get lost easily…) and then scale using the linear filter for the font. Thanks for the code, it helps me a lot! Sometimes it’s way better to use code/mathematics to explain concepts :slight_smile:

I made a “tutorial” with the “keeping the aspect ratio” idea I had and took the liberty of posting it in the tutorial section (here :point: visit it!).

All comments are welcomed!