From b299012e07363172d040fc3ae3d5f751cf1c9740 Mon Sep 17 00:00:00 2001
From: Kenneth Russel <kbrussel@alum.mit.edu>
Date: Thu, 2 Feb 2006 22:11:38 +0000
Subject: 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
---
 src/classes/com/sun/opengl/util/TileRenderer.java | 600 ++++++++++++++++++++++
 1 file changed, 600 insertions(+)
 create mode 100755 src/classes/com/sun/opengl/util/TileRenderer.java

(limited to 'src/classes/com/sun/opengl/util/TileRenderer.java')

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();
+      }
+    }
+  }
+}
-- 
cgit v1.2.3