diff options
author | Sven Gothel <[email protected]> | 2013-09-06 23:14:11 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-09-06 23:14:11 +0200 |
commit | b780eff49b626bd8429e1e87609f7a917f7b094e (patch) | |
tree | 40211bcd92c25aea0a005e0de57106ec540498bc /src | |
parent | 95d49687f5b9b783f3d8008df86df58cc0f9bfab (diff) |
GLCanvas Printing WIP: Add GLJPanel; GLCanvas TILE_SIZE 512; print(Graphics): Don't force on AWT-EDT -> Deadlock; releasePrint(): perform reshape/display!
Diffstat (limited to 'src')
6 files changed, 588 insertions, 88 deletions
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 14cc08feb..4ff25d0e6 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -736,7 +736,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing paint(g); } - private static final int PRINT_TILE_SIZE = 256; + private static final int PRINT_TILE_SIZE = 512; private volatile boolean printActive = false; private GLOffscreenAutoDrawable printGLAD = null; private TileRenderer printRenderer = null; @@ -874,7 +874,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing if( !printActive || null == printGLAD ) { throw new IllegalStateException("setupPrint() not called"); } + sendReshape = false; // clear reshape flag AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT); + sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! + display(); } private final Runnable releasePrintOnEDT = new Runnable() { @Override @@ -908,49 +911,46 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing if( !printActive || null == printGLAD ) { throw new IllegalStateException("setupPrint() not called"); } + if(DEBUG && !EventQueue.isDispatchThread()) { + System.err.println(getThreadName()+": Warning: GLCanvas print - not called from AWT-EDT"); + // we cannot dispatch print on AWT-EDT due to printing internal locking .. + } sendReshape = false; // clear reshape flag printGraphics = (Graphics2D)graphics; - AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, printOnEDT); - } - private final Runnable printOnEDT = new Runnable() { - @Override - public void run() { - sendReshape = false; // clear reshape flag - System.err.println("AWT print.0: canvasSize "+getWidth()+"x"+getWidth()+", printAnimator "+printAnimator); - { - final RenderingHints rHints = printGraphics.getRenderingHints(); - final Set<Entry<Object, Object>> rEntries = rHints.entrySet(); - int count = 0; - for(Iterator<Entry<Object, Object>> rEntryIter = rEntries.iterator(); rEntryIter.hasNext(); count++) { - final Entry<Object, Object> rEntry = rEntryIter.next(); - System.err.println("Hint["+count+"]: "+rEntry.getKey()+" -> "+rEntry.getValue()); - } + System.err.println("AWT print.0: canvasSize "+getWidth()+"x"+getWidth()+", printAnimator "+printAnimator); + { + final RenderingHints rHints = printGraphics.getRenderingHints(); + final Set<Entry<Object, Object>> rEntries = rHints.entrySet(); + int count = 0; + for(Iterator<Entry<Object, Object>> rEntryIter = rEntries.iterator(); rEntryIter.hasNext(); count++) { + final Entry<Object, Object> rEntry = rEntryIter.next(); + System.err.println("Hint["+count+"]: "+rEntry.getKey()+" -> "+rEntry.getValue()); } - // final GraphicsConfiguration gc = printGraphics.getDeviceConfiguration(); - final AffineTransform aTrans = printGraphics.getTransform(); - System.err.println(" scale "+aTrans.getScaleX()+" x "+aTrans.getScaleY()); - System.err.println(" move "+aTrans.getTranslateX()+" x "+aTrans.getTranslateY()); - - final Rectangle gClipOrig = printGraphics.getClipBounds(); - final Rectangle gClip = new Rectangle(gClipOrig); - if( 0 > gClip.x ) { - gClip.width += gClip.x; - gClip.x = 0; - } - if( 0 > gClip.y ) { - gClip.height += gClip.y; - gClip.y = 0; - } - printRenderer.setImageSize(gClip.width, gClip.height); - printRenderer.setTileOffset(gClip.x, gClip.y); - System.err.println("AWT print.0: "+gClipOrig+" -> "+gClip); - System.err.println("AWT print.0: "+printRenderer); - do { - printRenderer.display(); - } while ( !printRenderer.eot() ); - System.err.println("AWT print.X: "+printRenderer); } - }; + // final GraphicsConfiguration gc = printGraphics.getDeviceConfiguration(); + final AffineTransform aTrans = printGraphics.getTransform(); + System.err.println(" scale "+aTrans.getScaleX()+" x "+aTrans.getScaleY()); + System.err.println(" move "+aTrans.getTranslateX()+" x "+aTrans.getTranslateY()); + + final Rectangle gClipOrig = printGraphics.getClipBounds(); + final Rectangle gClip = new Rectangle(gClipOrig); + if( 0 > gClip.x ) { + gClip.width += gClip.x; + gClip.x = 0; + } + if( 0 > gClip.y ) { + gClip.height += gClip.y; + gClip.y = 0; + } + printRenderer.setImageSize(gClip.width, gClip.height); + printRenderer.setTileOffset(gClip.x, gClip.y); + System.err.println("AWT print.0: "+gClipOrig+" -> "+gClip); + System.err.println("AWT print.0: "+printRenderer); + do { + printRenderer.display(); + } while ( !printRenderer.eot() ); + System.err.println("AWT print.X: "+printRenderer); + } @Override public void addGLEventListener(GLEventListener listener) { diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index a8235d396..84663cb3a 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -44,15 +44,22 @@ import java.awt.Color; import java.awt.EventQueue; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.beans.Beans; import java.nio.IntBuffer; +import java.util.Iterator; import java.util.List; +import java.util.Set; +import java.util.Map.Entry; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; @@ -85,11 +92,15 @@ import jogamp.opengl.GLDrawableHelper; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.awt.Java2D; import jogamp.opengl.util.glsl.GLSLTextureRaster; + +import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; import com.jogamp.opengl.FBObject; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; import com.jogamp.opengl.util.GLPixelBuffer.SingletonGLPixelBufferProvider; import com.jogamp.opengl.util.GLPixelStorageModes; +import com.jogamp.opengl.util.TileRenderer; +import com.jogamp.opengl.util.TileRendererBase; import com.jogamp.opengl.util.awt.AWTGLPixelBuffer; import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.AWTGLPixelBufferProvider; import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.SingleAWTGLPixelBufferProvider; @@ -138,7 +149,7 @@ import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.SingleAWTGLPixelBufferProvide */ @SuppressWarnings("serial") -public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol { +public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol, AWTPrintLifecycle { private static final boolean DEBUG; private static final boolean DEBUG_VIEWPORT; private static final boolean USE_GLSL_TEXTURE_RASTERIZER; @@ -430,9 +441,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing sendReshape = handleReshape(); } - if( isVisible() ) { + if( isVisible() && !printActive ) { updater.setGraphics(g); - backend.doPaintComponent(g); } } @@ -481,14 +491,237 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (DEBUG) { System.err.println(getThreadName()+": GLJPanel.reshape: " +reshapeWidth+"x"+reshapeHeight + " -> " + width+"x"+height); - } - // reshapeX = x; - // reshapeY = y; - reshapeWidth = width; - reshapeHeight = height; - handleReshape = true; + } + if( !printActive ) { + // reshapeX = x; + // reshapeY = y; + reshapeWidth = width; + reshapeHeight = height; + handleReshape = true; + } + } + + private volatile boolean printActive = false; + private TileRenderer printRenderer = null; + private GLAnimatorControl printAnimator = null; + private AWTGLPixelBuffer printBuffer = null; + private BufferedImage printVFlipImage = null; + private Graphics2D printGraphics = null; + + @Override + public void setupPrint() { + if (!isInitialized) { + if(DEBUG) { + System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet"); + } + return; // not yet available .. + } + if( !isVisible() ) { + if(DEBUG) { + System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable visible"); + } + return; // not yet available .. + } + printActive = true; + sendReshape = false; // clear reshape flag + handleReshape = false; // ditto + AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, setupPrintOnEDT); } + private final Runnable setupPrintOnEDT = new Runnable() { + @Override + public void run() { + sendReshape = false; // clear reshape flag + handleReshape = false; // ditto + printAnimator = helper.getAnimator(); + if( null != printAnimator ) { + printAnimator.remove(GLJPanel.this); + } + final int tileWidth = getWidth(); + final int tileHeight = getHeight(); + + // FIXME final OffscreenBackend offscrBacken = (OffscreenBackend)backend; + final GLCapabilities caps = (GLCapabilities)getChosenGLCapabilities().cloneMutable(); + caps.setOnscreen(false); + printRenderer = new TileRenderer(); + printRenderer.setRowOrder(TileRenderer.TR_TOP_TO_BOTTOM); + printRenderer.setTileSize(tileWidth, tileHeight, 0); + printRenderer.attachToAutoDrawable(GLJPanel.this); + + final GLEventListener preTileGLEL = new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + } + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void display(GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + if( null == printBuffer ) { + final int componentCount = isOpaque() ? 3 : 4; + final AWTGLPixelBufferProvider printBufferProvider = new AWTGLPixelBufferProvider( true /* allowRowStride */ ); + final GLPixelAttributes pixelAttribs = printBufferProvider.getAttributes(gl, componentCount); + printBuffer = printBufferProvider.allocate(gl, pixelAttribs, tileWidth, tileHeight, 1, true, 0); + printRenderer.setTileBuffer(printBuffer); + printVFlipImage = new BufferedImage(printBuffer.width, printBuffer.height, printBuffer.image.getType()); + } + System.err.println("XXX tile-pre "+printRenderer); // FIXME + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }; + final GLEventListener postTileGLEL = new GLEventListener() { + int tTopRowHeight = 0; + @Override + public void init(GLAutoDrawable drawable) { + tTopRowHeight = 0; + } + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void display(GLAutoDrawable drawable) { + // 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 int tHeight = printRenderer.getParam(TileRendererBase.TR_CURRENT_TILE_HEIGHT); + final int tWidth = printRenderer.getParam(TileRendererBase.TR_CURRENT_TILE_WIDTH); + // final BufferedImage dstImage = printBuffer.image; + final BufferedImage srcImage = printBuffer.image; + final BufferedImage dstImage = printVFlipImage; + final int[] src = ((DataBufferInt) srcImage.getRaster().getDataBuffer()).getData(); + final int[] dst = ((DataBufferInt) dstImage.getRaster().getDataBuffer()).getData(); + final int incr = printBuffer.width; + int srcPos = 0; + int destPos = (tHeight - 1) * printBuffer.width; + for (; destPos >= 0; srcPos += incr, destPos -= incr) { + System.arraycopy(src, srcPos, dst, destPos, incr); + } + // Draw resulting image in one shot + final int tRows = printRenderer.getParam(TileRenderer.TR_ROWS); + final int tRow = printRenderer.getParam(TileRenderer.TR_CURRENT_ROW); + final int pX = printRenderer.getParam(TileRendererBase.TR_CURRENT_TILE_X_POS); + final int pYf; + if( tRow == tRows - 1 ) { + tTopRowHeight = tHeight; + pYf = 0; + } else if( tRow == tRows - 2 ){ + pYf = tTopRowHeight; + } else { + pYf = ( tRows - 2 - tRow ) * tHeight + tTopRowHeight; + } + final Shape oClip = printGraphics.getClip(); + printGraphics.clipRect(pX, pYf, tWidth, tHeight); + final Shape clip = printGraphics.getClip(); + printGraphics.drawImage(dstImage, pX, pYf, dstImage.getWidth(), dstImage.getHeight(), null); // Null ImageObserver since image data is ready. + printGraphics.setColor(Color.BLACK); + printGraphics.drawRect(pX, pYf, tWidth, tHeight); + { + final Rectangle r = oClip.getBounds(); + printGraphics.setColor(Color.YELLOW); + printGraphics.drawRect(r.x, r.y, r.width, r.height); + } + printGraphics.setClip(oClip); + System.err.println("XXX tile-post.X clip "+oClip+" -> "+clip); + System.err.println("XXX tile-post.X "+printRenderer); + System.err.println("XXX tile-post.X dst-img "+dstImage.getWidth()+"x"+dstImage.getHeight()+" -> "+pX+"/"+pYf); // +", "+dstImage); // FIXME + } + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} + }; + printRenderer.setGLEventListener(preTileGLEL, postTileGLEL); + System.err.println("AWT print.setup "+printRenderer); // FIXME + } + }; + + @Override + public void releasePrint() { + if( !printActive ) { + throw new IllegalStateException("setupPrint() not called"); + } + sendReshape = false; // clear reshape flag + handleReshape = false; // ditto + AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT); + sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! + handleReshape = true; // ditto + display(); + } + private final Runnable releasePrintOnEDT = new Runnable() { + @Override + public void run() { + printRenderer.detachFromAutoDrawable(); // tile-renderer -> printGLAD + if( null != printAnimator ) { + printAnimator.add(GLJPanel.this); + } + System.err.println("AWT print.release "+printRenderer); // FIXME + printRenderer = null; + printAnimator = null; + if( null != printBuffer ) { + printBuffer.dispose(); + printBuffer = null; + } + if( null != printVFlipImage ) { + printVFlipImage.flush(); + printVFlipImage = null; + } + printGraphics = null; + printActive = false; + } + }; + + @Override + public void print(Graphics graphics) { + if( !printActive ) { + throw new IllegalStateException("setupPrint() not called"); + } + if(DEBUG && !EventQueue.isDispatchThread()) { + System.err.println(getThreadName()+": Warning: GLCanvas print - not called from AWT-EDT"); + // we cannot dispatch print on AWT-EDT due to printing internal locking .. + } + sendReshape = false; // clear reshape flag + handleReshape = false; // ditto + printGraphics = (Graphics2D)graphics; + System.err.println("AWT print.0: canvasSize "+getWidth()+"x"+getWidth()+", printAnimator "+printAnimator); + { + final RenderingHints rHints = printGraphics.getRenderingHints(); + final Set<Entry<Object, Object>> rEntries = rHints.entrySet(); + int count = 0; + for(Iterator<Entry<Object, Object>> rEntryIter = rEntries.iterator(); rEntryIter.hasNext(); count++) { + final Entry<Object, Object> rEntry = rEntryIter.next(); + System.err.println("Hint["+count+"]: "+rEntry.getKey()+" -> "+rEntry.getValue()); + } + } + // final GraphicsConfiguration gc = printGraphics.getDeviceConfiguration(); + final AffineTransform aTrans = printGraphics.getTransform(); + System.err.println(" scale "+aTrans.getScaleX()+" x "+aTrans.getScaleY()); + System.err.println(" move "+aTrans.getTranslateX()+" x "+aTrans.getTranslateY()); + + final Rectangle gClipOrig = printGraphics.getClipBounds(); + final Rectangle gClip = new Rectangle(gClipOrig); + if( 0 > gClip.x ) { + gClip.width += gClip.x; + gClip.x = 0; + } + if( 0 > gClip.y ) { + gClip.height += gClip.y; + gClip.y = 0; + } + printRenderer.setImageSize(gClip.width, gClip.height); + printRenderer.setTileOffset(gClip.x, gClip.y); + System.err.println("AWT print.0: "+gClipOrig+" -> "+gClip); + System.err.println("AWT print.0: "+printRenderer); + do { + // printRenderer.display(); + backend.doPlainPaint(); + } while ( !printRenderer.eot() ); + System.err.println("AWT print.X: "+printRenderer); + } + @Override + protected void printComponent(Graphics g) { + System.err.println("AWT printComponent.X: "+printRenderer); + print(g); + } + @Override public void setOpaque(boolean opaque) { if (backend != null) { @@ -877,13 +1110,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing backend.postGL(g, true); } + public void print(GLAutoDrawable drawable) { + helper.display(GLJPanel.this); + } + @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { // This is handled above and dispatched directly to the appropriate context } - - public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { - } } @Override @@ -932,6 +1166,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } }; + private final Runnable updaterPlainDisplayAction = new Runnable() { + @Override + public void run() { + updater.print(GLJPanel.this); + } + }; + private final Runnable paintImmediatelyAction = new Runnable() { @Override public void run() { @@ -968,60 +1209,73 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // Implementations of the various backends // - // Abstraction of the different rendering backends: i.e., pure - // software / pixmap rendering, pbuffer-based acceleration, Java 2D - // / JOGL bridge + /** + * Abstraction of the different rendering backends: i.e., pure + * software / pixmap rendering, pbuffer-based acceleration, Java 2D + * JOGL bridge + */ static interface Backend { - // Create, Destroy, .. + /** Create, Destroy, .. */ public boolean isUsingOwnLifecycle(); - // Called each time the backend needs to initialize itself + /** Called each time the backend needs to initialize itself */ public void initialize(); - // Called when the backend should clean up its resources + /** Called when the backend should clean up its resources */ public void destroy(); - // Called when the opacity of the GLJPanel is changed + /** Called when the opacity of the GLJPanel is changed */ public void setOpaque(boolean opaque); - // Called to manually create an additional OpenGL context against - // this GLJPanel + /** + * Called to manually create an additional OpenGL context against + * this GLJPanel + */ public GLContext createContext(GLContext shareWith); - // Called to set the current backend's GLContext + /** Called to set the current backend's GLContext */ public void setContext(GLContext ctx); - // Called to get the current backend's GLContext + /** Called to get the current backend's GLContext */ public GLContext getContext(); - // Called to get the current backend's GLDrawable + /** Called to get the current backend's GLDrawable */ public GLDrawable getDrawable(); /** Returns the used texture unit, i.e. a value of [0..n], or -1 if non used. */ public int getTextureUnit(); - // Called to fetch the "real" GLCapabilities for the backend + /** Called to fetch the "real" GLCapabilities for the backend */ public GLCapabilitiesImmutable getChosenGLCapabilities(); - // Called to fetch the "real" GLProfile for the backend + /** Called to fetch the "real" GLProfile for the backend */ public GLProfile getGLProfile(); - // Called to handle a reshape event. When this is called, the - // OpenGL context associated with the backend is not current, to - // make it easier to destroy and re-create pbuffers if necessary. + /** + * Called to handle a reshape event. When this is called, the + * OpenGL context associated with the backend is not current, to + * make it easier to destroy and re-create pbuffers if necessary. + */ public boolean handleReshape(); - // Called before the OpenGL work is done in init() and display(). - // If false is returned, this render is aborted. + /** + * Called before the OpenGL work is done in init() and display(). + * If false is returned, this render is aborted. + */ public boolean preGL(Graphics g); - // Called after the OpenGL work is done in init() and display(). - // The isDisplay argument indicates whether this was called on - // behalf of a call to display() rather than init(). + /** + * Called after the OpenGL work is done in init() and display(). + * The isDisplay argument indicates whether this was called on + * behalf of a call to display() rather than init(). + */ public void postGL(Graphics g, boolean isDisplay); - // Called from within paintComponent() to initiate the render + /** Called from within paintComponent() to initiate the render */ public void doPaintComponent(Graphics g); + + /** Called from print .. no backend update desired onscreen */ + public void doPlainPaint(); } // Base class used by both the software (pixmap) and pbuffer @@ -1316,6 +1570,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); // Null ImageObserver since image data is ready. } } + + @Override + public void doPlainPaint() { + helper.invokeGL(offscreenDrawable, offscreenContext, updaterPlainDisplayAction, updaterInitAction); + } @Override public boolean handleReshape() { @@ -1830,6 +2089,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing }); } + @Override + public void doPlainPaint() { + helper.invokeGL(joglDrawable, joglContext, updaterPlainDisplayAction, updaterInitAction); + } + private void captureJ2DState(GL gl, Graphics g) { gl.glGetIntegerv(GL2.GL_DRAW_BUFFER, drawBuffer, 0); gl.glGetIntegerv(GL2.GL_READ_BUFFER, readBuffer, 0); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsAWT.java index 7d6135935..30967d75b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsAWT.java @@ -58,6 +58,7 @@ 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.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.util.Animator; @@ -97,7 +98,7 @@ public class TestTiledPrintingGearsAWT extends TiledPrintingAWTBase { final Gears gears = new Gears(); glCanvas.addGLEventListener(gears); - final Frame frame = new Frame("Gears AWT Test"); + final Frame frame = new Frame("AWT Print (offscr "+offscreenPrinting+")"); Assert.assertNotNull(frame); final ActionListener print72DPIAction = new ActionListener() { @@ -141,6 +142,9 @@ public class TestTiledPrintingGearsAWT extends TiledPrintingAWTBase { frame.pack(); frame.setVisible(true); }}); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true)); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glCanvas, true)); + animator.setUpdateFPSFrames(60, System.err); animator.start(); @@ -157,6 +161,9 @@ public class TestTiledPrintingGearsAWT extends TiledPrintingAWTBase { } } + try { + Thread.sleep(1000); // time to flush .. + } catch (InterruptedException e) { } Assert.assertNotNull(frame); Assert.assertNotNull(glCanvas); Assert.assertNotNull(animator); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsSwingAWT.java new file mode 100644 index 000000000..260c9e04c --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsSwingAWT.java @@ -0,0 +1,226 @@ +/** + * 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 java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Label; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.print.PageFormat; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import javax.media.opengl.awt.GLJPanel; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +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.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.QuitAdapter; +import com.jogamp.opengl.util.Animator; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestTiledPrintingGearsSwingAWT extends TiledPrintingAWTBase { + + static boolean waitForKey = false; + static GLProfile glp; + static int width, height; + + @BeforeClass + public static void initClass() { + if(GLProfile.isAvailable(GLProfile.GL2)) { + glp = GLProfile.get(GLProfile.GL2); + Assert.assertNotNull(glp); + width = 640; + height = 480; + } else { + setTestSupported(false); + } + // Runtime.getRuntime().traceInstructions(true); + // Runtime.getRuntime().traceMethodCalls(true); + } + + @AfterClass + public static void releaseClass() { + } + + protected void runTestGL(GLCapabilities caps, final boolean offscreenPrinting) throws InterruptedException, InvocationTargetException { + final GLJPanel glJPanel = new GLJPanel(caps); + Assert.assertNotNull(glJPanel); + Dimension glc_sz = new Dimension(width, height); + glJPanel.setMinimumSize(glc_sz); + glJPanel.setPreferredSize(glc_sz); + glJPanel.setSize(glc_sz); + + final Gears gears = new Gears(); + glJPanel.addGLEventListener(gears); + + final JFrame frame = new JFrame("Swing Print (offscr "+offscreenPrinting+")"); + Assert.assertNotNull(frame); + + final ActionListener print72DPIAction = new ActionListener() { + public void actionPerformed(ActionEvent e) { + doPrintManual(frame, glJPanel, TestTiledPrintingGearsSwingAWT.this, offscreenPrinting, 72); + } }; + final ActionListener print300DPIAction = new ActionListener() { + public void actionPerformed(ActionEvent e) { + doPrintManual(frame, glJPanel, TestTiledPrintingGearsSwingAWT.this, offscreenPrinting, 300); + } }; + final Button print72DPIButton = new Button("72dpi"); + print72DPIButton.addActionListener(print72DPIAction); + final Button print300DPIButton = new Button("300dpi"); + print300DPIButton.addActionListener(print300DPIAction); + + final JPanel printPanel = new JPanel(); + printPanel.add(print72DPIButton); + printPanel.add(print300DPIButton); + final JPanel southPanel = new JPanel(); + southPanel.add(new Label("South")); + final JPanel eastPanel = new JPanel(); + eastPanel.add(new Label("East")); + final JPanel westPanel = new JPanel(); + westPanel.add(new Label("West")); + + Animator animator = new Animator(glJPanel); + QuitAdapter quitAdapter = new QuitAdapter(); + + new AWTKeyAdapter(new TraceKeyAdapter(quitAdapter)).addTo(glJPanel); + new AWTWindowAdapter(new TraceWindowAdapter(quitAdapter)).addTo(frame); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + final Container fcont = frame.getContentPane(); + fcont.setLayout(new BorderLayout()); + fcont.add(printPanel, BorderLayout.NORTH); + fcont.add(glJPanel, BorderLayout.CENTER); + fcont.add(southPanel, BorderLayout.SOUTH); + fcont.add(eastPanel, BorderLayout.EAST); + fcont.add(westPanel, BorderLayout.WEST); + fcont.validate(); + frame.pack(); + frame.setVisible(true); + } } ) ; + + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true)); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glJPanel, true)); + + animator.setUpdateFPSFrames(60, System.err); + animator.start(); + Assert.assertEquals(true, animator.isAnimating()); + + boolean dpi72Done = false; + boolean dpi300Done = false; + while(!quitAdapter.shouldQuit() && animator.isAnimating() && ( 0 == duration || animator.getTotalFPSDuration()<duration )) { + Thread.sleep(200); + if( !dpi72Done ) { + dpi72Done = true; + System.err.println("XXX "+glJPanel); + doPrintAuto(frame, glJPanel, TestTiledPrintingGearsSwingAWT.this, PageFormat.LANDSCAPE, null, offscreenPrinting, 72); + } else if( !dpi300Done ) { + dpi300Done = true; + doPrintAuto(frame, glJPanel, TestTiledPrintingGearsSwingAWT.this, PageFormat.LANDSCAPE, null, offscreenPrinting, 300); + } + } + + try { + Thread.sleep(1000); // time to flush .. + } catch (InterruptedException e) { } + Assert.assertNotNull(frame); + Assert.assertNotNull(glJPanel); + 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() { + final Frame _frame = frame; + _frame.remove(glJPanel); + _frame.dispose(); + }}); + } + + @Test + public void test01_Onscreen() throws InterruptedException, InvocationTargetException { + GLCapabilities caps = new GLCapabilities(glp); + runTestGL(caps, false); + } + @Test + public void test02_Offscreen() throws InterruptedException, InvocationTargetException { + GLCapabilities caps = new GLCapabilities(glp); + runTestGL(caps, true); + } + + static long duration = 500; // ms + + 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(); } + } else if(args[i].equals("-wait")) { + waitForKey = true; + } + } + if(waitForKey) { + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + try { + System.err.println(stdin.readLine()); + } catch (IOException e) { } + } + org.junit.runner.JUnitCore.main(TestTiledPrintingGearsSwingAWT.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TiledPrintingAWTBase.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TiledPrintingAWTBase.java index 4a5953b5a..80268b07c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TiledPrintingAWTBase.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TiledPrintingAWTBase.java @@ -175,8 +175,10 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab g2d.scale(scale , scale ); } - frame.printAll(g2d); - awtPrintObject.releasePrint(); + AWTEDTExecutor.singleton.invoke(true, new Runnable() { + public void run() { + frame.printAll(g2d); + } } ); if( scaleComp != 1 ) { System.err.println("PRINT DPI: reset frame size "+frameWidth+"x"+frameHeight); @@ -188,13 +190,14 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab } }); } + awtPrintObject.releasePrint(); if( g2d == offscreenG2D ) { printG2D.translate(moveX, moveY); printG2D.scale(scale , scale ); printG2D.drawImage(offscreenImage, 0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), null); // Null ImageObserver since image data is ready. } - + /* tell the caller that this page is part of the printed document */ return PAGE_EXISTS; } diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java index a760bbb27..e85052d08 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java +++ b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java @@ -39,8 +39,8 @@ import java.awt.Robot; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowFactory; +import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLDrawable; -import javax.media.opengl.awt.GLCanvas; import org.junit.Assert; @@ -702,21 +702,21 @@ public class AWTRobotUtil { Thread.sleep(TIME_SLICE); } // if GLCanvas, ensure it got also painted -> drawable.setRealized(true); - if(wait<POLL_DIVIDER && comp instanceof GLCanvas) { - GLCanvas glcanvas = (GLCanvas) comp; - for (wait=0; wait<POLL_DIVIDER && realized != glcanvas.isRealized(); wait++) { + if(wait<POLL_DIVIDER && comp instanceof GLAutoDrawable) { + GLAutoDrawable glad = (GLAutoDrawable) comp; + for (wait=0; wait<POLL_DIVIDER && realized != glad.isRealized(); wait++) { Thread.sleep(TIME_SLICE); } if(wait>=POLL_DIVIDER) { // for some reason GLCanvas hasn't been painted yet, force it! - System.err.println("XXX: FORCE REPAINT PRE - canvas: "+glcanvas); - glcanvas.repaint(); - for (wait=0; wait<POLL_DIVIDER && realized != glcanvas.isRealized(); wait++) { + System.err.println("XXX: FORCE REPAINT PRE - glad: "+glad); + comp.repaint(); + for (wait=0; wait<POLL_DIVIDER && realized != glad.isRealized(); wait++) { Thread.sleep(TIME_SLICE); } - System.err.println("XXX: FORCE REPAINT POST - canvas: "+glcanvas); + System.err.println("XXX: FORCE REPAINT POST - glad: "+glad); } - for (wait=0; wait<POLL_DIVIDER && realized != glcanvas.isRealized(); wait++) { + for (wait=0; wait<POLL_DIVIDER && realized != glad.isRealized(); wait++) { Thread.sleep(TIME_SLICE); } } |