I just read the text of the page you gave the link to. You can forget the top bunch of formulas and just use the bottom ones.
The formulas for x and y offset look a bit complicated, but a one sentence explanation is given.
Basically if you have let’s say 3x3 tiles then with xoffset and yoffset you compute a transformation that transforms the center of each tile to the right position.
In the case where you have only a single tile you will be using the nornaml NDC space where (-1, -1) is in the lower left (0,0) is in the center and (1,1) is in the upper right. For this xoffset and yoffset will become 0.
If you have say 3x3 tiles xoffset and yoffset need to be 0 for the middle tile with i=1 and j=1 (no offset just scaling which is not the case for your formula), while for the other tiles you need to move the center of the tile to the correct location.
You can’t work with the lower left hand corner as you need to line up the centers!
Edit: Try if you can get the formulas to work. I myself are not exactly sure why does formulas are supposed to work. If they don’t you have to come up with something yourself.
You can also use gluPickMatrix for this task.
Use the size of the high-resolution image for the “viewport” parameter. “x” and “y” represent the position of the curret tile inside the screenshot and “width/height” are set to the size of the tile. Set the viewport size of your actual render target to the tile size. The setup then looks like this:
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
GLint screenshotviewport[4]={0,0,screenshot_width, screenshot_height};
gluPickMatrix(tile_x, tile_y, tile_width, tile_height, screenshotviewport)
glFrustum() (or whatever you use to setup your projection)
glMatrixMode(GL_MODELVIEW)
glViewport(0,0, tile_width, tile_height);
...render your image
Special attention is needed, when the screenshot width or height is not an exact multiple of the tile size. In this case you get border-tiles that are smaller than normal tiles.
gluPickMatrix looks like it would be a lot simpler and easier. The only issue is that if I use it, and it restricts drawing to an area of a huge fake viewport, that area maybe outside the real viewport. Say the real viewport is 1280x800, and the high resolution image is 9000x9000, then there will be tiles totally off the screen (which then can’t be copied with glTexImage2D or glReadPixels, etc.). I could try giving negative x/y coords in the viewport to try and have the tile rest inside the window area, but I don’t know if OpenGL will accept negative values there.
@skynet: Sorry in my previous post I misunderstood you. I was thinking gluPickMatrix acted just like the scissor test, I didn’t realize it “zoomed in” too.
However, I can’t get this method to work. I just get a blank white area. Does any of this look incorrect?
// Don't pick a tile size bigger than the framebuffer because we need to use glReadPixels
// to get our screenshot
int tileWidth, tileHeight;
for(int i = 1; i < 1000; ++i) {
tileWidth = std::ceil(double(sceneWidth) / double(i));
tileHeight = std::ceil(double(sceneHeight) / double(i));
if( tileWidth < framebufferWidth &&
tileHeight < framebufferHeight)
break;
}
int nTilesX = std::ceil(double(sceneWidth) / double(tileWidth));
int nTilesY = std::ceil(double(sceneHeight) / double(tileHeight));
for(int y = 0; y < nTilesY; ++y) {
for(int x = 0; x < nTilesX; ++x) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLint fake_viewport[4] = { 0, 0, sceneWidth, sceneHeight };
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPickMatrix(x * tileWidth, y * tileHeight, tileWidth, tileHeight, fake_viewport);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, tileWidth, tileHeight);
// This calls gluOrtho2D using the given width/size, then renders the scene
m_primarySelection->ContentsRender(sceneWidth, sceneHeight);
glPopAttrib();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
// This takes a screenshot of the given window area using glReadPixels, then copies it onto a large final bitmap named
// composite_shot
compositor.DrawBitmap(*Screenshot(0, 0, tileWidth, tileHeight), x * tileWidth, sceneHeight - (y+1) * tileHeight);
}
}
composite_shot.SaveFile(fileDlg.GetFilename(), wxBITMAP_TYPE_PNG);
I figured it out. In case anyone has the same problem, the code above is correct except for 2 changes – glLoadIdentity() needs to be called after glPushMatrix(), and gluPickMatrix expects the given x/y to be the center of the tile, so you have to add tileWidth / 2.0 and tileHeight / 2.0.