summaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl/util
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-04-18 03:16:33 +0200
committerSven Gothel <[email protected]>2013-04-18 03:16:33 +0200
commitfd418a69eca7b8c1bb74244982305fc6004d0a52 (patch)
tree8497ba7ce287b3295e6be8e2344e701cdb7c90e7 /src/jogl/classes/com/jogamp/opengl/util
parent3cc6fd350fe56ac5b344ee75cfa8bfe4dcc44f1b (diff)
Fix Bug 720: Unify all platform specific GLContextImpl specializations; Fix Bug 719 - Windows BITMAP Offscreen Orientation is not propagated through API
Fix Bug 719 - Windows BITMAP Offscreen Orientation is not propagated through API Depends on Bug 720, since cleaning up GLContextImpl* is required to move property 'GLContext.isGLOrientationFlippedVertical()' to 'GLDrawable.isGLOriented()' where it belongs! Windows BITMAP GLDrawable impl. isGLOriented() shall return false, while we keep the BITMAPINFOHEADER's height field negative to remove the need for vertical flip when used w/ AWT or Windows, .. Then property 'GLDrawable.isGLOriented()' has to be recognized throughout the utility functions, i.e. TextureData's mustFlipVertically and hence TextureIO writer. Fix Bug 720: Unify all platform specific GLContextImpl specializations GLContextImpl shall have only _one_ unique platform derivative to allow proper swapping of GLDrawables of any type via: - 'GLAutoDrawable.setContext(GLContext newCtx, boolean destroyPrevCtx)', which calls - 'GLContext.setGLDrawable(GLDrawable readWrite, boolean setWriteOnly)' Exception: External context may be specialized. All drawable specific property handling shall be provided and implemented (if possible) via GLDrawable specializations. - GLContext.isGLOrientationFlippedVertical() -> GLDrawable.isGLOriented() - PNGImage.createFromData() takes 'isGLOriented' to properly handle vertical flipping simply by line ordering - TextureIO's PNG writer passes TextureData's getMustFlipVertically() as isGLOriented to PNGImage.createFromData() - GLReadBufferUtil respects GLDrawable's isGLOriented() when creating TextureData instance. - Screenshot respects GLDrawable's isGLOriented() - Screenshot is deprecated, use GLReadBufferUtil. - Removed all PBuffer attributes, i.e. floatingPoint, RenderToTexture and RenderToTextureRectangle. - Allows removal of special pbuffer handling in GLContext* implementations. - Removed also from GLCapabilities* - Removed from deprecated GLPbuffer Impact: - Low, users who desire to render into a texture shall use our FBO GLOffscreenDrawable. - Only use case was the deprecated GLPbuffer - floating point framebuffer technology is still patented anyways :) - Removed Java2DGLContext, which was only used for OSX's GLJPanel Java2D bridge, which is no more supported anyways.
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/util')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java17
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/awt/Screenshot.java36
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java2
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java121
4 files changed, 126 insertions, 50 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
index b8709f31c..1345d29bd 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
@@ -111,11 +111,15 @@ public class GLReadBufferUtil {
*
* @param gl the current GL context object. It's read drawable is being used as the pixel source.
* @param drawable the drawable to read from
- * @param flip weather to flip the data vertically or not
+ * @param mustFlipVertically indicates weather to flip the data vertically or not.
+ * The context's drawable {@link GLDrawable#isGLOriented()} state
+ * is taken into account.
+ * Vertical flipping is propagated to TextureData
+ * and handled in a efficient manner there (TextureCoordinates and TextureIO writer).
*
* @see #GLReadBufferUtil(boolean, boolean)
*/
- public boolean readPixels(GL gl, boolean flip) {
+ public boolean readPixels(GL gl, boolean mustFlipVertically) {
final int glerr0 = gl.glGetError();
if(GL.GL_NO_ERROR != glerr0) {
System.err.println("Info: GLReadBufferUtil.readPixels: pre-exisiting GL error 0x"+Integer.toHexString(glerr0));
@@ -124,6 +128,13 @@ public class GLReadBufferUtil {
final int textureInternalFormat, textureDataFormat, textureDataType;
final int[] glImplColorReadVals = new int[] { 0, 0 };
+ final boolean flipVertically;
+ if( drawable.isGLOriented() ) {
+ flipVertically = mustFlipVertically;
+ } else {
+ flipVertically = !mustFlipVertically;
+ }
+
if(gl.isGL2GL3() && 3 == components) {
textureInternalFormat=GL.GL_RGB;
textureDataFormat=GL.GL_RGB;
@@ -158,7 +169,7 @@ public class GLReadBufferUtil {
textureDataFormat,
textureDataType,
false, false,
- flip,
+ flipVertically,
readPixelBuffer,
null /* Flusher */);
newData = true;
diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/Screenshot.java b/src/jogl/classes/com/jogamp/opengl/util/awt/Screenshot.java
index 0022d5c2d..0eab65380 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/awt/Screenshot.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/awt/Screenshot.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 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
@@ -43,17 +44,24 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
+import javax.media.opengl.GL;
import javax.media.opengl.GL2;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLException;
-import javax.media.opengl.glu.gl2.GLUgl2;
import com.jogamp.common.util.IOUtil;
import com.jogamp.opengl.GLExtensions;
import com.jogamp.opengl.util.GLPixelStorageModes;
import com.jogamp.opengl.util.TGAWriter;
-/** Utilities for taking screenshots of OpenGL applications. */
-
+/**
+ * Utilities for taking screenshots of OpenGL applications.
+ * @deprecated Please consider using {@link com.jogamp.opengl.util.GLReadBufferUtil},
+ * which is AWT independent and does not require a CPU based vertical image flip
+ * in case drawable {@link GLDrawable#isGLOriented() is in OpenGL orientation}.
+ */
public class Screenshot {
private Screenshot() {}
@@ -149,17 +157,17 @@ public class Screenshot {
writer.open(file, width, height, alpha);
ByteBuffer bgr = writer.getImageData();
- GL2 gl = GLUgl2.getCurrentGL2();
+ GL gl = GLContext.getCurrentGL();
// Set up pixel storage modes
GLPixelStorageModes psm = new GLPixelStorageModes();
psm.setPackAlignment(gl, 1);
- int readbackType = (alpha ? GL2.GL_ABGR_EXT : GL2.GL_BGR);
+ int readbackType = (alpha ? GL2.GL_ABGR_EXT : GL2GL3.GL_BGR);
// read the BGR values into the image buffer
gl.glReadPixels(x, y, width, height, readbackType,
- GL2.GL_UNSIGNED_BYTE, bgr);
+ GL.GL_UNSIGNED_BYTE, bgr);
// Restore pixel storage modes
psm.restore(gl);
@@ -247,7 +255,7 @@ public class Screenshot {
int height,
boolean alpha) throws GLException {
int bufImgType = (alpha ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR);
- int readbackType = (alpha ? GL2.GL_ABGR_EXT : GL2.GL_BGR);
+ int readbackType = (alpha ? GL2.GL_ABGR_EXT : GL2GL3.GL_BGR);
if (alpha) {
checkExtABGR();
@@ -256,7 +264,8 @@ public class Screenshot {
// Allocate necessary storage
BufferedImage image = new BufferedImage(width, height, bufImgType);
- GL2 gl = GLUgl2.getCurrentGL2();
+ GLContext glc = GLContext.getCurrent();
+ GL gl = glc.getGL();
// Set up pixel storage modes
GLPixelStorageModes psm = new GLPixelStorageModes();
@@ -264,14 +273,16 @@ public class Screenshot {
// read the BGR values into the image
gl.glReadPixels(x, y, width, height, readbackType,
- GL2.GL_UNSIGNED_BYTE,
+ GL.GL_UNSIGNED_BYTE,
ByteBuffer.wrap(((DataBufferByte) image.getRaster().getDataBuffer()).getData()));
// Restore pixel storage modes
psm.restore(gl);
- // Must flip BufferedImage vertically for correct results
- ImageUtil.flipImageVertically(image);
+ if( glc.getGLDrawable().isGLOriented() ) {
+ // Must flip BufferedImage vertically for correct results
+ ImageUtil.flipImageVertically(image);
+ }
return image;
}
@@ -392,7 +403,8 @@ public class Screenshot {
}
private static void checkExtABGR() {
- GL2 gl = GLUgl2.getCurrentGL2();
+ GL gl = GLContext.getCurrentGL();
+
if (!gl.isExtensionAvailable(GLExtensions.EXT_abgr)) {
throw new IllegalArgumentException("Saving alpha channel requires GL_EXT_abgr");
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
index 0b0af5625..14ceb6421 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
@@ -1408,7 +1408,7 @@ public class TextureIO {
buf.rewind();
PNGImage image = PNGImage.createFromData(data.getWidth(), data.getHeight(), -1f, -1f,
- bytesPerPixel, reversedChannels, buf);
+ bytesPerPixel, reversedChannels, !data.getMustFlipVertically(), buf);
image.write(file, true);
return true;
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java
index 847451b41..b4b00e744 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java
@@ -53,20 +53,39 @@ import com.jogamp.common.util.IOUtil;
public class PNGImage {
private static final boolean DEBUG = Debug.debug("PNGImage");
- /** Creates a PNGImage from data supplied by the end user. Shares
- data with the passed ByteBuffer. Assumes the data is already in
- the correct byte order for writing to disk, i.e., LUMINANCE, RGB or RGBA bottom-to-top (OpenGL coord). */
+ /**
+ * Creates a PNGImage from data supplied by the end user. Shares
+ * data with the passed ByteBuffer. Assumes the data is already in
+ * the correct byte order for writing to disk, i.e., LUMINANCE, RGB or RGBA.
+ * Orientation is <i>bottom-to-top</i> (OpenGL coord. default)
+ * or <i>top-to-bottom</i> depending on <code>isGLOriented</code>.
+ *
+ * @param width
+ * @param height
+ * @param dpiX
+ * @param dpiY
+ * @param bytesPerPixel
+ * @param reversedChannels
+ * @param isGLOriented see {@link #isGLOriented()}.
+ * @param data
+ * @return
+ */
public static PNGImage createFromData(int width, int height, double dpiX, double dpiY,
- int bytesPerPixel, boolean reversedChannels, ByteBuffer data) {
- return new PNGImage(width, height, dpiX, dpiY, bytesPerPixel, reversedChannels, data);
+ int bytesPerPixel, boolean reversedChannels, boolean isGLOriented, ByteBuffer data) {
+ return new PNGImage(width, height, dpiX, dpiY, bytesPerPixel, reversedChannels, isGLOriented, data);
}
- /** Reads a PNG image from the specified InputStream. */
+ /**
+ * Reads a PNG image from the specified InputStream.
+ * <p>
+ * Implicitly flip image to GL orientation, see {@link #isGLOriented()}.
+ * </p>
+ */
public static PNGImage read(InputStream in) throws IOException {
return new PNGImage(in);
}
- /** Reverse read and store, implicitly flip image to GL coords. */
+ /** Reverse read and store, implicitly flip image to GL orientation, see {@link #isGLOriented()}. */
private static final int getPixelRGBA8(ByteBuffer d, int dOff, int[] scanline, int lineOff, boolean hasAlpha) {
if(hasAlpha) {
d.put(dOff--, (byte)scanline[lineOff + 3]); // A
@@ -76,27 +95,28 @@ public class PNGImage {
d.put(dOff--, (byte)scanline[lineOff ]); // R
return dOff;
}
- /** Reverse read and store, implicitly flip image from GL coords. Handle reversed channels (BGR[A])*/
- private static int setPixelRGBA8(ImageLine line, int lineOff, ByteBuffer d, int dOff, boolean hasAlpha, boolean reversedChannels) {
- if(reversedChannels) {
- line.scanline[lineOff ] = d.get(dOff--); // R, A
- line.scanline[lineOff + 1] = d.get(dOff--); // G, B
- line.scanline[lineOff + 2] = d.get(dOff--); // B, G
+
+ /** Reverse write and store, implicitly flip image from current orientation, see {@link #isGLOriented()}. Handle reversed channels (BGR[A]). */
+ private int setPixelRGBA8(ImageLine line, int lineOff, ByteBuffer d, int dOff, boolean hasAlpha) {
+ if( reversedChannels ) {
if(hasAlpha) {
- line.scanline[lineOff + 3] = d.get(dOff--);// R
+ line.scanline[lineOff + 3] = d.get(dOff++); // A
}
+ line.scanline[lineOff + 2] = d.get(dOff++); // R
+ line.scanline[lineOff + 1] = d.get(dOff++); // G
+ line.scanline[lineOff ] = d.get(dOff++); // B
} else {
+ line.scanline[lineOff ] = d.get(dOff++); // R
+ line.scanline[lineOff + 1] = d.get(dOff++); // G
+ line.scanline[lineOff + 2] = d.get(dOff++); // B
if(hasAlpha) {
- line.scanline[lineOff + 3] = d.get(dOff--); // A
+ line.scanline[lineOff + 3] = d.get(dOff++); // A
}
- line.scanline[lineOff + 2] = d.get(dOff--); // B
- line.scanline[lineOff + 1] = d.get(dOff--); // G
- line.scanline[lineOff ] = d.get(dOff--); // R
}
- return dOff;
+ return isGLOriented ? dOff - bytesPerPixel - bytesPerPixel : dOff;
}
- private PNGImage(int width, int height, double dpiX, double dpiY, int bytesPerPixel, boolean reversedChannels, ByteBuffer data) {
+ private PNGImage(int width, int height, double dpiX, double dpiY, int bytesPerPixel, boolean reversedChannels, boolean isGLOriented, ByteBuffer data) {
pixelWidth=width;
pixelHeight=height;
dpi = new double[] { dpiX, dpiY };
@@ -109,6 +129,7 @@ public class PNGImage {
}
this.bytesPerPixel = bytesPerPixel;
this.reversedChannels = reversedChannels;
+ this.isGLOriented = isGLOriented;
this.data = data;
}
@@ -162,13 +183,14 @@ public class PNGImage {
data = Buffers.newDirectByteBuffer(bytesPerPixel * pixelWidth * pixelHeight);
reversedChannels = false; // RGB[A]
+ isGLOriented = true;
int dataOff = bytesPerPixel * pixelWidth * pixelHeight - 1; // start at end-of-buffer, reverse store
int[] rgbaScanline = indexed ? new int[imgInfo.cols * channels] : null;
for (int row = 0; row < pixelHeight; row++) {
final ImageLine l1 = pngr.readRow(row);
- int lineOff = ( pixelWidth - 1 ) * bytesPerPixel ; // start w/ last pixel in line, reverse read
+ int lineOff = ( pixelWidth - 1 ) * bytesPerPixel ; // start w/ last pixel in line, reverse read (PNG top-left -> OpenGL bottom-left origin)
if( indexed ) {
for (int j = pixelWidth - 1; j >= 0; j--) {
rgbaScanline = ImageLineHelper.palette2rgb(l1, plte, trns, rgbaScanline); // reuse rgbaScanline and update if resized
@@ -189,7 +211,8 @@ public class PNGImage {
pngr.end();
}
private final int pixelWidth, pixelHeight, glFormat, bytesPerPixel;
- private boolean reversedChannels;
+ private final boolean reversedChannels;
+ private final boolean isGLOriented;
private final double[] dpi;
private final ByteBuffer data;
@@ -202,6 +225,16 @@ public class PNGImage {
/** Returns true if data has the channels reversed to BGR or BGRA, otherwise RGB or RGBA is expected. */
public boolean getHasReversedChannels() { return reversedChannels; }
+ /**
+ * Returns <code>true</code> if the drawable is rendered in
+ * OpenGL's coordinate system, <i>origin at bottom left</i>.
+ * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>.
+ * <p>
+ * Default impl. is <code>true</code>, i.e. OpenGL coordinate system.
+ * </p>
+ */
+ public boolean isGLOriented() { return isGLOriented; }
+
/** Returns the dpi of the image. */
public double[] getDpi() { return dpi; }
@@ -231,20 +264,40 @@ public class PNGImage {
// png.getMetadata().setText("my key", "my text");
final boolean hasAlpha = 4 == bytesPerPixel;
final ImageLine l1 = new ImageLine(imi);
- int dataOff = bytesPerPixel * pixelWidth * pixelHeight - 1; // start at end-of-buffer, reverse read
- for (int row = 0; row < pixelHeight; row++) {
- int lineOff = ( pixelWidth - 1 ) * bytesPerPixel ; // start w/ last pixel in line, reverse store
- if(1 == bytesPerPixel) {
- for (int j = pixelWidth - 1; j >= 0; j--) {
- l1.scanline[lineOff--] = data.get(dataOff--); // // Luminance, 1 bytesPerPixel
- }
- } else {
- for (int j = pixelWidth - 1; j >= 0; j--) {
- dataOff = setPixelRGBA8(l1, lineOff, data, dataOff, hasAlpha, reversedChannels);
- lineOff -= bytesPerPixel;
+ if( isGLOriented ) {
+ // start at last pixel at end-of-buffer, reverse read (OpenGL bottom-left -> PNG top-left origin)
+ int dataOff = ( pixelWidth * bytesPerPixel * ( pixelHeight - 1 ) ) + // full lines - 1 line
+ ( ( pixelWidth - 1 ) * bytesPerPixel ); // one line - 1 pixel
+ for (int row = 0; row < pixelHeight; row++) {
+ int lineOff = ( pixelWidth - 1 ) * bytesPerPixel ; // start w/ last pixel in line, reverse store (OpenGL bottom-left -> PNG top-left origin)
+ if(1 == bytesPerPixel) {
+ for (int j = pixelWidth - 1; j >= 0; j--) {
+ l1.scanline[lineOff--] = data.get(dataOff--); // // Luminance, 1 bytesPerPixel
+ }
+ } else {
+ for (int j = pixelWidth - 1; j >= 0; j--) {
+ dataOff = setPixelRGBA8(l1, lineOff, data, dataOff, hasAlpha);
+ lineOff -= bytesPerPixel;
+ }
}
+ png.writeRow(l1, row);
}
- png.writeRow(l1, row);
+ } else {
+ int dataOff = 0; // start at first pixel at start-of-buffer, normal read (same origin: top-left)
+ for (int row = 0; row < pixelHeight; row++) {
+ int lineOff = 0; // start w/ first pixel in line, normal store (same origin: top-left)
+ if(1 == bytesPerPixel) {
+ for (int j = pixelWidth - 1; j >= 0; j--) {
+ l1.scanline[lineOff++] = data.get(dataOff++); // // Luminance, 1 bytesPerPixel
+ }
+ } else {
+ for (int j = pixelWidth - 1; j >= 0; j--) {
+ dataOff = setPixelRGBA8(l1, lineOff, data, dataOff, hasAlpha);
+ lineOff += bytesPerPixel;
+ }
+ }
+ png.writeRow(l1, row);
+ }
}
png.end();
} finally {