I haven’t tested the following but I figure that the zoom and translate code should look something like this.
Say initially your viewport is 300 x 300 pixels, your zoom factor is 1 and your projection matrix is a 10 x 10 x 10 box. Then you could define the following.
double zoom_factor = 1
glMatrixMode(GL_PROJECTION)
glOrtho(0, 10, 0, 10, 0, 10)
When you change the zoom you could do the following.
glTranslated(-10 / (zoom_factor * 2), -10 / (zoom_factor * 2), 0)
zoom_factor = new_zoom_factor
glMatrixMode(GL_PROJECTION)
glOrtho(0, 10 / zoom_factor, 0, 10 / zoom_factor, 0, 10)
xratio = 10 / (zoom_factor * 300)
yratio = 10 / (zoom_factor * 300)
glMatrixMode(GL_MODELVIEW)
glTranslated(10 / (zoom_factor * 2), 10 / (zoom_factor * 2), 0)
I use glTranslated() at the start and end of the code section to keep the zoom centred. The first translate uses the old zoom, the second the new zoom. Without the translations it will zoom in on the bottom left portion of the screen. If you want it to zoom on an arbitrary point the first translation should translate that point to the bottom left corner of the screen in OpenGL. The last translation remains and will centre the screen on the desired point.
The move ratios (xratio, yratio) indicate how much you should scale mouse movement by. It’s calculated as xratio = 3Dwidth/ViewportWidth, yratio = 3Dheight/ViewportHeight. Note that I assumed an aspect ratio of 1 (300 x 300 viewport). If not the right or x value should be (10 * aspect) / (zoom_factor …)
Then when you’re mouse moves just do the following.
glTranslated(xratio * -mousemove.x, yratio * -mousemove.y, 0)
mousemove is in window coordinates. I use -y cause windows y goes top down, while opengl y goes bottom up.