aboutsummaryrefslogtreecommitdiffstats
path: root/src/nativewindow/classes/javax
diff options
context:
space:
mode:
Diffstat (limited to 'src/nativewindow/classes/javax')
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java628
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java519
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java8
3 files changed, 962 insertions, 193 deletions
diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java
index e5901f584..2016b2885 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java
@@ -28,6 +28,10 @@
package javax.media.nativewindow.util;
+import java.util.Arrays;
+
+import com.jogamp.common.util.IntBitfield;
+
/**
* Basic pixel formats
* <p>
@@ -60,7 +64,7 @@ package javax.media.nativewindow.util;
*/
public enum PixelFormat {
/**
- * Pixel size is 1 bytes (8 bits) with one component of size 1 byte (8 bits).
+ * Stride is 8 bits, 8 bits per pixel, 1 component of 8 bits.
* Compatible with:
* <ul>
* <li>OpenGL: data-format GL_ALPHA (< GL3), GL_RED (>= GL3), data-type GL_UNSIGNED_BYTE</li>
@@ -68,34 +72,138 @@ public enum PixelFormat {
* </ul>
* </p>
*/
- LUMINANCE(1, 8),
+ LUMINANCE(new CType[]{ CType.Y }, 1, 8, 8),
/**
- * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits).
+ * Stride is 16 bits, 16 bits per pixel, 3 {@link PackedComposition#isUniform() discrete} components.
+ * <p>
+ * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>R: 0x1F << 0</li>
+ * <li>G: 0x3F << 5</li>
+ * <li>B: 0x1F << 11</li>
+ * </ol>
+ * </p>
* <p>
- * The components are interleaved in the order:
+ * Compatible with:
* <ul>
- * <li>Low to High: R, G, B</li>
+ * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5_REV</li>
+ * <li>AWT: <i>None</i></li>
* </ul>
* </p>
+ */
+ RGB565(new CType[]{ CType.R, CType.G, CType.B },
+ new int[]{ 0x1F, 0x3F, 0x1F },
+ new int[]{ 0, 5, 5+6 },
+ 16 ),
+
+ /**
+ * Stride is 16 bits, 16 bits per pixel, 3 {@link PackedComposition#isUniform() discrete} components.
+ * <p>
+ * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>B: 0x1F << 0</li>
+ * <li>G: 0x3F << 5</li>
+ * <li>R: 0x1F << 11</li>
+ * </ol>
+ * </p>
* <p>
* Compatible with:
* <ul>
- * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li>
+ * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5</li>
+ * <li>AWT: <i>None</i></li>
+ * </ul>
+ * </p>
+ */
+ BGR565(new CType[]{ CType.B, CType.G, CType.R},
+ new int[]{ 0x1F, 0x3F, 0x1F },
+ new int[]{ 0, 5, 5+6 },
+ 16 ),
+
+ /**
+ * Stride is 16 bits, 16 bits per pixel, 4 {@link PackedComposition#isUniform() discrete} components.
+ * <p>
+ * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>R: 0x1F << 0</li>
+ * <li>G: 0x1F << 5</li>
+ * <li>B: 0x1F << 10</li>
+ * <li>A: 0x01 << 15</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_1_5_5_5_REV</li>
+ * <li>AWT: <i>None</i></li>
+ * </ul>
+ * </p>
+ */
+ RGBA5551(new CType[]{ CType.R, CType.G, CType.B, CType.A},
+ new int[]{ 0x1F, 0x1F, 0x1F, 0x01 },
+ new int[]{ 0, 5, 5+5, 5+5+5 },
+ 16 ),
+
+ /**
+ * Stride is 16 bits, 16 bits per pixel, 4 {@link PackedComposition#isUniform() discrete} components.
+ * <p>
+ * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>A: 0x01 << 0</li>
+ * <li>B: 0x1F << 1</li>
+ * <li>G: 0x1F << 6</li>
+ * <li>R: 0x1F << 11</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_5_5_5_1</li>
* <li>AWT: <i>None</i></li>
* </ul>
* </p>
*/
- RGB888(3, 24),
+ ABGR1555(new CType[]{ CType.A, CType.B, CType.G, CType.R },
+ new int[]{ 0x01, 0x1F, 0x1F, 0x1F },
+ new int[]{ 0, 1, 1+5, 1+5+5 },
+ 16 ),
/**
- * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits).
+ * Stride 24 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits.
+ * <p>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>R: 0xFF << 0</li>
+ * <li>G: 0xFF << 8</li>
+ * <li>B: 0xFF << 16</li>
+ * </ol>
+ * </p>
* <p>
- * The components are interleaved in the order:
+ * Compatible with:
* <ul>
- * <li>Low to High: B, G, R</li>
+ * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li>
+ * <li>AWT: <i>None</i></li>
* </ul>
* </p>
+ */
+ RGB888(new CType[]{ CType.R, CType.G, CType.B }, 3, 8, 24),
+
+ /**
+ * Stride is 24 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of of 8 bits.
+ * <p>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>B: 0xFF << 0</li>
+ * <li>G: 0xFF << 8</li>
+ * <li>R: 0xFF << 16</li>
+ * </ol>
+ * </p>
* <p>
* Compatible with:
* <ul>
@@ -104,16 +212,62 @@ public enum PixelFormat {
* </ul>
* </p>
*/
- BGR888(3, 24),
+ BGR888(new CType[]{ CType.B, CType.G, CType.R }, 3, 8, 24),
+
+ /**
+ * Stride is 32 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits.
+ * <p>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>R: 0xFF << 0</li>
+ * <li>G: 0xFF << 8</li>
+ * <li>B: 0xFF << 16</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Compatible with:
+ * <ul>
+ * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE, with alpha discarded!</li>
+ * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_BGR TYPE_INT_BGR}</li>
+ * </ul>
+ * </p>
+ */
+ RGBx8888(new CType[]{ CType.R, CType.G, CType.B }, 3, 8, 32),
/**
- * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * Stride is 32 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits.
+ * <p>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>B: 0xFF << 0</li>
+ * <li>G: 0xFF << 8</li>
+ * <li>R: 0xFF << 16</li>
+ * </ol>
+ * </p>
* <p>
- * The components are interleaved in the order:
+ * Compatible with:
* <ul>
- * <li>Low to High: R, G, B, A</li>
+ * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE - with alpha discarded!</li>
+ * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_RGB TYPE_INT_RGB}</li>
* </ul>
* </p>
+ */
+ BGRx8888(new CType[]{ CType.B, CType.G, CType.R }, 3, 8, 32),
+
+ /**
+ * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits.
+ * <p>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>R: 0xFF << 0</li>
+ * <li>G: 0xFF << 8</li>
+ * <li>B: 0xFF << 16</li>
+ * <li>A: 0xFF << 24</li>
+ * </ol>
+ * </p>
* <p>
* Compatible with:
* <ul>
@@ -125,33 +279,41 @@ public enum PixelFormat {
* </ul>
* </p>
*/
- RGBA8888(4, 32),
+ RGBA8888(new CType[]{ CType.R, CType.G, CType.B, CType.A }, 4, 8, 32),
/**
- * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits.
* <p>
- * The components are interleaved in the order:
- * <ul>
- * <li>Low to High: A, B, G, R</li>
- * </ul>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>A: 0xFF << 0</li>
+ * <li>B: 0xFF << 8</li>
+ * <li>G: 0xFF << 16</li>
+ * <li>R: 0xFF << 24</li>
+ * </ol>
* </p>
* <p>
* Compatible with:
* <ul>
- * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_8_8_8_8</li>
+ * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_INT_8_8_8_8</li>
* <li>AWT: {@link java.awt.image.BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}</li>
* </ul>
* </p>
*/
- ABGR8888(4, 32),
+ ABGR8888(new CType[]{ CType.A, CType.B, CType.G, CType.R }, 4, 8, 32),
/**
- * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits.
* <p>
- * The components are interleaved in the order:
- * <ul>
- * <li>Low to High: A, R, G, B</li>
- * </ul>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>A: 0xFF << 0</li>
+ * <li>R: 0xFF << 8</li>
+ * <li>G: 0xFF << 16</li>
+ * <li>B: 0xFF << 24</li>
+ * </ol>
* </p>
* <p>
* Compatible with:
@@ -161,15 +323,19 @@ public enum PixelFormat {
* </ul>
* </p>
*/
- ARGB8888(4, 32),
+ ARGB8888(new CType[]{ CType.A, CType.R, CType.G, CType.B }, 4, 8, 32),
/**
- * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits).
+ * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits.
* <p>
- * The components are interleaved in the order:
- * <ul>
- * <li>Low to High: B, G, R, A</li>
- * </ul>
+ * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components}
+ * are interleaved in the order Low to High:
+ * <ol>
+ * <li>B: 0xFF << 0</li>
+ * <li>G: 0xFF << 8</li>
+ * <li>R: 0xFF << 16</li>
+ * <li>A: 0xFF << 24</li>
+ * </ol>
* </p>
* <p>
* Compatible with:
@@ -181,17 +347,393 @@ public enum PixelFormat {
* </ul>
* </p>
*/
- BGRA8888(4, 32);
+ BGRA8888(new CType[]{ CType.B, CType.G, CType.R, CType.A }, 4, 8, 32);
+
+ /** Unique {@link Composition Pixel Composition}, i.e. layout of its components. */
+ public final Composition comp;
+
+ /**
+ * @param componentOrder {@link CType Component type} order of all components, see {@link Composition#componentBitMask()}.
+ * @param componentCount number of components
+ * @param bpc bits per component
+ * @param bitStride stride bits to next pixel
+ */
+ private PixelFormat(final CType[] componentOrder, final int componentCount, final int bpc, final int bitStride) {
+ this.comp = new PackedComposition(componentOrder, componentCount, bpc, bitStride);
+ }
+
+ /**
+ * @param componentOrder {@link CType Component type} order of all components, see {@link Composition#componentBitMask()}.
+ * @param componentMask bit-mask of of all components, see {@link Composition##componentBitMask()}.
+ * @param componentBitShift bit-shift of all components, see {@link Composition##componentBitMask()}.
+ * @param bitStride stride bits to next pixel
+ */
+ private PixelFormat(final CType[] componentOrder, final int[] componentMask, final int[] componentBitShift, final int bitStride) {
+ this.comp = new PackedComposition(componentOrder, componentMask, componentBitShift, bitStride);
+ }
+
+ /**
+ * Returns the unique matching {@link PixelFormat} of the given {@link Composition}
+ * or {@code null} if none is available.
+ */
+ public static PixelFormat valueOf(final Composition comp) {
+ final PixelFormat[] all = PixelFormat.values();
+ for(int i=all.length-1; i>=0; i--) {
+ final PixelFormat pf = all[i];
+ if( comp.hashCode() == pf.comp.hashCode() && comp.equals(pf.comp) ) {
+ return pf;
+ }
+ }
+ return null;
+ }
+
+ /** Component types */
+ public static enum CType {
+ /** Red component */
+ R,
+ /** Green component */
+ G,
+ /** Blue component */
+ B,
+ /** Alpha component */
+ A,
+ /** Luminance component, e.g. grayscale or Y of YUV */
+ Y,
+ /** U component of YUV */
+ U,
+ /** V component of YUV */
+ V;
+ }
+
+ /**
+ * Pixel composition, i.e. layout of its components.
+ */
+ public static interface Composition {
+ /** {@value} */
+ public static final int UNDEF = -1;
+
+ /**
+ * Returns {@code true} if all components are of same bit-size, e.g. {@link PixelFormat#RGBA8888 RGBA8888},
+ * otherwise {@code false}, e.g. {@link PixelFormat#RGBA5551 RGBA5551}
+ */
+ boolean isUniform();
+
+ /**
+ * Returns {@code true} if all components are packed, i.e. interleaved, e.g. {@link PixelFormat#RGBA8888 RGBA8888},
+ * otherwise {@code false}.
+ */
+ boolean isInterleaved();
+
+ /** Number of components per pixel, e.g. 3 for {@link PixelFormat#RGBx8888 RGBx8888}. */
+ int componenCount();
+ /** Number of bits per pixel, e.g. 24 bits for {@link PixelFormat#RGBx8888 RGBx8888}. */
+ int bitsPerPixel();
+ /**
+ * Bit distance between pixels.
+ * <p>
+ * For packed pixels e.g. 32 bits for {@link PixelFormat#RGBx8888 RGBx8888}.
+ * </p>
+ */
+ int bitStride();
+ /** Number of bytes per pixel, i.e. packed {@link #bitStride()} in bytes, e.g. 4 for {@link PixelFormat#RGBx8888 RGBx8888}. */
+ int bytesPerPixel();
+ /**
+ * Returns the {@link CType Component type} order of all components, see {@link #componentBitMask()}.
+ */
+ CType[] componentOrder();
+ /**
+ * Returns the index of given {@link CType} within {@link #componentOrder()}, -1 if not exists.
+ */
+ int find(final PixelFormat.CType s);
+ /**
+ * Returns the un-shifted bit-mask of all components.
+ * <p>
+ * Components mask is returned in the order Low-Index to High-Index, e.g.:
+ * <ul>
+ * <li>{@link PixelFormat#RGB565 RGB565}: 0: R 0x1F, 1: G 0x3F, 2: B 0x1F</li>
+ * <li>{@link PixelFormat#RGBA5551 RGBA5551}: 0: R 0x1F, 1: G 0x1F, 2: B 0x1F, 3: A 0x01</li>
+ * <li>{@link PixelFormat#RGBA8888 RGBA8888}: 0: R 0xFF, 1: G 0xFF, 2: B 0xFF, 3: A 0xFF</li>
+ * </ul>
+ * </p>
+ * <p>
+ */
+ int[] componentBitMask();
+ /**
+ * Returns the number of bits of all components, see {@link #componentBitMask()}.
+ */
+ int[] componentBitCount();
+ /**
+ * Returns the bit-shift of all components, see {@link #componentBitMask()}.
+ */
+ int[] componentBitShift();
+
+ /**
+ * Decodes a component from the shifted pixel data with a {@link #bytesPerPixel()} of up to 32bit.
+ * @param shifted complete pixel encoded into on 32bit integer
+ * @param cIdx the desired component index
+ * @return the decoded component value
+ */
+ int decodeSingleI32(final int shifted, final int cIdx);
+ /**
+ * Decodes a component from the shifted pixel data with a {@link #bytesPerPixel()} of up to 64bit.
+ * @param shifted complete pixel encoded into on 64bit integer
+ * @param cIdx the desired component index
+ * @return the decoded component value
+ */
+ int decodeSingleI64(final long shifted, final int cIdx);
+
+ int encodeSingleI32(final int norm, final int cIdx);
+ long encodeSingleI64(final int norm, final int cIdx);
+
+ int encode3CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32);
+ int encode4CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32, final int c4NormI32);
+
+ int encodeSingleI8(final byte normalI8, final int cIdx);
+ int encode3CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8);
+ int encode4CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8, final byte c4NormI8);
+
+ float toFloat(final int i32, final int cIdx, final boolean i32Shifted);
+ int fromFloat(final float f, final int cIdx, final boolean shiftResult);
+
+ int defaultValue(final int cIdx, final boolean shiftResult);
+
+ /**
+ * Returns cached immutable hash value, see {@link Object#hashCode()}.
+ */
+ int hashCode();
+ /**
+ * Returns {@link Object#equals(Object)}
+ */
+ boolean equals(final Object o);
+
+ /**
+ * Returns {@link Object#toString()}.
+ */
+ String toString();
+ }
+
+ /**
+ * Packed pixel composition, see {@link Composition}.
+ * <p>
+ * Components are interleaved, i.e. packed.
+ * </p>
+ */
+ public static class PackedComposition implements Composition {
+ private final CType[] compOrder;
+ private final int[] compMask;
+ private final int[] compBitCount;
+ private final int[] compBitShift;
+ private final int bitsPerPixel;
+ private final int bitStride;
+ private final boolean uniform;
+ private final int hashCode;
+
+ public final String toString() {
+ return String.format("PackedComp[order %s, stride %d, bpp %d, uni %b, comp %d: %s]",
+ Arrays.toString(compOrder), bitStride, bitsPerPixel, uniform,
+ compMask.length, toHexString(compBitCount, compMask, compBitShift));
+ }
+
+ /**
+ * @param componentOrder {@link CType Component type} order of all components, see {@link #componentBitMask()}.
+ * @param componentCount number of components
+ * @param bpc bits per component
+ * @param bitStride stride bits to next pixel
+ */
+ public PackedComposition(final CType[] componentOrder, final int componentCount, final int bpc, final int bitStride) {
+ this.compOrder = componentOrder;
+ this.compMask = new int[componentCount];
+ this.compBitShift = new int[componentCount];
+ this.compBitCount = new int[componentCount];
+ final int compMask = ( 1 << bpc ) - 1;
+ for(int i=0; i<componentCount; i++) {
+ this.compMask[i] = compMask;
+ this.compBitShift[i] = bpc * i;
+ this.compBitCount[i] = bpc;
+ }
+ this.uniform = true;
+ this.bitsPerPixel = bpc * componentCount;
+ this.bitStride = bitStride;
+ if( this.bitStride < this.bitsPerPixel ) {
+ throw new IllegalArgumentException(String.format("bit-stride %d < bitsPerPixel %d", this.bitStride, this.bitsPerPixel));
+ }
+ this.hashCode = hashCodeImpl();
+ }
- /** 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; }
+ /**
+ * @param componentOrder {@link CType Component type} order of all components, see {@link #componentBitMask()}.
+ * @param componentMask bit-mask of of all components, see {@link #componentBitMask()}.
+ * @param componentBitShift bit-shift of all components, see {@link #componentBitMask()}.
+ * @param bitStride stride bits to next pixel
+ */
+ public PackedComposition(final CType[] componentOrder, final int[] componentMask, final int[] componentBitShift, final int bitStride) {
+ this.compOrder = componentOrder;
+ this.compMask = componentMask;
+ this.compBitShift = componentBitShift;
+ this.compBitCount = new int[componentMask.length];
+ int bpp = 0;
+ boolean uniform = true;
+ for(int i = componentMask.length-1; i>=0; i--) {
+ final int cmask = componentMask[i];
+ final int bitCount = IntBitfield.getBitCount(cmask);
+ bpp += bitCount;
+ this.compBitCount[i] = bitCount;
+ if( i > 0 && uniform ) {
+ uniform = componentMask[i-1] == cmask;
+ }
+ }
+ this.uniform = uniform;
+ this.bitsPerPixel = bpp;
+ this.bitStride = bitStride;
+ if( this.bitStride < this.bitsPerPixel ) {
+ throw new IllegalArgumentException(String.format("bit-stride %d < bitsPerPixel %d", this.bitStride, this.bitsPerPixel));
+ }
+ this.hashCode = hashCodeImpl();
+ }
+
+ @Override
+ public final boolean isUniform() { return uniform; }
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Instances of {@link PackedComposition} returns {@code true}.
+ * </p>
+ */
+ @Override
+ public final boolean isInterleaved() { return true; }
+ @Override
+ public final int componenCount() { return compMask.length; }
+ @Override
+ public final int bitsPerPixel() { return bitsPerPixel; }
+ @Override
+ public final int bitStride() { return bitStride; }
+ @Override
+ public final int bytesPerPixel() { return (7+bitStride)/8; }
+ @Override
+ public final CType[] componentOrder() { return compOrder; }
+ @Override
+ public final int find(final PixelFormat.CType s) { return PixelFormatUtil.find(s, compOrder, false /* mapRGB2Y */); }
+ @Override
+ public final int[] componentBitMask() { return compMask; }
+ @Override
+ public final int[] componentBitCount() { return compBitCount; }
+ @Override
+ public final int[] componentBitShift() { return compBitShift; }
+
+ @Override
+ public final int decodeSingleI32(final int shifted, final int cIdx) {
+ return ( shifted >>> compBitShift[cIdx] ) & compMask[cIdx];
+ }
+ @Override
+ public final int decodeSingleI64(final long shifted, final int cIdx) {
+ return ( (int)( 0xffffffffL & ( shifted >>> compBitShift[cIdx] ) ) ) & compMask[cIdx];
+ }
+ @Override
+ public final int encodeSingleI32(final int norm, final int cIdx) {
+ return ( norm & compMask[cIdx] ) << compBitShift[cIdx] ;
+ }
+ @Override
+ public final long encodeSingleI64(final int norm, final int cIdx) {
+ return ( 0xffffffffL & ( norm & compMask[cIdx] ) ) << compBitShift[cIdx] ;
+ }
+ @Override
+ public final int encode3CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32) {
+ return ( c1NormI32 & compMask[0] ) << compBitShift[0] |
+ ( c2NormI32 & compMask[1] ) << compBitShift[1] |
+ ( c3NormI32 & compMask[2] ) << compBitShift[2] ;
+ }
+ @Override
+ public final int encode4CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32, final int c4NormI32) {
+ return ( c1NormI32 & compMask[0] ) << compBitShift[0] |
+ ( c2NormI32 & compMask[1] ) << compBitShift[1] |
+ ( c3NormI32 & compMask[2] ) << compBitShift[2] |
+ ( c4NormI32 & compMask[3] ) << compBitShift[3] ;
+ }
+ @Override
+ public final int encodeSingleI8(final byte normI8, final int cIdx) {
+ return ( normI8 & compMask[cIdx] ) << compBitShift[cIdx] ;
+ }
+ @Override
+ public final int encode3CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8) {
+ return ( c1NormI8 & compMask[0] ) << compBitShift[0] |
+ ( c2NormI8 & compMask[1] ) << compBitShift[1] |
+ ( c3NormI8 & compMask[2] ) << compBitShift[2] ;
+ }
+ @Override
+ public final int encode4CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8, final byte c4NormI8) {
+ return ( c1NormI8 & compMask[0] ) << compBitShift[0] |
+ ( c2NormI8 & compMask[1] ) << compBitShift[1] |
+ ( c3NormI8 & compMask[2] ) << compBitShift[2] |
+ ( c4NormI8 & compMask[3] ) << compBitShift[3] ;
+ }
+
+ @Override
+ public final float toFloat(final int i32, final int cIdx, final boolean i32Shifted) {
+ if( i32Shifted ) {
+ return ( ( i32 >>> compBitShift[cIdx] ) & compMask[cIdx] ) / (float)( compMask[cIdx] ) ;
+ } else {
+ return ( i32 & compMask[cIdx] ) / (float)( compMask[cIdx] ) ;
+ }
+ }
+ @Override
+ public final int fromFloat(final float f, final int cIdx, final boolean shiftResult) {
+ final int v = (int)(f * compMask[cIdx] + 0.5f);
+ return shiftResult ? v << compBitShift[cIdx] : v;
+ }
+
+ @Override
+ public final int defaultValue(final int cIdx, final boolean shiftResult) {
+ final int v = ( CType.A == compOrder[cIdx] || CType.Y == compOrder[cIdx] )
+ ? compMask[cIdx] : 0;
+ return shiftResult ? v << compBitShift[cIdx] : v;
+ }
+
+ @Override
+ public final int hashCode() { return hashCode; }
+ private final int hashCodeImpl() {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + bitStride;
+ hash = ((hash << 5) - hash) + bitsPerPixel;
+ hash = ((hash << 5) - hash) + compMask.length;
+ for(int i=compOrder.length-1; i>=0; i--) {
+ hash = ((hash << 5) - hash) + compOrder[i].ordinal();
+ }
+ for(int i=compMask.length-1; i>=0; i--) {
+ hash = ((hash << 5) - hash) + compMask[i];
+ }
+ for(int i=compBitShift.length-1; i>=0; i--) {
+ hash = ((hash << 5) - hash) + compBitShift[i];
+ }
+ return hash;
+ }
+
+ @Override
+ public final boolean equals(final Object obj) {
+ if(this == obj) { return true; }
+ if( obj instanceof PackedComposition ) {
+ final PackedComposition other = (PackedComposition) obj;
+ return bitStride == other.bitStride &&
+ bitsPerPixel == other.bitsPerPixel &&
+ Arrays.equals(compOrder, other.compOrder) &&
+ Arrays.equals(compMask, other.compMask) &&
+ Arrays.equals(compBitShift, other.compBitShift);
+ } else {
+ return false;
+ }
+ }
+ }
- private PixelFormat(final int componentCount, final int bpp) {
- this.componentCount = componentCount;
- this.bitsPerPixel = bpp;
+ private static String toHexString(final int[] bitCount, final int[] mask, final int[] shift) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ final int l = mask.length;
+ for(int i=0; i < l; i++) {
+ if(i > 0) {
+ sb.append(", ");
+ }
+ sb.append(bitCount[i]).append(": ").
+ append("0x").append(Integer.toHexString(mask[i])).append(" << ").append(shift[i]);
+ }
+ return sb.append("]").toString();
}
}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
index 21bfa8a54..a449f8706 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
@@ -27,10 +27,12 @@
*/
package javax.media.nativewindow.util;
+import java.io.IOException;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
+import java.util.Arrays;
import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.util.Bitstream;
/**
* Pixel Rectangle Utilities.
@@ -39,46 +41,157 @@ import com.jogamp.common.nio.Buffers;
* </p>
*/
public class PixelFormatUtil {
- public static interface PixelSink {
- /** Return the sink's destination pixelformat. */
- PixelFormat getPixelformat();
+ private static boolean DEBUG = false;
+ public static class ComponentMap {
/**
- * 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>
+ * Contains the source index for each destination index,
+ * length is {@link Composition#componenCount()} of destination.
*/
- int getStride();
+ final int[] dst2src;
+ /**
+ * Contains the destination index for each source index,
+ * length is {@link Composition#componenCount()} of source.
+ */
+ final int[] src2dst;
/**
- * 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>.
+ * Contains the source index of RGBA components.
*/
- boolean isGLOriented();
+ final int[] srcRGBA;
+ final boolean hasSrcRGB;
+
+ public ComponentMap(final PixelFormat.Composition src, final PixelFormat.Composition dst) {
+ final int sCompCount = src.componenCount();
+ final int dCompCount = dst.componenCount();
+ final PixelFormat.CType[] sCompOrder = src.componentOrder();
+ final PixelFormat.CType[] dCompOrder = dst.componentOrder();
+
+ dst2src = new int[dCompCount];
+ for(int dIdx=0; dIdx<dCompCount; dIdx++) {
+ dst2src[dIdx] = PixelFormatUtil.find(dCompOrder[dIdx], sCompOrder, true);
+ }
+ src2dst = new int[sCompCount];
+ for(int sIdx=0; sIdx<sCompCount; sIdx++) {
+ src2dst[sIdx] = PixelFormatUtil.find(sCompOrder[sIdx], dCompOrder, true);
+ }
+ srcRGBA = new int[4];
+ srcRGBA[0] = PixelFormatUtil.find(PixelFormat.CType.R, sCompOrder, false);
+ srcRGBA[1] = PixelFormatUtil.find(PixelFormat.CType.G, sCompOrder, false);
+ srcRGBA[2] = PixelFormatUtil.find(PixelFormat.CType.B, sCompOrder, false);
+ srcRGBA[3] = PixelFormatUtil.find(PixelFormat.CType.A, sCompOrder, false);
+ hasSrcRGB = 0 <= srcRGBA[0] && 0 <= srcRGBA[1] && 0 <= srcRGBA[2];
+ }
}
+
+ public static final int find(final PixelFormat.CType s,
+ final PixelFormat.CType[] pool, final boolean mapRGB2Y) {
+ int i=pool.length-1;
+ while( i >= 0 && pool[i] != s) { i--; }
+
+ if( 0 > i && mapRGB2Y && 1 == pool.length && pool[0] == PixelFormat.CType.Y &&
+ ( PixelFormat.CType.R == s ||
+ PixelFormat.CType.G == s ||
+ PixelFormat.CType.B == s ) )
+ {
+ // Special case, fallback for RGB mapping -> LUMINANCE/Y
+ return 0;
+ } else {
+ return i;
+ }
+ }
+
/**
- * Pixel sink for up-to 32bit.
+ * Returns shifted bytes from the given {@code data} at given {@code offset}
+ * of maximal 4 {@code bytesPerPixel}.
+ * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
+ * @param data byte buffer covering complete pixel at position {@code offset}
+ * @param offset byte offset of pixel {@code data} start
+ * @return the shifted 32bit integer value of the pixel
*/
- 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);
+ public static int getShiftedI32(final int bytesPerPixel, final byte[] data, final int offset) {
+ if( bytesPerPixel <= 4 ) {
+ int shiftedI32 = 0;
+ for(int i=0; i<bytesPerPixel; i++) {
+ shiftedI32 |= ( 0xff & data[offset+i] ) << 8*i;
+ }
+ return shiftedI32;
+ } else {
+ throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4");
+ }
+ }
+ /**
+ * Returns shifted bytes from the given {@code data} at given {@code offset}
+ * of maximal 8 {@code bytesPerPixel}.
+ * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
+ * @param data byte buffer covering complete pixel at position {@code offset}
+ * @param offset byte offset of pixel {@code data} start
+ * @return the shifted 64bit integer value of the pixel
+ */
+ public static long getShiftedI64(final int bytesPerPixel, final byte[] data, final int offset) {
+ if( bytesPerPixel <= 8 ) {
+ long shiftedI64 = 0;
+ for(int i=0; i<bytesPerPixel; i++) {
+ shiftedI64 |= ( 0xff & data[offset+i] ) << 8*i;
+ }
+ return shiftedI64;
+ } else {
+ throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8");
+ }
+ }
+ /**
+ * Returns shifted bytes from the given {@code data} at current position
+ * of maximal 4 {@code bytesPerPixel}.
+ * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
+ * @param data byte buffer covering complete pixel at position {@code offset}
+ * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged.
+ * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes.
+ * @return the shifted 32bit integer value of the pixel
+ */
+ public static int getShiftedI32(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) {
+ if( bytesPerPixel <= 4 ) {
+ int shiftedI32 = 0;
+ if( retainDataPos ) {
+ final int offset = data.position();
+ for(int i=0; i<bytesPerPixel; i++) {
+ shiftedI32 |= ( 0xff & data.get(offset+i) ) << 8*i;
+ }
+ } else {
+ for(int i=0; i<bytesPerPixel; i++) {
+ shiftedI32 |= ( 0xff & data.get() ) << 8*i;
+ }
+ }
+ return shiftedI32;
+ } else {
+ throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4");
+ }
+ }
+ /**
+ * Returns shifted bytes from the given {@code data} at current position
+ * of maximal 8 {@code bytesPerPixel}.
+ * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
+ * @param data byte buffer covering complete pixel at position {@code offset}
+ * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged.
+ * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes.
+ * @return the shifted 64bit integer value of the pixel
+ */
+ public static long getShiftedI64(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) {
+ if( bytesPerPixel <= 8 ) {
+ long shiftedI64 = 0;
+ if( retainDataPos ) {
+ final int offset = data.position();
+ for(int i=0; i<bytesPerPixel; i++) {
+ shiftedI64 |= ( 0xff & data.get(offset+i) ) << 8*i;
+ }
+ } else {
+ for(int i=0; i<bytesPerPixel; i++) {
+ shiftedI64 |= ( 0xff & data.get() ) << 8*i;
+ }
+ }
+ return shiftedI64;
+ } else {
+ throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8");
+ }
}
/**
@@ -87,8 +200,14 @@ public class PixelFormatUtil {
*/
public static PixelFormat getReversed(final PixelFormat fmt) {
switch(fmt) {
- case LUMINANCE:
- return PixelFormat.LUMINANCE;
+ case RGB565:
+ return PixelFormat.BGR565;
+ case BGR565:
+ return PixelFormat.RGB565;
+ case RGBA5551:
+ return PixelFormat.ABGR1555;
+ case ABGR1555:
+ return PixelFormat.RGBA5551;
case RGB888:
return PixelFormat.BGR888;
case BGR888:
@@ -102,42 +221,14 @@ public class PixelFormatUtil {
case BGRA8888:
return PixelFormat.ABGR8888;
default:
- throw new InternalError("Unhandled format "+fmt);
+ return fmt;
}
}
- public static int getValue32(final PixelFormat src_fmt, final ByteBuffer src, int srcOff) {
- switch(src_fmt) {
+ public static int convertToInt32(final PixelFormat dst_fmt, final byte r, final byte g, final byte b, final byte a) {
+ switch(dst_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(final 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 ) );
+ final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) * a );
return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l );
}
case RGB888:
@@ -153,11 +244,11 @@ public class PixelFormatUtil {
case BGRA8888:
return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
default:
- throw new InternalError("Unhandled format "+dest_fmt);
+ throw new InternalError("Unhandled format "+dst_fmt);
}
}
- public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) {
+ public static int convertToInt32(final PixelFormat dst_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) {
final byte r, g, b, a;
switch(src_fmt) {
case LUMINANCE:
@@ -205,7 +296,7 @@ public class PixelFormatUtil {
default:
throw new InternalError("Unhandled format "+src_fmt);
}
- return convertToInt32(dest_fmt, r, g, b, a);
+ return convertToInt32(dst_fmt, r, g, b, a);
}
public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final int src_pixel) {
@@ -259,115 +350,251 @@ public class PixelFormatUtil {
return convertToInt32(dest_fmt, r, g, b, a);
}
- public static PixelRectangle convert32(final PixelRectangle src,
- final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented,
- final boolean destIsDirect) {
+ public static PixelRectangle convert(final PixelRectangle src,
+ final PixelFormat destFmt, final 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 bpp = destFmt.comp.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(final int x, final int y, final 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);
+ final ByteBuffer destBB = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order());
+ convert(src, destBB, destFmt, isGLOriented, destStride);
+ return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, destBB);
}
- public static void convert32(final PixelSink32 destInt32, final PixelRectangle src) {
- convert32(destInt32,
- src.getPixels(), src.getPixelformat(),
- src.isGLOriented(),
- src.getSize().getWidth(), src.getSize().getHeight(),
- src.getStride());
+ /**
+ * @param src
+ * @param dst_bb {@link ByteBuffer} sink
+ * @param dst_fmt destination {@link PixelFormat}
+ * @param dst_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 dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next.
+ * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width
+ * or {@code zero} for default stride.
+ *
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid
+ */
+ public static void convert(final PixelRectangle src,
+ final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, final int dst_lineStride)
+ throws IllegalStateException
+ {
+ convert(src.getSize().getWidth(), src.getSize().getHeight(),
+ src.getPixels(), src.getPixelformat(), src.isGLOriented(), src.getStride(),
+ dst_bb, dst_fmt, dst_glOriented, dst_lineStride);
}
+
/**
- *
- * @param dest32 32bit pixel sink
- * @param src_bb
- * @param src_fmt
+ * @param width width of the to be converted pixel rectangle
+ * @param height height of the to be converted pixel rectangle
+ * @param src_bb {@link ByteBuffer} source
+ * @param src_fmt source {@link PixelFormat}
* @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
+ * @param src_lineStride line stride in byte-size for source, i.e. byte count from one line to the next.
+ * Must be >= {@link PixelFormat.Composition#bytesPerPixel() src_fmt.comp.bytesPerPixel()} * width
+ * or {@code zero} for default stride.
+ * @param dst_bb {@link ByteBuffer} sink
+ * @param dst_fmt destination {@link PixelFormat}
+ * @param dst_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 dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next.
+ * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width
+ * or {@code zero} for default stride.
+ *
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid
*/
- public static void convert32(final 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);
+ public static void convert(final int width, final int height,
+ final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, int src_lineStride,
+ final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, int dst_lineStride
+ ) throws IllegalStateException, IllegalArgumentException {
+ final PixelFormat.Composition src_comp = src_fmt.comp;
+ final PixelFormat.Composition dst_comp = dst_fmt.comp;
+ final int src_bpp = src_comp.bytesPerPixel();
+ final int dst_bpp = dst_comp.bytesPerPixel();
+
+ if( 0 != src_lineStride ) {
+ if( src_lineStride < src_bpp * width ) {
+ throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d",
+ "source", src_lineStride, src_bpp, width));
}
} else {
- stride_bytes = src_bpp * width;
+ src_lineStride = src_bpp * width;
+ }
+ if( 0 != dst_lineStride ) {
+ if( dst_lineStride < dst_bpp * width ) {
+ throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d",
+ "destination", dst_lineStride, dst_bpp, width));
+ }
+ } else {
+ dst_lineStride = dst_bpp * width;
+ }
+
+ // final int src_comp_bitStride = src_comp.bitStride();
+ final int dst_comp_bitStride = dst_comp.bitStride();
+ final boolean vert_flip = src_glOriented != dst_glOriented;
+ final boolean fast_copy = src_comp.equals(dst_comp) && 0 == dst_comp_bitStride%8;
+ if( DEBUG ) {
+ System.err.println("XXX: size "+width+"x"+height+", fast_copy "+fast_copy);
+ System.err.println("XXX: SRC fmt "+src_fmt+", "+src_comp+", stride "+src_lineStride+", isGLOrient "+src_glOriented);
+ System.err.println("XXX: DST fmt "+dst_fmt+", "+dst_comp+", stride "+dst_lineStride+", isGLOrient "+dst_glOriented);
}
- 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;
+ int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride : y * src_lineStride;
+ int dst_off = dst_lineStride*y;
for(int x=0; x<width; x++) {
- dest32.store(x, y, getValue32(src_fmt, src_bb, o));
- o += src_bpp;
+ dst_bb.put(dst_off+0, src_bb.get(src_off+0)); // 1
+ if( 2 <= dst_bpp ) {
+ dst_bb.put(dst_off+1, src_bb.get(src_off+1)); // 2
+ if( 3 <= dst_bpp ) {
+ dst_bb.put(dst_off+2, src_bb.get(src_off+2)); // 3
+ if( 4 <= dst_bpp ) {
+ dst_bb.put(dst_off+3, src_bb.get(src_off+3)); // 4
+ }
+ }
+ }
+ src_off += src_bpp;
+ dst_off += dst_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;
+ final ComponentMap cmap = new ComponentMap(src_fmt.comp, dst_fmt.comp);
+
+ final Bitstream.ByteBufferStream srcBBS = new Bitstream.ByteBufferStream(src_bb);
+ final Bitstream<ByteBuffer> srcBitStream = new Bitstream<ByteBuffer>(srcBBS, false /* outputMode */);
+ srcBitStream.setThrowIOExceptionOnEOF(true);
+
+ final Bitstream.ByteBufferStream dstBBS = new Bitstream.ByteBufferStream(dst_bb);
+ final Bitstream<ByteBuffer> dstBitStream = new Bitstream<ByteBuffer>(dstBBS, true /* outputMode */);
+ dstBitStream.setThrowIOExceptionOnEOF(true);
+
+ if( DEBUG ) {
+ System.err.println("XXX: cmap.dst2src "+Arrays.toString(cmap.dst2src));
+ System.err.println("XXX: cmap.src2dst "+Arrays.toString(cmap.src2dst));
+ System.err.println("XXX: cmap.srcRGBA "+Arrays.toString(cmap.srcRGBA));
+ System.err.println("XXX: srcBitStream "+srcBitStream);
+ System.err.println("XXX: dstBitStream "+dstBitStream);
+ }
+ try {
+ for(int y=0; y<height; y++) {
+ final int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride * 8 : y * src_lineStride * 8;
+ // final int dst_off = dst_lineStride*8*y;
+ srcBitStream.position(src_off);
+ for(int x=0; x<width; x++) {
+ convert(cmap, dst_comp, dstBitStream, src_comp, srcBitStream);
+ }
+ // srcBitStream.skip(( src_lineStride * 8 ) - ( src_comp_bitStride * width ));
+ dstBitStream.skip(( dst_lineStride * 8 ) - ( dst_comp_bitStride * width ));
+ }
+ } catch(final IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ if( DEBUG ) {
+ System.err.println("XXX: srcBitStream "+srcBitStream);
+ System.err.println("XXX: dstBitStream "+dstBitStream);
+ }
+ }
+ }
+
+ public static void convert(final ComponentMap cmap,
+ final PixelFormat.Composition dstComp,
+ final Bitstream<ByteBuffer> dstBitStream,
+ final PixelFormat.Composition srcComp,
+ final Bitstream<ByteBuffer> srcBitStream) throws IllegalStateException, IOException {
+ final int sCompCount = srcComp.componenCount();
+ final int dCompCount = dstComp.componenCount();
+ final int[] sc = new int[sCompCount];
+ final int[] dcDef = new int[dCompCount];
+ final int[] srcCompBitCount = srcComp.componentBitCount();
+ final int[] srcCompBitMask = srcComp.componentBitMask();
+ final int[] dstCompBitCount = dstComp.componentBitCount();
+
+ // Fill w/ source values
+ for(int sIdx=0; sIdx<sCompCount; sIdx++) {
+ sc[sIdx] = srcBitStream.readBits31(srcCompBitCount[sIdx]) & srcCompBitMask[sIdx];
+ }
+ srcBitStream.skip(srcComp.bitStride() - srcComp.bitsPerPixel());
+
+ // Cache missing defaults
+ for(int i=0; i<dCompCount; i++) {
+ dcDef[i] = dstComp.defaultValue(i, false);
+ }
+
+ if( 1 == dCompCount &&
+ PixelFormat.CType.Y == dstComp.componentOrder()[0] &&
+ cmap.hasSrcRGB
+ )
+ {
+ // RGB[A] -> Y conversion
+ final int r = sc[cmap.srcRGBA[0]];
+ final int g = sc[cmap.srcRGBA[1]];
+ final int b = sc[cmap.srcRGBA[2]];
+ final float rF = srcComp.toFloat(r, cmap.srcRGBA[0], false);
+ final float gF = srcComp.toFloat(g, cmap.srcRGBA[1], false);
+ final float bF = srcComp.toFloat(b, cmap.srcRGBA[2], false);
+ final int a;
+ final float aF;
+ /** if( 0 <= cmap.srcRGBA[3] ) { // disable premultiplied-alpha
+ a = sc[cmap.srcRGBA[3]];
+ aF = srcComp.toFloat(a, false, cmap.srcRGBA[3]);
+ } else */ {
+ a = 1;
+ aF = 1f;
+ }
+ final float lF = ( rF + gF + bF ) * aF / 3f;
+ final int v = dstComp.fromFloat(lF, 0, false);
+
+ dstBitStream.writeBits31(dstCompBitCount[0], v);
+ dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
+ if( DEBUG ) {
+ if( srcBitStream.position() <= 8*4 ) {
+ System.err.printf("convert: rgb[a] -> Y: rgb 0x%02X 0x%02X 0x%02X 0x%02X -> %f %f %f %f"+
+ " -> %f -> dstC 0 0x%08X (%d bits: %s)%n",
+ r, g, b, a,
+ rF, gF, bF, aF,
+ lF, v, dstCompBitCount[0], Bitstream.toBinString(true, v, dstCompBitCount[0])
+ );
+ }
+ }
+ return;
+ }
+
+ for(int dIdx=0; dIdx<dCompCount; dIdx++) {
+ int sIdx;
+ if( 0 <= ( sIdx = cmap.dst2src[dIdx] ) ) {
+ final float f = srcComp.toFloat(sc[sIdx], sIdx, false);
+ final int v = dstComp.fromFloat(f, dIdx, false);
+ dstBitStream.writeBits31(dstCompBitCount[dIdx], v);
+ if( DEBUG ) {
+ if( srcBitStream.position() <= 8*4 ) {
+ System.err.printf("convert: srcC %d: 0x%08X -> %f -> dstC %d 0x%08X (%d bits: %s)%n",
+ sIdx, sc[sIdx], f, dIdx, v, dstCompBitCount[dIdx], Bitstream.toBinString(true, v, dstCompBitCount[dIdx]));
+ }
+ }
+ } else {
+ dstBitStream.writeBits31(dstCompBitCount[dIdx], dcDef[dIdx]);
+ if( DEBUG ) {
+ if( srcBitStream.position() <= 8*4 ) {
+ System.err.printf("convert: srcC %d: undef -> dstC %d 0x%08X (%d bits: %s)%n",
+ sIdx, dIdx, dcDef[dIdx], dstCompBitCount[dIdx], Bitstream.toBinString(true, dcDef[dIdx], dstCompBitCount[dIdx]));
+ }
}
}
}
+ dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
+ return;
}
}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java
index 96c1f7b33..f4fc99aee 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java
@@ -113,11 +113,11 @@ public interface PixelRectangle {
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());
+ if( strideInBytes < pixelformat.comp.bytesPerPixel() * size.getWidth()) {
+ throw new IllegalArgumentException("Invalid stride "+strideInBytes+", must be greater than bytesPerPixel "+pixelformat.comp.bytesPerPixel()+" * width "+size.getWidth());
}
} else {
- strideInBytes = pixelformat.bytesPerPixel() * size.getWidth();
+ strideInBytes = pixelformat.comp.bytesPerPixel() * size.getWidth();
}
final int reqBytes = strideInBytes * size.getHeight();
if( pixels.limit() < reqBytes ) {
@@ -148,7 +148,7 @@ public interface PixelRectangle {
synchronized (this) {
if( !hashCodeComputed ) {
// 31 * x == (x << 5) - x
- int hash = 31 + pixelformat.hashCode();
+ int hash = pixelformat.comp.hashCode();
hash = ((hash << 5) - hash) + size.hashCode();
hash = ((hash << 5) - hash) + strideInBytes;
hash = ((hash << 5) - hash) + ( isGLOriented ? 1 : 0);