2d – Changing the Coordinate System in LibGDX (Java)-ThrowExceptions

Exception or error:

LibGDX has a coordinate system where (0,0) is at the bottom-left. (like this image: http://i.stack.imgur.com/jVrJ0.png)

This has me beating my head against a wall, mainly because I’m porting a game I had already made with the usual coordinate system (where 0,0 is in the Top Left Corner).

My question: Is there any simple way of changing this coordinate system?

How to solve:

If you use a Camera (which you should) changing the coordinate system is pretty simple:

camera= new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

If you use TextureRegions and/or a TextureAtlas, all you need to do in addition to that is call region.flip(false, true).

The reasons we use y-up by default (which you can easily change as illustrated above) are as follows:

  • your simulation code will most likely use a standard euclidian coordinate system with y-up
  • if you go 3D you have y-up
  • The default coordinate system is a right handed one in OpenGL, with y-up. You can of course easily change that with some matrix magic.

The only two places in libgdx where we use y-down are:

  • Pixmap coordinates (top upper left origin, y-down)
  • Touch event coordinates which are given in window coordinates (top upper left origin, y-down)

Again, you can easily change the used coordinate system to whatever you want using either Camera or a tiny bit of matrix math.

Answer:

Just to expand a little on what badlogic said above, if you are using a TextureAtlas (with TextureRegions) you need to flip them, as badlogic said, in addition to the camera work. If you are using a TextureAtlas, you can use this code right after loading your atlas:

String textureFile = "data/textures.txt";  
atlas = new TextureAtlas(Gdx.files.internal(textureFile), Gdx.files.internal("data"));  
// Let's flip all the regions.  Required for y=0 is TOP
Array<AtlasRegion> tr = atlas.getRegions();      
for (int i = 0; i < tr.size; i++) {
  TextureRegion t = tr.get(i);
  t.flip(false, true);
}

Answer:

If you want to hide the transformation and not think about it after setting it up once, you can make a class that inherits all of the functionalities you need, but first transforms the coordinates before passing it to its parent class’s function. Unfortunately, this would take a lot of time.

You could alternatively make a method that does the simple y' = height - y transformation on the whole Coordinate object (or whatever it is you’re using), and call it once before each operation.

Answer:

Interesting graphics library, I would say. I found this assessment from the link below:

Another issue was that different coordinate systems were used in different parts of Libgdx. Sometimes the origin of the axes was in the
bottom left corner with the y-axis pointing upwards and sometimes in
the top left corner of the sprite pointing downwards. When drawing
Meshes the origin was even in the center of the screen. This caused
quite a bit of confusion and extra work to get everything in the
correct place on the screen.

http://www.csc.kth.se/utbildning/kandidatexjobb/datateknik/2011/rapport/ahmed_rakiv_OCH_aule_jonas_K11072.pdf

Answer:

I just made a class that extends SpriteBatch that overides certain methods adding y = Gdx.graphics.getHeight() - y - height. Simple but effective.

Answer:

Not sure if this helps anyone or not but I was able to get textures and fonts rendering correctly using the suggested flipped coordinate system via OrthographicCamera. Here’s what I did:

private SpriteBatch batch;
private BitmapFont font;
private OrthographicCamera cam;
private Texture tex;

@Override
public void create () {
    batch = new SpriteBatch();

    font = new BitmapFont(true);
    font.setColor(Color.WHITE);

    cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    cam.setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    tex = new Texture("badlogic.jpg");
}

@Override
public void dispose() {
    batch.dispose();
    font.dispose();
    tex.dispose();
}

@Override
public void render () {
    cam.update();
    batch.setProjectionMatrix(cam.combined);

    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.begin();

    font.draw(batch, "Test", 50, 50);
    batch.draw(tex, 100, 100, tex.getWidth(), tex.getHeight(), 0, 0, tex.getWidth(), tex.getHeight(), false, true);

    batch.end();
}

Important things to notice are:

  • The BitmapFont constructor, the boolean flips the font
  • For batch.draw() you need to use all those parameters because you need a boolean flipY at the end to flip the texture (I may extend SpriteBatch or make a utility method to avoid passing so many parameters all the time.)
  • Notice batch.setProjectionMatrix(cam.combined); in render()

Now we will see if I am back here later tonight doing edits to fix any other issues or discoveries with doing all this. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *