aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java489
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java26
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java12
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java6
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java6
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java195
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java8
7 files changed, 518 insertions, 224 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java
index a09321d75..00bbd6ce7 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java
@@ -58,41 +58,100 @@ public class GLPixelBuffer {
/** Allow {@link GL2ES3#GL_PACK_ROW_LENGTH}, or {@link GL2ES2#GL_UNPACK_ROW_LENGTH}. */
boolean getAllowRowStride();
- /** Called first to determine {@link GLPixelAttributes}. */
- GLPixelAttributes getAttributes(GL gl, int componentCount);
+ /**
+ * Returns RGB[A] {@link GLPixelAttributes} matching {@link GL}, {@code componentCount} and {@code pack}.
+ *
+ * @param gl the corresponding current {@link GL} context object
+ * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA)
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
+ */
+ GLPixelAttributes getAttributes(GL gl, int componentCount, boolean pack);
+
+ /**
+ * Returns the host {@link PixelFormat.Composition} matching {@link GL} and {@code componentCount}
+ * if required by implementation, otherwise {@code null}.
+ *
+ * @param glp the corresponding current {@link GL} context object
+ * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA)
+ */
+ PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount);
/**
* Allocates a new {@link GLPixelBuffer} object.
* <p>
- * Being called to gather the initial {@link GLPixelBuffer},
- * or a new replacement {@link GLPixelBuffer} if {@link GLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
- * </p>
- * <p>
* The minimum required {@link Buffer#remaining() remaining} byte size equals to <code>minByteSize</code>, if &gt; 0,
* otherwise utilize {@link GLBuffers#sizeof(GL, int[], int, int, int, int, int, boolean)}
* to calculate it.
* </p>
*
- * @param gl the corresponding current GL context object
- * @param pixelAttributes the desired {@link GLPixelAttributes}
+ * @param gl the corresponding current {@link GL} context object
+ * @param hostPixComp host {@link PixelFormat pixel format}, i.e. of the source or sink depending on {@code pack},
+ * e.g. fetched via {@link #getHostPixelComp(GLProfile, int)}.
+ * If {@code null}, {@code pixelAttributes} instance maybe used or an exception is thrown,
+ * depending on implementation semantics.
+ * @param pixelAttributes the desired {@link GLPixelAttributes}, e.g. fetched via {@link #getAttributes(GL, int, boolean)}
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
* @param width in pixels
* @param height in pixels
* @param depth in pixels
- * @param pack true for read mode GPU -> CPU, otherwise false for write mode CPU -> GPU
* @param minByteSize if &gt; 0, the pre-calculated minimum byte-size for the resulting buffer, otherwise ignore.
+ * @see #getHostPixelComp(GLProfile, int)
+ * @see #getAttributes(GL, int, boolean)
*/
- GLPixelBuffer allocate(GL gl, GLPixelAttributes pixelAttributes, int width, int height, int depth, boolean pack, int minByteSize);
+ GLPixelBuffer allocate(GL gl, PixelFormat.Composition hostPixComp, GLPixelAttributes pixelAttributes,
+ boolean pack, int width, int height, int depth, int minByteSize);
}
/** Single {@link GLPixelBuffer} provider. */
public static interface SingletonGLPixelBufferProvider extends GLPixelBufferProvider {
- /** Return the last {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated} {@link GLPixelBuffer} w/ {@link GLPixelAttributes#componentCount}. */
- GLPixelBuffer getSingleBuffer(GLPixelAttributes pixelAttributes);
/**
- * Initializes the single {@link GLPixelBuffer} w/ a given size, if not yet {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated}.
+ * {@inheritDoc}
+ * <p>
+ * Being called to gather the initial {@link GLPixelBuffer},
+ * or a new replacement {@link GLPixelBuffer} if {@link GLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
+ * </p>
+ */
+ @Override
+ GLPixelBuffer allocate(GL gl, PixelFormat.Composition hostPixComp, GLPixelAttributes pixelAttributes,
+ boolean pack, int width, int height, int depth, int minByteSize);
+
+ /**
+ * Return the last {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated} {@link GLPixelBuffer}
+ * matching the given parameter.
+ * <p>
+ * May return {@code null} if none has been allocated yet.
+ * </p>
+ * <p>
+ * Returned {@link GLPixelBuffer} may be {@link GLPixelBuffer#isValid() invalid}.
+ * </p>
+ * @param hostPixComp host {@link PixelFormat pixel format}, i.e. of the source or sink depending on {@code pack},
+ * e.g. fetched via {@link #getHostPixelComp(GLProfile, int)}.
+ * If {@code null}, {@code pixelAttributes} instance maybe used or an exception is thrown,
+ * depending on implementation semantics.
+ * @param pixelAttributes the desired {@link GLPixelAttributes}, e.g. fetched via {@link #getAttributes(GL, int, boolean)}
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
+ */
+ GLPixelBuffer getSingleBuffer(PixelFormat.Composition hostPixelComp, GLPixelAttributes pixelAttributes, boolean pack);
+ /**
+ * Initializes the single {@link GLPixelBuffer} w/ a given size,
+ * if not yet {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated}.
+ *
+ * @param glp
+ * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA)
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
+ * @param width
+ * @param height
+ * @param depth
* @return the newly initialized single {@link GLPixelBuffer}, or null if already allocated.
*/
- GLPixelBuffer initSingleton(int componentCount, int width, int height, int depth, boolean pack);
+ GLPixelBuffer initSingleton(GLProfile glp, int componentCount, boolean pack, int width, int height, int depth);
+
+ /** Dispose all resources.*/
+ void dispose();
}
public static class DefaultGLPixelBufferProvider implements GLPixelBufferProvider {
@@ -110,36 +169,24 @@ public class GLPixelBuffer {
public boolean getAllowRowStride() { return allowRowStride; }
@Override
- public GLPixelAttributes getAttributes(final GL gl, final int componentCount) {
- final GLContext ctx = gl.getContext();
- final int dFormat, dType;
-
- if( 1 == componentCount ) {
- if( gl.isGL3ES3() ) {
- // RED is supported on ES3 and >= GL3 [core]; ALPHA is deprecated on core
- dFormat = GL2ES2.GL_RED;
- } else {
- // ALPHA is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility
- dFormat = GL.GL_ALPHA;
- }
- dType = GL.GL_UNSIGNED_BYTE;
- } else if( 3 == componentCount ) {
- dFormat = GL.GL_RGB;
- dType = GL.GL_UNSIGNED_BYTE;
- } else if( 4 == componentCount ) {
- final int _dFormat = ctx.getDefaultPixelDataFormat();
- final int dComps = GLBuffers.componentCount(_dFormat);
- if( dComps == componentCount ) {
- dFormat = _dFormat;
- dType = ctx.getDefaultPixelDataType();
- } else {
- dFormat = GL.GL_RGBA;
- dType = GL.GL_UNSIGNED_BYTE;
- }
- } else {
+ public GLPixelAttributes getAttributes(final GL gl, final int componentCount, final boolean pack) {
+ final GLPixelAttributes res = GLPixelAttributes.convert(gl, componentCount, pack);
+ if( null == res ) {
throw new GLException("Unsupported componentCount "+componentCount+", contact maintainer to enhance");
+ } else {
+ return res;
}
- return new GLPixelAttributes(componentCount, dFormat, dType);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns {@code null}!
+ * </p>
+ */
+ @Override
+ public PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount) {
+ return null;
}
/**
@@ -149,13 +196,15 @@ public class GLPixelBuffer {
* </p>
*/
@Override
- public GLPixelBuffer allocate(final GL gl, final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) {
+ public GLPixelBuffer allocate(final GL gl, final PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes,
+ final boolean pack, final int width, final int height, final int depth, final int minByteSize) {
+ // unused: hostPixComp
if( minByteSize > 0 ) {
- return new GLPixelBuffer(pixelAttributes, width, height, depth, pack, Buffers.newDirectByteBuffer(minByteSize), getAllowRowStride());
+ return new GLPixelBuffer(pixelAttributes, pack, width, height, depth, Buffers.newDirectByteBuffer(minByteSize), getAllowRowStride());
} else {
final int[] tmp = { 0 };
- final int byteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.bytesPerPixel, width, height, depth, pack);
- return new GLPixelBuffer(pixelAttributes, width, height, depth, pack, Buffers.newDirectByteBuffer(byteSize), getAllowRowStride());
+ final int byteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.pfmt.comp.bytesPerPixel(), width, height, depth, pack);
+ return new GLPixelBuffer(pixelAttributes, pack, width, height, depth, Buffers.newDirectByteBuffer(byteSize), getAllowRowStride());
}
}
}
@@ -163,74 +212,190 @@ public class GLPixelBuffer {
/**
* Default {@link GLPixelBufferProvider} with {@link GLPixelBufferProvider#getAllowRowStride()} == <code>false</code>,
* utilizing best match for {@link GLPixelAttributes}
- * and {@link GLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocating} a {@link ByteBuffer}.
+ * and {@link GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocating} a {@link ByteBuffer}.
*/
public static final GLPixelBufferProvider defaultProviderNoRowStride = new DefaultGLPixelBufferProvider(false);
/**
* Default {@link GLPixelBufferProvider} with {@link GLPixelBufferProvider#getAllowRowStride()} == <code>true</code>,
* utilizing best match for {@link GLPixelAttributes}
- * and {@link GLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocating} a {@link ByteBuffer}.
+ * and {@link GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocating} a {@link ByteBuffer}.
*/
public static final GLPixelBufferProvider defaultProviderWithRowStride = new DefaultGLPixelBufferProvider(true);
/** Pixel attributes. */
public static class GLPixelAttributes {
/** Undefined instance of {@link GLPixelAttributes}, having componentCount:=0, format:=0 and type:= 0. */
- public static final GLPixelAttributes UNDEF = new GLPixelAttributes(0, 0, 0, false);
-
- /** Pixel <i>source</i> component count, i.e. number of meaningful components. */
- public final int componentCount;
- /** The OpenGL pixel data format */
- public final int format;
- /** The OpenGL pixel data type */
- public final int type;
- /** The OpenGL pixel size in bytes */
- public final int bytesPerPixel;
+ public static final GLPixelAttributes UNDEF = new GLPixelAttributes(null, PixelFormat.LUMINANCE, 0, 0, true, false);
/**
- * Deriving {@link #componentCount} via GL <code>dataFormat</code>, i.e. {@link GLBuffers#componentCount(int)} if &gt; 0.
- * @param dataFormat GL data format
- * @param dataType GL data type
+ * Returns the matching {@link PixelFormat} for the given GL format and type if exists,
+ * otherwise returns <code>null</code>.
*/
- public GLPixelAttributes(final int dataFormat, final int dataType) {
- this(0 < dataFormat ? GLBuffers.componentCount(dataFormat) : 0, dataFormat, dataType);
+ public static final PixelFormat getPixelFormat(final int glFormat, final int glDataType) {
+ PixelFormat pixFmt = null;
+
+ switch(glFormat) {
+ case GL.GL_ALPHA:
+ case GL.GL_LUMINANCE:
+ case GL2ES2.GL_RED:
+ pixFmt = PixelFormat.LUMINANCE;
+ break;
+ case GL.GL_RGB:
+ switch(glDataType) {
+ case GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV:
+ pixFmt = PixelFormat.RGB565;
+ break;
+ case GL.GL_UNSIGNED_SHORT_5_6_5:
+ pixFmt = PixelFormat.BGR565;
+ break;
+ case GL.GL_UNSIGNED_BYTE:
+ pixFmt = PixelFormat.RGB888;
+ break;
+ }
+ break;
+ case GL.GL_RGBA:
+ switch(glDataType) {
+ case GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV:
+ pixFmt = PixelFormat.RGBA5551;
+ break;
+ case GL.GL_UNSIGNED_SHORT_5_5_5_1:
+ pixFmt = PixelFormat.ABGR1555;
+ break;
+ case GL.GL_UNSIGNED_BYTE:
+ pixFmt = PixelFormat.RGBA8888;
+ break;
+ case GL2GL3.GL_UNSIGNED_INT_8_8_8_8:
+ pixFmt = PixelFormat.ABGR8888;
+ break;
+ }
+ break;
+ case GL2GL3.GL_BGR:
+ if( GL.GL_UNSIGNED_BYTE == glDataType ) {
+ pixFmt = PixelFormat.BGR888;
+ }
+ break;
+ case GL.GL_BGRA:
+ switch(glDataType) {
+ case GL2GL3.GL_UNSIGNED_INT_8_8_8_8:
+ pixFmt = PixelFormat.ARGB8888;
+ break;
+ case GL.GL_UNSIGNED_BYTE:
+ pixFmt = PixelFormat.BGRA8888;
+ break;
+ }
+ break;
+ }
+ return pixFmt;
}
+
/**
- * Using user specified source {@link #componentCount}.
- * @param componentCount source component count
- * @param dataFormat GL data format
- * @param dataType GL data type
+ * Returns the matching {@link GLPixelAttributes} for the given byte sized RGBA {@code componentCount} and {@link GL} if exists,
+ * otherwise returns {@code null}.
+ *
+ * @param gl the corresponding current {@link GL} context object
+ * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA)
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
*/
- public GLPixelAttributes(final int componentCount, final int dataFormat, final int dataType) {
- this(componentCount, dataFormat, dataType, true);
+ public static GLPixelAttributes convert(final GL gl, final int componentCount, final boolean pack) {
+ final int dFormat, dType;
+ final boolean glesReadMode = pack && gl.isGLES();
+
+ if( 1 == componentCount && !glesReadMode ) {
+ if( gl.isGL3ES3() ) {
+ // RED is supported on ES3 and >= GL3 [core]; ALPHA is deprecated on core
+ dFormat = GL2ES2.GL_RED;
+ } else {
+ // ALPHA is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility
+ dFormat = GL.GL_ALPHA;
+ }
+ dType = GL.GL_UNSIGNED_BYTE;
+ } else if( 3 == componentCount && !glesReadMode ) {
+ dFormat = GL.GL_RGB;
+ dType = GL.GL_UNSIGNED_BYTE;
+ } else if( 4 == componentCount || glesReadMode ) {
+ final GLContext ctx = gl.getContext();
+ final int _dFormat = ctx.getDefaultPixelDataFormat();
+ final int dComps = GLBuffers.componentCount(_dFormat);
+ if( dComps == componentCount || 4 == dComps ) { // accept if desired component count or 4 components
+ dFormat = _dFormat;
+ dType = ctx.getDefaultPixelDataType();
+ } else {
+ dFormat = GL.GL_RGBA;
+ dType = GL.GL_UNSIGNED_BYTE;
+ }
+ } else {
+ return null;
+ }
+ return new GLPixelAttributes(dFormat, dType);
}
/**
- * Returns the matching {@link GLPixelAttributes} for the given {@link PixelFormat} and {@link GLProfile} if exists,
- * otherwise returns <code>null</code>.
+ * Returns the matching {@link GLPixelAttributes} for the given {@link GLProfile}, {@link PixelFormat} and {@code pack} if exists,
+ * otherwise returns {@code null}.
+ * @param glp the corresponding {@link GLProfile}
+ * @param pixFmt the to be matched {@link PixelFormat pixel format}
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
*/
- public static final GLPixelAttributes convert(final PixelFormat pixFmt, final GLProfile glp) {
+ public static final GLPixelAttributes convert(final GLProfile glp, final PixelFormat pixFmt, final boolean pack) {
+ final int[] df = new int[1];
+ final int[] dt = new int[1];
+ convert(glp, pixFmt, pack, df, dt);
+ if( 0 != df[0] ) {
+ return new GLPixelAttributes(null, pixFmt, df[0], dt[0], true /* not used */, true);
+ }
+ return null;
+ }
+ private static final int convert(final GLProfile glp, final PixelFormat pixFmt, final boolean pack,
+ final int[] dfRes, final int[] dtRes) {
+ final boolean glesReadMode = pack && glp.isGLES();
int df = 0; // format
int dt = GL.GL_UNSIGNED_BYTE; // data type
switch(pixFmt) {
case LUMINANCE:
- if( glp.isGL3ES3() ) {
- // RED is supported on ES3 and >= GL3 [core]; ALPHA/LUMINANCE is deprecated on core
- df = GL2ES2.GL_RED;
- } else {
- // ALPHA/LUMINANCE is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility
- df = GL.GL_LUMINANCE;
+ if( !glesReadMode ) {
+ if( glp.isGL3ES3() ) {
+ // RED is supported on ES3 and >= GL3 [core]; ALPHA/LUMINANCE is deprecated on core
+ df = GL2ES2.GL_RED;
+ } else {
+ // ALPHA/LUMINANCE is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility
+ df = GL.GL_LUMINANCE;
+ }
}
break;
- case BGR888:
+ case RGB565:
if( glp.isGL2GL3() ) {
- df = GL2GL3.GL_BGR;
+ df = GL.GL_RGB; dt = GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV;
+ }
+ break;
+ case BGR565:
+ if( glp.isGL2GL3() ) {
+ df = GL.GL_RGB; dt = GL.GL_UNSIGNED_SHORT_5_6_5;
+ }
+ break;
+ case RGBA5551:
+ if( glp.isGL2GL3() ) {
+ df = GL.GL_RGBA; dt = GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ }
+ break;
+ case ABGR1555:
+ if( glp.isGL2GL3() ) {
+ df = GL.GL_RGBA; dt = GL.GL_UNSIGNED_SHORT_5_5_5_1;
}
break;
case RGB888:
- df = GL.GL_RGB;
+ if( !glesReadMode ) {
+ df = GL.GL_RGB;
+ }
+ break;
+ case BGR888:
+ if( glp.isGL2GL3() ) {
+ df = GL2GL3.GL_BGR;
+ }
break;
+ case RGBx8888:
case RGBA8888:
df = GL.GL_RGBA;
break;
@@ -239,85 +404,107 @@ public class GLPixelBuffer {
df = GL.GL_RGBA; dt = GL2GL3.GL_UNSIGNED_INT_8_8_8_8;
}
break;
- case BGRA8888:
- df = GL.GL_BGRA;
- break;
case ARGB8888:
if( glp.isGL2GL3() ) {
df = GL.GL_BGRA; dt = GL2GL3.GL_UNSIGNED_INT_8_8_8_8;
}
break;
- default:
+ case BGRx8888:
+ case BGRA8888:
+ if( glp.isGL2GL3() ) { // FIXME: or if( !glesReadMode ) ? BGRA n/a on GLES
+ df = GL.GL_BGRA;
+ }
break;
}
- if( 0 != df ) {
- return new GLPixelAttributes(pixFmt.componentCount, df, dt, true);
- }
- return null;
+ dfRes[0] = df;
+ dtRes[0] = dt;
+ return df;
}
- private GLPixelAttributes(final int componentCount, final int dataFormat, final int dataType, final boolean checkArgs) {
- this.componentCount = componentCount;
- this.format = dataFormat;
- this.type = dataType;
- this.bytesPerPixel = ( 0 < dataFormat && 0 < dataType ) ? GLBuffers.bytesPerPixel(dataFormat, dataType) : 0;
- if( checkArgs ) {
- if( 0 == componentCount || 0 == format || 0 == type ) {
- throw new GLException("Zero components, format and/or type: "+this);
- }
- if( 0 == bytesPerPixel ) {
- throw new GLException("Zero bytesPerPixel: "+this);
- }
+
+ /** The OpenGL pixel data format */
+ public final int format;
+ /** The OpenGL pixel data type */
+ public final int type;
+
+ /** {@link PixelFormat} describing the {@link PixelFormat.Composition component} layout */
+ public final PixelFormat pfmt;
+
+ @Override
+ public final int hashCode() {
+ // 31 * x == (x << 5) - x
+ int hash = pfmt.hashCode();
+ hash = ((hash << 5) - hash) + format;
+ return ((hash << 5) - hash) + type;
+ }
+
+ @Override
+ public final boolean equals(final Object obj) {
+ if(this == obj) { return true; }
+ if( obj instanceof GLPixelAttributes ) {
+ final GLPixelAttributes other = (GLPixelAttributes) obj;
+ return format == other.format &&
+ type == other.type &&
+ pfmt.equals(other.pfmt);
+ } else {
+ return false;
}
}
/**
- * Returns the matching {@link PixelFormat} of this {@link GLPixelAttributes} if exists,
- * otherwise returns <code>null</code>.
+ * Create a new {@link GLPixelAttributes} instance based on GL format and type.
+ * @param dataFormat GL data format
+ * @param dataType GL data type
+ * @throws GLException if {@link PixelFormat} could not be determined, see {@link #getPixelFormat(int, int)}.
*/
- public final PixelFormat getPixelFormat() {
- final PixelFormat pixFmt;
- // FIXME: Take 'type' into consideration and complete mapping!
- switch(format) {
- case GL.GL_ALPHA:
- case GL.GL_LUMINANCE:
- case GL2ES2.GL_RED:
- pixFmt = PixelFormat.LUMINANCE;
- break;
- case GL.GL_RGB:
- pixFmt = PixelFormat.RGB888;
- break;
- case GL.GL_RGBA:
- pixFmt = PixelFormat.RGBA8888;
- break;
- case GL2GL3.GL_BGR:
- pixFmt = PixelFormat.BGR888;
- break;
- case GL.GL_BGRA:
- pixFmt = PixelFormat.BGRA8888;
- break;
- default:
- switch( bytesPerPixel ) {
- case 1:
- pixFmt = PixelFormat.LUMINANCE;
- break;
- case 3:
- pixFmt = PixelFormat.RGB888;
- break;
- case 4:
- pixFmt = PixelFormat.RGBA8888;
- break;
- default:
- pixFmt = null;
- break;
- }
- break;
+ public GLPixelAttributes(final int dataFormat, final int dataType) throws GLException {
+ this(null, null, dataFormat, dataType, true /* not used */, true);
+ }
+
+ /**
+ * Create a new {@link GLPixelAttributes} instance based on {@link GLProfile}, {@link PixelFormat} and {@code pack}.
+ * @param glp the corresponding {@link GLProfile}
+ * @param pixFmt the to be matched {@link PixelFormat pixel format}
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
+ * @throws GLException if GL format or type could not be determined, see {@link #convert(GLProfile, PixelFormat, boolean)}.
+ */
+ public GLPixelAttributes(final GLProfile glp, final PixelFormat pixFmt, final boolean pack) throws GLException {
+ this(glp, pixFmt, 0, 0, pack, true);
+ }
+
+ private GLPixelAttributes(final GLProfile glp, final PixelFormat pixFmt,
+ final int dataFormat, final int dataType, final boolean pack, final boolean checkArgs) throws GLException {
+ if( checkArgs && ( 0 == dataFormat || 0 == dataType ) ) {
+ if( null == pixFmt || null == glp ) {
+ throw new GLException("Zero format and/or type w/o pixFmt or glp: "+this);
+ }
+ final int[] df = new int[1];
+ final int[] dt = new int[1];
+ if( 0 == convert(glp, pixFmt, pack, df, dt) ) {
+ throw new GLException("Could not find format and type for "+pixFmt+" and "+glp+", "+this);
+ }
+ this.format = df[0];
+ this.type = dt[0];
+ this.pfmt = pixFmt;
+ } else {
+ this.format = dataFormat;
+ this.type = dataType;
+ this.pfmt = null != pixFmt ? pixFmt : getPixelFormat(dataFormat, dataType);
+ if( null == this.pfmt ) {
+ throw new GLException("Could not find PixelFormat for format and/or type: "+this);
+ }
+ }
+ if( checkArgs ) {
+ final int bytesPerPixel = GLBuffers.bytesPerPixel(this.format, this.type);
+ if( 0 == bytesPerPixel ) {
+ throw new GLException("Zero bytesPerPixel: "+this);
+ }
}
- return pixFmt;
}
@Override
public String toString() {
- return "PixelAttributes[comp "+componentCount+", fmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+", bytesPerPixel "+bytesPerPixel+"]";
+ return "PixelAttributes[fmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+", "+pfmt+"]";
}
}
@@ -339,14 +526,18 @@ public class GLPixelBuffer {
public final int height;
/** Depth in pixels. */
public final int depth;
- /** Data packing direction. If <code>true</code> for read mode GPU -> CPU, <code>false</code> for write mode CPU -> GPU. */
+ /**
+ * Data packing direction.
+ * <p>{@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.</p>
+ * <p>{@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.</p>
+ */
public final boolean pack;
/** Byte size of the buffer. Actually the number of {@link Buffer#remaining()} bytes when passed in ctor. */
public final int byteSize;
/**
* Buffer holding the pixel data. If {@link #rewind()}, it holds <code>byteSize</code> {@link Buffer#remaining()} bytes.
* <p>
- * By default the {@link Buffer} is a {@link ByteBuffer}, due to {@link DefProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int)}.
+ * By default the {@link Buffer} is a {@link ByteBuffer}, due to {@link DefProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int)}.
* However, other {@link GLPixelBufferProvider} may utilize different {@link Buffer} types.
* </p>
*/
@@ -375,14 +566,16 @@ public class GLPixelBuffer {
/**
* @param pixelAttributes the desired {@link GLPixelAttributes}
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
* @param width in pixels
* @param height in pixels
* @param depth in pixels
- * @param pack true for read mode GPU -> CPU, otherwise false for write mode CPU -> GPU
* @param buffer the backing array
* @param allowRowStride If <code>true</code>, allow row-stride, otherwise not. See {@link #requiresNewBuffer(GL, int, int, int)}.
+ * @param hostPixelComp the host {@link PixelFormat.Composition}
*/
- public GLPixelBuffer(final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final Buffer buffer, final boolean allowRowStride) {
+ public GLPixelBuffer(final GLPixelAttributes pixelAttributes, final boolean pack, final int width, final int height, final int depth, final Buffer buffer, final boolean allowRowStride) {
this.pixelAttributes = pixelAttributes;
this.width = width;
this.height = height;
@@ -462,7 +655,7 @@ public class GLPixelBuffer {
* @param newWidth new width in pixels
* @param newHeight new height in pixels
* @param newByteSize if &gt; 0, the pre-calculated minimum byte-size for the resulting buffer, otherwise ignore.
- * @see GLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int)
+ * @see GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int)
*/
public boolean requiresNewBuffer(final GL gl, final int newWidth, final int newHeight, int newByteSize) {
if( !isValid() ) {
@@ -470,7 +663,7 @@ public class GLPixelBuffer {
}
if( 0 >= newByteSize ) {
final int[] tmp = { 0 };
- newByteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.bytesPerPixel, newWidth, newHeight, 1, true);
+ newByteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.pfmt.comp.bytesPerPixel(), newWidth, newHeight, 1, true);
}
if( allowRowStride ) {
return byteSize < newByteSize;
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
index e84a1d874..597498c9d 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
@@ -31,6 +31,7 @@ package com.jogamp.opengl.util;
import java.io.File;
import java.io.IOException;
+import javax.media.nativewindow.util.PixelFormat;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES3;
import javax.media.opengl.GLAutoDrawable;
@@ -51,10 +52,10 @@ import com.jogamp.opengl.util.texture.TextureIO;
*/
public class GLReadBufferUtil {
protected final GLPixelBufferProvider pixelBufferProvider;
- protected final int componentCount, alignment;
protected final Texture readTexture;
protected final GLPixelStorageModes psm;
+ protected boolean hasAlpha;
protected GLPixelBuffer readPixelBuffer = null;
protected TextureData readTextureData = null;
@@ -68,10 +69,9 @@ public class GLReadBufferUtil {
public GLReadBufferUtil(final GLPixelBufferProvider pixelBufferProvider, final boolean alpha, final boolean write2Texture) {
this.pixelBufferProvider = pixelBufferProvider;
- this.componentCount = alpha ? 4 : 3 ;
- this.alignment = alpha ? 4 : 1 ;
this.readTexture = write2Texture ? new Texture(GL.GL_TEXTURE_2D) : null ;
this.psm = new GLPixelStorageModes();
+ this.hasAlpha = alpha; // preset
}
/** Returns the {@link GLPixelBufferProvider} used by this instance. */
@@ -81,7 +81,7 @@ public class GLReadBufferUtil {
return null!=readTextureData && null!=readPixelBuffer && readPixelBuffer.isValid();
}
- public boolean hasAlpha() { return 4 == componentCount ? true : false ; }
+ public boolean hasAlpha() { return hasAlpha; }
public GLPixelStorageModes getGLPixelStorageModes() { return psm; }
@@ -173,13 +173,13 @@ public class GLReadBufferUtil {
if(GL.GL_NO_ERROR != glerr0) {
System.err.println("Info: GLReadBufferUtil.readPixels: pre-exisiting GL error 0x"+Integer.toHexString(glerr0));
}
- final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, componentCount);
- final int internalFormat;
- if(gl.isGL2GL3() && 3 == componentCount) {
- internalFormat = GL.GL_RGB;
- } else {
- internalFormat = (4 == componentCount) ? GL.GL_RGBA : GL.GL_RGB;
- }
+ final int reqCompCount = hasAlpha ? 4 : 3;
+ final PixelFormat.Composition hostPixelComp = pixelBufferProvider.getHostPixelComp(gl.getGLProfile(), reqCompCount);
+ final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, reqCompCount, true);
+ final int componentCount = pixelAttribs.pfmt.comp.componenCount();
+ hasAlpha = 0 <= pixelAttribs.pfmt.comp.find(PixelFormat.CType.A);
+ final int alignment = 4 == componentCount ? 4 : 1 ;
+ final int internalFormat = 4 == componentCount ? GL.GL_RGBA : GL.GL_RGB;
final boolean flipVertically;
if( drawable.isGLOriented() ) {
@@ -189,11 +189,11 @@ public class GLReadBufferUtil {
}
final int tmp[] = new int[1];
- final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, width, height, 1, true);
+ final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), width, height, 1, true);
boolean newData = false;
if( null == readPixelBuffer || readPixelBuffer.requiresNewBuffer(gl, width, height, readPixelSize) ) {
- readPixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, width, height, 1, true, readPixelSize);
+ readPixelBuffer = pixelBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, width, height, 1, readPixelSize);
Buffers.rangeCheckBytes(readPixelBuffer.buffer, readPixelSize);
try {
readTextureData = new TextureData(
diff --git a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java
index 64da547c2..29e1cf353 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java
@@ -137,7 +137,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
} else {
destFmt = ddestFmt; // user choice
}
- final int destStrideInBytes = Math.max(destMinStrideInBytes, destFmt.bytesPerPixel() * width);
+ final int destStrideInBytes = Math.max(destMinStrideInBytes, destFmt.comp.bytesPerPixel() * width);
final ByteBuffer destPixels = destDirectBuffer ? Buffers.newDirectByteBuffer(destStrideInBytes * height) :
ByteBuffer.allocate(destStrideInBytes * height);
{
@@ -153,7 +153,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
System.err.println("PNGPixelRect: indexed "+indexed+", alpha "+hasAlpha+", grayscale "+imgInfo.greyscale+", channels "+channels+"/"+imgInfo.channels+
", bytesPerPixel "+bytesPerPixel+"/"+imgInfo.bytesPixel+
", grayAlpha "+isGrayAlpha+", pixels "+width+"x"+height+", dpi "+dpiX+"x"+dpiY+", format "+srcFmt);
- System.err.println("PNGPixelRect: destFormat "+destFmt+" ("+ddestFmt+", bytesPerPixel "+destFmt.bytesPerPixel()+", fast-path "+(destFmt==srcFmt)+"), destDirectBuffer "+destDirectBuffer+", destIsGLOriented (flip) "+destIsGLOriented);
+ System.err.println("PNGPixelRect: destFormat "+destFmt+" ("+ddestFmt+", fast-path "+(destFmt==srcFmt)+"), destDirectBuffer "+destDirectBuffer+", destIsGLOriented (flip) "+destIsGLOriented);
System.err.println("PNGPixelRect: destStrideInBytes "+destStrideInBytes+" (destMinStrideInBytes "+destMinStrideInBytes+")");
}
@@ -227,7 +227,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
(byte)scanline[lineOff+1], // G
(byte)scanline[lineOff+2], // B
srcHasAlpha ? (byte)scanline[lineOff+3] : (byte)0xff); // A
- final int dbpp = dest_fmt.bytesPerPixel();
+ final int dbpp = dest_fmt.comp.bytesPerPixel();
d.put(dOff++, (byte) ( p )); // 1
if( 1 < dbpp ) {
d.put(dOff++, (byte) ( p >>> 8 )); // 2
@@ -261,7 +261,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
if(hasAlpha) {
line.scanline[lineOff + 3] = 0xff & ( p >>> 24 ); // A
}
- return srcOff + pixelformat.bytesPerPixel();
+ return srcOff + pixelformat.comp.bytesPerPixel();
}
private static void setPixelRGBA8(final PixelFormat pixelformat, final ImageLine line, final int lineOff, final int srcPix, final int bytesPerPixel, final boolean hasAlpha) {
@@ -304,7 +304,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
public void write(final OutputStream outstream, final boolean closeOutstream) throws IOException {
final int width = size.getWidth();
final int height = size.getHeight();
- final int bytesPerPixel = pixelformat.bytesPerPixel();
+ final int bytesPerPixel = pixelformat.comp.bytesPerPixel();
final ImageInfo imi = new ImageInfo(width, height, 8 /* bitdepth */,
(4 == bytesPerPixel) ? true : false /* alpha */,
(1 == bytesPerPixel) ? true : false /* grayscale */,
@@ -349,7 +349,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
final OutputStream outstream, final boolean closeOutstream) throws IOException {
final int width = size.getWidth();
final int height = size.getHeight();
- final int bytesPerPixel = pixelformat.bytesPerPixel();
+ final int bytesPerPixel = pixelformat.comp.bytesPerPixel();
final ImageInfo imi = new ImageInfo(width, height, 8 /* bitdepth */,
(4 == bytesPerPixel) ? true : false /* alpha */,
(1 == bytesPerPixel) ? true : false /* grayscale */,
diff --git a/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java
index 3b65b0824..bf7cf668c 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java
@@ -176,7 +176,7 @@ public class RandomTileRenderer extends TileRendererBase {
final int srcY = 0;
final int srcWidth = currentTileWidth;
final int srcHeight = currentTileHeight;
- final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true);
+ final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true);
tileBuffer.clear();
if( tileBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) {
throw new IndexOutOfBoundsException("Required " + readPixelSize + " bytes of buffer, only had " + tileBuffer);
@@ -200,9 +200,9 @@ public class RandomTileRenderer extends TileRendererBase {
psm.setPackRowLength(gl2es3, rowLength);
/* read the tile into the final image */
- final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true);
+ final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true);
- final int ibPos = ( currentTileXPos + ( currentTileYPos * rowLength ) ) * pixelAttribs.bytesPerPixel; // skipPixels + skipRows
+ final int ibPos = ( currentTileXPos + ( currentTileYPos * rowLength ) ) * pixelAttribs.pfmt.comp.bytesPerPixel(); // skipPixels + skipRows
final int ibLim = ibPos + readPixelSize;
imageBuffer.clear();
if( imageBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) {
diff --git a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java
index d8410a102..fee2e5933 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java
@@ -479,7 +479,7 @@ public class TileRenderer extends TileRendererBase {
final int srcY = tileBorder;
final int srcWidth = tileSizeNB.getWidth();
final int srcHeight = tileSizeNB.getHeight();
- final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true);
+ final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true);
tileBuffer.clear();
if( tileBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) {
throw new IndexOutOfBoundsException("Required " + readPixelSize + " bytes of buffer, only had " + tileBuffer);
@@ -503,11 +503,11 @@ public class TileRenderer extends TileRendererBase {
psm.setPackRowLength(gl2es3, rowLength);
/* read the tile into the final image */
- final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true);
+ final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true);
final int skipPixels = currentColumn * tileSizeNB.getWidth();
final int skipRows = currentRow * tileSizeNB.getHeight();
- final int ibPos = ( skipPixels + ( skipRows * rowLength ) ) * pixelAttribs.bytesPerPixel;
+ final int ibPos = ( skipPixels + ( skipRows * rowLength ) ) * pixelAttribs.pfmt.comp.bytesPerPixel();
final int ibLim = ibPos + readPixelSize;
imageBuffer.clear();
if( imageBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) {
diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java
index 04bc0a15d..81cb34239 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java
@@ -36,10 +36,14 @@ import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.nio.Buffer;
import java.nio.IntBuffer;
+import java.util.Iterator;
+import javax.media.nativewindow.util.PixelFormat;
import javax.media.opengl.GL;
+import javax.media.opengl.GLProfile;
import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.IntObjectHashMap;
import com.jogamp.opengl.util.GLPixelBuffer;
/**
@@ -50,7 +54,7 @@ import com.jogamp.opengl.util.GLPixelBuffer;
* </p>
* <p>
* {@link AWTGLPixelBuffer} can be produced via {@link AWTGLPixelBufferProvider}'s
- * {@link AWTGLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocate(..)}.
+ * {@link AWTGLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocate(..)}.
* </p>
* <p>
* See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)} for {@link #allowRowStride} details.
@@ -61,30 +65,49 @@ import com.jogamp.opengl.util.GLPixelBuffer;
* </p>
*/
public class AWTGLPixelBuffer extends GLPixelBuffer {
- public static final GLPixelAttributes awtPixelAttributesIntRGBA4 = new GLPixelAttributes(4, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE);
- public static final GLPixelAttributes awtPixelAttributesIntRGB3 = new GLPixelAttributes(3, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE);
+ /**
+ * Ignoring componentCount, since otherwise no AWT/GL matching types are found.
+ * <p>
+ * Due to using RGBA and BGRA, pack/unpack usage has makes no difference.
+ * </p>
+ */
+ private static final GLPixelAttributes awtPixelAttributesIntBGRA = new GLPixelAttributes(GL.GL_BGRA, GL.GL_UNSIGNED_BYTE);
+ private static final GLPixelAttributes awtPixelAttributesIntRGBA = new GLPixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_BYTE);
/** The underlying {@link BufferedImage}. */
public final BufferedImage image;
+ private final PixelFormat.Composition hostPixelComp;
+ private final int awtFormat;
+
/**
- *
+ * @param hostPixelComp the host {@link PixelFormat.Composition}
* @param pixelAttributes the desired {@link GLPixelAttributes}
+ * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
+ * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
+ * @param awtFormat the used AWT format, i.e. {@link AWTGLPixelBufferProvider#getAWTFormat(GLProfile, int)}
* @param width in pixels
* @param height in pixels
* @param depth in pixels
- * @param pack true for read mode GPU -> CPU, otherwise false for write mode CPU -> GPU
* @param image the AWT image
* @param buffer the backing array
* @param allowRowStride If <code>true</code>, allow row-stride, otherwise not. See {@link #requiresNewBuffer(GL, int, int, int)}.
* If <code>true</code>, user shall decide whether to use a {@link #getAlignedImage(int, int) width-aligned image}.
*/
- public AWTGLPixelBuffer(final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final BufferedImage image,
- final Buffer buffer, final boolean allowRowStride) {
- super(pixelAttributes, width, height, depth, pack, buffer, allowRowStride);
+ public AWTGLPixelBuffer(final PixelFormat.Composition hostPixelComp,
+ final GLPixelAttributes pixelAttributes,
+ final boolean pack,
+ final int awtFormat, final int width, final int height, final int depth,
+ final BufferedImage image, final Buffer buffer, final boolean allowRowStride) {
+ super(pixelAttributes, pack, width, height, depth, buffer, allowRowStride);
this.image = image;
+ this.hostPixelComp = hostPixelComp;
+ this.awtFormat = awtFormat;
}
+ public final PixelFormat.Composition getHostPixelComp() { return hostPixelComp; }
+ public final int getAWTFormat() { return awtFormat; }
+
@Override
public void dispose() {
image.flush();
@@ -147,12 +170,57 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
public AWTGLPixelBufferProvider(final boolean allowRowStride) {
this.allowRowStride = allowRowStride;
}
+
@Override
public boolean getAllowRowStride() { return allowRowStride; }
@Override
- public GLPixelAttributes getAttributes(final GL gl, final int componentCount) {
- return 4 == componentCount ? awtPixelAttributesIntRGBA4 : awtPixelAttributesIntRGB3;
+ public GLPixelAttributes getAttributes(final GL gl, final int componentCount, final boolean pack) {
+ return gl.isGLES() ? awtPixelAttributesIntRGBA : awtPixelAttributesIntBGRA;
+ }
+
+ public GLPixelAttributes getAttributes(final GLProfile glp, final int componentCount) {
+ return glp.isGLES() ? awtPixelAttributesIntRGBA : awtPixelAttributesIntBGRA;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns a valid {@link PixelFormat.Composition} instance from {@link #getAWTPixelFormat(GLProfile, int)}.
+ * </p>
+ */
+ @Override
+ public PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount) {
+ return getAWTPixelFormat(glp, componentCount).comp;
+ }
+
+ /**
+ * Returns one of
+ * <ul>
+ * <li>GL__, 4c -> 4c: {@link BufferedImage#TYPE_INT_ARGB} <-> {@link GL#GL_BGRA}</li>
+ * <li>GLES, 4c -> 4c: {@link BufferedImage#TYPE_INT_BGR} <-> {@link GL#GL_RGBA}</li>
+ * <li>GL__, 3c -> 4c: {@link BufferedImage#TYPE_INT_RGB} <-> {@link GL#GL_BGRA}</li>
+ * <li>GLES, 3c -> 4c: {@link BufferedImage#TYPE_INT_BGR} <-> {@link GL#GL_RGBA}</li>
+ * </ul>
+ * @param glp
+ * @param componentCount
+ * @return
+ */
+ public int getAWTFormat(final GLProfile glp, final int componentCount) {
+ if( 4 == componentCount ) {
+ // FIXME: 4 component solution BufferedImage.TYPE_INT_ARGB: GLES format missing (i.e. GL_BGRA)
+ return glp.isGLES() ? BufferedImage.TYPE_INT_BGR : BufferedImage.TYPE_INT_ARGB;
+ } else {
+ return glp.isGLES() ? BufferedImage.TYPE_INT_BGR : BufferedImage.TYPE_INT_RGB;
+ }
+ }
+
+ public PixelFormat getAWTPixelFormat(final GLProfile glp, final int componentCount) {
+ if( 4 == componentCount ) {
+ return glp.isGLES() ? PixelFormat.RGBx8888 : PixelFormat.BGRA8888;
+ } else {
+ return glp.isGLES() ? PixelFormat.RGBx8888 : PixelFormat.BGRx8888;
+ }
}
/**
@@ -162,11 +230,17 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
* </p>
*/
@Override
- public AWTGLPixelBuffer allocate(final GL gl, final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) {
- final BufferedImage image = new BufferedImage(width, height, 4 == pixelAttributes.componentCount ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
+ public AWTGLPixelBuffer allocate(final GL gl, final PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes, final boolean pack,
+ final int width, final int height, final int depth, final int minByteSize) {
+ if( null == hostPixComp ) {
+ throw new IllegalArgumentException("Null hostPixComp");
+ }
+ final int awtFormat = getAWTFormat(gl.getGLProfile(), hostPixComp.componenCount());
+ final BufferedImage image = new BufferedImage(width, height, awtFormat);
final int[] readBackIntBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
final Buffer ibuffer = IntBuffer.wrap( readBackIntBuffer );
- return new AWTGLPixelBuffer(pixelAttributes, width, height, depth, pack, image, ibuffer, allowRowStride);
+ return new AWTGLPixelBuffer(hostPixComp, pixelAttributes, pack,
+ awtFormat, width, height, depth, image, ibuffer, allowRowStride);
}
}
@@ -174,15 +248,22 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
* Provider for singleton {@link AWTGLPixelBuffer} instances.
* <p>
* Provider instance holds the last {@link AWTGLPixelBuffer} instance
- * {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated}.
- * A new {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocation}
+ * {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated}.
+ * A new {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocation}
* will return same instance, if a new buffer is not {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int) required}.
* The latter is true if size are compatible, hence <code>allowRowStride</code> should be enabled, if possible.
* </p>
*/
public static class SingleAWTGLPixelBufferProvider extends AWTGLPixelBufferProvider implements SingletonGLPixelBufferProvider {
- private AWTGLPixelBuffer singleRGBA4 = null;
- private AWTGLPixelBuffer singleRGB3 = null;
+ private final IntObjectHashMap bufferMap = new IntObjectHashMap(8);
+
+ private static int getHashCode(final PixelFormat.Composition hostPixelComp, final GLPixelAttributes pixelAttributes, final boolean pack) {
+ // 31 * x == (x << 5) - x
+ int hash = hostPixelComp.hashCode();
+ hash = ((hash << 5) - hash) + pixelAttributes.hashCode();
+ // hash = ((hash << 5) - hash) + (pack ? 100 : 0); // no difference due to RGBA/BGRA only modes.
+ return hash;
+ }
/**
* @param allowRowStride If <code>true</code>, allow row-stride, otherwise not. See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
@@ -198,52 +279,72 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
* </p>
*/
@Override
- public AWTGLPixelBuffer allocate(final GL gl, final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) {
- if( 4 == pixelAttributes.componentCount ) {
- if( null == singleRGBA4 || singleRGBA4.requiresNewBuffer(gl, width, height, minByteSize) ) {
- singleRGBA4 = allocateImpl(pixelAttributes, width, height, depth, pack, minByteSize);
- }
- return singleRGBA4;
- } else {
- if( null == singleRGB3 || singleRGB3.requiresNewBuffer(gl, width, height, minByteSize) ) {
- singleRGB3 = allocateImpl(pixelAttributes, width, height, depth, pack, minByteSize);
+ public AWTGLPixelBuffer allocate(final GL gl, PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes,
+ final boolean pack, final int width, final int height, final int depth, final int minByteSize) {
+ if( null == hostPixComp ) {
+ hostPixComp = pixelAttributes.pfmt.comp;
+ }
+ final int bufferKey = getHashCode(hostPixComp, pixelAttributes, pack);
+ AWTGLPixelBuffer r = (AWTGLPixelBuffer) bufferMap.get(bufferKey);
+ if( null == r || r.requiresNewBuffer(gl, width, height, minByteSize) ) {
+ if( null != r ) {
+ r.dispose();
}
- return singleRGB3;
+ r = allocateImpl(hostPixComp, pixelAttributes, pack,
+ getAWTFormat(gl.getGLProfile(), hostPixComp.componenCount()), width, height, depth, minByteSize);
+ bufferMap.put(bufferKey, r);
}
+ return r;
}
- private AWTGLPixelBuffer allocateImpl(final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) {
- final BufferedImage image = new BufferedImage(width, height, 4 == pixelAttributes.componentCount ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
+ private AWTGLPixelBuffer allocateImpl(final PixelFormat.Composition hostPixComp,
+ final GLPixelAttributes pixelAttributes,
+ final boolean pack,
+ final int awtFormat, final int width, final int height, final int depth,
+ final int minByteSize) {
+ final BufferedImage image = new BufferedImage(width, height, awtFormat);
final int[] readBackIntBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
final Buffer ibuffer = IntBuffer.wrap( readBackIntBuffer );
- return new AWTGLPixelBuffer(pixelAttributes, width, height, depth, pack, image, ibuffer, getAllowRowStride());
+ return new AWTGLPixelBuffer(hostPixComp, pixelAttributes, pack,
+ awtFormat, width, height, depth, image, ibuffer, getAllowRowStride());
}
- /** Return the last {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated} {@link AWTGLPixelBuffer} w/ {@link GLPixelAttributes#componentCount}. */
+ /**
+ * Return the last {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated}
+ * {@link AWTGLPixelBuffer}, if compatible w/ the given {@link PixelFormat.Composition} and {@link GLPixelAttributes}.
+ **/
@Override
- public AWTGLPixelBuffer getSingleBuffer(final GLPixelAttributes pixelAttributes) {
- return 4 == pixelAttributes.componentCount ? singleRGBA4 : singleRGB3;
+ public AWTGLPixelBuffer getSingleBuffer(final PixelFormat.Composition hostPixelComp, final GLPixelAttributes pixelAttributes, final boolean pack) {
+ return (AWTGLPixelBuffer) bufferMap.get(getHashCode(hostPixelComp, pixelAttributes, pack));
}
/**
- * Initializes the single {@link AWTGLPixelBuffer} w/ a given size, if not yet {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated}.
+ * Initializes the single {@link AWTGLPixelBuffer} w/ a given size, if not yet {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated}.
* @return the newly initialized single {@link AWTGLPixelBuffer}, or null if already allocated.
*/
@Override
- public AWTGLPixelBuffer initSingleton(final int componentCount, final int width, final int height, final int depth, final boolean pack) {
- if( 4 == componentCount ) {
- if( null != singleRGBA4 ) {
- return null;
- }
- singleRGBA4 = allocateImpl(AWTGLPixelBuffer.awtPixelAttributesIntRGBA4, width, height, depth, pack, 0);
- return singleRGBA4;
- } else {
- if( null != singleRGB3 ) {
- return null;
- }
- singleRGB3 = allocateImpl(AWTGLPixelBuffer.awtPixelAttributesIntRGB3, width, height, depth, pack, 0);
- return singleRGB3;
+ public AWTGLPixelBuffer initSingleton(final GLProfile glp, final int componentCount,
+ final boolean pack, final int width, final int height, final int depth) {
+ final GLPixelAttributes pixelAttributes = getAttributes(glp, componentCount);
+ final PixelFormat awtPixelFormat = getAWTPixelFormat(glp, componentCount);
+ final int awtFormat = getAWTFormat(glp, componentCount);
+ final int bufferKey = getHashCode(awtPixelFormat.comp, pixelAttributes, pack);
+ AWTGLPixelBuffer r = (AWTGLPixelBuffer) bufferMap.get(bufferKey);
+ if( null != r ) {
+ return null;
+ }
+ r = allocateImpl(awtPixelFormat.comp, pixelAttributes, pack, awtFormat, width, height, depth, 0);
+ bufferMap.put(bufferKey, r);
+ return r;
+ }
+
+ @Override
+ public void dispose() {
+ for(final Iterator<IntObjectHashMap.Entry> i=bufferMap.iterator(); i.hasNext(); ) {
+ final AWTGLPixelBuffer b = (AWTGLPixelBuffer)i.next().value;
+ b.dispose();
}
+ bufferMap.clear();
}
}
}
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 6011afe7b..14fb90662 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
@@ -1125,12 +1125,12 @@ public class TextureIO {
final String fileSuffix) throws IOException {
if (PNG.equals(fileSuffix)) {
final PNGPixelRect image = PNGPixelRect.read(stream, null, true /* directBuffer */, 0 /* destMinStrideInBytes */, true /* destIsGLOriented */);
- final GLPixelAttributes glpa = GLPixelAttributes.convert(image.getPixelformat(), glp);
+ final GLPixelAttributes glpa = new GLPixelAttributes(glp, image.getPixelformat(), false /* pack */);
if ( 0 == pixelFormat ) {
pixelFormat = glpa.format;
} // else FIXME: Actually not supported w/ preset pixelFormat!
if ( 0 == internalFormat ) {
- final boolean hasAlpha = 4 == glpa.bytesPerPixel;
+ final boolean hasAlpha = 4 == glpa.pfmt.comp.bytesPerPixel();
if(glp.isGL2ES3()) {
internalFormat = hasAlpha ? GL.GL_RGBA8 : GL.GL_RGB8;
} else {
@@ -1351,8 +1351,8 @@ public class TextureIO {
final GLPixelAttributes pixelAttribs = data.getPixelAttributes();
final int pixelFormat = pixelAttribs.format;
final int pixelType = pixelAttribs.type;
- final int bytesPerPixel = pixelAttribs.bytesPerPixel;
- final PixelFormat pixFmt = pixelAttribs.getPixelFormat();
+ final int bytesPerPixel = pixelAttribs.pfmt.comp.bytesPerPixel();
+ final PixelFormat pixFmt = pixelAttribs.pfmt;
if ( ( 1 == bytesPerPixel || 3 == bytesPerPixel || 4 == bytesPerPixel) &&
( pixelType == GL.GL_BYTE || pixelType == GL.GL_UNSIGNED_BYTE)) {
Buffer buf0 = data.getBuffer();