summaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-09-07 12:52:19 +0200
committerSven Gothel <[email protected]>2013-09-07 12:52:19 +0200
commit4b5e77961d1c660f3537f4041fc1a3ce47ef105c (patch)
treedb6bd07357ce6a79d5cb6279b76fa58d99e7b508 /src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java
parent27c4a837580c7a68582e852d5ff64f733e669509 (diff)
AWT/GL Printing WIP: Abstract AWT tile painting code out to AWTTilePainter, reused w/ GLCanvas and GLJPanel
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java')
-rw-r--r--src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java b/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java
new file mode 100644
index 000000000..7493a19c5
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java
@@ -0,0 +1,217 @@
+/**
+ * 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 jogamp.opengl.awt;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+
+import com.jogamp.opengl.util.TileRenderer;
+import com.jogamp.opengl.util.TileRendererBase;
+import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes;
+import com.jogamp.opengl.util.awt.AWTGLPixelBuffer;
+import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.AWTGLPixelBufferProvider;
+
+/**
+ * Implementing AWT {@link Graphics2D} based {@link TileRenderer} <i>painter</i>.
+ * <p>
+ * Maybe utilized for AWT printing.
+ * </p>
+ */
+public class AWTTilePainter {
+ final private TileRenderer renderer;
+ final private int componentCount;
+ final private boolean verbose;
+
+ private AWTGLPixelBuffer tBuffer = null;
+ private BufferedImage vFlipImage = null;
+ private Graphics2D g2d = null;
+
+ /**
+ * Assumes a configured {@link TileRenderer}, i.e.
+ * an {@link TileRenderer#attachToAutoDrawable(GLAutoDrawable) attached}
+ * {@link GLAutoDrawable} with {@link TileRenderer#setTileSize(int, int, int) set tile size}.
+ * <p>
+ * Sets the renderer to {@link TileRenderer#TR_TOP_TO_BOTTOM} row order.
+ * </p>
+ * <p>
+ * <code>componentCount</code> reflects opaque, i.e. 4 if non opaque.
+ * </p>
+ */
+ public AWTTilePainter(TileRenderer renderer, int componentCount, boolean verbose) {
+ this.renderer = renderer;
+ this.renderer.setGLEventListener(preTileGLEL, postTileGLEL);
+ this.componentCount = componentCount;
+ this.verbose = verbose;
+ this.renderer.setRowOrder(TileRenderer.TR_TOP_TO_BOTTOM);
+ }
+
+ public String toString() { return renderer.toString(); }
+
+ public TileRenderer getTileRenderer() { return renderer; }
+
+ /**
+ * Caches the {@link Graphics2D} instance for rendering.
+ * <p>
+ * Sets the {@link TileRenderer}'s {@link TileRenderer#setImageSize(int, int) image size}
+ * and {@link TileRenderer#setTileOffset(int, int) tile offset} according the
+ * the {@link Graphics2D#getClipBounds() graphics clip bounds}.
+ * </p>
+ * @param g2d
+ */
+ public void updateGraphics2DAndClipBounds(Graphics2D g2d) {
+ this.g2d = g2d;
+ final Rectangle gClipOrig = g2d.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;
+ }
+ if( verbose ) {
+ System.err.println("AWT print.0: "+gClipOrig+" -> "+gClip);
+ }
+ renderer.setImageSize(gClip.width, gClip.height);
+ renderer.setTileOffset(gClip.x, gClip.y);
+ }
+
+ /**
+ * Disposes resources and {@link TileRenderer#detachFromAutoDrawable() detaches}
+ * the {@link TileRenderer}'s {@link GLAutoDrawable}.
+ */
+ public void dispose() {
+ renderer.detachFromAutoDrawable(); // tile-renderer -> printGLAD
+ g2d = null;
+ if( null != tBuffer ) {
+ tBuffer.dispose();
+ tBuffer = null;
+ }
+ if( null != vFlipImage ) {
+ vFlipImage.flush();
+ vFlipImage = null;
+ }
+ }
+
+ 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 == tBuffer ) {
+ final int tWidth = renderer.getParam(TileRenderer.TR_TILE_WIDTH);
+ final int tHeight = renderer.getParam(TileRenderer.TR_TILE_HEIGHT);
+ final AWTGLPixelBufferProvider printBufferProvider = new AWTGLPixelBufferProvider( true /* allowRowStride */ );
+ final GLPixelAttributes pixelAttribs = printBufferProvider.getAttributes(gl, componentCount);
+ tBuffer = printBufferProvider.allocate(gl, pixelAttribs, tWidth, tHeight, 1, true, 0);
+ renderer.setTileBuffer(tBuffer);
+ vFlipImage = new BufferedImage(tBuffer.width, tBuffer.height, tBuffer.image.getType());
+ }
+ if( verbose ) {
+ System.err.println("XXX tile-pre "+renderer);
+ }
+ }
+ @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 tWidth = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_WIDTH);
+ final int tHeight = renderer.getParam(TileRendererBase.TR_CURRENT_TILE_HEIGHT);
+ // final BufferedImage dstImage = printBuffer.image;
+ final BufferedImage srcImage = tBuffer.image;
+ final BufferedImage dstImage = vFlipImage;
+ final int[] src = ((DataBufferInt) srcImage.getRaster().getDataBuffer()).getData();
+ final int[] dst = ((DataBufferInt) dstImage.getRaster().getDataBuffer()).getData();
+ final int incr = tBuffer.width;
+ int srcPos = 0;
+ int destPos = (tHeight - 1) * tBuffer.width;
+ for (; destPos >= 0; srcPos += incr, destPos -= incr) {
+ System.arraycopy(src, srcPos, dst, destPos, incr);
+ }
+ // 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( tRow == tRows - 1 ) {
+ tTopRowHeight = tHeight;
+ pYf = 0;
+ } else if( tRow == tRows - 2 ){
+ pYf = tTopRowHeight;
+ } else {
+ pYf = ( tRows - 2 - tRow ) * tHeight + tTopRowHeight;
+ }
+ final Shape oClip = g2d.getClip();
+ g2d.clipRect(pX, pYf, tWidth, tHeight);
+ final Shape clip = g2d.getClip();
+ g2d.drawImage(dstImage, pX, pYf, dstImage.getWidth(), dstImage.getHeight(), null); // Null ImageObserver since image data is ready.
+ g2d.setColor(Color.BLACK);
+ g2d.drawRect(pX, pYf, tWidth, tHeight);
+ {
+ final Rectangle r = oClip.getBounds();
+ g2d.setColor(Color.YELLOW);
+ g2d.drawRect(r.x, r.y, r.width, r.height);
+ }
+ g2d.setClip(oClip);
+ if( verbose ) {
+ System.err.println("XXX tile-post.X clip "+oClip+" -> "+clip);
+ System.err.println("XXX tile-post.X "+renderer);
+ System.err.println("XXX tile-post.X dst-img "+dstImage.getWidth()+"x"+dstImage.getHeight()+" -> "+pX+"/"+pYf);
+ }
+ }
+ @Override
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
+ };
+
+}