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 /src/jogl/classes/javax/media/opengl/awt | |
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 ..
Diffstat (limited to 'src/jogl/classes/javax/media/opengl/awt')
3 files changed, 25 insertions, 217 deletions
diff --git a/src/jogl/classes/javax/media/opengl/awt/AWTPrintLifecycle.java b/src/jogl/classes/javax/media/opengl/awt/AWTPrintLifecycle.java deleted file mode 100644 index 1a4c5bac0..000000000 --- a/src/jogl/classes/javax/media/opengl/awt/AWTPrintLifecycle.java +++ /dev/null @@ -1,162 +0,0 @@ -/** - * 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 javax.media.opengl.awt; - -import javax.media.opengl.GLAutoDrawable; -import java.awt.Component; -import java.awt.Container; -import java.awt.Graphics; -import java.awt.Graphics2D; - -import jogamp.nativewindow.awt.AWTMisc; - -/** - * Interface describing print lifecycle to support AWT printing - * on AWT {@link GLAutoDrawable}s. - * <a name="impl"><h5>Implementations</h5></a> - * <p> - * Implementing {@link 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()} - * 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(..)}: - * <pre> - * Graphics2D g2d; - * Frame frame; - * double scaleGLMatXY = 72.0/glDPI; - * ... - final AWTPrintLifecycle.Context ctx = AWTPrintLifecycle.Context.setupPrint(frame, g2d, scaleGLMatXY, scaleGLMatXY); - try { - AWTEDTExecutor.singleton.invoke(true, new Runnable() { - public void run() { - frame.printAll(g2d); - } }); - } finally { - ctx.releasePrint(); - } - * - * </pre> - * </p> - */ -public interface AWTPrintLifecycle { - - public static final int DEFAULT_PRINT_TILE_SIZE = 512; - - - /** - * Shall be called before {@link Component#print(Graphics)}. - * <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 - */ - void setupPrint(Graphics2D g2d, double scaleMatX, double scaleMatY); - - /** - * Shall be called after very last {@link Component#print(Graphics)}. - * <p> - * See <a href="#usage">Usage</a>. - * </p> - */ - void releasePrint(); - - /** - * Convenient {@link AWTPrintLifecycle} context simplifying calling {@link AWTPrintLifecycle#setupPrint(Graphics2D, double, double) setupPrint(..)} - * and {@link AWTPrintLifecycle#releasePrint()} on all {@link AWTPrintLifecycle} elements of a {@link Container}. - * <p> - * See <a href="#usage">Usage</a>. - * </p> - */ - public static class Context { - /** - * <p> - * 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 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 - * @return the context - */ - public static Context setupPrint(Container c, Graphics2D g2d, double scaleMatX, double scaleMatY) { - final Context t = new Context(c, g2d, scaleMatX, scaleMatY); - t.setupPrint(c); - return t; - } - - /** - * <p> - * See <a href="#usage">Usage</a>. - * </p> - */ - public void releasePrint() { - count = AWTMisc.performAction(cont, AWTPrintLifecycle.class, releaseAction); - } - - /** - * @return count of performed actions of last {@link #setupPrint(Container, Graphics2D, double, double) 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 int count; - - private final AWTMisc.ComponentAction setupAction = new AWTMisc.ComponentAction() { - @Override - public void run(Component c) { - ((AWTPrintLifecycle)c).setupPrint(g2d, scaleMatX, scaleMatY); - } }; - private final AWTMisc.ComponentAction releaseAction = new AWTMisc.ComponentAction() { - @Override - public void run(Component c) { - ((AWTPrintLifecycle)c).releasePrint(); - } }; - - private Context(Container c, Graphics2D g2d, double scaleMatX, double scaleMatY) { - this.cont = c; - this.g2d = g2d; - this.scaleMatX = scaleMatX; - this.scaleMatY = scaleMatY; - this.count = 0; - } - private void setupPrint(Container c) { - count = AWTMisc.performAction(c, AWTPrintLifecycle.class, setupAction); - } - } -} 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(); |