diff options
author | Sven Gothel <[email protected]> | 2013-09-15 23:27:16 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-09-15 23:27:16 +0200 |
commit | c2ce31e11eefcf1b900c0e9b41264f5d5566dc46 (patch) | |
tree | 09cc72c0b515bb18062e2bdf14f651981759f6bc | |
parent | 5a946df8fd812570826f267d4123b59d79c97cf7 (diff) |
Fix AWT printing issues w/ overlapping and/or non-opaque contents ; Change AWTPrintLifecycle's lifecycle
- AWTPrintLifecycle:
- Should decorate:
PrinterJob.print(..),
instead of within Printable.print(..) { .. container.printAll(..); .. }
This is due to AWT print implementation, i.e.
AWT will issue Printable.print(..) multiple times for 'overlapping'
or non-opaque elements!
- Move from javax.media.opengl.awt -> com.jogamp.nativewindow.awt
- Make _interface_ AWT agnostic, i.e. remove Graphics2D from 'setup(..)'
- Add 'int numSamples' to 'setup(..)' to determine the number of samples
- AWTTilePrinter:
- Use double precision when scaling image-size and clip-rect,
then round them to integer values.
Otherwise AWT will use the bounding box for the clipping-rectangular.
- Clip negative portion of clip-rect,
this removes redundant overpaints, as well as increasing the tile count
due to the increased clipping-size.
- Clip the image-size in the tile-renderer according to the clip-rect.
- DEBUG_TILES: Dump tiles to file
- Use sub-image of final BuffereImage instead
of adding another clipping region. This might increase performance
if no clip-rect has been set.
TODO:
TestTiledPrintingGearsSwingAWT overlapping tests exposes
a 'off by one' bug of the first layer's background!
Note: The GL content seems to be correct though - maybe it's simply an AWT rounding error ..
-rw-r--r-- | src/jogl/classes/javax/media/opengl/awt/GLCanvas.java | 33 | ||||
-rw-r--r-- | src/jogl/classes/javax/media/opengl/awt/GLJPanel.java | 47 | ||||
-rw-r--r-- | src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java | 189 | ||||
-rw-r--r-- | src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTPrintLifecycle.java (renamed from src/jogl/classes/javax/media/opengl/awt/AWTPrintLifecycle.java) | 54 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java | 63 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsAWT.java | 14 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsNewtAWT.java | 14 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsSwingAWT.java | 73 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/tile/TiledPrintingAWTBase.java | 123 |
9 files changed, 363 insertions, 247 deletions
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 4e0fdba5d..a519e33bb 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -53,7 +53,6 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import java.awt.RenderingHints; import java.awt.geom.Rectangle2D; import java.awt.EventQueue; @@ -94,6 +93,7 @@ import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import com.jogamp.nativewindow.awt.AWTPrintLifecycle; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; import com.jogamp.nativewindow.awt.JAWTWindow; import com.jogamp.opengl.JoglVersion; @@ -725,13 +725,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } private volatile boolean printActive = false; - private boolean printUseAA = false; + private int printNumSamples = 0; private GLAnimatorControl printAnimator = null; private GLAutoDrawable printGLAD = null; private AWTTilePainter printAWTTiles = null; @Override - public void setupPrint(Graphics2D g2d, double scaleMatX, double scaleMatY) { + public void setupPrint(double scaleMatX, double scaleMatY, int numSamples) { if( !validateGLDrawable() ) { if(DEBUG) { System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet"); @@ -746,14 +746,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } printActive = true; sendReshape = false; // clear reshape flag - final RenderingHints rHints = g2d.getRenderingHints(); - { - final Object _useAA = rHints.get(RenderingHints.KEY_ANTIALIASING); - printUseAA = null != _useAA && ( _useAA == RenderingHints.VALUE_ANTIALIAS_DEFAULT || _useAA == RenderingHints.VALUE_ANTIALIAS_ON ); - } + printNumSamples = AWTTilePainter.getNumSamples(numSamples, getChosenGLCapabilities()); if( DEBUG ) { - System.err.println("AWT print.setup: canvasSize "+getWidth()+"x"+getWidth()+", scaleMat "+scaleMatX+" x "+scaleMatY+", useAA "+printUseAA+", printAnimator "+printAnimator); - AWTTilePainter.dumpHintsAndScale(g2d); + System.err.println("AWT print.setup: canvasSize "+getWidth()+"x"+getWidth()+", scaleMat "+scaleMatX+" x "+scaleMatY+", numSamples "+numSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); } final int componentCount = isOpaque() ? 3 : 4; final TileRenderer printRenderer = new TileRenderer(); @@ -769,23 +764,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing printAnimator.remove(GLCanvas.this); } final GLCapabilities caps = (GLCapabilities)getChosenGLCapabilities().cloneMutable(); - final GLProfile glp = caps.getGLProfile(); if( caps.getSampleBuffers() ) { - // bug / issue w/ swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX + // Bug 830: swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX printGLAD = GLCanvas.this; } else { caps.setDoubleBuffered(false); caps.setOnscreen(false); - if( printUseAA && !caps.getSampleBuffers() ) { - if ( !glp.isGL2ES3() ) { - if( DEBUG ) { - System.err.println("Ignore MSAA due to gl-profile < GL2ES3"); - } - printUseAA = false; - } else { - caps.setSampleBuffers(true); - caps.setNumSamples(8); - } + if( printNumSamples != caps.getNumSamples() ) { + caps.setSampleBuffers(0 < printNumSamples); + caps.setNumSamples(printNumSamples); } final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); printGLAD = factory.createOffscreenAutoDrawable(null, caps, null, DEFAULT_PRINT_TILE_SIZE, DEFAULT_PRINT_TILE_SIZE, null); @@ -796,7 +783,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing printAWTTiles.renderer.attachToAutoDrawable(printGLAD); if( DEBUG ) { System.err.println("AWT print.setup "+printAWTTiles); - System.err.println("AWT print.setup AA "+printUseAA+", "+caps); + System.err.println("AWT print.setup AA "+printNumSamples+", "+caps); System.err.println("AWT print.setup "+printGLAD); } } diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 02f4e54a7..f0c6b7beb 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -48,7 +48,6 @@ import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; -import java.awt.RenderingHints; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; @@ -90,6 +89,7 @@ import jogamp.opengl.awt.Java2D; import jogamp.opengl.util.glsl.GLSLTextureRaster; import com.jogamp.common.util.awt.AWTEDTExecutor; +import com.jogamp.nativewindow.awt.AWTPrintLifecycle; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; import com.jogamp.opengl.FBObject; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; @@ -424,7 +424,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing createAndInitializeBackend(); } - if (!isInitialized) { + if (!isInitialized || printActive) { return; } @@ -498,13 +498,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } private volatile boolean printActive = false; - private boolean printUseAA = false; + private int printNumSamples = 0; private GLAnimatorControl printAnimator = null; private GLAutoDrawable printGLAD = null; private AWTTilePainter printAWTTiles = null; @Override - public void setupPrint(Graphics2D g2d, double scaleMatX, double scaleMatY) { + public void setupPrint(double scaleMatX, double scaleMatY, int numSamples) { if (!isInitialized) { if(DEBUG) { System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet"); @@ -520,14 +520,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing printActive = true; sendReshape = false; // clear reshape flag handleReshape = false; // ditto - final RenderingHints rHints = g2d.getRenderingHints(); - { - final Object _useAA = rHints.get(RenderingHints.KEY_ANTIALIASING); - printUseAA = null != _useAA && ( _useAA == RenderingHints.VALUE_ANTIALIAS_DEFAULT || _useAA == RenderingHints.VALUE_ANTIALIAS_ON ); - } + printNumSamples = AWTTilePainter.getNumSamples(numSamples, getChosenGLCapabilities()); if( DEBUG ) { - System.err.println("AWT print.setup: canvasSize "+getWidth()+"x"+getWidth()+", scaleMat "+scaleMatX+" x "+scaleMatY+", useAA "+printUseAA+", printAnimator "+printAnimator); - AWTTilePainter.dumpHintsAndScale(g2d); + System.err.println("AWT print.setup: canvasSize "+getWidth()+"x"+getWidth()+", scaleMat "+scaleMatX+" x "+scaleMatY+", numSamples "+numSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); } final int componentCount = isOpaque() ? 3 : 4; final TileRenderer printRenderer = new TileRenderer(); @@ -546,30 +541,21 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing printGLAD = GLJPanel.this; // default: re-use final GLCapabilities caps = (GLCapabilities)getChosenGLCapabilities().cloneMutable(); - final GLProfile glp = caps.getGLProfile(); - if( printUseAA && !caps.getSampleBuffers() ) { - if ( !glp.isGL2ES3() ) { - if( DEBUG ) { - System.err.println("Ignore MSAA due to gl-profile < GL2ES3"); - } - printUseAA = false; - } else { - // MSAA FBO .. - caps.setDoubleBuffered(false); - caps.setOnscreen(false); - caps.setSampleBuffers(true); - caps.setNumSamples(8); - final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); - printGLAD = factory.createOffscreenAutoDrawable(null, caps, null, DEFAULT_PRINT_TILE_SIZE, DEFAULT_PRINT_TILE_SIZE, null); - GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD); - } + if( printNumSamples != caps.getNumSamples() ) { + caps.setDoubleBuffered(false); + caps.setOnscreen(false); + caps.setSampleBuffers(0 < printNumSamples); + caps.setNumSamples(printNumSamples); + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + printGLAD = factory.createOffscreenAutoDrawable(null, caps, null, DEFAULT_PRINT_TILE_SIZE, DEFAULT_PRINT_TILE_SIZE, null); + GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD); } printAWTTiles.setIsGLOriented(printGLAD.isGLOriented()); printAWTTiles.renderer.setTileSize(printGLAD.getWidth(), printGLAD.getHeight(), 0); printAWTTiles.renderer.attachToAutoDrawable(printGLAD); if( DEBUG ) { System.err.println("AWT print.setup "+printAWTTiles); - System.err.println("AWT print.setup AA "+printUseAA+", "+caps); + System.err.println("AWT print.setup AA "+printNumSamples+", "+caps); System.err.println("AWT print.setup "+printGLAD); } } @@ -624,9 +610,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing printAWTTiles.setupGraphics2DAndClipBounds(g2d, getWidth(), getHeight()); try { final TileRenderer tileRenderer = printAWTTiles.renderer; - if( DEBUG ) { - System.err.println("AWT print.0: "+tileRenderer); - } do { if( printGLAD != GLJPanel.this ) { tileRenderer.display(); diff --git a/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java b/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java index 0ff733457..b16273b35 100644 --- a/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java +++ b/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java @@ -33,16 +33,25 @@ 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.io.File; +import java.io.IOException; +import java.util.Arrays; import java.util.Iterator; import java.util.Set; import java.util.Map.Entry; +import javax.imageio.ImageIO; +import javax.media.nativewindow.util.DimensionImmutable; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLEventListener; +import jogamp.opengl.Debug; + import com.jogamp.opengl.util.TileRenderer; import com.jogamp.opengl.util.TileRendererBase; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; @@ -56,6 +65,8 @@ import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.AWTGLPixelBufferProvider; * </p> */ public class AWTTilePainter { + private static final boolean DEBUG_TILES = Debug.debug("TileRenderer"); + public final TileRenderer renderer; public final int componentCount; public final double scaleMatX, scaleMatY; @@ -76,8 +87,28 @@ public class AWTTilePainter { System.err.println("Hint["+count+"]: "+rEntry.getKey()+" -> "+rEntry.getValue()); } final AffineTransform aTrans = g2d.getTransform(); + System.err.println(" type "+aTrans.getType()); System.err.println(" scale "+aTrans.getScaleX()+" x "+aTrans.getScaleY()); System.err.println(" move "+aTrans.getTranslateX()+" x "+aTrans.getTranslateY()); + System.err.println(" mat "+aTrans); + } + + /** + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples + * @param caps used capabilties + * @return resulting number of samples, 0 if disabled + */ + public static int getNumSamples(int numSamples, GLCapabilitiesImmutable caps) { + if( 0 > numSamples ) { + return 0; + } else if( 0 < numSamples ) { + if ( !caps.getGLProfile().isGL2ES3() ) { + return 0; + } + return Math.max(caps.getNumSamples(), numSamples); + } else { + return caps.getNumSamples(); + } } /** @@ -104,7 +135,6 @@ public class AWTTilePainter { this.scaleMatY = scaleMatY; this.verbose = verbose; this.flipVertical = true; - this.renderer.setRowOrder(TileRenderer.TR_TOP_TO_BOTTOM); } public String toString() { return renderer.toString(); } @@ -113,6 +143,25 @@ public class AWTTilePainter { flipVertical = v; } + private static Rectangle getRoundedRect(Rectangle2D r) { + if( null == r ) { return null; } + return new Rectangle((int)Math.round(r.getX()), (int)Math.round(r.getY()), + (int)Math.round(r.getWidth()), (int)Math.round(r.getHeight())); + } + private static Rectangle clipNegative(Rectangle in) { + if( null == in ) { return null; } + final Rectangle out = new Rectangle(in); + if( 0 > out.x ) { + out.width += out.x; + out.x = 0; + } + if( 0 > out.y ) { + out.height += out.y; + out.y = 0; + } + return out; + } + /** * Caches the {@link Graphics2D} instance for rendering. * <p> @@ -132,31 +181,49 @@ public class AWTTilePainter { public void setupGraphics2DAndClipBounds(Graphics2D g2d, int width, int height) { this.g2d = g2d; saveAT = g2d.getTransform(); - final Rectangle gClipOrig = g2d.getClipBounds(); - if( null == gClipOrig ) { - g2d.setClip(0, 0, width, height); + final Rectangle gClipOrigR; + final Rectangle2D dClipOrig, dImageSizeOrig; // double precision for scaling + // setup original rectangles + { + gClipOrigR = g2d.getClipBounds(); + final Rectangle gClipOrig = clipNegative(gClipOrigR); + dClipOrig = null != gClipOrig ? new Rectangle2D.Double(gClipOrig.getX(), gClipOrig.getY(), gClipOrig.getWidth(), gClipOrig.getHeight()) : null; + dImageSizeOrig = new Rectangle2D.Double(0, 0, width, height); } - g2d.scale(scaleMatX, scaleMatY); - - final Rectangle gClipScaled = g2d.getClipBounds(); - if( 0 > gClipScaled.x ) { - gClipScaled.width += gClipScaled.x; - gClipScaled.x = 0; + final Rectangle2D dClipScaled, dImageSizeScaled; // double precision for scaling + // retrieve scaled image-size and clip-bounds + { + g2d.setClip(dImageSizeOrig); + g2d.scale(scaleMatX, scaleMatY); + dImageSizeScaled = (Rectangle2D) g2d.getClip(); + if( null == dClipOrig ) { + g2d.setClip(null); + dClipScaled = (Rectangle2D) dImageSizeScaled.clone(); + } else { + g2d.setTransform(saveAT); // reset + g2d.setClip(dClipOrig); + g2d.scale(scaleMatX, scaleMatY); + dClipScaled = (Rectangle2D) g2d.getClip(); + } } - if( 0 > gClipScaled.y ) { - gClipScaled.height += gClipScaled.y; - gClipScaled.y = 0; + final Rectangle iClipScaled = getRoundedRect(dClipScaled); + final Rectangle iImageSizeScaled = getRoundedRect(dImageSizeScaled); + scaledYOffset = iClipScaled.y; + renderer.setImageSize(iImageSizeScaled.width, iImageSizeScaled.height); + renderer.clipImageSize(iClipScaled.width, iClipScaled.height); + final int clipH = Math.min(iImageSizeScaled.height, iClipScaled.height); + if( flipVertical ) { + renderer.setTileOffset(iClipScaled.x, iImageSizeScaled.height - ( iClipScaled.y + clipH )); + } else { + renderer.setTileOffset(iClipScaled.x, iClipScaled.y); } if( verbose ) { - System.err.println("AWT print.0: "+gClipOrig+" -> "+gClipScaled); - } - renderer.setImageSize(gClipScaled.width, gClipScaled.height); - renderer.setTileOffset(gClipScaled.x, gClipScaled.y); - if( null == gClipOrig ) { - // reset - g2d.setClip(null); + System.err.println("AWT print.0: image "+dImageSizeOrig + " -> " + dImageSizeScaled + " -> " + iImageSizeScaled); + System.err.println("AWT print.0: clip "+gClipOrigR + " -> " + dClipOrig + " -> " + dClipScaled + " -> " + iClipScaled); + System.err.println("AWT print.0: "+renderer); } } + private int scaledYOffset; /** See {@ #setupGraphics2DAndClipBounds(Graphics2D)}. */ public void resetGraphics2D() { @@ -208,28 +275,55 @@ public class AWTTilePainter { @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} }; + static int _counter = 0; 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) { + final DimensionImmutable cis = renderer.getClippedImageSize(); + final int tWidth = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_WIDTH); + final int tHeight = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_HEIGHT); + final int pX = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_X_POS); + final int pY = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_Y_POS); + final int pYOff = renderer.getParam(TileRenderer.TR_TILE_Y_OFFSET); + final int pYf; + if( flipVertical ) { + pYf = cis.getHeight() - ( pY - pYOff + tHeight ) + scaledYOffset; + } else { + pYf = pY; + } + // 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 tWidth = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_WIDTH); - final int tHeight = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_HEIGHT); final BufferedImage dstImage; + if( DEBUG_TILES ) { + final String fname = String.format("file_%03d_0_tile_[%02d][%02d]_sz_%03dx%03d_pos0_%03d_%03d_yOff_%03d_pos1_%03d_%03d.png", + _counter, + renderer.getParam(TileRenderer.TR_CURRENT_COLUMN), renderer.getParam(TileRenderer.TR_CURRENT_ROW), + tWidth, tHeight, + pX, pY, pYOff, pX, pYf).replace(' ', '_'); + System.err.println("XXX file "+fname); + final File fout = new File(fname); + try { + ImageIO.write(tBuffer.image, "png", fout); + } catch (IOException e) { + e.printStackTrace(); + } + } if( flipVertical ) { final BufferedImage srcImage = tBuffer.image; dstImage = vFlipImage; final int[] src = ((DataBufferInt) srcImage.getRaster().getDataBuffer()).getData(); final int[] dst = ((DataBufferInt) dstImage.getRaster().getDataBuffer()).getData(); + if( DEBUG_TILES ) { + Arrays.fill(dst, 0x55); + } final int incr = tBuffer.width; int srcPos = 0; int destPos = (tHeight - 1) * tBuffer.width; @@ -239,28 +333,31 @@ public class AWTTilePainter { } else { dstImage = tBuffer.image; } - // Draw resulting image in one shot - final int tRows = renderer.getParam(TileRenderer.TR_ROWS); - final int tRow = renderer.getParam(TileRenderer.TR_CURRENT_ROW); - final int pX = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_X_POS); - final int pYf; - if( flipVertical ) { - if( tRow == tRows - 1 ) { - tTopRowHeight = tHeight; - pYf = 0; - } else if( tRow == tRows - 2 ){ - pYf = tTopRowHeight; - } else { - pYf = ( tRows - 2 - tRow ) * tHeight + tTopRowHeight; + if( DEBUG_TILES ) { + final String fname = String.format("file_%03d_1_tile_[%02d][%02d]_sz_%03dx%03d_pos0_%03d_%03d_yOff_%03d_pos1_%03d_%03d.png", + _counter, + renderer.getParam(TileRenderer.TR_CURRENT_COLUMN), renderer.getParam(TileRenderer.TR_CURRENT_ROW), + tWidth, tHeight, + pX, pY, pYOff, pX, pYf).replace(' ', '_'); + System.err.println("XXX file "+fname); + final File fout = new File(fname); + try { + ImageIO.write(dstImage, "png", fout); + } catch (IOException e) { + e.printStackTrace(); } - } else { - pYf = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_Y_POS); - } + _counter++; + } + // Draw resulting image in one shot final Shape oClip = g2d.getClip(); - g2d.clipRect(pX, pYf, tWidth, tHeight); - g2d.drawImage(dstImage, pX, pYf, dstImage.getWidth(), dstImage.getHeight(), null); // Null ImageObserver since image data is ready. + // g2d.clipRect(pX, pYf, tWidth, tHeight); + final BufferedImage outImage = dstImage.getSubimage(0, 0, tWidth, tHeight); // instead of clipping + final boolean drawDone = g2d.drawImage(outImage, pX, pYf, null); // Null ImageObserver since image data is ready. + // final boolean drawDone = g2d.drawImage(dstImage, pX, pYf, dstImage.getWidth(), dstImage.getHeight(), null); // Null ImageObserver since image data is ready. if( verbose ) { - System.err.println("XXX tile-post.X clip "+oClip+" -> "+g2d.getClip()); + System.err.println("XXX tile-post.X clippedImageSize "+cis); + System.err.println("XXX tile-post.X pYf "+cis.getHeight()+" - ( "+pY+" - "+pYOff+" + "+tHeight+" ) "+scaledYOffset+" = "+ pYf); + System.err.println("XXX tile-post.X clip "+oClip+" + "+pX+" / [pY "+pY+", pYOff "+pYOff+", pYf "+pYf+"] "+tWidth+"x"+tHeight+" -> "+g2d.getClip()); g2d.setColor(Color.BLACK); g2d.drawRect(pX, pYf, tWidth, tHeight); if( null != oClip ) { @@ -269,9 +366,11 @@ public class AWTTilePainter { g2d.drawRect(r.x, r.y, r.width, r.height); } System.err.println("XXX tile-post.X "+renderer); - System.err.println("XXX tile-post.X dst-img "+dstImage.getWidth()+"x"+dstImage.getHeight()+", y-flip "+flipVertical+" -> "+pX+"/"+pYf); + System.err.println("XXX tile-post.X dst-img "+dstImage.getWidth()+"x"+dstImage.getHeight()); + System.err.println("XXX tile-post.X out-img "+outImage.getWidth()+"x"+dstImage.getHeight()); + System.err.println("XXX tile-post.X y-flip "+flipVertical+" -> "+pX+"/"+pYf+", drawDone "+drawDone); } - g2d.setClip(oClip); + // g2d.setClip(oClip); } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {} diff --git a/src/jogl/classes/javax/media/opengl/awt/AWTPrintLifecycle.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTPrintLifecycle.java index 1a4c5bac0..a54f6bac6 100644 --- a/src/jogl/classes/javax/media/opengl/awt/AWTPrintLifecycle.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTPrintLifecycle.java @@ -25,41 +25,47 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ -package javax.media.opengl.awt; +package com.jogamp.nativewindow.awt; -import javax.media.opengl.GLAutoDrawable; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.print.PrinterJob; import jogamp.nativewindow.awt.AWTMisc; /** - * Interface describing print lifecycle to support AWT printing - * on AWT {@link GLAutoDrawable}s. + * Interface describing print lifecycle to support AWT printing, + * e.g. on AWT {@link javax.media.opengl.GLAutoDrawable GLAutoDrawable}s. * <a name="impl"><h5>Implementations</h5></a> * <p> - * Implementing {@link GLAutoDrawable} classes based on AWT + * Implementing {@link javax.media.opengl.GLAutoDrawable GLAutoDrawable} classes based on AWT * supporting {@link Component#print(Graphics)} shall implement this interface. * </p> * <a name="usage"><h5>Usage</h5></a> * <p> * Users attempting to print an AWT {@link Container} containing {@link AWTPrintLifecycle} elements * shall consider decorating the {@link Container#printAll(Graphics)} call with<br> - * {@link #setupPrint(Graphics2D, double, double) setupPrint(..)} and {@link #releasePrint()} + * {@link #setupPrint(double, double, int) setupPrint(..)} and {@link #releasePrint()} * on all {@link AWTPrintLifecycle} elements in the {@link Container}.<br> - * To minimize this burden, a user can use {@link Context#setupPrint(Container, Graphics2D, double, double) Context.setupPrint(..)}: + * To minimize this burden, a user can use {@link Context#setupPrint(Container, double, double, int) Context.setupPrint(..)}: * <pre> * Graphics2D g2d; - * Frame frame; + * Container cont; * double scaleGLMatXY = 72.0/glDPI; + * int numSamples = 0; // leave multisampling as-is + * PrinterJob job; * ... - final AWTPrintLifecycle.Context ctx = AWTPrintLifecycle.Context.setupPrint(frame, g2d, scaleGLMatXY, scaleGLMatXY); + final AWTPrintLifecycle.Context ctx = AWTPrintLifecycle.Context.setupPrint(cont, scaleGLMatXY, scaleGLMatXY, numSamples); try { AWTEDTExecutor.singleton.invoke(true, new Runnable() { public void run() { - frame.printAll(g2d); + try { + job.print(); + } catch (PrinterException ex) { + ex.printStackTrace(); + } } }); } finally { ctx.releasePrint(); @@ -74,18 +80,18 @@ public interface AWTPrintLifecycle { /** - * Shall be called before {@link Component#print(Graphics)}. + * Shall be called before {@link PrinterJob#print()}. * <p> * See <a href="#usage">Usage</a>. * </p> - * @param g2d the {@link Graphics2D} instance, which will be used for printing. * @param scaleMatX {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatX * width pixels * @param scaleMatY {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatY * height pixels + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples */ - void setupPrint(Graphics2D g2d, double scaleMatX, double scaleMatY); + void setupPrint(double scaleMatX, double scaleMatY, int numSamples); /** - * Shall be called after very last {@link Component#print(Graphics)}. + * Shall be called after {@link PrinterJob#print()}. * <p> * See <a href="#usage">Usage</a>. * </p> @@ -93,7 +99,7 @@ public interface AWTPrintLifecycle { void releasePrint(); /** - * Convenient {@link AWTPrintLifecycle} context simplifying calling {@link AWTPrintLifecycle#setupPrint(Graphics2D, double, double) setupPrint(..)} + * Convenient {@link AWTPrintLifecycle} context simplifying calling {@link AWTPrintLifecycle#setupPrint(double, double, int) setupPrint(..)} * and {@link AWTPrintLifecycle#releasePrint()} on all {@link AWTPrintLifecycle} elements of a {@link Container}. * <p> * See <a href="#usage">Usage</a>. @@ -105,14 +111,14 @@ public interface AWTPrintLifecycle { * See <a href="#usage">Usage</a>. * </p> * - * @param c container to be traversed through to perform {@link AWTPrintLifecycle#setupPrint(Graphics2D, double, double) setupPrint(..)} on all {@link AWTPrintLifecycle} elements. - * @param g2d the {@link Graphics2D} instance, which will be used for printing. + * @param c container to be traversed through to perform {@link AWTPrintLifecycle#setupPrint(double, double, int) setupPrint(..)} on all {@link AWTPrintLifecycle} elements. * @param scaleMatX {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatX * width pixels * @param scaleMatY {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatY * height pixels + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples * @return the context */ - public static Context setupPrint(Container c, Graphics2D g2d, double scaleMatX, double scaleMatY) { - final Context t = new Context(c, g2d, scaleMatX, scaleMatY); + public static Context setupPrint(Container c, double scaleMatX, double scaleMatY, int numSamples) { + final Context t = new Context(c, scaleMatX, scaleMatY, numSamples); t.setupPrint(c); return t; } @@ -127,20 +133,20 @@ public interface AWTPrintLifecycle { } /** - * @return count of performed actions of last {@link #setupPrint(Container, Graphics2D, double, double) setupPrint(..)} or {@link #releasePrint()}. + * @return count of performed actions of last {@link #setupPrint(Container, double, double, int) setupPrint(..)} or {@link #releasePrint()}. */ public int getCount() { return count; } private final Container cont; - private final Graphics2D g2d; private final double scaleMatX; private final double scaleMatY; + private final int numSamples; private int count; private final AWTMisc.ComponentAction setupAction = new AWTMisc.ComponentAction() { @Override public void run(Component c) { - ((AWTPrintLifecycle)c).setupPrint(g2d, scaleMatX, scaleMatY); + ((AWTPrintLifecycle)c).setupPrint(scaleMatX, scaleMatY, numSamples); } }; private final AWTMisc.ComponentAction releaseAction = new AWTMisc.ComponentAction() { @Override @@ -148,11 +154,11 @@ public interface AWTPrintLifecycle { ((AWTPrintLifecycle)c).releasePrint(); } }; - private Context(Container c, Graphics2D g2d, double scaleMatX, double scaleMatY) { + private Context(Container c, double scaleMatX, double scaleMatY, int numSamples) { this.cont = c; - this.g2d = g2d; this.scaleMatX = scaleMatX; this.scaleMatY = scaleMatY; + this.numSamples = numSamples; this.count = 0; } private void setupPrint(Container c) { diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index cdf47cbb3..a2d4eb7f0 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -37,7 +37,6 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.KeyboardFocusManager; -import java.awt.RenderingHints; import java.beans.Beans; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -53,8 +52,6 @@ import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLProfile; -import javax.media.opengl.awt.AWTPrintLifecycle; import javax.swing.MenuSelectionManager; import jogamp.nativewindow.awt.AWTMisc; @@ -67,6 +64,7 @@ import jogamp.opengl.awt.AWTTilePainter; import com.jogamp.common.os.Platform; import com.jogamp.common.util.awt.AWTEDTExecutor; +import com.jogamp.nativewindow.awt.AWTPrintLifecycle; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; import com.jogamp.nativewindow.awt.JAWTWindow; import com.jogamp.newt.Display; @@ -455,13 +453,20 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto } private volatile boolean printActive = false; - private boolean printUseAA = false; + private int printNumSamples = 0; private GLAnimatorControl printAnimator = null; private GLAutoDrawable printGLAD = null; private AWTTilePainter printAWTTiles = null; + private final GLAutoDrawable getGLAD() { + if( null != newtChild && newtChild instanceof GLAutoDrawable ) { + return (GLAutoDrawable)newtChild; + } + return null; + } + @Override - public void setupPrint(Graphics2D g2d, double scaleMatX, double scaleMatY) { + public void setupPrint(double scaleMatX, double scaleMatY, int numSamples) { if( !validateComponent(true) ) { if(DEBUG) { System.err.println(getThreadName()+": Info: NewtCanvasAWT setupPrint - skipped GL render, drawable not valid yet"); @@ -474,15 +479,17 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto } return; // not yet available .. } - printActive = true; - final RenderingHints rHints = g2d.getRenderingHints(); - { - final Object _useAA = rHints.get(RenderingHints.KEY_ANTIALIASING); - printUseAA = null != _useAA && ( _useAA == RenderingHints.VALUE_ANTIALIAS_DEFAULT || _useAA == RenderingHints.VALUE_ANTIALIAS_ON ); + final GLAutoDrawable glad = getGLAD(); + if( null == glad ) { + if( DEBUG ) { + System.err.println("AWT print.setup exit, newtChild not a GLAutoDrawable: "+newtChild); + } + return; } + printActive = true; + printNumSamples = AWTTilePainter.getNumSamples(numSamples, glad.getChosenGLCapabilities()); if( DEBUG ) { - System.err.println("AWT print.setup: canvasSize "+getWidth()+"x"+getWidth()+", scaleMat "+scaleMatX+" x "+scaleMatY+", useAA "+printUseAA+", printAnimator "+printAnimator); - AWTTilePainter.dumpHintsAndScale(g2d); + System.err.println("AWT print.setup: canvasSize "+getWidth()+"x"+getWidth()+", scaleMat "+scaleMatX+" x "+scaleMatY+", numSamples "+numSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); } final int componentCount = isOpaque() ? 3 : 4; final TileRenderer printRenderer = new TileRenderer(); @@ -492,39 +499,21 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto private final Runnable setupPrintOnEDT = new Runnable() { @Override public void run() { - final GLAutoDrawable glad; - if( null != newtChild && newtChild instanceof GLAutoDrawable ) { - glad = (GLAutoDrawable)newtChild; - } else { - if( DEBUG ) { - System.err.println("AWT print.setup exit, newtChild not a GLAutoDrawable: "+newtChild); - } - printAWTTiles = null; - printActive = false; - return; - } + final GLAutoDrawable glad = getGLAD(); printAnimator = glad.getAnimator(); if( null != printAnimator ) { printAnimator.remove(glad); } final GLCapabilities caps = (GLCapabilities)glad.getChosenGLCapabilities().cloneMutable(); - final GLProfile glp = caps.getGLProfile(); if( caps.getSampleBuffers() ) { - // bug / issue w/ swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX + // Bug 830: swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX printGLAD = glad; } else { caps.setDoubleBuffered(false); caps.setOnscreen(false); - if( printUseAA && !caps.getSampleBuffers() ) { - if ( !glp.isGL2ES3() ) { - if( DEBUG ) { - System.err.println("Ignore MSAA due to gl-profile < GL2ES3"); - } - printUseAA = false; - } else { - caps.setSampleBuffers(true); - caps.setNumSamples(8); - } + if( printNumSamples != caps.getNumSamples() ) { + caps.setSampleBuffers(0 < printNumSamples); + caps.setNumSamples(printNumSamples); } final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); printGLAD = factory.createOffscreenAutoDrawable(null, caps, null, DEFAULT_PRINT_TILE_SIZE, DEFAULT_PRINT_TILE_SIZE, null); @@ -535,7 +524,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto printAWTTiles.renderer.attachToAutoDrawable(printGLAD); if( DEBUG ) { System.err.println("AWT print.setup "+printAWTTiles); - System.err.println("AWT print.setup AA "+printUseAA+", "+caps); + System.err.println("AWT print.setup AA "+printNumSamples+", "+caps); System.err.println("AWT print.setup "+printGLAD); } } @@ -557,7 +546,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto if( DEBUG ) { System.err.println("AWT print.release "+printAWTTiles); } - final GLAutoDrawable glad = (GLAutoDrawable)newtChild; + final GLAutoDrawable glad = getGLAD(); printAWTTiles.dispose(); printAWTTiles= null; if( printGLAD != glad ) { 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 322d2d1b5..908a89a32 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 @@ -115,15 +115,15 @@ public class TestTiledPrintingGearsAWT extends TiledPrintingAWTBase { final ActionListener print72DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 72, false); + doPrintManual(frame, 72, 0); } }; final ActionListener print300DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 300, false); + doPrintManual(frame, 300, -1); } }; final ActionListener print600DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 600, false); + doPrintManual(frame, 600, -1); } }; final Button print72DPIButton = new Button("72dpi"); print72DPIButton.addActionListener(print72DPIAction); @@ -176,15 +176,15 @@ public class TestTiledPrintingGearsAWT extends TiledPrintingAWTBase { Thread.sleep(200); if( !printDone ) { printDone = true; - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, 0); waitUntilPrintJobsIdle(); - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, true); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, 8); waitUntilPrintJobsIdle(); // No AA needed for 300 dpi and greater :) - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 300, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 300, -1); waitUntilPrintJobsIdle(); if( allow600dpi ) { - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 600, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 600, -1); waitUntilPrintJobsIdle(); } } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsNewtAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsNewtAWT.java index f7f856676..c695febbe 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsNewtAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsNewtAWT.java @@ -120,15 +120,15 @@ public class TestTiledPrintingGearsNewtAWT extends TiledPrintingAWTBase { final ActionListener print72DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 72, false); + doPrintManual(frame, 72, 0); } }; final ActionListener print300DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 300, false); + doPrintManual(frame, 300, -1); } }; final ActionListener print600DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 600, false); + doPrintManual(frame, 600, -1); } }; final Button print72DPIButton = new Button("72dpi"); print72DPIButton.addActionListener(print72DPIAction); @@ -181,15 +181,15 @@ public class TestTiledPrintingGearsNewtAWT extends TiledPrintingAWTBase { Thread.sleep(200); if( !printDone ) { printDone = true; - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, 0); waitUntilPrintJobsIdle(); - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, true); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, 8); waitUntilPrintJobsIdle(); // No AA needed for 300 dpi and greater :) - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 300, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 300, -1); waitUntilPrintJobsIdle(); if( allow600dpi ) { - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 600, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 600, -1); waitUntilPrintJobsIdle(); } } 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 index da577ea1d..9c5d6bf8b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsSwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledPrintingGearsSwingAWT.java @@ -45,7 +45,11 @@ import java.lang.reflect.InvocationTargetException; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLProfile; import javax.media.opengl.awt.GLJPanel; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; import javax.swing.JFrame; +import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; @@ -93,40 +97,67 @@ public class TestTiledPrintingGearsSwingAWT extends TiledPrintingAWTBase { public static void releaseClass() { } - protected void runTestGL(GLCapabilities caps) throws InterruptedException, InvocationTargetException { - final Dimension glc_sz = new Dimension(width/2, height); + protected void runTestGL(GLCapabilities caps, boolean layered) throws InterruptedException, InvocationTargetException { + final int layerStepX = width/6, layerStepY = height/6; + final Dimension glc_sz = new Dimension(layered ? width - 2*layerStepX : width/2, layered ? height - 2*layerStepY : height); final GLJPanel glJPanel1 = new GLJPanel(caps); Assert.assertNotNull(glJPanel1); glJPanel1.setMinimumSize(glc_sz); glJPanel1.setPreferredSize(glc_sz); - glJPanel1.setSize(glc_sz); + if( layered ) { + glJPanel1.setBounds(layerStepX/2, layerStepY/2, glc_sz.width, glc_sz.height); + } else { + glJPanel1.setBounds(0, 0, glc_sz.width, glc_sz.height); + } glJPanel1.addGLEventListener(new Gears()); final GLJPanel glJPanel2 = new GLJPanel(caps); Assert.assertNotNull(glJPanel2); glJPanel2.setMinimumSize(glc_sz); glJPanel2.setPreferredSize(glc_sz); - glJPanel2.setSize(glc_sz); + if( layered ) { + glJPanel2.setBounds(3*layerStepY, 2*layerStepY, glc_sz.width, glc_sz.height); + } else { + glJPanel2.setBounds(0, 0, glc_sz.width, glc_sz.height); + } glJPanel2.addGLEventListener(new RedSquareES2()); + // glJPanel2.addGLEventListener(new Gears()); - final JPanel demoPanel = new JPanel(); - demoPanel.add(glJPanel1); - demoPanel.add(glJPanel2); + final JComponent demoPanel; + if( layered ) { + glJPanel1.setOpaque(true); + glJPanel2.setOpaque(false); + final Dimension lsz = new Dimension(width, height); + demoPanel = new JLayeredPane(); + demoPanel.setMinimumSize(lsz); + demoPanel.setPreferredSize(lsz); + demoPanel.setBounds(0, 0, lsz.width, lsz.height); + demoPanel.setBorder(BorderFactory.createTitledBorder("Layered Pane")); + demoPanel.add(glJPanel1, JLayeredPane.DEFAULT_LAYER); + demoPanel.add(glJPanel2, Integer.valueOf(1)); + final JButton tb = new JButton("On Top"); + tb.setBounds(4*layerStepY, 3*layerStepY, 100, 50); + demoPanel.add(tb, Integer.valueOf(2)); + } else { + demoPanel = new JPanel(); + demoPanel.add(glJPanel1); + demoPanel.add(glJPanel2); + } final JFrame frame = new JFrame("Swing Print"); Assert.assertNotNull(frame); final ActionListener print72DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 72, false); + doPrintManual(frame, 72, 0); } }; final ActionListener print300DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 300, false); + doPrintManual(frame, 300, -1); } }; final ActionListener print600DPIAction = new ActionListener() { public void actionPerformed(ActionEvent e) { - doPrintManual(frame, 600, false); + doPrintManual(frame, 600, -1); } }; final Button print72DPIButton = new Button("72dpi"); print72DPIButton.addActionListener(print72DPIAction); @@ -182,20 +213,19 @@ public class TestTiledPrintingGearsSwingAWT extends TiledPrintingAWTBase { Thread.sleep(200); if( !printDone ) { printDone = true; - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, 0); waitUntilPrintJobsIdle(); - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, true); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 72, 8); waitUntilPrintJobsIdle(); // No AA needed for 300 dpi and greater :) - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 300, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 300, -1); waitUntilPrintJobsIdle(); if( allow600dpi ) { - doPrintAuto(frame, PageFormat.LANDSCAPE, null, 600, false); + doPrintAuto(frame, PageFormat.LANDSCAPE, null, 600, -1); waitUntilPrintJobsIdle(); } } } - // try { Thread.sleep(4000); } catch (InterruptedException e) { } // time to finish print jobs .. FIXME ?? Assert.assertNotNull(frame); Assert.assertNotNull(glJPanel1); @@ -220,15 +250,22 @@ public class TestTiledPrintingGearsSwingAWT extends TiledPrintingAWTBase { @Test public void test01_Onscreen_aa0() throws InterruptedException, InvocationTargetException { GLCapabilities caps = new GLCapabilities(glp); - runTestGL(caps); + runTestGL(caps, false); + } + + @Test + public void test01_Onscreen_aa0_layered() throws InterruptedException, InvocationTargetException { + GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(8); + runTestGL(caps, true); } @Test public void test02_Onscreen_aa8() throws InterruptedException, InvocationTargetException { GLCapabilities caps = new GLCapabilities(glp); caps.setSampleBuffers(true); - caps.setNumSamples(8); // FIXME - runTestGL(caps); + caps.setNumSamples(8); + runTestGL(caps, false); } static long duration = 500; // ms 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 ec216a95e..c23d51c51 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 @@ -28,11 +28,10 @@ package com.jogamp.opengl.test.junit.jogl.tile; -import java.awt.Frame; +import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; -import java.awt.RenderingHints; import java.awt.print.PageFormat; import java.awt.print.Paper; import java.awt.print.Printable; @@ -41,7 +40,6 @@ import java.awt.print.PrinterJob; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import javax.media.opengl.awt.AWTPrintLifecycle; import javax.print.StreamPrintService; import javax.print.StreamPrintServiceFactory; import javax.print.attribute.HashPrintRequestAttributeSet; @@ -53,6 +51,7 @@ import org.junit.Assert; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.nativewindow.awt.AWTPrintLifecycle; import com.jogamp.opengl.test.junit.util.UITestCase; /** @@ -97,11 +96,7 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab public static final double A0_HEIGHT_INCH = A0_WIDTH_MM / MM_PER_INCH; */ /** Helper to pass desired Frame to print! **/ - private Frame frame; - /** Helper to pass desired DPI value ! **/ - private int glDPI = 72; - /** Helper to pass desired AA hint ! **/ - private boolean printAA = false; + private Container printContainer; private RecursiveLock lockPrinting = LockFactory.createRecursiveLock(); @@ -155,9 +150,9 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab /** * See: 'Scaling of Frame and GL content' in Class description! */ - final Insets frameInsets = frame.getInsets(); - final int frameWidth = frame.getWidth(); - final int frameHeight= frame.getHeight(); + final Insets frameInsets = printContainer.getInsets(); + final int frameWidth = printContainer.getWidth(); + final int frameHeight= printContainer.getHeight(); final double scaleComp72; { final int frameBorderW = frameInsets.left + frameInsets.right; @@ -166,32 +161,21 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab final double sy = pf.getImageableHeight() / ( frameHeight + frameBorderH ); scaleComp72 = Math.min(sx, sy); } - final double scaleGLMatXY = 72.0 / glDPI; System.err.println("PRINT thread "+Thread.currentThread().getName()); - System.err.println("PRINT DPI: "+glDPI+", AA "+printAA+", scaleGL "+scaleGLMatXY+", scaleComp72 "+scaleComp72+ + System.err.println("PRINT DPI: scaleComp72 "+scaleComp72+ ", frame: border "+frameInsets+", size "+frameWidth+"x"+frameHeight); - final Graphics2D printG2D = (Graphics2D)g; - final Graphics2D g2d = printG2D; - + final Graphics2D g2d = (Graphics2D)g; + System.err.println("PRINT at.pre: "+g2d.getTransform()); g2d.translate(pf.getImageableX(), pf.getImageableY()); g2d.scale(scaleComp72, scaleComp72); - - if( printAA ) { - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - } - final AWTPrintLifecycle.Context ctx = AWTPrintLifecycle.Context.setupPrint(frame, g2d, scaleGLMatXY, scaleGLMatXY); - try { - System.err.println("PRINT AWTPrintLifecycle.setup.count "+ctx.getCount()); - AWTEDTExecutor.singleton.invoke(true, new Runnable() { - public void run() { - frame.printAll(g2d); - } - }); - } finally { - ctx.releasePrint(); - System.err.println("PRINT AWTPrintLifecycle.release.count "+ctx.getCount()); - } + System.err.println("PRINT at.post: "+g2d.getTransform()); + + AWTEDTExecutor.singleton.invoke(true, new Runnable() { + public void run() { + printContainer.printAll(g2d); + } + }); /* tell the caller that this page is part of the printed document */ return PAGE_EXISTS; @@ -207,7 +191,15 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab super(); } - public void doPrintAuto(Frame frame, int pOrientation, Paper paper, int dpi, boolean antialiasing) { + /** + * + * @param cont + * @param pOrientation + * @param paper + * @param dpi + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples + */ + public void doPrintAuto(Container cont, int pOrientation, Paper paper, int dpi, int numSamples) { lock.lock(); try { final PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); @@ -224,12 +216,12 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab StreamPrintServiceFactory[] factories = PrinterJob.lookupStreamPrintServices(pdfMimeType); if (factories.length > 0) { - final String fname = getPrintFilename(dpi, antialiasing, "pdf"); + final String fname = getPrintFilename(dpi, numSamples, "pdf"); System.err.println("doPrint: dpi "+dpi+", "+fname); FileOutputStream outstream; try { outstream = new FileOutputStream(fname); - Assert.assertTrue(doPrintAutoImpl(frame, pj, factories[0].getPrintService(outstream), pOrientation, paper, dpi, antialiasing)); + Assert.assertTrue(doPrintAutoImpl(cont, pj, factories[0].getPrintService(outstream), pOrientation, paper, dpi, numSamples)); } catch (FileNotFoundException e) { Assert.assertNull("Unexpected exception", e); } @@ -239,12 +231,12 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab factories = PrinterJob.lookupStreamPrintServices(psMimeType); if (factories.length > 0) { - final String fname = getPrintFilename(dpi, antialiasing, "ps"); + final String fname = getPrintFilename(dpi, numSamples, "ps"); System.err.println("doPrint: dpi "+dpi+", "+fname); FileOutputStream outstream; try { outstream = new FileOutputStream(fname); - Assert.assertTrue(doPrintAutoImpl(frame, pj, factories[0].getPrintService(outstream), pOrientation, paper, dpi, antialiasing)); + Assert.assertTrue(doPrintAutoImpl(cont, pj, factories[0].getPrintService(outstream), pOrientation, paper, dpi, numSamples)); } catch (FileNotFoundException e) { Assert.assertNull("Unexpected exception", e); } @@ -255,18 +247,14 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab lock.unlock(); } } - private String getPrintFilename(int dpi, boolean antialiasing, String suffix) { + private String getPrintFilename(int dpi, int numSamples, String suffix) { final int maxSimpleTestNameLen = getMaxTestNameLen()+getClass().getSimpleName().length()+1; final String simpleTestName = getSimpleTestName("."); - final String sAA = antialiasing ? "aa_" : "raw"; - return String.format("%-"+maxSimpleTestNameLen+"s-n%04d-dpi%03d-%s.%s", simpleTestName, printCount, dpi, sAA, suffix).replace(' ', '_'); + return String.format("%-"+maxSimpleTestNameLen+"s-n%04d-dpi%03d-aa%d.%s", simpleTestName, printCount, dpi, numSamples, suffix).replace(' ', '_'); } - private boolean doPrintAutoImpl(Frame frame, PrinterJob job, + private boolean doPrintAutoImpl(Container cont, PrinterJob job, StreamPrintService ps, int pOrientation, Paper paper, int dpi, - boolean antialiasing) { - this.frame = frame; - glDPI = dpi; - printAA = antialiasing; + int numSamples) { boolean ok = true; try { PageFormat pageFormat = job.defaultPage(); @@ -280,7 +268,7 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab pageFormat.setOrientation(pOrientation); // PageFormat.LANDSCAPE or PageFormat.PORTRAIT job.setPrintService(ps); job.setPrintable(this, pageFormat); - job.print(); + doPrintImpl(cont, job, dpi, numSamples); } catch (PrinterException pe) { pe.printStackTrace(); ok = false; @@ -288,25 +276,52 @@ public abstract class TiledPrintingAWTBase extends UITestCase implements Printab return ok; } - public void doPrintManual(Frame frame, int dpi, boolean antialiasing) { + /** + * + * @param cont + * @param dpi + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples + */ + public void doPrintManual(Container cont, int dpi, int numSamples) { lock.lock(); try { - this.frame = frame; - glDPI = dpi; - printAA = antialiasing; PrinterJob job = PrinterJob.getPrinterJob(); job.setPrintable(this); boolean ok = job.printDialog(); if (ok) { + doPrintImpl(cont, job, dpi, numSamples); + } + } finally { + lock.unlock(); + } + } + + /** + * + * @param cont + * @param job + * @param dpi + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples + */ + private void doPrintImpl(final Container cont, final PrinterJob job, final int dpi, final int numSamples) { + printContainer = cont; + final double scaleGLMatXY = 72.0 / dpi; + System.err.println("PRINT DPI: "+dpi+", AA "+numSamples+", scaleGL "+scaleGLMatXY); + final AWTPrintLifecycle.Context ctx = AWTPrintLifecycle.Context.setupPrint(printContainer, scaleGLMatXY, scaleGLMatXY, numSamples); + System.err.println("PRINT AWTPrintLifecycle.setup.count "+ctx.getCount()); + try { + AWTEDTExecutor.singleton.invoke(true, new Runnable() { + public void run() { try { job.print(); } catch (PrinterException ex) { ex.printStackTrace(); } - } - } finally { - lock.unlock(); - } + } }); + } finally { + ctx.releasePrint(); + System.err.println("PRINT AWTPrintLifecycle.release.count "+ctx.getCount()); + } } /** Wait for idle .. simply acquiring all locks and releasing them. */ |