aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--make/build.xml19
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/Texture.java13
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/TextureIO.java.javame_cdc_fp1184
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/TextureIO.java.javase (renamed from src/classes/com/sun/opengl/util/texture/TextureIO.java)0
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javame_cdc_fp890
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javase (renamed from src/classes/com/sun/opengl/util/texture/spi/DDSImage.java)0
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/LEDataOutputStream.java165
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javame_cdc_fp385
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javase (renamed from src/classes/com/sun/opengl/util/texture/spi/TGAImage.java)0
9 files changed, 2646 insertions, 10 deletions
diff --git a/make/build.xml b/make/build.xml
index ac154ba0c..92e4188a8 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -277,7 +277,7 @@
</condition>
<condition property="java.excludes.cdcfp"
- value="com/sun/opengl/util/io/TGAWriter*, com/sun/opengl/util/texture/**">
+ value="com/sun/opengl/util/io/TGAWriter*, com/sun/opengl/util/texture/spi/awt/**">
<isset property="jogl.cdcfp"/>
</condition>
@@ -781,6 +781,21 @@
<!-- Generate the BufferUtil class for this particular profile -->
<target name="java.generate.BufferUtil" depends="java.generate.BufferUtil.javase, java.generate.BufferUtil.javame_cdc_fp" />
+ <target name="java.generate.TextureIO.javame_cdc_fp" if="jogl.cdcfp">
+ <copy file="../src/classes/com/sun/opengl/util/texture/TextureIO.java.javame_cdc_fp" tofile="../build/gensrc/classes/com/sun/opengl/util/texture/TextureIO.java" />
+ <copy file="../src/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javame_cdc_fp" tofile="../build/gensrc/classes/com/sun/opengl/util/texture/spi/DDSImage.java" />
+ <copy file="../src/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javame_cdc_fp" tofile="../build/gensrc/classes/com/sun/opengl/util/texture/spi/TGAImage.java" />
+ </target>
+
+ <target name="java.generate.TextureIO.javase" unless="jogl.cdcfp">
+ <copy file="../src/classes/com/sun/opengl/util/texture/TextureIO.java.javase" tofile="../build/gensrc/classes/com/sun/opengl/util/texture/TextureIO.java" />
+ <copy file="../src/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javase" tofile="../build/gensrc/classes/com/sun/opengl/util/texture/spi/DDSImage.java" />
+ <copy file="../src/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javase" tofile="../build/gensrc/classes/com/sun/opengl/util/texture/spi/TGAImage.java" />
+ </target>
+
+ <!-- Generate the TextureIO classes for this particular profile -->
+ <target name="java.generate.TextureIO" depends="java.generate.TextureIO.javase, java.generate.TextureIO.javame_cdc_fp" />
+
<target name="java.generate.gl.platforms" >
<dirset id="stub.includes.fileset.platform" dir="." includes="${stub.includes.dir}/${window.os.system}/** ${stub.includes.dir}/${window.es.system}/** ${stub.includes.dir}/common/** ${stub.includes.dir}/opengl/**" />
@@ -795,7 +810,7 @@
- from the C GL headers. This involves setting the taskdef and creating
- the classpath reference id then running the task on each header.
-->
- <target name="java.generate" depends="build.gluegen, java.generate.BufferUtil, java.generate.check" unless="java.generate.skip">
+ <target name="java.generate" depends="build.gluegen, java.generate.BufferUtil, java.generate.TextureIO, java.generate.check" unless="java.generate.skip">
<!-- Add the GlueGen and BuildStaticGLInfo tasks to ANT -->
<taskdef name="gluegen" classname="com.sun.gluegen.ant.GlueGenTask"
diff --git a/src/classes/com/sun/opengl/util/texture/Texture.java b/src/classes/com/sun/opengl/util/texture/Texture.java
index ec3692196..957f91490 100755
--- a/src/classes/com/sun/opengl/util/texture/Texture.java
+++ b/src/classes/com/sun/opengl/util/texture/Texture.java
@@ -40,7 +40,6 @@ import java.nio.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
-import javax.media.opengl.glu.gl2.*;
import com.sun.opengl.impl.*;
import com.sun.opengl.util.texture.*;
import com.sun.opengl.util.texture.spi.*;
@@ -519,13 +518,11 @@ public class Texture {
}
try {
- if(gl.isGL2()) {
- // FIXME: need to get rid of this cast
- GLUgl2 glu = (GLUgl2) GLU.createGLU();
- glu.gluBuild2DMipmaps(texTarget, data.getInternalFormat(),
- data.getWidth(), data.getHeight(),
- data.getPixelFormat(), data.getPixelType(), data.getBuffer());
- }
+ // FIXME: may need check for GLUnsupportedException
+ GLU glu = GLU.createGLU();
+ 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
}
diff --git a/src/classes/com/sun/opengl/util/texture/TextureIO.java.javame_cdc_fp b/src/classes/com/sun/opengl/util/texture/TextureIO.java.javame_cdc_fp
new file mode 100755
index 000000000..72e07b4bb
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/texture/TextureIO.java.javame_cdc_fp
@@ -0,0 +1,1184 @@
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.opengl.util.texture;
+
+import java.io.*;
+import java.net.*;
+import java.nio.*;
+import java.util.*;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+import com.sun.opengl.impl.Debug;
+import com.sun.opengl.util.io.*;
+import com.sun.opengl.util.texture.spi.*;
+
+/** <P> Provides input and output facilities for both loading OpenGL
+ textures from disk and streams as well as writing textures already
+ in memory back to disk. </P>
+
+ <P> The TextureIO class supports an arbitrary number of plug-in
+ readers and writers via TextureProviders and TextureWriters.
+ TextureProviders know how to produce TextureData objects from
+ files, InputStreams and URLs. TextureWriters know how to write
+ TextureData objects to disk in various file formats. The
+ TextureData class represents the raw data of the texture before it
+ has been converted to an OpenGL texture object. The Texture class
+ represents the OpenGL texture object and provides easy facilities
+ for using the texture. </P>
+
+ <P> There are several built-in TextureProviders and TextureWriters
+ supplied with the TextureIO implementation. The most basic
+ provider uses the platform's Image I/O facilities to read in a
+ BufferedImage and convert it to a texture. This is the baseline
+ provider and is registered so that it is the last one consulted.
+ All others are asked first to open a given file. </P>
+
+ <P> There are three other providers registered by default as of
+ the time of this writing. One handles SGI RGB (".sgi", ".rgb")
+ images from both files and streams. One handles DirectDraw Surface
+ (".dds") images read from files, though can not read these images
+ from streams. One handles Targa (".tga") images read from both
+ files and streams. These providers are executed in an arbitrary
+ order. Some of these providers require the file's suffix to either
+ be specified via the newTextureData methods or for the file to be
+ named with the appropriate suffix. In general a file suffix should
+ be provided to the newTexture and newTextureData methods if at all
+ possible. </P>
+
+ <P> Note that additional TextureProviders, if reading images from
+ InputStreams, must use the mark()/reset() methods on InputStream
+ when probing for e.g. magic numbers at the head of the file to
+ make sure not to disturb the state of the InputStream for
+ downstream TextureProviders. </P>
+
+ <P> There are analogous TextureWriters provided for writing
+ textures back to disk if desired. As of this writing, there are
+ four TextureWriters registered by default: one for Targa files,
+ one for SGI RGB files, one for DirectDraw surface (.dds) files,
+ and one for ImageIO-supplied formats such as .jpg and .png. Some
+ of these writers have certain limitations such as only being able
+ to write out textures stored in GL_RGB or GL_RGBA format. The DDS
+ writer supports fetching and writing to disk of texture data in
+ DXTn compressed format. Whether this will occur is dependent on
+ whether the texture's internal format is one of the DXTn
+ compressed formats and whether the target file is .dds format.
+*/
+
+public class TextureIO {
+ /** Constant which can be used as a file suffix to indicate a
+ DirectDraw Surface file. */
+ public static final String DDS = "dds";
+
+ /** Constant which can be used as a file suffix to indicate an SGI
+ RGB file. */
+ public static final String SGI = "sgi";
+
+ /** Constant which can be used as a file suffix to indicate an SGI
+ RGB file. */
+ public static final String SGI_RGB = "rgb";
+
+ /** Constant which can be used as a file suffix to indicate a GIF
+ file. */
+ public static final String GIF = "gif";
+
+ /** Constant which can be used as a file suffix to indicate a JPEG
+ file. */
+ public static final String JPG = "jpg";
+
+ /** Constant which can be used as a file suffix to indicate a PNG
+ file. */
+ public static final String PNG = "png";
+
+ /** Constant which can be used as a file suffix to indicate a Targa
+ file. */
+ public static final String TGA = "tga";
+
+ /** Constant which can be used as a file suffix to indicate a TIFF
+ file. */
+ public static final String TIFF = "tiff";
+
+ private static final boolean DEBUG = Debug.debug("TextureIO");
+
+ // For manually disabling the use of the texture rectangle
+ // extensions so you know the texture target is GL_TEXTURE_2D; this
+ // is useful for shader writers (thanks to Chris Campbell for this
+ // observation)
+ private static boolean texRectEnabled = true;
+
+ //----------------------------------------------------------------------
+ // methods that *do not* require a current context
+ // These methods assume RGB or RGBA textures.
+ // Some texture providers may not recognize the file format unless
+ // the fileSuffix is specified, so it is strongly recommended to
+ // specify it wherever it is known.
+ // Some texture providers may also only support one kind of input,
+ // i.e., reading from a file as opposed to a stream.
+
+ /**
+ * Creates a TextureData from the given file. Does no OpenGL work.
+ *
+ * @param file the file from which to read the texture data
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the file, or null if none of the
+ * registered texture providers could read the file
+ * @throws IOException if an error occurred while reading the file
+ */
+ public static TextureData newTextureData(File file,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(file);
+ }
+ return newTextureDataImpl(file, 0, 0, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given stream. Does no OpenGL work.
+ *
+ * @param stream the stream from which to read the texture data
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the stream, or null if none of the
+ * registered texture providers could read the stream
+ * @throws IOException if an error occurred while reading the stream
+ */
+ public static TextureData newTextureData(InputStream stream,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ return newTextureDataImpl(stream, 0, 0, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given URL. Does no OpenGL work.
+ *
+ * @param url the URL from which to read the texture data
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the URL, or null if none of the
+ * registered texture providers could read the URL
+ * @throws IOException if an error occurred while reading the URL
+ */
+ public static TextureData newTextureData(URL url,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(url.getPath());
+ }
+ return newTextureDataImpl(url, 0, 0, mipmap, fileSuffix);
+ }
+
+ //----------------------------------------------------------------------
+ // These methods make no assumption about the OpenGL internal format
+ // or pixel format of the texture; they must be specified by the
+ // user. It is not allowed to supply 0 (indicating no preference)
+ // for either the internalFormat or the pixelFormat;
+ // IllegalArgumentException will be thrown in this case.
+
+ /**
+ * Creates a TextureData from the given file, using the specified
+ * OpenGL internal format and pixel format for the texture which
+ * will eventually result. The internalFormat and pixelFormat must
+ * be specified and may not be zero; to use default values, use the
+ * variant of this method which does not take these arguments. Does
+ * no OpenGL work.
+ *
+ * @param file the file from which to read the texture data
+ * @param internalFormat the OpenGL internal format of the texture
+ * which will eventually result from the TextureData
+ * @param pixelFormat the OpenGL pixel format of the texture
+ * which will eventually result from the TextureData
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the file, or null if none of the
+ * registered texture providers could read the file
+ * @throws IllegalArgumentException if either internalFormat or
+ * pixelFormat was 0
+ * @throws IOException if an error occurred while reading the file
+ */
+ public static TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException, IllegalArgumentException {
+ if ((internalFormat == 0) || (pixelFormat == 0)) {
+ throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero");
+ }
+
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(file);
+ }
+
+ return newTextureDataImpl(file, internalFormat, pixelFormat, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given stream, using the specified
+ * OpenGL internal format and pixel format for the texture which
+ * will eventually result. The internalFormat and pixelFormat must
+ * be specified and may not be zero; to use default values, use the
+ * variant of this method which does not take these arguments. Does
+ * no OpenGL work.
+ *
+ * @param stream the stream from which to read the texture data
+ * @param internalFormat the OpenGL internal format of the texture
+ * which will eventually result from the TextureData
+ * @param pixelFormat the OpenGL pixel format of the texture
+ * which will eventually result from the TextureData
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the stream, or null if none of the
+ * registered texture providers could read the stream
+ * @throws IllegalArgumentException if either internalFormat or
+ * pixelFormat was 0
+ * @throws IOException if an error occurred while reading the stream
+ */
+ public static TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException, IllegalArgumentException {
+ if ((internalFormat == 0) || (pixelFormat == 0)) {
+ throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero");
+ }
+
+ return newTextureDataImpl(stream, internalFormat, pixelFormat, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given URL, using the specified
+ * OpenGL internal format and pixel format for the texture which
+ * will eventually result. The internalFormat and pixelFormat must
+ * be specified and may not be zero; to use default values, use the
+ * variant of this method which does not take these arguments. Does
+ * no OpenGL work.
+ *
+ * @param url the URL from which to read the texture data
+ * @param internalFormat the OpenGL internal format of the texture
+ * which will eventually result from the TextureData
+ * @param pixelFormat the OpenGL pixel format of the texture
+ * which will eventually result from the TextureData
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the URL, or null if none of the
+ * registered texture providers could read the URL
+ * @throws IllegalArgumentException if either internalFormat or
+ * pixelFormat was 0
+ * @throws IOException if an error occurred while reading the URL
+ */
+ public static TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException, IllegalArgumentException {
+ if ((internalFormat == 0) || (pixelFormat == 0)) {
+ throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero");
+ }
+
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(url.getPath());
+ }
+
+ return newTextureDataImpl(url, internalFormat, pixelFormat, mipmap, fileSuffix);
+ }
+
+ //----------------------------------------------------------------------
+ // methods that *do* require a current context
+ //
+
+ /**
+ * Creates an OpenGL texture object from the specified TextureData
+ * using the current OpenGL context.
+ *
+ * @param data the texture data to turn into an OpenGL texture
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ * @throws IllegalArgumentException if the passed TextureData was null
+ */
+ public static Texture newTexture(TextureData data) throws GLException, IllegalArgumentException {
+ if (data == null) {
+ throw new IllegalArgumentException("Null TextureData");
+ }
+ return new Texture(data);
+ }
+
+ /**
+ * Creates an OpenGL texture object from the specified file using
+ * the current OpenGL context.
+ *
+ * @param file the file from which to read the texture data
+ * @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.
+ * @throws IOException if an error occurred while reading the file
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(File file, boolean mipmap) throws IOException, GLException {
+ TextureData data = newTextureData(file, mipmap, FileUtil.getFileSuffix(file));
+ Texture texture = newTexture(data);
+ data.flush();
+ return texture;
+ }
+
+ /**
+ * Creates an OpenGL texture object from the specified stream using
+ * the current OpenGL context.
+ *
+ * @param stream the stream from which to read the texture data
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @throws IOException if an error occurred while reading the stream
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(InputStream stream, boolean mipmap, String fileSuffix) throws IOException, GLException {
+ TextureData data = newTextureData(stream, mipmap, fileSuffix);
+ Texture texture = newTexture(data);
+ data.flush();
+ return texture;
+ }
+
+ /**
+ * Creates an OpenGL texture object from the specified URL using the
+ * current OpenGL context.
+ *
+ * @param url the URL from which to read the texture data
+ * @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 suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @throws IOException if an error occurred while reading the URL
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(URL url, boolean mipmap, String fileSuffix) throws IOException, GLException {
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(url.getPath());
+ }
+ TextureData data = newTextureData(url, mipmap, fileSuffix);
+ Texture texture = newTexture(data);
+ data.flush();
+ return texture;
+ }
+
+ /**
+ * Creates an OpenGL texture object associated with the given OpenGL
+ * texture target using the current OpenGL context. The texture has
+ * no initial data. This is used, for example, to construct cube
+ * maps out of multiple TextureData objects.
+ *
+ * @param target the OpenGL target type, eg GL.GL_TEXTURE_2D,
+ * GL.GL_TEXTURE_RECTANGLE_ARB
+ *
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(int target) throws GLException {
+ return new Texture(target);
+ }
+
+ /**
+ * Writes the given texture to a file. The type of the file is
+ * inferred from its suffix. An OpenGL context must be current in
+ * order to fetch the texture data back from the OpenGL pipeline.
+ * This method causes the specified Texture to be bound to the
+ * GL_TEXTURE_2D state. If no suitable writer for the requested file
+ * format was found, throws an IOException. <P>
+ *
+ * Reasonable attempts are made to produce good results in the
+ * resulting images. The Targa, SGI and ImageIO writers produce
+ * results in the correct vertical orientation for those file
+ * formats. The DDS writer performs no vertical flip of the data,
+ * even in uncompressed mode. (It is impossible to perform such a
+ * vertical flip with compressed data.) Applications should keep
+ * this in mind when using this routine to save textures to disk for
+ * later re-loading. <P>
+ *
+ * Any mipmaps for the specified texture are currently discarded
+ * when it is written to disk, regardless of whether the underlying
+ * file format supports multiple mipmaps in a given file.
+ *
+ * @throws IOException if an error occurred during writing or no
+ * suitable writer was found
+ * @throws GLException if no OpenGL context was current or an
+ * OpenGL-related error occurred
+ */
+ public static void write(Texture texture, File file) throws IOException, GLException {
+ if (texture.getTarget() != GL.GL_TEXTURE_2D) {
+ throw new GLException("Only GL_TEXTURE_2D textures are supported");
+ }
+
+ // First fetch the texture data
+ GL _gl = GLU.getCurrentGL();
+ if (!_gl.isGL2()) {
+ throw new GLException("Only GL2 supports fetching compressed images, GL: " + _gl);
+ }
+ GL2 gl = _gl.getGL2();
+
+ texture.bind();
+ int internalFormat = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_INTERNAL_FORMAT);
+ int width = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_WIDTH);
+ int height = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_HEIGHT);
+ int border = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_BORDER);
+ TextureData data = null;
+ if (internalFormat == GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ internalFormat == GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
+ internalFormat == GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
+ internalFormat == GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) {
+ // Fetch using glGetCompressedTexImage
+ int size = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
+ ByteBuffer res = ByteBuffer.wrap(new byte[size]);
+ gl.glGetCompressedTexImage(GL.GL_TEXTURE_2D, 0, res);
+ data = new TextureData(internalFormat, width, height, border, internalFormat, GL.GL_UNSIGNED_BYTE,
+ false, true, true, res, null);
+ } else {
+ int bytesPerPixel = 0;
+ int fetchedFormat = 0;
+ switch (internalFormat) {
+ case GL.GL_RGB:
+ case GL2.GL_BGR:
+ case GL.GL_RGB8:
+ bytesPerPixel = 3;
+ fetchedFormat = GL.GL_RGB;
+ break;
+ case GL.GL_RGBA:
+ case GL2.GL_BGRA:
+ case GL2.GL_ABGR_EXT:
+ case GL.GL_RGBA8:
+ bytesPerPixel = 4;
+ fetchedFormat = GL.GL_RGBA;
+ break;
+ default:
+ throw new IOException("Unsupported texture internal format 0x" + Integer.toHexString(internalFormat));
+ }
+
+ // Fetch using glGetTexImage
+ int packAlignment = glGetInteger(GL.GL_PACK_ALIGNMENT);
+ int packRowLength = glGetInteger(GL2.GL_PACK_ROW_LENGTH);
+ int packSkipRows = glGetInteger(GL2.GL_PACK_SKIP_ROWS);
+ int packSkipPixels = glGetInteger(GL2.GL_PACK_SKIP_PIXELS);
+ int packSwapBytes = glGetInteger(GL2.GL_PACK_SWAP_BYTES);
+
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
+ gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, 0);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_ROWS, 0);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_PIXELS, 0);
+ gl.glPixelStorei(GL2.GL_PACK_SWAP_BYTES, 0);
+
+ ByteBuffer res = ByteBuffer.wrap(new byte[(width + (2 * border)) *
+ (height + (2 * border)) *
+ bytesPerPixel]);
+ if (DEBUG) {
+ System.out.println("Allocated buffer of size " + res.remaining() + " for fetched image (" +
+ ((fetchedFormat == GL.GL_RGB) ? "GL_RGB" : "GL_RGBA") + ")");
+ }
+ gl.glGetTexImage(GL.GL_TEXTURE_2D, 0, fetchedFormat, GL.GL_UNSIGNED_BYTE, res);
+
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, packAlignment);
+ gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, packRowLength);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_ROWS, packSkipRows);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_PIXELS, packSkipPixels);
+ gl.glPixelStorei(GL2.GL_PACK_SWAP_BYTES, packSwapBytes);
+
+ data = new TextureData(internalFormat, width, height, border, fetchedFormat, GL.GL_UNSIGNED_BYTE,
+ false, false, false, res, null);
+
+ if (DEBUG) {
+ System.out.println("data.getPixelFormat() = " +
+ ((data.getPixelFormat() == GL.GL_RGB) ? "GL_RGB" : "GL_RGBA"));
+ }
+ }
+
+ for (Iterator iter = textureWriters.iterator(); iter.hasNext(); ) {
+ TextureWriter writer = (TextureWriter) iter.next();
+ if (writer.write(file, data)) {
+ return;
+ }
+ }
+
+ throw new IOException("No suitable texture writer found");
+ }
+
+ //----------------------------------------------------------------------
+ // SPI support
+ //
+
+ /** Adds a TextureProvider to support reading of a new file
+ format. */
+ public static void addTextureProvider(TextureProvider provider) {
+ // Must always add at the front so the ImageIO provider is last,
+ // so we don't accidentally use it instead of a user's possibly
+ // more optimal provider
+ textureProviders.add(0, provider);
+ }
+
+ /** Adds a TextureWriter to support writing of a new file
+ format. */
+ public static void addTextureWriter(TextureWriter writer) {
+ // Must always add at the front so the ImageIO writer is last,
+ // so we don't accidentally use it instead of a user's possibly
+ // more optimal writer
+ textureWriters.add(0, writer);
+ }
+
+ //---------------------------------------------------------------------------
+ // Global disabling of texture rectangle extension
+ //
+
+ /** Toggles the use of the GL_ARB_texture_rectangle extension by the
+ TextureIO classes. By default, on hardware supporting this
+ extension, the TextureIO classes may use the
+ GL_ARB_texture_rectangle extension for non-power-of-two
+ textures. (If the hardware supports the
+ GL_ARB_texture_non_power_of_two extension, that one is
+ preferred.) In some situations, for example when writing
+ shaders, it is advantageous to force the texture target to
+ always be GL_TEXTURE_2D in order to have one version of the
+ shader, even at the expense of texture memory in the case where
+ NPOT textures are not supported. This method allows the use of
+ the GL_ARB_texture_rectangle extension to be turned off globally
+ for this purpose. The default is that the use of the extension
+ is enabled. */
+ public static void setTexRectEnabled(boolean enabled) {
+ texRectEnabled = enabled;
+ }
+
+ /** Indicates whether the GL_ARB_texture_rectangle extension is
+ allowed to be used for non-power-of-two textures; see {@link
+ #setTexRectEnabled setTexRectEnabled}. */
+ public static boolean isTexRectEnabled() {
+ return texRectEnabled;
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static List/*<TextureProvider>*/ textureProviders = new ArrayList/*<TextureProvider>*/();
+ private static List/*<TextureWriter>*/ textureWriters = new ArrayList/*<TextureWriter>*/();
+
+ static {
+ // ImageIO provider, the fall-back, must be the first one added
+ try {
+ // Use reflection to avoid compile-time dependencies on AWT-related classes
+ TextureProvider provider = (TextureProvider)
+ Class.forName("com.sun.opengl.util.texture.spi.awt.IIOTextureProvider").newInstance();
+ addTextureProvider(provider);
+ } catch (Exception e) {
+ if (DEBUG) {
+ e.printStackTrace();
+ }
+ }
+
+ // Other special-case providers
+ addTextureProvider(new DDSTextureProvider());
+ addTextureProvider(new SGITextureProvider());
+ addTextureProvider(new TGATextureProvider());
+
+ // ImageIO writer, the fall-back, must be the first one added
+ try {
+ // Use reflection to avoid compile-time dependencies on AWT-related classes
+ TextureWriter writer = (TextureWriter)
+ Class.forName("com.sun.opengl.util.texture.spi.awt.IIOTextureWriter").newInstance();
+ addTextureWriter(writer);
+ } catch (Exception e) {
+ if (DEBUG) {
+ e.printStackTrace();
+ }
+ }
+
+ // Other special-case writers
+ addTextureWriter(new DDSTextureWriter());
+ addTextureWriter(new SGITextureWriter());
+ addTextureWriter(new TGATextureWriter());
+ }
+
+ // Implementation methods
+ private static TextureData newTextureDataImpl(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (file == null) {
+ throw new IOException("File was null");
+ }
+
+ fileSuffix = toLowerCase(fileSuffix);
+
+ for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) {
+ TextureProvider provider = (TextureProvider) iter.next();
+ TextureData data = provider.newTextureData(file,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ fileSuffix);
+ if (data != null) {
+ return data;
+ }
+ }
+
+ throw new IOException("No suitable reader for given file");
+ }
+
+ private static TextureData newTextureDataImpl(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (stream == null) {
+ throw new IOException("Stream was null");
+ }
+
+ fileSuffix = toLowerCase(fileSuffix);
+
+ // Note: use of BufferedInputStream works around 4764639/4892246
+ if (!(stream instanceof BufferedInputStream)) {
+ stream = new BufferedInputStream(stream);
+ }
+
+ for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) {
+ TextureProvider provider = (TextureProvider) iter.next();
+ TextureData data = provider.newTextureData(stream,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ fileSuffix);
+ if (data != null) {
+ return data;
+ }
+ }
+
+ throw new IOException("No suitable reader for given stream");
+ }
+
+ private static TextureData newTextureDataImpl(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (url == null) {
+ throw new IOException("URL was null");
+ }
+
+ fileSuffix = toLowerCase(fileSuffix);
+
+ for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) {
+ TextureProvider provider = (TextureProvider) iter.next();
+ TextureData data = provider.newTextureData(url,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ fileSuffix);
+ if (data != null) {
+ return data;
+ }
+ }
+
+ throw new IOException("No suitable reader for given URL");
+ }
+
+ //----------------------------------------------------------------------
+ // DDS provider -- supports files only for now
+ static class DDSTextureProvider implements TextureProvider {
+ public TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (DDS.equals(fileSuffix) ||
+ DDS.equals(FileUtil.getFileSuffix(file))) {
+ DDSImage image = DDSImage.read(file);
+ return newTextureData(image, internalFormat, pixelFormat, mipmap);
+ }
+
+ return null;
+ }
+
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (DDS.equals(fileSuffix) ||
+ DDSImage.isDDSImage(stream)) {
+ DDSImage image = DDSImage.read(stream);
+ return newTextureData(image, internalFormat, pixelFormat, mipmap);
+ }
+
+ return null;
+ }
+
+ public TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ InputStream stream = new BufferedInputStream(url.openStream());
+ try {
+ return newTextureData(stream, internalFormat, pixelFormat, mipmap, fileSuffix);
+ } finally {
+ stream.close();
+ }
+ }
+
+ private TextureData newTextureData(final DDSImage image,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap) {
+ DDSImage.ImageInfo info = image.getMipMap(0);
+ if (pixelFormat == 0) {
+ switch (image.getPixelFormat()) {
+ case DDSImage.D3DFMT_R8G8B8:
+ pixelFormat = GL.GL_RGB;
+ break;
+ default:
+ pixelFormat = GL.GL_RGBA;
+ break;
+ }
+ }
+ if (info.isCompressed()) {
+ switch (info.getCompressionFormat()) {
+ case DDSImage.D3DFMT_DXT1:
+ internalFormat = GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ break;
+ case DDSImage.D3DFMT_DXT3:
+ internalFormat = GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ break;
+ case DDSImage.D3DFMT_DXT5:
+ internalFormat = GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ break;
+ default:
+ throw new RuntimeException("Unsupported DDS compression format \"" +
+ DDSImage.getCompressionFormatName(info.getCompressionFormat()) + "\"");
+ }
+ }
+ if (internalFormat == 0) {
+ switch (image.getPixelFormat()) {
+ case DDSImage.D3DFMT_R8G8B8:
+ pixelFormat = GL.GL_RGB;
+ break;
+ default:
+ pixelFormat = GL.GL_RGBA;
+ break;
+ }
+ }
+ TextureData.Flusher flusher = new TextureData.Flusher() {
+ public void flush() {
+ image.close();
+ }
+ };
+ TextureData data;
+ if (mipmap && image.getNumMipMaps() > 0) {
+ Buffer[] mipmapData = new Buffer[image.getNumMipMaps()];
+ for (int i = 0; i < image.getNumMipMaps(); i++) {
+ mipmapData[i] = image.getMipMap(i).getData();
+ }
+ data = new TextureData(internalFormat,
+ info.getWidth(),
+ info.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ info.isCompressed(),
+ true,
+ mipmapData,
+ flusher);
+ } else {
+ // Fix this up for the end user because we can't generate
+ // mipmaps for compressed textures
+ mipmap = false;
+ data = new TextureData(internalFormat,
+ info.getWidth(),
+ info.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ mipmap,
+ info.isCompressed(),
+ true,
+ info.getData(),
+ flusher);
+ }
+ return data;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Base class for SGI RGB and TGA image providers
+ static abstract class StreamBasedTextureProvider implements TextureProvider {
+ public TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ InputStream inStream = new BufferedInputStream(new FileInputStream(file));
+ try {
+ // The SGIImage and TGAImage implementations use InputStreams
+ // anyway so there isn't much point in having a separate code
+ // path for files
+ return newTextureData(inStream,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ ((fileSuffix != null) ? fileSuffix : FileUtil.getFileSuffix(file)));
+ } finally {
+ inStream.close();
+ }
+ }
+
+ public TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ InputStream stream = new BufferedInputStream(url.openStream());
+ try {
+ return newTextureData(stream, internalFormat, pixelFormat, mipmap, fileSuffix);
+ } finally {
+ stream.close();
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // SGI RGB image provider
+ static class SGITextureProvider extends StreamBasedTextureProvider {
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (SGI.equals(fileSuffix) ||
+ SGI_RGB.equals(fileSuffix) ||
+ SGIImage.isSGIImage(stream)) {
+ SGIImage image = SGIImage.read(stream);
+ if (pixelFormat == 0) {
+ pixelFormat = image.getFormat();
+ }
+ if (internalFormat == 0) {
+ internalFormat = image.getFormat();
+ }
+ return new TextureData(internalFormat,
+ image.getWidth(),
+ image.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ mipmap,
+ false,
+ false,
+ ByteBuffer.wrap(image.getData()),
+ null);
+ }
+
+ return null;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // TGA (Targa) image provider
+ static class TGATextureProvider extends StreamBasedTextureProvider {
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (TGA.equals(fileSuffix)) {
+ TGAImage image = TGAImage.read(stream);
+ if (pixelFormat == 0) {
+ pixelFormat = image.getGLFormat();
+ }
+ if (internalFormat == 0) {
+ internalFormat = GL.GL_RGBA8;
+ }
+ return new TextureData(internalFormat,
+ image.getWidth(),
+ image.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ mipmap,
+ false,
+ false,
+ image.getData(),
+ null);
+ }
+
+ return null;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // DDS texture writer
+ //
+ static class DDSTextureWriter implements TextureWriter {
+ public boolean write(File file,
+ TextureData data) throws IOException {
+ if (DDS.equals(FileUtil.getFileSuffix(file))) {
+ // See whether the DDS writer can handle this TextureData
+ int pixelFormat = data.getPixelFormat();
+ int pixelType = data.getPixelType();
+ if (pixelType != GL.GL_BYTE &&
+ pixelType != GL.GL_UNSIGNED_BYTE) {
+ throw new IOException("DDS writer only supports byte / unsigned byte textures");
+ }
+
+ int d3dFormat = 0;
+ // FIXME: some of these are probably not completely correct and would require swizzling
+ switch (pixelFormat) {
+ case GL.GL_RGB: d3dFormat = DDSImage.D3DFMT_R8G8B8; break;
+ case GL.GL_RGBA: d3dFormat = DDSImage.D3DFMT_A8R8G8B8; break;
+ case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: d3dFormat = DDSImage.D3DFMT_DXT1; break;
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: throw new IOException("RGBA DXT1 not yet supported");
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: d3dFormat = DDSImage.D3DFMT_DXT3; break;
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: d3dFormat = DDSImage.D3DFMT_DXT5; break;
+ default: throw new IOException("Unsupported pixel format 0x" + Integer.toHexString(pixelFormat) + " by DDS writer");
+ }
+
+ ByteBuffer[] mipmaps = null;
+ if (data.getMipmapData() != null) {
+ mipmaps = new ByteBuffer[data.getMipmapData().length];
+ for (int i = 0; i < mipmaps.length; i++) {
+ mipmaps[i] = (ByteBuffer) data.getMipmapData()[i];
+ }
+ } else {
+ mipmaps = new ByteBuffer[] { (ByteBuffer) data.getBuffer() };
+ }
+
+ DDSImage image = DDSImage.createFromData(d3dFormat,
+ data.getWidth(),
+ data.getHeight(),
+ mipmaps);
+ image.write(file);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // SGI (rgb) texture writer
+ //
+ static class SGITextureWriter implements TextureWriter {
+ public boolean write(File file,
+ TextureData data) throws IOException {
+ String fileSuffix = FileUtil.getFileSuffix(file);
+ if (SGI.equals(fileSuffix) ||
+ SGI_RGB.equals(fileSuffix)) {
+ // See whether the SGI writer can handle this TextureData
+ int pixelFormat = data.getPixelFormat();
+ int pixelType = data.getPixelType();
+ if ((pixelFormat == GL.GL_RGB ||
+ pixelFormat == GL.GL_RGBA) &&
+ (pixelType == GL.GL_BYTE ||
+ pixelType == GL.GL_UNSIGNED_BYTE)) {
+ ByteBuffer buf = ((data.getBuffer() != null) ?
+ (ByteBuffer) data.getBuffer() :
+ (ByteBuffer) data.getMipmapData()[0]);
+ byte[] bytes;
+ if (buf.hasArray()) {
+ bytes = buf.array();
+ } else {
+ buf.rewind();
+ bytes = new byte[buf.remaining()];
+ buf.get(bytes);
+ buf.rewind();
+ }
+
+ SGIImage image = SGIImage.createFromData(data.getWidth(),
+ data.getHeight(),
+ (pixelFormat == GL.GL_RGBA),
+ bytes);
+ image.write(file, false);
+ return true;
+ }
+
+ throw new IOException("SGI writer doesn't support this pixel format / type (only GL_RGB/A + bytes)");
+ }
+
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // TGA (Targa) texture writer
+
+ static class TGATextureWriter implements TextureWriter {
+ public boolean write(File file,
+ TextureData data) throws IOException {
+ if (TGA.equals(FileUtil.getFileSuffix(file))) {
+ // See whether the TGA writer can handle this TextureData
+ int pixelFormat = data.getPixelFormat();
+ int pixelType = data.getPixelType();
+ if ((pixelFormat == GL.GL_RGB ||
+ pixelFormat == GL.GL_RGBA) &&
+ (pixelType == GL.GL_BYTE ||
+ pixelType == GL.GL_UNSIGNED_BYTE)) {
+ ByteBuffer buf = ((data.getBuffer() != null) ?
+ (ByteBuffer) data.getBuffer() :
+ (ByteBuffer) data.getMipmapData()[0]);
+ // Must reverse order of red and blue channels to get correct results
+ int skip = ((pixelFormat == GL.GL_RGB) ? 3 : 4);
+ for (int i = 0; i < buf.remaining(); i += skip) {
+ byte red = buf.get(i + 0);
+ byte blue = buf.get(i + 2);
+ buf.put(i + 0, blue);
+ buf.put(i + 2, red);
+ }
+
+ TGAImage image = TGAImage.createFromData(data.getWidth(),
+ data.getHeight(),
+ (pixelFormat == GL.GL_RGBA),
+ false,
+ ((data.getBuffer() != null) ?
+ (ByteBuffer) data.getBuffer() :
+ (ByteBuffer) data.getMipmapData()[0]));
+ image.write(file);
+ return true;
+ }
+
+ throw new IOException("TGA writer doesn't support this pixel format / type (only GL_RGB/A + bytes)");
+ }
+
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Helper routines
+ //
+
+ private static int glGetInteger(int pname) {
+ int[] tmp = new int[1];
+ GL gl = GLU.getCurrentGL();
+ gl.glGetIntegerv(pname, tmp, 0);
+ return tmp[0];
+ }
+
+ private static int glGetTexLevelParameteri(GL2 gl, int target, int level, int pname) {
+ int[] tmp = new int[1];
+ gl.glGetTexLevelParameteriv(target, 0, pname, tmp, 0);
+ return tmp[0];
+ }
+
+ private static String toLowerCase(String arg) {
+ if (arg == null) {
+ return null;
+ }
+
+ return arg.toLowerCase();
+ }
+}
diff --git a/src/classes/com/sun/opengl/util/texture/TextureIO.java b/src/classes/com/sun/opengl/util/texture/TextureIO.java.javase
index 567432172..567432172 100755
--- a/src/classes/com/sun/opengl/util/texture/TextureIO.java
+++ b/src/classes/com/sun/opengl/util/texture/TextureIO.java.javase
diff --git a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javame_cdc_fp b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javame_cdc_fp
new file mode 100755
index 000000000..de776a2e1
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javame_cdc_fp
@@ -0,0 +1,890 @@
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.opengl.util.texture.spi;
+
+import java.io.*;
+import java.nio.*;
+
+import javax.media.opengl.*;
+import javax.media.opengl.util.*;
+import com.sun.opengl.util.io.*;
+import com.sun.opengl.util.texture.*;
+
+/** A reader and writer for DirectDraw Surface (.dds) files, which are
+ used to describe textures. These files can contain multiple mipmap
+ levels in one file. This class is currently minimal and does not
+ support all of the possible file formats. */
+
+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 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 InputStream, returning
+ the resulting DDSImage.
+
+ @param input Input stream
+ @return DDS image object
+ @throws java.io.IOException if an I/O exception occurred
+ */
+ public static DDSImage read(InputStream input) throws IOException {
+ DDSImage image = new DDSImage();
+ image.readFromStream(input);
+ 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() {
+ }
+
+ /**
+ * 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 (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 {
+ LEDataOutputStream output =
+ new LEDataOutputStream(new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
+ header.write(output);
+ output.write(buf.array());
+ output.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 = 0;
+ 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(LEDataInputStream input) throws IOException {
+ int magic = input.readInt();
+ if (magic != MAGIC) {
+ throw new IOException("Incorrect magic number 0x" +
+ Integer.toHexString(magic) +
+ " (expected " + MAGIC + ")");
+ }
+
+ size = input.readInt();
+ flags = input.readInt();
+ height = input.readInt();
+ width = input.readInt();
+ pitchOrLinearSize = input.readInt();
+ backBufferCountOrDepth = input.readInt();
+ mipMapCountOrAux = input.readInt();
+ alphaBitDepth = input.readInt();
+ reserved1 = input.readInt();
+ surface = input.readInt();
+ colorSpaceLowValue = input.readInt();
+ colorSpaceHighValue = input.readInt();
+ destBltColorSpaceLowValue = input.readInt();
+ destBltColorSpaceHighValue = input.readInt();
+ srcOverlayColorSpaceLowValue = input.readInt();
+ srcOverlayColorSpaceHighValue = input.readInt();
+ srcBltColorSpaceLowValue = input.readInt();
+ srcBltColorSpaceHighValue = input.readInt();
+ pfSize = input.readInt();
+ pfFlags = input.readInt();
+ pfFourCC = input.readInt();
+ pfRGBBitCount = input.readInt();
+ pfRBitMask = input.readInt();
+ pfGBitMask = input.readInt();
+ pfBBitMask = input.readInt();
+ pfABitMask = input.readInt();
+ ddsCaps1 = input.readInt();
+ ddsCaps2 = input.readInt();
+ ddsCapsReserved1 = input.readInt();
+ ddsCapsReserved2 = input.readInt();
+ textureStage = input.readInt();
+ }
+
+ // buf must be in little-endian byte order
+ void write(LEDataOutputStream output) throws IOException {
+ output.writeInt(MAGIC);
+ output.writeInt(size);
+ output.writeInt(flags);
+ output.writeInt(height);
+ output.writeInt(width);
+ output.writeInt(pitchOrLinearSize);
+ output.writeInt(backBufferCountOrDepth);
+ output.writeInt(mipMapCountOrAux);
+ output.writeInt(alphaBitDepth);
+ output.writeInt(reserved1);
+ output.writeInt(surface);
+ output.writeInt(colorSpaceLowValue);
+ output.writeInt(colorSpaceHighValue);
+ output.writeInt(destBltColorSpaceLowValue);
+ output.writeInt(destBltColorSpaceHighValue);
+ output.writeInt(srcOverlayColorSpaceLowValue);
+ output.writeInt(srcOverlayColorSpaceHighValue);
+ output.writeInt(srcBltColorSpaceLowValue);
+ output.writeInt(srcBltColorSpaceHighValue);
+ output.writeInt(pfSize);
+ output.writeInt(pfFlags);
+ output.writeInt(pfFourCC);
+ output.writeInt(pfRGBBitCount);
+ output.writeInt(pfRBitMask);
+ output.writeInt(pfGBitMask);
+ output.writeInt(pfBBitMask);
+ output.writeInt(pfABitMask);
+ output.writeInt(ddsCaps1);
+ output.writeInt(ddsCaps2);
+ output.writeInt(ddsCapsReserved1);
+ output.writeInt(ddsCapsReserved2);
+ output.writeInt(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 {
+ readFromStream(new BufferedInputStream(new FileInputStream(file)));
+ }
+
+ private void readFromStream(InputStream input) throws IOException {
+ LEDataInputStream leInput = new LEDataInputStream(input);
+ header = new Header();
+ header.read(leInput);
+ fixupHeader();
+ buf = ByteBuffer.wrap(StreamUtil.readAll(input));
+ }
+
+ 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 byte array to hold all of the mipmap data
+ byte[] data = new byte[totalSize];
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ 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;
+ }
+}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javase
index cca8dbd2b..cca8dbd2b 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java.javase
diff --git a/src/classes/com/sun/opengl/util/texture/spi/LEDataOutputStream.java b/src/classes/com/sun/opengl/util/texture/spi/LEDataOutputStream.java
new file mode 100755
index 000000000..730ec0dbd
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/texture/spi/LEDataOutputStream.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.opengl.util.texture.spi;
+
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Little Endian Data Output Stream.
+ *
+ * This class implements an output stream filter to allow writing
+ * of java native datatypes to an output stream which has those
+ * native datatypes stored in a little endian byte order.<p>
+ *
+ * This is the sister class of the DataOutputStream which allows
+ * for writing of java native datatypes to an output stream with
+ * the datatypes stored in big endian byte order.<p>
+ *
+ * This class implements the minimum required and calls DataOutputStream
+ * for some of the required methods for DataOutput.<p>
+ *
+ * Not all methods are implemented due to lack of immediate requirement
+ * for that functionality. It is not clear if it is ever going to be
+ * functionally required to be able to read UTF data in a LittleEndianManner<p>
+ *
+ */
+public class LEDataOutputStream extends FilterOutputStream implements DataOutput
+{
+ /**
+ * To reuse some of the non endian dependent methods from
+ * DataOutputStream's methods.
+ */
+ DataOutputStream dataOut;
+
+ public LEDataOutputStream(OutputStream out)
+ {
+ super(out);
+ dataOut = new DataOutputStream(out);
+ }
+
+ public void close() throws IOException
+ {
+ dataOut.close(); // better close as we create it.
+ // this will close underlying as well.
+ }
+
+ public synchronized final void write(byte b[]) throws IOException
+ {
+ dataOut.write(b, 0, b.length);
+ }
+
+ public synchronized final void write(byte b[], int off, int len) throws IOException
+ {
+ dataOut.write(b, off, len);
+ }
+
+ public final void write(int b) throws IOException
+ {
+ dataOut.write(b);
+ }
+
+ public final void writeBoolean(boolean v) throws IOException
+ {
+ dataOut.writeBoolean(v);
+ }
+
+ public final void writeByte(int v) throws IOException
+ {
+ dataOut.writeByte(v);
+ }
+
+ /** Don't call this -- not implemented */
+ public final void writeBytes(String s) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public final void writeChar(int v) throws IOException
+ {
+ dataOut.writeChar(((v >> 8) & 0xff) |
+ ((v & 0xff) << 8));
+ }
+
+ /** Don't call this -- not implemented */
+ public final void writeChars(String s) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public final void writeDouble(double v) throws IOException
+ {
+ writeLong(Double.doubleToRawLongBits(v));
+ }
+
+ public final void writeFloat(float v) throws IOException
+ {
+ writeInt(Float.floatToRawIntBits(v));
+ }
+
+ public final void writeInt(int v) throws IOException
+ {
+ dataOut.writeInt((v >>> 24) |
+ ((v >>> 8) & 0xff00) |
+ ((v << 8) & 0x00ff00) |
+ (v << 24));
+ }
+
+ public final void writeLong(long v) throws IOException
+ {
+ writeInt((int) v);
+ writeInt((int) (v >>> 32));
+ }
+
+ public final void writeShort(int v) throws IOException
+ {
+ dataOut.writeShort(((v >> 8) & 0xff) |
+ ((v & 0xff) << 8));
+ }
+
+ /** Don't call this -- not implemented */
+ public final void writeUTF(String s) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javame_cdc_fp b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javame_cdc_fp
new file mode 100755
index 000000000..be4ac36d2
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javame_cdc_fp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.opengl.util.texture.spi;
+
+import java.io.*;
+import java.nio.*;
+import javax.media.opengl.*;
+import com.sun.opengl.util.*;
+import com.sun.opengl.util.texture.spi.*;
+import com.sun.opengl.util.texture.*;
+
+/**
+ * Targa image reader and writer adapted from sources of the <a href =
+ * "http://java.sun.com/products/jimi/">Jimi</a> image I/O class library.
+ *
+ * <P>
+ *
+ * Image decoder for image data stored in TGA file format.
+ * Currently only the original TGA file format is supported. This is
+ * because the new TGA format has data at the end of the file, getting
+ * to the end of a file in an InputStream orient environment presents
+ * several difficulties which are avoided at the moment.
+ *
+ * <P>
+ *
+ * This is a simple decoder and is only setup to load a single image
+ * from the input stream
+ *
+ * <P>
+ *
+ * @author Robin Luiten
+ * @author Kenneth Russell
+ * @version $Revision$
+ */
+
+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.
+ }
+
+ 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; }
+
+ private void write(LEDataOutputStream output) throws IOException {
+ output.write(idLength);
+ output.write(colorMapType);
+ output.write(imageType);
+ output.writeShort(firstEntryIndex);
+ output.writeShort(colorMapLength);
+ output.write(colorMapEntrySize);
+ output.writeShort(xOrigin);
+ output.writeShort(yOrigin);
+ output.writeShort(width);
+ output.writeShort(height);
+ output.write(pixelDepth);
+ output.write(imageDescriptor);
+ if (idLength > 0) {
+ try {
+ byte[] chars = imageID.getBytes("US-ASCII");
+ output.write(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");
+ }
+ }
+
+ /**
+ * 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));
+ }
+
+ /** 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 {
+ LEDataOutputStream output =
+ new LEDataOutputStream(new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
+ header.write(output);
+ if (!data.isDirect()) {
+ output.write(data.array());
+ } else {
+ for (int i = 0; i < data.limit(); i++) {
+ output.write(data.get(i));
+ }
+ }
+ output.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;
+ }
+}
diff --git a/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javase
index 2738536f0..2738536f0 100755
--- a/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java
+++ b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java.javase