aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java100
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java196
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java374
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java193
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java364
5 files changed, 1227 insertions, 0 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java
index 50124c349..a921a2818 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java
@@ -30,11 +30,15 @@ package com.jogamp.opengl.util;
import java.nio.Buffer;
import java.nio.ByteBuffer;
+import javax.media.nativewindow.util.PixelFormat;
import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GL2ES3;
+import javax.media.opengl.GL2GL3;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.util.texture.TextureData;
@@ -202,6 +206,56 @@ public class GLPixelBuffer {
public GLPixelAttributes(int componentCount, int dataFormat, int dataType) {
this(componentCount, dataFormat, dataType, true);
}
+
+ /**
+ * Returns the matching {@link GLPixelAttributes} for the given {@link PixelFormat} and {@link GLProfile} if exists,
+ * otherwise returns <code>null</code>.
+ */
+ public static final GLPixelAttributes convert(PixelFormat pixFmt, GLProfile glp) {
+ 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 = GL2ES2.GL_LUMINANCE;
+ }
+ break;
+ case BGR888:
+ if( glp.isGL2GL3() ) {
+ df = GL2GL3.GL_BGR;
+ }
+ break;
+ case RGB888:
+ df = GL.GL_RGB;
+ break;
+ case RGBA8888:
+ df = GL.GL_RGBA;
+ break;
+ case ABGR8888:
+ if( glp.isGL2GL3() ) {
+ 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:
+ break;
+ }
+ if( 0 != df ) {
+ return new GLPixelAttributes(pixFmt.componentCount, df, dt, true);
+ }
+ return null;
+ }
private GLPixelAttributes(int componentCount, int dataFormat, int dataType, boolean checkArgs) {
this.componentCount = componentCount;
this.format = dataFormat;
@@ -216,6 +270,52 @@ public class GLPixelBuffer {
}
}
}
+
+ /**
+ * Returns the matching {@link PixelFormat} of this {@link GLPixelAttributes} if exists,
+ * otherwise returns <code>null</code>.
+ */
+ 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 GL2.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;
+ }
+ return pixFmt;
+ }
+
@Override
public String toString() {
return "PixelAttributes[comp "+componentCount+", fmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+", bytesPerPixel "+bytesPerPixel+"]";
diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java
new file mode 100644
index 000000000..823496a92
--- /dev/null
+++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java
@@ -0,0 +1,196 @@
+/**
+ * Copyright (c) 2014 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.nativewindow.util;
+
+/**
+ * Basic pixel formats
+ * <p>
+ * Notation follows OpenGL notation, i.e.
+ * name consist of all it's component names
+ * followed by their bit size.
+ * </p>
+ * <p>
+ * Order of component names is from lowest-bit to highest-bit.
+ * </p>
+ * <p>
+ * In case component-size is 1 byte (e.g. OpenGL data-type GL_UNSIGNED_BYTE),
+ * component names are ordered from lowest-byte to highest-byte.
+ * Note that OpenGL applies special interpretation if
+ * data-type is e.g. GL_UNSIGNED_8_8_8_8_REV or GL_UNSIGNED_8_8_8_8_REV.
+ * </p>
+ * <p>
+ * PixelFormat can be converted to OpenGL GLPixelAttributes
+ * via
+ * <pre>
+ * GLPixelAttributes glpa = GLPixelAttributes.convert(PixelFormat pixFmt, GLProfile glp);
+ * </pre>
+ * </p>
+ * <p>
+ * See OpenGL Specification 4.3 - February 14, 2013, Core Profile,
+ * Section 8.4.4 Transfer of Pixel Rectangles, p. 161-174.
+ * </ul>
+ *
+ * </p>
+ */
+public enum PixelFormat {
+ /**
+ * Pixel size is 1 bytes (8 bits) with one component of size 1 byte (8 bits).
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_ALPHA (< GL3), GL_RED (>= GL3), data-type GL_UNSIGNED_BYTE</li>
+ * <li>AWT: <i>none</i></li>
+ * </ul>
+ * </p>
+ */
+ LUMINANCE(1, 8),
+
+ /**
+ * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits).
+ * <p>
+ * The components are interleaved in the order:
+ * <ul>
+ * <li>Low to High: R, G, B</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li>
+ * <li>AWT: <i>None</i></li>
+ * </ul>
+ * </p>
+ */
+ RGB888(3, 24),
+
+ /**
+ * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits).
+ * <p>
+ * The components are interleaved in the order:
+ * <ul>
+ * <li>Low to High: B, G, R</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_BGR (>= GL2), data-type GL_UNSIGNED_BYTE</li>
+ * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_3BYTE_BGR TYPE_3BYTE_BGR}</li>
+ * </ul>
+ * </p>
+ */
+ BGR888(3, 24),
+
+ /**
+ * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * <p>
+ * The components are interleaved in the order:
+ * <ul>
+ * <li>Low to High: R, G, B, A</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE</li>
+ * <li>AWT: <i>None</i></li>
+ * <li>PointerIcon: X11 (XCURSOR)</li>
+ * <li>PNGJ: Scanlines</li>
+ * </ul>
+ * </p>
+ */
+ RGBA8888(4, 32),
+
+ /**
+ * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * <p>
+ * The components are interleaved in the order:
+ * <ul>
+ * <li>Low to High: A, B, G, R</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_8_8_8_8</li>
+ * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}</li>
+ * </ul>
+ * </p>
+ */
+ ABGR8888(4, 32),
+
+ /**
+ * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * <p>
+ * The components are interleaved in the order:
+ * <ul>
+ * <li>Low to High: A, R, G, B</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_INT_8_8_8_8</li>
+ * <li>AWT: <i>None</i></li>
+ * </ul>
+ * </p>
+ */
+ ARGB8888(4, 32),
+
+ /**
+ * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * <p>
+ * The components are interleaved in the order:
+ * <ul>
+ * <li>Low to High: B, G, R, A</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE</li>
+ * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_ARGB TYPE_INT_ARGB}</li>
+ * <li>PointerIcon: Win32, OSX (NSBitmapImageRep), AWT</li>
+ * <li>Window Icon: X11, Win32, OSX (NSBitmapImageRep)</li>
+ * </ul>
+ * </p>
+ */
+ BGRA8888(4, 32);
+
+ /** Number of components per pixel, e.g. 4 for RGBA. */
+ public final int componentCount;
+ /** Number of bits per pixel, e.g. 32 for RGBA. */
+ public final int bitsPerPixel;
+ /** Number of bytes per pixel, e.g. 4 for RGBA. */
+ public final int bytesPerPixel() { return (7+bitsPerPixel)/8; }
+
+ private PixelFormat(int componentCount, int bpp) {
+ this.componentCount = componentCount;
+ this.bitsPerPixel = bpp;
+ }
+}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
new file mode 100644
index 000000000..361d03446
--- /dev/null
+++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
@@ -0,0 +1,374 @@
+/**
+ * Copyright (c) 2014 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.nativewindow.util;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import com.jogamp.common.nio.Buffers;
+
+/**
+ * Pixel Rectangle Utilities.
+ * <p>
+ * All conversion methods are endian independent.
+ * </p>
+ */
+public class PixelFormatUtil {
+ public static interface PixelSink {
+ /** Return the sink's destination pixelformat. */
+ PixelFormat getPixelformat();
+
+ /**
+ * Returns stride in byte-size, i.e. byte count from one line to the next.
+ * <p>
+ * Must be >= {@link #getPixelformat()}.{@link PixelFormat#bytesPerPixel() bytesPerPixel()} * {@link #getSize()}.{@link DimensionImmutable#getWidth() getWidth()}.
+ * </p>
+ */
+ int getStride();
+
+ /**
+ * Returns <code>true</code> if the sink's memory is laid out in
+ * OpenGL's coordinate system, <i>origin at bottom left</i>.
+ * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>.
+ */
+ boolean isGLOriented();
+ }
+ /**
+ * Pixel sink for up-to 32bit.
+ */
+ public static interface PixelSink32 extends PixelSink {
+ /**
+ * Will be invoked over all rows top-to down
+ * and all columns left-to-right.
+ * <p>
+ * Shall consider dest pixelformat and only store as much components
+ * as defined, up to 32bit.
+ * </p>
+ * <p>
+ * Implementation may better write single bytes from low-to-high bits,
+ * e.g. {@link ByteOrder#LITTLE_ENDIAN} order.
+ * Otherwise a possible endian conversion must be taken into consideration.
+ * </p>
+ * @param x
+ * @param y
+ * @param pixel
+ */
+ void store(int x, int y, int pixel);
+ }
+
+ /**
+ * Returns the {@link PixelFormat} with reversed components of <code>fmt</code>.
+ * If no reversed {@link PixelFormat} is available, returns <code>fmt</code>.
+ */
+ public static PixelFormat getReversed(PixelFormat fmt) {
+ switch(fmt) {
+ case LUMINANCE:
+ return PixelFormat.LUMINANCE;
+ case RGB888:
+ return PixelFormat.BGR888;
+ case BGR888:
+ return PixelFormat.RGB888;
+ case RGBA8888:
+ return PixelFormat.ABGR8888;
+ case ABGR8888:
+ return PixelFormat.RGBA8888;
+ case ARGB8888:
+ return PixelFormat.BGRA8888;
+ case BGRA8888:
+ return PixelFormat.ABGR8888;
+ default:
+ throw new InternalError("Unhandled format "+fmt);
+ }
+ }
+
+ public static int getValue32(PixelFormat src_fmt, ByteBuffer src, int srcOff) {
+ switch(src_fmt) {
+ case LUMINANCE: {
+ final byte c1 = src.get(srcOff++);
+ return ( 0xff ) << 24 | ( 0xff & c1 ) << 16 | ( 0xff & c1 ) << 8 | ( 0xff & c1 );
+ }
+ case RGB888:
+ case BGR888: {
+ final byte c1 = src.get(srcOff++);
+ final byte c2 = src.get(srcOff++);
+ final byte c3 = src.get(srcOff++);
+ return ( 0xff ) << 24 | ( 0xff & c3 ) << 16 | ( 0xff & c2 ) << 8 | ( 0xff & c1 );
+ }
+ case RGBA8888:
+ case ABGR8888:
+ case ARGB8888:
+ case BGRA8888: {
+ final byte c1 = src.get(srcOff++);
+ final byte c2 = src.get(srcOff++);
+ final byte c3 = src.get(srcOff++);
+ final byte c4 = src.get(srcOff++);
+ return ( 0xff & c4 ) << 24 | ( 0xff & c3 ) << 16 | ( 0xff & c2 ) << 8 | ( 0xff & c1 );
+ }
+ default:
+ throw new InternalError("Unhandled format "+src_fmt);
+ }
+ }
+
+ public static int convertToInt32(PixelFormat dest_fmt, final byte r, final byte g, final byte b, final byte a) {
+ switch(dest_fmt) {
+ case LUMINANCE: {
+ final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) );
+ return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l );
+ }
+ case RGB888:
+ return ( 0xff ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
+ case BGR888:
+ return ( 0xff ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
+ case RGBA8888:
+ return ( 0xff & a ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
+ case ABGR8888:
+ return ( 0xff & r ) << 24 | ( 0xff & g ) << 16 | ( 0xff & b ) << 8 | ( 0xff & a );
+ case ARGB8888:
+ return ( 0xff & b ) << 24 | ( 0xff & g ) << 16 | ( 0xff & r ) << 8 | ( 0xff & a );
+ case BGRA8888:
+ return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
+ default:
+ throw new InternalError("Unhandled format "+dest_fmt);
+ }
+ }
+
+ public static int convertToInt32(PixelFormat dest_fmt, PixelFormat src_fmt, ByteBuffer src, int srcOff) {
+ final byte r, g, b, a;
+ switch(src_fmt) {
+ case LUMINANCE:
+ r = src.get(srcOff++); // R
+ g = r; // G
+ b = r; // B
+ a = (byte) 0xff; // A
+ break;
+ case RGB888:
+ r = src.get(srcOff++); // R
+ g = src.get(srcOff++); // G
+ b = src.get(srcOff++); // B
+ a = (byte) 0xff; // A
+ break;
+ case BGR888:
+ b = src.get(srcOff++); // B
+ g = src.get(srcOff++); // G
+ r = src.get(srcOff++); // R
+ a = (byte) 0xff; // A
+ break;
+ case RGBA8888:
+ r = src.get(srcOff++); // R
+ g = src.get(srcOff++); // G
+ b = src.get(srcOff++); // B
+ a = src.get(srcOff++); // A
+ break;
+ case ABGR8888:
+ a = src.get(srcOff++); // A
+ b = src.get(srcOff++); // B
+ g = src.get(srcOff++); // G
+ r = src.get(srcOff++); // R
+ break;
+ case ARGB8888:
+ a = src.get(srcOff++); // A
+ r = src.get(srcOff++); // R
+ g = src.get(srcOff++); // G
+ b = src.get(srcOff++); // B
+ break;
+ case BGRA8888:
+ b = src.get(srcOff++); // B
+ g = src.get(srcOff++); // G
+ r = src.get(srcOff++); // R
+ a = src.get(srcOff++); // A
+ break;
+ default:
+ throw new InternalError("Unhandled format "+src_fmt);
+ }
+ return convertToInt32(dest_fmt, r, g, b, a);
+ }
+
+ /**
+ public static int convertToInt32(PixelFormat dest_fmt, PixelFormat src_fmt, final int src_pixel) {
+ final byte r, g, b, a;
+ switch(src_fmt) {
+ case LUMINANCE:
+ r = (byte) ( src_pixel ); // R
+ g = r; // G
+ b = r; // B
+ a = (byte) 0xff; // A
+ break;
+ case RGB888:
+ r = (byte) ( src_pixel ); // R
+ g = (byte) ( src_pixel >>> 8 ); // G
+ b = (byte) ( src_pixel >>> 16 ); // B
+ a = (byte) 0xff; // A
+ break;
+ case BGR888:
+ b = (byte) ( src_pixel ); // B
+ g = (byte) ( src_pixel >>> 8 ); // G
+ r = (byte) ( src_pixel >>> 16 ); // R
+ a = (byte) 0xff; // A
+ break;
+ case RGBA8888:
+ r = (byte) ( src_pixel ); // R
+ g = (byte) ( src_pixel >>> 8 ); // G
+ b = (byte) ( src_pixel >>> 16 ); // B
+ a = (byte) ( src_pixel >>> 24 ); // A
+ break;
+ case ABGR8888:
+ a = (byte) ( src_pixel ); // A
+ b = (byte) ( src_pixel >>> 8 ); // B
+ g = (byte) ( src_pixel >>> 16 ); // G
+ r = (byte) ( src_pixel >>> 24 ); // R
+ break;
+ case ARGB8888:
+ a = (byte) ( src_pixel ); // A
+ r = (byte) ( src_pixel >>> 8 ); // R
+ g = (byte) ( src_pixel >>> 16 ); // G
+ b = (byte) ( src_pixel >>> 24 ); // B
+ break;
+ case BGRA8888:
+ b = (byte) ( src_pixel ); // B
+ g = (byte) ( src_pixel >>> 8 ); // G
+ r = (byte) ( src_pixel >>> 16 ); // R
+ a = (byte) ( src_pixel >>> 24 ); // A
+ break;
+ default:
+ throw new InternalError("Unhandled format "+src_fmt);
+ }
+ return convertToInt32(dest_fmt, r, g, b, a);
+ } */
+
+ public static PixelRectangle convert32(final PixelRectangle src,
+ final PixelFormat destFmt, int ddestStride, final boolean isGLOriented,
+ final boolean destIsDirect) {
+ final int width = src.getSize().getWidth();
+ final int height = src.getSize().getHeight();
+ final int bpp = destFmt.bytesPerPixel();
+ final int destStride;
+ if( 0 != ddestStride ) {
+ destStride = ddestStride;
+ if( destStride < bpp * width ) {
+ throw new IllegalArgumentException("Invalid stride "+destStride+", must be greater than bytesPerPixel "+bpp+" * width "+width);
+ }
+ } else {
+ destStride = bpp * width;
+ }
+ final int capacity = destStride*height;
+ final ByteBuffer bb = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order());
+
+ // System.err.println("XXX: SOURCE "+src);
+ // System.err.println("XXX: DEST fmt "+destFmt+", stride "+destStride+" ("+ddestStride+"), isGL "+isGLOriented+", "+width+"x"+height+", capacity "+capacity+", "+bb);
+
+ final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() {
+ public void store(int x, int y, int pixel) {
+ int o = destStride*y+x*bpp;
+ bb.put(o++, (byte) ( pixel )); // 1
+ if( 3 <= bpp ) {
+ bb.put(o++, (byte) ( pixel >>> 8 )); // 2
+ bb.put(o++, (byte) ( pixel >>> 16 )); // 3
+ if( 4 <= bpp ) {
+ bb.put(o++, (byte) ( pixel >>> 24 )); // 4
+ }
+ }
+ }
+ @Override
+ public final PixelFormat getPixelformat() {
+ return destFmt;
+ }
+ @Override
+ public final int getStride() {
+ return destStride;
+ }
+ @Override
+ public final boolean isGLOriented() {
+ return isGLOriented;
+ }
+ };
+ convert32(imgSink, src);
+ return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, bb);
+ }
+
+ public static void convert32(PixelSink32 destInt32, final PixelRectangle src) {
+ convert32(destInt32,
+ src.getPixels(), src.getPixelformat(),
+ src.isGLOriented(),
+ src.getSize().getWidth(), src.getSize().getHeight(),
+ src.getStride());
+ }
+
+ /**
+ *
+ * @param dest32 32bit pixel sink
+ * @param src_bb
+ * @param src_fmt
+ * @param src_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>,
+ * otherwise <i>origin at top left</i>.
+ * @param width
+ * @param height
+ * @param strideInBytes stride in byte-size, i.e. byte count from one line to the next.
+ * If zero, stride is set to <code>width * bytes-per-pixel</code>.
+ * If not zero, value must be >= <code>width * bytes-per-pixel</code>.
+ * @param stride_bytes stride in byte-size, i.e. byte count from one line to the next.
+ * Must be >= {@link PixelFormat#bytesPerPixel() src_fmt.bytesPerPixel()} * width.
+ * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid
+ */
+ public static void convert32(PixelSink32 dest32,
+ final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, final int width, final int height, int stride_bytes) {
+ final int src_bpp = src_fmt.bytesPerPixel();
+ if( 0 != stride_bytes ) {
+ if( stride_bytes < src_bpp * width ) {
+ throw new IllegalArgumentException("Invalid stride "+stride_bytes+", must be greater than bytesPerPixel "+src_bpp+" * width "+width);
+ }
+ } else {
+ stride_bytes = src_bpp * width;
+ }
+ final PixelFormat dest_fmt = dest32.getPixelformat();
+ final boolean vert_flip = src_glOriented != dest32.isGLOriented();
+ final boolean fast_copy = src_fmt == dest_fmt && dest_fmt.bytesPerPixel() == 4 ;
+ // System.err.println("XXX: SRC fmt "+src_fmt+", stride "+stride_bytes+", isGL "+src_glOriented+", "+width+"x"+height);
+ // System.err.println("XXX: DST fmt "+dest_fmt+", fast_copy "+fast_copy);
+
+ if( fast_copy ) {
+ // Fast copy
+ for(int y=0; y<height; y++) {
+ int o = vert_flip ? ( height - 1 - y ) * stride_bytes : y * stride_bytes;
+ for(int x=0; x<width; x++) {
+ dest32.store(x, y, getValue32(src_fmt, src_bb, o));
+ o += src_bpp;
+ }
+ }
+ } else {
+ // Conversion
+ for(int y=0; y<height; y++) {
+ int o = vert_flip ? ( height - 1 - y ) * stride_bytes : y * stride_bytes;
+ for(int x=0; x<width; x++) {
+ dest32.store( x, y, convertToInt32( dest_fmt, src_fmt, src_bb, o));
+ o += src_bpp;
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java
new file mode 100644
index 000000000..493c712bb
--- /dev/null
+++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java
@@ -0,0 +1,193 @@
+/**
+ * Copyright (c) 2014 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.nativewindow.util;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Pixel Rectangle identified by it's {@link #hashCode()}.
+ * <p>
+ * The {@link #getPixels()} are assumed to be immutable.
+ * </p>
+ */
+public interface PixelRectangle {
+ /**
+ * <p>
+ * Computes a hash code over:
+ * <ul>
+ * <li>pixelformat</li>
+ * <li>size</li>
+ * <li>stride</li>
+ * <li>isGLOriented</li>
+ * <li>pixels</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The hashCode shall be computed only once with first call
+ * and stored for later retrieval to enhance performance.
+ * </p>
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ @Override
+ int hashCode();
+
+ /** Returns the {@link PixelFormat}. */
+ PixelFormat getPixelformat();
+
+ /** Returns the size, i.e. width and height. */
+ DimensionImmutable getSize();
+
+ /**
+ * Returns stride in byte-size, i.e. byte count from one line to the next.
+ * <p>
+ * Must be >= {@link #getPixelformat()}.{@link PixelFormat#bytesPerPixel() bytesPerPixel()} * {@link #getSize()}.{@link DimensionImmutable#getWidth() getWidth()}.
+ * </p>
+ */
+ int getStride();
+
+ /**
+ * Returns <code>true</code> if the memory is laid out in
+ * OpenGL's coordinate system, <i>origin at bottom left</i>.
+ * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>.
+ */
+ public boolean isGLOriented();
+
+ /** Returns the pixels. */
+ ByteBuffer getPixels();
+
+ @Override
+ String toString();
+
+ /**
+ * Generic PixelRectangle implementation
+ */
+ public static class GenericPixelRect implements PixelRectangle {
+ protected final PixelFormat pixelformat;
+ protected final DimensionImmutable size;
+ protected final int strideInBytes;
+ protected final boolean isGLOriented;
+ protected final ByteBuffer pixels;
+ private int hashCode = 0;
+ private volatile boolean hashCodeComputed = false;
+
+ /**
+ *
+ * @param pixelformat
+ * @param size
+ * @param strideInBytes stride in byte-size, i.e. byte count from one line to the next.
+ * If not zero, value must be >= <code>width * bytes-per-pixel</code>.
+ * If zero, stride is set to <code>width * bytes-per-pixel</code>.
+ * @param isGLOriented
+ * @param pixels
+ * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid.
+ * @throws IndexOutOfBoundsException if <code>pixels</code> has insufficient bytes left
+ */
+ public GenericPixelRect(final PixelFormat pixelformat, final DimensionImmutable size, int strideInBytes, final boolean isGLOriented, final ByteBuffer pixels)
+ throws IllegalArgumentException, IndexOutOfBoundsException
+ {
+ if( 0 != strideInBytes ) {
+ if( strideInBytes < pixelformat.bytesPerPixel() * size.getWidth()) {
+ throw new IllegalArgumentException("Invalid stride "+strideInBytes+", must be greater than bytesPerPixel "+pixelformat.bytesPerPixel()+" * width "+size.getWidth());
+ }
+ } else {
+ strideInBytes = pixelformat.bytesPerPixel() * size.getWidth();
+ }
+ final int reqBytes = strideInBytes * size.getHeight();
+ if( pixels.limit() < reqBytes ) {
+ throw new IndexOutOfBoundsException("Dest buffer has insufficient bytes left, needs "+reqBytes+": "+pixels);
+ }
+ this.pixelformat = pixelformat;
+ this.size = size;
+ this.strideInBytes = strideInBytes;
+ this.isGLOriented = isGLOriented;
+ this.pixels = pixels;
+ }
+
+ /**
+ * Copy ctor validating src.
+ * @param src
+ * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid.
+ * @throws IndexOutOfBoundsException if <code>pixels</code> has insufficient bytes left
+ */
+ public GenericPixelRect(final PixelRectangle src)
+ throws IllegalArgumentException, IndexOutOfBoundsException
+ {
+ this(src.getPixelformat(), src.getSize(), src.getStride(), src.isGLOriented(), src.getPixels());
+ }
+
+ @Override
+ public int hashCode() {
+ if( !hashCodeComputed ) { // DBL CHECKED OK VOLATILE
+ synchronized (this) {
+ if( !hashCodeComputed ) {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + pixelformat.hashCode();
+ hash = ((hash << 5) - hash) + size.hashCode();
+ hash = ((hash << 5) - hash) + strideInBytes;
+ hash = ((hash << 5) - hash) + ( isGLOriented ? 1 : 0);
+ hashCode = ((hash << 5) - hash) + pixels.hashCode();
+ }
+ }
+ }
+ return hashCode;
+ }
+
+ @Override
+ public PixelFormat getPixelformat() {
+ return pixelformat;
+ }
+
+ @Override
+ public DimensionImmutable getSize() {
+ return size;
+ }
+
+ @Override
+ public int getStride() {
+ return strideInBytes;
+ }
+
+ @Override
+ public boolean isGLOriented() {
+ return isGLOriented;
+ }
+
+ @Override
+ public ByteBuffer getPixels() {
+ return pixels;
+ }
+
+ @Override
+ public final String toString() {
+ return "PixelRect[obj 0x"+Integer.toHexString(super.hashCode())+", "+pixelformat+", "+size+", stride "+strideInBytes+", isGLOrient "+isGLOriented+", pixels "+pixels+"]";
+ }
+ }
+}
+
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java
new file mode 100644
index 000000000..bfcf9c2d7
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java
@@ -0,0 +1,364 @@
+/**
+ * Copyright 2014 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 com.jogamp.opengl.test.junit.jogl.util.texture;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import javax.media.nativewindow.util.Dimension;
+import javax.media.nativewindow.util.PixelFormat;
+import javax.media.nativewindow.util.PixelFormatUtil;
+import javax.media.nativewindow.util.PixelRectangle;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+/**
+ * Testing PixelFormatUtil's Conversion using synthetic test data
+ * including strides, endian-order and all PixelFormat conversions.
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestPixelFormatUtil00NEWT extends UITestCase {
+ @Test
+ public void testConversion01_srcS000_BE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException {
+ testPNG00Impl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
+ 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ }
+ @Test
+ public void testConversion02_srcS000_LE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException {
+ testPNG00Impl(0 /* srcMinStrideInBytes */, ByteOrder.LITTLE_ENDIAN, false /* srcIsGLOriented */,
+ 0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ }
+ @Test
+ public void testConversion03_srcS000_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException {
+ testPNG00Impl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
+ 259 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ }
+ @Test
+ public void testConversion04_srcS259_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException {
+ testPNG00Impl(259 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
+ 259 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ }
+ @Test
+ public void testConversion05_srcS301_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException {
+ testPNG00Impl(301 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
+ 259 /* destMinStrideInBytes */, false /* destIsGLOriented */);
+ }
+
+ static final byte red___val = (byte)0x01;
+ static final byte green_val = (byte)0x02;
+ static final byte blue__val = (byte)0x03;
+ static final byte alpha_val = (byte)0x04;
+ static final byte undef_val = (byte)0xff;
+
+ static final void getComponents(final int srcComps, final PixelFormat fmt, final byte[] components) {
+ final byte b1, b2, b3, b4;
+ if( 1 == srcComps ) {
+ // LUM -> Fmt Conversion
+ switch(fmt) {
+ case LUMINANCE:
+ b1 = red___val;
+ b2 = undef_val;
+ b3 = undef_val;
+ b4 = undef_val;
+ break;
+ case RGB888:
+ b1 = red___val;
+ b2 = red___val;
+ b3 = red___val;
+ b4 = undef_val;
+ break;
+ case BGR888:
+ b1 = red___val;
+ b2 = red___val;
+ b3 = red___val;
+ b4 = undef_val;
+ break;
+ case RGBA8888:
+ b1 = red___val;
+ b2 = red___val;
+ b3 = red___val;
+ b4 = undef_val;
+ break;
+ case ABGR8888:
+ b1 = undef_val;
+ b2 = red___val;
+ b3 = red___val;
+ b4 = red___val;
+ break;
+ case BGRA8888:
+ b1 = red___val;
+ b2 = red___val;
+ b3 = red___val;
+ b4 = undef_val;
+ break;
+ case ARGB8888:
+ b1 = undef_val;
+ b2 = red___val;
+ b3 = red___val;
+ b4 = red___val;
+ break;
+ default:
+ throw new InternalError("Unhandled format "+fmt);
+ }
+ } else {
+ // 1:1 values
+ switch(fmt) {
+ case LUMINANCE:
+ if( srcComps > 1 ) {
+ b1 = ( red___val + green_val+ blue__val ) / 3;
+ b2 = undef_val;
+ b3 = undef_val;
+ b4 = undef_val;
+ } else {
+ b1 = red___val;
+ b2 = undef_val;
+ b3 = undef_val;
+ b4 = undef_val;
+ }
+ break;
+ case RGB888:
+ b1 = red___val;
+ b2 = green_val;
+ b3 = blue__val;
+ b4 = undef_val;
+ break;
+ case BGR888:
+ b1 = blue__val;
+ b2 = green_val;
+ b3 = red___val;
+ b4 = undef_val;
+ break;
+ case RGBA8888:
+ b1 = red___val;
+ b2 = green_val;
+ b3 = blue__val;
+ b4 = srcComps > 3 ? alpha_val : undef_val;
+ break;
+ case ABGR8888:
+ b1 = srcComps > 3 ? alpha_val : undef_val;
+ b2 = blue__val;
+ b3 = green_val;
+ b4 = red___val;
+ break;
+ case BGRA8888:
+ b1 = blue__val;
+ b2 = green_val;
+ b3 = red___val;
+ b4 = srcComps > 3 ? alpha_val : undef_val;
+ break;
+ case ARGB8888:
+ b1 = srcComps > 3 ? alpha_val : undef_val;
+ b2 = red___val;
+ b3 = green_val;
+ b4 = blue__val;
+ break;
+ default:
+ throw new InternalError("Unhandled format "+fmt);
+ }
+ }
+ components[0] = b1;
+ components[1] = b2;
+ components[2] = b3;
+ components[3] = b4;
+ }
+ private void testPNG00Impl(final int srcMinStrideInBytes, final ByteOrder srcByteOrder, final boolean srcIsGLOriented,
+ final int destMinStrideInBytes, final boolean destIsGLOriented)
+ throws InterruptedException, IOException, MalformedURLException
+ {
+ System.err.println("Test00: srcMinStrideInBytes "+srcMinStrideInBytes+", srcByteOrder "+srcByteOrder+", srcIsGLOriented "+srcIsGLOriented+
+ ", destMinStrideInBytes "+destMinStrideInBytes+", destIsGLOriented "+destIsGLOriented);
+
+ final PixelFormat[] formats = PixelFormat.values();
+ final int width = 64, height = 64;
+
+ for(int i=0; i<formats.length; i++) {
+ final PixelFormat srcFmt = formats[i];
+ final int srcBpp = srcFmt.bytesPerPixel();
+ final int srcStrideBytes = Math.max(srcMinStrideInBytes, width*srcBpp);
+ final ByteBuffer srcPixels = ByteBuffer.allocate(height*srcStrideBytes).order(srcByteOrder);
+ final byte[] srcComponents = new byte[4];
+ getComponents(srcFmt.componentCount, srcFmt, srcComponents);
+ for(int y=0; y<height; y++) {
+ int o = y*srcStrideBytes;
+ for(int x=0; x<width; x++) {
+ switch(srcFmt) {
+ case LUMINANCE:
+ srcPixels.put(o++, srcComponents[0]);
+ break;
+ case RGB888:
+ case BGR888:
+ srcPixels.put(o++, srcComponents[0]);
+ srcPixels.put(o++, srcComponents[1]);
+ srcPixels.put(o++, srcComponents[2]);
+ break;
+ case RGBA8888:
+ case ABGR8888:
+ case BGRA8888:
+ case ARGB8888:
+ srcPixels.put(o++, srcComponents[0]);
+ srcPixels.put(o++, srcComponents[1]);
+ srcPixels.put(o++, srcComponents[2]);
+ srcPixels.put(o++, srcComponents[3]);
+ break;
+ default:
+ throw new InternalError("Unhandled format "+srcFmt);
+ }
+ }
+ }
+ final PixelRectangle imageSrc = new PixelRectangle.GenericPixelRect(srcFmt, new Dimension(width, height), srcStrideBytes, srcIsGLOriented, srcPixels);
+ System.err.println("CONVERT["+i+"][*]: Image0 - Orig: "+imageSrc);
+ testComponents(imageSrc, 0, 0, srcComponents);
+ testComponents(imageSrc, width-1, height-1, srcComponents);
+
+ for(int j=0; j<formats.length; j++) {
+ final PixelFormat destFmt = formats[j];
+ System.err.println("CONVERT["+i+"]["+j+"]: "+srcFmt+" -> "+destFmt);
+
+ final int destStrideBytes = Math.max(destMinStrideInBytes, width*destFmt.bytesPerPixel());
+ final byte[] destComponents = new byte[4];
+ getComponents(srcFmt.componentCount, destFmt, destComponents);
+ final PixelRectangle imageConv1 = PixelFormatUtil.convert32(imageSrc, destFmt, destStrideBytes, destIsGLOriented, false /* nio */);
+ System.err.println("CONVERT["+i+"]["+j+"]: Conv1: "+imageConv1);
+ testComponents(imageConv1, 0, 0, destComponents);
+ testComponents(imageConv1, width-1, height-1, destComponents);
+ if( PixelFormat.LUMINANCE != srcFmt && PixelFormat.LUMINANCE == destFmt ) {
+ // Cannot convert: RGB* -> LUM -> RGB*
+ System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to RGB* -> LUM");
+ } else if( srcFmt.componentCount > destFmt.componentCount ) {
+ // Cannot convert back if: src.componentCount > dest.componentCount
+ System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to src.componentCount > dest.componentCount");
+ } else {
+ final PixelRectangle imageConv2 = PixelFormatUtil.convert32(imageConv1, imageSrc.getPixelformat(), imageSrc.getStride(), imageSrc.isGLOriented(), false /* nio */);
+ System.err.println("CONVERT["+i+"]["+j+"]: Conv2: "+imageConv2);
+ testComponents(imageConv2, 0, 0, srcComponents);
+ testComponents(imageConv2, width-1, height-1, srcComponents);
+ if( imageSrc.getStride() == imageConv1.getStride() ) {
+ Assert.assertEquals(imageSrc.getPixels(), imageConv2.getPixels());
+ }
+ }
+ }
+ }
+ }
+ private void dumpComponents(PixelRectangle image, int x1, int y1, int w, int h) {
+ if( x1 + w >= image.getSize().getWidth() ) {
+ x1 = image.getSize().getWidth() - w;
+ }
+ if( y1 + h >= image.getSize().getHeight() ) {
+ y1 = image.getSize().getHeight() - h;
+ }
+ System.err.print("PixelsBytes "+x1+"/"+y1+" "+w+"x"+h+":");
+ final ByteBuffer bb = image.getPixels();
+ final int bpp = image.getPixelformat().bytesPerPixel();
+ for(int y = y1; y< y1+h; y++) {
+ System.err.printf("%n[%3d][%3d] ", x1, y);
+ int o = y * image.getStride()+x1*bpp;
+ for(int x = x1; x< x1+w; x++) {
+ switch(bpp) {
+ case 1: {
+ final byte a = bb.get(o++);
+ System.err.printf(" 0x%02X", a);
+ }
+ break;
+ case 2: {
+ final byte a = bb.get(o++), b = bb.get(o++);
+ System.err.printf(" 0x%02X%02X", b, a);
+ }
+ break;
+ case 3: {
+ final byte a = bb.get(o++), b = bb.get(o++), c = bb.get(o++);
+ System.err.printf(" 0x%02X%02X%02X", c, b, a);
+ }
+ break;
+ case 4: {
+ final byte a = bb.get(o++), b = bb.get(o++), c = bb.get(o++), d = bb.get(o++);
+ System.err.printf(" 0x%02X%02X%02X%02X", d, c, b, a);
+ }
+ break;
+ }
+ }
+ }
+ System.err.println();
+ }
+ private void testComponents(PixelRectangle image, int x, int y, byte[] components) {
+ dumpComponents(image, x, y, 3, 3);
+ final ByteBuffer bb = image.getPixels();
+ final int bpp = image.getPixelformat().bytesPerPixel();
+ int o = y * image.getStride()+x*bpp;
+ switch(bpp) {
+ case 1: {
+ final byte c1 = bb.get(o++);
+ final boolean equal = c1==components[0];
+ System.err.printf("Test [%3d][%3d] exp 0x%02X == has 0x%02X : %b%n",
+ x, y, components[0], c1, equal );
+ Assert.assertEquals(components[0], c1);
+ }
+ break;
+ case 2: {
+ final byte c1 = bb.get(o++), c2 = bb.get(o++);
+ final boolean equal = c1==components[0] && c2==components[1];
+ System.err.printf("Test [%3d][%3d] exp 0x%02X%02X == has 0x%02X%02X : %b%n",
+ x, components[1], components[0], c2, c1, equal );
+ Assert.assertEquals(components[0], c1);
+ Assert.assertEquals(components[1], c2);
+ }
+ break;
+ case 3: {
+ final byte c1 = bb.get(o++), c2 = bb.get(o++), c3 = bb.get(o++);
+ final boolean equal = c1==components[0] && c2==components[1] && c3==components[2];
+ System.err.printf("Test [%3d][%3d] exp 0x%02X%02X%02X == has 0x%02X%02X%02X : %b%n",
+ x, y, components[2], components[1], components[0], c3, c2, c1, equal );
+ Assert.assertEquals(components[0], c1);
+ Assert.assertEquals(components[1], c2);
+ Assert.assertEquals(components[2], c3);
+ }
+ break;
+ case 4: {
+ final byte c1 = bb.get(o++), c2 = bb.get(o++), c3 = bb.get(o++), c4 = bb.get(o++);
+ final boolean equal = c1==components[0] && c2==components[1] && c3==components[2] && c4==components[3];
+ System.err.printf("Test [%3d][%3d] exp 0x%02X%02X%02X%02X == has 0x%02X%02X%02X%02X : %b%n",
+ x, y, components[3], components[2], components[1], components[0], c4, c3, c2, c1, equal );
+ Assert.assertEquals(components[0], c1);
+ Assert.assertEquals(components[1], c2);
+ Assert.assertEquals(components[2], c3);
+ Assert.assertEquals(components[3], c4);
+ }
+ break;
+ }
+ }
+
+ public static void main(String args[]) {
+ org.junit.runner.JUnitCore.main(TestPixelFormatUtil00NEWT.class.getName());
+ }
+}