diff options
9 files changed, 1126 insertions, 523 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index c391f7cdc..bbb8c6ece 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -315,9 +315,6 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestTeapotNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl3.newt.TestGeomShader01TextureGL3NEWT $* -testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.TestTiledRendering1GL2 $* -#testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.TestTiledRendering2GL2 $* - # # av demos # @@ -326,6 +323,13 @@ testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.TestTiledRendering1GL2 $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSimple $* # +# tile rendring / printing w/ & w/o AWT +# +testnoawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledRendering1GL2 $* +testnoawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledRendering2GL2 $* +testnoawt com.jogamp.opengl.test.junit.jogl.tile.TestRandomTiledRendering2GL2 $* + +# # core/newt (testnoawt and testawt) # #testnoawt com.jogamp.nativewindow.NativeWindowVersion $* diff --git a/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java new file mode 100644 index 000000000..ac420da3d --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java @@ -0,0 +1,367 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.util; + +import javax.media.nativewindow.util.Dimension; +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES3; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLEventListener; + +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; + +/** + * Variation of {@link TileRenderer} w/o using fixed tiles but arbitrary rectangular regions. + */ +public class RandomTileRenderer { + private final Dimension imageSize = new Dimension(0, 0); + private final GLPixelStorageModes psm = new GLPixelStorageModes(); + + private GLPixelBuffer imageBuffer; + private GLPixelBuffer tileBuffer; + private PMVMatrixCallback pmvMatrixCB = null; + private int tX = 0; + private int tY = 0; + private int tWidth = 0; + private int tHeight = 0; + + private GLAutoDrawable glad; + private GLEventListener[] listeners; + private boolean[] listenersInit; + private GLEventListener glEventListenerPre = null; + private GLEventListener glEventListenerPost = null; + + public static interface PMVMatrixCallback { + void reshapePMVMatrix(GL gl, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight); + } + + /** + * Creates a new TileRenderer object + */ + public RandomTileRenderer() { + } + + public final void setPMVMatrixCallback(PMVMatrixCallback pmvMatrixCB) { + assert ( null != pmvMatrixCB ); + this.pmvMatrixCB = pmvMatrixCB; + } + + /** + * 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 buffer The buffer itself. Must be large enough to contain a random tile + */ + public final void setTileBuffer(GLPixelBuffer buffer) { + tileBuffer = buffer; + } + + /** @see #setTileBuffer(GLPixelBuffer) */ + public final GLPixelBuffer getTileBuffer() { return tileBuffer; } + + /** + * 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 final void setImageSize(int width, int height) { + imageSize.setWidth(width); + imageSize.setHeight(height); + } + + /** @see #setImageSize(int, int) */ + public final Dimension getImageSize() { return imageSize; } + + /** + * Sets the buffer in which to store the final image + * + * @param buffer the buffer itself, must be large enough to hold the final image + */ + public final void setImageBuffer(GLPixelBuffer buffer) { + imageBuffer = buffer; + } + + /** @see #setImageBuffer(GLPixelBuffer) */ + public final GLPixelBuffer getImageBuffer() { return imageBuffer; } + + /** + * Begins rendering a tile. + * <p> + * Methods modifies the viewport, hence user shall reset the viewport when finishing tile rendering. + * </p> + * <p> + * The projection matrix stack should be + * left alone after calling this method! + * </p> + * + * @param gl The gl context + * @throws IllegalStateException + * @throws IllegalArgumentException + */ + public final void beginTile(GL2ES3 gl, int tX, int tY, int tWidth, int tHeight) throws IllegalStateException, IllegalArgumentException { + if( 0 >= imageSize.getWidth() || 0 >= imageSize.getHeight() ) { + throw new IllegalStateException("Image size has not been set"); + } + if( null == this.pmvMatrixCB ) { + throw new IllegalStateException("pmvMatrixCB has not been set"); + } + if( 0 > tX || 0 > tX ) { + throw new IllegalArgumentException("Tile pos must be >= 0/0"); + } + if( 0 >= tWidth || 0 >= tHeight ) { + throw new IllegalArgumentException("Tile size must be > 0x0"); + } + + gl.glViewport( 0, 0, tWidth, tHeight ); + pmvMatrixCB.reshapePMVMatrix(gl, tX, tY, tWidth, tHeight, imageSize.getWidth(), imageSize.getHeight()); + + this.tX = tX; + this.tY = tY; + this.tWidth = tWidth; + this.tHeight = tHeight; + } + + /** + * 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 void endTile( GL2ES3 gl ) { + if( 0 >= tWidth || 0 >= tHeight ) { + throw new IllegalStateException("beginTile(..) has not been called"); + } + + // be sure OpenGL rendering is finished + gl.glFlush(); + + // save current glPixelStore values + psm.save(gl); + + final int tmp[] = new int[1]; + + if( tileBuffer != null ) { + final GLPixelAttributes pixelAttribs = tileBuffer.pixelAttributes; + final int srcX = 0; + final int srcY = 0; + final int srcWidth = tWidth; + final int srcHeight = tHeight; + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); + tileBuffer.clear(); + if( tileBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { + throw new IndexOutOfBoundsException("Required " + readPixelSize + " bytes of buffer, only had " + tileBuffer); + } + gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, pixelAttribs.format, pixelAttribs.type, tileBuffer.buffer); + // be sure OpenGL rendering is finished + gl.glFlush(); + tileBuffer.position( readPixelSize ); + tileBuffer.flip(); + } + + if( imageBuffer != null ) { + final GLPixelAttributes pixelAttribs = imageBuffer.pixelAttributes; + final int srcX = 0; + final int srcY = 0; + final int srcWidth = tWidth; + final int srcHeight = tHeight; + + /* setup pixel store for glReadPixels */ + final int rowLength = imageSize.getWidth(); + psm.setPackRowLength(gl, rowLength); + psm.setPackAlignment(gl, 1); + + /* read the tile into the final image */ + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); + + final int ibPos = ( tX + ( tY * rowLength ) ) * pixelAttribs.bytesPerPixel; // skipPixels + skipRows + final int ibLim = ibPos + readPixelSize; + imageBuffer.clear(); + if( imageBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { + throw new IndexOutOfBoundsException("Required " + ibLim + " bytes of buffer, only had " + imageBuffer); + } + imageBuffer.position(ibPos); + + gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, pixelAttribs.format, pixelAttribs.type, imageBuffer.buffer); + // be sure OpenGL rendering is finished + gl.glFlush(); + imageBuffer.position( ibLim ); + imageBuffer.flip(); + } + + /* restore previous glPixelStore values */ + psm.restore(gl); + + this.tX = 0; + this.tY = 0; + this.tWidth = 0; + this.tHeight = 0; + } + + /** + * + * <p> + * 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 ) + * </p> + * @param glad + * @throws IllegalStateException if an {@link GLAutoDrawable} is already attached + */ + public void attachAutoDrawable(GLAutoDrawable glad, PMVMatrixCallback pmvMatrixCB) throws IllegalStateException { + if( null != this.glad ) { + throw new IllegalStateException("GLAutoDrawable already attached"); + } + this.glad = glad; + setPMVMatrixCallback(pmvMatrixCB); + + final int aSz = glad.getGLEventListenerCount(); + listeners = new GLEventListener[aSz]; + listenersInit = new boolean[aSz]; + for(int i=0; i<aSz; i++) { + final GLEventListener l = glad.getGLEventListener(0); + listenersInit[i] = glad.getGLEventListenerInitState(l); + listeners[i] = glad.removeGLEventListener( l ); + } + glad.addGLEventListener(tiledGLEL); + } + + public void detachAutoDrawable() { + if( null != glad ) { + glad.removeGLEventListener(tiledGLEL); + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + final GLEventListener l = listeners[i]; + glad.addGLEventListener(l); + glad.setGLEventListenerInitState(l, listenersInit[i]); + } + listeners = null; + listenersInit = null; + glad = null; + pmvMatrixCB = null; + } + } + + /** + * Set {@link GLEventListener} for pre- and post operations when used w/ + * {@link #attachAutoDrawable(GLAutoDrawable, int, PMVMatrixCallback)} + * for each {@link GLEventListener} callback. + * @param preTile the pre operations + * @param postTile the post operations + */ + public void setGLEventListener(GLEventListener preTile, GLEventListener postTile) { + glEventListenerPre = preTile; + glEventListenerPost = postTile; + } + + /** + * Rendering one tile, by simply calling {@link GLAutoDrawable#display()}. + * + * @return true if there are more tiles to be rendered, false if the final image is complete + * @throws IllegalStateException if no {@link GLAutoDrawable} is {@link #attachAutoDrawable(GLAutoDrawable, int) attached} + * or imageSize is not set + */ + public void display(int tX, int tY, int tWidth, int tHeight) throws IllegalStateException { + if( null == glad ) { + throw new IllegalStateException("No GLAutoDrawable attached"); + } + this.tX = tX; + this.tY = tY; + this.tWidth = tWidth; + this.tHeight = tHeight; + glad.display(); + } + + private final GLEventListener tiledGLEL = new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + if( null != glEventListenerPre ) { + glEventListenerPre.init(drawable); + } + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + final GLEventListener l = listeners[i]; + l.init(drawable); + listenersInit[i] = true; + } + if( null != glEventListenerPost ) { + glEventListenerPost.init(drawable); + } + } + @Override + public void dispose(GLAutoDrawable drawable) { + if( null != glEventListenerPre ) { + glEventListenerPre.dispose(drawable); + } + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + listeners[i].dispose(drawable); + } + if( null != glEventListenerPost ) { + glEventListenerPost.dispose(drawable); + } + } + @Override + public void display(GLAutoDrawable drawable) { + if( null != glEventListenerPre ) { + glEventListenerPre.display(drawable); + } + final GL2ES3 gl = drawable.getGL().getGL2ES3(); + + beginTile(gl, tX, tY, tWidth, tHeight); + + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + listeners[i].display(drawable); + } + + endTile(gl); + if( null != glEventListenerPost ) { + glEventListenerPost.display(drawable); + } + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + if( null != glEventListenerPre ) { + glEventListenerPre.reshape(drawable, x, y, width, height); + } + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + listeners[i].reshape(drawable, x, y, width, height); + } + if( null != glEventListenerPost ) { + glEventListenerPost.reshape(drawable, x, y, width, height); + } + } + }; +}
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java index afd023224..c7c94c8da 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java @@ -1,10 +1,48 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + * + * --------------------- + * + * Based on 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>. + * + * Copyright (C) 1997-2005 Brian Paul. + * Licensed under BSD-compatible terms with permission of the author. + * See LICENSE.txt for license information. + */ package com.jogamp.opengl.util; -import java.nio.ByteBuffer; - import javax.media.nativewindow.util.Dimension; import javax.media.opengl.GL; import javax.media.opengl.GL2ES3; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLEventListener; + +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; /** * A fairly direct port of Brian Paul's tile rendering library, found @@ -23,12 +61,6 @@ import javax.media.opengl.GL2ES3; * @author ryanm, sgothel */ public class TileRenderer { - - protected static final boolean DEBUG = true; - protected static final int DEFAULT_TILE_WIDTH = 256; - protected static final int DEFAULT_TILE_HEIGHT = 256; - protected static final int DEFAULT_TILE_BORDER = 0; - /** * The width of a tile */ @@ -86,29 +118,37 @@ public class TileRenderer { */ public static final int TR_BOTTOM_TO_TOP = 2; - protected final Dimension imageSize = new Dimension(0, 0); - protected final Dimension tileSize = new Dimension(DEFAULT_TILE_WIDTH, DEFAULT_TILE_HEIGHT); - protected final Dimension tileSizeNB = new Dimension(DEFAULT_TILE_WIDTH - 2 * DEFAULT_TILE_BORDER, DEFAULT_TILE_HEIGHT - 2 * DEFAULT_TILE_BORDER); - protected final int[] userViewport = new int[ 4 ]; - protected final GLPixelStorageModes psm = new GLPixelStorageModes(); - - protected int tileBorder = DEFAULT_TILE_BORDER; - protected int imageFormat; - protected int imageType; - protected ByteBuffer imageBuffer; - protected int tileFormat; - protected int tileType; - protected ByteBuffer tileBuffer; - protected int rowOrder = TR_BOTTOM_TO_TOP; - protected int rows; - protected int columns; - protected int currentTile = -1; - protected int currentTileWidth; - protected int currentTileHeight; - protected int currentRow; - protected int currentColumn; - protected PMVMatrixCallback pmvMatrixCB = null; - + private static final boolean DEBUG = true; + private static final int DEFAULT_TILE_WIDTH = 256; + private static final int DEFAULT_TILE_HEIGHT = 256; + private static final int DEFAULT_TILE_BORDER = 0; + + private final Dimension imageSize = new Dimension(0, 0); + private final Dimension tileSize = new Dimension(DEFAULT_TILE_WIDTH, DEFAULT_TILE_HEIGHT); + private final Dimension tileSizeNB = new Dimension(DEFAULT_TILE_WIDTH - 2 * DEFAULT_TILE_BORDER, DEFAULT_TILE_HEIGHT - 2 * DEFAULT_TILE_BORDER); + private final int[] userViewport = new int[ 4 ]; + private final GLPixelStorageModes psm = new GLPixelStorageModes(); + + private int tileBorder = DEFAULT_TILE_BORDER; + private GLPixelBuffer imageBuffer; + private GLPixelBuffer tileBuffer; + private int rowOrder = TR_BOTTOM_TO_TOP; + private int rows; + private int columns; + private int currentTile = -1; + private int currentTileWidth; + private int currentTileHeight; + private int currentRow; + private int currentColumn; + private PMVMatrixCallback pmvMatrixCB = null; + private boolean beginCalled = false; + + private GLAutoDrawable glad; + private GLEventListener[] listeners; + private boolean[] listenersInit; + private GLEventListener glEventListenerPre = null; + private GLEventListener glEventListenerPost = null; + public static interface PMVMatrixCallback { void reshapePMVMatrix(GL gl, int tileNum, int tileColumn, int tileRow, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight); } @@ -136,12 +176,12 @@ public class TileRenderer { * thickness > 1. */ public final 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 ); - + if( 0 > border ) { + throw new IllegalArgumentException("Tile border must be >= 0"); + } + if( 2 * border >= width || 2 * border >= height ) { + throw new IllegalArgumentException("Tile size must be > 0x0 minus 2*border"); + } tileBorder = border; tileSize.setWidth( width ); tileSize.setHeight( height ); @@ -158,7 +198,7 @@ public class TileRenderer { /** * Sets up the number of rows and columns needed */ - protected final void setup() throws IllegalStateException { + private final void setup() throws IllegalStateException { columns = ( imageSize.getWidth() + tileSizeNB.getWidth() - 1 ) / tileSizeNB.getWidth(); rows = ( imageSize.getHeight() + tileSizeNB.getHeight() - 1 ) / tileSizeNB.getHeight(); currentTile = 0; @@ -182,20 +222,15 @@ public class TileRenderer { * 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 buffer - * The buffer itself. Must be large enough to contain a - * tile, minus any borders + * @param buffer The buffer itself. Must be large enough to contain a tile, minus any borders */ - public final void setTileBuffer(int format, int type, ByteBuffer buffer) { - tileFormat = format; - tileType = type; + public final void setTileBuffer(GLPixelBuffer buffer) { tileBuffer = buffer; } + /** @see #setTileBuffer(GLPixelBuffer) */ + public final GLPixelBuffer getTileBuffer() { return tileBuffer; } + /** * Sets the desired size of the final image * @@ -210,23 +245,21 @@ public class TileRenderer { setup(); } + /** @see #setImageSize(int, int) */ + public final Dimension getImageSize() { return imageSize; } + /** * 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 + * @param image the buffer itself, must be large enough to hold the final image */ - public final void setImageBuffer(int format, int type, ByteBuffer buffer) { - imageFormat = format; - imageType = type; + public final void setImageBuffer(GLPixelBuffer buffer) { imageBuffer = buffer; } + /** @see #setImageBuffer(GLPixelBuffer) */ + public final GLPixelBuffer getImageBuffer() { return imageBuffer; } + /** * Gets the parameters of this TileRenderer object * @@ -294,8 +327,9 @@ public class TileRenderer { * </p> * * @param gl The gl context + * @throws IllegalStateException */ - public final void beginTile( GL2ES3 gl ) { + public final void beginTile( GL2ES3 gl ) throws IllegalStateException { if( 0 >= imageSize.getWidth() || 0 >= imageSize.getHeight() ) { throw new IllegalStateException("Image size has not been set"); } @@ -342,8 +376,8 @@ public class TileRenderer { tW = imageSize.getWidth() - ( columns - 1 ) * ( tileSizeNB.getWidth() ) + 2 * border; } - final int tX = currentColumn * tileSizeNB.getWidth() - border; - final int tY = currentRow * tileSizeNB.getHeight() - border; + final int tX = currentColumn * tileSizeNB.getWidth(); + final int tY = currentRow * tileSizeNB.getHeight(); final int preTileWidth = currentTileWidth; final int preTileHeight = currentTileHeight; @@ -359,6 +393,7 @@ public class TileRenderer { gl.glViewport( 0, 0, tW, tH ); pmvMatrixCB.reshapePMVMatrix(gl, currentTile, currentColumn, currentRow, tX, tY, tW, tH, imageSize.getWidth(), imageSize.getHeight()); + beginCalled = true; } /** @@ -368,9 +403,12 @@ public class TileRenderer { * the gl context * @return true if there are more tiles to be rendered, false if * the final image is complete + * @throws IllegalStateException */ - public boolean endTile( GL2ES3 gl ) { - assert ( currentTile >= 0 ); + public boolean endTile( GL2ES3 gl ) throws IllegalStateException { + if( !beginCalled ) { + throw new IllegalStateException("beginTile(..) has not been called"); + } // be sure OpenGL rendering is finished gl.glFlush(); @@ -381,17 +419,17 @@ public class TileRenderer { final int tmp[] = new int[1]; if( tileBuffer != null ) { - int srcX = tileBorder; - int srcY = tileBorder; - int srcWidth = tileSizeNB.getWidth(); - int srcHeight = tileSizeNB.getHeight(); - final int bytesPerPixel = GLBuffers.bytesPerPixel(tileFormat, tileType); - final int readPixelSize = GLBuffers.sizeof(gl, tmp, bytesPerPixel, srcWidth, srcHeight, 1, true); + final GLPixelAttributes pixelAttribs = tileBuffer.pixelAttributes; + final int srcX = tileBorder; + final int srcY = tileBorder; + final int srcWidth = tileSizeNB.getWidth(); + final int srcHeight = tileSizeNB.getHeight(); + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); tileBuffer.clear(); - if( tileBuffer.limit() < readPixelSize ) { - throw new IndexOutOfBoundsException("Required " + readPixelSize + " bytes of buffer, only had " + tileBuffer.limit()); + if( tileBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { + throw new IndexOutOfBoundsException("Required " + readPixelSize + " bytes of buffer, only had " + tileBuffer); } - gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, tileFormat, tileType, tileBuffer ); + gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, pixelAttribs.format, pixelAttribs.type, tileBuffer.buffer); // be sure OpenGL rendering is finished gl.glFlush(); tileBuffer.position( readPixelSize ); @@ -399,10 +437,11 @@ public class TileRenderer { } if( imageBuffer != null ) { - int srcX = tileBorder; - int srcY = tileBorder; - int srcWidth = currentTileWidth - 2 * tileBorder; - int srcHeight = currentTileHeight - 2 * tileBorder; + final GLPixelAttributes pixelAttribs = imageBuffer.pixelAttributes; + final int srcX = tileBorder; + final int srcY = tileBorder; + final int srcWidth = currentTileWidth - 2 * tileBorder; + final int srcHeight = currentTileHeight - 2 * tileBorder; /* setup pixel store for glReadPixels */ final int rowLength = imageSize.getWidth(); @@ -410,20 +449,19 @@ public class TileRenderer { psm.setPackAlignment(gl, 1); /* read the tile into the final image */ - final int bytesPerPixel = GLBuffers.bytesPerPixel(imageFormat, imageType); - final int readPixelSize = GLBuffers.sizeof(gl, tmp, bytesPerPixel, srcWidth, srcHeight, 1, true); + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); - final int skipPixels = tileSizeNB.getWidth() * currentColumn; - final int skipRows = tileSizeNB.getHeight() * currentRow; - final int ibPos = ( skipPixels + ( skipRows * rowLength ) ) * bytesPerPixel; + final int skipPixels = currentColumn * tileSizeNB.getWidth(); + final int skipRows = currentRow * tileSizeNB.getHeight(); + final int ibPos = ( skipPixels + ( skipRows * rowLength ) ) * pixelAttribs.bytesPerPixel; final int ibLim = ibPos + readPixelSize; imageBuffer.clear(); - if( imageBuffer.limit() < ibLim ) { - throw new IndexOutOfBoundsException("Required " + ibLim + " bytes of buffer, only had " + imageBuffer.limit()); + if( imageBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { + throw new IndexOutOfBoundsException("Required " + ibLim + " bytes of buffer, only had " + imageBuffer); } imageBuffer.position(ibPos); - gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, imageFormat, imageType, imageBuffer); + gl.glReadPixels( srcX, srcY, srcWidth, srcHeight, pixelAttribs.format, pixelAttribs.type, imageBuffer.buffer); // be sure OpenGL rendering is finished gl.glFlush(); imageBuffer.position( ibLim ); @@ -433,6 +471,8 @@ public class TileRenderer { /* restore previous glPixelStore values */ psm.restore(gl); + beginCalled = false; + /* increment tile counter, return 1 if more tiles left to render */ currentTile++; if( currentTile >= rows * columns ) { @@ -444,4 +484,143 @@ public class TileRenderer { return true; } } + + /** + * + * <p> + * 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 ) + * </p> + * @param glad + * @param border + * The width of the borders on each tile. This is needed + * to avoid artifacts when rendering lines or points with + * thickness > 1. + * @throws IllegalStateException if an {@link GLAutoDrawable} is already attached + */ + public void attachAutoDrawable(GLAutoDrawable glad, int border, PMVMatrixCallback pmvMatrixCB) throws IllegalStateException { + if( null != this.glad ) { + throw new IllegalStateException("GLAutoDrawable already attached"); + } + this.glad = glad; + setTileSize(glad.getWidth(), glad.getHeight(), border); + setPMVMatrixCallback(pmvMatrixCB); + + final int aSz = glad.getGLEventListenerCount(); + listeners = new GLEventListener[aSz]; + listenersInit = new boolean[aSz]; + for(int i=0; i<aSz; i++) { + final GLEventListener l = glad.getGLEventListener(0); + listenersInit[i] = glad.getGLEventListenerInitState(l); + listeners[i] = glad.removeGLEventListener( l ); + } + glad.addGLEventListener(tiledGLEL); + } + + public void detachAutoDrawable() { + if( null != glad ) { + glad.removeGLEventListener(tiledGLEL); + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + final GLEventListener l = listeners[i]; + glad.addGLEventListener(l); + glad.setGLEventListenerInitState(l, listenersInit[i]); + } + listeners = null; + listenersInit = null; + glad = null; + pmvMatrixCB = null; + } + } + + /** + * Set {@link GLEventListener} for pre- and post operations when used w/ + * {@link #attachAutoDrawable(GLAutoDrawable, int, PMVMatrixCallback)} + * for each {@link GLEventListener} callback. + * @param preTile the pre operations + * @param postTile the post operations + */ + public void setGLEventListener(GLEventListener preTile, GLEventListener postTile) { + glEventListenerPre = preTile; + glEventListenerPost = postTile; + } + + /** + * Rendering one tile, by simply calling {@link GLAutoDrawable#display()}. + * + * @return true if there are more tiles to be rendered, false if the final image is complete + * @throws IllegalStateException if no {@link GLAutoDrawable} is {@link #attachAutoDrawable(GLAutoDrawable, int) attached} + * or imageSize is not set + */ + public boolean display() throws IllegalStateException { + if( null == glad ) { + throw new IllegalStateException("No GLAutoDrawable attached"); + } + glad.display(); + return !eot(); + } + + private final GLEventListener tiledGLEL = new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + if( null != glEventListenerPre ) { + glEventListenerPre.init(drawable); + } + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + final GLEventListener l = listeners[i]; + l.init(drawable); + listenersInit[i] = true; + } + if( null != glEventListenerPost ) { + glEventListenerPost.init(drawable); + } + } + @Override + public void dispose(GLAutoDrawable drawable) { + if( null != glEventListenerPre ) { + glEventListenerPre.dispose(drawable); + } + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + listeners[i].dispose(drawable); + } + if( null != glEventListenerPost ) { + glEventListenerPost.dispose(drawable); + } + } + @Override + public void display(GLAutoDrawable drawable) { + if( null != glEventListenerPre ) { + glEventListenerPre.display(drawable); + } + final GL2ES3 gl = drawable.getGL().getGL2ES3(); + + beginTile(gl); + + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + listeners[i].display(drawable); + } + + endTile(gl); + if( null != glEventListenerPost ) { + glEventListenerPost.display(drawable); + } + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + if( null != glEventListenerPre ) { + glEventListenerPre.reshape(drawable, x, y, width, height); + } + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + listeners[i].reshape(drawable, x, y, width, height); + } + if( null != glEventListenerPost ) { + glEventListenerPost.reshape(drawable, x, y, width, height); + } + } + }; }
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer2.java b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer2.java deleted file mode 100644 index a77456889..000000000 --- a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer2.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.jogamp.opengl.util; - -import javax.media.opengl.GL2ES3; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLEventListener; - -/** - * See {@link TileRenderer}. - * <p> - * Enhanced for {@link GLAutoDrawable} usage. - * </p> - */ -public class TileRenderer2 extends TileRenderer { - private GLAutoDrawable glad; - private GLEventListener[] listeners; - private boolean[] listenersInit; - - /** - * Creates a new TileRenderer object - */ - public TileRenderer2() { - glad = null; - listeners = null; - listenersInit = null; - } - - /** - * - * <p> - * 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 ) - * </p> - * @param glad - * @param border - * The width of the borders on each tile. This is needed - * to avoid artifacts when rendering lines or points with - * thickness > 1. - * @throws IllegalStateException if an {@link GLAutoDrawable} is already attached - */ - public void attachAutoDrawable(GLAutoDrawable glad, int border, PMVMatrixCallback pmvMatrixCB) throws IllegalStateException { - if( null != this.glad ) { - throw new IllegalStateException("GLAutoDrawable already attached"); - } - this.glad = glad; - setTileSize(glad.getWidth(), glad.getHeight(), border); - setPMVMatrixCallback(pmvMatrixCB); - - final int aSz = glad.getGLEventListenerCount(); - listeners = new GLEventListener[aSz]; - listenersInit = new boolean[aSz]; - for(int i=0; i<aSz; i++) { - final GLEventListener l = glad.getGLEventListener(0); - listenersInit[i] = glad.getGLEventListenerInitState(l); - listeners[i] = glad.removeGLEventListener( l ); - } - glad.addGLEventListener(tiledGLEL); - } - - public void detachAutoDrawable() { - if( null != glad ) { - glad.removeGLEventListener(tiledGLEL); - final int aSz = listenersInit.length; - for(int i=0; i<aSz; i++) { - final GLEventListener l = listeners[i]; - glad.addGLEventListener(l); - glad.setGLEventListenerInitState(l, listenersInit[i]); - } - listeners = null; - listenersInit = null; - glad = null; - pmvMatrixCB = null; - } - } - - /** - * Rendering one tile, by simply calling {@link GLAutoDrawable#display()}. - * - * @return true if there are more tiles to be rendered, false if the final image is complete - * @throws IllegalStateException if no {@link GLAutoDrawable} is {@link #attachAutoDrawable(GLAutoDrawable, int) attached} - * or imageSize is not set - */ - public boolean display() throws IllegalStateException { - if( null == glad ) { - throw new IllegalStateException("No GLAutoDrawable attached"); - } - glad.display(); - return !eot(); - } - - private final GLEventListener tiledGLEL = new GLEventListener() { - @Override - public void init(GLAutoDrawable drawable) { - final int aSz = listenersInit.length; - for(int i=0; i<aSz; i++) { - final GLEventListener l = listeners[i]; - l.init(drawable); - listenersInit[i] = true; - } - } - @Override - public void dispose(GLAutoDrawable drawable) { - final int aSz = listenersInit.length; - for(int i=0; i<aSz; i++) { - listeners[i].dispose(drawable); - } - } - @Override - public void display(GLAutoDrawable drawable) { - final GL2ES3 gl = drawable.getGL().getGL2ES3(); - - beginTile(gl); - - final int aSz = listenersInit.length; - for(int i=0; i<aSz; i++) { - listeners[i].display(drawable); - } - - endTile(gl); - } - @Override - public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { - final int aSz = listenersInit.length; - for(int i=0; i<aSz; i++) { - listeners[i].reshape(drawable, x, y, width, height); - } - } - }; -} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/TestTiledRendering1GL2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/TestTiledRendering1GL2.java deleted file mode 100644 index 05da3d71b..000000000 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/TestTiledRendering1GL2.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.jogamp.opengl.test.junit.jogl.demos.gl2; - -import com.jogamp.common.util.IOUtil; -import com.jogamp.opengl.util.TGAWriter; -import com.jogamp.opengl.util.TileRenderer; -import com.jogamp.opengl.util.awt.ImageUtil; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import javax.imageio.ImageIO; -import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLOffscreenAutoDrawable; - -/** Demonstrates the TileRenderer class by rendering a large version - of the Gears demo to the specified file. */ - -public class TestTiledRendering1GL2 { - - public static void main(String[] args) throws IOException { - - if (args.length != 1) { - System.out.println("Usage: java TiledRendering [output file name]"); - System.out.println("Writes output (a large version of the Gears demo) to"); - System.out.println("the specified file, using either ImageIO or the fast TGA writer"); - System.out.println("depending on the file extension."); - System.exit(1); - } - - String filename = args[0]; - File file = new File(filename); - - GLCapabilities caps = new GLCapabilities(null); - caps.setDoubleBuffered(false); - - if (!GLDrawableFactory.getFactory(caps.getGLProfile()).canCreateGLPbuffer(null, caps.getGLProfile())) { - System.out.println("Demo requires pbuffer support"); - System.exit(1); - } - - // Use a pbuffer for rendering - final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); - final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(null, caps, null, 256, 256, null); - - // Fix the image size for now - // final int imageWidth = glad.getWidth() * 16; - // final int imageHeight = glad.getHeight() * 12; - final int imageWidth = glad.getWidth() * 2; - final int imageHeight = glad.getHeight() * 2; - - System.err.println("XXX1: "+imageWidth+"x"+imageHeight); - System.err.println("XXX1: "+glad); - - // Figure out the file format - TGAWriter tga = null; - BufferedImage img = null; - ByteBuffer buf = null; - - if (filename.endsWith(".tga")) { - tga = new TGAWriter(); - tga.open(file, - imageWidth, - imageHeight, - false); - buf = tga.getImageData(); - } else { - img = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_3BYTE_BGR); - buf = ByteBuffer.wrap(((DataBufferByte) img.getRaster().getDataBuffer()).getData()); - } - - // Initialize the tile rendering library - final TileRenderer renderer = new com.jogamp.opengl.util.TileRenderer(); - final TileRenderer.PMVMatrixCallback pmvMatrixCallback = new TileRenderer.PMVMatrixCallback() { - public void reshapePMVMatrix(GL _gl, int tileNum, int tileColumn, int tileRow, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight) { - final GL2 gl = _gl.getGL2(); - gl.glMatrixMode( GL2.GL_PROJECTION ); - gl.glLoadIdentity(); - - /* compute projection parameters */ - float left, right, bottom, top; - if( imageHeight > imageWidth ) { - float a = (float)imageHeight / (float)imageWidth; - left = -1.0f; - right = 1.0f; - bottom = -a; - top = a; - } else { - float a = (float)imageWidth / (float)imageHeight; - left = -a; - right = a; - bottom = -1.0f; - top = 1.0f; - } - final float w = right - left; - final float h = top - bottom; - final float l = left + w * tileX / imageWidth; - final float r = l + w * tileWidth / imageWidth; - final float b = bottom + h * tileY / imageHeight; - final float t = b + h * tileHeight / imageHeight; - - final float _w = r - l; - final float _h = t - b; - System.err.println(">> [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h); - gl.glFrustum(l, r, b, t, 5.0f, 60.0f); - - gl.glMatrixMode(GL2.GL_MODELVIEW); - } - }; - - renderer.setTileSize(glad.getWidth(), glad.getHeight(), 0); - renderer.setPMVMatrixCallback(pmvMatrixCallback); - renderer.setImageSize(imageWidth, imageHeight); - renderer.setImageBuffer(GL2.GL_BGR, GL.GL_UNSIGNED_BYTE, buf); - - glad.addGLEventListener( new GLEventListener() { - @Override - public void init(GLAutoDrawable drawable) { - System.err.println("XXX2: "+drawable); - } - @Override - public void dispose(GLAutoDrawable drawable) { - } - @Override - public void display(GLAutoDrawable drawable) { - renderer.beginTile(drawable.getGL().getGL2()); - } - @Override - public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { - } - }); - final Gears gears = new Gears(); - gears.setDoRotation(false); - glad.addGLEventListener( gears ); - glad.addGLEventListener( new GLEventListener() { - @Override - public void init(GLAutoDrawable drawable) { - } - @Override - public void dispose(GLAutoDrawable drawable) { - } - @Override - public void display(GLAutoDrawable drawable) { - renderer.endTile(drawable.getGL().getGL2()); - } - @Override - public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { - } - }); - - do { - glad.display(); - } while ( !renderer.eot() ); - - glad.destroy(); - - // Close things up and/or write image using ImageIO - if (tga != null) { - tga.close(); - } else { - ImageUtil.flipImageVertically(img); - if (!ImageIO.write(img, IOUtil.getFileSuffix(file), file)) { - System.err.println("Error writing file using ImageIO (unsupported file format?)"); - } - } - } -} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/TestTiledRendering2GL2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/TestTiledRendering2GL2.java deleted file mode 100644 index 2f04f5a0c..000000000 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/TestTiledRendering2GL2.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.jogamp.opengl.test.junit.jogl.demos.gl2; - -import com.jogamp.common.util.IOUtil; -import com.jogamp.opengl.util.TGAWriter; -import com.jogamp.opengl.util.TileRenderer; -import com.jogamp.opengl.util.TileRenderer2; - -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import javax.imageio.ImageIO; -import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLOffscreenAutoDrawable; - -/** Demonstrates the TileRenderer class by rendering a large version - of the Gears demo to the specified file. */ - -public class TestTiledRendering2GL2 { - - public static void main(String[] args) throws IOException { - - if (args.length != 1) { - System.out.println("Usage: java TiledRendering [output file name]"); - System.out.println("Writes output (a large version of the Gears demo) to"); - System.out.println("the specified file, using either ImageIO or the fast TGA writer"); - System.out.println("depending on the file extension."); - System.exit(1); - } - - String filename = args[0]; - File file = new File(filename); - - GLCapabilities caps = new GLCapabilities(null); - caps.setDoubleBuffered(false); - - if (!GLDrawableFactory.getFactory(caps.getGLProfile()).canCreateGLPbuffer(null, caps.getGLProfile())) { - System.out.println("Demo requires pbuffer support"); - System.exit(1); - } - - // Use a pbuffer for rendering - final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); - final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(null, caps, null, 256, 256, null); - - final Gears gears = new Gears(); - gears.setDoRotation(false); - glad.addGLEventListener( gears ); - - // Fix the image size for now - // final int imageWidth = glad.getWidth() * 16; - // final int imageHeight = glad.getHeight() * 12; - final int imageWidth = glad.getWidth() * 2; - final int imageHeight = glad.getHeight() * 2; - - // Figure out the file format - TGAWriter tga = null; - BufferedImage img = null; - ByteBuffer buf = null; - - if (filename.endsWith(".tga")) { - tga = new TGAWriter(); - tga.open(file, - imageWidth, - imageHeight, - false); - buf = tga.getImageData(); - } else { - img = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_3BYTE_BGR); - buf = ByteBuffer.wrap(((DataBufferByte) img.getRaster().getDataBuffer()).getData()); - } - - // Initialize the tile rendering library - final TileRenderer2 renderer = new TileRenderer2(); - final TileRenderer.PMVMatrixCallback pmvMatrixCallback = new TileRenderer.PMVMatrixCallback() { - public void reshapePMVMatrix(GL _gl, int tileNum, int tileColumn, int tileRow, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight) { - final GL2 gl = _gl.getGL2(); - gl.glMatrixMode( GL2.GL_PROJECTION ); - gl.glLoadIdentity(); - - /* compute projection parameters */ - float left, right, bottom, top; - if( imageHeight > imageWidth ) { - float a = (float)imageHeight / (float)imageWidth; - left = -1.0f; - right = 1.0f; - bottom = -a; - top = a; - } else { - float a = (float)imageWidth / (float)imageHeight; - left = -a; - right = a; - bottom = -1.0f; - top = 1.0f; - } - final float w = right - left; - final float h = top - bottom; - final float l = left + w * tileX / imageWidth; - final float r = l + w * tileWidth / imageWidth; - final float b = bottom + h * tileY / imageHeight; - final float t = b + h * tileHeight / imageHeight; - - final float _w = r - l; - final float _h = t - b; - System.err.println(">> [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h); - gl.glFrustum(l, r, b, t, 5.0f, 60.0f); - - gl.glMatrixMode(GL2.GL_MODELVIEW); - } - }; - - renderer.attachAutoDrawable(glad, 0, pmvMatrixCallback); - renderer.setImageSize(imageWidth, imageHeight); - renderer.setImageBuffer(GL2.GL_BGR, GL.GL_UNSIGNED_BYTE, buf); - - while ( renderer.display() ); - - renderer.detachAutoDrawable(); - - glad.destroy(); - - // Close things up and/or write image using ImageIO - if (tga != null) { - tga.close(); - } else { - if (!ImageIO.write(img, IOUtil.getFileSuffix(file), file)) { - System.err.println("Error writing file using ImageIO (unsupported file format?)"); - } - } - } -} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2.java new file mode 100644 index 000000000..1d917efb9 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2.java @@ -0,0 +1,167 @@ +package com.jogamp.opengl.test.junit.jogl.tile; + +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.GLPixelBuffer; +import com.jogamp.opengl.util.RandomTileRenderer; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; + +import java.io.File; +import java.io.IOException; +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLOffscreenAutoDrawable; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** Demonstrates the RandomTileRenderer class by rendering a large version + of the Gears demo to the specified file. */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestRandomTiledRendering2GL2 extends UITestCase { + static long duration = 500; // ms + + @Test + public void test01() throws IOException { + doTest(); + } + + void doTest() throws IOException { + GLCapabilities caps = new GLCapabilities(null); + caps.setDoubleBuffered(false); + + // Use a pbuffer for rendering + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(null, caps, null, 256, 256, null); + + final Gears gears = new Gears(); + gears.setDoRotation(false); + glad.addGLEventListener( gears ); + + // Fix the image size for now + final int imageWidth = glad.getWidth() * 6; + final int imageHeight = glad.getHeight() * 4; + + final String filename = this.getSnapshotFilename(0, "-tile", glad.getChosenGLCapabilities(), imageWidth, imageHeight, false, TextureIO.PNG, null); + final File file = new File(filename); + + // Initialize the tile rendering library + final RandomTileRenderer renderer = new RandomTileRenderer(); + final RandomTileRenderer.PMVMatrixCallback pmvMatrixCallback = new RandomTileRenderer.PMVMatrixCallback() { + public void reshapePMVMatrix(GL _gl, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight) { + final GL2 gl = _gl.getGL2(); + gl.glMatrixMode( GL2.GL_PROJECTION ); + gl.glLoadIdentity(); + + /* compute projection parameters */ + float left, right, bottom, top; + if( imageHeight > imageWidth ) { + float a = (float)imageHeight / (float)imageWidth; + left = -1.0f; + right = 1.0f; + bottom = -a; + top = a; + } else { + float a = (float)imageWidth / (float)imageHeight; + left = -a; + right = a; + bottom = -1.0f; + top = 1.0f; + } + final float w = right - left; + final float h = top - bottom; + final float l = left + w * tileX / imageWidth; + final float r = l + w * tileWidth / imageWidth; + final float b = bottom + h * tileY / imageHeight; + final float t = b + h * tileHeight / imageHeight; + + final float _w = r - l; + final float _h = t - b; + System.err.println(">> [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h); + gl.glFrustum(l, r, b, t, 5.0f, 60.0f); + + gl.glMatrixMode(GL2.GL_MODELVIEW); + } + }; + renderer.attachAutoDrawable(glad, pmvMatrixCallback); + renderer.setImageSize(imageWidth, imageHeight); + + final GLPixelBuffer.GLPixelBufferProvider pixelBufferProvider = GLPixelBuffer.defaultProviderWithRowStride; + final boolean[] flipVertically = { false }; + + final GLEventListener preTileGLEL = new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); + System.err.println("XXX: "+pixelAttribs+", gl2gl3 "+gl.isGL2GL3()+", "+gl.getContext().getGLVersion()); + GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + System.err.println("XXX: "+pixelBuffer); + renderer.setImageBuffer(pixelBuffer); + if( drawable.isGLOriented() ) { + flipVertically[0] = false; + } else { + flipVertically[0] = true; + } + } + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void display(GLAutoDrawable drawable) {} + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }; + renderer.setGLEventListener(preTileGLEL, null); + + final int w = 50, h = 50; + int dx = 0, dy = 0; + while( dx+w <= imageWidth && dy+h <= imageHeight ) { + renderer.display(dx, dy, w, h); + dx+=w+w/2; + if( dx + w > imageWidth ) { + dx = 0; + dy+=h+h/2; + } + } + + renderer.detachAutoDrawable(); + + glad.destroy(); + + final GLPixelBuffer imageBuffer = renderer.getImageBuffer(); + imageBuffer.clear(); // full size available + System.err.println("XXX2: "+imageBuffer); + final TextureData textureData = new TextureData( + caps.getGLProfile(), + 0 /* internalFormat */, + imageWidth, imageHeight, + 0, + imageBuffer.pixelAttributes, + false, false, + flipVertically[0], + imageBuffer.buffer, + null /* Flusher */); + System.err.println("XXX3: "+textureData.getPixelFormat()+", "+textureData.getPixelAttributes()); + + TextureIO.write(textureData, file); + } + + public static void main(String args[]) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + org.junit.runner.JUnitCore.main(TestRandomTiledRendering2GL2.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2.java new file mode 100644 index 000000000..7b1272993 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2.java @@ -0,0 +1,168 @@ +package com.jogamp.opengl.test.junit.jogl.tile; + +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.GLPixelBuffer; +import com.jogamp.opengl.util.TileRenderer; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; + +import java.io.File; +import java.io.IOException; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLOffscreenAutoDrawable; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** Demonstrates the TileRenderer class by rendering a large version + of the Gears demo to the specified file. */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestTiledRendering1GL2 extends UITestCase { + static long duration = 500; // ms + + @Test + public void test01() throws IOException { + doTest(); + } + + void doTest() throws IOException { + GLCapabilities caps = new GLCapabilities(null); + caps.setDoubleBuffered(false); + + // Use a pbuffer for rendering + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(null, caps, null, 256, 256, null); + + // Fix the image size for now + final int imageWidth = glad.getWidth() * 6; + final int imageHeight = glad.getHeight() * 4; + + final String filename = this.getSnapshotFilename(0, "-tile", glad.getChosenGLCapabilities(), imageWidth, imageHeight, false, TextureIO.PNG, null); + final File file = new File(filename); + + // Initialize the tile rendering library + final TileRenderer renderer = new com.jogamp.opengl.util.TileRenderer(); + final TileRenderer.PMVMatrixCallback pmvMatrixCallback = new TileRenderer.PMVMatrixCallback() { + public void reshapePMVMatrix(GL _gl, int tileNum, int tileColumn, int tileRow, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight) { + final GL2 gl = _gl.getGL2(); + gl.glMatrixMode( GL2.GL_PROJECTION ); + gl.glLoadIdentity(); + + /* compute projection parameters */ + float left, right, bottom, top; + if( imageHeight > imageWidth ) { + float a = (float)imageHeight / (float)imageWidth; + left = -1.0f; + right = 1.0f; + bottom = -a; + top = a; + } else { + float a = (float)imageWidth / (float)imageHeight; + left = -a; + right = a; + bottom = -1.0f; + top = 1.0f; + } + final float w = right - left; + final float h = top - bottom; + final float l = left + w * tileX / imageWidth; + final float r = l + w * tileWidth / imageWidth; + final float b = bottom + h * tileY / imageHeight; + final float t = b + h * tileHeight / imageHeight; + + final float _w = r - l; + final float _h = t - b; + System.err.println(">> [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h); + gl.glFrustum(l, r, b, t, 5.0f, 60.0f); + + gl.glMatrixMode(GL2.GL_MODELVIEW); + } + }; + + renderer.setTileSize(glad.getWidth(), glad.getHeight(), 0); + renderer.setPMVMatrixCallback(pmvMatrixCallback); + renderer.setImageSize(imageWidth, imageHeight); + + final GLPixelBuffer.GLPixelBufferProvider pixelBufferProvider = GLPixelBuffer.defaultProviderWithRowStride; + final boolean[] flipVertically = { false }; + + glad.addGLEventListener( new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); + GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + renderer.setImageBuffer(pixelBuffer); + if( drawable.isGLOriented() ) { + flipVertically[0] = false; + } else { + flipVertically[0] = true; + } + } + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void display(GLAutoDrawable drawable) { + renderer.beginTile(drawable.getGL().getGL2()); + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }); + final Gears gears = new Gears(); + gears.setDoRotation(false); + glad.addGLEventListener( gears ); + glad.addGLEventListener( new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) {} + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void display(GLAutoDrawable drawable) { + renderer.endTile(drawable.getGL().getGL2()); + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }); + + do { + glad.display(); + } while ( !renderer.eot() ); + + glad.destroy(); + + final GLPixelBuffer imageBuffer = renderer.getImageBuffer(); + final TextureData textureData = new TextureData( + caps.getGLProfile(), + 0 /* internalFormat */, + imageWidth, imageHeight, + 0, + imageBuffer.pixelAttributes, + false, false, + flipVertically[0], + imageBuffer.buffer, + null /* Flusher */); + + TextureIO.write(textureData, file); + } + + public static void main(String args[]) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + org.junit.runner.JUnitCore.main(TestTiledRendering1GL2.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2GL2.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2GL2.java new file mode 100644 index 000000000..27198b149 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2GL2.java @@ -0,0 +1,154 @@ +package com.jogamp.opengl.test.junit.jogl.tile; + +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.GLPixelBuffer; +import com.jogamp.opengl.util.TileRenderer; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; + +import java.io.File; +import java.io.IOException; +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLOffscreenAutoDrawable; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** Demonstrates the TileRenderer class by rendering a large version + of the Gears demo to the specified file. */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestTiledRendering2GL2 extends UITestCase { + static long duration = 500; // ms + + @Test + public void test01() throws IOException { + doTest(); + } + + void doTest() throws IOException { + GLCapabilities caps = new GLCapabilities(null); + caps.setDoubleBuffered(false); + + // Use a pbuffer for rendering + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(null, caps, null, 256, 256, null); + + final Gears gears = new Gears(); + gears.setDoRotation(false); + glad.addGLEventListener( gears ); + + // Fix the image size for now + final int imageWidth = glad.getWidth() * 6; + final int imageHeight = glad.getHeight() * 4; + + final String filename = this.getSnapshotFilename(0, "-tile", glad.getChosenGLCapabilities(), imageWidth, imageHeight, false, TextureIO.PNG, null); + final File file = new File(filename); + + // Initialize the tile rendering library + final TileRenderer renderer = new TileRenderer(); + final TileRenderer.PMVMatrixCallback pmvMatrixCallback = new TileRenderer.PMVMatrixCallback() { + public void reshapePMVMatrix(GL _gl, int tileNum, int tileColumn, int tileRow, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight) { + final GL2 gl = _gl.getGL2(); + gl.glMatrixMode( GL2.GL_PROJECTION ); + gl.glLoadIdentity(); + + /* compute projection parameters */ + float left, right, bottom, top; + if( imageHeight > imageWidth ) { + float a = (float)imageHeight / (float)imageWidth; + left = -1.0f; + right = 1.0f; + bottom = -a; + top = a; + } else { + float a = (float)imageWidth / (float)imageHeight; + left = -a; + right = a; + bottom = -1.0f; + top = 1.0f; + } + final float w = right - left; + final float h = top - bottom; + final float l = left + w * tileX / imageWidth; + final float r = l + w * tileWidth / imageWidth; + final float b = bottom + h * tileY / imageHeight; + final float t = b + h * tileHeight / imageHeight; + + final float _w = r - l; + final float _h = t - b; + System.err.println(">> [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h); + gl.glFrustum(l, r, b, t, 5.0f, 60.0f); + + gl.glMatrixMode(GL2.GL_MODELVIEW); + } + }; + + renderer.attachAutoDrawable(glad, 0, pmvMatrixCallback); + renderer.setImageSize(imageWidth, imageHeight); + + final GLPixelBuffer.GLPixelBufferProvider pixelBufferProvider = GLPixelBuffer.defaultProviderWithRowStride; + final boolean[] flipVertically = { false }; + + final GLEventListener preTileGLEL = new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); + GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + renderer.setImageBuffer(pixelBuffer); + if( drawable.isGLOriented() ) { + flipVertically[0] = false; + } else { + flipVertically[0] = true; + } + } + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void display(GLAutoDrawable drawable) {} + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }; + renderer.setGLEventListener(preTileGLEL, null); + + while ( renderer.display() ); + + renderer.detachAutoDrawable(); + + glad.destroy(); + + final GLPixelBuffer imageBuffer = renderer.getImageBuffer(); + final TextureData textureData = new TextureData( + caps.getGLProfile(), + 0 /* internalFormat */, + imageWidth, imageHeight, + 0, + imageBuffer.pixelAttributes, + false, false, + flipVertically[0], + imageBuffer.buffer, + null /* Flusher */); + + TextureIO.write(textureData, file); + } + + public static void main(String args[]) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + org.junit.runner.JUnitCore.main(TestTiledRendering2GL2.class.getName()); + } +} |