TR - OpenGL Tile Rendering Library

Version 1.1

Copyright (C) 1997 Brian Paul



Introduction

The TR (Tile Rendering) library is an OpenGL utility library for doing tiled rendering. Tiled rendering is a technique for generating large images in pieces (tiles).

TR is memory efficient; arbitrarily large image files may be generated without allocating a full-sized image buffer in main memory.

The TR library is copyrighted by Brian Paul. See the LICENSE file for details.

You may download TR 1.1 from by SHIFT-clicking on one of the following:



Prerequisites

TR works with any version of OpenGL or Mesa. No extensions are necessary and there are no dependencies on GLX, WGL or any other window system interface.

TR is written in ANSI C and may be used from C or C++.

The TR demo programs require Mark Kilgard's GLUT.

Users should have intermediate experience with OpenGL.



Example

The following image is divided into four rows and three columns of tiles. Note that the image size is not an exact multiple of the tile size. The TR library handles the situation in which the top row and right column are a fraction of the full tile size.

Also note that the tiles do not have to be square.

This is a small example. In reality, one may use tiles of 512 by 512 pixels and the final image may be 4000 by 3000 pixels (or larger!).



Using the Library

Ordinarily, OpenGL can't render arbitrarily large images. The maximum viewport size is typically 2K pixels or less and the window system usually imposes a maximum color buffer size.

To overcome this limitation we can render large images in pieces (tiles).

To render each tile we must carefully set the viewport and projection matrix and render the entire scene. The TR library hides the details involved in doing this. Also, TR can either automatically assemble the final image or allow the client to write the image, row by row, to a file.

The basic steps in using TR are as follows:

1. Determine where you'll render the tiles

Tiles may be rendered either in a window (front or back buffer) or in an off-screen buffer. The choice depends on your application. It doesn't matter to the TR library since TR just retrieves image tiles with glReadPixels. Just be sure glDrawBuffer and glReadBuffer are set to the same buffer.

2. Determine the destination for the final image

The final, large image may either be automatically assembed in main memory by TR or you may elect to process tiles yourself, perhaps writing them to an image file.

3. Isolate your drawing code

It should be a simple matter to completely re-render your OpenGL scene. Ideally, inside the tile rendering loop you should be able to make one function call which clears the color (and depth, etc) buffer(s) and draws your scene. If you're using a double buffered window you should not call SwapBuffers since glReadBuffer, by default, specifies the back buffer.

4. Allocate a TR context

Every TR function takes a TRcontext pointer. A TR context encapsulates the state of the library and allows one to have several TR contexts simultaneously. TR contexts are allocated with trNew.

5. Set the image and tile sizes

Call trImageSize to set the final image size, in pixels. Optionally, call trTileSize to set the tile size. The default tile size is 256 by 256 pixels with 0 border. Generally, larger tiles are better since fewer tiles (and rendering passes) will be needed.

6. Specify an image or tile buffer

If you want TR to automatically assemble the final image you must call trImageBuffer to specify an image buffer, format, and pixel type. The format and type parameters directly correspond to those used by glReadPixels.

Otherwise, if you want to process image tiles yourself you must call trTileBuffer to specify a tile buffer, format, and pixel type. The trEndTile function will copy the tile image into your buffer. You may then use or write the tile to a file, for example.

7. Optional: set tile rendering order

Since OpenGL specifies that image data are stored in bottom-to-top order TR follows the same model. However, when incrementally writing tiles to a file we usually want to do it in top-to-bottom order since that's the order used by most file formats.

The trRowOrder function allows you to specify that tiles are to be rendering in TR_TOP_TO_BOTTOM order or TR_BOTTOM_TO_TOP order. The later is the default.

8. Specify the projection

The projection matrix must be carefully controlled by TR in order to produce a final image which has no cracks or edge artifacts.

OpenGL programs typically call glFrustum, glOrtho or gluPerspective to setup the projection matrix. There are three corresponding functions in the TR library. One of them must be called to specify the projection to use. The arguments to the TR projection functions exactly match the arguments to the corresponding OpenGL functions.

9. Tile rendering loop

After the tile size and image size are specified the TR library computes how many tiles will be needed to produce the final image.

The tiles are rendered inside a loop similar to this:

int more = 1;
while (more)
{
	trBeginTile(tr);
	DrawScene();
	more = trEndTile(tr);
}

This should be self-explanatory. Simply call trBeginTile, render your entire scene, and call trEndTile inside a loop until trEndTile returns zero.

10. Query functions

The trGet function can be called to query a number of TR state variables such as the number of rows and columns of tiles, tile size, image size, currently rendered tile, etc. See the detailed description of trGet below.

11. glRasterPos problem

The glRasterPos function is troublesome. The problem is that the current raster position is invalidated if glRasterPos results in a coordinate outside of the window. Subsequent glDrawPixels and glBitmap functions are ignored. This will frequently happen during tiled rendering resulting in flawed images.

TR includes a substitute function: trRasterPos3f which doesn't have this problem. Basically, replace calls to glRasterPos with trRasterPos. See the included demo programs for example usage.

12. Compilation

Include the tr.h header file in your client code.

Compile and link with the tr.c library source file. There is no need to compile TR as a separate library file.



API Functions

Creating and Destroying Contexts

TRcontext *trNew(void)
Return a pointer to a new TR context and initialize it. Returns NULL if out of memory.
void trDelete(TRcontext *tr)
Deallocate a TR context.

Image and Tile Setup Functions

void trTileSize(TRcontext *tr, GLint width, GLint height, GLint border)
width and height specifies size of tiles to generate. This should be no larger than the size of your window or off-screen image buffer.
border specifies how many pixels along each edge are to be uses as a border.
Borders provide overlap between adjacent tiles and are needed when drawing wide lines (width > 1) or large points (size > 1). The effective tile size is therefore width - 2 * border by height - 2 * border pixels.
void trImageSize(TRcontext *tr, GLint width, GLint height)
Specifies size of final image to generate.
void trTileBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image);
This is an optional function. After a tile is rendered (after trEnd) it will be copied into the buffer specified by this function.
image must point to a buffer large enough to hold an image equal to the tile size specified by trTileSize, minus any border.
format and type are interpreted in the same way as glReadPixels.
void trImageBuffer(TRcontext *tr, GLenum format, GLenum type, GLvoid *image);
This is an optional function. This specifies a buffer into which the final image is assembled.
As tiles are generated they will automatically be copied into this buffer. The image will be complete after the last tile has been rendered.
image must point to a buffer large enough to hold an image equal to the size specified by trImageSize.
format and type are interpreted in the same way as glReadPixels.

Note: trImageBuffer and trTileBuffer are the means by which image data is obtained from the TR library. You must call one (or both) of these functions in order to get output from TR.

void trRowOrder(TRcontext *tr, TRenum order)
Specifies the order in which tiles are generated.
order may take one of two values:

Projection Setup Functions

void trOrtho(TRcontext *tr, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
Specify an orthographic projection as with glOrtho.
Must be called before rendering first tile.
void trFrustum(TRcontext *tr, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
Specify a perspective projection as with glFrustum.
Must be called before rendering first tile.
void trPerspective(TRcontext *tr, GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar );
Specify a perspective projection as with gluPerspective.
Must be called before rendering first tile.

Tile Rendering Functions

trBeginTile(TRcontext *tr)
Begin rendering a tile.
int trEndTile(TRcontext *tr)
End rendering a tile.
Return 0 if finished rendering image.
Return 1 if more tiles remain to be rendered.

The trBeginTile and trEndTile functions are meant to be used in a loop like this:

int more = 1;
while (more)
{
	trBeginTile(tr);
	DrawScene();
	more = trEndTile(tr);
}

DrawScene is a function which renders your OpenGL scene. It should include glClear but not SwapBuffers.

Miscellaneous Functions

GLint trGet(TRcontext *tr, TRenum param)
Query TR state. param may be one of the following:

Note the difference between TR_TILE_WIDTH/HEIGHT and TR_CURRENT_TILE_WIDTH/HEIGHT. The former is the size of the tile buffer. The later is the size of the current tile which can be less than or equal to the TR_TILE_WIDTH/HEIGHT. Unless the final image size is an exact multiple of the tile size, the last tile in each row and column will be smaller than TR_TILE_WIDTH/HEIGHT.

void trRasterPos3f(TRcontext *tr, GLfloat x, GLfloat y, GLfloat z)
This function is a replacement for glRasterPos3f. The problem with the OpenGL RasterPos functions is that if the resulting window coordinate is outside the view frustum then the raster position is invalidated and glBitmap becomes a no-op.

This function avoids that problem.

You should replace calls to glRasterPos with this function. Otherwise, glRasterPos/glBitmap sequences won't work correctly during tiled rendering.

Unfortunately, trRasterPos3f can't be saved in a display list.



Notes

More on Tile Borders

A tile border should be used when drawing any of:

By using a tile border, rendering artifacts (pixel drop-outs) at tile boundaries can be eliminated.

Suppose you call glTileSize(tr, W, H, B). TR will render tiles of W by H pixels of which B pixels along each edge overlap the adjacent tiles. Therefore, the image buffer specified by calling glTileBuffer() must only be large enough to hold an image of W-2*B by H-2*B pixels.



Demonstration Programs

The TR distribution includes two GLUT-based demo programs:

You'll probably have to edit the Makefile for your computer. Compiling the demos is very simple though since they only require OpenGL and GLUT.



Contributors



Version History

Version 1.0 - April 1997

Version 1.1 - July 1997



Document created on April 19, 1997. Last edited on December 15, 1997.