Changing the Coordinate System in LibGDX (Java)
Java2dSpriteCoordinate SystemsLibgdxJava Problem Overview
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?
Java Solutions
Solution 1 - Java
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.
Solution 2 - Java
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);
}
Solution 3 - Java
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.
Solution 4 - Java
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.
Solution 5 - Java
I just made a class that extends SpriteBatch
that overides certain methods adding y = Gdx.graphics.getHeight() - y - height
. Simple but effective.
Solution 6 - Java
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.