58
votes

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?

6
sure, that's kind of what I'm doing right now. But is there any way to flip the coordinate system. Something like creating a projection matrix with the coordinate system that I want. Or telling the Spritebatch to draw according to a certain coordinate system... I've been looking like crazy, but I can't seem to find anything in particular... (and if so, whats the actual code)Sosavpm
This is indeed a nightmare. Things like SpriteBatch and sprites go from bottomleft. Things like input and textureregion go from top left. Resulting in super awkward coding and turning around things in your mind so often your eyes start to pop out. Anyway, i recommend getting used to it, turning around the camera results in flipped images and then you need to flip everything back, but not everything just most of the things and having them draw expectedly unexpectedly. LibGDX is awesome, but the coordinate system has serious issues. Better get used to it.Madmenyo

6 Answers

125
votes

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.

9
votes

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);
}
6
votes

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.

5
votes

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

1
votes

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

0
votes

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.