aboutsummaryrefslogtreecommitdiffstats
path: root/src/classes/com/sun/opengl/util/texture/TextureData.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/classes/com/sun/opengl/util/texture/TextureData.java')
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/TextureData.java280
1 files changed, 153 insertions, 127 deletions
diff --git a/src/classes/com/sun/opengl/util/texture/TextureData.java b/src/classes/com/sun/opengl/util/texture/TextureData.java
index d03faa697..39075e387 100755
--- a/src/classes/com/sun/opengl/util/texture/TextureData.java
+++ b/src/classes/com/sun/opengl/util/texture/TextureData.java
@@ -73,9 +73,18 @@ public class TextureData {
private Buffer buffer; // the actual data...
private Buffer[] mipmapData; // ...or a series of mipmaps
private Flusher flusher;
+ private int rowLength;
private int alignment; // 1, 2, or 4 bytes
private int estimatedMemorySize;
+ // Mechanism for lazily converting input BufferedImages with custom
+ // ColorModels to standard ones for uploading to OpenGL, as well as
+ // backing off from the optimization of hoping that GL_EXT_abgr is
+ // present
+ private BufferedImage imageForLazyCustomConversion;
+ private boolean expectingEXTABGR;
+ private boolean haveEXTABGR;
+
private static final ColorModel rgbaColorModel =
new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[] {8, 8, 8, 8}, true, true,
@@ -220,12 +229,12 @@ public class TextureData {
/**
* Constructs a new TextureData object with the specified parameters
- * and data contained in the given BufferedImage. Note that
- * subsequent modifications to the BufferedImage after the
- * construction of the TextureData object are not guaranteed to be
- * visible in any Texture object created from the TextureData (and,
- * in fact, the expectation should be that they will not be visible,
- * although this behavior is explicitly left undefined).
+ * and data contained in the given BufferedImage. The resulting
+ * TextureData "wraps" the contents of the BufferedImage, so if a
+ * modification is made to the BufferedImage between the time the
+ * TextureData is constructed and when a Texture is made from the
+ * TextureData, that modification will be visible in the resulting
+ * Texture.
*
* @param internalFormat the OpenGL internal format for the
* resulting texture; may be 0, in which case
@@ -273,12 +282,26 @@ public class TextureData {
vertically for proper display. */
public boolean getMustFlipVertically() { return mustFlipVertically; }
/** Returns the texture data, or null if it is specified as a set of mipmaps. */
- public Buffer getBuffer() { return buffer; }
+ public Buffer getBuffer() {
+ if (imageForLazyCustomConversion != null) {
+ if (!expectingEXTABGR ||
+ (expectingEXTABGR && !haveEXTABGR)) {
+ // Must present the illusion to the end user that we are simply
+ // wrapping the input BufferedImage
+ createFromCustom(imageForLazyCustomConversion);
+ }
+ }
+ return buffer;
+ }
/** Returns all mipmap levels for the texture data, or null if it is
specified as a single image. */
public Buffer[] getMipmapData() { return mipmapData; }
/** Returns the required byte alignment for the texture data. */
public int getAlignment() { return alignment; }
+ /** Returns the row length needed for correct GL_UNPACK_ROW_LENGTH
+ specification. This is currently only supported for
+ non-mipmapped, non-compressed textures. */
+ public int getRowLength() { return rowLength; }
/** Sets the width in pixels of the texture data. */
public void setWidth(int width) { this.width = width; }
@@ -303,6 +326,16 @@ public class TextureData {
public void setBuffer(Buffer buffer) { this.buffer = buffer; }
/** Sets the required byte alignment for the texture data. */
public void setAlignment(int alignment) { this.alignment = alignment; }
+ /** Sets the row length needed for correct GL_UNPACK_ROW_LENGTH
+ specification. This is currently only supported for
+ non-mipmapped, non-compressed textures. */
+ public void setRowLength(int rowLength) { this.rowLength = rowLength; }
+ /** Indicates to this TextureData whether the GL_EXT_abgr extension
+ is available. Used for optimization along some code paths to
+ avoid data copies. */
+ public void setHaveEXTABGR(boolean haveEXTABGR) {
+ this.haveEXTABGR = haveEXTABGR;
+ }
/** Returns an estimate of the amount of memory in bytes this
TextureData will consume once uploaded to the graphics card. It
@@ -335,176 +368,145 @@ public class TextureData {
// Internals only below this point
//
- private void createNIOBufferFromImage(BufferedImage image, boolean flipVertically) {
- if (flipVertically) {
- ImageUtil.flipImageVertically(image);
- }
-
- try {
- //
- // Note: Grabbing the DataBuffer will defeat Java2D's image
- // management mechanism (as of JDK 5/6, at least). This shouldn't
- // be a problem for most JOGL apps, but those that try to upload
- // the image into an OpenGL texture and then use the same image in
- // Java2D rendering might find the 2D rendering is not as fast as
- // it could be.
- //
-
- // Allow previously-selected pixelType (if any) to override that
- // we can infer from the DataBuffer
- DataBuffer data = image.getRaster().getDataBuffer();
- if (data instanceof DataBufferByte) {
- if (pixelType == 0) pixelType = GL.GL_UNSIGNED_BYTE;
- buffer = ByteBuffer.wrap(copyIfNecessary(((DataBufferByte) data).getData(), flipVertically));
- } else if (data instanceof DataBufferDouble) {
- throw new RuntimeException("DataBufferDouble rasters not supported by OpenGL");
- } else if (data instanceof DataBufferFloat) {
- if (pixelType == 0) pixelType = GL.GL_FLOAT;
- buffer = FloatBuffer.wrap(copyIfNecessary(((DataBufferFloat) data).getData(), flipVertically));
- } else if (data instanceof DataBufferInt) {
- // FIXME: should we support signed ints?
- if (pixelType == 0) pixelType = GL.GL_UNSIGNED_INT;
- buffer = IntBuffer.wrap(copyIfNecessary(((DataBufferInt) data).getData(), flipVertically));
- } else if (data instanceof DataBufferShort) {
- if (pixelType == 0) pixelType = GL.GL_SHORT;
- buffer = ShortBuffer.wrap(copyIfNecessary(((DataBufferShort) data).getData(), flipVertically));
- } else if (data instanceof DataBufferUShort) {
- if (pixelType == 0) pixelType = GL.GL_UNSIGNED_SHORT;
- buffer = ShortBuffer.wrap(copyIfNecessary(((DataBufferShort) data).getData(), flipVertically));
- } else {
- throw new RuntimeException("Unexpected DataBuffer type?");
- }
- } finally {
- // Put image back right-side up if necessary
- if (flipVertically) {
- ImageUtil.flipImageVertically(image);
- }
- }
- }
-
- private byte[] copyIfNecessary(byte[] data, boolean needsCopy) {
- if (needsCopy) {
- return (byte[]) data.clone();
- }
- return data;
- }
-
- private short[] copyIfNecessary(short[] data, boolean needsCopy) {
- if (needsCopy) {
- return (short[]) data.clone();
- }
- return data;
- }
-
- private int[] copyIfNecessary(int[] data, boolean needsCopy) {
- if (needsCopy) {
- return (int[]) data.clone();
- }
- return data;
- }
-
- private float[] copyIfNecessary(float[] data, boolean needsCopy) {
- if (needsCopy) {
- return (float[]) data.clone();
- }
- return data;
- }
-
- private double[] copyIfNecessary(double[] data, boolean needsCopy) {
- if (needsCopy) {
- return (double[]) data.clone();
+ private void createNIOBufferFromImage(BufferedImage image) {
+ //
+ // Note: Grabbing the DataBuffer will defeat Java2D's image
+ // management mechanism (as of JDK 5/6, at least). This shouldn't
+ // be a problem for most JOGL apps, but those that try to upload
+ // the image into an OpenGL texture and then use the same image in
+ // Java2D rendering might find the 2D rendering is not as fast as
+ // it could be.
+ //
+
+ DataBuffer data = image.getRaster().getDataBuffer();
+ if (data instanceof DataBufferByte) {
+ buffer = ByteBuffer.wrap(((DataBufferByte) data).getData());
+ } else if (data instanceof DataBufferDouble) {
+ throw new RuntimeException("DataBufferDouble rasters not supported by OpenGL");
+ } else if (data instanceof DataBufferFloat) {
+ buffer = FloatBuffer.wrap(((DataBufferFloat) data).getData());
+ } else if (data instanceof DataBufferInt) {
+ buffer = IntBuffer.wrap(((DataBufferInt) data).getData());
+ } else if (data instanceof DataBufferShort) {
+ buffer = ShortBuffer.wrap(((DataBufferShort) data).getData());
+ } else if (data instanceof DataBufferUShort) {
+ buffer = ShortBuffer.wrap(((DataBufferUShort) data).getData());
+ } else {
+ throw new RuntimeException("Unexpected DataBuffer type?");
}
- return data;
}
-
private void createFromImage(BufferedImage image) {
pixelType = 0; // Determine from image
+ mustFlipVertically = true;
width = image.getWidth();
height = image.getHeight();
+ int scanlineStride;
+ SampleModel sm = image.getRaster().getSampleModel();
+ if (sm instanceof SinglePixelPackedSampleModel) {
+ scanlineStride =
+ ((SinglePixelPackedSampleModel)sm).getScanlineStride();
+ } else if (sm instanceof MultiPixelPackedSampleModel) {
+ scanlineStride =
+ ((MultiPixelPackedSampleModel)sm).getScanlineStride();
+ } else if (sm instanceof ComponentSampleModel) {
+ scanlineStride =
+ ((ComponentSampleModel)sm).getScanlineStride();
+ } else {
+ // This will only happen for TYPE_CUSTOM anyway
+ setupLazyCustomConversion(image);
+ return;
+ }
+
switch (image.getType()) {
case BufferedImage.TYPE_INT_RGB:
pixelFormat = GL.GL_BGRA;
pixelType = GL.GL_UNSIGNED_INT_8_8_8_8_REV;
+ rowLength = scanlineStride;
alignment = 4;
break;
+ case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
pixelFormat = GL.GL_BGRA;
pixelType = GL.GL_UNSIGNED_INT_8_8_8_8_REV;
+ rowLength = scanlineStride;
alignment = 4;
break;
case BufferedImage.TYPE_INT_BGR:
pixelFormat = GL.GL_RGBA;
pixelType = GL.GL_UNSIGNED_INT_8_8_8_8_REV;
+ rowLength = scanlineStride;
alignment = 4;
break;
case BufferedImage.TYPE_3BYTE_BGR:
{
- Raster raster = image.getRaster();
- ComponentSampleModel csm =
- (ComponentSampleModel)raster.getSampleModel();
// we can pass the image data directly to OpenGL only if
- // the raster is tightly packed (i.e. there is no extra
- // space at the end of each scanline)
- if ((csm.getScanlineStride() / 3) == csm.getWidth()) {
+ // we have an integral number of pixels in each scanline
+ if ((scanlineStride % 3) == 0) {
pixelFormat = GL.GL_BGR;
pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 3;
alignment = 1;
} else {
- createFromCustom(image);
+ setupLazyCustomConversion(image);
return;
}
}
break;
+ case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
{
- Raster raster = image.getRaster();
- ComponentSampleModel csm =
- (ComponentSampleModel)raster.getSampleModel();
// we can pass the image data directly to OpenGL only if
- // the raster is tightly packed (i.e. there is no extra
- // space at the end of each scanline) and only if the
- // GL_EXT_abgr extension is present
-
- // FIXME: with the way this is currently organized we can't
- // probe for the existence of the GL_EXT_abgr extension
- // here; disable this code path for now
- if (((csm.getScanlineStride() / 4) == csm.getWidth()) &&
- /* gl.isExtensionAvailable("GL_EXT_abgr") */ false)
- {
- pixelFormat = GL.GL_ABGR_EXT;
- pixelType = GL.GL_UNSIGNED_BYTE;
- alignment = 4;
- } else {
- createFromCustom(image);
- return;
- }
+ // we have an integral number of pixels in each scanline
+ // and only if the GL_EXT_abgr extension is present
+
+ // NOTE: disabling this code path for now as it appears it's
+ // buggy at least on some NVidia drivers and doesn't perform
+ // the necessary byte swapping (FIXME: needs more
+ // investigation)
+ if ((scanlineStride % 4) == 0 && false) {
+ pixelFormat = GL.GL_ABGR_EXT;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 4;
+ alignment = 4;
+
+ // Store a reference to the original image for later in
+ // case it turns out that we don't have GL_EXT_abgr at the
+ // time we're going to do the texture upload to OpenGL
+ setupLazyCustomConversion(image);
+ expectingEXTABGR = true;
+ break;
+ } else {
+ setupLazyCustomConversion(image);
+ return;
+ }
}
- break;
case BufferedImage.TYPE_USHORT_565_RGB:
pixelFormat = GL.GL_RGB;
pixelType = GL.GL_UNSIGNED_SHORT_5_6_5;
+ rowLength = scanlineStride;
alignment = 2;
break;
case BufferedImage.TYPE_USHORT_555_RGB:
pixelFormat = GL.GL_BGRA;
pixelType = GL.GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ rowLength = scanlineStride;
alignment = 2;
break;
case BufferedImage.TYPE_BYTE_GRAY:
pixelFormat = GL.GL_LUMINANCE;
pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride;
alignment = 1;
break;
case BufferedImage.TYPE_USHORT_GRAY:
pixelFormat = GL.GL_LUMINANCE;
pixelType = GL.GL_UNSIGNED_SHORT;
+ rowLength = scanlineStride;
alignment = 2;
break;
- case BufferedImage.TYPE_INT_ARGB:
- case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_BYTE_BINARY:
case BufferedImage.TYPE_BYTE_INDEXED:
case BufferedImage.TYPE_CUSTOM:
@@ -513,19 +515,49 @@ public class TextureData {
if (cm.equals(rgbColorModel)) {
pixelFormat = GL.GL_RGB;
pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 4; // FIXME: correct?
alignment = 1;
} else if (cm.equals(rgbaColorModel)) {
pixelFormat = GL.GL_RGBA;
pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 4; // FIXME: correct?
alignment = 4;
} else {
- createFromCustom(image);
+ setupLazyCustomConversion(image);
return;
}
break;
}
- createNIOBufferFromImage(image, true);
+ createNIOBufferFromImage(image);
+ }
+
+ private void setupLazyCustomConversion(BufferedImage image) {
+ imageForLazyCustomConversion = image;
+ boolean hasAlpha = image.getColorModel().hasAlpha();
+ pixelFormat = hasAlpha ? GL.GL_RGBA : GL.GL_RGB;
+ alignment = 1; // FIXME: do we need better?
+ rowLength = width; // FIXME: correct in all cases?
+
+ // Allow previously-selected pixelType (if any) to override that
+ // we can infer from the DataBuffer
+ DataBuffer data = image.getRaster().getDataBuffer();
+ if (data instanceof DataBufferByte) {
+ if (pixelType == 0) pixelType = GL.GL_UNSIGNED_BYTE;
+ } else if (data instanceof DataBufferDouble) {
+ throw new RuntimeException("DataBufferDouble rasters not supported by OpenGL");
+ } else if (data instanceof DataBufferFloat) {
+ if (pixelType == 0) pixelType = GL.GL_FLOAT;
+ } else if (data instanceof DataBufferInt) {
+ // FIXME: should we support signed ints?
+ if (pixelType == 0) pixelType = GL.GL_UNSIGNED_INT;
+ } else if (data instanceof DataBufferShort) {
+ if (pixelType == 0) pixelType = GL.GL_SHORT;
+ } else if (data instanceof DataBufferUShort) {
+ if (pixelType == 0) pixelType = GL.GL_UNSIGNED_SHORT;
+ } else {
+ throw new RuntimeException("Unexpected DataBuffer type?");
+ }
}
private void createFromCustom(BufferedImage image) {
@@ -560,17 +592,11 @@ public class TextureData {
// copy the source image into the temporary image
Graphics2D g = texImage.createGraphics();
g.setComposite(AlphaComposite.Src);
- // Flip image vertically as long as we're at it
- g.drawImage(image,
- 0, height, width, 0,
- 0, 0, width, height,
- null);
+ g.drawImage(image, 0, 0, null);
g.dispose();
// Wrap the buffer from the temporary image
- createNIOBufferFromImage(texImage, false);
- pixelFormat = hasAlpha ? GL.GL_RGBA : GL.GL_RGB;
- alignment = 1; // FIXME: do we need better?
+ createNIOBufferFromImage(texImage);
}
private int estimatedMemorySize(Buffer buffer) {