diff options
10 files changed, 844 insertions, 408 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index bbb8c6ece..61b805215 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -328,6 +328,7 @@ function testawtswt() { 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 $* +testawt com.jogamp.opengl.test.junit.jogl.tile.TestRandomTiledRendering3GL2AWT $* # # core/newt (testnoawt and testawt) diff --git a/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java index 0fba1170d..4fcf0b6cc 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java @@ -29,12 +29,14 @@ package com.jogamp.opengl.util; 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. + * <p> + * See {@link TileRendererBase} for details. + * </p> */ public class RandomTileRenderer extends TileRendererBase { private boolean tileRectSet = false; @@ -47,8 +49,8 @@ public class RandomTileRenderer extends TileRendererBase { } @Override - public final int getParam(int param) { - switch (param) { + public final int getParam(int pname) { + switch (pname) { case TR_IMAGE_WIDTH: return imageSize.getWidth(); case TR_IMAGE_HEIGHT: @@ -62,7 +64,7 @@ public class RandomTileRenderer extends TileRendererBase { case TR_CURRENT_TILE_HEIGHT: return currentTileHeight; default: - throw new IllegalArgumentException("Invalid enumerant as argument"); + throw new IllegalArgumentException("Invalid pname: "+pname); } } @@ -94,15 +96,14 @@ public class RandomTileRenderer extends TileRendererBase { 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( !tileRectSet ) { throw new IllegalStateException("tileRect has not been set"); } gl.glViewport( 0, 0, currentTileWidth, currentTileHeight ); - pmvMatrixCB.reshapePMVMatrix(gl, currentTileXPos, currentTileYPos, currentTileWidth, currentTileHeight, imageSize.getWidth(), imageSize.getHeight()); + // Do not forget to issue: + // reshape( 0, 0, tW, tH ); + // which shall reflect tile renderer fileds: currentTileXPos, currentTileYPos and imageSize beginCalled = true; } @@ -178,75 +179,11 @@ public class RandomTileRenderer extends TileRendererBase { /** * Rendering one tile, by simply calling {@link GLAutoDrawable#display()}. * - * @throws IllegalStateException if no {@link GLAutoDrawable} is {@link #attachToAutoDrawable(GLAutoDrawable, int) attached} + * @throws IllegalStateException if no {@link GLAutoDrawable} is {@link #attachToAutoDrawable(GLAutoDrawable) attached} * or imageSize is not set */ public void display(int tX, int tY, int tWidth, int tHeight) throws IllegalStateException { setTileRect(tX, tY, tWidth, tHeight); display(); } - - protected final GLEventListener getTiledGLEL() { return tiledGLEL; } - 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/TileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java index a63694207..3bb9dc169 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java @@ -39,7 +39,6 @@ package com.jogamp.opengl.util; import javax.media.nativewindow.util.Dimension; import javax.media.opengl.GL2ES3; import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLEventListener; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; @@ -56,48 +55,51 @@ import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; * <p> * Enhanced for {@link GL2ES3}. * </p> + * <p> + * See {@link TileRendererBase} for details. + * </p> * * @author ryanm, sgothel */ public class TileRenderer extends TileRendererBase { /** - * The width of a tile + * The width of a tile. See {@link #getParam(int)}. */ public static final int TR_TILE_WIDTH = 7; /** - * The height of a tile + * The height of a tile. See {@link #getParam(int)}. */ public static final int TR_TILE_HEIGHT = 8; /** - * The width of the border around the tiles + * The width of the border around the tiles. See {@link #getParam(int)}. */ public static final int TR_TILE_BORDER = 9; /** - * The number of rows of tiles + * The number of rows of tiles. See {@link #getParam(int)}. */ public static final int TR_ROWS = 10; /** - * The number of columns of tiles + * The number of columns of tiles. See {@link #getParam(int)}. */ public static final int TR_COLUMNS = 11; /** - * The current row number + * The current row number. See {@link #getParam(int)}. */ public static final int TR_CURRENT_ROW = 12; /** - * The current column number + * The current column number. See {@link #getParam(int)}. */ public static final int TR_CURRENT_COLUMN = 13; /** - * The order that the rows are traversed + * The order that the rows are traversed. See {@link #getParam(int)}. */ public static final int TR_ROW_ORDER = 14; /** - * Indicates we are traversing rows from the top to the bottom + * Indicates we are traversing rows from the top to the bottom. See {@link #getParam(int)}. */ public static final int TR_TOP_TO_BOTTOM = 15; /** - * Indicates we are traversing rows from the bottom to the top + * Indicates we are traversing rows from the bottom to the top. See {@link #getParam(int)}. */ public static final int TR_BOTTOM_TO_TOP = 16; @@ -180,8 +182,8 @@ public class TileRenderer extends TileRendererBase { public final boolean eot() { return 0 > currentTile; } @Override - public final int getParam(int param) { - switch (param) { + public final int getParam(int pname) { + switch (pname) { case TR_TILE_WIDTH: return tileSize.getWidth(); case TR_TILE_HEIGHT: @@ -219,7 +221,7 @@ public class TileRenderer extends TileRendererBase { case TR_ROW_ORDER: return rowOrder; default: - throw new IllegalArgumentException("Invalid enumerant as argument"); + throw new IllegalArgumentException("Invalid pname: "+pname); } } @@ -243,9 +245,6 @@ public class TileRenderer extends TileRendererBase { 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 (currentTile <= 0) { setup(); } @@ -297,7 +296,9 @@ public class TileRenderer extends TileRendererBase { } gl.glViewport( 0, 0, tW, tH ); - pmvMatrixCB.reshapePMVMatrix(gl, currentTileXPos, currentTileYPos, tW, tH, imageSize.getWidth(), imageSize.getHeight()); + // Do not forget to issue: + // reshape( 0, 0, tW, tH ); + // which shall reflect tile renderer fileds: currentTileXPos, currentTileYPos and imageSize beginCalled = true; } @@ -385,72 +386,8 @@ public class TileRenderer extends TileRendererBase { * </p> */ @Override - public void attachToAutoDrawable(GLAutoDrawable glad, PMVMatrixCallback pmvMatrixCB) throws IllegalStateException { - super.attachToAutoDrawable(glad, pmvMatrixCB); + public void attachToAutoDrawable(GLAutoDrawable glad) throws IllegalStateException { + super.attachToAutoDrawable(glad); setTileSize(glad.getWidth(), glad.getHeight(), 0); } - - protected final GLEventListener getTiledGLEL() { return tiledGLEL; } - 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/TileRendererBase.java b/src/jogl/classes/com/jogamp/opengl/util/TileRendererBase.java index 3aa6ea786..8779fa59f 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/TileRendererBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/TileRendererBase.java @@ -37,7 +37,6 @@ 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; @@ -55,32 +54,43 @@ import javax.media.opengl.GLEventListener; * <p> * Enhanced for {@link GL2ES3}, abstracted to suit {@link TileRenderer} and {@link RandomTileRenderer}. * </p> + * <a name="pmvmatrix"><h5>PMV Matrix Considerations</h5></a> + * <p> + * The PMV matrix needs to be reshaped in user code + * after calling {@link #beginTile(GL2ES3)}, See {@link #beginTile(GL2ES3)}. + * </p> + * <p> + * If {@link #attachToAutoDrawable(GLAutoDrawable) attaching to} an {@link GLAutoDrawable}, + * the {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int)} method + * is being called after {@link #beginTile(GL2ES3)}. + * It's implementation shall reshape the PMV matrix according to {@link #beginTile(GL2ES3)}. + * </p> * * @author ryanm, sgothel */ public abstract class TileRendererBase { /** - * The width of the final image + * The width of the final image. See {@link #getParam(int)}. */ public static final int TR_IMAGE_WIDTH = 1; /** - * The height of the final image + * The height of the final image. See {@link #getParam(int)}. */ public static final int TR_IMAGE_HEIGHT = 2; /** - * The width of the current tile + * The width of the current tile. See {@link #getParam(int)}. */ public static final int TR_CURRENT_TILE_X_POS = 3; /** - * The height of the current tile + * The height of the current tile. See {@link #getParam(int)}. */ public static final int TR_CURRENT_TILE_Y_POS = 4; /** - * The width of the current tile + * The width of the current tile. See {@link #getParam(int)}. */ public static final int TR_CURRENT_TILE_WIDTH = 5; /** - * The height of the current tile + * The height of the current tile. See {@link #getParam(int)}. */ public static final int TR_CURRENT_TILE_HEIGHT = 6; @@ -88,7 +98,6 @@ public abstract class TileRendererBase { protected final GLPixelStorageModes psm = new GLPixelStorageModes(); protected GLPixelBuffer imageBuffer; protected GLPixelBuffer tileBuffer; - protected PMVMatrixCallback pmvMatrixCB = null; protected boolean beginCalled = false; protected int currentTileXPos; protected int currentTileYPos; @@ -100,34 +109,19 @@ public abstract class TileRendererBase { protected GLEventListener glEventListenerPre = null; protected GLEventListener glEventListenerPost = null; - public static interface PMVMatrixCallback { - void reshapePMVMatrix(GL gl, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight); - } - protected TileRendererBase() { } /** * Gets the parameters of this TileRenderer object * - * @param param The parameter that is to be retrieved + * @param pname The parameter name that is to be retrieved * @return the value of the parameter - * @throws IllegalArgumentException if <code>param</code> is not handled + * @throws IllegalArgumentException if <code>pname</code> is not handled */ - public abstract int getParam(int param) throws IllegalArgumentException; + public abstract int getParam(int pname) throws IllegalArgumentException; /** - * @param pmvMatrixCB - * @throws IllegalArgumentException if <code>pmvMatrixCB</code> is null - */ - public final void setPMVMatrixCallback(PMVMatrixCallback pmvMatrixCB) throws IllegalArgumentException { - if( null == pmvMatrixCB ) { - throw new IllegalArgumentException("pmvMatrixCB is null"); - } - 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. @@ -170,13 +164,26 @@ public abstract class TileRendererBase { /** * Begins rendering a tile. * <p> - * Methods modifies the viewport. - * User shall reset the viewport when finishing tile rendering, - * i.e. after last call of {@link #endTile(GL2ES3)}! + * Methods modifies the viewport, see below. + * User shall reset the viewport when finishing all tile rendering, + * i.e. after very last call of {@link #endTile(GL2ES3)}! * </p> - * <p> - * The projection matrix stack should be - * left alone after calling this method! + * <p> + * The <a href="#pmvmatrix">PMV Matrix</a> + * must be reshaped after this call using: + * <ul> + * <li>Current Viewport + * <ul> + * <li>x 0</li> + * <li>y 0</li> + * <li>{@link #TR_CURRENT_TILE_WIDTH tile width}</li> + * <li>{@link #TR_CURRENT_TILE_HEIGHT tile height}</li> + * </ul></li> + * <li>{@link #TR_CURRENT_TILE_X_POS tile x-pos}</li> + * <li>{@link #TR_CURRENT_TILE_Y_POS tile y-pos}</li> + * <li>{@link #TR_IMAGE_WIDTH image width}</li> + * <li>{@link #TR_IMAGE_HEIGHT image height}</li> + * </ul> * </p> * <p> * Use shall render the scene afterwards, concluded with a call to @@ -200,23 +207,46 @@ public abstract class TileRendererBase { /** * Attaches this renderer to the {@link GLAutoDrawable}. * <p> - * The {@link GLAutoDrawable}'s {@link GLEventListener} are removed first and stored locally. + * The {@link GLAutoDrawable}'s original {@link GLEventListener} are moved to local storage. * This renderer {@link GLEventListener} is then added to handle the tile rendering - * for the original {@link GLEventListener}. + * for the original {@link GLEventListener}, i.e. it's {@link GLEventListener#display(GLAutoDrawable) display} issues: + * <ul> + * <li>Optional {@link #setGLEventListener(GLEventListener, GLEventListener) pre-glel}.{@link GLEventListener#display(GLAutoDrawable) display(..)}</li> + * <li>{@link #beginTile(GL2ES3)}</li> + * <li>for all original {@link GLEventListener}: + * <ul> + * <li>{@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(0, 0, tile-width, tile-height)}</li> + * <li>{@link GLEventListener#display(GLAutoDrawable) display(autoDrawable)}</li> + * </ul></li> + * <li>{@link #endTile(GL2ES3)}</li> + * <li>Optional {@link #setGLEventListener(GLEventListener, GLEventListener) post-glel}.{@link GLEventListener#display(GLAutoDrawable) display(..)}</li> + * </ul> + * </p> + * <p> + * Consider using {@link #setGLEventListener(GLEventListener, GLEventListener)} to add pre- and post + * hooks to be performed on this renderer {@link GLEventListener}.<br> + * The pre-hook is able to allocate memory and setup parameters, since it's called before {@link #beginTile(GL2ES3)}.<br> + * The post-hook is able to use the rendering result and can even shutdown tile-rendering, + * since it's called after {@link #endTile(GL2ES3)}. * </p> * <p> * Call {@link #detachFromAutoDrawable()} to remove this renderer from the {@link GLAutoDrawable} * and to restore it's original {@link GLEventListener}. * </p> + * <p> + * The <a href="#pmvmatrix">PMV Matrix</a> shall be reshaped in the + * original {@link GLEventListener}'s {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape} + * method. The latter is called for each tile w/ the current viewport. + * The tile's position and image size can be utilized. See details in {@link #beginTile(GL2ES3)}. + * </p> * @param glad * @throws IllegalStateException if an {@link GLAutoDrawable} is already attached */ - public void attachToAutoDrawable(GLAutoDrawable glad, PMVMatrixCallback pmvMatrixCB) throws IllegalStateException { + public void attachToAutoDrawable(GLAutoDrawable glad) 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]; @@ -226,18 +256,18 @@ public abstract class TileRendererBase { listenersInit[i] = glad.getGLEventListenerInitState(l); listeners[i] = glad.removeGLEventListener( l ); } - glad.addGLEventListener(getTiledGLEL()); + glad.addGLEventListener(tiledGLEL); } /** * Detaches this renderer from the {@link GLAutoDrawable}. * <p> - * See {@link #attachToAutoDrawable(GLAutoDrawable, PMVMatrixCallback)}. + * See {@link #attachToAutoDrawable(GLAutoDrawable)}. * </p> */ public void detachFromAutoDrawable() { if( null != glad ) { - glad.removeGLEventListener(getTiledGLEL()); + glad.removeGLEventListener(tiledGLEL); final int aSz = listenersInit.length; for(int i=0; i<aSz; i++) { final GLEventListener l = listeners[i]; @@ -247,13 +277,9 @@ public abstract class TileRendererBase { listeners = null; listenersInit = null; glad = null; - pmvMatrixCB = null; } } - /** Return this rendere {@link GLEventListener} implementation. */ - protected abstract GLEventListener getTiledGLEL(); - /** * Set {@link GLEventListener} for pre- and post operations when used w/ * {@link #attachAutoDrawable(GLAutoDrawable, int, PMVMatrixCallback)} @@ -269,7 +295,7 @@ public abstract class TileRendererBase { /** * Rendering one tile, by simply calling {@link GLAutoDrawable#display()}. * - * @throws IllegalStateException if no {@link GLAutoDrawable} is {@link #attachToAutoDrawable(GLAutoDrawable, int) attached} + * @throws IllegalStateException if no {@link GLAutoDrawable} is {@link #attachToAutoDrawable(GLAutoDrawable) attached} * or imageSize is not set */ public void display() throws IllegalStateException { @@ -278,4 +304,68 @@ public abstract class TileRendererBase { } 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); + + final int aSz = listenersInit.length; + for(int i=0; i<aSz; i++) { + listeners[i].reshape(drawable, 0, 0, currentTileWidth, currentTileHeight); + 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/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index b7a24a777..e04051cc0 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -52,10 +52,14 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; +import java.awt.Rectangle; import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; import java.awt.EventQueue; import java.lang.reflect.InvocationTargetException; +import java.nio.IntBuffer; import java.util.ArrayList; import java.util.List; @@ -95,6 +99,11 @@ import com.jogamp.nativewindow.awt.AWTGraphicsScreen; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; import com.jogamp.nativewindow.awt.JAWTWindow; import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.util.GLPixelBuffer; +import com.jogamp.opengl.util.RandomTileRenderer; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; +import com.jogamp.opengl.util.awt.AWTGLPixelBuffer; +import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.SingleAWTGLPixelBufferProvider; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; @@ -719,6 +728,107 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing paint(g); } + private static SingleAWTGLPixelBufferProvider singleAWTGLPixelBufferProvider = null; + private static synchronized SingleAWTGLPixelBufferProvider getSingleAWTGLPixelBufferProvider() { + if( null == singleAWTGLPixelBufferProvider ) { + singleAWTGLPixelBufferProvider = new SingleAWTGLPixelBufferProvider( true /* allowRowStride */ ); + } + return singleAWTGLPixelBufferProvider; + } + private boolean animatorPaused = false; + private RandomTileRenderer tileRenderer; + private SingleAWTGLPixelBufferProvider printBufferProvider; + private IntBuffer cpuVFlipIntBbuffer; + + public void setupPrint(final int printWidth, final int printHeight, RandomTileRenderer.PMVMatrixCallback pmvMatrixCB) { + final GLAnimatorControl animator = helper.getAnimator(); + if( animator.isAnimating() ) { + animator.pause(); + animatorPaused = true; + } + printBufferProvider = getSingleAWTGLPixelBufferProvider(); + tileRenderer = new RandomTileRenderer(); + tileRenderer.setImageSize(printWidth, printHeight); + tileRenderer.attachToAutoDrawable(this); + final GLEventListener preTileGLEL = new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + GLPixelAttributes pixelAttribs = printBufferProvider.getAttributes(gl, 3); + GLPixelBuffer pixelBuffer = printBufferProvider.allocate(gl, pixelAttribs, drawable.getWidth(), drawable.getHeight(), 1, true, 0); + tileRenderer.setTileBuffer(pixelBuffer); + } + @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) {} + }; + tileRenderer.setGLEventListener(preTileGLEL, null); + } + public void releasePrint() { + tileRenderer.detachFromAutoDrawable(); + tileRenderer = null; + printBufferProvider = null; + singleAWTGLPixelBufferProvider = null; + final GLAnimatorControl animator = animatorPaused ? helper.getAnimator() : null; + if( null != animator ) { + animator.resume(); + } + animatorPaused = false; + } + + @Override + public void print(Graphics graphics) { + if( null != tileRenderer ) { + final Rectangle clip = graphics.getClipBounds(); + System.err.println("AWT print clip: "+clip); + tileRenderer.setTileRect(clip.x, clip.y, clip.width, clip.height); + } + super.print(graphics); + } + private void print(GL gl) { + final int componentCount; + if( isOpaque() ) { + // w/o alpha + componentCount = 3; + } else { + // with alpha + componentCount = 4; + } + final GLPixelAttributes pixelAttribs = printBufferProvider.getAttributes(gl, componentCount); + final int imageWidth = tileRenderer.getImageSize().getWidth(); + final int imageHeight = tileRenderer.getImageSize().getHeight(); + AWTGLPixelBuffer pixelBuffer = printBufferProvider.getSingleBuffer(pixelAttribs); + if( null != pixelBuffer && pixelBuffer.requiresNewBuffer(gl, imageWidth, imageHeight, 0) ) { + pixelBuffer.dispose(); + pixelBuffer = null; + } + if ( null == pixelBuffer ) { + pixelBuffer = printBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + } + if( null == cpuVFlipIntBbuffer || pixelBuffer.width * pixelBuffer.height > cpuVFlipIntBbuffer.remaining() ) { + cpuVFlipIntBbuffer = IntBuffer.allocate(pixelBuffer.width * pixelBuffer.height); + } + + tileRenderer.setImageBuffer(pixelBuffer); + + // Copy temporary data into raster of BufferedImage for faster + // blitting Note that we could avoid this copy in the cases + // where !offscreenDrawable.isGLOriented(), + // but that's the software rendering path which is very slow anyway. + final BufferedImage image = pixelBuffer.image; + final int[] src = cpuVFlipIntBbuffer.array(); + final int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); + final int incr = pixelBuffer.width; + int srcPos = 0; + int destPos = (imageHeight - 1) * pixelBuffer.width; + for (; destPos >= 0; srcPos += incr, destPos -= incr) { + System.arraycopy(src, srcPos, dest, destPos, incr); + } + } + @Override public void addGLEventListener(GLEventListener listener) { helper.addGLEventListener(listener); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java index d3ab05e82..0c84fac39 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java @@ -17,6 +17,7 @@ import com.jogamp.newt.event.MouseListener; import com.jogamp.newt.event.awt.AWTKeyAdapter; import com.jogamp.newt.event.awt.AWTMouseAdapter; import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.util.TileRendererBase; /** * Gears.java <BR> @@ -33,7 +34,8 @@ public class Gears implements GLEventListener { private int swapInterval; private MouseListener gearsMouse = new GearsMouseAdapter(); private KeyListener gearsKeys = new GearsKeyAdapter(); - + private TileRendererBase tileRendererInUse = null; + // private boolean mouseRButtonDown = false; private int prevMouseX, prevMouseY; @@ -45,6 +47,10 @@ public class Gears implements GLEventListener { this.swapInterval = 1; } + public void setTileRenderer(TileRendererBase tileRenderer) { + tileRendererInUse = tileRenderer; + } + public void setDoRotation(boolean rotate) { this.doRotate = rotate; } public void setGears(int g1, int g2, int g3) { @@ -75,7 +81,22 @@ public class Gears implements GLEventListener { System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); System.err.println("INIT GL IS: " + gl.getClass().getName()); System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); + + init(gl); + + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.addMouseListener(gearsMouse); + window.addKeyListener(gearsKeys); + } else if (GLProfile.isAWTAvailable() && upstreamWidget instanceof java.awt.Component) { + final java.awt.Component comp = (java.awt.Component) upstreamWidget; + new AWTMouseAdapter(gearsMouse).addTo(comp); + new AWTKeyAdapter(gearsKeys).addTo(comp); + } + } + public void init(GL2 gl) { float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f }; float red[] = { 0.8f, 0.1f, 0.0f, 0.7f }; float green[] = { 0.0f, 0.8f, 0.2f, 0.7f }; @@ -122,36 +143,64 @@ public class Gears implements GLEventListener { } gl.glEnable(GL2.GL_NORMALIZE); - - final Object upstreamWidget = drawable.getUpstreamWidget(); - if (upstreamWidget instanceof Window) { - final Window window = (Window) upstreamWidget; - window.addMouseListener(gearsMouse); - window.addKeyListener(gearsKeys); - } else if (GLProfile.isAWTAvailable() && upstreamWidget instanceof java.awt.Component) { - final java.awt.Component comp = (java.awt.Component) upstreamWidget; - new AWTMouseAdapter(gearsMouse).addTo(comp); - new AWTKeyAdapter(gearsKeys).addTo(comp); - } } - + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { - System.err.println("Gears: Reshape "+x+"/"+y+" "+width+"x"+height); - GL2 gl = drawable.getGL().getGL2(); - - gl.setSwapInterval(swapInterval); + GL2 gl = drawable.getGL().getGL2(); + this.reshape(gl, x, y, width, height); + } + + public void reshape(GL2 gl, int x, int y, int width, int height) { + System.err.println("Gears: Reshape "+x+"/"+y+" "+width+"x"+height+", tileRendererInUse "+tileRendererInUse); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); - if(height>width) { - float h = (float)height / (float)width; - gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f); + + final int tileWidth = width; + final int tileHeight = height; + final int tileX, tileY, imageWidth, imageHeight; + if( null == tileRendererInUse ) { + gl.setSwapInterval(swapInterval); + tileX = 0; + tileY = 0; + imageWidth = width; + imageHeight = height; + } else { + gl.setSwapInterval(0); + tileX = tileRendererInUse.getParam(TileRendererBase.TR_CURRENT_TILE_X_POS); + tileY = tileRendererInUse.getParam(TileRendererBase.TR_CURRENT_TILE_Y_POS); + imageWidth = tileRendererInUse.getParam(TileRendererBase.TR_IMAGE_WIDTH); + imageHeight = tileRendererInUse.getParam(TileRendererBase.TR_IMAGE_HEIGHT); + } + /* 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 h = (float)width / (float)height; - gl.glFrustum(-h, h, -1.0f, 1.0f, 5.0f, 60.0f); + float a = (float)imageWidth / (float)imageHeight; + left = -a; + right = a; + bottom = -1.0f; + top = 1.0f; } - gl.glMatrixMode(GL2.GL_MODELVIEW); + 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(">> angle "+angle+", [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); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -40.0f); } @@ -170,11 +219,6 @@ public class Gears implements GLEventListener { } public void display(GLAutoDrawable drawable) { - if( doRotate ) { - // Turn the gears' teeth - angle += 2.0f; - } - // Get the GL corresponding to the drawable we are animating GL2 gl = drawable.getGL().getGL2(); @@ -190,7 +234,18 @@ public class Gears implements GLEventListener { } else { gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); } - + displayImpl(gl); + } + public void display(GL2 gl) { + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); + displayImpl(gl); + } + private void displayImpl(GL2 gl) { + if( doRotate ) { + // Turn the gears' teeth + angle += 2.0f; + } // Rotate the entire assembly of gears based on how the user // dragged the mouse around gl.glPushMatrix(); @@ -221,7 +276,7 @@ public class Gears implements GLEventListener { // Remember that every push needs a pop; this one is paired with // rotating the entire gear assembly - gl.glPopMatrix(); + gl.glPopMatrix(); } public static void gear(GL2 gl, 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 index d1fabfa6b..1efc95c9e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2.java @@ -1,9 +1,37 @@ +/** + * 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.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.TileRendererBase; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; import com.jogamp.opengl.util.texture.TextureData; import com.jogamp.opengl.util.texture.TextureIO; @@ -11,19 +39,35 @@ 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 javax.media.opengl.GLRunnable; 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. */ +/** + * Demos offscreen {@link GLAutoDrawable} being used for + * {@link RandomTileRenderer} rendering to produce a PNG file. + * <p> + * {@link RandomTileRenderer} is being kicked off from the main thread. + * </p> + * <p> + * {@link RandomTileRenderer} buffer allocation is performed + * within the pre {@link GLEventListener} + * set via {@link TileRendererBase#setGLEventListener(GLEventListener, GLEventListener)} + * on the main thread. + * </p> + * <p> + * At tile rendering finish, the viewport and + * and the original {@link GLEventListener}'s PMV matrix as well. + * The latter is done by calling it's {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape} method. + * </p> +*/ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestRandomTiledRendering2GL2 extends UITestCase { static long duration = 500; // ms @@ -37,7 +81,6 @@ public class TestRandomTiledRendering2GL2 extends UITestCase { 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); @@ -54,43 +97,8 @@ public class TestRandomTiledRendering2GL2 extends UITestCase { // 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.attachToAutoDrawable(glad, pmvMatrixCallback); + gears.setTileRenderer(renderer); + renderer.attachToAutoDrawable(glad); renderer.setImageSize(imageWidth, imageHeight); final GLPixelBuffer.GLPixelBufferProvider pixelBufferProvider = GLPixelBuffer.defaultProviderWithRowStride; @@ -130,6 +138,18 @@ public class TestRandomTiledRendering2GL2 extends UITestCase { } renderer.detachFromAutoDrawable(); + gears.setTileRenderer(null); + + // Restore viewport and Gear's PMV matrix + // .. even though we close the demo, this is for documentation! + glad.invoke(true, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable drawable) { + drawable.getGL().glViewport(0, 0, drawable.getWidth(), drawable.getHeight()); + gears.reshape(drawable, 0, 0, drawable.getWidth(), drawable.getHeight()); + return false; + } + }); glad.destroy(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering3GL2AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering3GL2AWT.java new file mode 100644 index 000000000..26e53c17b --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering3GL2AWT.java @@ -0,0 +1,261 @@ +/** + * 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.test.junit.jogl.tile; + +import com.jogamp.newt.event.TraceKeyAdapter; +import com.jogamp.newt.event.TraceWindowAdapter; +import com.jogamp.newt.event.awt.AWTKeyAdapter; +import com.jogamp.newt.event.awt.AWTWindowAdapter; +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.QuitAdapter; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLPixelBuffer; +import com.jogamp.opengl.util.RandomTileRenderer; +import com.jogamp.opengl.util.TileRendererBase; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; + +import java.awt.Dimension; +import java.awt.Frame; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GL; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.awt.GLCanvas; + +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * Demos an onscreen AWT {@link GLCanvas} being used for + * {@link RandomTileRenderer} rendering to produce a PNG file. + * <p> + * {@link RandomTileRenderer} is being kicked off from the main thread. + * </p> + * <p> + * {@link RandomTileRenderer} setup and finishing is performed + * within the pre- and post {@link GLEventListener} + * set via {@link TileRendererBase#setGLEventListener(GLEventListener, GLEventListener)} + * on the animation thread. + * </p> + * <p> + * At tile rendering finish, the viewport and + * and the original {@link GLEventListener}'s PMV matrix as well. + * The latter is done by calling it's {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape} method. + * </p> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestRandomTiledRendering3GL2AWT extends UITestCase { + static long duration = 3500; // ms + static int width = 640; + static int height = 480; + + @Test + public void test01() throws IOException, InterruptedException, InvocationTargetException { + doTest(); + } + + void doTest() throws IOException, InterruptedException, InvocationTargetException { + final GLCapabilities caps = new GLCapabilities(null); + caps.setDoubleBuffered(false); + + final Frame frame = new Frame("Gears AWT Test"); + Assert.assertNotNull(frame); + + final GLCanvas glad = new GLCanvas(caps); + Assert.assertNotNull(glad); + Dimension glc_sz = new Dimension(width, height); + glad.setMinimumSize(glc_sz); + glad.setPreferredSize(glc_sz); + glad.setSize(glc_sz); + frame.add(glad); + + final Gears gears = new Gears(); + glad.addGLEventListener( gears ); + + final Animator animator = new Animator(glad); + final QuitAdapter quitAdapter = new QuitAdapter(); + + new AWTKeyAdapter(new TraceKeyAdapter(quitAdapter)).addTo(glad); + new AWTWindowAdapter(new TraceWindowAdapter(quitAdapter)).addTo(frame); + + // Fix the image size for now + final int imageWidth = glad.getWidth() * 3; + final int imageHeight = glad.getHeight() * 2; + + // Initialize the tile rendering library + final RandomTileRenderer renderer = new RandomTileRenderer(); + renderer.setImageSize(imageWidth, imageHeight); + final GLPixelBuffer.GLPixelBufferProvider pixelBufferProvider = GLPixelBuffer.defaultProviderWithRowStride; + final boolean[] flipVertically = { false }; + final boolean[] rendererActive = { true }; + + final GLEventListener preTileGLEL = new GLEventListener() { + final int w = 50, h = 50; + int dx = 0, dy = 0; + + @Override + public void init(GLAutoDrawable drawable) { + gears.setDoRotation(false); + 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) { + if( dx+w <= imageWidth && dy+h <= imageHeight ) { + System.err.println("XXX setTileRect["+dx+"/"+dy+" "+w+"x"+h+"]"); + renderer.setTileRect(dx, dy, w, h); + dx+=w+w/2; + if( dx + w > imageWidth ) { + dx = 0; + dy+=h+h/2; + } + } else if( rendererActive[0] ) { + System.err.println("XXX active -> false"); + rendererActive[0] = false; + } + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }; + final GLEventListener postTileGLEL = new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) {} + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void display(GLAutoDrawable drawable) { + if( !rendererActive[0] ) { + final GLPixelBuffer imageBuffer = renderer.getImageBuffer(); + imageBuffer.clear(); // full size available + System.err.println("XXX !active -> save"); + 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()); + try { + final String filename = getSnapshotFilename(0, "-tile", glad.getChosenGLCapabilities(), imageWidth, imageHeight, false, TextureIO.PNG, null); + final File file = new File(filename); + TextureIO.write(textureData, file); + } catch (IOException e) { + e.printStackTrace(); + } + gears.setTileRenderer(null); + renderer.detachFromAutoDrawable(); + System.err.println("XXX detach: glel "+glad.getGLEventListener(0)); + System.err.println("XXX detach: "+animator); + drawable.getGL().glViewport(0, 0, drawable.getWidth(), drawable.getHeight()); + glad.getGLEventListener(0).reshape(drawable, 0, 0, drawable.getWidth(), drawable.getHeight()); + gears.setDoRotation(true); + } + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }; + renderer.setGLEventListener(preTileGLEL, postTileGLEL); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.pack(); + frame.setVisible(true); + }}); + animator.setUpdateFPSFrames(60, System.err); + animator.start(); + + boolean signalTileRenderer = true; + + while(!quitAdapter.shouldQuit() && animator.isAnimating() && + ( rendererActive[0] || animator.getTotalFPSDuration()<duration ) ) + { + if( signalTileRenderer && animator.getTotalFPSDuration() > 90 ) { + signalTileRenderer = false; + // tile rendering ! + System.err.println("XXX START TILE RENDERING"); + gears.setTileRenderer(renderer); + renderer.attachToAutoDrawable(glad); + System.err.println("XXX attach: glel "+glad.getGLEventListener(0)); + System.err.println("XXX attach: "+animator); + } + Thread.sleep(100); + } + + Assert.assertNotNull(frame); + Assert.assertNotNull(glad); + Assert.assertNotNull(animator); + + animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(false); + }}); + Assert.assertEquals(false, frame.isVisible()); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.remove(glad); + frame.dispose(); + }}); + } + + 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(TestRandomTiledRendering3GL2AWT.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 index 5b628091b..24466e32e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2.java @@ -1,3 +1,30 @@ +/** + * 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.test.junit.jogl.tile; import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; @@ -5,26 +32,37 @@ 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.TileRendererBase; 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.GLContext; +import javax.media.opengl.GLDrawable; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLOffscreenAutoDrawable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; +import org.junit.Assert; 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. */ +/** + * Demos offscreen {@link GLDrawable} being used for + * {@link TileRenderer} rendering to produce a PNG file. + * <p> + * All {@link TileRenderer} operations are + * being performed from the main thread sequentially + * without {@link GLAutoDrawable} or {@link GLEventListener}. + * </p> +*/ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestTiledRendering1GL2 extends UITestCase { static long duration = 500; // ms @@ -34,110 +72,78 @@ public class TestTiledRendering1GL2 extends UITestCase { doTest(); } - void doTest() throws IOException { - GLCapabilities caps = new GLCapabilities(null); - caps.setDoubleBuffered(false); + static class DrawableContext { + DrawableContext(GLDrawable d, GLContext glc) { + this.d = d; + this.glc = glc; + } + GLDrawable d; + GLContext glc; + } + + private static DrawableContext createDrawableAndCurrentCtx(GLCapabilities glCaps, int width, int height) { + GLDrawableFactory factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); + GLDrawable d = factory.createOffscreenDrawable(null, glCaps, null, width, height); + d.setRealized(true); + GLContext glc = null; + glc = d.createContext(null); + Assert.assertTrue("Context could not be made current", GLContext.CONTEXT_NOT_CURRENT < glc.makeCurrent()); + return new DrawableContext(d, glc); + } + + private static void destroyDrawableContext(DrawableContext dc) { + if(null != dc.glc) { + dc.glc.destroy(); + dc.glc = null; + } + if(null != dc.d) { + dc.d.setRealized(false); + dc.d = null; + } + } - // Use a pbuffer for rendering - final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); - final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(null, caps, null, 256, 256, null); - + void doTest() throws GLException, IOException { + GLProfile glp = GLProfile.getMaxFixedFunc(true); + GLCapabilities caps = new GLCapabilities(glp); + caps.setOnscreen(false); + + DrawableContext dc = createDrawableAndCurrentCtx(caps, 256, 256); + final GL2 gl = dc.glc.getGL().getGL2(); + // Fix the image size for now - final int imageWidth = glad.getWidth() * 6; - final int imageHeight = glad.getHeight() * 4; + final int imageWidth = dc.d.getWidth() * 6; + final int imageHeight = dc.d.getHeight() * 4; - final String filename = this.getSnapshotFilename(0, "-tile", glad.getChosenGLCapabilities(), imageWidth, imageHeight, false, TextureIO.PNG, null); + final String filename = this.getSnapshotFilename(0, "-tile", dc.d.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 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); + final TileRenderer renderer = new com.jogamp.opengl.util.TileRenderer(); + renderer.setTileSize(dc.d.getWidth(), dc.d.getHeight(), 0); 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) {} - }); + GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); + GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + renderer.setImageBuffer(pixelBuffer); + flipVertically[0] = false; + 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(); + gears.init(gl); + + gears.setTileRenderer(renderer); + do { + renderer.beginTile(dc.glc.getGL().getGL2ES3()); + gears.reshape(gl, 0, 0, renderer.getParam(TileRendererBase.TR_CURRENT_TILE_WIDTH), renderer.getParam(TileRendererBase.TR_CURRENT_TILE_HEIGHT)); + gears.display(gl); + renderer.endTile(dc.glc.getGL().getGL2ES3()); } while ( !renderer.eot() ); - - glad.destroy(); + gears.setTileRenderer(null); + + destroyDrawableContext(dc); final GLPixelBuffer imageBuffer = renderer.getImageBuffer(); final TextureData textureData = new TextureData( 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 index d750ca853..6fd13538b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2GL2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2GL2.java @@ -1,9 +1,37 @@ +/** + * 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.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.TileRendererBase; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; import com.jogamp.opengl.util.texture.TextureData; import com.jogamp.opengl.util.texture.TextureIO; @@ -11,19 +39,35 @@ 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 javax.media.opengl.GLRunnable; 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. */ +/** + * Demos offscreen {@link GLAutoDrawable} being used for + * {@link TileRenderer} rendering to produce a PNG file. + * <p> + * {@link TileRenderer} is being kicked off from the main thread. + * </p> + * <p> + * {@link TileRenderer} buffer allocation is performed + * within the pre {@link GLEventListener} + * set via {@link TileRendererBase#setGLEventListener(GLEventListener, GLEventListener)} + * on the main thread. + * </p> + * <p> + * At tile rendering finish, the viewport and + * and the original {@link GLEventListener}'s PMV matrix as well. + * The latter is done by calling it's {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape} method. + * </p> +*/ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestTiledRendering2GL2 extends UITestCase { static long duration = 500; // ms @@ -37,7 +81,6 @@ public class TestTiledRendering2GL2 extends UITestCase { 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); @@ -54,44 +97,8 @@ public class TestTiledRendering2GL2 extends UITestCase { // Initialize the tile rendering library final TileRenderer renderer = new TileRenderer(); - final TileRenderer.PMVMatrixCallback pmvMatrixCallback = new TileRenderer.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.attachToAutoDrawable(glad, pmvMatrixCallback); + gears.setTileRenderer(renderer); + renderer.attachToAutoDrawable(glad); renderer.setImageSize(imageWidth, imageHeight); final GLPixelBuffer.GLPixelBufferProvider pixelBufferProvider = GLPixelBuffer.defaultProviderWithRowStride; @@ -124,6 +131,18 @@ public class TestTiledRendering2GL2 extends UITestCase { } while ( !renderer.eot() ); renderer.detachFromAutoDrawable(); + gears.setTileRenderer(null); + + // Restore viewport and Gear's PMV matrix + // .. even though we close the demo, this is for documentation! + glad.invoke(true, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable drawable) { + drawable.getGL().glViewport(0, 0, drawable.getWidth(), drawable.getHeight()); + gears.reshape(drawable, 0, 0, drawable.getWidth(), drawable.getHeight()); + return false; + } + }); glad.destroy(); |