aboutsummaryrefslogtreecommitdiffstats
path: root/src/nativewindow
diff options
context:
space:
mode:
Diffstat (limited to 'src/nativewindow')
-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
3 files changed, 763 insertions, 0 deletions
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+"]";
+ }
+ }
+}
+