aboutsummaryrefslogtreecommitdiffstats
path: root/src/classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/classes')
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/Texture.java1694
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/TextureCoords.java50
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/TextureData.java544
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/DDSImage.java1714
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java298
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/SGIImage.java1140
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/TGAImage.java598
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/TextureProvider.java216
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/TextureWriter.java14
9 files changed, 3134 insertions, 3134 deletions
diff --git a/src/classes/com/sun/opengl/util/texture/Texture.java b/src/classes/com/sun/opengl/util/texture/Texture.java
index b9d75b650..f0c36e398 100755
--- a/src/classes/com/sun/opengl/util/texture/Texture.java
+++ b/src/classes/com/sun/opengl/util/texture/Texture.java
@@ -140,894 +140,894 @@ import com.sun.opengl.util.texture.spi.*;
* @author Kenneth Russell
*/
public class Texture {
- /** The GL target type. */
- private int target;
- /** The GL texture ID. */
- private int texID;
- /** The width of the texture. */
- private int texWidth;
- /** The height of the texture. */
- private int texHeight;
- /** The width of the image. */
- private int imgWidth;
- /** The height of the image. */
- private int imgHeight;
- /** The original aspect ratio of the image, before any rescaling
- that might have occurred due to using the GLU mipmap routines. */
- private float aspectRatio;
- /** Indicates whether the TextureData requires a vertical flip of
- the texture coords. */
- private boolean mustFlipVertically;
- /** Indicates whether we're using automatic mipmap generation
- support (GL_GENERATE_MIPMAP). */
- private boolean usingAutoMipmapGeneration;
-
- /** The texture coordinates corresponding to the entire image. */
- private TextureCoords coords;
-
- /** An estimate of the amount of texture memory this texture consumes. */
- private int estimatedMemorySize;
-
- private static final boolean DEBUG = Debug.debug("Texture");
- private static final boolean VERBOSE = Debug.verbose();
-
- // For testing alternate code paths on more capable hardware
- private static final boolean disableNPOT = Debug.isPropertyDefined("jogl.texture.nonpot");
- private static final boolean disableTexRect = Debug.isPropertyDefined("jogl.texture.notexrect");
-
- public Texture(TextureData data) throws GLException {
- GL gl = GLU.getCurrentGL();
- texID = createTextureID(gl);
-
- updateImage(data);
- }
-
- // Constructor for use when creating e.g. cube maps, where there is
- // no initial texture data
- public Texture(int target) throws GLException {
- GL gl = GLU.getCurrentGL();
- texID = createTextureID(gl);
- this.target = target;
- }
-
- /**
- * Enables this texture's target (e.g., GL_TEXTURE_2D) in the
- * current GL context's state. This method is a shorthand equivalent
- * of the following OpenGL code:
-<pre>
- gl.glEnable(texture.getTarget());
-</pre>
- *
- * See the <a href="#perftips">performance tips</a> above for hints
- * on how to maximize performance when using many Texture objects.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void enable() throws GLException {
- GLU.getCurrentGL().glEnable(target);
- }
-
- /**
- * Disables this texture's target (e.g., GL_TEXTURE_2D) in the
- * current GL context's state. This method is a shorthand equivalent
- * of the following OpenGL code:
-<pre>
- gl.glDisable(texture.getTarget());
-</pre>
- *
- * See the <a href="#perftips">performance tips</a> above for hints
- * on how to maximize performance when using many Texture objects.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void disable() throws GLException {
- GLU.getCurrentGL().glDisable(target);
- }
-
- /**
- * Binds this texture to the current GL context. This method is a
- * shorthand equivalent of the following OpenGL code:
-<pre>
- gl.glBindTexture(texture.getTarget(), texture.getTextureObject());
-</pre>
- *
- * See the <a href="#perftips">performance tips</a> above for hints
- * on how to maximize performance when using many Texture objects.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void bind() throws GLException {
- GLU.getCurrentGL().glBindTexture(target, texID);
- }
-
- /**
- * Disposes the native resources used by this texture object.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void dispose() throws GLException {
- GLU.getCurrentGL().glDeleteTextures(1, new int[] {texID}, 0);
- texID = 0;
- }
-
- /**
- * Returns the OpenGL "target" of this texture.
- *
- * @return the OpenGL target of this texture
- * @see javax.media.opengl.GL#GL_TEXTURE_2D
- * @see javax.media.opengl.GL2#GL_TEXTURE_RECTANGLE
- */
- public int getTarget() {
- return target;
- }
-
- /**
- * Returns the width of the allocated OpenGL texture in pixels.
- * Note that the texture width will be greater than or equal to the
- * width of the image contained within.
- *
- * @return the width of the texture
- */
- public int getWidth() {
- return texWidth;
- }
+ /** The GL target type. */
+ private int target;
+ /** The GL texture ID. */
+ private int texID;
+ /** The width of the texture. */
+ private int texWidth;
+ /** The height of the texture. */
+ private int texHeight;
+ /** The width of the image. */
+ private int imgWidth;
+ /** The height of the image. */
+ private int imgHeight;
+ /** The original aspect ratio of the image, before any rescaling
+ that might have occurred due to using the GLU mipmap routines. */
+ private float aspectRatio;
+ /** Indicates whether the TextureData requires a vertical flip of
+ the texture coords. */
+ private boolean mustFlipVertically;
+ /** Indicates whether we're using automatic mipmap generation
+ support (GL_GENERATE_MIPMAP). */
+ private boolean usingAutoMipmapGeneration;
+
+ /** The texture coordinates corresponding to the entire image. */
+ private TextureCoords coords;
+
+ /** An estimate of the amount of texture memory this texture consumes. */
+ private int estimatedMemorySize;
+
+ private static final boolean DEBUG = Debug.debug("Texture");
+ private static final boolean VERBOSE = Debug.verbose();
+
+ // For testing alternate code paths on more capable hardware
+ private static final boolean disableNPOT = Debug.isPropertyDefined("jogl.texture.nonpot");
+ private static final boolean disableTexRect = Debug.isPropertyDefined("jogl.texture.notexrect");
+
+ public Texture(TextureData data) throws GLException {
+ GL gl = GLU.getCurrentGL();
+ texID = createTextureID(gl);
+
+ updateImage(data);
+ }
+
+ // Constructor for use when creating e.g. cube maps, where there is
+ // no initial texture data
+ public Texture(int target) throws GLException {
+ GL gl = GLU.getCurrentGL();
+ texID = createTextureID(gl);
+ this.target = target;
+ }
+
+ /**
+ * Enables this texture's target (e.g., GL_TEXTURE_2D) in the
+ * current GL context's state. This method is a shorthand equivalent
+ * of the following OpenGL code:
+ <pre>
+ gl.glEnable(texture.getTarget());
+ </pre>
+ *
+ * See the <a href="#perftips">performance tips</a> above for hints
+ * on how to maximize performance when using many Texture objects.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void enable() throws GLException {
+ GLU.getCurrentGL().glEnable(target);
+ }
+
+ /**
+ * Disables this texture's target (e.g., GL_TEXTURE_2D) in the
+ * current GL context's state. This method is a shorthand equivalent
+ * of the following OpenGL code:
+ <pre>
+ gl.glDisable(texture.getTarget());
+ </pre>
+ *
+ * See the <a href="#perftips">performance tips</a> above for hints
+ * on how to maximize performance when using many Texture objects.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void disable() throws GLException {
+ GLU.getCurrentGL().glDisable(target);
+ }
+
+ /**
+ * Binds this texture to the current GL context. This method is a
+ * shorthand equivalent of the following OpenGL code:
+ <pre>
+ gl.glBindTexture(texture.getTarget(), texture.getTextureObject());
+ </pre>
+ *
+ * See the <a href="#perftips">performance tips</a> above for hints
+ * on how to maximize performance when using many Texture objects.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void bind() throws GLException {
+ GLU.getCurrentGL().glBindTexture(target, texID);
+ }
+
+ /**
+ * Disposes the native resources used by this texture object.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void dispose() throws GLException {
+ GLU.getCurrentGL().glDeleteTextures(1, new int[] {texID}, 0);
+ texID = 0;
+ }
+
+ /**
+ * Returns the OpenGL "target" of this texture.
+ *
+ * @return the OpenGL target of this texture
+ * @see javax.media.opengl.GL#GL_TEXTURE_2D
+ * @see javax.media.opengl.GL2#GL_TEXTURE_RECTANGLE
+ */
+ public int getTarget() {
+ return target;
+ }
+
+ /**
+ * Returns the width of the allocated OpenGL texture in pixels.
+ * Note that the texture width will be greater than or equal to the
+ * width of the image contained within.
+ *
+ * @return the width of the texture
+ */
+ public int getWidth() {
+ return texWidth;
+ }
- /**
- * Returns the height of the allocated OpenGL texture in pixels.
- * Note that the texture height will be greater than or equal to the
- * height of the image contained within.
- *
- * @return the height of the texture
- */
- public int getHeight() {
- return texHeight;
- }
+ /**
+ * Returns the height of the allocated OpenGL texture in pixels.
+ * Note that the texture height will be greater than or equal to the
+ * height of the image contained within.
+ *
+ * @return the height of the texture
+ */
+ public int getHeight() {
+ return texHeight;
+ }
- /**
- * Returns the width of the image contained within this texture.
- * Note that for non-power-of-two textures in particular this may
- * not be equal to the result of {@link #getWidth}. It is
- * recommended that applications call {@link #getImageTexCoords} and
- * {@link #getSubImageTexCoords} rather than using this API
- * directly.
- *
- * @return the width of the image
- */
- public int getImageWidth() {
- return imgWidth;
- }
-
- /**
- * Returns the height of the image contained within this texture.
- * Note that for non-power-of-two textures in particular this may
- * not be equal to the result of {@link #getHeight}. It is
- * recommended that applications call {@link #getImageTexCoords} and
- * {@link #getSubImageTexCoords} rather than using this API
- * directly.
- *
- * @return the height of the image
- */
- public int getImageHeight() {
- return imgHeight;
- }
-
- /**
- * Returns the original aspect ratio of the image, defined as (image
- * width) / (image height), before any scaling that might have
- * occurred as a result of using the GLU mipmap routines.
- */
- public float getAspectRatio() {
- return aspectRatio;
- }
-
- /**
- * Returns the set of texture coordinates corresponding to the
- * entire image. If the TextureData indicated that the texture
- * coordinates must be flipped vertically, the returned
- * TextureCoords will take that into account.
- *
- * @return the texture coordinates corresponding to the entire image
- */
- public TextureCoords getImageTexCoords() {
- return coords;
- }
-
- /**
- * Returns the set of texture coordinates corresponding to the
- * specified sub-image. The (x1, y1) and (x2, y2) points are
- * specified in terms of pixels starting from the lower-left of the
- * image. (x1, y1) should specify the lower-left corner of the
- * sub-image and (x2, y2) the upper-right corner of the sub-image.
- * If the TextureData indicated that the texture coordinates must be
- * flipped vertically, the returned TextureCoords will take that
- * into account; this should not be handled by the end user in the
- * specification of the y1 and y2 coordinates.
- *
- * @return the texture coordinates corresponding to the specified sub-image
- */
- public TextureCoords getSubImageTexCoords(int x1, int y1, int x2, int y2) {
- if (target == GL2.GL_TEXTURE_RECTANGLE) {
- if (mustFlipVertically) {
- return new TextureCoords(x1, texHeight - y1, x2, texHeight - y2);
- } else {
- return new TextureCoords(x1, y1, x2, y2);
- }
- } else {
- float tx1 = (float)x1 / (float)texWidth;
- float ty1 = (float)y1 / (float)texHeight;
- float tx2 = (float)x2 / (float)texWidth;
- float ty2 = (float)y2 / (float)texHeight;
- if (mustFlipVertically) {
- float yMax = (float) imgHeight / (float) texHeight;
- return new TextureCoords(tx1, yMax - ty1, tx2, yMax - ty2);
- } else {
- return new TextureCoords(tx1, ty1, tx2, ty2);
- }
+ /**
+ * Returns the width of the image contained within this texture.
+ * Note that for non-power-of-two textures in particular this may
+ * not be equal to the result of {@link #getWidth}. It is
+ * recommended that applications call {@link #getImageTexCoords} and
+ * {@link #getSubImageTexCoords} rather than using this API
+ * directly.
+ *
+ * @return the width of the image
+ */
+ public int getImageWidth() {
+ return imgWidth;
}
- }
-
- /**
- * Updates the entire content area of this texture using the data in
- * the given image.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void updateImage(TextureData data) throws GLException {
- updateImage(data, 0);
- }
-
- /**
- * Indicates whether this texture's texture coordinates must be
- * flipped vertically in order to properly display the texture. This
- * is handled automatically by {@link #getImageTexCoords
- * getImageTexCoords} and {@link #getSubImageTexCoords
- * getSubImageTexCoords}, but applications may generate or otherwise
- * produce texture coordinates which must be corrected.
- */
- public boolean getMustFlipVertically() {
- return mustFlipVertically;
- }
-
- /**
- * Updates the content area of the specified target of this texture
- * using the data in the given image. In general this is intended
- * for construction of cube maps.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void updateImage(TextureData data, int target) throws GLException {
- GL gl = GLU.getCurrentGL();
-
- imgWidth = data.getWidth();
- imgHeight = data.getHeight();
- aspectRatio = (float) imgWidth / (float) imgHeight;
- mustFlipVertically = data.getMustFlipVertically();
-
- int texTarget = 0;
- int texParamTarget = this.target;
-
- // See whether we have automatic mipmap generation support
- boolean haveAutoMipmapGeneration =
- (gl.isExtensionAvailable("GL_VERSION_1_4") ||
- gl.isExtensionAvailable("GL_SGIS_generate_mipmap"));
-
- // Indicate to the TextureData what functionality is available
- data.setHaveEXTABGR(gl.isExtensionAvailable("GL_EXT_abgr"));
- data.setHaveGL12(gl.isExtensionAvailable("GL_VERSION_1_2"));
-
- // Note that automatic mipmap generation doesn't work for
- // GL_ARB_texture_rectangle
- if ((!isPowerOfTwo(imgWidth) || !isPowerOfTwo(imgHeight)) &&
- !haveNPOT(gl)) {
- haveAutoMipmapGeneration = false;
+
+ /**
+ * Returns the height of the image contained within this texture.
+ * Note that for non-power-of-two textures in particular this may
+ * not be equal to the result of {@link #getHeight}. It is
+ * recommended that applications call {@link #getImageTexCoords} and
+ * {@link #getSubImageTexCoords} rather than using this API
+ * directly.
+ *
+ * @return the height of the image
+ */
+ public int getImageHeight() {
+ return imgHeight;
+ }
+
+ /**
+ * Returns the original aspect ratio of the image, defined as (image
+ * width) / (image height), before any scaling that might have
+ * occurred as a result of using the GLU mipmap routines.
+ */
+ public float getAspectRatio() {
+ return aspectRatio;
}
- boolean expandingCompressedTexture = false;
- if (data.getMipmap() && !haveAutoMipmapGeneration) {
- // GLU always scales the texture's dimensions to be powers of
- // two. It also doesn't really matter exactly what the texture
- // width and height are because the texture coords are always
- // between 0.0 and 1.0.
- imgWidth = nextPowerOfTwo(imgWidth);
- imgHeight = nextPowerOfTwo(imgHeight);
- texWidth = imgWidth;
- texHeight = imgHeight;
- texTarget = GL.GL_TEXTURE_2D;
- } else if ((isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) ||
- haveNPOT(gl)) {
- if (DEBUG) {
- if (isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) {
- System.err.println("Power-of-two texture");
+ /**
+ * Returns the set of texture coordinates corresponding to the
+ * entire image. If the TextureData indicated that the texture
+ * coordinates must be flipped vertically, the returned
+ * TextureCoords will take that into account.
+ *
+ * @return the texture coordinates corresponding to the entire image
+ */
+ public TextureCoords getImageTexCoords() {
+ return coords;
+ }
+
+ /**
+ * Returns the set of texture coordinates corresponding to the
+ * specified sub-image. The (x1, y1) and (x2, y2) points are
+ * specified in terms of pixels starting from the lower-left of the
+ * image. (x1, y1) should specify the lower-left corner of the
+ * sub-image and (x2, y2) the upper-right corner of the sub-image.
+ * If the TextureData indicated that the texture coordinates must be
+ * flipped vertically, the returned TextureCoords will take that
+ * into account; this should not be handled by the end user in the
+ * specification of the y1 and y2 coordinates.
+ *
+ * @return the texture coordinates corresponding to the specified sub-image
+ */
+ public TextureCoords getSubImageTexCoords(int x1, int y1, int x2, int y2) {
+ if (target == GL2.GL_TEXTURE_RECTANGLE) {
+ if (mustFlipVertically) {
+ return new TextureCoords(x1, texHeight - y1, x2, texHeight - y2);
+ } else {
+ return new TextureCoords(x1, y1, x2, y2);
+ }
} else {
- System.err.println("Using GL_ARB_texture_non_power_of_two");
+ float tx1 = (float)x1 / (float)texWidth;
+ float ty1 = (float)y1 / (float)texHeight;
+ float tx2 = (float)x2 / (float)texWidth;
+ float ty2 = (float)y2 / (float)texHeight;
+ if (mustFlipVertically) {
+ float yMax = (float) imgHeight / (float) texHeight;
+ return new TextureCoords(tx1, yMax - ty1, tx2, yMax - ty2);
+ } else {
+ return new TextureCoords(tx1, ty1, tx2, ty2);
+ }
}
- }
-
- texWidth = imgWidth;
- texHeight = imgHeight;
- texTarget = GL.GL_TEXTURE_2D;
- } else if (haveTexRect(gl) && !data.isDataCompressed() && !gl.isGL2()) {
- // GL_ARB_texture_rectangle does not work for compressed textures
- if (DEBUG) {
- System.err.println("Using GL_ARB_texture_rectangle");
- }
-
- texWidth = imgWidth;
- texHeight = imgHeight;
- texTarget = GL2.GL_TEXTURE_RECTANGLE;
- } else {
- // If we receive non-power-of-two compressed texture data and
- // don't have true hardware support for compressed textures, we
- // can fake this support by producing an empty "compressed"
- // texture image, using glCompressedTexImage2D with that to
- // allocate the texture, and glCompressedTexSubImage2D with the
- // incoming data.
- if (data.isDataCompressed()) {
- if (data.getMipmapData() != null) {
+ }
+
+ /**
+ * Updates the entire content area of this texture using the data in
+ * the given image.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void updateImage(TextureData data) throws GLException {
+ updateImage(data, 0);
+ }
+
+ /**
+ * Indicates whether this texture's texture coordinates must be
+ * flipped vertically in order to properly display the texture. This
+ * is handled automatically by {@link #getImageTexCoords
+ * getImageTexCoords} and {@link #getSubImageTexCoords
+ * getSubImageTexCoords}, but applications may generate or otherwise
+ * produce texture coordinates which must be corrected.
+ */
+ public boolean getMustFlipVertically() {
+ return mustFlipVertically;
+ }
- // We don't currently support expanding of compressed,
- // mipmapped non-power-of-two textures to the nearest power
- // of two; the obvious port of the non-mipmapped code didn't
- // work
- throw new GLException("Mipmapped non-power-of-two compressed textures only supported on OpenGL 2.0 hardware (GL_ARB_texture_non_power_of_two)");
+ /**
+ * Updates the content area of the specified target of this texture
+ * using the data in the given image. In general this is intended
+ * for construction of cube maps.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void updateImage(TextureData data, int target) throws GLException {
+ GL gl = GLU.getCurrentGL();
+
+ imgWidth = data.getWidth();
+ imgHeight = data.getHeight();
+ aspectRatio = (float) imgWidth / (float) imgHeight;
+ mustFlipVertically = data.getMustFlipVertically();
+
+ int texTarget = 0;
+ int texParamTarget = this.target;
+
+ // See whether we have automatic mipmap generation support
+ boolean haveAutoMipmapGeneration =
+ (gl.isExtensionAvailable("GL_VERSION_1_4") ||
+ gl.isExtensionAvailable("GL_SGIS_generate_mipmap"));
+
+ // Indicate to the TextureData what functionality is available
+ data.setHaveEXTABGR(gl.isExtensionAvailable("GL_EXT_abgr"));
+ data.setHaveGL12(gl.isExtensionAvailable("GL_VERSION_1_2"));
+
+ // Note that automatic mipmap generation doesn't work for
+ // GL_ARB_texture_rectangle
+ if ((!isPowerOfTwo(imgWidth) || !isPowerOfTwo(imgHeight)) &&
+ !haveNPOT(gl)) {
+ haveAutoMipmapGeneration = false;
}
- expandingCompressedTexture = true;
- }
+ boolean expandingCompressedTexture = false;
+ if (data.getMipmap() && !haveAutoMipmapGeneration) {
+ // GLU always scales the texture's dimensions to be powers of
+ // two. It also doesn't really matter exactly what the texture
+ // width and height are because the texture coords are always
+ // between 0.0 and 1.0.
+ imgWidth = nextPowerOfTwo(imgWidth);
+ imgHeight = nextPowerOfTwo(imgHeight);
+ texWidth = imgWidth;
+ texHeight = imgHeight;
+ texTarget = GL.GL_TEXTURE_2D;
+ } else if ((isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) ||
+ haveNPOT(gl)) {
+ if (DEBUG) {
+ if (isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) {
+ System.err.println("Power-of-two texture");
+ } else {
+ System.err.println("Using GL_ARB_texture_non_power_of_two");
+ }
+ }
+
+ texWidth = imgWidth;
+ texHeight = imgHeight;
+ texTarget = GL.GL_TEXTURE_2D;
+ } else if (haveTexRect(gl) && !data.isDataCompressed() && !gl.isGL2()) {
+ // GL_ARB_texture_rectangle does not work for compressed textures
+ if (DEBUG) {
+ System.err.println("Using GL_ARB_texture_rectangle");
+ }
+
+ texWidth = imgWidth;
+ texHeight = imgHeight;
+ texTarget = GL2.GL_TEXTURE_RECTANGLE;
+ } else {
+ // If we receive non-power-of-two compressed texture data and
+ // don't have true hardware support for compressed textures, we
+ // can fake this support by producing an empty "compressed"
+ // texture image, using glCompressedTexImage2D with that to
+ // allocate the texture, and glCompressedTexSubImage2D with the
+ // incoming data.
+ if (data.isDataCompressed()) {
+ if (data.getMipmapData() != null) {
+
+ // We don't currently support expanding of compressed,
+ // mipmapped non-power-of-two textures to the nearest power
+ // of two; the obvious port of the non-mipmapped code didn't
+ // work
+ throw new GLException("Mipmapped non-power-of-two compressed textures only supported on OpenGL 2.0 hardware (GL_ARB_texture_non_power_of_two)");
+ }
+
+ expandingCompressedTexture = true;
+ }
+
+ if (DEBUG) {
+ System.err.println("Expanding texture to power-of-two dimensions");
+ }
+
+ if (data.getBorder() != 0) {
+ throw new RuntimeException("Scaling up a non-power-of-two texture which has a border won't work");
+ }
+ texWidth = nextPowerOfTwo(imgWidth);
+ texHeight = nextPowerOfTwo(imgHeight);
+ texTarget = GL.GL_TEXTURE_2D;
+ }
- if (DEBUG) {
- System.err.println("Expanding texture to power-of-two dimensions");
- }
+ texParamTarget = texTarget;
+ setImageSize(imgWidth, imgHeight, texTarget);
+
+ if (target != 0) {
+ // Allow user to override auto detection and skip bind step (for
+ // cubemap construction)
+ texTarget = target;
+ if (this.target == 0) {
+ throw new GLException("Override of target failed; no target specified yet");
+ }
+ texParamTarget = this.target;
+ gl.glBindTexture(texParamTarget, texID);
+ } else {
+ gl.glBindTexture(texTarget, texID);
+ }
- if (data.getBorder() != 0) {
- throw new RuntimeException("Scaling up a non-power-of-two texture which has a border won't work");
- }
- texWidth = nextPowerOfTwo(imgWidth);
- texHeight = nextPowerOfTwo(imgHeight);
- texTarget = GL.GL_TEXTURE_2D;
- }
+ if (data.getMipmap() && !haveAutoMipmapGeneration) {
+ int[] align = new int[1];
+ gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment
+ gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment());
+
+ if (data.isDataCompressed()) {
+ throw new GLException("May not request mipmap generation for compressed textures");
+ }
+
+ try {
+ // FIXME: need to get rid of this cast
+ GLUgl2 glu = (GLUgl2) GLU.createGLU(gl);
+ glu.gluBuild2DMipmaps(texTarget, data.getInternalFormat(),
+ data.getWidth(), data.getHeight(),
+ data.getPixelFormat(), data.getPixelType(), data.getBuffer());
+ } finally {
+ gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment
+ }
+ } else {
+ checkCompressedTextureExtensions(data);
+ Buffer[] mipmapData = data.getMipmapData();
+ if (mipmapData != null) {
+ int width = texWidth;
+ int height = texHeight;
+ for (int i = 0; i < mipmapData.length; i++) {
+ if (data.isDataCompressed()) {
+ // Need to use glCompressedTexImage2D directly to allocate and fill this image
+ // Avoid spurious memory allocation when possible
+ gl.glCompressedTexImage2D(texTarget, i, data.getInternalFormat(),
+ width, height, data.getBorder(),
+ mipmapData[i].remaining(), mipmapData[i]);
+ } else {
+ // Allocate texture image at this level
+ gl.glTexImage2D(texTarget, i, data.getInternalFormat(),
+ width, height, data.getBorder(),
+ data.getPixelFormat(), data.getPixelType(), null);
+ updateSubImageImpl(data, texTarget, i, 0, 0, 0, 0, data.getWidth(), data.getHeight());
+ }
+
+ width = Math.max(width / 2, 1);
+ height = Math.max(height / 2, 1);
+ }
+ } else {
+ if (data.isDataCompressed()) {
+ if (!expandingCompressedTexture) {
+ // Need to use glCompressedTexImage2D directly to allocate and fill this image
+ // Avoid spurious memory allocation when possible
+ gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(),
+ texWidth, texHeight, data.getBorder(),
+ data.getBuffer().capacity(), data.getBuffer());
+ } else {
+ ByteBuffer buf = DDSImage.allocateBlankBuffer(texWidth,
+ texHeight,
+ data.getInternalFormat());
+ gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(),
+ texWidth, texHeight, data.getBorder(),
+ buf.capacity(), buf);
+ updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight());
+ }
+ } else {
+ if (data.getMipmap() && haveAutoMipmapGeneration && gl.isGL2ES1()) {
+ // For now, only use hardware mipmapping for uncompressed 2D
+ // textures where the user hasn't explicitly specified
+ // mipmap data; don't know about interactions between
+ // GL_GENERATE_MIPMAP and glCompressedTexImage2D
+ gl.glTexParameteri(texParamTarget, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE);
+ usingAutoMipmapGeneration = true;
+ }
+
+ gl.glTexImage2D(texTarget, 0, data.getInternalFormat(),
+ texWidth, texHeight, data.getBorder(),
+ data.getPixelFormat(), data.getPixelType(), null);
+ updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight());
+ }
+ }
+ }
- texParamTarget = texTarget;
- setImageSize(imgWidth, imgHeight, texTarget);
-
- if (target != 0) {
- // Allow user to override auto detection and skip bind step (for
- // cubemap construction)
- texTarget = target;
- if (this.target == 0) {
- throw new GLException("Override of target failed; no target specified yet");
- }
- texParamTarget = this.target;
- gl.glBindTexture(texParamTarget, texID);
- } else {
- gl.glBindTexture(texTarget, texID);
+ int minFilter = (data.getMipmap() ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR);
+ int magFilter = GL.GL_LINEAR;
+ int wrapMode = (gl.isExtensionAvailable("GL_VERSION_1_2") || !gl.isGL2()) ? GL.GL_CLAMP_TO_EDGE : GL2.GL_CLAMP;
+
+ // REMIND: figure out what to do for GL_TEXTURE_RECTANGLE
+ if (texTarget != GL2.GL_TEXTURE_RECTANGLE) {
+ gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MIN_FILTER, minFilter);
+ gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MAG_FILTER, magFilter);
+ gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_S, wrapMode);
+ gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_T, wrapMode);
+ if (this.target == GL2.GL_TEXTURE_CUBE_MAP) {
+ gl.glTexParameteri(texParamTarget, GL2.GL_TEXTURE_WRAP_R, wrapMode);
+ }
+ }
+
+ // Don't overwrite target if we're loading e.g. faces of a cube
+ // map
+ if ((this.target == 0) ||
+ (this.target == GL.GL_TEXTURE_2D) ||
+ (this.target == GL2.GL_TEXTURE_RECTANGLE)) {
+ this.target = texTarget;
+ }
+
+ // This estimate will be wrong for cube maps
+ estimatedMemorySize = data.getEstimatedMemorySize();
}
- if (data.getMipmap() && !haveAutoMipmapGeneration) {
- int[] align = new int[1];
- gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment
- gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment());
-
- if (data.isDataCompressed()) {
- throw new GLException("May not request mipmap generation for compressed textures");
- }
-
- try {
- // FIXME: need to get rid of this cast
- GLUgl2 glu = (GLUgl2) GLU.createGLU(gl);
- glu.gluBuild2DMipmaps(texTarget, data.getInternalFormat(),
- data.getWidth(), data.getHeight(),
- data.getPixelFormat(), data.getPixelType(), data.getBuffer());
- } finally {
- gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment
- }
- } else {
- checkCompressedTextureExtensions(data);
- Buffer[] mipmapData = data.getMipmapData();
- if (mipmapData != null) {
- int width = texWidth;
- int height = texHeight;
- for (int i = 0; i < mipmapData.length; i++) {
- if (data.isDataCompressed()) {
- // Need to use glCompressedTexImage2D directly to allocate and fill this image
- // Avoid spurious memory allocation when possible
- gl.glCompressedTexImage2D(texTarget, i, data.getInternalFormat(),
- width, height, data.getBorder(),
- mipmapData[i].remaining(), mipmapData[i]);
- } else {
- // Allocate texture image at this level
- gl.glTexImage2D(texTarget, i, data.getInternalFormat(),
- width, height, data.getBorder(),
- data.getPixelFormat(), data.getPixelType(), null);
- updateSubImageImpl(data, texTarget, i, 0, 0, 0, 0, data.getWidth(), data.getHeight());
- }
-
- width = Math.max(width / 2, 1);
- height = Math.max(height / 2, 1);
+ /**
+ * Updates a subregion of the content area of this texture using the
+ * given data. If automatic mipmap generation is in use (see {@link
+ * #isUsingAutoMipmapGeneration isUsingAutoMipmapGeneration}),
+ * updates to the base (level 0) mipmap will cause the lower-level
+ * mipmaps to be regenerated, and updates to other mipmap levels
+ * will be ignored. Otherwise, if automatic mipmap generation is not
+ * in use, only updates the specified mipmap level and does not
+ * re-generate mipmaps if they were originally produced or loaded.
+ *
+ * @param data the image data to be uploaded to this texture
+ * @param mipmapLevel the mipmap level of the texture to set. If
+ * this is non-zero and the TextureData contains mipmap data, the
+ * appropriate mipmap level will be selected.
+ * @param x the x offset (in pixels) relative to the lower-left corner
+ * of this texture
+ * @param y the y offset (in pixels) relative to the lower-left corner
+ * of this texture
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void updateSubImage(TextureData data, int mipmapLevel, int x, int y) throws GLException {
+ if (usingAutoMipmapGeneration && mipmapLevel != 0) {
+ // When we're using mipmap generation via GL_GENERATE_MIPMAP, we
+ // don't need to update other mipmap levels
+ return;
}
- } else {
+ bind();
+ updateSubImageImpl(data, target, mipmapLevel, x, y, 0, 0, data.getWidth(), data.getHeight());
+ }
+
+ /**
+ * Updates a subregion of the content area of this texture using the
+ * specified sub-region of the given data. If automatic mipmap
+ * generation is in use (see {@link #isUsingAutoMipmapGeneration
+ * isUsingAutoMipmapGeneration}), updates to the base (level 0)
+ * mipmap will cause the lower-level mipmaps to be regenerated, and
+ * updates to other mipmap levels will be ignored. Otherwise, if
+ * automatic mipmap generation is not in use, only updates the
+ * specified mipmap level and does not re-generate mipmaps if they
+ * were originally produced or loaded. This method is only supported
+ * for uncompressed TextureData sources.
+ *
+ * @param data the image data to be uploaded to this texture
+ * @param mipmapLevel the mipmap level of the texture to set. If
+ * this is non-zero and the TextureData contains mipmap data, the
+ * appropriate mipmap level will be selected.
+ * @param dstx the x offset (in pixels) relative to the lower-left corner
+ * of this texture where the update will be applied
+ * @param dsty the y offset (in pixels) relative to the lower-left corner
+ * of this texture where the update will be applied
+ * @param srcx the x offset (in pixels) relative to the lower-left corner
+ * of the supplied TextureData from which to fetch the update rectangle
+ * @param srcy the y offset (in pixels) relative to the lower-left corner
+ * of the supplied TextureData from which to fetch the update rectangle
+ * @param width the width (in pixels) of the rectangle to be updated
+ * @param height the height (in pixels) of the rectangle to be updated
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void updateSubImage(TextureData data, int mipmapLevel,
+ int dstx, int dsty,
+ int srcx, int srcy,
+ int width, int height) throws GLException {
if (data.isDataCompressed()) {
- if (!expandingCompressedTexture) {
- // Need to use glCompressedTexImage2D directly to allocate and fill this image
- // Avoid spurious memory allocation when possible
- gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(),
- texWidth, texHeight, data.getBorder(),
- data.getBuffer().capacity(), data.getBuffer());
- } else {
- ByteBuffer buf = DDSImage.allocateBlankBuffer(texWidth,
- texHeight,
- data.getInternalFormat());
- gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(),
- texWidth, texHeight, data.getBorder(),
- buf.capacity(), buf);
- updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight());
- }
- } else {
- if (data.getMipmap() && haveAutoMipmapGeneration && gl.isGL2ES1()) {
- // For now, only use hardware mipmapping for uncompressed 2D
- // textures where the user hasn't explicitly specified
- // mipmap data; don't know about interactions between
- // GL_GENERATE_MIPMAP and glCompressedTexImage2D
- gl.glTexParameteri(texParamTarget, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE);
- usingAutoMipmapGeneration = true;
- }
-
- gl.glTexImage2D(texTarget, 0, data.getInternalFormat(),
- texWidth, texHeight, data.getBorder(),
- data.getPixelFormat(), data.getPixelType(), null);
- updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight());
+ throw new GLException("updateSubImage specifying a sub-rectangle is not supported for compressed TextureData");
+ }
+ if (usingAutoMipmapGeneration && mipmapLevel != 0) {
+ // When we're using mipmap generation via GL_GENERATE_MIPMAP, we
+ // don't need to update other mipmap levels
+ return;
}
- }
+ bind();
+ updateSubImageImpl(data, target, mipmapLevel, dstx, dsty, srcx, srcy, width, height);
}
- int minFilter = (data.getMipmap() ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR);
- int magFilter = GL.GL_LINEAR;
- int wrapMode = (gl.isExtensionAvailable("GL_VERSION_1_2") || !gl.isGL2()) ? GL.GL_CLAMP_TO_EDGE : GL2.GL_CLAMP;
-
- // REMIND: figure out what to do for GL_TEXTURE_RECTANGLE
- if (texTarget != GL2.GL_TEXTURE_RECTANGLE) {
- gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MIN_FILTER, minFilter);
- gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MAG_FILTER, magFilter);
- gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_S, wrapMode);
- gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_T, wrapMode);
- if (this.target == GL2.GL_TEXTURE_CUBE_MAP) {
- gl.glTexParameteri(texParamTarget, GL2.GL_TEXTURE_WRAP_R, wrapMode);
- }
+ /**
+ * Sets the OpenGL floating-point texture parameter for the
+ * texture's target. This gives control over parameters such as
+ * GL_TEXTURE_MAX_ANISOTROPY_EXT. Causes this texture to be bound to
+ * the current texture state.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void setTexParameterf(int parameterName,
+ float value) {
+ bind();
+ GL gl = GLU.getCurrentGL();
+ gl.glTexParameterf(target, parameterName, value);
}
- // Don't overwrite target if we're loading e.g. faces of a cube
- // map
- if ((this.target == 0) ||
- (this.target == GL.GL_TEXTURE_2D) ||
- (this.target == GL2.GL_TEXTURE_RECTANGLE)) {
- this.target = texTarget;
+ /**
+ * Sets the OpenGL multi-floating-point texture parameter for the
+ * texture's target. Causes this texture to be bound to the current
+ * texture state.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void setTexParameterfv(int parameterName,
+ FloatBuffer params) {
+ bind();
+ GL gl = GLU.getCurrentGL();
+ gl.glTexParameterfv(target, parameterName, params);
}
- // This estimate will be wrong for cube maps
- estimatedMemorySize = data.getEstimatedMemorySize();
- }
-
- /**
- * Updates a subregion of the content area of this texture using the
- * given data. If automatic mipmap generation is in use (see {@link
- * #isUsingAutoMipmapGeneration isUsingAutoMipmapGeneration}),
- * updates to the base (level 0) mipmap will cause the lower-level
- * mipmaps to be regenerated, and updates to other mipmap levels
- * will be ignored. Otherwise, if automatic mipmap generation is not
- * in use, only updates the specified mipmap level and does not
- * re-generate mipmaps if they were originally produced or loaded.
- *
- * @param data the image data to be uploaded to this texture
- * @param mipmapLevel the mipmap level of the texture to set. If
- * this is non-zero and the TextureData contains mipmap data, the
- * appropriate mipmap level will be selected.
- * @param x the x offset (in pixels) relative to the lower-left corner
- * of this texture
- * @param y the y offset (in pixels) relative to the lower-left corner
- * of this texture
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void updateSubImage(TextureData data, int mipmapLevel, int x, int y) throws GLException {
- if (usingAutoMipmapGeneration && mipmapLevel != 0) {
- // When we're using mipmap generation via GL_GENERATE_MIPMAP, we
- // don't need to update other mipmap levels
- return;
- }
- bind();
- updateSubImageImpl(data, target, mipmapLevel, x, y, 0, 0, data.getWidth(), data.getHeight());
- }
-
- /**
- * Updates a subregion of the content area of this texture using the
- * specified sub-region of the given data. If automatic mipmap
- * generation is in use (see {@link #isUsingAutoMipmapGeneration
- * isUsingAutoMipmapGeneration}), updates to the base (level 0)
- * mipmap will cause the lower-level mipmaps to be regenerated, and
- * updates to other mipmap levels will be ignored. Otherwise, if
- * automatic mipmap generation is not in use, only updates the
- * specified mipmap level and does not re-generate mipmaps if they
- * were originally produced or loaded. This method is only supported
- * for uncompressed TextureData sources.
- *
- * @param data the image data to be uploaded to this texture
- * @param mipmapLevel the mipmap level of the texture to set. If
- * this is non-zero and the TextureData contains mipmap data, the
- * appropriate mipmap level will be selected.
- * @param dstx the x offset (in pixels) relative to the lower-left corner
- * of this texture where the update will be applied
- * @param dsty the y offset (in pixels) relative to the lower-left corner
- * of this texture where the update will be applied
- * @param srcx the x offset (in pixels) relative to the lower-left corner
- * of the supplied TextureData from which to fetch the update rectangle
- * @param srcy the y offset (in pixels) relative to the lower-left corner
- * of the supplied TextureData from which to fetch the update rectangle
- * @param width the width (in pixels) of the rectangle to be updated
- * @param height the height (in pixels) of the rectangle to be updated
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void updateSubImage(TextureData data, int mipmapLevel,
- int dstx, int dsty,
- int srcx, int srcy,
- int width, int height) throws GLException {
- if (data.isDataCompressed()) {
- throw new GLException("updateSubImage specifying a sub-rectangle is not supported for compressed TextureData");
+ /**
+ * Sets the OpenGL multi-floating-point texture parameter for the
+ * texture's target. Causes this texture to be bound to the current
+ * texture state.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void setTexParameterfv(int parameterName,
+ float[] params, int params_offset) {
+ bind();
+ GL gl = GLU.getCurrentGL();
+ gl.glTexParameterfv(target, parameterName, params, params_offset);
}
- if (usingAutoMipmapGeneration && mipmapLevel != 0) {
- // When we're using mipmap generation via GL_GENERATE_MIPMAP, we
- // don't need to update other mipmap levels
- return;
- }
- bind();
- updateSubImageImpl(data, target, mipmapLevel, dstx, dsty, srcx, srcy, width, height);
- }
-
- /**
- * Sets the OpenGL floating-point texture parameter for the
- * texture's target. This gives control over parameters such as
- * GL_TEXTURE_MAX_ANISOTROPY_EXT. Causes this texture to be bound to
- * the current texture state.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void setTexParameterf(int parameterName,
- float value) {
- bind();
- GL gl = GLU.getCurrentGL();
- gl.glTexParameterf(target, parameterName, value);
- }
-
- /**
- * Sets the OpenGL multi-floating-point texture parameter for the
- * texture's target. Causes this texture to be bound to the current
- * texture state.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void setTexParameterfv(int parameterName,
- FloatBuffer params) {
- bind();
- GL gl = GLU.getCurrentGL();
- gl.glTexParameterfv(target, parameterName, params);
- }
-
- /**
- * Sets the OpenGL multi-floating-point texture parameter for the
- * texture's target. Causes this texture to be bound to the current
- * texture state.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void setTexParameterfv(int parameterName,
- float[] params, int params_offset) {
- bind();
- GL gl = GLU.getCurrentGL();
- gl.glTexParameterfv(target, parameterName, params, params_offset);
- }
-
- /**
- * Sets the OpenGL integer texture parameter for the texture's
- * target. This gives control over parameters such as
- * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T, which by default are set
- * to GL_CLAMP_TO_EDGE if OpenGL 1.2 is supported on the current
- * platform and GL_CLAMP if not. Causes this texture to be bound to
- * the current texture state.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void setTexParameteri(int parameterName,
- int value) {
- bind();
- GL gl = GLU.getCurrentGL();
- gl.glTexParameteri(target, parameterName, value);
- }
-
- /**
- * Sets the OpenGL multi-integer texture parameter for the texture's
- * target. Causes this texture to be bound to the current texture
- * state.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void setTexParameteriv(int parameterName,
- IntBuffer params) {
- bind();
- GL gl = GLU.getCurrentGL();
- gl.glTexParameteriv(target, parameterName, params);
- }
-
- /**
- * Sets the OpenGL multi-integer texture parameter for the texture's
- * target. Causes this texture to be bound to the current texture
- * state.
- *
- * @throws GLException if no OpenGL context was current or if any
- * OpenGL-related errors occurred
- */
- public void setTexParameteriv(int parameterName,
- int[] params, int params_offset) {
- bind();
- GL gl = GLU.getCurrentGL();
- gl.glTexParameteriv(target, parameterName, params, params_offset);
- }
-
- /**
- * Returns the underlying OpenGL texture object for this texture.
- * Most applications will not need to access this, since it is
- * handled automatically by the bind() and dispose() APIs.
- */
- public int getTextureObject() {
- return texID;
- }
-
- /** Returns an estimate of the amount of texture memory in bytes
- this Texture consumes. It should only be treated as an estimate;
- most applications should not need to query this but instead let
- the OpenGL implementation page textures in and out as
- necessary. */
- public int getEstimatedMemorySize() {
- return estimatedMemorySize;
- }
-
- /** Indicates whether this Texture is using automatic mipmap
- generation (via the OpenGL texture parameter
- GL_GENERATE_MIPMAP). This will automatically be used when
- mipmapping is requested via the TextureData and either OpenGL
- 1.4 or the GL_SGIS_generate_mipmap extension is available. If
- so, updates to the base image (mipmap level 0) will
- automatically propagate down to the lower mipmap levels. Manual
- updates of the mipmap data at these lower levels will be
- ignored. */
- public boolean isUsingAutoMipmapGeneration() {
- return usingAutoMipmapGeneration;
- }
-
- //----------------------------------------------------------------------
- // Internals only below this point
- //
-
- /**
- * Returns true if the given value is a power of two.
- *
- * @return true if the given value is a power of two, false otherwise
- */
- private static boolean isPowerOfTwo(int val) {
- return ((val & (val - 1)) == 0);
- }
-
- /**
- * Returns the nearest power of two that is larger than the given value.
- * If the given value is already a power of two, this method will simply
- * return that value.
- *
- * @param val the value
- * @return the next power of two
- */
- private static int nextPowerOfTwo(int val) {
- int ret = 1;
- while (ret < val) {
- ret <<= 1;
+
+ /**
+ * Sets the OpenGL integer texture parameter for the texture's
+ * target. This gives control over parameters such as
+ * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T, which by default are set
+ * to GL_CLAMP_TO_EDGE if OpenGL 1.2 is supported on the current
+ * platform and GL_CLAMP if not. Causes this texture to be bound to
+ * the current texture state.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void setTexParameteri(int parameterName,
+ int value) {
+ bind();
+ GL gl = GLU.getCurrentGL();
+ gl.glTexParameteri(target, parameterName, value);
}
- return ret;
- }
-
- /**
- * Updates the actual image dimensions; usually only called from
- * <code>updateImage</code>.
- */
- private void setImageSize(int width, int height, int target) {
- imgWidth = width;
- imgHeight = height;
- if (target == GL2.GL_TEXTURE_RECTANGLE) {
- if (mustFlipVertically) {
- coords = new TextureCoords(0, imgHeight, imgWidth, 0);
- } else {
- coords = new TextureCoords(0, 0, imgWidth, imgHeight);
- }
- } else {
- if (mustFlipVertically) {
- coords = new TextureCoords(0, (float) imgHeight / (float) texHeight,
- (float) imgWidth / (float) texWidth, 0);
- } else {
- coords = new TextureCoords(0, 0,
- (float) imgWidth / (float) texWidth,
- (float) imgHeight / (float) texHeight);
- }
+
+ /**
+ * Sets the OpenGL multi-integer texture parameter for the texture's
+ * target. Causes this texture to be bound to the current texture
+ * state.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void setTexParameteriv(int parameterName,
+ IntBuffer params) {
+ bind();
+ GL gl = GLU.getCurrentGL();
+ gl.glTexParameteriv(target, parameterName, params);
}
- }
-
- private void updateSubImageImpl(TextureData data, int newTarget, int mipmapLevel,
- int dstx, int dsty,
- int srcx, int srcy, int width, int height) throws GLException {
- GL gl = GLU.getCurrentGL();
- data.setHaveEXTABGR(gl.isExtensionAvailable("GL_EXT_abgr"));
- data.setHaveGL12(gl.isExtensionAvailable("GL_VERSION_1_2"));
-
- Buffer buffer = data.getBuffer();
- if (buffer == null && data.getMipmapData() == null) {
- // Assume user just wanted to get the Texture object allocated
- return;
+
+ /**
+ * Sets the OpenGL multi-integer texture parameter for the texture's
+ * target. Causes this texture to be bound to the current texture
+ * state.
+ *
+ * @throws GLException if no OpenGL context was current or if any
+ * OpenGL-related errors occurred
+ */
+ public void setTexParameteriv(int parameterName,
+ int[] params, int params_offset) {
+ bind();
+ GL gl = GLU.getCurrentGL();
+ gl.glTexParameteriv(target, parameterName, params, params_offset);
}
- int rowlen = data.getRowLength();
- int dataWidth = data.getWidth();
- int dataHeight = data.getHeight();
- if (data.getMipmapData() != null) {
- // Compute the width, height and row length at the specified mipmap level
- // Note we do not support specification of the row length for
- // mipmapped textures at this point
- for (int i = 0; i < mipmapLevel; i++) {
- width = Math.max(width / 2, 1);
- height = Math.max(height / 2, 1);
-
- dataWidth = Math.max(dataWidth / 2, 1);
- dataHeight = Math.max(dataHeight / 2, 1);
- }
- rowlen = 0;
- buffer = data.getMipmapData()[mipmapLevel];
+ /**
+ * Returns the underlying OpenGL texture object for this texture.
+ * Most applications will not need to access this, since it is
+ * handled automatically by the bind() and dispose() APIs.
+ */
+ public int getTextureObject() {
+ return texID;
}
- // Clip incoming rectangles to what is available both on this
- // texture and in the incoming TextureData
- if (srcx < 0) {
- width += srcx;
- srcx = 0;
+ /** Returns an estimate of the amount of texture memory in bytes
+ this Texture consumes. It should only be treated as an estimate;
+ most applications should not need to query this but instead let
+ the OpenGL implementation page textures in and out as
+ necessary. */
+ public int getEstimatedMemorySize() {
+ return estimatedMemorySize;
}
- if (srcy < 0) {
- height += srcy;
- srcy = 0;
+
+ /** Indicates whether this Texture is using automatic mipmap
+ generation (via the OpenGL texture parameter
+ GL_GENERATE_MIPMAP). This will automatically be used when
+ mipmapping is requested via the TextureData and either OpenGL
+ 1.4 or the GL_SGIS_generate_mipmap extension is available. If
+ so, updates to the base image (mipmap level 0) will
+ automatically propagate down to the lower mipmap levels. Manual
+ updates of the mipmap data at these lower levels will be
+ ignored. */
+ public boolean isUsingAutoMipmapGeneration() {
+ return usingAutoMipmapGeneration;
}
- // NOTE: not sure whether the following two are the correct thing to do
- if (dstx < 0) {
- width += dstx;
- dstx = 0;
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ /**
+ * Returns true if the given value is a power of two.
+ *
+ * @return true if the given value is a power of two, false otherwise
+ */
+ private static boolean isPowerOfTwo(int val) {
+ return ((val & (val - 1)) == 0);
}
- if (dsty < 0) {
- height += dsty;
- dsty = 0;
+
+ /**
+ * Returns the nearest power of two that is larger than the given value.
+ * If the given value is already a power of two, this method will simply
+ * return that value.
+ *
+ * @param val the value
+ * @return the next power of two
+ */
+ private static int nextPowerOfTwo(int val) {
+ int ret = 1;
+ while (ret < val) {
+ ret <<= 1;
+ }
+ return ret;
}
- if (srcx + width > dataWidth) {
- width = dataWidth - srcx;
+ /**
+ * Updates the actual image dimensions; usually only called from
+ * <code>updateImage</code>.
+ */
+ private void setImageSize(int width, int height, int target) {
+ imgWidth = width;
+ imgHeight = height;
+ if (target == GL2.GL_TEXTURE_RECTANGLE) {
+ if (mustFlipVertically) {
+ coords = new TextureCoords(0, imgHeight, imgWidth, 0);
+ } else {
+ coords = new TextureCoords(0, 0, imgWidth, imgHeight);
+ }
+ } else {
+ if (mustFlipVertically) {
+ coords = new TextureCoords(0, (float) imgHeight / (float) texHeight,
+ (float) imgWidth / (float) texWidth, 0);
+ } else {
+ coords = new TextureCoords(0, 0,
+ (float) imgWidth / (float) texWidth,
+ (float) imgHeight / (float) texHeight);
+ }
+ }
}
- if (srcy + height > dataHeight) {
- height = dataHeight - srcy;
+
+ private void updateSubImageImpl(TextureData data, int newTarget, int mipmapLevel,
+ int dstx, int dsty,
+ int srcx, int srcy, int width, int height) throws GLException {
+ GL gl = GLU.getCurrentGL();
+ data.setHaveEXTABGR(gl.isExtensionAvailable("GL_EXT_abgr"));
+ data.setHaveGL12(gl.isExtensionAvailable("GL_VERSION_1_2"));
+
+ Buffer buffer = data.getBuffer();
+ if (buffer == null && data.getMipmapData() == null) {
+ // Assume user just wanted to get the Texture object allocated
+ return;
+ }
+
+ int rowlen = data.getRowLength();
+ int dataWidth = data.getWidth();
+ int dataHeight = data.getHeight();
+ if (data.getMipmapData() != null) {
+ // Compute the width, height and row length at the specified mipmap level
+ // Note we do not support specification of the row length for
+ // mipmapped textures at this point
+ for (int i = 0; i < mipmapLevel; i++) {
+ width = Math.max(width / 2, 1);
+ height = Math.max(height / 2, 1);
+
+ dataWidth = Math.max(dataWidth / 2, 1);
+ dataHeight = Math.max(dataHeight / 2, 1);
+ }
+ rowlen = 0;
+ buffer = data.getMipmapData()[mipmapLevel];
+ }
+
+ // Clip incoming rectangles to what is available both on this
+ // texture and in the incoming TextureData
+ if (srcx < 0) {
+ width += srcx;
+ srcx = 0;
+ }
+ if (srcy < 0) {
+ height += srcy;
+ srcy = 0;
+ }
+ // NOTE: not sure whether the following two are the correct thing to do
+ if (dstx < 0) {
+ width += dstx;
+ dstx = 0;
+ }
+ if (dsty < 0) {
+ height += dsty;
+ dsty = 0;
+ }
+
+ if (srcx + width > dataWidth) {
+ width = dataWidth - srcx;
+ }
+ if (srcy + height > dataHeight) {
+ height = dataHeight - srcy;
+ }
+ if (dstx + width > texWidth) {
+ width = texWidth - dstx;
+ }
+ if (dsty + height > texHeight) {
+ height = texHeight - dsty;
+ }
+
+ checkCompressedTextureExtensions(data);
+
+ if (data.isDataCompressed()) {
+ gl.glCompressedTexSubImage2D(newTarget, mipmapLevel,
+ dstx, dsty, width, height,
+ data.getInternalFormat(),
+ buffer.remaining(), buffer);
+ } else {
+ int[] align = { 0 };
+ int[] rowLength = { 0 };
+ int[] skipRows = { 0 };
+ int[] skipPixels = { 0 };
+ gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment
+ if(gl.isGL2()) {
+ gl.glGetIntegerv(GL2.GL_UNPACK_ROW_LENGTH, rowLength, 0); // save row length
+ gl.glGetIntegerv(GL2.GL_UNPACK_SKIP_ROWS, skipRows, 0); // save skipped rows
+ gl.glGetIntegerv(GL2.GL_UNPACK_SKIP_PIXELS, skipPixels, 0); // save skipped pixels
+ }
+ gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment());
+ if (DEBUG && VERBOSE) {
+ System.out.println("Row length = " + rowlen);
+ System.out.println("skip pixels = " + srcx);
+ System.out.println("skip rows = " + srcy);
+ System.out.println("dstx = " + dstx);
+ System.out.println("dsty = " + dsty);
+ System.out.println("width = " + width);
+ System.out.println("height = " + height);
+ }
+ if(gl.isGL2()) {
+ gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, rowlen);
+ gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, srcy);
+ gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, srcx);
+ } else {
+ if ( rowlen!=0 && rowlen!=width &&
+ srcy!=0 && srcx!=0 ) {
+ throw new GLException("rowlen and/or x/y offset only available for GL2");
+ }
+ }
+
+ gl.glTexSubImage2D(newTarget, mipmapLevel,
+ dstx, dsty, width, height,
+ data.getPixelFormat(), data.getPixelType(),
+ buffer);
+ gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment
+ if(gl.isGL2()) {
+ gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, rowLength[0]); // restore row length
+ gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, skipRows[0]); // restore skipped rows
+ gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, skipPixels[0]); // restore skipped pixels
+ }
+ }
}
- if (dstx + width > texWidth) {
- width = texWidth - dstx;
+
+ private void checkCompressedTextureExtensions(TextureData data) {
+ GL gl = GLU.getCurrentGL();
+ if (data.isDataCompressed()) {
+ switch (data.getInternalFormat()) {
+ case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ if (!gl.isExtensionAvailable("GL_EXT_texture_compression_s3tc") &&
+ !gl.isExtensionAvailable("GL_NV_texture_compression_vtc")) {
+ throw new GLException("DXTn compressed textures not supported by this graphics card");
+ }
+ break;
+ default:
+ // FI1027GXME: should test availability of more texture
+ // compression extensions here
+ break;
+ }
+ }
}
- if (dsty + height > texHeight) {
- height = texHeight - dsty;
+
+ /**
+ * Creates a new texture ID.
+ *
+ * @param gl the GL object associated with the current OpenGL context
+ * @return a new texture ID
+ */
+ private static int createTextureID(GL gl) {
+ int[] tmp = new int[1];
+ gl.glGenTextures(1, tmp, 0);
+ return tmp[0];
}
- checkCompressedTextureExtensions(data);
-
- if (data.isDataCompressed()) {
- gl.glCompressedTexSubImage2D(newTarget, mipmapLevel,
- dstx, dsty, width, height,
- data.getInternalFormat(),
- buffer.remaining(), buffer);
- } else {
- int[] align = { 0 };
- int[] rowLength = { 0 };
- int[] skipRows = { 0 };
- int[] skipPixels = { 0 };
- gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment
- if(gl.isGL2()) {
- gl.glGetIntegerv(GL2.GL_UNPACK_ROW_LENGTH, rowLength, 0); // save row length
- gl.glGetIntegerv(GL2.GL_UNPACK_SKIP_ROWS, skipRows, 0); // save skipped rows
- gl.glGetIntegerv(GL2.GL_UNPACK_SKIP_PIXELS, skipPixels, 0); // save skipped pixels
- }
- gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment());
- if (DEBUG && VERBOSE) {
- System.out.println("Row length = " + rowlen);
- System.out.println("skip pixels = " + srcx);
- System.out.println("skip rows = " + srcy);
- System.out.println("dstx = " + dstx);
- System.out.println("dsty = " + dsty);
- System.out.println("width = " + width);
- System.out.println("height = " + height);
- }
- if(gl.isGL2()) {
- gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, rowlen);
- gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, srcy);
- gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, srcx);
- } else {
- if ( rowlen!=0 && rowlen!=width &&
- srcy!=0 && srcx!=0 ) {
- throw new GLException("rowlen and/or x/y offset only available for GL2");
- }
- }
-
- gl.glTexSubImage2D(newTarget, mipmapLevel,
- dstx, dsty, width, height,
- data.getPixelFormat(), data.getPixelType(),
- buffer);
- gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment
- if(gl.isGL2()) {
- gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, rowLength[0]); // restore row length
- gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, skipRows[0]); // restore skipped rows
- gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, skipPixels[0]); // restore skipped pixels
- }
+ // Helper routines for disabling certain codepaths
+ private static boolean haveNPOT(GL gl) {
+ return (!disableNPOT &&
+ gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two"));
}
- }
-
- private void checkCompressedTextureExtensions(TextureData data) {
- GL gl = GLU.getCurrentGL();
- if (data.isDataCompressed()) {
- switch (data.getInternalFormat()) {
- case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- if (!gl.isExtensionAvailable("GL_EXT_texture_compression_s3tc") &&
- !gl.isExtensionAvailable("GL_NV_texture_compression_vtc")) {
- throw new GLException("DXTn compressed textures not supported by this graphics card");
- }
- break;
- default:
- // FI1027GXME: should test availability of more texture
- // compression extensions here
- break;
- }
+
+ private static boolean haveTexRect(GL gl) {
+ return (!disableTexRect &&
+ TextureIO.isTexRectEnabled() &&
+ gl.isExtensionAvailable("GL_ARB_texture_rectangle"));
}
- }
-
- /**
- * Creates a new texture ID.
- *
- * @param gl the GL object associated with the current OpenGL context
- * @return a new texture ID
- */
- private static int createTextureID(GL gl) {
- int[] tmp = new int[1];
- gl.glGenTextures(1, tmp, 0);
- return tmp[0];
- }
-
- // Helper routines for disabling certain codepaths
- private static boolean haveNPOT(GL gl) {
- return (!disableNPOT &&
- gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two"));
- }
-
- private static boolean haveTexRect(GL gl) {
- return (!disableTexRect &&
- TextureIO.isTexRectEnabled() &&
- gl.isExtensionAvailable("GL_ARB_texture_rectangle"));
- }
}
diff --git a/src/classes/com/sun/opengl/util/texture/TextureCoords.java b/src/classes/com/sun/opengl/util/texture/TextureCoords.java
index dca1d1e01..51710e077 100755
--- a/src/classes/com/sun/opengl/util/texture/TextureCoords.java
+++ b/src/classes/com/sun/opengl/util/texture/TextureCoords.java
@@ -46,34 +46,34 @@ package com.sun.opengl.util.texture;
textured polygon and achieve correct results. */
public class TextureCoords {
- // These represent the lower-left point
- private float left;
- private float bottom;
- // These represent the upper-right point
- private float right;
- private float top;
+ // These represent the lower-left point
+ private float left;
+ private float bottom;
+ // These represent the upper-right point
+ private float right;
+ private float top;
- public TextureCoords(float left, float bottom,
- float right, float top) {
- this.left = left;
- this.bottom = bottom;
- this.right = right;
- this.top = top;
- }
+ public TextureCoords(float left, float bottom,
+ float right, float top) {
+ this.left = left;
+ this.bottom = bottom;
+ this.right = right;
+ this.top = top;
+ }
- /** Returns the leftmost (x) texture coordinate of this
- rectangle. */
- public float left() { return left; }
+ /** Returns the leftmost (x) texture coordinate of this
+ rectangle. */
+ public float left() { return left; }
- /** Returns the rightmost (x) texture coordinate of this
- rectangle. */
- public float right() { return right; }
+ /** Returns the rightmost (x) texture coordinate of this
+ rectangle. */
+ public float right() { return right; }
- /** Returns the bottommost (y) texture coordinate of this
- rectangle. */
- public float bottom() { return bottom; }
+ /** Returns the bottommost (y) texture coordinate of this
+ rectangle. */
+ public float bottom() { return bottom; }
- /** Returns the topmost (y) texture coordinate of this
- rectangle. */
- public float top() { return top; }
+ /** Returns the topmost (y) texture coordinate of this
+ rectangle. */
+ public float top() { return top; }
}
diff --git a/src/classes/com/sun/opengl/util/texture/TextureData.java b/src/classes/com/sun/opengl/util/texture/TextureData.java
index 464305311..5316ed191 100755
--- a/src/classes/com/sun/opengl/util/texture/TextureData.java
+++ b/src/classes/com/sun/opengl/util/texture/TextureData.java
@@ -53,291 +53,291 @@ import com.sun.opengl.util.*;
*/
public class TextureData {
- protected int width;
- protected int height;
- private int border;
- protected int pixelFormat;
- protected int pixelType;
- protected int internalFormat; // perhaps inferred from pixelFormat?
- protected boolean mipmap; // indicates whether mipmaps should be generated
- // (ignored if mipmaps are supplied from the file)
- private boolean dataIsCompressed;
- protected boolean mustFlipVertically; // Must flip texture coordinates
- // vertically to get OpenGL output
- // to look correct
- protected Buffer buffer; // the actual data...
- private Buffer[] mipmapData; // ...or a series of mipmaps
- private Flusher flusher;
- protected int rowLength;
- protected int alignment; // 1, 2, or 4 bytes
- protected int estimatedMemorySize;
+ protected int width;
+ protected int height;
+ private int border;
+ protected int pixelFormat;
+ protected int pixelType;
+ protected int internalFormat; // perhaps inferred from pixelFormat?
+ protected boolean mipmap; // indicates whether mipmaps should be generated
+ // (ignored if mipmaps are supplied from the file)
+ private boolean dataIsCompressed;
+ protected boolean mustFlipVertically; // Must flip texture coordinates
+ // vertically to get OpenGL output
+ // to look correct
+ protected Buffer buffer; // the actual data...
+ private Buffer[] mipmapData; // ...or a series of mipmaps
+ private Flusher flusher;
+ protected int rowLength;
+ protected int alignment; // 1, 2, or 4 bytes
+ protected int estimatedMemorySize;
- // These booleans are a concession to the AWTTextureData subclass
- protected boolean haveEXTABGR;
- protected boolean haveGL12;
+ // These booleans are a concession to the AWTTextureData subclass
+ protected boolean haveEXTABGR;
+ protected boolean haveGL12;
- /**
- * Constructs a new TextureData object with the specified parameters
- * and data contained in the given Buffer. The optional Flusher can
- * be used to clean up native resources associated with this
- * TextureData when processing is complete; for example, closing of
- * memory-mapped files that might otherwise require a garbage
- * collection to reclaim and close.
- *
- * @param internalFormat the OpenGL internal format for the
- * resulting texture; must be specified, may
- * not be 0
- * @param width the width in pixels of the texture
- * @param height the height in pixels of the texture
- * @param border the number of pixels of border this texture
- * data has (0 or 1)
- * @param pixelFormat the OpenGL pixel format for the
- * resulting texture; must be specified, may
- * not be 0
- * @param pixelType the OpenGL type of the pixels of the texture
- * @param mipmap indicates whether mipmaps should be
- * autogenerated (using GLU) for the resulting
- * texture. Currently if mipmap is true then
- * dataIsCompressed may not be true.
- * @param dataIsCompressed indicates whether the texture data is in
- * compressed form
- * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
- * @param mustFlipVertically indicates whether the texture
- * coordinates must be flipped vertically
- * in order to properly display the
- * texture
- * @param buffer the buffer containing the texture data
- * @param flusher optional flusher to perform cleanup tasks
- * upon call to flush()
- *
- * @throws IllegalArgumentException if any parameters of the texture
- * data were invalid, such as requesting mipmap generation for a
- * compressed texture
- */
- public TextureData(int internalFormat,
- int width,
- int height,
- int border,
- int pixelFormat,
- int pixelType,
- boolean mipmap,
- boolean dataIsCompressed,
- boolean mustFlipVertically,
- Buffer buffer,
- Flusher flusher) throws IllegalArgumentException {
- if (mipmap && dataIsCompressed) {
- throw new IllegalArgumentException("Can not generate mipmaps for compressed textures");
- }
+ /**
+ * Constructs a new TextureData object with the specified parameters
+ * and data contained in the given Buffer. The optional Flusher can
+ * be used to clean up native resources associated with this
+ * TextureData when processing is complete; for example, closing of
+ * memory-mapped files that might otherwise require a garbage
+ * collection to reclaim and close.
+ *
+ * @param internalFormat the OpenGL internal format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param width the width in pixels of the texture
+ * @param height the height in pixels of the texture
+ * @param border the number of pixels of border this texture
+ * data has (0 or 1)
+ * @param pixelFormat the OpenGL pixel format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param pixelType the OpenGL type of the pixels of the texture
+ * @param mipmap indicates whether mipmaps should be
+ * autogenerated (using GLU) for the resulting
+ * texture. Currently if mipmap is true then
+ * dataIsCompressed may not be true.
+ * @param dataIsCompressed indicates whether the texture data is in
+ * compressed form
+ * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
+ * @param mustFlipVertically indicates whether the texture
+ * coordinates must be flipped vertically
+ * in order to properly display the
+ * texture
+ * @param buffer the buffer containing the texture data
+ * @param flusher optional flusher to perform cleanup tasks
+ * upon call to flush()
+ *
+ * @throws IllegalArgumentException if any parameters of the texture
+ * data were invalid, such as requesting mipmap generation for a
+ * compressed texture
+ */
+ public TextureData(int internalFormat,
+ int width,
+ int height,
+ int border,
+ int pixelFormat,
+ int pixelType,
+ boolean mipmap,
+ boolean dataIsCompressed,
+ boolean mustFlipVertically,
+ Buffer buffer,
+ Flusher flusher) throws IllegalArgumentException {
+ if (mipmap && dataIsCompressed) {
+ throw new IllegalArgumentException("Can not generate mipmaps for compressed textures");
+ }
- this.width = width;
- this.height = height;
- this.border = border;
- this.pixelFormat = pixelFormat;
- this.pixelType = pixelType;
- this.internalFormat = internalFormat;
- this.mipmap = mipmap;
- this.dataIsCompressed = dataIsCompressed;
- this.mustFlipVertically = mustFlipVertically;
- this.buffer = buffer;
- this.flusher = flusher;
- alignment = 1; // FIXME: is this correct enough in all situations?
- estimatedMemorySize = estimatedMemorySize(buffer);
- }
+ this.width = width;
+ this.height = height;
+ this.border = border;
+ this.pixelFormat = pixelFormat;
+ this.pixelType = pixelType;
+ this.internalFormat = internalFormat;
+ this.mipmap = mipmap;
+ this.dataIsCompressed = dataIsCompressed;
+ this.mustFlipVertically = mustFlipVertically;
+ this.buffer = buffer;
+ this.flusher = flusher;
+ alignment = 1; // FIXME: is this correct enough in all situations?
+ estimatedMemorySize = estimatedMemorySize(buffer);
+ }
- /**
- * Constructs a new TextureData object with the specified parameters
- * and data for multiple mipmap levels contained in the given array
- * of Buffers. The optional Flusher can be used to clean up native
- * resources associated with this TextureData when processing is
- * complete; for example, closing of memory-mapped files that might
- * otherwise require a garbage collection to reclaim and close.
- *
- * @param internalFormat the OpenGL internal format for the
- * resulting texture; must be specified, may
- * not be 0
- * @param width the width in pixels of the topmost mipmap
- * level of the texture
- * @param height the height in pixels of the topmost mipmap
- * level of the texture
- * @param border the number of pixels of border this texture
- * data has (0 or 1)
- * @param pixelFormat the OpenGL pixel format for the
- * resulting texture; must be specified, may
- * not be 0
- * @param pixelType the OpenGL type of the pixels of the texture
- * @param dataIsCompressed indicates whether the texture data is in
- * compressed form
- * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
- * @param mustFlipVertically indicates whether the texture
- * coordinates must be flipped vertically
- * in order to properly display the
- * texture
- * @param mipmapData the buffers containing all mipmap levels
- * of the texture's data
- * @param flusher optional flusher to perform cleanup tasks
- * upon call to flush()
- *
- * @throws IllegalArgumentException if any parameters of the texture
- * data were invalid, such as requesting mipmap generation for a
- * compressed texture
- */
- public TextureData(int internalFormat,
- int width,
- int height,
- int border,
- int pixelFormat,
- int pixelType,
- boolean dataIsCompressed,
- boolean mustFlipVertically,
- Buffer[] mipmapData,
- Flusher flusher) throws IllegalArgumentException {
- this.width = width;
- this.height = height;
- this.border = border;
- this.pixelFormat = pixelFormat;
- this.pixelType = pixelType;
- this.internalFormat = internalFormat;
- this.dataIsCompressed = dataIsCompressed;
- this.mustFlipVertically = mustFlipVertically;
- this.mipmapData = (Buffer[]) mipmapData.clone();
- this.flusher = flusher;
- alignment = 1; // FIXME: is this correct enough in all situations?
- for (int i = 0; i < mipmapData.length; i++) {
- estimatedMemorySize += estimatedMemorySize(mipmapData[i]);
+ /**
+ * Constructs a new TextureData object with the specified parameters
+ * and data for multiple mipmap levels contained in the given array
+ * of Buffers. The optional Flusher can be used to clean up native
+ * resources associated with this TextureData when processing is
+ * complete; for example, closing of memory-mapped files that might
+ * otherwise require a garbage collection to reclaim and close.
+ *
+ * @param internalFormat the OpenGL internal format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param width the width in pixels of the topmost mipmap
+ * level of the texture
+ * @param height the height in pixels of the topmost mipmap
+ * level of the texture
+ * @param border the number of pixels of border this texture
+ * data has (0 or 1)
+ * @param pixelFormat the OpenGL pixel format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param pixelType the OpenGL type of the pixels of the texture
+ * @param dataIsCompressed indicates whether the texture data is in
+ * compressed form
+ * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
+ * @param mustFlipVertically indicates whether the texture
+ * coordinates must be flipped vertically
+ * in order to properly display the
+ * texture
+ * @param mipmapData the buffers containing all mipmap levels
+ * of the texture's data
+ * @param flusher optional flusher to perform cleanup tasks
+ * upon call to flush()
+ *
+ * @throws IllegalArgumentException if any parameters of the texture
+ * data were invalid, such as requesting mipmap generation for a
+ * compressed texture
+ */
+ public TextureData(int internalFormat,
+ int width,
+ int height,
+ int border,
+ int pixelFormat,
+ int pixelType,
+ boolean dataIsCompressed,
+ boolean mustFlipVertically,
+ Buffer[] mipmapData,
+ Flusher flusher) throws IllegalArgumentException {
+ this.width = width;
+ this.height = height;
+ this.border = border;
+ this.pixelFormat = pixelFormat;
+ this.pixelType = pixelType;
+ this.internalFormat = internalFormat;
+ this.dataIsCompressed = dataIsCompressed;
+ this.mustFlipVertically = mustFlipVertically;
+ this.mipmapData = (Buffer[]) mipmapData.clone();
+ this.flusher = flusher;
+ alignment = 1; // FIXME: is this correct enough in all situations?
+ for (int i = 0; i < mipmapData.length; i++) {
+ estimatedMemorySize += estimatedMemorySize(mipmapData[i]);
+ }
}
- }
- /** Used only by subclasses */
- protected TextureData() {
- }
+ /** Used only by subclasses */
+ protected TextureData() {
+ }
- /** Returns the width in pixels of the texture data. */
- public int getWidth() { return width; }
- /** Returns the height in pixels of the texture data. */
- public int getHeight() { return height; }
- /** Returns the border in pixels of the texture data. */
- public int getBorder() { return border; }
- /** Returns the intended OpenGL pixel format of the texture data. */
- public int getPixelFormat() {
- return pixelFormat;
- }
- /** Returns the intended OpenGL pixel type of the texture data. */
- public int getPixelType() {
- return pixelType;
- }
- /** Returns the intended OpenGL internal format of the texture data. */
- public int getInternalFormat() { return internalFormat; }
- /** Returns whether mipmaps should be generated for the texture data. */
- public boolean getMipmap() { return mipmap; }
- /** Indicates whether the texture data is in compressed form. */
- public boolean isDataCompressed() { return dataIsCompressed; }
- /** Indicates whether the texture coordinates must be flipped
- 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;
- }
- /** 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; }
+ /** Returns the width in pixels of the texture data. */
+ public int getWidth() { return width; }
+ /** Returns the height in pixels of the texture data. */
+ public int getHeight() { return height; }
+ /** Returns the border in pixels of the texture data. */
+ public int getBorder() { return border; }
+ /** Returns the intended OpenGL pixel format of the texture data. */
+ public int getPixelFormat() {
+ return pixelFormat;
+ }
+ /** Returns the intended OpenGL pixel type of the texture data. */
+ public int getPixelType() {
+ return pixelType;
+ }
+ /** Returns the intended OpenGL internal format of the texture data. */
+ public int getInternalFormat() { return internalFormat; }
+ /** Returns whether mipmaps should be generated for the texture data. */
+ public boolean getMipmap() { return mipmap; }
+ /** Indicates whether the texture data is in compressed form. */
+ public boolean isDataCompressed() { return dataIsCompressed; }
+ /** Indicates whether the texture coordinates must be flipped
+ 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;
+ }
+ /** 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; }
- /** Sets the height in pixels of the texture data. */
- public void setHeight(int height) { this.height = height; }
- /** Sets the border in pixels of the texture data. */
- public void setBorder(int border) { this.border = border; }
- /** Sets the intended OpenGL pixel format of the texture data. */
- public void setPixelFormat(int pixelFormat) { this.pixelFormat = pixelFormat; }
- /** Sets the intended OpenGL pixel type of the texture data. */
- public void setPixelType(int pixelType) { this.pixelType = pixelType; }
- /** Sets the intended OpenGL internal format of the texture data. */
- public void setInternalFormat(int internalFormat) { this.internalFormat = internalFormat; }
- /** Sets whether mipmaps should be generated for the texture data. */
- public void setMipmap(boolean mipmap) { this.mipmap = mipmap; }
- /** Sets whether the texture data is in compressed form. */
- public void setIsDataCompressed(boolean compressed) { this.dataIsCompressed = compressed; }
- /** Sets whether the texture coordinates must be flipped vertically
- for proper display. */
- public void setMustFlipVertically(boolean mustFlipVertically) { this.mustFlipVertically = mustFlipVertically; }
- /** Sets the texture data. */
- public void setBuffer(Buffer buffer) {
- this.buffer = buffer;
- estimatedMemorySize = estimatedMemorySize(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;
- }
- /** Indicates to this TextureData whether OpenGL version 1.2 is
- available. If not, falls back to relatively inefficient code
- paths for several input data types (several kinds of packed
- pixel formats, in particular). */
- public void setHaveGL12(boolean haveGL12) {
- this.haveGL12 = haveGL12;
- }
+ /** Sets the width in pixels of the texture data. */
+ public void setWidth(int width) { this.width = width; }
+ /** Sets the height in pixels of the texture data. */
+ public void setHeight(int height) { this.height = height; }
+ /** Sets the border in pixels of the texture data. */
+ public void setBorder(int border) { this.border = border; }
+ /** Sets the intended OpenGL pixel format of the texture data. */
+ public void setPixelFormat(int pixelFormat) { this.pixelFormat = pixelFormat; }
+ /** Sets the intended OpenGL pixel type of the texture data. */
+ public void setPixelType(int pixelType) { this.pixelType = pixelType; }
+ /** Sets the intended OpenGL internal format of the texture data. */
+ public void setInternalFormat(int internalFormat) { this.internalFormat = internalFormat; }
+ /** Sets whether mipmaps should be generated for the texture data. */
+ public void setMipmap(boolean mipmap) { this.mipmap = mipmap; }
+ /** Sets whether the texture data is in compressed form. */
+ public void setIsDataCompressed(boolean compressed) { this.dataIsCompressed = compressed; }
+ /** Sets whether the texture coordinates must be flipped vertically
+ for proper display. */
+ public void setMustFlipVertically(boolean mustFlipVertically) { this.mustFlipVertically = mustFlipVertically; }
+ /** Sets the texture data. */
+ public void setBuffer(Buffer buffer) {
+ this.buffer = buffer;
+ estimatedMemorySize = estimatedMemorySize(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;
+ }
+ /** Indicates to this TextureData whether OpenGL version 1.2 is
+ available. If not, falls back to relatively inefficient code
+ paths for several input data types (several kinds of packed
+ pixel formats, in particular). */
+ public void setHaveGL12(boolean haveGL12) {
+ this.haveGL12 = haveGL12;
+ }
- /** Returns an estimate of the amount of memory in bytes this
- TextureData will consume once uploaded to the graphics card. It
- should only be treated as an estimate; most applications should
- not need to query this but instead let the OpenGL implementation
- page textures in and out as necessary. */
- public int getEstimatedMemorySize() {
- return estimatedMemorySize;
- }
+ /** Returns an estimate of the amount of memory in bytes this
+ TextureData will consume once uploaded to the graphics card. It
+ should only be treated as an estimate; most applications should
+ not need to query this but instead let the OpenGL implementation
+ page textures in and out as necessary. */
+ public int getEstimatedMemorySize() {
+ return estimatedMemorySize;
+ }
- /** Flushes resources associated with this TextureData by calling
- Flusher.flush(). */
- public void flush() {
- if (flusher != null) {
- flusher.flush();
- flusher = null;
+ /** Flushes resources associated with this TextureData by calling
+ Flusher.flush(). */
+ public void flush() {
+ if (flusher != null) {
+ flusher.flush();
+ flusher = null;
+ }
}
- }
- /** Defines a callback mechanism to allow the user to explicitly
- deallocate native resources (memory-mapped files, etc.)
- associated with a particular TextureData. */
- public static interface Flusher {
- /** Flushes any native resources associated with this
- TextureData. */
- public void flush();
- }
+ /** Defines a callback mechanism to allow the user to explicitly
+ deallocate native resources (memory-mapped files, etc.)
+ associated with a particular TextureData. */
+ public static interface Flusher {
+ /** Flushes any native resources associated with this
+ TextureData. */
+ public void flush();
+ }
- //----------------------------------------------------------------------
- // Internals only below this point
- //
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
- protected int estimatedMemorySize(Buffer buffer) {
- if (buffer == null) {
- return 0;
- }
- int capacity = buffer.capacity();
- if (buffer instanceof ByteBuffer) {
- return capacity;
- } else if (buffer instanceof IntBuffer) {
- return capacity * BufferUtil.SIZEOF_INT;
- } else if (buffer instanceof FloatBuffer) {
- return capacity * BufferUtil.SIZEOF_FLOAT;
- } else if (buffer instanceof ShortBuffer) {
- return capacity * BufferUtil.SIZEOF_SHORT;
+ protected int estimatedMemorySize(Buffer buffer) {
+ if (buffer == null) {
+ return 0;
+ }
+ int capacity = buffer.capacity();
+ if (buffer instanceof ByteBuffer) {
+ return capacity;
+ } else if (buffer instanceof IntBuffer) {
+ return capacity * BufferUtil.SIZEOF_INT;
+ } else if (buffer instanceof FloatBuffer) {
+ return capacity * BufferUtil.SIZEOF_FLOAT;
+ } else if (buffer instanceof ShortBuffer) {
+ return capacity * BufferUtil.SIZEOF_SHORT;
+ }
+ throw new RuntimeException("Unexpected buffer type " +
+ buffer.getClass().getName());
}
- throw new RuntimeException("Unexpected buffer type " +
- buffer.getClass().getName());
- }
}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java
index 01cdf4867..cca8dbd2b 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java
@@ -54,866 +54,866 @@ import com.sun.opengl.util.texture.*;
public class DDSImage {
- /** Simple class describing images and data; does not encapsulate
- image format information. User is responsible for transmitting
- that information in another way. */
-
- public static class ImageInfo {
- private ByteBuffer data;
- private int width;
- private int height;
- private boolean isCompressed;
- private int compressionFormat;
-
- public ImageInfo(ByteBuffer data, int width, int height, boolean compressed, int compressionFormat) {
- this.data = data; this.width = width; this.height = height;
- this.isCompressed = compressed; this.compressionFormat = compressionFormat;
- }
- public int getWidth() { return width; }
- public int getHeight() { return height; }
- public ByteBuffer getData() { return data; }
- public boolean isCompressed() { return isCompressed; }
- public int getCompressionFormat() {
- if (!isCompressed())
- throw new RuntimeException("Should not call unless compressed");
- return compressionFormat;
- }
- }
-
- private FileInputStream fis;
- private FileChannel chan;
- private ByteBuffer buf;
- private Header header;
-
- //
- // Selected bits in header flags
- //
-
- public static final int DDSD_CAPS = 0x00000001; // Capacities are valid
- public static final int DDSD_HEIGHT = 0x00000002; // Height is valid
- public static final int DDSD_WIDTH = 0x00000004; // Width is valid
- public static final int DDSD_PITCH = 0x00000008; // Pitch is valid
- public static final int DDSD_BACKBUFFERCOUNT = 0x00000020; // Back buffer count is valid
- public static final int DDSD_ZBUFFERBITDEPTH = 0x00000040; // Z-buffer bit depth is valid (shouldn't be used in DDSURFACEDESC2)
- public static final int DDSD_ALPHABITDEPTH = 0x00000080; // Alpha bit depth is valid
- public static final int DDSD_LPSURFACE = 0x00000800; // lpSurface is valid
- public static final int DDSD_PIXELFORMAT = 0x00001000; // ddpfPixelFormat is valid
- public static final int DDSD_MIPMAPCOUNT = 0x00020000; // Mip map count is valid
- public static final int DDSD_LINEARSIZE = 0x00080000; // dwLinearSize is valid
- public static final int DDSD_DEPTH = 0x00800000; // dwDepth is valid
-
- public static final int DDPF_ALPHAPIXELS = 0x00000001; // Alpha channel is present
- public static final int DDPF_ALPHA = 0x00000002; // Only contains alpha information
- public static final int DDPF_FOURCC = 0x00000004; // FourCC code is valid
- public static final int DDPF_PALETTEINDEXED4 = 0x00000008; // Surface is 4-bit color indexed
- public static final int DDPF_PALETTEINDEXEDTO8 = 0x00000010; // Surface is indexed into a palette which stores indices
- // into the destination surface's 8-bit palette
- public static final int DDPF_PALETTEINDEXED8 = 0x00000020; // Surface is 8-bit color indexed
- public static final int DDPF_RGB = 0x00000040; // RGB data is present
- public static final int DDPF_COMPRESSED = 0x00000080; // Surface will accept pixel data in the format specified
- // and compress it during the write
- public static final int DDPF_RGBTOYUV = 0x00000100; // Surface will accept RGB data and translate it during
- // the write to YUV data. The format of the data to be written
- // will be contained in the pixel format structure. The DDPF_RGB
- // flag will be set.
- public static final int DDPF_YUV = 0x00000200; // Pixel format is YUV - YUV data in pixel format struct is valid
- public static final int DDPF_ZBUFFER = 0x00000400; // Pixel format is a z buffer only surface
- public static final int DDPF_PALETTEINDEXED1 = 0x00000800; // Surface is 1-bit color indexed
- public static final int DDPF_PALETTEINDEXED2 = 0x00001000; // Surface is 2-bit color indexed
- public static final int DDPF_ZPIXELS = 0x00002000; // Surface contains Z information in the pixels
-
- // Selected bits in DDS capabilities flags
- public static final int DDSCAPS_TEXTURE = 0x00001000; // Can be used as a texture
- public static final int DDSCAPS_MIPMAP = 0x00400000; // Is one level of a mip-map
- public static final int DDSCAPS_COMPLEX = 0x00000008; // Complex surface structure, such as a cube map
-
- // Selected bits in DDS extended capabilities flags
- public static final int DDSCAPS2_CUBEMAP = 0x00000200;
- public static final int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400;
- public static final int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800;
- public static final int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000;
- public static final int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000;
- public static final int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000;
- public static final int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000;
-
- // Known pixel formats
- public static final int D3DFMT_UNKNOWN = 0;
- public static final int D3DFMT_R8G8B8 = 20;
- public static final int D3DFMT_A8R8G8B8 = 21;
- public static final int D3DFMT_X8R8G8B8 = 22;
- // The following are also valid FourCC codes
- public static final int D3DFMT_DXT1 = 0x31545844;
- public static final int D3DFMT_DXT2 = 0x32545844;
- public static final int D3DFMT_DXT3 = 0x33545844;
- public static final int D3DFMT_DXT4 = 0x34545844;
- public static final int D3DFMT_DXT5 = 0x35545844;
-
- /** Reads a DirectDraw surface from the specified file name,
- returning the resulting DDSImage.
-
- @param filename File name
- @return DDS image object
- @throws java.io.IOException if an I/O exception occurred
- */
- public static DDSImage read(String filename) throws IOException {
- return read(new File(filename));
- }
+ /** Simple class describing images and data; does not encapsulate
+ image format information. User is responsible for transmitting
+ that information in another way. */
+
+ public static class ImageInfo {
+ private ByteBuffer data;
+ private int width;
+ private int height;
+ private boolean isCompressed;
+ private int compressionFormat;
+
+ public ImageInfo(ByteBuffer data, int width, int height, boolean compressed, int compressionFormat) {
+ this.data = data; this.width = width; this.height = height;
+ this.isCompressed = compressed; this.compressionFormat = compressionFormat;
+ }
+ public int getWidth() { return width; }
+ public int getHeight() { return height; }
+ public ByteBuffer getData() { return data; }
+ public boolean isCompressed() { return isCompressed; }
+ public int getCompressionFormat() {
+ if (!isCompressed())
+ throw new RuntimeException("Should not call unless compressed");
+ return compressionFormat;
+ }
+ }
+
+ private FileInputStream fis;
+ private FileChannel chan;
+ private ByteBuffer buf;
+ private Header header;
+
+ //
+ // Selected bits in header flags
+ //
+
+ public static final int DDSD_CAPS = 0x00000001; // Capacities are valid
+ public static final int DDSD_HEIGHT = 0x00000002; // Height is valid
+ public static final int DDSD_WIDTH = 0x00000004; // Width is valid
+ public static final int DDSD_PITCH = 0x00000008; // Pitch is valid
+ public static final int DDSD_BACKBUFFERCOUNT = 0x00000020; // Back buffer count is valid
+ public static final int DDSD_ZBUFFERBITDEPTH = 0x00000040; // Z-buffer bit depth is valid (shouldn't be used in DDSURFACEDESC2)
+ public static final int DDSD_ALPHABITDEPTH = 0x00000080; // Alpha bit depth is valid
+ public static final int DDSD_LPSURFACE = 0x00000800; // lpSurface is valid
+ public static final int DDSD_PIXELFORMAT = 0x00001000; // ddpfPixelFormat is valid
+ public static final int DDSD_MIPMAPCOUNT = 0x00020000; // Mip map count is valid
+ public static final int DDSD_LINEARSIZE = 0x00080000; // dwLinearSize is valid
+ public static final int DDSD_DEPTH = 0x00800000; // dwDepth is valid
+
+ public static final int DDPF_ALPHAPIXELS = 0x00000001; // Alpha channel is present
+ public static final int DDPF_ALPHA = 0x00000002; // Only contains alpha information
+ public static final int DDPF_FOURCC = 0x00000004; // FourCC code is valid
+ public static final int DDPF_PALETTEINDEXED4 = 0x00000008; // Surface is 4-bit color indexed
+ public static final int DDPF_PALETTEINDEXEDTO8 = 0x00000010; // Surface is indexed into a palette which stores indices
+ // into the destination surface's 8-bit palette
+ public static final int DDPF_PALETTEINDEXED8 = 0x00000020; // Surface is 8-bit color indexed
+ public static final int DDPF_RGB = 0x00000040; // RGB data is present
+ public static final int DDPF_COMPRESSED = 0x00000080; // Surface will accept pixel data in the format specified
+ // and compress it during the write
+ public static final int DDPF_RGBTOYUV = 0x00000100; // Surface will accept RGB data and translate it during
+ // the write to YUV data. The format of the data to be written
+ // will be contained in the pixel format structure. The DDPF_RGB
+ // flag will be set.
+ public static final int DDPF_YUV = 0x00000200; // Pixel format is YUV - YUV data in pixel format struct is valid
+ public static final int DDPF_ZBUFFER = 0x00000400; // Pixel format is a z buffer only surface
+ public static final int DDPF_PALETTEINDEXED1 = 0x00000800; // Surface is 1-bit color indexed
+ public static final int DDPF_PALETTEINDEXED2 = 0x00001000; // Surface is 2-bit color indexed
+ public static final int DDPF_ZPIXELS = 0x00002000; // Surface contains Z information in the pixels
+
+ // Selected bits in DDS capabilities flags
+ public static final int DDSCAPS_TEXTURE = 0x00001000; // Can be used as a texture
+ public static final int DDSCAPS_MIPMAP = 0x00400000; // Is one level of a mip-map
+ public static final int DDSCAPS_COMPLEX = 0x00000008; // Complex surface structure, such as a cube map
+
+ // Selected bits in DDS extended capabilities flags
+ public static final int DDSCAPS2_CUBEMAP = 0x00000200;
+ public static final int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400;
+ public static final int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800;
+ public static final int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000;
+ public static final int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000;
+ public static final int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000;
+ public static final int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000;
+
+ // Known pixel formats
+ public static final int D3DFMT_UNKNOWN = 0;
+ public static final int D3DFMT_R8G8B8 = 20;
+ public static final int D3DFMT_A8R8G8B8 = 21;
+ public static final int D3DFMT_X8R8G8B8 = 22;
+ // The following are also valid FourCC codes
+ public static final int D3DFMT_DXT1 = 0x31545844;
+ public static final int D3DFMT_DXT2 = 0x32545844;
+ public static final int D3DFMT_DXT3 = 0x33545844;
+ public static final int D3DFMT_DXT4 = 0x34545844;
+ public static final int D3DFMT_DXT5 = 0x35545844;
+
+ /** Reads a DirectDraw surface from the specified file name,
+ returning the resulting DDSImage.
+
+ @param filename File name
+ @return DDS image object
+ @throws java.io.IOException if an I/O exception occurred
+ */
+ public static DDSImage read(String filename) throws IOException {
+ return read(new File(filename));
+ }
- /** Reads a DirectDraw surface from the specified file, returning
- the resulting DDSImage.
-
- @param file File object
- @return DDS image object
- @throws java.io.IOException if an I/O exception occurred
- */
- public static DDSImage read(File file) throws IOException {
- DDSImage image = new DDSImage();
- image.readFromFile(file);
- return image;
- }
-
- /** Reads a DirectDraw surface from the specified ByteBuffer, returning
- the resulting DDSImage.
-
- @param buf Input data
- @return DDS image object
- @throws java.io.IOException if an I/O exception occurred
- */
- public static DDSImage read(ByteBuffer buf) throws IOException {
- DDSImage image = new DDSImage();
- image.readFromBuffer(buf);
- return image;
- }
-
- /** Closes open files and resources associated with the open
- DDSImage. No other methods may be called on this object once
- this is called. */
- public void close() {
- try {
- if (chan != null) {
- chan.close();
- chan = null;
- }
- if (fis != null) {
- fis.close();
- fis = null;
- }
- buf = null;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Creates a new DDSImage from data supplied by the user. The
- * resulting DDSImage can be written to disk using the write()
- * method.
- *
- * @param d3dFormat the D3DFMT_ constant describing the data; it is
- * assumed that it is packed tightly
- * @param width the width in pixels of the topmost mipmap image
- * @param height the height in pixels of the topmost mipmap image
- * @param mipmapData the data for each mipmap level of the resulting
- * DDSImage; either only one mipmap level should
- * be specified, or they all must be
- * @throws IllegalArgumentException if the data does not match the
- * specified arguments
- * @return DDS image object
- */
- public static DDSImage createFromData(int d3dFormat,
- int width,
- int height,
- ByteBuffer[] mipmapData) throws IllegalArgumentException {
- DDSImage image = new DDSImage();
- image.initFromData(d3dFormat, width, height, mipmapData);
- return image;
- }
-
- /** Determines from the magic number whether the given InputStream
- points to a DDS image. The given InputStream must return true
- from markSupported() and support a minimum of four bytes of
- read-ahead.
-
- @param in Stream to check
- @return true if input stream is DDS image or false otherwise
- @throws java.io.IOException if an I/O exception occurred
- */
- public static boolean isDDSImage(InputStream in) throws IOException {
- if (!(in instanceof BufferedInputStream)) {
- in = new BufferedInputStream(in);
- }
- if (!in.markSupported()) {
- throw new IOException("Can not test non-destructively whether given InputStream is a DDS image");
- }
- in.mark(4);
- int magic = 0;
- for (int i = 0; i < 4; i++) {
- int tmp = in.read();
- if (tmp < 0) {
+ /** Reads a DirectDraw surface from the specified file, returning
+ the resulting DDSImage.
+
+ @param file File object
+ @return DDS image object
+ @throws java.io.IOException if an I/O exception occurred
+ */
+ public static DDSImage read(File file) throws IOException {
+ DDSImage image = new DDSImage();
+ image.readFromFile(file);
+ return image;
+ }
+
+ /** Reads a DirectDraw surface from the specified ByteBuffer, returning
+ the resulting DDSImage.
+
+ @param buf Input data
+ @return DDS image object
+ @throws java.io.IOException if an I/O exception occurred
+ */
+ public static DDSImage read(ByteBuffer buf) throws IOException {
+ DDSImage image = new DDSImage();
+ image.readFromBuffer(buf);
+ return image;
+ }
+
+ /** Closes open files and resources associated with the open
+ DDSImage. No other methods may be called on this object once
+ this is called. */
+ public void close() {
+ try {
+ if (chan != null) {
+ chan.close();
+ chan = null;
+ }
+ if (fis != null) {
+ fis.close();
+ fis = null;
+ }
+ buf = null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Creates a new DDSImage from data supplied by the user. The
+ * resulting DDSImage can be written to disk using the write()
+ * method.
+ *
+ * @param d3dFormat the D3DFMT_ constant describing the data; it is
+ * assumed that it is packed tightly
+ * @param width the width in pixels of the topmost mipmap image
+ * @param height the height in pixels of the topmost mipmap image
+ * @param mipmapData the data for each mipmap level of the resulting
+ * DDSImage; either only one mipmap level should
+ * be specified, or they all must be
+ * @throws IllegalArgumentException if the data does not match the
+ * specified arguments
+ * @return DDS image object
+ */
+ public static DDSImage createFromData(int d3dFormat,
+ int width,
+ int height,
+ ByteBuffer[] mipmapData) throws IllegalArgumentException {
+ DDSImage image = new DDSImage();
+ image.initFromData(d3dFormat, width, height, mipmapData);
+ return image;
+ }
+
+ /** Determines from the magic number whether the given InputStream
+ points to a DDS image. The given InputStream must return true
+ from markSupported() and support a minimum of four bytes of
+ read-ahead.
+
+ @param in Stream to check
+ @return true if input stream is DDS image or false otherwise
+ @throws java.io.IOException if an I/O exception occurred
+ */
+ public static boolean isDDSImage(InputStream in) throws IOException {
+ if (!(in instanceof BufferedInputStream)) {
+ in = new BufferedInputStream(in);
+ }
+ if (!in.markSupported()) {
+ throw new IOException("Can not test non-destructively whether given InputStream is a DDS image");
+ }
+ in.mark(4);
+ int magic = 0;
+ for (int i = 0; i < 4; i++) {
+ int tmp = in.read();
+ if (tmp < 0) {
+ in.reset();
+ return false;
+ }
+ magic = ((magic >>> 8) | (tmp << 24));
+ }
in.reset();
- return false;
- }
- magic = ((magic >>> 8) | (tmp << 24));
- }
- in.reset();
- return (magic == MAGIC);
- }
-
- /**
- * Writes this DDSImage to the specified file name.
- * @param filename File name to write to
- * @throws java.io.IOException if an I/O exception occurred
- */
- public void write(String filename) throws IOException {
- write(new File(filename));
- }
-
- /**
- * Writes this DDSImage to the specified file name.
- * @param file File object to write to
- * @throws java.io.IOException if an I/O exception occurred
- */
- public void write(File file) throws IOException {
- FileOutputStream stream = new FileOutputStream(file);
- FileChannel chan = stream.getChannel();
- // Create ByteBuffer for header in case the start of our
- // ByteBuffer isn't actually memory-mapped
- ByteBuffer hdr = ByteBuffer.allocate(Header.writtenSize());
- hdr.order(ByteOrder.LITTLE_ENDIAN);
- header.write(hdr);
- hdr.rewind();
- chan.write(hdr);
- buf.position(Header.writtenSize());
- chan.write(buf);
- chan.force(true);
- chan.close();
- stream.close();
- }
-
- /** Test for presence/absence of surface description flags (DDSD_*)
- * @param flag DDSD_* flags set to test
- * @return true if flag present or false otherwise
- */
- public boolean isSurfaceDescFlagSet(int flag) {
- return ((header.flags & flag) != 0);
- }
-
- /** Test for presence/absence of pixel format flags (DDPF_*) */
- public boolean isPixelFormatFlagSet(int flag) {
- return ((header.pfFlags & flag) != 0);
- }
-
- /** Gets the pixel format of this texture (D3DFMT_*) based on some
- heuristics. Returns D3DFMT_UNKNOWN if could not recognize the
- pixel format. */
- public int getPixelFormat() {
- if (isCompressed()) {
- return getCompressionFormat();
- } else if (isPixelFormatFlagSet(DDPF_RGB)) {
- if (isPixelFormatFlagSet(DDPF_ALPHAPIXELS)) {
- if (getDepth() == 32 &&
- header.pfRBitMask == 0x00FF0000 &&
- header.pfGBitMask == 0x0000FF00 &&
- header.pfBBitMask == 0x000000FF &&
- header.pfABitMask == 0xFF000000) {
- return D3DFMT_A8R8G8B8;
- }
- } else {
- if (getDepth() == 24 &&
- header.pfRBitMask == 0x00FF0000 &&
- header.pfGBitMask == 0x0000FF00 &&
- header.pfBBitMask == 0x000000FF) {
- return D3DFMT_R8G8B8;
- } else if (getDepth() == 32 &&
- header.pfRBitMask == 0x00FF0000 &&
- header.pfGBitMask == 0x0000FF00 &&
- header.pfBBitMask == 0x000000FF) {
- return D3DFMT_X8R8G8B8;
- }
- }
- }
-
- return D3DFMT_UNKNOWN;
- }
-
- /**
- * Indicates whether this texture is cubemap
- * @return true if cubemap or false otherwise
- */
- public boolean isCubemap() {
- return ((header.ddsCaps1 & DDSCAPS_COMPLEX) != 0) && ((header.ddsCaps2 & DDSCAPS2_CUBEMAP) != 0);
- }
-
- /**
- * Indicates whethe this cubemap side present
- * @param side Side to test
- * @return true if side present or false otherwise
- */
- public boolean isCubemapSidePresent(int side) {
- return isCubemap() && (header.ddsCaps2 & side) != 0;
- }
-
- /** Indicates whether this texture is compressed. */
- public boolean isCompressed() {
- return (isPixelFormatFlagSet(DDPF_FOURCC));
- }
-
- /** If this surface is compressed, returns the kind of compression
- used (DXT1..DXT5). */
- public int getCompressionFormat() {
- return header.pfFourCC;
- }
-
- /** Width of the texture (or the top-most mipmap if mipmaps are
- present) */
- public int getWidth() {
- return header.width;
- }
-
- /** Height of the texture (or the top-most mipmap if mipmaps are
- present) */
- public int getHeight() {
- return header.height;
- }
-
- /** Total number of bits per pixel. Only valid if DDPF_RGB is
- present. For A8R8G8B8, would be 32. */
- public int getDepth() {
- return header.pfRGBBitCount;
- }
-
- /** Number of mip maps in the texture */
- public int getNumMipMaps() {
- if (!isSurfaceDescFlagSet(DDSD_MIPMAPCOUNT)) {
- return 0;
- }
- return header.mipMapCountOrAux;
- }
-
- /** Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1)
- * @param map Mipmap index
- * @return Image object
- */
- public ImageInfo getMipMap(int map) {
- return getMipMap( 0, map );
- }
-
- /**
- * Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1)
- * @param side Cubemap side or 0 for 2D texture
- * @param map Mipmap index
- * @return Image object
- */
- public ImageInfo getMipMap(int side, int map) {
- if (!isCubemap() && (side != 0)) {
- throw new RuntimeException( "Illegal side for 2D texture: " + side );
- }
- if (isCubemap() && !isCubemapSidePresent(side)) {
- throw new RuntimeException( "Illegal side, side not present: " + side );
- }
- if (getNumMipMaps() > 0 &&
- ((map < 0) || (map >= getNumMipMaps()))) {
- throw new RuntimeException("Illegal mipmap number " + map + " (0.." + (getNumMipMaps() - 1) + ")");
- }
-
- // Figure out how far to seek
- int seek = Header.writtenSize();
- if (isCubemap()) {
- seek += sideShiftInBytes(side);
- }
- for (int i = 0; i < map; i++) {
- seek += mipMapSizeInBytes(i);
- }
- buf.limit(seek + mipMapSizeInBytes(map));
- buf.position(seek);
- ByteBuffer next = buf.slice();
- buf.position(0);
- buf.limit(buf.capacity());
- return new ImageInfo(next, mipMapWidth(map), mipMapHeight(map), isCompressed(), getCompressionFormat());
- }
-
- /** Returns an array of ImageInfos corresponding to all mipmap
- levels of this DDS file.
- @return Mipmap image objects set
- */
- public ImageInfo[] getAllMipMaps() {
- return getAllMipMaps(0);
- }
-
- /**
- * Returns an array of ImageInfos corresponding to all mipmap
- * levels of this DDS file.
- * @param side Cubemap side or 0 for 2D texture
- * @return Mipmap image objects set
- */
- public ImageInfo[] getAllMipMaps( int side ) {
- int numLevels = getNumMipMaps();
- if (numLevels == 0) {
- numLevels = 1;
- }
- ImageInfo[] result = new ImageInfo[numLevels];
- for (int i = 0; i < numLevels; i++) {
- result[i] = getMipMap(side, i);
- }
- return result;
- }
-
- /** Converts e.g. DXT1 compression format constant (see {@link
- #getCompressionFormat}) into "DXT1".
- @param compressionFormat Compression format constant
- @return String format code
- */
- public static String getCompressionFormatName(int compressionFormat) {
- StringBuffer buf = new StringBuffer();
- for (int i = 0; i < 4; i++) {
- char c = (char) (compressionFormat & 0xFF);
- buf.append(c);
- compressionFormat = compressionFormat >> 8;
- }
- return buf.toString();
- }
-
- /** Allocates a temporary, empty ByteBuffer suitable for use in a
- call to glCompressedTexImage2D. This is used by the Texture
- class to expand non-power-of-two DDS compressed textures to
- power-of-two sizes on hardware not supporting OpenGL 2.0 and the
- NPOT texture extension. The specified OpenGL internal format
- must be one of GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
- GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
- GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, or
- GL_COMPRESSED_RGBA_S3TC_DXT5_EXT.
- */
- public static ByteBuffer allocateBlankBuffer(int width,
- int height,
- int openGLInternalFormat) {
- int size = width * height;
- switch (openGLInternalFormat) {
- case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- size /= 2;
- break;
-
- case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- break;
-
- default:
- throw new IllegalArgumentException("Illegal OpenGL texture internal format " +
- openGLInternalFormat);
- }
- if (size == 0)
- size = 1;
- return BufferUtil.newByteBuffer(size);
- }
-
- public void debugPrint() {
- PrintStream tty = System.err;
- tty.println("Compressed texture: " + isCompressed());
- if (isCompressed()) {
- int fmt = getCompressionFormat();
- String name = getCompressionFormatName(fmt);
- tty.println("Compression format: 0x" + Integer.toHexString(fmt) + " (" + name + ")");
- }
- tty.println("Width: " + header.width + " Height: " + header.height);
- tty.println("header.pitchOrLinearSize: " + header.pitchOrLinearSize);
- tty.println("header.pfRBitMask: 0x" + Integer.toHexString(header.pfRBitMask));
- tty.println("header.pfGBitMask: 0x" + Integer.toHexString(header.pfGBitMask));
- tty.println("header.pfBBitMask: 0x" + Integer.toHexString(header.pfBBitMask));
- tty.println("SurfaceDesc flags:");
- boolean recognizedAny = false;
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_CAPS, "DDSD_CAPS");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_HEIGHT, "DDSD_HEIGHT");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_WIDTH, "DDSD_WIDTH");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PITCH, "DDSD_PITCH");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_BACKBUFFERCOUNT, "DDSD_BACKBUFFERCOUNT");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ZBUFFERBITDEPTH, "DDSD_ZBUFFERBITDEPTH");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ALPHABITDEPTH, "DDSD_ALPHABITDEPTH");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LPSURFACE, "DDSD_LPSURFACE");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PIXELFORMAT, "DDSD_PIXELFORMAT");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_MIPMAPCOUNT, "DDSD_MIPMAPCOUNT");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LINEARSIZE, "DDSD_LINEARSIZE");
- recognizedAny |= printIfRecognized(tty, header.flags, DDSD_DEPTH, "DDSD_DEPTH");
- if (!recognizedAny) {
- tty.println("(none)");
- }
- tty.println("Raw SurfaceDesc flags: 0x" + Integer.toHexString(header.flags));
- tty.println("Pixel format flags:");
- recognizedAny = false;
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHAPIXELS, "DDPF_ALPHAPIXELS");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHA, "DDPF_ALPHA");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_FOURCC, "DDPF_FOURCC");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED4, "DDPF_PALETTEINDEXED4");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXEDTO8, "DDPF_PALETTEINDEXEDTO8");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED8, "DDPF_PALETTEINDEXED8");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGB, "DDPF_RGB");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_COMPRESSED, "DDPF_COMPRESSED");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGBTOYUV, "DDPF_RGBTOYUV");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_YUV, "DDPF_YUV");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZBUFFER, "DDPF_ZBUFFER");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED1, "DDPF_PALETTEINDEXED1");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED2, "DDPF_PALETTEINDEXED2");
- recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZPIXELS, "DDPF_ZPIXELS");
- if (!recognizedAny) {
- tty.println("(none)");
- }
- tty.println("Raw pixel format flags: 0x" + Integer.toHexString(header.pfFlags));
- tty.println("Depth: " + getDepth());
- tty.println("Number of mip maps: " + getNumMipMaps());
- int fmt = getPixelFormat();
- tty.print("Pixel format: ");
- switch (fmt) {
- case D3DFMT_R8G8B8: tty.println("D3DFMT_R8G8B8"); break;
- case D3DFMT_A8R8G8B8: tty.println("D3DFMT_A8R8G8B8"); break;
- case D3DFMT_X8R8G8B8: tty.println("D3DFMT_X8R8G8B8"); break;
- case D3DFMT_DXT1: tty.println("D3DFMT_DXT1"); break;
- case D3DFMT_DXT2: tty.println("D3DFMT_DXT2"); break;
- case D3DFMT_DXT3: tty.println("D3DFMT_DXT3"); break;
- case D3DFMT_DXT4: tty.println("D3DFMT_DXT4"); break;
- case D3DFMT_DXT5: tty.println("D3DFMT_DXT5"); break;
- case D3DFMT_UNKNOWN: tty.println("D3DFMT_UNKNOWN"); break;
- default: tty.println("(unknown pixel format " + fmt + ")"); break;
- }
- }
-
- //----------------------------------------------------------------------
- // Internals only below this point
- //
-
- private static final int MAGIC = 0x20534444;
-
- static class Header {
- int size; // size of the DDSURFACEDESC structure
- int flags; // determines what fields are valid
- int height; // height of surface to be created
- int width; // width of input surface
- int pitchOrLinearSize;
- int backBufferCountOrDepth;
- int mipMapCountOrAux; // number of mip-map levels requested (in this context)
- int alphaBitDepth; // depth of alpha buffer requested
- int reserved1; // reserved
- int surface; // pointer to the associated surface memory
- // NOTE: following two entries are from DDCOLORKEY data structure
- // Are overlaid with color for empty cubemap faces (unused in this reader)
- int colorSpaceLowValue;
- int colorSpaceHighValue;
- int destBltColorSpaceLowValue;
- int destBltColorSpaceHighValue;
- int srcOverlayColorSpaceLowValue;
- int srcOverlayColorSpaceHighValue;
- int srcBltColorSpaceLowValue;
- int srcBltColorSpaceHighValue;
- // NOTE: following entries are from DDPIXELFORMAT data structure
- // Are overlaid with flexible vertex format description of vertex
- // buffers (unused in this reader)
- int pfSize; // size of DDPIXELFORMAT structure
- int pfFlags; // pixel format flags
- int pfFourCC; // (FOURCC code)
- // Following five entries have multiple interpretations, not just
- // RGBA (but that's all we support right now)
- int pfRGBBitCount; // how many bits per pixel
- int pfRBitMask; // mask for red bits
- int pfGBitMask; // mask for green bits
- int pfBBitMask; // mask for blue bits
- int pfABitMask; // mask for alpha channel
- int ddsCaps1; // Texture and mip-map flags
- int ddsCaps2; // Advanced capabilities including cubemap support
- int ddsCapsReserved1;
- int ddsCapsReserved2;
- int textureStage; // stage in multitexture cascade
-
- void read(ByteBuffer buf) throws IOException {
- int magic = buf.getInt();
- if (magic != MAGIC) {
- throw new IOException("Incorrect magic number 0x" +
- Integer.toHexString(magic) +
- " (expected " + MAGIC + ")");
- }
-
- size = buf.getInt();
- flags = buf.getInt();
- height = buf.getInt();
- width = buf.getInt();
- pitchOrLinearSize = buf.getInt();
- backBufferCountOrDepth = buf.getInt();
- mipMapCountOrAux = buf.getInt();
- alphaBitDepth = buf.getInt();
- reserved1 = buf.getInt();
- surface = buf.getInt();
- colorSpaceLowValue = buf.getInt();
- colorSpaceHighValue = buf.getInt();
- destBltColorSpaceLowValue = buf.getInt();
- destBltColorSpaceHighValue = buf.getInt();
- srcOverlayColorSpaceLowValue = buf.getInt();
- srcOverlayColorSpaceHighValue = buf.getInt();
- srcBltColorSpaceLowValue = buf.getInt();
- srcBltColorSpaceHighValue = buf.getInt();
- pfSize = buf.getInt();
- pfFlags = buf.getInt();
- pfFourCC = buf.getInt();
- pfRGBBitCount = buf.getInt();
- pfRBitMask = buf.getInt();
- pfGBitMask = buf.getInt();
- pfBBitMask = buf.getInt();
- pfABitMask = buf.getInt();
- ddsCaps1 = buf.getInt();
- ddsCaps2 = buf.getInt();
- ddsCapsReserved1 = buf.getInt();
- ddsCapsReserved2 = buf.getInt();
- textureStage = buf.getInt();
- }
-
- // buf must be in little-endian byte order
- void write(ByteBuffer buf) {
- buf.putInt(MAGIC);
- buf.putInt(size);
- buf.putInt(flags);
- buf.putInt(height);
- buf.putInt(width);
- buf.putInt(pitchOrLinearSize);
- buf.putInt(backBufferCountOrDepth);
- buf.putInt(mipMapCountOrAux);
- buf.putInt(alphaBitDepth);
- buf.putInt(reserved1);
- buf.putInt(surface);
- buf.putInt(colorSpaceLowValue);
- buf.putInt(colorSpaceHighValue);
- buf.putInt(destBltColorSpaceLowValue);
- buf.putInt(destBltColorSpaceHighValue);
- buf.putInt(srcOverlayColorSpaceLowValue);
- buf.putInt(srcOverlayColorSpaceHighValue);
- buf.putInt(srcBltColorSpaceLowValue);
- buf.putInt(srcBltColorSpaceHighValue);
- buf.putInt(pfSize);
- buf.putInt(pfFlags);
- buf.putInt(pfFourCC);
- buf.putInt(pfRGBBitCount);
- buf.putInt(pfRBitMask);
- buf.putInt(pfGBitMask);
- buf.putInt(pfBBitMask);
- buf.putInt(pfABitMask);
- buf.putInt(ddsCaps1);
- buf.putInt(ddsCaps2);
- buf.putInt(ddsCapsReserved1);
- buf.putInt(ddsCapsReserved2);
- buf.putInt(textureStage);
- }
-
- private static int size() {
- return 124;
- }
-
- private static int pfSize() {
- return 32;
- }
-
- private static int writtenSize() {
- return 128;
- }
- }
-
- private DDSImage() {
- }
-
- private void readFromFile(File file) throws IOException {
- fis = new FileInputStream(file);
- chan = fis.getChannel();
- ByteBuffer buf = chan.map(FileChannel.MapMode.READ_ONLY,
- 0, (int) file.length());
- readFromBuffer(buf);
- }
-
- private void readFromBuffer(ByteBuffer buf) throws IOException {
- this.buf = buf;
- buf.order(ByteOrder.LITTLE_ENDIAN);
- header = new Header();
- header.read(buf);
- fixupHeader();
- }
-
- private void initFromData(int d3dFormat,
- int width,
- int height,
- ByteBuffer[] mipmapData) throws IllegalArgumentException {
- // Check size of mipmap data compared against format, width and
- // height
- int topmostMipmapSize = width * height;
- int pitchOrLinearSize = width;
- boolean isCompressed = false;
- switch (d3dFormat) {
- case D3DFMT_R8G8B8: topmostMipmapSize *= 3; pitchOrLinearSize *= 3; break;
- case D3DFMT_A8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break;
- case D3DFMT_X8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break;
- case D3DFMT_DXT1:
- case D3DFMT_DXT2:
- case D3DFMT_DXT3:
- case D3DFMT_DXT4:
- case D3DFMT_DXT5:
- topmostMipmapSize = computeCompressedBlockSize(width, height, 1, d3dFormat);
- pitchOrLinearSize = topmostMipmapSize;
- isCompressed = true;
- break;
- default:
- throw new IllegalArgumentException("d3dFormat must be one of the known formats");
+ return (magic == MAGIC);
+ }
+
+ /**
+ * Writes this DDSImage to the specified file name.
+ * @param filename File name to write to
+ * @throws java.io.IOException if an I/O exception occurred
+ */
+ public void write(String filename) throws IOException {
+ write(new File(filename));
+ }
+
+ /**
+ * Writes this DDSImage to the specified file name.
+ * @param file File object to write to
+ * @throws java.io.IOException if an I/O exception occurred
+ */
+ public void write(File file) throws IOException {
+ FileOutputStream stream = new FileOutputStream(file);
+ FileChannel chan = stream.getChannel();
+ // Create ByteBuffer for header in case the start of our
+ // ByteBuffer isn't actually memory-mapped
+ ByteBuffer hdr = ByteBuffer.allocate(Header.writtenSize());
+ hdr.order(ByteOrder.LITTLE_ENDIAN);
+ header.write(hdr);
+ hdr.rewind();
+ chan.write(hdr);
+ buf.position(Header.writtenSize());
+ chan.write(buf);
+ chan.force(true);
+ chan.close();
+ stream.close();
+ }
+
+ /** Test for presence/absence of surface description flags (DDSD_*)
+ * @param flag DDSD_* flags set to test
+ * @return true if flag present or false otherwise
+ */
+ public boolean isSurfaceDescFlagSet(int flag) {
+ return ((header.flags & flag) != 0);
+ }
+
+ /** Test for presence/absence of pixel format flags (DDPF_*) */
+ public boolean isPixelFormatFlagSet(int flag) {
+ return ((header.pfFlags & flag) != 0);
+ }
+
+ /** Gets the pixel format of this texture (D3DFMT_*) based on some
+ heuristics. Returns D3DFMT_UNKNOWN if could not recognize the
+ pixel format. */
+ public int getPixelFormat() {
+ if (isCompressed()) {
+ return getCompressionFormat();
+ } else if (isPixelFormatFlagSet(DDPF_RGB)) {
+ if (isPixelFormatFlagSet(DDPF_ALPHAPIXELS)) {
+ if (getDepth() == 32 &&
+ header.pfRBitMask == 0x00FF0000 &&
+ header.pfGBitMask == 0x0000FF00 &&
+ header.pfBBitMask == 0x000000FF &&
+ header.pfABitMask == 0xFF000000) {
+ return D3DFMT_A8R8G8B8;
+ }
+ } else {
+ if (getDepth() == 24 &&
+ header.pfRBitMask == 0x00FF0000 &&
+ header.pfGBitMask == 0x0000FF00 &&
+ header.pfBBitMask == 0x000000FF) {
+ return D3DFMT_R8G8B8;
+ } else if (getDepth() == 32 &&
+ header.pfRBitMask == 0x00FF0000 &&
+ header.pfGBitMask == 0x0000FF00 &&
+ header.pfBBitMask == 0x000000FF) {
+ return D3DFMT_X8R8G8B8;
+ }
+ }
+ }
+
+ return D3DFMT_UNKNOWN;
+ }
+
+ /**
+ * Indicates whether this texture is cubemap
+ * @return true if cubemap or false otherwise
+ */
+ public boolean isCubemap() {
+ return ((header.ddsCaps1 & DDSCAPS_COMPLEX) != 0) && ((header.ddsCaps2 & DDSCAPS2_CUBEMAP) != 0);
+ }
+
+ /**
+ * Indicates whethe this cubemap side present
+ * @param side Side to test
+ * @return true if side present or false otherwise
+ */
+ public boolean isCubemapSidePresent(int side) {
+ return isCubemap() && (header.ddsCaps2 & side) != 0;
+ }
+
+ /** Indicates whether this texture is compressed. */
+ public boolean isCompressed() {
+ return (isPixelFormatFlagSet(DDPF_FOURCC));
+ }
+
+ /** If this surface is compressed, returns the kind of compression
+ used (DXT1..DXT5). */
+ public int getCompressionFormat() {
+ return header.pfFourCC;
}
+
+ /** Width of the texture (or the top-most mipmap if mipmaps are
+ present) */
+ public int getWidth() {
+ return header.width;
+ }
+
+ /** Height of the texture (or the top-most mipmap if mipmaps are
+ present) */
+ public int getHeight() {
+ return header.height;
+ }
+
+ /** Total number of bits per pixel. Only valid if DDPF_RGB is
+ present. For A8R8G8B8, would be 32. */
+ public int getDepth() {
+ return header.pfRGBBitCount;
+ }
+
+ /** Number of mip maps in the texture */
+ public int getNumMipMaps() {
+ if (!isSurfaceDescFlagSet(DDSD_MIPMAPCOUNT)) {
+ return 0;
+ }
+ return header.mipMapCountOrAux;
+ }
+
+ /** Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1)
+ * @param map Mipmap index
+ * @return Image object
+ */
+ public ImageInfo getMipMap(int map) {
+ return getMipMap( 0, map );
+ }
+
+ /**
+ * Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1)
+ * @param side Cubemap side or 0 for 2D texture
+ * @param map Mipmap index
+ * @return Image object
+ */
+ public ImageInfo getMipMap(int side, int map) {
+ if (!isCubemap() && (side != 0)) {
+ throw new RuntimeException( "Illegal side for 2D texture: " + side );
+ }
+ if (isCubemap() && !isCubemapSidePresent(side)) {
+ throw new RuntimeException( "Illegal side, side not present: " + side );
+ }
+ if (getNumMipMaps() > 0 &&
+ ((map < 0) || (map >= getNumMipMaps()))) {
+ throw new RuntimeException("Illegal mipmap number " + map + " (0.." + (getNumMipMaps() - 1) + ")");
+ }
+
+ // Figure out how far to seek
+ int seek = Header.writtenSize();
+ if (isCubemap()) {
+ seek += sideShiftInBytes(side);
+ }
+ for (int i = 0; i < map; i++) {
+ seek += mipMapSizeInBytes(i);
+ }
+ buf.limit(seek + mipMapSizeInBytes(map));
+ buf.position(seek);
+ ByteBuffer next = buf.slice();
+ buf.position(0);
+ buf.limit(buf.capacity());
+ return new ImageInfo(next, mipMapWidth(map), mipMapHeight(map), isCompressed(), getCompressionFormat());
+ }
+
+ /** Returns an array of ImageInfos corresponding to all mipmap
+ levels of this DDS file.
+ @return Mipmap image objects set
+ */
+ public ImageInfo[] getAllMipMaps() {
+ return getAllMipMaps(0);
+ }
+
+ /**
+ * Returns an array of ImageInfos corresponding to all mipmap
+ * levels of this DDS file.
+ * @param side Cubemap side or 0 for 2D texture
+ * @return Mipmap image objects set
+ */
+ public ImageInfo[] getAllMipMaps( int side ) {
+ int numLevels = getNumMipMaps();
+ if (numLevels == 0) {
+ numLevels = 1;
+ }
+ ImageInfo[] result = new ImageInfo[numLevels];
+ for (int i = 0; i < numLevels; i++) {
+ result[i] = getMipMap(side, i);
+ }
+ return result;
+ }
+
+ /** Converts e.g. DXT1 compression format constant (see {@link
+ #getCompressionFormat}) into "DXT1".
+ @param compressionFormat Compression format constant
+ @return String format code
+ */
+ public static String getCompressionFormatName(int compressionFormat) {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < 4; i++) {
+ char c = (char) (compressionFormat & 0xFF);
+ buf.append(c);
+ compressionFormat = compressionFormat >> 8;
+ }
+ return buf.toString();
+ }
+
+ /** Allocates a temporary, empty ByteBuffer suitable for use in a
+ call to glCompressedTexImage2D. This is used by the Texture
+ class to expand non-power-of-two DDS compressed textures to
+ power-of-two sizes on hardware not supporting OpenGL 2.0 and the
+ NPOT texture extension. The specified OpenGL internal format
+ must be one of GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, or
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT.
+ */
+ public static ByteBuffer allocateBlankBuffer(int width,
+ int height,
+ int openGLInternalFormat) {
+ int size = width * height;
+ switch (openGLInternalFormat) {
+ case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ size /= 2;
+ break;
+
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ break;
+
+ default:
+ throw new IllegalArgumentException("Illegal OpenGL texture internal format " +
+ openGLInternalFormat);
+ }
+ if (size == 0)
+ size = 1;
+ return BufferUtil.newByteBuffer(size);
+ }
+
+ public void debugPrint() {
+ PrintStream tty = System.err;
+ tty.println("Compressed texture: " + isCompressed());
+ if (isCompressed()) {
+ int fmt = getCompressionFormat();
+ String name = getCompressionFormatName(fmt);
+ tty.println("Compression format: 0x" + Integer.toHexString(fmt) + " (" + name + ")");
+ }
+ tty.println("Width: " + header.width + " Height: " + header.height);
+ tty.println("header.pitchOrLinearSize: " + header.pitchOrLinearSize);
+ tty.println("header.pfRBitMask: 0x" + Integer.toHexString(header.pfRBitMask));
+ tty.println("header.pfGBitMask: 0x" + Integer.toHexString(header.pfGBitMask));
+ tty.println("header.pfBBitMask: 0x" + Integer.toHexString(header.pfBBitMask));
+ tty.println("SurfaceDesc flags:");
+ boolean recognizedAny = false;
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_CAPS, "DDSD_CAPS");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_HEIGHT, "DDSD_HEIGHT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_WIDTH, "DDSD_WIDTH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PITCH, "DDSD_PITCH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_BACKBUFFERCOUNT, "DDSD_BACKBUFFERCOUNT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ZBUFFERBITDEPTH, "DDSD_ZBUFFERBITDEPTH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ALPHABITDEPTH, "DDSD_ALPHABITDEPTH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LPSURFACE, "DDSD_LPSURFACE");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PIXELFORMAT, "DDSD_PIXELFORMAT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_MIPMAPCOUNT, "DDSD_MIPMAPCOUNT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LINEARSIZE, "DDSD_LINEARSIZE");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_DEPTH, "DDSD_DEPTH");
+ if (!recognizedAny) {
+ tty.println("(none)");
+ }
+ tty.println("Raw SurfaceDesc flags: 0x" + Integer.toHexString(header.flags));
+ tty.println("Pixel format flags:");
+ recognizedAny = false;
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHAPIXELS, "DDPF_ALPHAPIXELS");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHA, "DDPF_ALPHA");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_FOURCC, "DDPF_FOURCC");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED4, "DDPF_PALETTEINDEXED4");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXEDTO8, "DDPF_PALETTEINDEXEDTO8");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED8, "DDPF_PALETTEINDEXED8");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGB, "DDPF_RGB");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_COMPRESSED, "DDPF_COMPRESSED");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGBTOYUV, "DDPF_RGBTOYUV");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_YUV, "DDPF_YUV");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZBUFFER, "DDPF_ZBUFFER");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED1, "DDPF_PALETTEINDEXED1");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED2, "DDPF_PALETTEINDEXED2");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZPIXELS, "DDPF_ZPIXELS");
+ if (!recognizedAny) {
+ tty.println("(none)");
+ }
+ tty.println("Raw pixel format flags: 0x" + Integer.toHexString(header.pfFlags));
+ tty.println("Depth: " + getDepth());
+ tty.println("Number of mip maps: " + getNumMipMaps());
+ int fmt = getPixelFormat();
+ tty.print("Pixel format: ");
+ switch (fmt) {
+ case D3DFMT_R8G8B8: tty.println("D3DFMT_R8G8B8"); break;
+ case D3DFMT_A8R8G8B8: tty.println("D3DFMT_A8R8G8B8"); break;
+ case D3DFMT_X8R8G8B8: tty.println("D3DFMT_X8R8G8B8"); break;
+ case D3DFMT_DXT1: tty.println("D3DFMT_DXT1"); break;
+ case D3DFMT_DXT2: tty.println("D3DFMT_DXT2"); break;
+ case D3DFMT_DXT3: tty.println("D3DFMT_DXT3"); break;
+ case D3DFMT_DXT4: tty.println("D3DFMT_DXT4"); break;
+ case D3DFMT_DXT5: tty.println("D3DFMT_DXT5"); break;
+ case D3DFMT_UNKNOWN: tty.println("D3DFMT_UNKNOWN"); break;
+ default: tty.println("(unknown pixel format " + fmt + ")"); break;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static final int MAGIC = 0x20534444;
+
+ static class Header {
+ int size; // size of the DDSURFACEDESC structure
+ int flags; // determines what fields are valid
+ int height; // height of surface to be created
+ int width; // width of input surface
+ int pitchOrLinearSize;
+ int backBufferCountOrDepth;
+ int mipMapCountOrAux; // number of mip-map levels requested (in this context)
+ int alphaBitDepth; // depth of alpha buffer requested
+ int reserved1; // reserved
+ int surface; // pointer to the associated surface memory
+ // NOTE: following two entries are from DDCOLORKEY data structure
+ // Are overlaid with color for empty cubemap faces (unused in this reader)
+ int colorSpaceLowValue;
+ int colorSpaceHighValue;
+ int destBltColorSpaceLowValue;
+ int destBltColorSpaceHighValue;
+ int srcOverlayColorSpaceLowValue;
+ int srcOverlayColorSpaceHighValue;
+ int srcBltColorSpaceLowValue;
+ int srcBltColorSpaceHighValue;
+ // NOTE: following entries are from DDPIXELFORMAT data structure
+ // Are overlaid with flexible vertex format description of vertex
+ // buffers (unused in this reader)
+ int pfSize; // size of DDPIXELFORMAT structure
+ int pfFlags; // pixel format flags
+ int pfFourCC; // (FOURCC code)
+ // Following five entries have multiple interpretations, not just
+ // RGBA (but that's all we support right now)
+ int pfRGBBitCount; // how many bits per pixel
+ int pfRBitMask; // mask for red bits
+ int pfGBitMask; // mask for green bits
+ int pfBBitMask; // mask for blue bits
+ int pfABitMask; // mask for alpha channel
+ int ddsCaps1; // Texture and mip-map flags
+ int ddsCaps2; // Advanced capabilities including cubemap support
+ int ddsCapsReserved1;
+ int ddsCapsReserved2;
+ int textureStage; // stage in multitexture cascade
+
+ void read(ByteBuffer buf) throws IOException {
+ int magic = buf.getInt();
+ if (magic != MAGIC) {
+ throw new IOException("Incorrect magic number 0x" +
+ Integer.toHexString(magic) +
+ " (expected " + MAGIC + ")");
+ }
+
+ size = buf.getInt();
+ flags = buf.getInt();
+ height = buf.getInt();
+ width = buf.getInt();
+ pitchOrLinearSize = buf.getInt();
+ backBufferCountOrDepth = buf.getInt();
+ mipMapCountOrAux = buf.getInt();
+ alphaBitDepth = buf.getInt();
+ reserved1 = buf.getInt();
+ surface = buf.getInt();
+ colorSpaceLowValue = buf.getInt();
+ colorSpaceHighValue = buf.getInt();
+ destBltColorSpaceLowValue = buf.getInt();
+ destBltColorSpaceHighValue = buf.getInt();
+ srcOverlayColorSpaceLowValue = buf.getInt();
+ srcOverlayColorSpaceHighValue = buf.getInt();
+ srcBltColorSpaceLowValue = buf.getInt();
+ srcBltColorSpaceHighValue = buf.getInt();
+ pfSize = buf.getInt();
+ pfFlags = buf.getInt();
+ pfFourCC = buf.getInt();
+ pfRGBBitCount = buf.getInt();
+ pfRBitMask = buf.getInt();
+ pfGBitMask = buf.getInt();
+ pfBBitMask = buf.getInt();
+ pfABitMask = buf.getInt();
+ ddsCaps1 = buf.getInt();
+ ddsCaps2 = buf.getInt();
+ ddsCapsReserved1 = buf.getInt();
+ ddsCapsReserved2 = buf.getInt();
+ textureStage = buf.getInt();
+ }
+
+ // buf must be in little-endian byte order
+ void write(ByteBuffer buf) {
+ buf.putInt(MAGIC);
+ buf.putInt(size);
+ buf.putInt(flags);
+ buf.putInt(height);
+ buf.putInt(width);
+ buf.putInt(pitchOrLinearSize);
+ buf.putInt(backBufferCountOrDepth);
+ buf.putInt(mipMapCountOrAux);
+ buf.putInt(alphaBitDepth);
+ buf.putInt(reserved1);
+ buf.putInt(surface);
+ buf.putInt(colorSpaceLowValue);
+ buf.putInt(colorSpaceHighValue);
+ buf.putInt(destBltColorSpaceLowValue);
+ buf.putInt(destBltColorSpaceHighValue);
+ buf.putInt(srcOverlayColorSpaceLowValue);
+ buf.putInt(srcOverlayColorSpaceHighValue);
+ buf.putInt(srcBltColorSpaceLowValue);
+ buf.putInt(srcBltColorSpaceHighValue);
+ buf.putInt(pfSize);
+ buf.putInt(pfFlags);
+ buf.putInt(pfFourCC);
+ buf.putInt(pfRGBBitCount);
+ buf.putInt(pfRBitMask);
+ buf.putInt(pfGBitMask);
+ buf.putInt(pfBBitMask);
+ buf.putInt(pfABitMask);
+ buf.putInt(ddsCaps1);
+ buf.putInt(ddsCaps2);
+ buf.putInt(ddsCapsReserved1);
+ buf.putInt(ddsCapsReserved2);
+ buf.putInt(textureStage);
+ }
+
+ private static int size() {
+ return 124;
+ }
+
+ private static int pfSize() {
+ return 32;
+ }
+
+ private static int writtenSize() {
+ return 128;
+ }
+ }
+
+ private DDSImage() {
+ }
+
+ private void readFromFile(File file) throws IOException {
+ fis = new FileInputStream(file);
+ chan = fis.getChannel();
+ ByteBuffer buf = chan.map(FileChannel.MapMode.READ_ONLY,
+ 0, (int) file.length());
+ readFromBuffer(buf);
+ }
+
+ private void readFromBuffer(ByteBuffer buf) throws IOException {
+ this.buf = buf;
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ header = new Header();
+ header.read(buf);
+ fixupHeader();
+ }
+
+ private void initFromData(int d3dFormat,
+ int width,
+ int height,
+ ByteBuffer[] mipmapData) throws IllegalArgumentException {
+ // Check size of mipmap data compared against format, width and
+ // height
+ int topmostMipmapSize = width * height;
+ int pitchOrLinearSize = width;
+ boolean isCompressed = false;
+ switch (d3dFormat) {
+ case D3DFMT_R8G8B8: topmostMipmapSize *= 3; pitchOrLinearSize *= 3; break;
+ case D3DFMT_A8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break;
+ case D3DFMT_X8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break;
+ case D3DFMT_DXT1:
+ case D3DFMT_DXT2:
+ case D3DFMT_DXT3:
+ case D3DFMT_DXT4:
+ case D3DFMT_DXT5:
+ topmostMipmapSize = computeCompressedBlockSize(width, height, 1, d3dFormat);
+ pitchOrLinearSize = topmostMipmapSize;
+ isCompressed = true;
+ break;
+ default:
+ throw new IllegalArgumentException("d3dFormat must be one of the known formats");
+ }
- // Now check the mipmaps against this size
- int curSize = topmostMipmapSize;
- int totalSize = 0;
- for (int i = 0; i < mipmapData.length; i++) {
- if (mipmapData[i].remaining() != curSize) {
- throw new IllegalArgumentException("Mipmap level " + i +
- " didn't match expected data size (expected " + curSize + ", got " +
- mipmapData[i].remaining() + ")");
- }
- curSize /= 4;
- totalSize += mipmapData[i].remaining();
- }
-
- // OK, create one large ByteBuffer to hold all of the mipmap data
- totalSize += Header.writtenSize();
- ByteBuffer buf = ByteBuffer.allocate(totalSize);
- buf.position(Header.writtenSize());
- for (int i = 0; i < mipmapData.length; i++) {
- buf.put(mipmapData[i]);
- }
- this.buf = buf;
+ // Now check the mipmaps against this size
+ int curSize = topmostMipmapSize;
+ int totalSize = 0;
+ for (int i = 0; i < mipmapData.length; i++) {
+ if (mipmapData[i].remaining() != curSize) {
+ throw new IllegalArgumentException("Mipmap level " + i +
+ " didn't match expected data size (expected " + curSize + ", got " +
+ mipmapData[i].remaining() + ")");
+ }
+ curSize /= 4;
+ totalSize += mipmapData[i].remaining();
+ }
+
+ // OK, create one large ByteBuffer to hold all of the mipmap data
+ totalSize += Header.writtenSize();
+ ByteBuffer buf = ByteBuffer.allocate(totalSize);
+ buf.position(Header.writtenSize());
+ for (int i = 0; i < mipmapData.length; i++) {
+ buf.put(mipmapData[i]);
+ }
+ this.buf = buf;
- // Allocate and initialize a Header
- header = new Header();
- header.size = Header.size();
- header.flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
- if (mipmapData.length > 1) {
- header.flags |= DDSD_MIPMAPCOUNT;
- header.mipMapCountOrAux = mipmapData.length;
- }
- header.width = width;
- header.height = height;
- if (isCompressed) {
- header.flags |= DDSD_LINEARSIZE;
- header.pfFlags |= DDPF_FOURCC;
- header.pfFourCC = d3dFormat;
- } else {
- header.flags |= DDSD_PITCH;
- // Figure out the various settings from the pixel format
- header.pfFlags |= DDPF_RGB;
- switch (d3dFormat) {
- case D3DFMT_R8G8B8: header.pfRGBBitCount = 24; break;
- case D3DFMT_A8R8G8B8: header.pfRGBBitCount = 32; header.pfFlags |= DDPF_ALPHAPIXELS; break;
- case D3DFMT_X8R8G8B8: header.pfRGBBitCount = 32; break;
- }
- header.pfRBitMask = 0x00FF0000;
- header.pfGBitMask = 0x0000FF00;
- header.pfBBitMask = 0x000000FF;
- if (d3dFormat == D3DFMT_A8R8G8B8) {
- header.pfABitMask = 0xFF000000;
- }
- }
- header.pitchOrLinearSize = pitchOrLinearSize;
- header.pfSize = Header.pfSize();
- // Not sure whether we can get away with leaving the rest of the
- // header blank
- }
-
- // Microsoft doesn't follow their own specifications and the
- // simplest conversion using the DxTex tool to e.g. a DXT3 texture
- // results in an illegal .dds file without either DDSD_PITCH or
- // DDSD_LINEARSIZE set in the header's flags. This code, adapted
- // from the DevIL library, fixes up the header in these situations.
- private void fixupHeader() {
- if (isCompressed() && !isSurfaceDescFlagSet(DDSD_LINEARSIZE)) {
- // Figure out how big the linear size should be
- int depth = header.backBufferCountOrDepth;
- if (depth == 0) {
- depth = 1;
- }
-
- header.pitchOrLinearSize = computeCompressedBlockSize(getWidth(), getHeight(), depth, getCompressionFormat());
- header.flags |= DDSD_LINEARSIZE;
- }
- }
-
- private static int computeCompressedBlockSize(int width,
- int height,
- int depth,
- int compressionFormat) {
- int blockSize = ((width + 3)/4) * ((height + 3)/4) * ((depth + 3)/4);
- switch (compressionFormat) {
- case D3DFMT_DXT1: blockSize *= 8; break;
- default: blockSize *= 16; break;
- }
- return blockSize;
- }
-
- private int mipMapWidth(int map) {
- int width = getWidth();
- for (int i = 0; i < map; i++) {
- width >>= 1;
- }
- return Math.max(width, 1);
- }
-
- private int mipMapHeight(int map) {
- int height = getHeight();
- for (int i = 0; i < map; i++) {
- height >>= 1;
- }
- return Math.max(height, 1);
- }
-
- private int mipMapSizeInBytes(int map) {
- int width = mipMapWidth(map);
- int height = mipMapHeight(map);
- if (isCompressed()) {
- int blockSize = (getCompressionFormat() == D3DFMT_DXT1 ? 8 : 16);
- return ((width+3)/4)*((height+3)/4)*blockSize;
- } else {
- return width * height * (getDepth() / 8);
- }
- }
-
- private int sideSizeInBytes() {
- int numLevels = getNumMipMaps();
- if (numLevels == 0) {
- numLevels = 1;
- }
-
- int size = 0;
- for (int i = 0; i < numLevels; i++) {
- size += mipMapSizeInBytes(i);
- }
-
- return size;
- }
-
- private int sideShiftInBytes(int side) {
- int[] sides = {
- DDSCAPS2_CUBEMAP_POSITIVEX,
- DDSCAPS2_CUBEMAP_NEGATIVEX,
- DDSCAPS2_CUBEMAP_POSITIVEY,
- DDSCAPS2_CUBEMAP_NEGATIVEY,
- DDSCAPS2_CUBEMAP_POSITIVEZ,
- DDSCAPS2_CUBEMAP_NEGATIVEZ
- };
-
- int shift = 0;
- int sideSize = sideSizeInBytes();
- for (int i = 0; i < sides.length; i++) {
- int temp = sides[i];
- if ((temp & side) != 0) {
- return shift;
- }
-
- shift += sideSize;
- }
-
- throw new RuntimeException("Illegal side: " + side);
- }
-
- private boolean printIfRecognized(PrintStream tty, int flags, int flag, String what) {
- if ((flags & flag) != 0) {
- tty.println(what);
- return true;
- }
- return false;
- }
+ // Allocate and initialize a Header
+ header = new Header();
+ header.size = Header.size();
+ header.flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
+ if (mipmapData.length > 1) {
+ header.flags |= DDSD_MIPMAPCOUNT;
+ header.mipMapCountOrAux = mipmapData.length;
+ }
+ header.width = width;
+ header.height = height;
+ if (isCompressed) {
+ header.flags |= DDSD_LINEARSIZE;
+ header.pfFlags |= DDPF_FOURCC;
+ header.pfFourCC = d3dFormat;
+ } else {
+ header.flags |= DDSD_PITCH;
+ // Figure out the various settings from the pixel format
+ header.pfFlags |= DDPF_RGB;
+ switch (d3dFormat) {
+ case D3DFMT_R8G8B8: header.pfRGBBitCount = 24; break;
+ case D3DFMT_A8R8G8B8: header.pfRGBBitCount = 32; header.pfFlags |= DDPF_ALPHAPIXELS; break;
+ case D3DFMT_X8R8G8B8: header.pfRGBBitCount = 32; break;
+ }
+ header.pfRBitMask = 0x00FF0000;
+ header.pfGBitMask = 0x0000FF00;
+ header.pfBBitMask = 0x000000FF;
+ if (d3dFormat == D3DFMT_A8R8G8B8) {
+ header.pfABitMask = 0xFF000000;
+ }
+ }
+ header.pitchOrLinearSize = pitchOrLinearSize;
+ header.pfSize = Header.pfSize();
+ // Not sure whether we can get away with leaving the rest of the
+ // header blank
+ }
+
+ // Microsoft doesn't follow their own specifications and the
+ // simplest conversion using the DxTex tool to e.g. a DXT3 texture
+ // results in an illegal .dds file without either DDSD_PITCH or
+ // DDSD_LINEARSIZE set in the header's flags. This code, adapted
+ // from the DevIL library, fixes up the header in these situations.
+ private void fixupHeader() {
+ if (isCompressed() && !isSurfaceDescFlagSet(DDSD_LINEARSIZE)) {
+ // Figure out how big the linear size should be
+ int depth = header.backBufferCountOrDepth;
+ if (depth == 0) {
+ depth = 1;
+ }
+
+ header.pitchOrLinearSize = computeCompressedBlockSize(getWidth(), getHeight(), depth, getCompressionFormat());
+ header.flags |= DDSD_LINEARSIZE;
+ }
+ }
+
+ private static int computeCompressedBlockSize(int width,
+ int height,
+ int depth,
+ int compressionFormat) {
+ int blockSize = ((width + 3)/4) * ((height + 3)/4) * ((depth + 3)/4);
+ switch (compressionFormat) {
+ case D3DFMT_DXT1: blockSize *= 8; break;
+ default: blockSize *= 16; break;
+ }
+ return blockSize;
+ }
+
+ private int mipMapWidth(int map) {
+ int width = getWidth();
+ for (int i = 0; i < map; i++) {
+ width >>= 1;
+ }
+ return Math.max(width, 1);
+ }
+
+ private int mipMapHeight(int map) {
+ int height = getHeight();
+ for (int i = 0; i < map; i++) {
+ height >>= 1;
+ }
+ return Math.max(height, 1);
+ }
+
+ private int mipMapSizeInBytes(int map) {
+ int width = mipMapWidth(map);
+ int height = mipMapHeight(map);
+ if (isCompressed()) {
+ int blockSize = (getCompressionFormat() == D3DFMT_DXT1 ? 8 : 16);
+ return ((width+3)/4)*((height+3)/4)*blockSize;
+ } else {
+ return width * height * (getDepth() / 8);
+ }
+ }
+
+ private int sideSizeInBytes() {
+ int numLevels = getNumMipMaps();
+ if (numLevels == 0) {
+ numLevels = 1;
+ }
+
+ int size = 0;
+ for (int i = 0; i < numLevels; i++) {
+ size += mipMapSizeInBytes(i);
+ }
+
+ return size;
+ }
+
+ private int sideShiftInBytes(int side) {
+ int[] sides = {
+ DDSCAPS2_CUBEMAP_POSITIVEX,
+ DDSCAPS2_CUBEMAP_NEGATIVEX,
+ DDSCAPS2_CUBEMAP_POSITIVEY,
+ DDSCAPS2_CUBEMAP_NEGATIVEY,
+ DDSCAPS2_CUBEMAP_POSITIVEZ,
+ DDSCAPS2_CUBEMAP_NEGATIVEZ
+ };
+
+ int shift = 0;
+ int sideSize = sideSizeInBytes();
+ for (int i = 0; i < sides.length; i++) {
+ int temp = sides[i];
+ if ((temp & side) != 0) {
+ return shift;
+ }
+
+ shift += sideSize;
+ }
+
+ throw new RuntimeException("Illegal side: " + side);
+ }
+
+ private boolean printIfRecognized(PrintStream tty, int flags, int flag, String what) {
+ if ((flags & flag) != 0) {
+ tty.println(what);
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java b/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java
index 8baa1f414..b2b1226bd 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java
@@ -70,154 +70,154 @@ import java.io.IOException;
*/
public class LEDataInputStream extends FilterInputStream implements DataInput
{
- /**
- * To reuse some of the non endian dependent methods from
- * DataInputStreams methods.
- */
- DataInputStream dataIn;
-
- public LEDataInputStream(InputStream in)
- {
- super(in);
- dataIn = new DataInputStream(in);
- }
-
- public void close() throws IOException
- {
- dataIn.close(); // better close as we create it.
- // this will close underlying as well.
- }
-
- public synchronized final int read(byte b[]) throws IOException
- {
- return dataIn.read(b, 0, b.length);
- }
-
- public synchronized final int read(byte b[], int off, int len) throws IOException
- {
- int rl = dataIn.read(b, off, len);
- return rl;
- }
-
- public final void readFully(byte b[]) throws IOException
- {
- dataIn.readFully(b, 0, b.length);
- }
-
- public final void readFully(byte b[], int off, int len) throws IOException
- {
- dataIn.readFully(b, off, len);
- }
-
- public final int skipBytes(int n) throws IOException
- {
- return dataIn.skipBytes(n);
- }
-
- public final boolean readBoolean() throws IOException
- {
- int ch = dataIn.read();
- if (ch < 0)
- throw new EOFException();
- return (ch != 0);
- }
-
- public final byte readByte() throws IOException
- {
- int ch = dataIn.read();
- if (ch < 0)
- throw new EOFException();
- return (byte)(ch);
- }
-
- public final int readUnsignedByte() throws IOException
- {
- int ch = dataIn.read();
- if (ch < 0)
- throw new EOFException();
- return ch;
- }
-
- public final short readShort() throws IOException
- {
- int ch1 = dataIn.read();
- int ch2 = dataIn.read();
- if ((ch1 | ch2) < 0)
- throw new EOFException();
- return (short)((ch1 << 0) + (ch2 << 8));
- }
-
- public final int readUnsignedShort() throws IOException
- {
- int ch1 = dataIn.read();
- int ch2 = dataIn.read();
- if ((ch1 | ch2) < 0)
- throw new EOFException();
- return (ch1 << 0) + (ch2 << 8);
- }
-
- public final char readChar() throws IOException
- {
- int ch1 = dataIn.read();
- int ch2 = dataIn.read();
- if ((ch1 | ch2) < 0)
- throw new EOFException();
- return (char)((ch1 << 0) + (ch2 << 8));
- }
-
- public final int readInt() throws IOException
- {
- int ch1 = dataIn.read();
- int ch2 = dataIn.read();
- int ch3 = dataIn.read();
- int ch4 = dataIn.read();
- if ((ch1 | ch2 | ch3 | ch4) < 0)
- throw new EOFException();
- return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24));
- }
-
- public final long readLong() throws IOException
- {
- int i1 = readInt();
- int i2 = readInt();
- return ((long)(i1) & 0xFFFFFFFFL) + (i2 << 32);
- }
-
- public final float readFloat() throws IOException
- {
- return Float.intBitsToFloat(readInt());
- }
-
- public final double readDouble() throws IOException
- {
- return Double.longBitsToDouble(readLong());
- }
-
- /**
- * dont call this it is not implemented.
- * @return empty new string
- **/
- public final String readLine() throws IOException
- {
- return new String();
- }
-
- /**
- * dont call this it is not implemented
- * @return empty new string
- **/
- public final String readUTF() throws IOException
- {
- return new String();
- }
-
- /**
- * dont call this it is not implemented
- * @return empty new string
- **/
- public final static String readUTF(DataInput in) throws IOException
- {
- return new String();
- }
+ /**
+ * To reuse some of the non endian dependent methods from
+ * DataInputStreams methods.
+ */
+ DataInputStream dataIn;
+
+ public LEDataInputStream(InputStream in)
+ {
+ super(in);
+ dataIn = new DataInputStream(in);
+ }
+
+ public void close() throws IOException
+ {
+ dataIn.close(); // better close as we create it.
+ // this will close underlying as well.
+ }
+
+ public synchronized final int read(byte b[]) throws IOException
+ {
+ return dataIn.read(b, 0, b.length);
+ }
+
+ public synchronized final int read(byte b[], int off, int len) throws IOException
+ {
+ int rl = dataIn.read(b, off, len);
+ return rl;
+ }
+
+ public final void readFully(byte b[]) throws IOException
+ {
+ dataIn.readFully(b, 0, b.length);
+ }
+
+ public final void readFully(byte b[], int off, int len) throws IOException
+ {
+ dataIn.readFully(b, off, len);
+ }
+
+ public final int skipBytes(int n) throws IOException
+ {
+ return dataIn.skipBytes(n);
+ }
+
+ public final boolean readBoolean() throws IOException
+ {
+ int ch = dataIn.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (ch != 0);
+ }
+
+ public final byte readByte() throws IOException
+ {
+ int ch = dataIn.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (byte)(ch);
+ }
+
+ public final int readUnsignedByte() throws IOException
+ {
+ int ch = dataIn.read();
+ if (ch < 0)
+ throw new EOFException();
+ return ch;
+ }
+
+ public final short readShort() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (short)((ch1 << 0) + (ch2 << 8));
+ }
+
+ public final int readUnsignedShort() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (ch1 << 0) + (ch2 << 8);
+ }
+
+ public final char readChar() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (char)((ch1 << 0) + (ch2 << 8));
+ }
+
+ public final int readInt() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ int ch3 = dataIn.read();
+ int ch4 = dataIn.read();
+ if ((ch1 | ch2 | ch3 | ch4) < 0)
+ throw new EOFException();
+ return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24));
+ }
+
+ public final long readLong() throws IOException
+ {
+ int i1 = readInt();
+ int i2 = readInt();
+ return ((long)(i1) & 0xFFFFFFFFL) + (i2 << 32);
+ }
+
+ public final float readFloat() throws IOException
+ {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ public final double readDouble() throws IOException
+ {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ /**
+ * dont call this it is not implemented.
+ * @return empty new string
+ **/
+ public final String readLine() throws IOException
+ {
+ return new String();
+ }
+
+ /**
+ * dont call this it is not implemented
+ * @return empty new string
+ **/
+ public final String readUTF() throws IOException
+ {
+ return new String();
+ }
+
+ /**
+ * dont call this it is not implemented
+ * @return empty new string
+ **/
+ public final static String readUTF(DataInput in) throws IOException
+ {
+ return new String();
+ }
}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java b/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java
index 5360dc01d..284fa64bd 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java
@@ -53,618 +53,618 @@ import com.sun.opengl.util.*;
*/
public class SGIImage {
- private Header header;
- private int format;
- private byte[] data;
- // Used for decoding RLE-compressed images
- private int[] rowStart;
- private int[] rowSize;
- private int rleEnd;
- private byte[] tmpData;
- private byte[] tmpRead;
-
- private static final int MAGIC = 474;
-
- static class Header {
- short magic; // IRIS image file magic number
- // This should be decimal 474
- byte storage; // Storage format
- // 0 for uncompressed
- // 1 for RLE compression
- byte bpc; // Number of bytes per pixel channel
- // Legally 1 or 2
- short dimension; // Number of dimensions
- // Legally 1, 2, or 3
- // 1 means a single row, XSIZE long
- // 2 means a single 2D image
- // 3 means multiple 2D images
- short xsize; // X size in pixels
- short ysize; // Y size in pixels
- short zsize; // Number of channels
- // 1 indicates greyscale
- // 3 indicates RGB
- // 4 indicates RGB and Alpha
- int pixmin; // Minimum pixel value
- // This is the lowest pixel value in the image
- int pixmax; // Maximum pixel value
- // This is the highest pixel value in the image
- int dummy; // Ignored
- // Normally set to 0
- String imagename; // Image name; 80 bytes long
- // Must be null terminated, therefore at most 79 bytes
- int colormap; // Colormap ID
- // 0 - normal mode
- // 1 - dithered, 3 mits for red and green, 2 for blue, obsolete
- // 2 - index colour, obsolete
- // 3 - not an image but a colourmap
- // 404 bytes char DUMMY Ignored
- // Should be set to 0, makes the header 512 bytes.
-
- Header() {
- magic = MAGIC;
+ private Header header;
+ private int format;
+ private byte[] data;
+ // Used for decoding RLE-compressed images
+ private int[] rowStart;
+ private int[] rowSize;
+ private int rleEnd;
+ private byte[] tmpData;
+ private byte[] tmpRead;
+
+ private static final int MAGIC = 474;
+
+ static class Header {
+ short magic; // IRIS image file magic number
+ // This should be decimal 474
+ byte storage; // Storage format
+ // 0 for uncompressed
+ // 1 for RLE compression
+ byte bpc; // Number of bytes per pixel channel
+ // Legally 1 or 2
+ short dimension; // Number of dimensions
+ // Legally 1, 2, or 3
+ // 1 means a single row, XSIZE long
+ // 2 means a single 2D image
+ // 3 means multiple 2D images
+ short xsize; // X size in pixels
+ short ysize; // Y size in pixels
+ short zsize; // Number of channels
+ // 1 indicates greyscale
+ // 3 indicates RGB
+ // 4 indicates RGB and Alpha
+ int pixmin; // Minimum pixel value
+ // This is the lowest pixel value in the image
+ int pixmax; // Maximum pixel value
+ // This is the highest pixel value in the image
+ int dummy; // Ignored
+ // Normally set to 0
+ String imagename; // Image name; 80 bytes long
+ // Must be null terminated, therefore at most 79 bytes
+ int colormap; // Colormap ID
+ // 0 - normal mode
+ // 1 - dithered, 3 mits for red and green, 2 for blue, obsolete
+ // 2 - index colour, obsolete
+ // 3 - not an image but a colourmap
+ // 404 bytes char DUMMY Ignored
+ // Should be set to 0, makes the header 512 bytes.
+
+ Header() {
+ magic = MAGIC;
+ }
+
+ Header(DataInputStream in) throws IOException {
+ magic = in.readShort();
+ storage = in.readByte();
+ bpc = in.readByte();
+ dimension = in.readShort();
+ xsize = in.readShort();
+ ysize = in.readShort();
+ zsize = in.readShort();
+ pixmin = in.readInt();
+ pixmax = in.readInt();
+ dummy = in.readInt();
+ byte[] tmpname = new byte[80];
+ in.read(tmpname);
+ int numChars = 0;
+ while (tmpname[numChars++] != 0);
+ imagename = new String(tmpname, 0, numChars);
+ colormap = in.readInt();
+ byte[] tmp = new byte[404];
+ in.read(tmp);
+ }
+
+ public String toString() {
+ return ("magic: " + magic +
+ " storage: " + (int) storage +
+ " bpc: " + (int) bpc +
+ " dimension: " + dimension +
+ " xsize: " + xsize +
+ " ysize: " + ysize +
+ " zsize: " + zsize +
+ " pixmin: " + pixmin +
+ " pixmax: " + pixmax +
+ " imagename: " + imagename +
+ " colormap: " + colormap);
+ }
}
- Header(DataInputStream in) throws IOException {
- magic = in.readShort();
- storage = in.readByte();
- bpc = in.readByte();
- dimension = in.readShort();
- xsize = in.readShort();
- ysize = in.readShort();
- zsize = in.readShort();
- pixmin = in.readInt();
- pixmax = in.readInt();
- dummy = in.readInt();
- byte[] tmpname = new byte[80];
- in.read(tmpname);
- int numChars = 0;
- while (tmpname[numChars++] != 0);
- imagename = new String(tmpname, 0, numChars);
- colormap = in.readInt();
- byte[] tmp = new byte[404];
- in.read(tmp);
+ private SGIImage(Header header) {
+ this.header = header;
}
- public String toString() {
- return ("magic: " + magic +
- " storage: " + (int) storage +
- " bpc: " + (int) bpc +
- " dimension: " + dimension +
- " xsize: " + xsize +
- " ysize: " + ysize +
- " zsize: " + zsize +
- " pixmin: " + pixmin +
- " pixmax: " + pixmax +
- " imagename: " + imagename +
- " colormap: " + colormap);
+ /** Reads an SGI image from the specified file. */
+ public static SGIImage read(String filename) throws IOException {
+ return read(new FileInputStream(filename));
}
- }
-
- private SGIImage(Header header) {
- this.header = header;
- }
-
- /** Reads an SGI image from the specified file. */
- public static SGIImage read(String filename) throws IOException {
- return read(new FileInputStream(filename));
- }
-
- /** Reads an SGI image from the specified InputStream. */
- public static SGIImage read(InputStream in) throws IOException {
- DataInputStream dIn = new DataInputStream(new BufferedInputStream(in));
-
- Header header = new Header(dIn);
- SGIImage res = new SGIImage(header);
- res.decodeImage(dIn);
- return res;
- }
-
- /** Writes this SGIImage to the specified file name. If
- flipVertically is set, outputs the scanlines from top to bottom
- rather than the default bottom to top order. */
- public void write(String filename, boolean flipVertically) throws IOException {
- write(new File(filename), flipVertically);
- }
-
- /** Writes this SGIImage to the specified file. If flipVertically is
- set, outputs the scanlines from top to bottom rather than the
- default bottom to top order. */
- public void write(File file, boolean flipVertically) throws IOException {
- writeImage(file, data, header.xsize, header.ysize, header.zsize, flipVertically);
- }
-
- /** Creates an SGIImage from the specified data in either RGB or
- RGBA format. */
- public static SGIImage createFromData(int width,
- int height,
- boolean hasAlpha,
- byte[] data) {
- Header header = new Header();
- header.xsize = (short) width;
- header.ysize = (short) height;
- header.zsize = (short) (hasAlpha ? 4 : 3);
- SGIImage image = new SGIImage(header);
- image.data = data;
- return image;
- }
-
- /** Determines from the magic number whether the given InputStream
- points to an SGI RGB image. The given InputStream must return
- true from markSupported() and support a minimum of two bytes
- of read-ahead. */
- public static boolean isSGIImage(InputStream in) throws IOException {
- if (!(in instanceof BufferedInputStream)) {
- in = new BufferedInputStream(in);
+
+ /** Reads an SGI image from the specified InputStream. */
+ public static SGIImage read(InputStream in) throws IOException {
+ DataInputStream dIn = new DataInputStream(new BufferedInputStream(in));
+
+ Header header = new Header(dIn);
+ SGIImage res = new SGIImage(header);
+ res.decodeImage(dIn);
+ return res;
}
- if (!in.markSupported()) {
- throw new IOException("Can not test non-destructively whether given InputStream is an SGI RGB image");
+
+ /** Writes this SGIImage to the specified file name. If
+ flipVertically is set, outputs the scanlines from top to bottom
+ rather than the default bottom to top order. */
+ public void write(String filename, boolean flipVertically) throws IOException {
+ write(new File(filename), flipVertically);
}
- DataInputStream dIn = new DataInputStream(in);
- dIn.mark(4);
- short magic = dIn.readShort();
- dIn.reset();
- return (magic == MAGIC);
- }
-
- /** Returns the width of the image. */
- public int getWidth() {
- return header.xsize;
- }
-
- /** Returns the height of the image. */
- public int getHeight() {
- return header.ysize;
- }
-
- /** Returns the OpenGL format for this texture; e.g. GL.GL_RGB or GL.GL_RGBA. */
- public int getFormat() {
- return format;
- }
-
- /** Returns the raw data for this texture in the correct
- (bottom-to-top) order for calls to glTexImage2D. */
- public byte[] getData() { return data; }
-
- public String toString() {
- return header.toString();
- }
-
- //----------------------------------------------------------------------
- // Internals only below this point
- //
-
- private void decodeImage(DataInputStream in) throws IOException {
- if (header.storage == 1) {
- // Read RLE compression data; row starts and sizes
- int x = header.ysize * header.zsize;
- rowStart = new int[x];
- rowSize = new int[x];
- rleEnd = 4 * 2 * x + 512;
- for (int i = 0; i < x; i++) {
- rowStart[i] = in.readInt();
- }
- for (int i = 0; i < x; i++) {
- rowSize[i] = in.readInt();
- }
- tmpRead = new byte[header.xsize * 256];
+
+ /** Writes this SGIImage to the specified file. If flipVertically is
+ set, outputs the scanlines from top to bottom rather than the
+ default bottom to top order. */
+ public void write(File file, boolean flipVertically) throws IOException {
+ writeImage(file, data, header.xsize, header.ysize, header.zsize, flipVertically);
}
- tmpData = readAll(in);
-
- int xsize = header.xsize;
- int ysize = header.ysize;
- int zsize = header.zsize;
- int lptr = 0;
-
- data = new byte[xsize * ysize * 4];
- byte[] rbuf = new byte[xsize];
- byte[] gbuf = new byte[xsize];
- byte[] bbuf = new byte[xsize];
- byte[] abuf = new byte[xsize];
- for (int y = 0; y < ysize; y++) {
- if (zsize >= 4) {
- getRow(rbuf, y, 0);
- getRow(gbuf, y, 1);
- getRow(bbuf, y, 2);
- getRow(abuf, y, 3);
- rgbatorgba(rbuf, gbuf, bbuf, abuf, data, lptr);
- } else if (zsize == 3) {
- getRow(rbuf, y, 0);
- getRow(gbuf, y, 1);
- getRow(bbuf, y, 2);
- rgbtorgba(rbuf, gbuf, bbuf, data, lptr);
- } else if (zsize == 2) {
- getRow(rbuf, y, 0);
- getRow(abuf, y, 1);
- latorgba(rbuf, abuf, data, lptr);
- } else {
- getRow(rbuf, y, 0);
- bwtorgba(rbuf, data, lptr);
- }
- lptr += 4 * xsize;
+
+ /** Creates an SGIImage from the specified data in either RGB or
+ RGBA format. */
+ public static SGIImage createFromData(int width,
+ int height,
+ boolean hasAlpha,
+ byte[] data) {
+ Header header = new Header();
+ header.xsize = (short) width;
+ header.ysize = (short) height;
+ header.zsize = (short) (hasAlpha ? 4 : 3);
+ SGIImage image = new SGIImage(header);
+ image.data = data;
+ return image;
+ }
+
+ /** Determines from the magic number whether the given InputStream
+ points to an SGI RGB image. The given InputStream must return
+ true from markSupported() and support a minimum of two bytes
+ of read-ahead. */
+ public static boolean isSGIImage(InputStream in) throws IOException {
+ if (!(in instanceof BufferedInputStream)) {
+ in = new BufferedInputStream(in);
+ }
+ if (!in.markSupported()) {
+ throw new IOException("Can not test non-destructively whether given InputStream is an SGI RGB image");
+ }
+ DataInputStream dIn = new DataInputStream(in);
+ dIn.mark(4);
+ short magic = dIn.readShort();
+ dIn.reset();
+ return (magic == MAGIC);
+ }
+
+ /** Returns the width of the image. */
+ public int getWidth() {
+ return header.xsize;
+ }
+
+ /** Returns the height of the image. */
+ public int getHeight() {
+ return header.ysize;
+ }
+
+ /** Returns the OpenGL format for this texture; e.g. GL.GL_RGB or GL.GL_RGBA. */
+ public int getFormat() {
+ return format;
}
- rowStart = null;
- rowSize = null;
- tmpData = null;
- tmpRead = null;
- format = GL.GL_RGBA;
- header.zsize = 4;
- }
-
- private void getRow(byte[] buf, int y, int z) {
- if (header.storage == 1) {
- int offs = rowStart[y + z * header.ysize] - rleEnd;
- System.arraycopy(tmpData, offs, tmpRead, 0, rowSize[y + z * header.ysize]);
- int iPtr = 0;
- int oPtr = 0;
- for (;;) {
- byte pixel = tmpRead[iPtr++];
- int count = (int) (pixel & 0x7F);
- if (count == 0) {
- return;
+
+ /** Returns the raw data for this texture in the correct
+ (bottom-to-top) order for calls to glTexImage2D. */
+ public byte[] getData() { return data; }
+
+ public String toString() {
+ return header.toString();
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private void decodeImage(DataInputStream in) throws IOException {
+ if (header.storage == 1) {
+ // Read RLE compression data; row starts and sizes
+ int x = header.ysize * header.zsize;
+ rowStart = new int[x];
+ rowSize = new int[x];
+ rleEnd = 4 * 2 * x + 512;
+ for (int i = 0; i < x; i++) {
+ rowStart[i] = in.readInt();
+ }
+ for (int i = 0; i < x; i++) {
+ rowSize[i] = in.readInt();
+ }
+ tmpRead = new byte[header.xsize * 256];
+ }
+ tmpData = readAll(in);
+
+ int xsize = header.xsize;
+ int ysize = header.ysize;
+ int zsize = header.zsize;
+ int lptr = 0;
+
+ data = new byte[xsize * ysize * 4];
+ byte[] rbuf = new byte[xsize];
+ byte[] gbuf = new byte[xsize];
+ byte[] bbuf = new byte[xsize];
+ byte[] abuf = new byte[xsize];
+ for (int y = 0; y < ysize; y++) {
+ if (zsize >= 4) {
+ getRow(rbuf, y, 0);
+ getRow(gbuf, y, 1);
+ getRow(bbuf, y, 2);
+ getRow(abuf, y, 3);
+ rgbatorgba(rbuf, gbuf, bbuf, abuf, data, lptr);
+ } else if (zsize == 3) {
+ getRow(rbuf, y, 0);
+ getRow(gbuf, y, 1);
+ getRow(bbuf, y, 2);
+ rgbtorgba(rbuf, gbuf, bbuf, data, lptr);
+ } else if (zsize == 2) {
+ getRow(rbuf, y, 0);
+ getRow(abuf, y, 1);
+ latorgba(rbuf, abuf, data, lptr);
+ } else {
+ getRow(rbuf, y, 0);
+ bwtorgba(rbuf, data, lptr);
+ }
+ lptr += 4 * xsize;
}
- if ((pixel & 0x80) != 0) {
- while ((count--) > 0) {
- buf[oPtr++] = tmpRead[iPtr++];
- }
+ rowStart = null;
+ rowSize = null;
+ tmpData = null;
+ tmpRead = null;
+ format = GL.GL_RGBA;
+ header.zsize = 4;
+ }
+
+ private void getRow(byte[] buf, int y, int z) {
+ if (header.storage == 1) {
+ int offs = rowStart[y + z * header.ysize] - rleEnd;
+ System.arraycopy(tmpData, offs, tmpRead, 0, rowSize[y + z * header.ysize]);
+ int iPtr = 0;
+ int oPtr = 0;
+ for (;;) {
+ byte pixel = tmpRead[iPtr++];
+ int count = (int) (pixel & 0x7F);
+ if (count == 0) {
+ return;
+ }
+ if ((pixel & 0x80) != 0) {
+ while ((count--) > 0) {
+ buf[oPtr++] = tmpRead[iPtr++];
+ }
+ } else {
+ pixel = tmpRead[iPtr++];
+ while ((count--) > 0) {
+ buf[oPtr++] = pixel;
+ }
+ }
+ }
} else {
- pixel = tmpRead[iPtr++];
- while ((count--) > 0) {
- buf[oPtr++] = pixel;
- }
+ int offs = (y * header.xsize) + (z * header.xsize * header.ysize);
+ System.arraycopy(tmpData, offs, buf, 0, header.xsize);
}
- }
- } else {
- int offs = (y * header.xsize) + (z * header.xsize * header.ysize);
- System.arraycopy(tmpData, offs, buf, 0, header.xsize);
}
- }
-
- private void bwtorgba(byte[] b, byte[] dest, int lptr) {
- for (int i = 0; i < b.length; i++) {
- dest[4 * i + lptr + 0] = b[i];
- dest[4 * i + lptr + 1] = b[i];
- dest[4 * i + lptr + 2] = b[i];
- dest[4 * i + lptr + 3] = (byte) 0xFF;
+
+ private void bwtorgba(byte[] b, byte[] dest, int lptr) {
+ for (int i = 0; i < b.length; i++) {
+ dest[4 * i + lptr + 0] = b[i];
+ dest[4 * i + lptr + 1] = b[i];
+ dest[4 * i + lptr + 2] = b[i];
+ dest[4 * i + lptr + 3] = (byte) 0xFF;
+ }
}
- }
-
- private void latorgba(byte[] b, byte[] a, byte[] dest, int lptr) {
- for (int i = 0; i < b.length; i++) {
- dest[4 * i + lptr + 0] = b[i];
- dest[4 * i + lptr + 1] = b[i];
- dest[4 * i + lptr + 2] = b[i];
- dest[4 * i + lptr + 3] = a[i];
+
+ private void latorgba(byte[] b, byte[] a, byte[] dest, int lptr) {
+ for (int i = 0; i < b.length; i++) {
+ dest[4 * i + lptr + 0] = b[i];
+ dest[4 * i + lptr + 1] = b[i];
+ dest[4 * i + lptr + 2] = b[i];
+ dest[4 * i + lptr + 3] = a[i];
+ }
}
- }
-
- private void rgbtorgba(byte[] r, byte[] g, byte[] b, byte[] dest, int lptr) {
- for (int i = 0; i < b.length; i++) {
- dest[4 * i + lptr + 0] = r[i];
- dest[4 * i + lptr + 1] = g[i];
- dest[4 * i + lptr + 2] = b[i];
- dest[4 * i + lptr + 3] = (byte) 0xFF;
+
+ private void rgbtorgba(byte[] r, byte[] g, byte[] b, byte[] dest, int lptr) {
+ for (int i = 0; i < b.length; i++) {
+ dest[4 * i + lptr + 0] = r[i];
+ dest[4 * i + lptr + 1] = g[i];
+ dest[4 * i + lptr + 2] = b[i];
+ dest[4 * i + lptr + 3] = (byte) 0xFF;
+ }
}
- }
-
- private void rgbatorgba(byte[] r, byte[] g, byte[] b, byte[] a, byte[] dest, int lptr) {
- for (int i = 0; i < b.length; i++) {
- dest[4 * i + lptr + 0] = r[i];
- dest[4 * i + lptr + 1] = g[i];
- dest[4 * i + lptr + 2] = b[i];
- dest[4 * i + lptr + 3] = a[i];
+
+ private void rgbatorgba(byte[] r, byte[] g, byte[] b, byte[] a, byte[] dest, int lptr) {
+ for (int i = 0; i < b.length; i++) {
+ dest[4 * i + lptr + 0] = r[i];
+ dest[4 * i + lptr + 1] = g[i];
+ dest[4 * i + lptr + 2] = b[i];
+ dest[4 * i + lptr + 3] = a[i];
+ }
}
- }
-
- private static byte imgref(byte[] i,
- int x,
- int y,
- int z,
- int xs,
- int ys,
- int zs) {
- return i[(xs*ys*z)+(xs*y)+x];
- }
-
-
- private void writeHeader(DataOutputStream stream,
- int xsize, int ysize, int zsize, boolean rle) throws IOException {
- // effects: outputs the 512-byte IRIS RGB header to STREAM, using xsize,
- // ysize, and depth as the dimensions of the image. NOTE that
- // the following defaults are used:
- // STORAGE = 1 (storage format = RLE)
- // BPC = 1 (# bytes/channel)
- // DIMENSION = 3
- // PIXMIN = 0
- // PIXMAX = 255
- // IMAGENAME = <80 nulls>
- // COLORMAP = 0
- // See ftp://ftp.sgi.com/pub/sgi/SGIIMAGESPEC for more details.
-
- // write out MAGIC, STORAGE, BPC
- stream.writeShort(474);
- stream.write((rle ? 1 : 0));
- stream.write(1);
-
- // write out DIMENSION
- stream.writeShort(3);
-
- // write XSIZE, YSIZE, ZSIZE
- stream.writeShort(xsize);
- stream.writeShort(ysize);
- stream.writeShort(zsize);
-
- // write PIXMIN, PIXMAX
- stream.writeInt(0);
- stream.writeInt(255);
-
- // write DUMMY
- stream.writeInt(0);
-
- // write IMAGENAME
- for (int i = 0; i < 80; i++)
- stream.write(0);
-
- // write COLORMAP
- stream.writeInt(0);
-
- // write DUMMY (404 bytes)
- for (int i = 0; i < 404; i++)
- stream.write(0);
- }
-
- private void writeImage(File file,
- byte[] data,
- int xsize,
- int ysize,
- int zsize,
- boolean yflip) throws IOException {
- // Input data is in RGBRGBRGB or RGBARGBARGBA format; first unswizzle it
- byte[] tmpData = new byte[xsize * ysize * zsize];
- int dest = 0;
- for (int i = 0; i < zsize; i++) {
- for (int j = i; j < (xsize * ysize * zsize); j += zsize) {
- tmpData[dest++] = data[j];
- }
+
+ private static byte imgref(byte[] i,
+ int x,
+ int y,
+ int z,
+ int xs,
+ int ys,
+ int zs) {
+ return i[(xs*ys*z)+(xs*y)+x];
}
- data = tmpData;
-
- // requires: DATA must be an array of size XSIZE * YSIZE * ZSIZE,
- // indexed in the following manner:
- // data[0] ...data[xsize-1] == first row of first channel
- // data[xsize]...data[2*xsize-1] == second row of first channel
- // ... data[(ysize - 1) * xsize]...data[(ysize * xsize) - 1] ==
- // last row of first channel
- // Later channels follow the same format.
- // *** NOTE that "first row" is defined by the BOTTOM ROW of
- // the image. That is, the origin is in the lower left corner.
- // effects: writes out an SGI image to FILE, RLE-compressed, INCLUDING
- // header, of dimensions (xsize, ysize, zsize), and containing
- // the data in DATA. If YFLIP is set, outputs the data in DATA
- // in reverse order vertically (equivalent to a flip about the
- // x axis).
-
- // Build the offset tables
- int[] starttab = new int[ysize * zsize];
- int[] lengthtab = new int[ysize * zsize];
-
- // Temporary buffer for holding RLE data.
- // Note that this makes the assumption that RLE-compressed data will
- // never exceed twice the size of the input data.
- // There are surely formal proofs about how big the RLE buffer should
- // be, as well as what the optimal look-ahead size is (i.e. don't switch
- // copy/repeat modes for less than N repeats). However, I'm going from
- // empirical evidence here; the break-even point seems to be a look-
- // ahead of 3. (That is, if the three values following this one are all
- // the same as the current value, switch to repeat mode.)
- int lookahead = 3;
- byte[] rlebuf = new byte[2 * xsize * ysize * zsize];
-
- int cur_loc = 0; // current offset location.
- int ptr = 0;
- int total_size = 0;
- int ystart = 0;
- int yincr = 1;
- int yend = ysize;
-
- if (yflip) {
- ystart = ysize - 1;
- yend = -1;
- yincr = -1;
+
+
+ private void writeHeader(DataOutputStream stream,
+ int xsize, int ysize, int zsize, boolean rle) throws IOException {
+ // effects: outputs the 512-byte IRIS RGB header to STREAM, using xsize,
+ // ysize, and depth as the dimensions of the image. NOTE that
+ // the following defaults are used:
+ // STORAGE = 1 (storage format = RLE)
+ // BPC = 1 (# bytes/channel)
+ // DIMENSION = 3
+ // PIXMIN = 0
+ // PIXMAX = 255
+ // IMAGENAME = <80 nulls>
+ // COLORMAP = 0
+ // See ftp://ftp.sgi.com/pub/sgi/SGIIMAGESPEC for more details.
+
+ // write out MAGIC, STORAGE, BPC
+ stream.writeShort(474);
+ stream.write((rle ? 1 : 0));
+ stream.write(1);
+
+ // write out DIMENSION
+ stream.writeShort(3);
+
+ // write XSIZE, YSIZE, ZSIZE
+ stream.writeShort(xsize);
+ stream.writeShort(ysize);
+ stream.writeShort(zsize);
+
+ // write PIXMIN, PIXMAX
+ stream.writeInt(0);
+ stream.writeInt(255);
+
+ // write DUMMY
+ stream.writeInt(0);
+
+ // write IMAGENAME
+ for (int i = 0; i < 80; i++)
+ stream.write(0);
+
+ // write COLORMAP
+ stream.writeInt(0);
+
+ // write DUMMY (404 bytes)
+ for (int i = 0; i < 404; i++)
+ stream.write(0);
}
- boolean DEBUG = false;
+ private void writeImage(File file,
+ byte[] data,
+ int xsize,
+ int ysize,
+ int zsize,
+ boolean yflip) throws IOException {
+ // Input data is in RGBRGBRGB or RGBARGBARGBA format; first unswizzle it
+ byte[] tmpData = new byte[xsize * ysize * zsize];
+ int dest = 0;
+ for (int i = 0; i < zsize; i++) {
+ for (int j = i; j < (xsize * ysize * zsize); j += zsize) {
+ tmpData[dest++] = data[j];
+ }
+ }
+ data = tmpData;
+
+ // requires: DATA must be an array of size XSIZE * YSIZE * ZSIZE,
+ // indexed in the following manner:
+ // data[0] ...data[xsize-1] == first row of first channel
+ // data[xsize]...data[2*xsize-1] == second row of first channel
+ // ... data[(ysize - 1) * xsize]...data[(ysize * xsize) - 1] ==
+ // last row of first channel
+ // Later channels follow the same format.
+ // *** NOTE that "first row" is defined by the BOTTOM ROW of
+ // the image. That is, the origin is in the lower left corner.
+ // effects: writes out an SGI image to FILE, RLE-compressed, INCLUDING
+ // header, of dimensions (xsize, ysize, zsize), and containing
+ // the data in DATA. If YFLIP is set, outputs the data in DATA
+ // in reverse order vertically (equivalent to a flip about the
+ // x axis).
+
+ // Build the offset tables
+ int[] starttab = new int[ysize * zsize];
+ int[] lengthtab = new int[ysize * zsize];
+
+ // Temporary buffer for holding RLE data.
+ // Note that this makes the assumption that RLE-compressed data will
+ // never exceed twice the size of the input data.
+ // There are surely formal proofs about how big the RLE buffer should
+ // be, as well as what the optimal look-ahead size is (i.e. don't switch
+ // copy/repeat modes for less than N repeats). However, I'm going from
+ // empirical evidence here; the break-even point seems to be a look-
+ // ahead of 3. (That is, if the three values following this one are all
+ // the same as the current value, switch to repeat mode.)
+ int lookahead = 3;
+ byte[] rlebuf = new byte[2 * xsize * ysize * zsize];
+
+ int cur_loc = 0; // current offset location.
+ int ptr = 0;
+ int total_size = 0;
+ int ystart = 0;
+ int yincr = 1;
+ int yend = ysize;
+
+ if (yflip) {
+ ystart = ysize - 1;
+ yend = -1;
+ yincr = -1;
+ }
+
+ boolean DEBUG = false;
- for (int z = 0; z < zsize; z++) {
- for (int y = ystart; y != yend; y += yincr) {
- // RLE-compress each row.
+ for (int z = 0; z < zsize; z++) {
+ for (int y = ystart; y != yend; y += yincr) {
+ // RLE-compress each row.
- int x = 0;
- byte count = 0;
- boolean repeat_mode = false;
- boolean should_switch = false;
- int start_ptr = ptr;
- int num_ptr = ptr++;
- byte repeat_val = 0;
+ int x = 0;
+ byte count = 0;
+ boolean repeat_mode = false;
+ boolean should_switch = false;
+ int start_ptr = ptr;
+ int num_ptr = ptr++;
+ byte repeat_val = 0;
- while (x < xsize) {
- // see if we should switch modes
- should_switch = false;
- if (repeat_mode) {
- if (imgref(data, x, y, z, xsize, ysize, zsize) != repeat_val) {
- should_switch = true;
- }
- } else {
- // look ahead to see if we should switch to repeat mode.
- // stay within the scanline for the lookahead
- if ((x + lookahead) < xsize) {
- should_switch = true;
- for (int i = 1; i <= lookahead; i++) {
- if (DEBUG)
- System.err.println("left side was " + ((int) imgref(data, x, y, z, xsize, ysize, zsize)) +
- ", right side was " + (int)imgref(data, x+i, y, z, xsize, ysize, zsize));
+ while (x < xsize) {
+ // see if we should switch modes
+ should_switch = false;
+ if (repeat_mode) {
+ if (imgref(data, x, y, z, xsize, ysize, zsize) != repeat_val) {
+ should_switch = true;
+ }
+ } else {
+ // look ahead to see if we should switch to repeat mode.
+ // stay within the scanline for the lookahead
+ if ((x + lookahead) < xsize) {
+ should_switch = true;
+ for (int i = 1; i <= lookahead; i++) {
+ if (DEBUG)
+ System.err.println("left side was " + ((int) imgref(data, x, y, z, xsize, ysize, zsize)) +
+ ", right side was " + (int)imgref(data, x+i, y, z, xsize, ysize, zsize));
- if (imgref(data, x, y, z, xsize, ysize, zsize) !=
- imgref(data, x+i, y, z, xsize, ysize, zsize))
- should_switch = false;
- }
- }
- }
-
- if (should_switch || (count == 127)) {
- // update the number of elements we repeated/copied
- if (x > 0) {
- if (repeat_mode)
- rlebuf[num_ptr] = count;
- else
- rlebuf[num_ptr] = (byte) (count | 0x80);
- }
- // perform mode switch if necessary; output repeat_val if
- // switching FROM repeat mode, and set it if switching
- // TO repeat mode.
- if (repeat_mode) {
- if (should_switch)
- repeat_mode = false;
- rlebuf[ptr++] = repeat_val;
- } else {
- if (should_switch)
- repeat_mode = true;
- repeat_val = imgref(data, x, y, z, xsize, ysize, zsize);
- }
+ if (imgref(data, x, y, z, xsize, ysize, zsize) !=
+ imgref(data, x+i, y, z, xsize, ysize, zsize))
+ should_switch = false;
+ }
+ }
+ }
+
+ if (should_switch || (count == 127)) {
+ // update the number of elements we repeated/copied
+ if (x > 0) {
+ if (repeat_mode)
+ rlebuf[num_ptr] = count;
+ else
+ rlebuf[num_ptr] = (byte) (count | 0x80);
+ }
+ // perform mode switch if necessary; output repeat_val if
+ // switching FROM repeat mode, and set it if switching
+ // TO repeat mode.
+ if (repeat_mode) {
+ if (should_switch)
+ repeat_mode = false;
+ rlebuf[ptr++] = repeat_val;
+ } else {
+ if (should_switch)
+ repeat_mode = true;
+ repeat_val = imgref(data, x, y, z, xsize, ysize, zsize);
+ }
- if (x > 0) {
- // reset the number pointer
- num_ptr = ptr++;
- // reset number of bytes copied
- count = 0;
- }
- }
+ if (x > 0) {
+ // reset the number pointer
+ num_ptr = ptr++;
+ // reset number of bytes copied
+ count = 0;
+ }
+ }
- // if not in repeat mode, copy element to ptr
- if (!repeat_mode) {
- rlebuf[ptr++] = imgref(data, x, y, z, xsize, ysize, zsize);
- }
- count++;
-
- if (x == xsize - 1) {
- // Need to store the number of pixels we copied/repeated.
- if (repeat_mode) {
- rlebuf[num_ptr] = count;
- // If we ended the row in repeat mode, store the
- // repeated value
- rlebuf[ptr++] = repeat_val;
+ // if not in repeat mode, copy element to ptr
+ if (!repeat_mode) {
+ rlebuf[ptr++] = imgref(data, x, y, z, xsize, ysize, zsize);
+ }
+ count++;
+
+ if (x == xsize - 1) {
+ // Need to store the number of pixels we copied/repeated.
+ if (repeat_mode) {
+ rlebuf[num_ptr] = count;
+ // If we ended the row in repeat mode, store the
+ // repeated value
+ rlebuf[ptr++] = repeat_val;
+ }
+ else
+ rlebuf[num_ptr] = (byte) (count | 0x80);
+
+ // output zero counter for the last value in the row
+ rlebuf[ptr++] = 0;
+ }
+
+ x++;
+ }
+ // output this row's length into the length table
+ int rowlen = ptr - start_ptr;
+ if (yflip)
+ lengthtab[ysize*z+(ysize-y-1)] = rowlen;
+ else
+ lengthtab[ysize*z+y] = rowlen;
+ // add to the start table, and update the current offset
+ if (yflip)
+ starttab[ysize*z+(ysize-y-1)] = cur_loc;
+ else
+ starttab[ysize*z+y] = cur_loc;
+ cur_loc += rowlen;
}
- else
- rlebuf[num_ptr] = (byte) (count | 0x80);
-
- // output zero counter for the last value in the row
- rlebuf[ptr++] = 0;
- }
-
- x++;
}
- // output this row's length into the length table
- int rowlen = ptr - start_ptr;
- if (yflip)
- lengthtab[ysize*z+(ysize-y-1)] = rowlen;
- else
- lengthtab[ysize*z+y] = rowlen;
- // add to the start table, and update the current offset
- if (yflip)
- starttab[ysize*z+(ysize-y-1)] = cur_loc;
- else
- starttab[ysize*z+y] = cur_loc;
- cur_loc += rowlen;
- }
- }
- // Now we have the offset tables computed, as well as the RLE data.
- // Output this information to the file.
- total_size = ptr;
+ // Now we have the offset tables computed, as well as the RLE data.
+ // Output this information to the file.
+ total_size = ptr;
- if (DEBUG)
- System.err.println("total_size was " + total_size);
+ if (DEBUG)
+ System.err.println("total_size was " + total_size);
- DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
+ DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
- writeHeader(stream, xsize, ysize, zsize, true);
+ writeHeader(stream, xsize, ysize, zsize, true);
- int SIZEOF_INT = 4;
- for (int i = 0; i < (ysize * zsize); i++)
- stream.writeInt(starttab[i] + 512 + (2 * ysize * zsize * SIZEOF_INT));
- for (int i = 0; i < (ysize * zsize); i++)
- stream.writeInt(lengthtab[i]);
- for (int i = 0; i < total_size; i++)
- stream.write(rlebuf[i]);
+ int SIZEOF_INT = 4;
+ for (int i = 0; i < (ysize * zsize); i++)
+ stream.writeInt(starttab[i] + 512 + (2 * ysize * zsize * SIZEOF_INT));
+ for (int i = 0; i < (ysize * zsize); i++)
+ stream.writeInt(lengthtab[i]);
+ for (int i = 0; i < total_size; i++)
+ stream.write(rlebuf[i]);
- stream.close();
- }
+ stream.close();
+ }
- private byte[] readAll(DataInputStream in) throws IOException {
- byte[] dest = new byte[16384];
- int pos = 0;
- int numRead = 0;
+ private byte[] readAll(DataInputStream in) throws IOException {
+ byte[] dest = new byte[16384];
+ int pos = 0;
+ int numRead = 0;
- boolean done = false;
-
- do {
- numRead = in.read(dest, pos, dest.length - pos);
- if (pos == dest.length) {
- // Resize destination buffer
- byte[] newDest = new byte[2 * dest.length];
- System.arraycopy(dest, 0, newDest, 0, pos);
- dest = newDest;
- }
- if (numRead > 0) {
- pos += numRead;
- }
+ boolean done = false;
+
+ do {
+ numRead = in.read(dest, pos, dest.length - pos);
+ if (pos == dest.length) {
+ // Resize destination buffer
+ byte[] newDest = new byte[2 * dest.length];
+ System.arraycopy(dest, 0, newDest, 0, pos);
+ dest = newDest;
+ }
+ if (numRead > 0) {
+ pos += numRead;
+ }
- done = ((numRead == -1) || (in.available() == 0));
- } while (!done);
+ done = ((numRead == -1) || (in.available() == 0));
+ } while (!done);
- // Trim destination buffer
- if (pos != dest.length) {
- byte[] finalDest = new byte[pos];
- System.arraycopy(dest, 0, finalDest, 0, pos);
- dest = finalDest;
- }
+ // Trim destination buffer
+ if (pos != dest.length) {
+ byte[] finalDest = new byte[pos];
+ System.arraycopy(dest, 0, finalDest, 0, pos);
+ dest = finalDest;
+ }
- return dest;
- }
+ return dest;
+ }
- // Test case
- /*
- import java.awt.image.*;
- import javax.swing.*;
+ // Test case
+ /*
+ import java.awt.image.*;
+ import javax.swing.*;
- public static void main(String[] args) {
- for (int i = 0; i < args.length; i++) {
+ public static void main(String[] args) {
+ for (int i = 0; i < args.length; i++) {
try {
- System.out.println(args[i] + ":");
- SGIImage image = SGIImage.read(args[i]);
- System.out.println(image);
- BufferedImage img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
- WritableRaster raster = img.getRaster();
- DataBufferByte db = (DataBufferByte) raster.getDataBuffer();
- byte[] src = image.getData();
- byte[] dest = db.getData();
- for (int j = 0; j < src.length; j += 4) {
- dest[j + 0] = src[j + 3];
- dest[j + 1] = src[j + 2];
- dest[j + 2] = src[j + 1];
- dest[j + 3] = src[j + 0];
- }
- // System.arraycopy(src, 0, dest, 0, src.length);
- ImageIcon icon = new ImageIcon(img);
- JLabel label = new JLabel();
- label.setIcon(icon);
- JFrame frame = new JFrame(args[i]);
- frame.getContentPane().add(label);
- frame.pack();
- frame.show();
+ System.out.println(args[i] + ":");
+ SGIImage image = SGIImage.read(args[i]);
+ System.out.println(image);
+ BufferedImage img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
+ WritableRaster raster = img.getRaster();
+ DataBufferByte db = (DataBufferByte) raster.getDataBuffer();
+ byte[] src = image.getData();
+ byte[] dest = db.getData();
+ for (int j = 0; j < src.length; j += 4) {
+ dest[j + 0] = src[j + 3];
+ dest[j + 1] = src[j + 2];
+ dest[j + 2] = src[j + 1];
+ dest[j + 3] = src[j + 0];
+ }
+ // System.arraycopy(src, 0, dest, 0, src.length);
+ ImageIcon icon = new ImageIcon(img);
+ JLabel label = new JLabel();
+ label.setIcon(icon);
+ JFrame frame = new JFrame(args[i]);
+ frame.getContentPane().add(label);
+ frame.pack();
+ frame.show();
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace();
}
- }
- }
- */
+ }
+ }
+ */
}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java
index e9e414891..2738536f0 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java
@@ -72,317 +72,317 @@ import com.sun.opengl.util.texture.*;
*/
public class TGAImage {
- private Header header;
- private int format;
- private ByteBuffer data;
-
- private TGAImage(Header header) {
- this.header = header;
- }
-
- /**
- * This class reads in all of the TGA image header in addition it also
- * reads in the imageID field as it is convenient to handle that here.
- *
- * @author Robin Luiten
- * @version 1.1
- */
- public static class Header {
- /** Set of possible file format TGA types */
- public final static int TYPE_NEW = 0;
- public final static int TYPE_OLD = 1;
- public final static int TYPE_UNK = 2; // cant rewind stream so unknown for now.
-
- /** Set of possible image types in TGA file */
- public final static int NO_IMAGE = 0; // no image data
- public final static int UCOLORMAPPED = 1; // uncompressed color mapped image
- public final static int UTRUECOLOR = 2; // uncompressed true color image
- public final static int UBLACKWHITE = 3; // uncompressed black and white image
- public final static int COLORMAPPED = 9; // compressed color mapped image
- public final static int TRUECOLOR = 10; // compressed true color image
- public final static int BLACKWHITE = 11; // compressed black and white image
-
- /** Field image descriptor bitfield values definitions */
- public final static int ID_ATTRIBPERPIXEL = 0xF;
- public final static int ID_RIGHTTOLEFT = 0x10;
- public final static int ID_TOPTOBOTTOM = 0x20;
- public final static int ID_INTERLEAVE = 0xC0;
-
- /** Field image descriptor / interleave values */
- public final static int I_NOTINTERLEAVED = 0;
- public final static int I_TWOWAY = 1;
- public final static int I_FOURWAY = 2;
-
- /** Type of this TGA file format */
- private int tgaType;
-
- /** initial TGA image data fields */
- private int idLength; // byte value
- private int colorMapType; // byte value
- private int imageType; // byte value
-
- /** TGA image colour map fields */
- private int firstEntryIndex;
- private int colorMapLength;
- private byte colorMapEntrySize;
-
- /** TGA image specification fields */
- private int xOrigin;
- private int yOrigin;
- private int width;
- private int height;
- private byte pixelDepth;
- private byte imageDescriptor;
-
- private byte[] imageIDbuf;
- private String imageID;
-
- // For construction from user data
- Header() {
- tgaType = TYPE_OLD; // dont try and get footer.
- }
+ private Header header;
+ private int format;
+ private ByteBuffer data;
- Header(LEDataInputStream in) throws IOException {
- int ret;
-
- tgaType = TYPE_OLD; // dont try and get footer.
-
- // initial header fields
- idLength = in.readUnsignedByte();
- colorMapType = in.readUnsignedByte();
- imageType = in.readUnsignedByte();
-
- // color map header fields
- firstEntryIndex = in.readUnsignedShort();
- colorMapLength = in.readUnsignedShort();
- colorMapEntrySize = in.readByte();
-
- // TGA image specification fields
- xOrigin = in.readUnsignedShort();
- yOrigin = in.readUnsignedShort();
- width = in.readUnsignedShort();
- height = in.readUnsignedShort();
- pixelDepth = in.readByte();
- imageDescriptor = in.readByte();
-
- if (idLength > 0) {
- imageIDbuf = new byte[idLength];
- in.read(imageIDbuf, 0, idLength);
- imageID = new String(imageIDbuf, "US-ASCII");
- }
+ private TGAImage(Header header) {
+ this.header = header;
}
- public int tgaType() { return tgaType; }
-
- /** initial TGA image data fields */
- public int idLength() { return idLength; }
- public int colorMapType() { return colorMapType; }
- public int imageType() { return imageType; }
-
- /** TGA image colour map fields */
- public int firstEntryIndex() { return firstEntryIndex; }
- public int colorMapLength() { return colorMapLength; }
- public byte colorMapEntrySize() { return colorMapEntrySize; }
-
- /** TGA image specification fields */
- public int xOrigin() { return xOrigin; }
- public int yOrigin() { return yOrigin; }
- public int width() { return width; }
- public int height() { return height; }
- public byte pixelDepth() { return pixelDepth; }
- public byte imageDescriptor() { return imageDescriptor; }
-
- /** bitfields in imageDescriptor */
- public byte attribPerPixel() { return (byte)(imageDescriptor & ID_ATTRIBPERPIXEL); }
- public boolean rightToLeft() { return ((imageDescriptor & ID_RIGHTTOLEFT) != 0); }
- public boolean topToBottom() { return ((imageDescriptor & ID_TOPTOBOTTOM) != 0); }
- public byte interleave() { return (byte)((imageDescriptor & ID_INTERLEAVE) >> 6); }
-
- public byte[] imageIDbuf() { return imageIDbuf; }
- public String imageID() { return imageID; }
-
- public String toString() {
- return "TGA Header " +
- " id length: " + idLength +
- " color map type: "+ colorMapType +
- " image type: "+ imageType +
- " first entry index: " + firstEntryIndex +
- " color map length: " + colorMapLength +
- " color map entry size: " + colorMapEntrySize +
- " x Origin: " + xOrigin +
- " y Origin: " + yOrigin +
- " width: "+ width +
- " height: "+ height +
- " pixel depth: "+ pixelDepth +
- " image descriptor: "+ imageDescriptor +
- (imageIDbuf == null ? "" : (" ID String: " + imageID));
- }
+ /**
+ * This class reads in all of the TGA image header in addition it also
+ * reads in the imageID field as it is convenient to handle that here.
+ *
+ * @author Robin Luiten
+ * @version 1.1
+ */
+ public static class Header {
+ /** Set of possible file format TGA types */
+ public final static int TYPE_NEW = 0;
+ public final static int TYPE_OLD = 1;
+ public final static int TYPE_UNK = 2; // cant rewind stream so unknown for now.
+
+ /** Set of possible image types in TGA file */
+ public final static int NO_IMAGE = 0; // no image data
+ public final static int UCOLORMAPPED = 1; // uncompressed color mapped image
+ public final static int UTRUECOLOR = 2; // uncompressed true color image
+ public final static int UBLACKWHITE = 3; // uncompressed black and white image
+ public final static int COLORMAPPED = 9; // compressed color mapped image
+ public final static int TRUECOLOR = 10; // compressed true color image
+ public final static int BLACKWHITE = 11; // compressed black and white image
+
+ /** Field image descriptor bitfield values definitions */
+ public final static int ID_ATTRIBPERPIXEL = 0xF;
+ public final static int ID_RIGHTTOLEFT = 0x10;
+ public final static int ID_TOPTOBOTTOM = 0x20;
+ public final static int ID_INTERLEAVE = 0xC0;
+
+ /** Field image descriptor / interleave values */
+ public final static int I_NOTINTERLEAVED = 0;
+ public final static int I_TWOWAY = 1;
+ public final static int I_FOURWAY = 2;
+
+ /** Type of this TGA file format */
+ private int tgaType;
+
+ /** initial TGA image data fields */
+ private int idLength; // byte value
+ private int colorMapType; // byte value
+ private int imageType; // byte value
+
+ /** TGA image colour map fields */
+ private int firstEntryIndex;
+ private int colorMapLength;
+ private byte colorMapEntrySize;
+
+ /** TGA image specification fields */
+ private int xOrigin;
+ private int yOrigin;
+ private int width;
+ private int height;
+ private byte pixelDepth;
+ private byte imageDescriptor;
+
+ private byte[] imageIDbuf;
+ private String imageID;
+
+ // For construction from user data
+ Header() {
+ tgaType = TYPE_OLD; // dont try and get footer.
+ }
+
+ Header(LEDataInputStream in) throws IOException {
+ int ret;
+
+ tgaType = TYPE_OLD; // dont try and get footer.
+
+ // initial header fields
+ idLength = in.readUnsignedByte();
+ colorMapType = in.readUnsignedByte();
+ imageType = in.readUnsignedByte();
+
+ // color map header fields
+ firstEntryIndex = in.readUnsignedShort();
+ colorMapLength = in.readUnsignedShort();
+ colorMapEntrySize = in.readByte();
+
+ // TGA image specification fields
+ xOrigin = in.readUnsignedShort();
+ yOrigin = in.readUnsignedShort();
+ width = in.readUnsignedShort();
+ height = in.readUnsignedShort();
+ pixelDepth = in.readByte();
+ imageDescriptor = in.readByte();
+
+ if (idLength > 0) {
+ imageIDbuf = new byte[idLength];
+ in.read(imageIDbuf, 0, idLength);
+ imageID = new String(imageIDbuf, "US-ASCII");
+ }
+ }
+
+ public int tgaType() { return tgaType; }
+
+ /** initial TGA image data fields */
+ public int idLength() { return idLength; }
+ public int colorMapType() { return colorMapType; }
+ public int imageType() { return imageType; }
+
+ /** TGA image colour map fields */
+ public int firstEntryIndex() { return firstEntryIndex; }
+ public int colorMapLength() { return colorMapLength; }
+ public byte colorMapEntrySize() { return colorMapEntrySize; }
+
+ /** TGA image specification fields */
+ public int xOrigin() { return xOrigin; }
+ public int yOrigin() { return yOrigin; }
+ public int width() { return width; }
+ public int height() { return height; }
+ public byte pixelDepth() { return pixelDepth; }
+ public byte imageDescriptor() { return imageDescriptor; }
+
+ /** bitfields in imageDescriptor */
+ public byte attribPerPixel() { return (byte)(imageDescriptor & ID_ATTRIBPERPIXEL); }
+ public boolean rightToLeft() { return ((imageDescriptor & ID_RIGHTTOLEFT) != 0); }
+ public boolean topToBottom() { return ((imageDescriptor & ID_TOPTOBOTTOM) != 0); }
+ public byte interleave() { return (byte)((imageDescriptor & ID_INTERLEAVE) >> 6); }
+
+ public byte[] imageIDbuf() { return imageIDbuf; }
+ public String imageID() { return imageID; }
+
+ public String toString() {
+ return "TGA Header " +
+ " id length: " + idLength +
+ " color map type: "+ colorMapType +
+ " image type: "+ imageType +
+ " first entry index: " + firstEntryIndex +
+ " color map length: " + colorMapLength +
+ " color map entry size: " + colorMapEntrySize +
+ " x Origin: " + xOrigin +
+ " y Origin: " + yOrigin +
+ " width: "+ width +
+ " height: "+ height +
+ " pixel depth: "+ pixelDepth +
+ " image descriptor: "+ imageDescriptor +
+ (imageIDbuf == null ? "" : (" ID String: " + imageID));
+ }
- public int size() { return 18 + idLength; }
-
- // buf must be in little-endian byte order
- private void write(ByteBuffer buf) {
- buf.put((byte) idLength);
- buf.put((byte) colorMapType);
- buf.put((byte) imageType);
- buf.putShort((short) firstEntryIndex);
- buf.putShort((short) colorMapLength);
- buf.put((byte) colorMapEntrySize);
- buf.putShort((short) xOrigin);
- buf.putShort((short) yOrigin);
- buf.putShort((short) width);
- buf.putShort((short) height);
- buf.put((byte) pixelDepth);
- buf.put((byte) imageDescriptor);
- if (idLength > 0) {
- try {
- byte[] chars = imageID.getBytes("US-ASCII");
- buf.put(chars);
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
+ public int size() { return 18 + idLength; }
+
+ // buf must be in little-endian byte order
+ private void write(ByteBuffer buf) {
+ buf.put((byte) idLength);
+ buf.put((byte) colorMapType);
+ buf.put((byte) imageType);
+ buf.putShort((short) firstEntryIndex);
+ buf.putShort((short) colorMapLength);
+ buf.put((byte) colorMapEntrySize);
+ buf.putShort((short) xOrigin);
+ buf.putShort((short) yOrigin);
+ buf.putShort((short) width);
+ buf.putShort((short) height);
+ buf.put((byte) pixelDepth);
+ buf.put((byte) imageDescriptor);
+ if (idLength > 0) {
+ try {
+ byte[] chars = imageID.getBytes("US-ASCII");
+ buf.put(chars);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
- }
}
- }
-
-
- /**
- * Identifies the image type of the tga image data and loads
- * it into the JimiImage structure. This was taken from the
- * prototype and modified for the new Jimi structure
- */
- private void decodeImage(LEDataInputStream dIn) throws IOException {
- switch (header.imageType()) {
- case Header.UCOLORMAPPED:
- throw new IOException("TGADecoder Uncompressed Colormapped images not supported");
-
- case Header.UTRUECOLOR: // pixelDepth 15, 16, 24 and 32
- switch (header.pixelDepth) {
- case 16:
- throw new IOException("TGADecoder Compressed 16-bit True Color images not supported");
-
- case 24:
- case 32:
- decodeRGBImageU24_32(dIn);
- break;
- }
- break;
-
- case Header.UBLACKWHITE:
- throw new IOException("TGADecoder Uncompressed Grayscale images not supported");
-
- case Header.COLORMAPPED:
- throw new IOException("TGADecoder Compressed Colormapped images not supported");
-
- case Header.TRUECOLOR:
- throw new IOException("TGADecoder Compressed True Color images not supported");
-
- case Header.BLACKWHITE:
- throw new IOException("TGADecoder Compressed Grayscale images not supported");
+
+
+ /**
+ * Identifies the image type of the tga image data and loads
+ * it into the JimiImage structure. This was taken from the
+ * prototype and modified for the new Jimi structure
+ */
+ private void decodeImage(LEDataInputStream dIn) throws IOException {
+ switch (header.imageType()) {
+ case Header.UCOLORMAPPED:
+ throw new IOException("TGADecoder Uncompressed Colormapped images not supported");
+
+ case Header.UTRUECOLOR: // pixelDepth 15, 16, 24 and 32
+ switch (header.pixelDepth) {
+ case 16:
+ throw new IOException("TGADecoder Compressed 16-bit True Color images not supported");
+
+ case 24:
+ case 32:
+ decodeRGBImageU24_32(dIn);
+ break;
+ }
+ break;
+
+ case Header.UBLACKWHITE:
+ throw new IOException("TGADecoder Uncompressed Grayscale images not supported");
+
+ case Header.COLORMAPPED:
+ throw new IOException("TGADecoder Compressed Colormapped images not supported");
+
+ case Header.TRUECOLOR:
+ throw new IOException("TGADecoder Compressed True Color images not supported");
+
+ case Header.BLACKWHITE:
+ throw new IOException("TGADecoder Compressed Grayscale images not supported");
+ }
}
- }
- /**
- * This assumes that the body is for a 24 bit or 32 bit for a
- * RGB or ARGB image respectively.
- */
- private void decodeRGBImageU24_32(LEDataInputStream dIn) throws IOException {
- int i; // row index
- int j; // column index
- int y; // output row index
- int raw; // index through the raw input buffer
- int rawWidth = header.width() * (header.pixelDepth() / 8);
- byte[] rawBuf = new byte[rawWidth];
- byte[] tmpData = new byte[rawWidth * header.height()];
-
- if (header.pixelDepth() == 24) {
- format = GL2.GL_BGR;
- } else {
- assert header.pixelDepth() == 32;
- format = GL2.GL_BGRA;
+ /**
+ * This assumes that the body is for a 24 bit or 32 bit for a
+ * RGB or ARGB image respectively.
+ */
+ private void decodeRGBImageU24_32(LEDataInputStream dIn) throws IOException {
+ int i; // row index
+ int j; // column index
+ int y; // output row index
+ int raw; // index through the raw input buffer
+ int rawWidth = header.width() * (header.pixelDepth() / 8);
+ byte[] rawBuf = new byte[rawWidth];
+ byte[] tmpData = new byte[rawWidth * header.height()];
+
+ if (header.pixelDepth() == 24) {
+ format = GL2.GL_BGR;
+ } else {
+ assert header.pixelDepth() == 32;
+ format = GL2.GL_BGRA;
+ }
+
+ for (i = 0; i < header.height(); ++i) {
+ dIn.readFully(rawBuf, 0, rawWidth);
+
+ if (header.topToBottom())
+ y = header.height - i - 1; // range 0 to (header.height - 1)
+ else
+ y = i;
+
+ System.arraycopy(rawBuf, 0, tmpData, y * rawWidth, rawBuf.length);
+ }
+
+ data = ByteBuffer.wrap(tmpData);
+ }
+
+ /** Returns the width of the image. */
+ public int getWidth() { return header.width(); }
+
+ /** Returns the height of the image. */
+ public int getHeight() { return header.height(); }
+
+ /** Returns the OpenGL format for this texture; e.g. GL.GL_BGR or GL.GL_BGRA. */
+ public int getGLFormat() { return format; }
+
+ /** Returns the raw data for this texture in the correct
+ (bottom-to-top) order for calls to glTexImage2D. */
+ public ByteBuffer getData() { return data; }
+
+ /** Reads a Targa image from the specified file. */
+ public static TGAImage read(String filename) throws IOException {
+ return read(new FileInputStream(filename));
}
- for (i = 0; i < header.height(); ++i) {
- dIn.readFully(rawBuf, 0, rawWidth);
+ /** Reads a Targa image from the specified InputStream. */
+ public static TGAImage read(InputStream in) throws IOException {
+ LEDataInputStream dIn = new LEDataInputStream(new BufferedInputStream(in));
- if (header.topToBottom())
- y = header.height - i - 1; // range 0 to (header.height - 1)
- else
- y = i;
+ Header header = new Header(dIn);
+ TGAImage res = new TGAImage(header);
+ res.decodeImage(dIn);
+ return res;
+ }
+
+ /** Writes the image in Targa format to the specified file name. */
+ public void write(String filename) throws IOException {
+ write(new File(filename));
+ }
- System.arraycopy(rawBuf, 0, tmpData, y * rawWidth, rawBuf.length);
+ /** Writes the image in Targa format to the specified file. */
+ public void write(File file) throws IOException {
+ FileOutputStream stream = new FileOutputStream(file);
+ FileChannel chan = stream.getChannel();
+ ByteBuffer buf = ByteBuffer.allocate(header.size());
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ header.write(buf);
+ buf.rewind();
+ chan.write(buf);
+ chan.write(data);
+ data.rewind();
+ chan.force(true);
+ chan.close();
+ stream.close();
}
- data = ByteBuffer.wrap(tmpData);
- }
-
- /** Returns the width of the image. */
- public int getWidth() { return header.width(); }
-
- /** Returns the height of the image. */
- public int getHeight() { return header.height(); }
-
- /** Returns the OpenGL format for this texture; e.g. GL.GL_BGR or GL.GL_BGRA. */
- public int getGLFormat() { return format; }
-
- /** Returns the raw data for this texture in the correct
- (bottom-to-top) order for calls to glTexImage2D. */
- public ByteBuffer getData() { return data; }
-
- /** Reads a Targa image from the specified file. */
- public static TGAImage read(String filename) throws IOException {
- return read(new FileInputStream(filename));
- }
-
- /** Reads a Targa image from the specified InputStream. */
- public static TGAImage read(InputStream in) throws IOException {
- LEDataInputStream dIn = new LEDataInputStream(new BufferedInputStream(in));
-
- Header header = new Header(dIn);
- TGAImage res = new TGAImage(header);
- res.decodeImage(dIn);
- return res;
- }
-
- /** Writes the image in Targa format to the specified file name. */
- public void write(String filename) throws IOException {
- write(new File(filename));
- }
-
- /** Writes the image in Targa format to the specified file. */
- public void write(File file) throws IOException {
- FileOutputStream stream = new FileOutputStream(file);
- FileChannel chan = stream.getChannel();
- ByteBuffer buf = ByteBuffer.allocate(header.size());
- buf.order(ByteOrder.LITTLE_ENDIAN);
- header.write(buf);
- buf.rewind();
- chan.write(buf);
- chan.write(data);
- data.rewind();
- chan.force(true);
- chan.close();
- stream.close();
- }
-
- /** Creates a TGAImage from data supplied by the end user. Shares
- data with the passed ByteBuffer. Assumes the data is already in
- the correct byte order for writing to disk, i.e., BGR or
- BGRA. */
- public static TGAImage createFromData(int width,
- int height,
- boolean hasAlpha,
- boolean topToBottom,
- ByteBuffer data) {
- Header header = new Header();
- header.imageType = Header.UTRUECOLOR;
- header.width = width;
- header.height = height;
- header.pixelDepth = (byte) (hasAlpha ? 32 : 24);
- header.imageDescriptor = (byte) (topToBottom ? Header.ID_TOPTOBOTTOM : 0);
- // Note ID not supported
- TGAImage ret = new TGAImage(header);
- ret.data = data;
- return ret;
- }
+ /** Creates a TGAImage from data supplied by the end user. Shares
+ data with the passed ByteBuffer. Assumes the data is already in
+ the correct byte order for writing to disk, i.e., BGR or
+ BGRA. */
+ public static TGAImage createFromData(int width,
+ int height,
+ boolean hasAlpha,
+ boolean topToBottom,
+ ByteBuffer data) {
+ Header header = new Header();
+ header.imageType = Header.UTRUECOLOR;
+ header.width = width;
+ header.height = height;
+ header.pixelDepth = (byte) (hasAlpha ? 32 : 24);
+ header.imageDescriptor = (byte) (topToBottom ? Header.ID_TOPTOBOTTOM : 0);
+ // Note ID not supported
+ TGAImage ret = new TGAImage(header);
+ ret.data = data;
+ return ret;
+ }
}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java b/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java
index 1c822ef02..baa087289 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java
@@ -52,114 +52,114 @@ import com.sun.opengl.util.texture.*;
public interface TextureProvider {
- /**
- * Produces a TextureData object from a file, or returns null if the
- * file format was not supported by this TextureProvider. Does not
- * do any OpenGL-related work. The resulting TextureData can be
- * converted into an OpenGL texture in a later step.
- *
- * @param file the file from which to read the texture data
- *
- * @param internalFormat the OpenGL internal format to be used for
- * the texture, or 0 if it should be inferred
- * from the file's contents
- *
- * @param pixelFormat the OpenGL pixel format to be used for
- * the texture, or 0 if it should be inferred
- * from the file's contents
- *
- * @param mipmap whether mipmaps should be produced for this
- * texture either by autogenerating them or
- * reading them from the file. Some file formats
- * support multiple mipmaps in a single file in
- * which case those mipmaps will be used rather
- * than generating them.
- *
- * @param fileSuffix the file suffix to be used as a hint to the
- * provider to more quickly decide whether it
- * can handle the file, or null if the
- * provider should infer the type from the
- * file's contents
- *
- * @throws IOException if an error occurred while reading the file
- */
- public TextureData newTextureData(File file,
- int internalFormat,
- int pixelFormat,
- boolean mipmap,
- String fileSuffix) throws IOException;
+ /**
+ * Produces a TextureData object from a file, or returns null if the
+ * file format was not supported by this TextureProvider. Does not
+ * do any OpenGL-related work. The resulting TextureData can be
+ * converted into an OpenGL texture in a later step.
+ *
+ * @param file the file from which to read the texture data
+ *
+ * @param internalFormat the OpenGL internal format to be used for
+ * the texture, or 0 if it should be inferred
+ * from the file's contents
+ *
+ * @param pixelFormat the OpenGL pixel format to be used for
+ * the texture, or 0 if it should be inferred
+ * from the file's contents
+ *
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ *
+ * @param fileSuffix the file suffix to be used as a hint to the
+ * provider to more quickly decide whether it
+ * can handle the file, or null if the
+ * provider should infer the type from the
+ * file's contents
+ *
+ * @throws IOException if an error occurred while reading the file
+ */
+ public TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException;
- /**
- * Produces a TextureData object from a stream, or returns null if
- * the file format was not supported by this TextureProvider. Does
- * not do any OpenGL-related work. The resulting TextureData can be
- * converted into an OpenGL texture in a later step.
- *
- * @param stream the stream from which to read the texture data
- *
- * @param internalFormat the OpenGL internal format to be used for
- * the texture, or 0 if it should be inferred
- * from the file's contents
- *
- * @param pixelFormat the OpenGL pixel format to be used for
- * the texture, or 0 if it should be inferred
- * from the file's contents
- *
- * @param mipmap whether mipmaps should be produced for this
- * texture either by autogenerating them or
- * reading them from the file. Some file formats
- * support multiple mipmaps in a single file in
- * which case those mipmaps will be used rather
- * than generating them.
- *
- * @param fileSuffix the file suffix to be used as a hint to the
- * provider to more quickly decide whether it
- * can handle the file, or null if the
- * provider should infer the type from the
- * file's contents
- *
- * @throws IOException if an error occurred while reading the stream
- */
- public TextureData newTextureData(InputStream stream,
- int internalFormat,
- int pixelFormat,
- boolean mipmap,
- String fileSuffix) throws IOException;
+ /**
+ * Produces a TextureData object from a stream, or returns null if
+ * the file format was not supported by this TextureProvider. Does
+ * not do any OpenGL-related work. The resulting TextureData can be
+ * converted into an OpenGL texture in a later step.
+ *
+ * @param stream the stream from which to read the texture data
+ *
+ * @param internalFormat the OpenGL internal format to be used for
+ * the texture, or 0 if it should be inferred
+ * from the file's contents
+ *
+ * @param pixelFormat the OpenGL pixel format to be used for
+ * the texture, or 0 if it should be inferred
+ * from the file's contents
+ *
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ *
+ * @param fileSuffix the file suffix to be used as a hint to the
+ * provider to more quickly decide whether it
+ * can handle the file, or null if the
+ * provider should infer the type from the
+ * file's contents
+ *
+ * @throws IOException if an error occurred while reading the stream
+ */
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException;
- /**
- * Produces a TextureData object from a URL, or returns null if the
- * file format was not supported by this TextureProvider. Does not
- * do any OpenGL-related work. The resulting TextureData can be
- * converted into an OpenGL texture in a later step.
- *
- * @param url the URL from which to read the texture data
- *
- * @param internalFormat the OpenGL internal format to be used for
- * the texture, or 0 if it should be inferred
- * from the file's contents
- *
- * @param pixelFormat the OpenGL pixel format to be used for
- * the texture, or 0 if it should be inferred
- * from the file's contents
- *
- * @param mipmap whether mipmaps should be produced for this
- * texture either by autogenerating them or
- * reading them from the file. Some file formats
- * support multiple mipmaps in a single file in
- * which case those mipmaps will be used rather
- * than generating them.
- *
- * @param fileSuffix the file suffix to be used as a hint to the
- * provider to more quickly decide whether it
- * can handle the file, or null if the
- * provider should infer the type from the
- * file's contents
- *
- * @throws IOException if an error occurred while reading the URL
- */
- public TextureData newTextureData(URL url,
- int internalFormat,
- int pixelFormat,
- boolean mipmap,
- String fileSuffix) throws IOException;
+ /**
+ * Produces a TextureData object from a URL, or returns null if the
+ * file format was not supported by this TextureProvider. Does not
+ * do any OpenGL-related work. The resulting TextureData can be
+ * converted into an OpenGL texture in a later step.
+ *
+ * @param url the URL from which to read the texture data
+ *
+ * @param internalFormat the OpenGL internal format to be used for
+ * the texture, or 0 if it should be inferred
+ * from the file's contents
+ *
+ * @param pixelFormat the OpenGL pixel format to be used for
+ * the texture, or 0 if it should be inferred
+ * from the file's contents
+ *
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ *
+ * @param fileSuffix the file suffix to be used as a hint to the
+ * provider to more quickly decide whether it
+ * can handle the file, or null if the
+ * provider should infer the type from the
+ * file's contents
+ *
+ * @throws IOException if an error occurred while reading the URL
+ */
+ public TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException;
}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java b/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java
index 423a3b3e5..cdad15bb2 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java
@@ -47,11 +47,11 @@ import com.sun.opengl.util.texture.*;
to new file formats. */
public interface TextureWriter {
- /** Writes the given TextureData to the passed file. Returns true if
- this TextureWriter successfully handled the writing of the file,
- otherwise false. May throw IOException if either this writer did
- not support certain parameters of the TextureData or if an I/O
- error occurred. */
- public boolean write(File file,
- TextureData data) throws IOException;
+ /** Writes the given TextureData to the passed file. Returns true if
+ this TextureWriter successfully handled the writing of the file,
+ otherwise false. May throw IOException if either this writer did
+ not support certain parameters of the TextureData or if an I/O
+ error occurred. */
+ public boolean write(File file,
+ TextureData data) throws IOException;
}