Zooming around a point

In a new game I’m making, which I’ve done in LWJGL (woo first LWJGL only game!), I want to be able to zoom and pan around the map. I have that working now, but I want the zooming to be around whatever’s in the center of the map.

Right now, I have a 20x20 grid. If I hit zoom in enough times, the top left tile will fill up the whole area. This is done with:


GL11.glTranslatef((float)( X - xShift ), (float)( Y - yShift ), 0);
GL11.glScalef((float)zoom, (float)zoom, 0);
//all my happy drawing
GL11.glPopMatrix();

So I want it smarter so that when I zoom in, it doesn’t zoom about (0,0) but instead it zooms around whatever happens to be in the center of the screen. What’s the best way to do this?

Also, after that’s done, I want to be able to tell what’s under the mouse. AffineTransform is really nice because it let’s you pass it a coordinate and it’ll tell you where that coordinate is, and you can also ask for it to inversely transform the coordinates. Do I have an option like that with the OpenGL transformation matrix?

Are you using orthographic projection (glOrtho) or perspective projection (glFrustum) ?

ortho, it’s for a 2D game. I have a map in a box in a part of my screen and I want to be able to pan it and zoom it in a useful manner so that it’s easy to move around the map and still see details.

If its 2D via an ortho projection I find it more intuitive to do a zoom my altering the range of values to the glOrtho call - zooming just becomes a case of restricting the values so that the resulting area fills the screen.

Then assuming you’ve got a 2d camera with the position being the center of the screen you should be all set. If your camera position is based off of a screen corner then you might have to do some jiggery-pokery to offset it based on the current zoom (personally I’d just convert it to be centered of the point though).

Edit: Actually, if you reverse the order of your translate and scale ops, that might work as well…

If its for 3D, i suggest you alter the frustum instead of actually scaling and translating everything. I think this also works for 2d too…not sure.

Anyway, renanse from jmonkeyengine.com has this working nicely:

http://www.jmonkeyengine.com/index.php?option=com_content&task=view&id=52&Itemid=70&limit=1&limitstart=4

Its a dev diary, but all the code in there is relevant to what your doing.

DP

OrangyTang, I like where you’re going with that, but the only experience I have with the glOrtho stuff is when I initialize my display. Other than that I haven’t used it. Can you point me to where I can get more info on that? Also, you talked about having a camera. I don’t know if I have a camera. Are you referring to something built into OpenGL? All I know are basic OpenGL commands to help me do what I usually do in Java2D. I don’t know of any camera stuff I can use.

First you need to read the red book. This is mandetory if you are going to use OpenGL.

Then you can use the opengl man pages to look up the functions.

[quote]OrangyTang, I like where you’re going with that, but the only experience I have with the glOrtho stuff is when I initialize my display.
[/quote]
I typically setup the projection matrix (via glOrtho) at the start of rendering every frame, which makes it dead easy to tinker with the parameters. Just move your calls from your init (and remember to switch to and from PROJECTION_MATRIX).

[quote]Also, you talked about having a camera. I don’t know if I have a camera. Are you referring to something built into OpenGL? All I know are basic OpenGL commands to help me do what I usually do in Java2D. I don’t know of any camera stuff I can use.
[/quote]
A 2d camera class in OpenGL is dead easy, you basically just need to keep track of the current camera position and possibly some kind of zoom parameter. You can then just use it to setup your projection before every frame, something like:

// The following gets your 2d view with 0,0 at the center of the screen:
glMatrixMode(GL_PROJECTION);
glOrtho(-400, -300, +400, +300); // or better yet, use Display.getWidth() / 2 etc. rather than assuming 800x600

// Then translate the ‘camera’
glMatrixMode(GL_MODEL_VIEW);
glTranslatef(-cameraX, -cameraY, 0f); // negative 'cos we move the world around the camera

After that all your drawing calls can be made in world space, rather than manually offseting everything like you would for Java2d drawing. Just remember not to trash the modelview matrix during drawing (so remember to glPush/Pop when you modify it).

OK, I’ll be reading the Red Book then :slight_smile:

Orangy Tang, you talked about needing a zoom parameter, but didn’t actually show it used in your psuedo code. The only new code you showed was the glMatrixMode stuff and in attempting that either I just got an empty screen or I got the same screen I was used to. I’m not sure what to make of what you’ve shown me.

Also, if I’m going to be manipulating my screen like this with all the camera helper methods, how do I convert coordinates so that I know where my mouse is pointing?

ok, here’s the solution I found.


boardTrans.setTransform(1, 0, 0, 1, WIDTH/2, HEIGHT/2);
boardTrans.scale(zoom, zoom);
boardTrans.translate(X - xCenter, Y - yCenter);

I modify an AffineTransform that way, then I apply the transform to the OpenGL matrix using a handy method tom wrote for me in use for Rimscape (tom rocks!!). This transformation does the zooming I was hoping for perfectly.

Then I call the AffineTransform.inverseTransform() method which takes a Point2D and returns a Point2D, telling me exactly where my mouse coordinates are pointing in my transformed space. Woohoo! :slight_smile: