summaryrefslogtreecommitdiffstats
path: root/src/classes/com/sun/opengl/util
diff options
context:
space:
mode:
authorKenneth Russel <[email protected]>2006-02-02 22:11:38 +0000
committerKenneth Russel <[email protected]>2006-02-02 22:11:38 +0000
commitb299012e07363172d040fc3ae3d5f751cf1c9740 (patch)
tree9feee40c8db3e97732056674486a00cf2d5d2131 /src/classes/com/sun/opengl/util
parent25d1c7512a02d7a34af2583b94da944fa1adee92 (diff)
Fixed Issue 199: Incorporate tile rendering library
With the permission of the author, Brian Paul, the Mesa tile rendering library has been incorporated under BSD-compatible licensing terms thanks to porting work by user bleb from the javagaming.org forums. Added demos.misc.TiledRendering demo creating a high-resolution screenshot of the Gears demo. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@580 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/classes/com/sun/opengl/util')
-rwxr-xr-xsrc/classes/com/sun/opengl/util/TileRenderer.java600
1 files changed, 600 insertions, 0 deletions
diff --git a/src/classes/com/sun/opengl/util/TileRenderer.java b/src/classes/com/sun/opengl/util/TileRenderer.java
new file mode 100755
index 000000000..982ea4a16
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/TileRenderer.java
@@ -0,0 +1,600 @@
+package com.sun.opengl.util;
+
+import java.awt.Dimension;
+import java.nio.Buffer;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+
+/**
+ * A fairly direct port of Brian Paul's tile rendering library, found
+ * at <a href = "http://www.mesa3d.org/brianp/TR.html">
+ * http://www.mesa3d.org/brianp/TR.html </a> . I've java-fied it, but
+ * the functionality is the same.
+ *
+ * Original code Copyright (C) 1997-2005 Brian Paul. Licensed under
+ * BSD-compatible terms with permission of the author. See LICENSE.txt
+ * for license information.
+ *
+ * @author ryanm
+ */
+public class TileRenderer
+{
+ private static final int DEFAULT_TILE_WIDTH = 256;
+
+ private static final int DEFAULT_TILE_HEIGHT = 256;
+
+ private static final int DEFAULT_TILE_BORDER = 0;
+
+ //
+ // Enumeration flags for accessing variables
+ //
+ // @author ryanm
+ //
+
+ /**
+ * The width of a tile
+ */
+ public static final int TR_TILE_WIDTH = 0;
+ /**
+ * The height of a tile
+ */
+ public static final int TR_TILE_HEIGHT = 1;
+ /**
+ * The width of the border around the tiles
+ */
+ public static final int TR_TILE_BORDER = 2;
+ /**
+ * The width of the final image
+ */
+ public static final int TR_IMAGE_WIDTH = 3;
+ /**
+ * The height of the final image
+ */
+ public static final int TR_IMAGE_HEIGHT = 4;
+ /**
+ * The number of rows of tiles
+ */
+ public static final int TR_ROWS = 5;
+ /**
+ * The number of columns of tiles
+ */
+ public static final int TR_COLUMNS = 6;
+ /**
+ * The current row number
+ */
+ public static final int TR_CURRENT_ROW = 7;
+ /**
+ * The current column number
+ */
+ public static final int TR_CURRENT_COLUMN = 8;
+ /**
+ * The width of the current tile
+ */
+ public static final int TR_CURRENT_TILE_WIDTH = 9;
+ /**
+ * The height of the current tile
+ */
+ public static final int TR_CURRENT_TILE_HEIGHT = 10;
+ /**
+ * The order that the rows are traversed
+ */
+ public static final int TR_ROW_ORDER = 11;
+
+
+ /**
+ * Indicates we are traversing rows from the top to the bottom
+ */
+ public static final int TR_TOP_TO_BOTTOM = 1;
+
+ /**
+ * Indicates we are traversing rows from the bottom to the top
+ */
+ public static final int TR_BOTTOM_TO_TOP = 2;
+
+ /* Final image parameters */
+ private Dimension imageSize = new Dimension();
+
+ private int imageFormat, imageType;
+
+ private Buffer imageBuffer;
+
+ /* Tile parameters */
+ private Dimension tileSize = new Dimension();
+
+ private Dimension tileSizeNB = new Dimension();
+
+ private int tileBorder;
+
+ private int tileFormat, tileType;
+
+ private Buffer tileBuffer;
+
+ /* Projection parameters */
+ private boolean perspective;
+
+ private double left;
+
+ private double right;
+
+ private double bottom;
+
+ private double top;
+
+ private double near;
+
+ private double far;
+
+ /* Misc */
+ private int rowOrder;
+
+ private int rows, columns;
+
+ private int currentTile;
+
+ private int currentTileWidth, currentTileHeight;
+
+ private int currentRow, currentColumn;
+
+ private int[] viewportSave = new int[ 4 ];
+
+ /**
+ * Creates a new TileRenderer object
+ */
+ public TileRenderer()
+ {
+ tileSize.width = DEFAULT_TILE_WIDTH;
+ tileSize.height = DEFAULT_TILE_HEIGHT;
+ tileBorder = DEFAULT_TILE_BORDER;
+ rowOrder = TR_BOTTOM_TO_TOP;
+ currentTile = -1;
+ }
+
+ /**
+ * Sets up the number of rows and columns needed
+ */
+ private void setup()
+ {
+ columns = ( imageSize.width + tileSizeNB.width - 1 ) / tileSizeNB.width;
+ rows = ( imageSize.height + tileSizeNB.height - 1 ) / tileSizeNB.height;
+ currentTile = 0;
+
+ assert columns >= 0;
+ assert rows >= 0;
+ }
+
+ /**
+ * Sets the size of the tiles to use in rendering. The actual
+ * effective size of the tile depends on the border size, ie (
+ * width - 2*border ) * ( height - 2 * border )
+ *
+ * @param width
+ * The width of the tiles. Must not be larger than the GL
+ * context
+ * @param height
+ * The height of the tiles. Must not be larger than the
+ * GL context
+ * @param border
+ * The width of the borders on each tile. This is needed
+ * to avoid artifacts when rendering lines or points with
+ * thickness > 1.
+ */
+ public void setTileSize( int width, int height, int border )
+ {
+ assert ( border >= 0 );
+ assert ( width >= 1 );
+ assert ( height >= 1 );
+ assert ( width >= 2 * border );
+ assert ( height >= 2 * border );
+
+ tileBorder = border;
+ tileSize.width = width;
+ tileSize.height = height;
+ tileSizeNB.width = width - 2 * border;
+ tileSizeNB.height = height - 2 * border;
+ setup();
+ }
+
+ /**
+ * Specify a buffer the tiles to be copied to. This is not
+ * necessary for the creation of the final image, but useful if you
+ * want to inspect each tile in turn.
+ *
+ * @param format
+ * Interpreted as in glReadPixels
+ * @param type
+ * Interpreted as in glReadPixels
+ * @param image
+ * The buffer itself. Must be large enough to contain a
+ * tile, minus any borders
+ */
+ public void setTileBuffer( int format, int type, Buffer image )
+ {
+ tileFormat = format;
+ tileType = type;
+ tileBuffer = image;
+ }
+
+ /**
+ * Sets the desired size of the final image
+ *
+ * @param width
+ * The width of the final image
+ * @param height
+ * The height of the final image
+ */
+ public void setImageSize( int width, int height )
+ {
+ imageSize.width = width;
+ imageSize.height = height;
+ setup();
+ }
+
+ /**
+ * Sets the buffer in which to store the final image
+ *
+ * @param format
+ * Interpreted as in glReadPixels
+ * @param type
+ * Interpreted as in glReadPixels
+ * @param image
+ * the buffer itself, must be large enough to hold the
+ * final image
+ */
+ public void setImageBuffer( int format, int type, Buffer image )
+ {
+ imageFormat = format;
+ imageType = type;
+ imageBuffer = image;
+ }
+
+ /**
+ * Gets the parameters of this TileRenderer object
+ *
+ * @param param
+ * The parameter that is to be retrieved
+ * @return the value of the parameter
+ */
+ public int getParam( int param )
+ {
+ switch (param) {
+ case TR_TILE_WIDTH:
+ return tileSize.width;
+ case TR_TILE_HEIGHT:
+ return tileSize.height;
+ case TR_TILE_BORDER:
+ return tileBorder;
+ case TR_IMAGE_WIDTH:
+ return imageSize.width;
+ case TR_IMAGE_HEIGHT:
+ return imageSize.height;
+ case TR_ROWS:
+ return rows;
+ case TR_COLUMNS:
+ return columns;
+ case TR_CURRENT_ROW:
+ if( currentTile < 0 )
+ return -1;
+ else
+ return currentRow;
+ case TR_CURRENT_COLUMN:
+ if( currentTile < 0 )
+ return -1;
+ else
+ return currentColumn;
+ case TR_CURRENT_TILE_WIDTH:
+ return currentTileWidth;
+ case TR_CURRENT_TILE_HEIGHT:
+ return currentTileHeight;
+ case TR_ROW_ORDER:
+ return rowOrder;
+ default:
+ throw new IllegalArgumentException("Invalid enumerant as argument");
+ }
+ }
+
+ /**
+ * Sets the order of row traversal
+ *
+ * @param order
+ * The row traversal order, must be
+ * eitherTR_TOP_TO_BOTTOM or TR_BOTTOM_TO_TOP
+ */
+ public void setRowOrder( int order )
+ {
+ if (order == TR_TOP_TO_BOTTOM || order == TR_BOTTOM_TO_TOP) {
+ rowOrder = order;
+ } else {
+ throw new IllegalArgumentException("Must pass TR_TOP_TO_BOTTOM or TR_BOTTOM_TO_TOP");
+ }
+ }
+
+ /**
+ * Sets the context to use an orthographic projection. Must be
+ * called before rendering the first tile
+ *
+ * @param left
+ * As in glOrtho
+ * @param right
+ * As in glOrtho
+ * @param bottom
+ * As in glOrtho
+ * @param top
+ * As in glOrtho
+ * @param zNear
+ * As in glOrtho
+ * @param zFar
+ * As in glOrtho
+ */
+ public void trOrtho( double left, double right, double bottom, double top, double zNear,
+ double zFar )
+ {
+ this.perspective = false;
+ this.left = left;
+ this.right = right;
+ this.bottom = bottom;
+ this.top = top;
+ this.near = zNear;
+ this.far = zFar;
+ }
+
+ /**
+ * Sets the perspective projection frustrum. Must be called before
+ * rendering the first tile
+ *
+ * @param left
+ * As in glFrustrum
+ * @param right
+ * As in glFrustrum
+ * @param bottom
+ * As in glFrustrum
+ * @param top
+ * As in glFrustrum
+ * @param zNear
+ * As in glFrustrum
+ * @param zFar
+ * As in glFrustrum
+ */
+ public void trFrustum( double left, double right, double bottom, double top, double zNear,
+ double zFar )
+ {
+ this.perspective = true;
+ this.left = left;
+ this.right = right;
+ this.bottom = bottom;
+ this.top = top;
+ this.near = zNear;
+ this.far = zFar;
+ }
+
+ /**
+ * Convenient way to specify a perspective projection
+ *
+ * @param fovy
+ * As in gluPerspective
+ * @param aspect
+ * As in gluPerspective
+ * @param zNear
+ * As in gluPerspective
+ * @param zFar
+ * As in gluPerspective
+ */
+ public void trPerspective( double fovy, double aspect, double zNear, double zFar )
+ {
+ double xmin, xmax, ymin, ymax;
+ ymax = zNear * Math.tan( fovy * 3.14159265 / 360.0 );
+ ymin = -ymax;
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+ trFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
+ }
+
+ /**
+ * Begins rendering a tile. The projection matrix stack should be
+ * left alone after calling this
+ *
+ * @param gl
+ * The gl context
+ */
+ public void beginTile( GL gl )
+ {
+ if (currentTile <= 0) {
+ setup();
+ /*
+ * Save user's viewport, will be restored after last tile
+ * rendered
+ */
+ gl.glGetIntegerv( GL.GL_VIEWPORT, viewportSave, 0 );
+ }
+
+ /* which tile (by row and column) we're about to render */
+ if (rowOrder == TR_BOTTOM_TO_TOP) {
+ currentRow = currentTile / columns;
+ currentColumn = currentTile % columns;
+ } else {
+ currentRow = rows - ( currentTile / columns ) - 1;
+ currentColumn = currentTile % columns;
+ }
+ assert ( currentRow < rows );
+ assert ( currentColumn < columns );
+
+ int border = tileBorder;
+
+ int th, tw;
+
+ /* Compute actual size of this tile with border */
+ if (currentRow < rows - 1) {
+ th = tileSize.height;
+ } else {
+ th = imageSize.height - ( rows - 1 ) * ( tileSizeNB.height ) + 2 * border;
+ }
+
+ if (currentColumn < columns - 1) {
+ tw = tileSize.width;
+ } else {
+ tw = imageSize.width - ( columns - 1 ) * ( tileSizeNB.width ) + 2 * border;
+ }
+
+ /* Save tile size, with border */
+ currentTileWidth = tw;
+ currentTileHeight = th;
+
+ gl.glViewport( 0, 0, tw, th );
+
+ /* save current matrix mode */
+ int[] matrixMode = new int[ 1 ];
+ gl.glGetIntegerv( GL.GL_MATRIX_MODE, matrixMode, 0 );
+ gl.glMatrixMode( GL.GL_PROJECTION );
+ gl.glLoadIdentity();
+
+ /* compute projection parameters */
+ double l =
+ left + ( right - left ) * ( currentColumn * tileSizeNB.width - border )
+ / imageSize.width;
+ double r = l + ( right - left ) * tw / imageSize.width;
+ double b =
+ bottom + ( top - bottom ) * ( currentRow * tileSizeNB.height - border )
+ / imageSize.height;
+ double t = b + ( top - bottom ) * th / imageSize.height;
+
+ if( perspective ) {
+ gl.glFrustum( l, r, b, t, near, far );
+ } else {
+ gl.glOrtho( l, r, b, t, near, far );
+ }
+
+ /* restore user's matrix mode */
+ gl.glMatrixMode( matrixMode[ 0 ] );
+ }
+
+ /**
+ * Must be called after rendering the scene
+ *
+ * @param gl
+ * the gl context
+ * @return true if there are more tiles to be rendered, false if
+ * the final image is complete
+ */
+ public boolean endTile( GL gl )
+ {
+ int[] prevRowLength = new int[ 1 ], prevSkipRows = new int[ 1 ], prevSkipPixels = new int[ 1 ], prevAlignment =
+ new int[ 1 ];
+
+ assert ( currentTile >= 0 );
+
+ // be sure OpenGL rendering is finished
+ gl.glFlush();
+
+ // save current glPixelStore values
+ gl.glGetIntegerv( GL.GL_PACK_ROW_LENGTH, prevRowLength, 0 );
+ gl.glGetIntegerv( GL.GL_PACK_SKIP_ROWS, prevSkipRows, 0 );
+ gl.glGetIntegerv( GL.GL_PACK_SKIP_PIXELS, prevSkipPixels, 0 );
+ gl.glGetIntegerv( GL.GL_PACK_ALIGNMENT, prevAlignment, 0 );
+
+ if( tileBuffer != null ) {
+ int srcX = tileBorder;
+ int srcY = tileBorder;
+ int srcWidth = tileSizeNB.width;
+ int srcHeight = tileSizeNB.height;
+ gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, tileFormat, tileType, tileBuffer );
+ }
+
+ if( imageBuffer != null ) {
+ int srcX = tileBorder;
+ int srcY = tileBorder;
+ int srcWidth = currentTileWidth - 2 * tileBorder;
+ int srcHeight = currentTileHeight - 2 * tileBorder;
+ int destX = tileSizeNB.width * currentColumn;
+ int destY = tileSizeNB.height * currentRow;
+
+ /* setup pixel store for glReadPixels */
+ gl.glPixelStorei( GL.GL_PACK_ROW_LENGTH, imageSize.width );
+ gl.glPixelStorei( GL.GL_PACK_SKIP_ROWS, destY );
+ gl.glPixelStorei( GL.GL_PACK_SKIP_PIXELS, destX );
+ gl.glPixelStorei( GL.GL_PACK_ALIGNMENT, 1 );
+
+ /* read the tile into the final image */
+ gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, imageFormat, imageType, imageBuffer );
+ }
+
+ /* restore previous glPixelStore values */
+ gl.glPixelStorei( GL.GL_PACK_ROW_LENGTH, prevRowLength[ 0 ] );
+ gl.glPixelStorei( GL.GL_PACK_SKIP_ROWS, prevSkipRows[ 0 ] );
+ gl.glPixelStorei( GL.GL_PACK_SKIP_PIXELS, prevSkipPixels[ 0 ] );
+ gl.glPixelStorei( GL.GL_PACK_ALIGNMENT, prevAlignment[ 0 ] );
+
+ /* increment tile counter, return 1 if more tiles left to render */
+ currentTile++;
+ if( currentTile >= rows * columns ) {
+ /* restore user's viewport */
+ gl.glViewport( viewportSave[ 0 ], viewportSave[ 1 ], viewportSave[ 2 ], viewportSave[ 3 ] );
+ currentTile = -1; /* all done */
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Tile rendering causes problems with using glRasterPos3f, so you
+ * should use this replacement instead
+ *
+ * @param x
+ * As in glRasterPos3f
+ * @param y
+ * As in glRasterPos3f
+ * @param z
+ * As in glRasterPos3f
+ * @param gl
+ * The gl context
+ * @param glu
+ * A GLU object
+ */
+ public void trRasterPos3f( float x, float y, float z, GL gl, GLU glu )
+ {
+ if (currentTile < 0) {
+ /* not doing tile rendering right now. Let OpenGL do this. */
+ gl.glRasterPos3f( x, y, z );
+ } else {
+ double[] modelview = new double[ 16 ], proj = new double[ 16 ];
+ int[] viewport = new int[ 4 ];
+ double[] win = new double[3];
+
+ /* Get modelview, projection and viewport */
+ gl.glGetDoublev( GL.GL_MODELVIEW_MATRIX, modelview, 0 );
+ gl.glGetDoublev( GL.GL_PROJECTION_MATRIX, proj, 0 );
+ viewport[ 0 ] = 0;
+ viewport[ 1 ] = 0;
+ viewport[ 2 ] = currentTileWidth;
+ viewport[ 3 ] = currentTileHeight;
+
+ /* Project object coord to window coordinate */
+ if( glu.gluProject( x, y, z, modelview, 0, proj, 0, viewport, 0, win, 0 ) ) {
+
+ /* set raster pos to window coord (0,0) */
+ gl.glMatrixMode( GL.GL_MODELVIEW );
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ gl.glMatrixMode( GL.GL_PROJECTION );
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ gl.glOrtho( 0.0, currentTileWidth, 0.0, currentTileHeight, 0.0, 1.0 );
+ gl.glRasterPos3d( 0.0, 0.0, -win[ 2 ] );
+
+ /*
+ * Now use empty bitmap to adjust raster position to
+ * (winX,winY)
+ */
+ {
+ byte[] bitmap = { 0 };
+ gl.glBitmap( 1, 1, 0.0f, 0.0f, ( float ) win[ 0 ], ( float ) win[ 1 ], bitmap , 0 );
+ }
+
+ /* restore original matrices */
+ gl.glPopMatrix(); /* proj */
+ gl.glMatrixMode( GL.GL_MODELVIEW );
+ gl.glPopMatrix();
+ }
+ }
+ }
+}