diff options
author | Kenneth Russel <[email protected]> | 2008-07-16 08:06:19 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2008-07-16 08:06:19 +0000 |
commit | db5aca42f5678f4f44750e8297464ca7bbbbc944 (patch) | |
tree | 8e28e9f0e7e65553993731c4ce2b0a52c30246a2 /src/classes/com/sun/opengl/util/texture/spi | |
parent | 0867db5f547bedae63ed2be34cc02d7bf39e6ec9 (diff) |
Formatting changes only
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JOGL_2_SANDBOX@1724 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/classes/com/sun/opengl/util/texture/spi')
6 files changed, 1990 insertions, 1990 deletions
diff --git a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java index 01cdf4867..cca8dbd2b 100755 --- a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java +++ b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java @@ -54,866 +54,866 @@ import com.sun.opengl.util.texture.*; public class DDSImage { - /** Simple class describing images and data; does not encapsulate - image format information. User is responsible for transmitting - that information in another way. */ - - public static class ImageInfo { - private ByteBuffer data; - private int width; - private int height; - private boolean isCompressed; - private int compressionFormat; - - public ImageInfo(ByteBuffer data, int width, int height, boolean compressed, int compressionFormat) { - this.data = data; this.width = width; this.height = height; - this.isCompressed = compressed; this.compressionFormat = compressionFormat; - } - public int getWidth() { return width; } - public int getHeight() { return height; } - public ByteBuffer getData() { return data; } - public boolean isCompressed() { return isCompressed; } - public int getCompressionFormat() { - if (!isCompressed()) - throw new RuntimeException("Should not call unless compressed"); - return compressionFormat; - } - } - - private FileInputStream fis; - private FileChannel chan; - private ByteBuffer buf; - private Header header; - - // - // Selected bits in header flags - // - - public static final int DDSD_CAPS = 0x00000001; // Capacities are valid - public static final int DDSD_HEIGHT = 0x00000002; // Height is valid - public static final int DDSD_WIDTH = 0x00000004; // Width is valid - public static final int DDSD_PITCH = 0x00000008; // Pitch is valid - public static final int DDSD_BACKBUFFERCOUNT = 0x00000020; // Back buffer count is valid - public static final int DDSD_ZBUFFERBITDEPTH = 0x00000040; // Z-buffer bit depth is valid (shouldn't be used in DDSURFACEDESC2) - public static final int DDSD_ALPHABITDEPTH = 0x00000080; // Alpha bit depth is valid - public static final int DDSD_LPSURFACE = 0x00000800; // lpSurface is valid - public static final int DDSD_PIXELFORMAT = 0x00001000; // ddpfPixelFormat is valid - public static final int DDSD_MIPMAPCOUNT = 0x00020000; // Mip map count is valid - public static final int DDSD_LINEARSIZE = 0x00080000; // dwLinearSize is valid - public static final int DDSD_DEPTH = 0x00800000; // dwDepth is valid - - public static final int DDPF_ALPHAPIXELS = 0x00000001; // Alpha channel is present - public static final int DDPF_ALPHA = 0x00000002; // Only contains alpha information - public static final int DDPF_FOURCC = 0x00000004; // FourCC code is valid - public static final int DDPF_PALETTEINDEXED4 = 0x00000008; // Surface is 4-bit color indexed - public static final int DDPF_PALETTEINDEXEDTO8 = 0x00000010; // Surface is indexed into a palette which stores indices - // into the destination surface's 8-bit palette - public static final int DDPF_PALETTEINDEXED8 = 0x00000020; // Surface is 8-bit color indexed - public static final int DDPF_RGB = 0x00000040; // RGB data is present - public static final int DDPF_COMPRESSED = 0x00000080; // Surface will accept pixel data in the format specified - // and compress it during the write - public static final int DDPF_RGBTOYUV = 0x00000100; // Surface will accept RGB data and translate it during - // the write to YUV data. The format of the data to be written - // will be contained in the pixel format structure. The DDPF_RGB - // flag will be set. - public static final int DDPF_YUV = 0x00000200; // Pixel format is YUV - YUV data in pixel format struct is valid - public static final int DDPF_ZBUFFER = 0x00000400; // Pixel format is a z buffer only surface - public static final int DDPF_PALETTEINDEXED1 = 0x00000800; // Surface is 1-bit color indexed - public static final int DDPF_PALETTEINDEXED2 = 0x00001000; // Surface is 2-bit color indexed - public static final int DDPF_ZPIXELS = 0x00002000; // Surface contains Z information in the pixels - - // Selected bits in DDS capabilities flags - public static final int DDSCAPS_TEXTURE = 0x00001000; // Can be used as a texture - public static final int DDSCAPS_MIPMAP = 0x00400000; // Is one level of a mip-map - public static final int DDSCAPS_COMPLEX = 0x00000008; // Complex surface structure, such as a cube map - - // Selected bits in DDS extended capabilities flags - public static final int DDSCAPS2_CUBEMAP = 0x00000200; - public static final int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400; - public static final int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800; - public static final int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000; - public static final int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000; - public static final int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000; - public static final int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000; - - // Known pixel formats - public static final int D3DFMT_UNKNOWN = 0; - public static final int D3DFMT_R8G8B8 = 20; - public static final int D3DFMT_A8R8G8B8 = 21; - public static final int D3DFMT_X8R8G8B8 = 22; - // The following are also valid FourCC codes - public static final int D3DFMT_DXT1 = 0x31545844; - public static final int D3DFMT_DXT2 = 0x32545844; - public static final int D3DFMT_DXT3 = 0x33545844; - public static final int D3DFMT_DXT4 = 0x34545844; - public static final int D3DFMT_DXT5 = 0x35545844; - - /** Reads a DirectDraw surface from the specified file name, - returning the resulting DDSImage. - - @param filename File name - @return DDS image object - @throws java.io.IOException if an I/O exception occurred - */ - public static DDSImage read(String filename) throws IOException { - return read(new File(filename)); - } + /** Simple class describing images and data; does not encapsulate + image format information. User is responsible for transmitting + that information in another way. */ + + public static class ImageInfo { + private ByteBuffer data; + private int width; + private int height; + private boolean isCompressed; + private int compressionFormat; + + public ImageInfo(ByteBuffer data, int width, int height, boolean compressed, int compressionFormat) { + this.data = data; this.width = width; this.height = height; + this.isCompressed = compressed; this.compressionFormat = compressionFormat; + } + public int getWidth() { return width; } + public int getHeight() { return height; } + public ByteBuffer getData() { return data; } + public boolean isCompressed() { return isCompressed; } + public int getCompressionFormat() { + if (!isCompressed()) + throw new RuntimeException("Should not call unless compressed"); + return compressionFormat; + } + } + + private FileInputStream fis; + private FileChannel chan; + private ByteBuffer buf; + private Header header; + + // + // Selected bits in header flags + // + + public static final int DDSD_CAPS = 0x00000001; // Capacities are valid + public static final int DDSD_HEIGHT = 0x00000002; // Height is valid + public static final int DDSD_WIDTH = 0x00000004; // Width is valid + public static final int DDSD_PITCH = 0x00000008; // Pitch is valid + public static final int DDSD_BACKBUFFERCOUNT = 0x00000020; // Back buffer count is valid + public static final int DDSD_ZBUFFERBITDEPTH = 0x00000040; // Z-buffer bit depth is valid (shouldn't be used in DDSURFACEDESC2) + public static final int DDSD_ALPHABITDEPTH = 0x00000080; // Alpha bit depth is valid + public static final int DDSD_LPSURFACE = 0x00000800; // lpSurface is valid + public static final int DDSD_PIXELFORMAT = 0x00001000; // ddpfPixelFormat is valid + public static final int DDSD_MIPMAPCOUNT = 0x00020000; // Mip map count is valid + public static final int DDSD_LINEARSIZE = 0x00080000; // dwLinearSize is valid + public static final int DDSD_DEPTH = 0x00800000; // dwDepth is valid + + public static final int DDPF_ALPHAPIXELS = 0x00000001; // Alpha channel is present + public static final int DDPF_ALPHA = 0x00000002; // Only contains alpha information + public static final int DDPF_FOURCC = 0x00000004; // FourCC code is valid + public static final int DDPF_PALETTEINDEXED4 = 0x00000008; // Surface is 4-bit color indexed + public static final int DDPF_PALETTEINDEXEDTO8 = 0x00000010; // Surface is indexed into a palette which stores indices + // into the destination surface's 8-bit palette + public static final int DDPF_PALETTEINDEXED8 = 0x00000020; // Surface is 8-bit color indexed + public static final int DDPF_RGB = 0x00000040; // RGB data is present + public static final int DDPF_COMPRESSED = 0x00000080; // Surface will accept pixel data in the format specified + // and compress it during the write + public static final int DDPF_RGBTOYUV = 0x00000100; // Surface will accept RGB data and translate it during + // the write to YUV data. The format of the data to be written + // will be contained in the pixel format structure. The DDPF_RGB + // flag will be set. + public static final int DDPF_YUV = 0x00000200; // Pixel format is YUV - YUV data in pixel format struct is valid + public static final int DDPF_ZBUFFER = 0x00000400; // Pixel format is a z buffer only surface + public static final int DDPF_PALETTEINDEXED1 = 0x00000800; // Surface is 1-bit color indexed + public static final int DDPF_PALETTEINDEXED2 = 0x00001000; // Surface is 2-bit color indexed + public static final int DDPF_ZPIXELS = 0x00002000; // Surface contains Z information in the pixels + + // Selected bits in DDS capabilities flags + public static final int DDSCAPS_TEXTURE = 0x00001000; // Can be used as a texture + public static final int DDSCAPS_MIPMAP = 0x00400000; // Is one level of a mip-map + public static final int DDSCAPS_COMPLEX = 0x00000008; // Complex surface structure, such as a cube map + + // Selected bits in DDS extended capabilities flags + public static final int DDSCAPS2_CUBEMAP = 0x00000200; + public static final int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400; + public static final int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800; + public static final int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000; + public static final int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000; + public static final int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000; + public static final int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000; + + // Known pixel formats + public static final int D3DFMT_UNKNOWN = 0; + public static final int D3DFMT_R8G8B8 = 20; + public static final int D3DFMT_A8R8G8B8 = 21; + public static final int D3DFMT_X8R8G8B8 = 22; + // The following are also valid FourCC codes + public static final int D3DFMT_DXT1 = 0x31545844; + public static final int D3DFMT_DXT2 = 0x32545844; + public static final int D3DFMT_DXT3 = 0x33545844; + public static final int D3DFMT_DXT4 = 0x34545844; + public static final int D3DFMT_DXT5 = 0x35545844; + + /** Reads a DirectDraw surface from the specified file name, + returning the resulting DDSImage. + + @param filename File name + @return DDS image object + @throws java.io.IOException if an I/O exception occurred + */ + public static DDSImage read(String filename) throws IOException { + return read(new File(filename)); + } - /** Reads a DirectDraw surface from the specified file, returning - the resulting DDSImage. - - @param file File object - @return DDS image object - @throws java.io.IOException if an I/O exception occurred - */ - public static DDSImage read(File file) throws IOException { - DDSImage image = new DDSImage(); - image.readFromFile(file); - return image; - } - - /** Reads a DirectDraw surface from the specified ByteBuffer, returning - the resulting DDSImage. - - @param buf Input data - @return DDS image object - @throws java.io.IOException if an I/O exception occurred - */ - public static DDSImage read(ByteBuffer buf) throws IOException { - DDSImage image = new DDSImage(); - image.readFromBuffer(buf); - return image; - } - - /** Closes open files and resources associated with the open - DDSImage. No other methods may be called on this object once - this is called. */ - public void close() { - try { - if (chan != null) { - chan.close(); - chan = null; - } - if (fis != null) { - fis.close(); - fis = null; - } - buf = null; - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Creates a new DDSImage from data supplied by the user. The - * resulting DDSImage can be written to disk using the write() - * method. - * - * @param d3dFormat the D3DFMT_ constant describing the data; it is - * assumed that it is packed tightly - * @param width the width in pixels of the topmost mipmap image - * @param height the height in pixels of the topmost mipmap image - * @param mipmapData the data for each mipmap level of the resulting - * DDSImage; either only one mipmap level should - * be specified, or they all must be - * @throws IllegalArgumentException if the data does not match the - * specified arguments - * @return DDS image object - */ - public static DDSImage createFromData(int d3dFormat, - int width, - int height, - ByteBuffer[] mipmapData) throws IllegalArgumentException { - DDSImage image = new DDSImage(); - image.initFromData(d3dFormat, width, height, mipmapData); - return image; - } - - /** Determines from the magic number whether the given InputStream - points to a DDS image. The given InputStream must return true - from markSupported() and support a minimum of four bytes of - read-ahead. - - @param in Stream to check - @return true if input stream is DDS image or false otherwise - @throws java.io.IOException if an I/O exception occurred - */ - public static boolean isDDSImage(InputStream in) throws IOException { - if (!(in instanceof BufferedInputStream)) { - in = new BufferedInputStream(in); - } - if (!in.markSupported()) { - throw new IOException("Can not test non-destructively whether given InputStream is a DDS image"); - } - in.mark(4); - int magic = 0; - for (int i = 0; i < 4; i++) { - int tmp = in.read(); - if (tmp < 0) { + /** Reads a DirectDraw surface from the specified file, returning + the resulting DDSImage. + + @param file File object + @return DDS image object + @throws java.io.IOException if an I/O exception occurred + */ + public static DDSImage read(File file) throws IOException { + DDSImage image = new DDSImage(); + image.readFromFile(file); + return image; + } + + /** Reads a DirectDraw surface from the specified ByteBuffer, returning + the resulting DDSImage. + + @param buf Input data + @return DDS image object + @throws java.io.IOException if an I/O exception occurred + */ + public static DDSImage read(ByteBuffer buf) throws IOException { + DDSImage image = new DDSImage(); + image.readFromBuffer(buf); + return image; + } + + /** Closes open files and resources associated with the open + DDSImage. No other methods may be called on this object once + this is called. */ + public void close() { + try { + if (chan != null) { + chan.close(); + chan = null; + } + if (fis != null) { + fis.close(); + fis = null; + } + buf = null; + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Creates a new DDSImage from data supplied by the user. The + * resulting DDSImage can be written to disk using the write() + * method. + * + * @param d3dFormat the D3DFMT_ constant describing the data; it is + * assumed that it is packed tightly + * @param width the width in pixels of the topmost mipmap image + * @param height the height in pixels of the topmost mipmap image + * @param mipmapData the data for each mipmap level of the resulting + * DDSImage; either only one mipmap level should + * be specified, or they all must be + * @throws IllegalArgumentException if the data does not match the + * specified arguments + * @return DDS image object + */ + public static DDSImage createFromData(int d3dFormat, + int width, + int height, + ByteBuffer[] mipmapData) throws IllegalArgumentException { + DDSImage image = new DDSImage(); + image.initFromData(d3dFormat, width, height, mipmapData); + return image; + } + + /** Determines from the magic number whether the given InputStream + points to a DDS image. The given InputStream must return true + from markSupported() and support a minimum of four bytes of + read-ahead. + + @param in Stream to check + @return true if input stream is DDS image or false otherwise + @throws java.io.IOException if an I/O exception occurred + */ + public static boolean isDDSImage(InputStream in) throws IOException { + if (!(in instanceof BufferedInputStream)) { + in = new BufferedInputStream(in); + } + if (!in.markSupported()) { + throw new IOException("Can not test non-destructively whether given InputStream is a DDS image"); + } + in.mark(4); + int magic = 0; + for (int i = 0; i < 4; i++) { + int tmp = in.read(); + if (tmp < 0) { + in.reset(); + return false; + } + magic = ((magic >>> 8) | (tmp << 24)); + } in.reset(); - return false; - } - magic = ((magic >>> 8) | (tmp << 24)); - } - in.reset(); - return (magic == MAGIC); - } - - /** - * Writes this DDSImage to the specified file name. - * @param filename File name to write to - * @throws java.io.IOException if an I/O exception occurred - */ - public void write(String filename) throws IOException { - write(new File(filename)); - } - - /** - * Writes this DDSImage to the specified file name. - * @param file File object to write to - * @throws java.io.IOException if an I/O exception occurred - */ - public void write(File file) throws IOException { - FileOutputStream stream = new FileOutputStream(file); - FileChannel chan = stream.getChannel(); - // Create ByteBuffer for header in case the start of our - // ByteBuffer isn't actually memory-mapped - ByteBuffer hdr = ByteBuffer.allocate(Header.writtenSize()); - hdr.order(ByteOrder.LITTLE_ENDIAN); - header.write(hdr); - hdr.rewind(); - chan.write(hdr); - buf.position(Header.writtenSize()); - chan.write(buf); - chan.force(true); - chan.close(); - stream.close(); - } - - /** Test for presence/absence of surface description flags (DDSD_*) - * @param flag DDSD_* flags set to test - * @return true if flag present or false otherwise - */ - public boolean isSurfaceDescFlagSet(int flag) { - return ((header.flags & flag) != 0); - } - - /** Test for presence/absence of pixel format flags (DDPF_*) */ - public boolean isPixelFormatFlagSet(int flag) { - return ((header.pfFlags & flag) != 0); - } - - /** Gets the pixel format of this texture (D3DFMT_*) based on some - heuristics. Returns D3DFMT_UNKNOWN if could not recognize the - pixel format. */ - public int getPixelFormat() { - if (isCompressed()) { - return getCompressionFormat(); - } else if (isPixelFormatFlagSet(DDPF_RGB)) { - if (isPixelFormatFlagSet(DDPF_ALPHAPIXELS)) { - if (getDepth() == 32 && - header.pfRBitMask == 0x00FF0000 && - header.pfGBitMask == 0x0000FF00 && - header.pfBBitMask == 0x000000FF && - header.pfABitMask == 0xFF000000) { - return D3DFMT_A8R8G8B8; - } - } else { - if (getDepth() == 24 && - header.pfRBitMask == 0x00FF0000 && - header.pfGBitMask == 0x0000FF00 && - header.pfBBitMask == 0x000000FF) { - return D3DFMT_R8G8B8; - } else if (getDepth() == 32 && - header.pfRBitMask == 0x00FF0000 && - header.pfGBitMask == 0x0000FF00 && - header.pfBBitMask == 0x000000FF) { - return D3DFMT_X8R8G8B8; - } - } - } - - return D3DFMT_UNKNOWN; - } - - /** - * Indicates whether this texture is cubemap - * @return true if cubemap or false otherwise - */ - public boolean isCubemap() { - return ((header.ddsCaps1 & DDSCAPS_COMPLEX) != 0) && ((header.ddsCaps2 & DDSCAPS2_CUBEMAP) != 0); - } - - /** - * Indicates whethe this cubemap side present - * @param side Side to test - * @return true if side present or false otherwise - */ - public boolean isCubemapSidePresent(int side) { - return isCubemap() && (header.ddsCaps2 & side) != 0; - } - - /** Indicates whether this texture is compressed. */ - public boolean isCompressed() { - return (isPixelFormatFlagSet(DDPF_FOURCC)); - } - - /** If this surface is compressed, returns the kind of compression - used (DXT1..DXT5). */ - public int getCompressionFormat() { - return header.pfFourCC; - } - - /** Width of the texture (or the top-most mipmap if mipmaps are - present) */ - public int getWidth() { - return header.width; - } - - /** Height of the texture (or the top-most mipmap if mipmaps are - present) */ - public int getHeight() { - return header.height; - } - - /** Total number of bits per pixel. Only valid if DDPF_RGB is - present. For A8R8G8B8, would be 32. */ - public int getDepth() { - return header.pfRGBBitCount; - } - - /** Number of mip maps in the texture */ - public int getNumMipMaps() { - if (!isSurfaceDescFlagSet(DDSD_MIPMAPCOUNT)) { - return 0; - } - return header.mipMapCountOrAux; - } - - /** Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1) - * @param map Mipmap index - * @return Image object - */ - public ImageInfo getMipMap(int map) { - return getMipMap( 0, map ); - } - - /** - * Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1) - * @param side Cubemap side or 0 for 2D texture - * @param map Mipmap index - * @return Image object - */ - public ImageInfo getMipMap(int side, int map) { - if (!isCubemap() && (side != 0)) { - throw new RuntimeException( "Illegal side for 2D texture: " + side ); - } - if (isCubemap() && !isCubemapSidePresent(side)) { - throw new RuntimeException( "Illegal side, side not present: " + side ); - } - if (getNumMipMaps() > 0 && - ((map < 0) || (map >= getNumMipMaps()))) { - throw new RuntimeException("Illegal mipmap number " + map + " (0.." + (getNumMipMaps() - 1) + ")"); - } - - // Figure out how far to seek - int seek = Header.writtenSize(); - if (isCubemap()) { - seek += sideShiftInBytes(side); - } - for (int i = 0; i < map; i++) { - seek += mipMapSizeInBytes(i); - } - buf.limit(seek + mipMapSizeInBytes(map)); - buf.position(seek); - ByteBuffer next = buf.slice(); - buf.position(0); - buf.limit(buf.capacity()); - return new ImageInfo(next, mipMapWidth(map), mipMapHeight(map), isCompressed(), getCompressionFormat()); - } - - /** Returns an array of ImageInfos corresponding to all mipmap - levels of this DDS file. - @return Mipmap image objects set - */ - public ImageInfo[] getAllMipMaps() { - return getAllMipMaps(0); - } - - /** - * Returns an array of ImageInfos corresponding to all mipmap - * levels of this DDS file. - * @param side Cubemap side or 0 for 2D texture - * @return Mipmap image objects set - */ - public ImageInfo[] getAllMipMaps( int side ) { - int numLevels = getNumMipMaps(); - if (numLevels == 0) { - numLevels = 1; - } - ImageInfo[] result = new ImageInfo[numLevels]; - for (int i = 0; i < numLevels; i++) { - result[i] = getMipMap(side, i); - } - return result; - } - - /** Converts e.g. DXT1 compression format constant (see {@link - #getCompressionFormat}) into "DXT1". - @param compressionFormat Compression format constant - @return String format code - */ - public static String getCompressionFormatName(int compressionFormat) { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < 4; i++) { - char c = (char) (compressionFormat & 0xFF); - buf.append(c); - compressionFormat = compressionFormat >> 8; - } - return buf.toString(); - } - - /** Allocates a temporary, empty ByteBuffer suitable for use in a - call to glCompressedTexImage2D. This is used by the Texture - class to expand non-power-of-two DDS compressed textures to - power-of-two sizes on hardware not supporting OpenGL 2.0 and the - NPOT texture extension. The specified OpenGL internal format - must be one of GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, or - GL_COMPRESSED_RGBA_S3TC_DXT5_EXT. - */ - public static ByteBuffer allocateBlankBuffer(int width, - int height, - int openGLInternalFormat) { - int size = width * height; - switch (openGLInternalFormat) { - case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - size /= 2; - break; - - case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - break; - - default: - throw new IllegalArgumentException("Illegal OpenGL texture internal format " + - openGLInternalFormat); - } - if (size == 0) - size = 1; - return BufferUtil.newByteBuffer(size); - } - - public void debugPrint() { - PrintStream tty = System.err; - tty.println("Compressed texture: " + isCompressed()); - if (isCompressed()) { - int fmt = getCompressionFormat(); - String name = getCompressionFormatName(fmt); - tty.println("Compression format: 0x" + Integer.toHexString(fmt) + " (" + name + ")"); - } - tty.println("Width: " + header.width + " Height: " + header.height); - tty.println("header.pitchOrLinearSize: " + header.pitchOrLinearSize); - tty.println("header.pfRBitMask: 0x" + Integer.toHexString(header.pfRBitMask)); - tty.println("header.pfGBitMask: 0x" + Integer.toHexString(header.pfGBitMask)); - tty.println("header.pfBBitMask: 0x" + Integer.toHexString(header.pfBBitMask)); - tty.println("SurfaceDesc flags:"); - boolean recognizedAny = false; - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_CAPS, "DDSD_CAPS"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_HEIGHT, "DDSD_HEIGHT"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_WIDTH, "DDSD_WIDTH"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PITCH, "DDSD_PITCH"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_BACKBUFFERCOUNT, "DDSD_BACKBUFFERCOUNT"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ZBUFFERBITDEPTH, "DDSD_ZBUFFERBITDEPTH"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ALPHABITDEPTH, "DDSD_ALPHABITDEPTH"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LPSURFACE, "DDSD_LPSURFACE"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PIXELFORMAT, "DDSD_PIXELFORMAT"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_MIPMAPCOUNT, "DDSD_MIPMAPCOUNT"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LINEARSIZE, "DDSD_LINEARSIZE"); - recognizedAny |= printIfRecognized(tty, header.flags, DDSD_DEPTH, "DDSD_DEPTH"); - if (!recognizedAny) { - tty.println("(none)"); - } - tty.println("Raw SurfaceDesc flags: 0x" + Integer.toHexString(header.flags)); - tty.println("Pixel format flags:"); - recognizedAny = false; - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHAPIXELS, "DDPF_ALPHAPIXELS"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHA, "DDPF_ALPHA"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_FOURCC, "DDPF_FOURCC"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED4, "DDPF_PALETTEINDEXED4"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXEDTO8, "DDPF_PALETTEINDEXEDTO8"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED8, "DDPF_PALETTEINDEXED8"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGB, "DDPF_RGB"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_COMPRESSED, "DDPF_COMPRESSED"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGBTOYUV, "DDPF_RGBTOYUV"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_YUV, "DDPF_YUV"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZBUFFER, "DDPF_ZBUFFER"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED1, "DDPF_PALETTEINDEXED1"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED2, "DDPF_PALETTEINDEXED2"); - recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZPIXELS, "DDPF_ZPIXELS"); - if (!recognizedAny) { - tty.println("(none)"); - } - tty.println("Raw pixel format flags: 0x" + Integer.toHexString(header.pfFlags)); - tty.println("Depth: " + getDepth()); - tty.println("Number of mip maps: " + getNumMipMaps()); - int fmt = getPixelFormat(); - tty.print("Pixel format: "); - switch (fmt) { - case D3DFMT_R8G8B8: tty.println("D3DFMT_R8G8B8"); break; - case D3DFMT_A8R8G8B8: tty.println("D3DFMT_A8R8G8B8"); break; - case D3DFMT_X8R8G8B8: tty.println("D3DFMT_X8R8G8B8"); break; - case D3DFMT_DXT1: tty.println("D3DFMT_DXT1"); break; - case D3DFMT_DXT2: tty.println("D3DFMT_DXT2"); break; - case D3DFMT_DXT3: tty.println("D3DFMT_DXT3"); break; - case D3DFMT_DXT4: tty.println("D3DFMT_DXT4"); break; - case D3DFMT_DXT5: tty.println("D3DFMT_DXT5"); break; - case D3DFMT_UNKNOWN: tty.println("D3DFMT_UNKNOWN"); break; - default: tty.println("(unknown pixel format " + fmt + ")"); break; - } - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private static final int MAGIC = 0x20534444; - - static class Header { - int size; // size of the DDSURFACEDESC structure - int flags; // determines what fields are valid - int height; // height of surface to be created - int width; // width of input surface - int pitchOrLinearSize; - int backBufferCountOrDepth; - int mipMapCountOrAux; // number of mip-map levels requested (in this context) - int alphaBitDepth; // depth of alpha buffer requested - int reserved1; // reserved - int surface; // pointer to the associated surface memory - // NOTE: following two entries are from DDCOLORKEY data structure - // Are overlaid with color for empty cubemap faces (unused in this reader) - int colorSpaceLowValue; - int colorSpaceHighValue; - int destBltColorSpaceLowValue; - int destBltColorSpaceHighValue; - int srcOverlayColorSpaceLowValue; - int srcOverlayColorSpaceHighValue; - int srcBltColorSpaceLowValue; - int srcBltColorSpaceHighValue; - // NOTE: following entries are from DDPIXELFORMAT data structure - // Are overlaid with flexible vertex format description of vertex - // buffers (unused in this reader) - int pfSize; // size of DDPIXELFORMAT structure - int pfFlags; // pixel format flags - int pfFourCC; // (FOURCC code) - // Following five entries have multiple interpretations, not just - // RGBA (but that's all we support right now) - int pfRGBBitCount; // how many bits per pixel - int pfRBitMask; // mask for red bits - int pfGBitMask; // mask for green bits - int pfBBitMask; // mask for blue bits - int pfABitMask; // mask for alpha channel - int ddsCaps1; // Texture and mip-map flags - int ddsCaps2; // Advanced capabilities including cubemap support - int ddsCapsReserved1; - int ddsCapsReserved2; - int textureStage; // stage in multitexture cascade - - void read(ByteBuffer buf) throws IOException { - int magic = buf.getInt(); - if (magic != MAGIC) { - throw new IOException("Incorrect magic number 0x" + - Integer.toHexString(magic) + - " (expected " + MAGIC + ")"); - } - - size = buf.getInt(); - flags = buf.getInt(); - height = buf.getInt(); - width = buf.getInt(); - pitchOrLinearSize = buf.getInt(); - backBufferCountOrDepth = buf.getInt(); - mipMapCountOrAux = buf.getInt(); - alphaBitDepth = buf.getInt(); - reserved1 = buf.getInt(); - surface = buf.getInt(); - colorSpaceLowValue = buf.getInt(); - colorSpaceHighValue = buf.getInt(); - destBltColorSpaceLowValue = buf.getInt(); - destBltColorSpaceHighValue = buf.getInt(); - srcOverlayColorSpaceLowValue = buf.getInt(); - srcOverlayColorSpaceHighValue = buf.getInt(); - srcBltColorSpaceLowValue = buf.getInt(); - srcBltColorSpaceHighValue = buf.getInt(); - pfSize = buf.getInt(); - pfFlags = buf.getInt(); - pfFourCC = buf.getInt(); - pfRGBBitCount = buf.getInt(); - pfRBitMask = buf.getInt(); - pfGBitMask = buf.getInt(); - pfBBitMask = buf.getInt(); - pfABitMask = buf.getInt(); - ddsCaps1 = buf.getInt(); - ddsCaps2 = buf.getInt(); - ddsCapsReserved1 = buf.getInt(); - ddsCapsReserved2 = buf.getInt(); - textureStage = buf.getInt(); - } - - // buf must be in little-endian byte order - void write(ByteBuffer buf) { - buf.putInt(MAGIC); - buf.putInt(size); - buf.putInt(flags); - buf.putInt(height); - buf.putInt(width); - buf.putInt(pitchOrLinearSize); - buf.putInt(backBufferCountOrDepth); - buf.putInt(mipMapCountOrAux); - buf.putInt(alphaBitDepth); - buf.putInt(reserved1); - buf.putInt(surface); - buf.putInt(colorSpaceLowValue); - buf.putInt(colorSpaceHighValue); - buf.putInt(destBltColorSpaceLowValue); - buf.putInt(destBltColorSpaceHighValue); - buf.putInt(srcOverlayColorSpaceLowValue); - buf.putInt(srcOverlayColorSpaceHighValue); - buf.putInt(srcBltColorSpaceLowValue); - buf.putInt(srcBltColorSpaceHighValue); - buf.putInt(pfSize); - buf.putInt(pfFlags); - buf.putInt(pfFourCC); - buf.putInt(pfRGBBitCount); - buf.putInt(pfRBitMask); - buf.putInt(pfGBitMask); - buf.putInt(pfBBitMask); - buf.putInt(pfABitMask); - buf.putInt(ddsCaps1); - buf.putInt(ddsCaps2); - buf.putInt(ddsCapsReserved1); - buf.putInt(ddsCapsReserved2); - buf.putInt(textureStage); - } - - private static int size() { - return 124; - } - - private static int pfSize() { - return 32; - } - - private static int writtenSize() { - return 128; - } - } - - private DDSImage() { - } - - private void readFromFile(File file) throws IOException { - fis = new FileInputStream(file); - chan = fis.getChannel(); - ByteBuffer buf = chan.map(FileChannel.MapMode.READ_ONLY, - 0, (int) file.length()); - readFromBuffer(buf); - } - - private void readFromBuffer(ByteBuffer buf) throws IOException { - this.buf = buf; - buf.order(ByteOrder.LITTLE_ENDIAN); - header = new Header(); - header.read(buf); - fixupHeader(); - } - - private void initFromData(int d3dFormat, - int width, - int height, - ByteBuffer[] mipmapData) throws IllegalArgumentException { - // Check size of mipmap data compared against format, width and - // height - int topmostMipmapSize = width * height; - int pitchOrLinearSize = width; - boolean isCompressed = false; - switch (d3dFormat) { - case D3DFMT_R8G8B8: topmostMipmapSize *= 3; pitchOrLinearSize *= 3; break; - case D3DFMT_A8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break; - case D3DFMT_X8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break; - case D3DFMT_DXT1: - case D3DFMT_DXT2: - case D3DFMT_DXT3: - case D3DFMT_DXT4: - case D3DFMT_DXT5: - topmostMipmapSize = computeCompressedBlockSize(width, height, 1, d3dFormat); - pitchOrLinearSize = topmostMipmapSize; - isCompressed = true; - break; - default: - throw new IllegalArgumentException("d3dFormat must be one of the known formats"); + return (magic == MAGIC); + } + + /** + * Writes this DDSImage to the specified file name. + * @param filename File name to write to + * @throws java.io.IOException if an I/O exception occurred + */ + public void write(String filename) throws IOException { + write(new File(filename)); + } + + /** + * Writes this DDSImage to the specified file name. + * @param file File object to write to + * @throws java.io.IOException if an I/O exception occurred + */ + public void write(File file) throws IOException { + FileOutputStream stream = new FileOutputStream(file); + FileChannel chan = stream.getChannel(); + // Create ByteBuffer for header in case the start of our + // ByteBuffer isn't actually memory-mapped + ByteBuffer hdr = ByteBuffer.allocate(Header.writtenSize()); + hdr.order(ByteOrder.LITTLE_ENDIAN); + header.write(hdr); + hdr.rewind(); + chan.write(hdr); + buf.position(Header.writtenSize()); + chan.write(buf); + chan.force(true); + chan.close(); + stream.close(); + } + + /** Test for presence/absence of surface description flags (DDSD_*) + * @param flag DDSD_* flags set to test + * @return true if flag present or false otherwise + */ + public boolean isSurfaceDescFlagSet(int flag) { + return ((header.flags & flag) != 0); + } + + /** Test for presence/absence of pixel format flags (DDPF_*) */ + public boolean isPixelFormatFlagSet(int flag) { + return ((header.pfFlags & flag) != 0); + } + + /** Gets the pixel format of this texture (D3DFMT_*) based on some + heuristics. Returns D3DFMT_UNKNOWN if could not recognize the + pixel format. */ + public int getPixelFormat() { + if (isCompressed()) { + return getCompressionFormat(); + } else if (isPixelFormatFlagSet(DDPF_RGB)) { + if (isPixelFormatFlagSet(DDPF_ALPHAPIXELS)) { + if (getDepth() == 32 && + header.pfRBitMask == 0x00FF0000 && + header.pfGBitMask == 0x0000FF00 && + header.pfBBitMask == 0x000000FF && + header.pfABitMask == 0xFF000000) { + return D3DFMT_A8R8G8B8; + } + } else { + if (getDepth() == 24 && + header.pfRBitMask == 0x00FF0000 && + header.pfGBitMask == 0x0000FF00 && + header.pfBBitMask == 0x000000FF) { + return D3DFMT_R8G8B8; + } else if (getDepth() == 32 && + header.pfRBitMask == 0x00FF0000 && + header.pfGBitMask == 0x0000FF00 && + header.pfBBitMask == 0x000000FF) { + return D3DFMT_X8R8G8B8; + } + } + } + + return D3DFMT_UNKNOWN; + } + + /** + * Indicates whether this texture is cubemap + * @return true if cubemap or false otherwise + */ + public boolean isCubemap() { + return ((header.ddsCaps1 & DDSCAPS_COMPLEX) != 0) && ((header.ddsCaps2 & DDSCAPS2_CUBEMAP) != 0); + } + + /** + * Indicates whethe this cubemap side present + * @param side Side to test + * @return true if side present or false otherwise + */ + public boolean isCubemapSidePresent(int side) { + return isCubemap() && (header.ddsCaps2 & side) != 0; + } + + /** Indicates whether this texture is compressed. */ + public boolean isCompressed() { + return (isPixelFormatFlagSet(DDPF_FOURCC)); + } + + /** If this surface is compressed, returns the kind of compression + used (DXT1..DXT5). */ + public int getCompressionFormat() { + return header.pfFourCC; } + + /** Width of the texture (or the top-most mipmap if mipmaps are + present) */ + public int getWidth() { + return header.width; + } + + /** Height of the texture (or the top-most mipmap if mipmaps are + present) */ + public int getHeight() { + return header.height; + } + + /** Total number of bits per pixel. Only valid if DDPF_RGB is + present. For A8R8G8B8, would be 32. */ + public int getDepth() { + return header.pfRGBBitCount; + } + + /** Number of mip maps in the texture */ + public int getNumMipMaps() { + if (!isSurfaceDescFlagSet(DDSD_MIPMAPCOUNT)) { + return 0; + } + return header.mipMapCountOrAux; + } + + /** Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1) + * @param map Mipmap index + * @return Image object + */ + public ImageInfo getMipMap(int map) { + return getMipMap( 0, map ); + } + + /** + * Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1) + * @param side Cubemap side or 0 for 2D texture + * @param map Mipmap index + * @return Image object + */ + public ImageInfo getMipMap(int side, int map) { + if (!isCubemap() && (side != 0)) { + throw new RuntimeException( "Illegal side for 2D texture: " + side ); + } + if (isCubemap() && !isCubemapSidePresent(side)) { + throw new RuntimeException( "Illegal side, side not present: " + side ); + } + if (getNumMipMaps() > 0 && + ((map < 0) || (map >= getNumMipMaps()))) { + throw new RuntimeException("Illegal mipmap number " + map + " (0.." + (getNumMipMaps() - 1) + ")"); + } + + // Figure out how far to seek + int seek = Header.writtenSize(); + if (isCubemap()) { + seek += sideShiftInBytes(side); + } + for (int i = 0; i < map; i++) { + seek += mipMapSizeInBytes(i); + } + buf.limit(seek + mipMapSizeInBytes(map)); + buf.position(seek); + ByteBuffer next = buf.slice(); + buf.position(0); + buf.limit(buf.capacity()); + return new ImageInfo(next, mipMapWidth(map), mipMapHeight(map), isCompressed(), getCompressionFormat()); + } + + /** Returns an array of ImageInfos corresponding to all mipmap + levels of this DDS file. + @return Mipmap image objects set + */ + public ImageInfo[] getAllMipMaps() { + return getAllMipMaps(0); + } + + /** + * Returns an array of ImageInfos corresponding to all mipmap + * levels of this DDS file. + * @param side Cubemap side or 0 for 2D texture + * @return Mipmap image objects set + */ + public ImageInfo[] getAllMipMaps( int side ) { + int numLevels = getNumMipMaps(); + if (numLevels == 0) { + numLevels = 1; + } + ImageInfo[] result = new ImageInfo[numLevels]; + for (int i = 0; i < numLevels; i++) { + result[i] = getMipMap(side, i); + } + return result; + } + + /** Converts e.g. DXT1 compression format constant (see {@link + #getCompressionFormat}) into "DXT1". + @param compressionFormat Compression format constant + @return String format code + */ + public static String getCompressionFormatName(int compressionFormat) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < 4; i++) { + char c = (char) (compressionFormat & 0xFF); + buf.append(c); + compressionFormat = compressionFormat >> 8; + } + return buf.toString(); + } + + /** Allocates a temporary, empty ByteBuffer suitable for use in a + call to glCompressedTexImage2D. This is used by the Texture + class to expand non-power-of-two DDS compressed textures to + power-of-two sizes on hardware not supporting OpenGL 2.0 and the + NPOT texture extension. The specified OpenGL internal format + must be one of GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, or + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT. + */ + public static ByteBuffer allocateBlankBuffer(int width, + int height, + int openGLInternalFormat) { + int size = width * height; + switch (openGLInternalFormat) { + case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + size /= 2; + break; + + case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + break; + + default: + throw new IllegalArgumentException("Illegal OpenGL texture internal format " + + openGLInternalFormat); + } + if (size == 0) + size = 1; + return BufferUtil.newByteBuffer(size); + } + + public void debugPrint() { + PrintStream tty = System.err; + tty.println("Compressed texture: " + isCompressed()); + if (isCompressed()) { + int fmt = getCompressionFormat(); + String name = getCompressionFormatName(fmt); + tty.println("Compression format: 0x" + Integer.toHexString(fmt) + " (" + name + ")"); + } + tty.println("Width: " + header.width + " Height: " + header.height); + tty.println("header.pitchOrLinearSize: " + header.pitchOrLinearSize); + tty.println("header.pfRBitMask: 0x" + Integer.toHexString(header.pfRBitMask)); + tty.println("header.pfGBitMask: 0x" + Integer.toHexString(header.pfGBitMask)); + tty.println("header.pfBBitMask: 0x" + Integer.toHexString(header.pfBBitMask)); + tty.println("SurfaceDesc flags:"); + boolean recognizedAny = false; + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_CAPS, "DDSD_CAPS"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_HEIGHT, "DDSD_HEIGHT"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_WIDTH, "DDSD_WIDTH"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PITCH, "DDSD_PITCH"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_BACKBUFFERCOUNT, "DDSD_BACKBUFFERCOUNT"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ZBUFFERBITDEPTH, "DDSD_ZBUFFERBITDEPTH"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ALPHABITDEPTH, "DDSD_ALPHABITDEPTH"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LPSURFACE, "DDSD_LPSURFACE"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PIXELFORMAT, "DDSD_PIXELFORMAT"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_MIPMAPCOUNT, "DDSD_MIPMAPCOUNT"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LINEARSIZE, "DDSD_LINEARSIZE"); + recognizedAny |= printIfRecognized(tty, header.flags, DDSD_DEPTH, "DDSD_DEPTH"); + if (!recognizedAny) { + tty.println("(none)"); + } + tty.println("Raw SurfaceDesc flags: 0x" + Integer.toHexString(header.flags)); + tty.println("Pixel format flags:"); + recognizedAny = false; + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHAPIXELS, "DDPF_ALPHAPIXELS"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHA, "DDPF_ALPHA"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_FOURCC, "DDPF_FOURCC"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED4, "DDPF_PALETTEINDEXED4"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXEDTO8, "DDPF_PALETTEINDEXEDTO8"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED8, "DDPF_PALETTEINDEXED8"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGB, "DDPF_RGB"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_COMPRESSED, "DDPF_COMPRESSED"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGBTOYUV, "DDPF_RGBTOYUV"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_YUV, "DDPF_YUV"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZBUFFER, "DDPF_ZBUFFER"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED1, "DDPF_PALETTEINDEXED1"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_PALETTEINDEXED2, "DDPF_PALETTEINDEXED2"); + recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ZPIXELS, "DDPF_ZPIXELS"); + if (!recognizedAny) { + tty.println("(none)"); + } + tty.println("Raw pixel format flags: 0x" + Integer.toHexString(header.pfFlags)); + tty.println("Depth: " + getDepth()); + tty.println("Number of mip maps: " + getNumMipMaps()); + int fmt = getPixelFormat(); + tty.print("Pixel format: "); + switch (fmt) { + case D3DFMT_R8G8B8: tty.println("D3DFMT_R8G8B8"); break; + case D3DFMT_A8R8G8B8: tty.println("D3DFMT_A8R8G8B8"); break; + case D3DFMT_X8R8G8B8: tty.println("D3DFMT_X8R8G8B8"); break; + case D3DFMT_DXT1: tty.println("D3DFMT_DXT1"); break; + case D3DFMT_DXT2: tty.println("D3DFMT_DXT2"); break; + case D3DFMT_DXT3: tty.println("D3DFMT_DXT3"); break; + case D3DFMT_DXT4: tty.println("D3DFMT_DXT4"); break; + case D3DFMT_DXT5: tty.println("D3DFMT_DXT5"); break; + case D3DFMT_UNKNOWN: tty.println("D3DFMT_UNKNOWN"); break; + default: tty.println("(unknown pixel format " + fmt + ")"); break; + } + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private static final int MAGIC = 0x20534444; + + static class Header { + int size; // size of the DDSURFACEDESC structure + int flags; // determines what fields are valid + int height; // height of surface to be created + int width; // width of input surface + int pitchOrLinearSize; + int backBufferCountOrDepth; + int mipMapCountOrAux; // number of mip-map levels requested (in this context) + int alphaBitDepth; // depth of alpha buffer requested + int reserved1; // reserved + int surface; // pointer to the associated surface memory + // NOTE: following two entries are from DDCOLORKEY data structure + // Are overlaid with color for empty cubemap faces (unused in this reader) + int colorSpaceLowValue; + int colorSpaceHighValue; + int destBltColorSpaceLowValue; + int destBltColorSpaceHighValue; + int srcOverlayColorSpaceLowValue; + int srcOverlayColorSpaceHighValue; + int srcBltColorSpaceLowValue; + int srcBltColorSpaceHighValue; + // NOTE: following entries are from DDPIXELFORMAT data structure + // Are overlaid with flexible vertex format description of vertex + // buffers (unused in this reader) + int pfSize; // size of DDPIXELFORMAT structure + int pfFlags; // pixel format flags + int pfFourCC; // (FOURCC code) + // Following five entries have multiple interpretations, not just + // RGBA (but that's all we support right now) + int pfRGBBitCount; // how many bits per pixel + int pfRBitMask; // mask for red bits + int pfGBitMask; // mask for green bits + int pfBBitMask; // mask for blue bits + int pfABitMask; // mask for alpha channel + int ddsCaps1; // Texture and mip-map flags + int ddsCaps2; // Advanced capabilities including cubemap support + int ddsCapsReserved1; + int ddsCapsReserved2; + int textureStage; // stage in multitexture cascade + + void read(ByteBuffer buf) throws IOException { + int magic = buf.getInt(); + if (magic != MAGIC) { + throw new IOException("Incorrect magic number 0x" + + Integer.toHexString(magic) + + " (expected " + MAGIC + ")"); + } + + size = buf.getInt(); + flags = buf.getInt(); + height = buf.getInt(); + width = buf.getInt(); + pitchOrLinearSize = buf.getInt(); + backBufferCountOrDepth = buf.getInt(); + mipMapCountOrAux = buf.getInt(); + alphaBitDepth = buf.getInt(); + reserved1 = buf.getInt(); + surface = buf.getInt(); + colorSpaceLowValue = buf.getInt(); + colorSpaceHighValue = buf.getInt(); + destBltColorSpaceLowValue = buf.getInt(); + destBltColorSpaceHighValue = buf.getInt(); + srcOverlayColorSpaceLowValue = buf.getInt(); + srcOverlayColorSpaceHighValue = buf.getInt(); + srcBltColorSpaceLowValue = buf.getInt(); + srcBltColorSpaceHighValue = buf.getInt(); + pfSize = buf.getInt(); + pfFlags = buf.getInt(); + pfFourCC = buf.getInt(); + pfRGBBitCount = buf.getInt(); + pfRBitMask = buf.getInt(); + pfGBitMask = buf.getInt(); + pfBBitMask = buf.getInt(); + pfABitMask = buf.getInt(); + ddsCaps1 = buf.getInt(); + ddsCaps2 = buf.getInt(); + ddsCapsReserved1 = buf.getInt(); + ddsCapsReserved2 = buf.getInt(); + textureStage = buf.getInt(); + } + + // buf must be in little-endian byte order + void write(ByteBuffer buf) { + buf.putInt(MAGIC); + buf.putInt(size); + buf.putInt(flags); + buf.putInt(height); + buf.putInt(width); + buf.putInt(pitchOrLinearSize); + buf.putInt(backBufferCountOrDepth); + buf.putInt(mipMapCountOrAux); + buf.putInt(alphaBitDepth); + buf.putInt(reserved1); + buf.putInt(surface); + buf.putInt(colorSpaceLowValue); + buf.putInt(colorSpaceHighValue); + buf.putInt(destBltColorSpaceLowValue); + buf.putInt(destBltColorSpaceHighValue); + buf.putInt(srcOverlayColorSpaceLowValue); + buf.putInt(srcOverlayColorSpaceHighValue); + buf.putInt(srcBltColorSpaceLowValue); + buf.putInt(srcBltColorSpaceHighValue); + buf.putInt(pfSize); + buf.putInt(pfFlags); + buf.putInt(pfFourCC); + buf.putInt(pfRGBBitCount); + buf.putInt(pfRBitMask); + buf.putInt(pfGBitMask); + buf.putInt(pfBBitMask); + buf.putInt(pfABitMask); + buf.putInt(ddsCaps1); + buf.putInt(ddsCaps2); + buf.putInt(ddsCapsReserved1); + buf.putInt(ddsCapsReserved2); + buf.putInt(textureStage); + } + + private static int size() { + return 124; + } + + private static int pfSize() { + return 32; + } + + private static int writtenSize() { + return 128; + } + } + + private DDSImage() { + } + + private void readFromFile(File file) throws IOException { + fis = new FileInputStream(file); + chan = fis.getChannel(); + ByteBuffer buf = chan.map(FileChannel.MapMode.READ_ONLY, + 0, (int) file.length()); + readFromBuffer(buf); + } + + private void readFromBuffer(ByteBuffer buf) throws IOException { + this.buf = buf; + buf.order(ByteOrder.LITTLE_ENDIAN); + header = new Header(); + header.read(buf); + fixupHeader(); + } + + private void initFromData(int d3dFormat, + int width, + int height, + ByteBuffer[] mipmapData) throws IllegalArgumentException { + // Check size of mipmap data compared against format, width and + // height + int topmostMipmapSize = width * height; + int pitchOrLinearSize = width; + boolean isCompressed = false; + switch (d3dFormat) { + case D3DFMT_R8G8B8: topmostMipmapSize *= 3; pitchOrLinearSize *= 3; break; + case D3DFMT_A8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break; + case D3DFMT_X8R8G8B8: topmostMipmapSize *= 4; pitchOrLinearSize *= 4; break; + case D3DFMT_DXT1: + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + topmostMipmapSize = computeCompressedBlockSize(width, height, 1, d3dFormat); + pitchOrLinearSize = topmostMipmapSize; + isCompressed = true; + break; + default: + throw new IllegalArgumentException("d3dFormat must be one of the known formats"); + } - // Now check the mipmaps against this size - int curSize = topmostMipmapSize; - int totalSize = 0; - for (int i = 0; i < mipmapData.length; i++) { - if (mipmapData[i].remaining() != curSize) { - throw new IllegalArgumentException("Mipmap level " + i + - " didn't match expected data size (expected " + curSize + ", got " + - mipmapData[i].remaining() + ")"); - } - curSize /= 4; - totalSize += mipmapData[i].remaining(); - } - - // OK, create one large ByteBuffer to hold all of the mipmap data - totalSize += Header.writtenSize(); - ByteBuffer buf = ByteBuffer.allocate(totalSize); - buf.position(Header.writtenSize()); - for (int i = 0; i < mipmapData.length; i++) { - buf.put(mipmapData[i]); - } - this.buf = buf; + // Now check the mipmaps against this size + int curSize = topmostMipmapSize; + int totalSize = 0; + for (int i = 0; i < mipmapData.length; i++) { + if (mipmapData[i].remaining() != curSize) { + throw new IllegalArgumentException("Mipmap level " + i + + " didn't match expected data size (expected " + curSize + ", got " + + mipmapData[i].remaining() + ")"); + } + curSize /= 4; + totalSize += mipmapData[i].remaining(); + } + + // OK, create one large ByteBuffer to hold all of the mipmap data + totalSize += Header.writtenSize(); + ByteBuffer buf = ByteBuffer.allocate(totalSize); + buf.position(Header.writtenSize()); + for (int i = 0; i < mipmapData.length; i++) { + buf.put(mipmapData[i]); + } + this.buf = buf; - // Allocate and initialize a Header - header = new Header(); - header.size = Header.size(); - header.flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; - if (mipmapData.length > 1) { - header.flags |= DDSD_MIPMAPCOUNT; - header.mipMapCountOrAux = mipmapData.length; - } - header.width = width; - header.height = height; - if (isCompressed) { - header.flags |= DDSD_LINEARSIZE; - header.pfFlags |= DDPF_FOURCC; - header.pfFourCC = d3dFormat; - } else { - header.flags |= DDSD_PITCH; - // Figure out the various settings from the pixel format - header.pfFlags |= DDPF_RGB; - switch (d3dFormat) { - case D3DFMT_R8G8B8: header.pfRGBBitCount = 24; break; - case D3DFMT_A8R8G8B8: header.pfRGBBitCount = 32; header.pfFlags |= DDPF_ALPHAPIXELS; break; - case D3DFMT_X8R8G8B8: header.pfRGBBitCount = 32; break; - } - header.pfRBitMask = 0x00FF0000; - header.pfGBitMask = 0x0000FF00; - header.pfBBitMask = 0x000000FF; - if (d3dFormat == D3DFMT_A8R8G8B8) { - header.pfABitMask = 0xFF000000; - } - } - header.pitchOrLinearSize = pitchOrLinearSize; - header.pfSize = Header.pfSize(); - // Not sure whether we can get away with leaving the rest of the - // header blank - } - - // Microsoft doesn't follow their own specifications and the - // simplest conversion using the DxTex tool to e.g. a DXT3 texture - // results in an illegal .dds file without either DDSD_PITCH or - // DDSD_LINEARSIZE set in the header's flags. This code, adapted - // from the DevIL library, fixes up the header in these situations. - private void fixupHeader() { - if (isCompressed() && !isSurfaceDescFlagSet(DDSD_LINEARSIZE)) { - // Figure out how big the linear size should be - int depth = header.backBufferCountOrDepth; - if (depth == 0) { - depth = 1; - } - - header.pitchOrLinearSize = computeCompressedBlockSize(getWidth(), getHeight(), depth, getCompressionFormat()); - header.flags |= DDSD_LINEARSIZE; - } - } - - private static int computeCompressedBlockSize(int width, - int height, - int depth, - int compressionFormat) { - int blockSize = ((width + 3)/4) * ((height + 3)/4) * ((depth + 3)/4); - switch (compressionFormat) { - case D3DFMT_DXT1: blockSize *= 8; break; - default: blockSize *= 16; break; - } - return blockSize; - } - - private int mipMapWidth(int map) { - int width = getWidth(); - for (int i = 0; i < map; i++) { - width >>= 1; - } - return Math.max(width, 1); - } - - private int mipMapHeight(int map) { - int height = getHeight(); - for (int i = 0; i < map; i++) { - height >>= 1; - } - return Math.max(height, 1); - } - - private int mipMapSizeInBytes(int map) { - int width = mipMapWidth(map); - int height = mipMapHeight(map); - if (isCompressed()) { - int blockSize = (getCompressionFormat() == D3DFMT_DXT1 ? 8 : 16); - return ((width+3)/4)*((height+3)/4)*blockSize; - } else { - return width * height * (getDepth() / 8); - } - } - - private int sideSizeInBytes() { - int numLevels = getNumMipMaps(); - if (numLevels == 0) { - numLevels = 1; - } - - int size = 0; - for (int i = 0; i < numLevels; i++) { - size += mipMapSizeInBytes(i); - } - - return size; - } - - private int sideShiftInBytes(int side) { - int[] sides = { - DDSCAPS2_CUBEMAP_POSITIVEX, - DDSCAPS2_CUBEMAP_NEGATIVEX, - DDSCAPS2_CUBEMAP_POSITIVEY, - DDSCAPS2_CUBEMAP_NEGATIVEY, - DDSCAPS2_CUBEMAP_POSITIVEZ, - DDSCAPS2_CUBEMAP_NEGATIVEZ - }; - - int shift = 0; - int sideSize = sideSizeInBytes(); - for (int i = 0; i < sides.length; i++) { - int temp = sides[i]; - if ((temp & side) != 0) { - return shift; - } - - shift += sideSize; - } - - throw new RuntimeException("Illegal side: " + side); - } - - private boolean printIfRecognized(PrintStream tty, int flags, int flag, String what) { - if ((flags & flag) != 0) { - tty.println(what); - return true; - } - return false; - } + // Allocate and initialize a Header + header = new Header(); + header.size = Header.size(); + header.flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + if (mipmapData.length > 1) { + header.flags |= DDSD_MIPMAPCOUNT; + header.mipMapCountOrAux = mipmapData.length; + } + header.width = width; + header.height = height; + if (isCompressed) { + header.flags |= DDSD_LINEARSIZE; + header.pfFlags |= DDPF_FOURCC; + header.pfFourCC = d3dFormat; + } else { + header.flags |= DDSD_PITCH; + // Figure out the various settings from the pixel format + header.pfFlags |= DDPF_RGB; + switch (d3dFormat) { + case D3DFMT_R8G8B8: header.pfRGBBitCount = 24; break; + case D3DFMT_A8R8G8B8: header.pfRGBBitCount = 32; header.pfFlags |= DDPF_ALPHAPIXELS; break; + case D3DFMT_X8R8G8B8: header.pfRGBBitCount = 32; break; + } + header.pfRBitMask = 0x00FF0000; + header.pfGBitMask = 0x0000FF00; + header.pfBBitMask = 0x000000FF; + if (d3dFormat == D3DFMT_A8R8G8B8) { + header.pfABitMask = 0xFF000000; + } + } + header.pitchOrLinearSize = pitchOrLinearSize; + header.pfSize = Header.pfSize(); + // Not sure whether we can get away with leaving the rest of the + // header blank + } + + // Microsoft doesn't follow their own specifications and the + // simplest conversion using the DxTex tool to e.g. a DXT3 texture + // results in an illegal .dds file without either DDSD_PITCH or + // DDSD_LINEARSIZE set in the header's flags. This code, adapted + // from the DevIL library, fixes up the header in these situations. + private void fixupHeader() { + if (isCompressed() && !isSurfaceDescFlagSet(DDSD_LINEARSIZE)) { + // Figure out how big the linear size should be + int depth = header.backBufferCountOrDepth; + if (depth == 0) { + depth = 1; + } + + header.pitchOrLinearSize = computeCompressedBlockSize(getWidth(), getHeight(), depth, getCompressionFormat()); + header.flags |= DDSD_LINEARSIZE; + } + } + + private static int computeCompressedBlockSize(int width, + int height, + int depth, + int compressionFormat) { + int blockSize = ((width + 3)/4) * ((height + 3)/4) * ((depth + 3)/4); + switch (compressionFormat) { + case D3DFMT_DXT1: blockSize *= 8; break; + default: blockSize *= 16; break; + } + return blockSize; + } + + private int mipMapWidth(int map) { + int width = getWidth(); + for (int i = 0; i < map; i++) { + width >>= 1; + } + return Math.max(width, 1); + } + + private int mipMapHeight(int map) { + int height = getHeight(); + for (int i = 0; i < map; i++) { + height >>= 1; + } + return Math.max(height, 1); + } + + private int mipMapSizeInBytes(int map) { + int width = mipMapWidth(map); + int height = mipMapHeight(map); + if (isCompressed()) { + int blockSize = (getCompressionFormat() == D3DFMT_DXT1 ? 8 : 16); + return ((width+3)/4)*((height+3)/4)*blockSize; + } else { + return width * height * (getDepth() / 8); + } + } + + private int sideSizeInBytes() { + int numLevels = getNumMipMaps(); + if (numLevels == 0) { + numLevels = 1; + } + + int size = 0; + for (int i = 0; i < numLevels; i++) { + size += mipMapSizeInBytes(i); + } + + return size; + } + + private int sideShiftInBytes(int side) { + int[] sides = { + DDSCAPS2_CUBEMAP_POSITIVEX, + DDSCAPS2_CUBEMAP_NEGATIVEX, + DDSCAPS2_CUBEMAP_POSITIVEY, + DDSCAPS2_CUBEMAP_NEGATIVEY, + DDSCAPS2_CUBEMAP_POSITIVEZ, + DDSCAPS2_CUBEMAP_NEGATIVEZ + }; + + int shift = 0; + int sideSize = sideSizeInBytes(); + for (int i = 0; i < sides.length; i++) { + int temp = sides[i]; + if ((temp & side) != 0) { + return shift; + } + + shift += sideSize; + } + + throw new RuntimeException("Illegal side: " + side); + } + + private boolean printIfRecognized(PrintStream tty, int flags, int flag, String what) { + if ((flags & flag) != 0) { + tty.println(what); + return true; + } + return false; + } } diff --git a/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java b/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java index 8baa1f414..b2b1226bd 100755 --- a/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java +++ b/src/classes/com/sun/opengl/util/texture/spi/LEDataInputStream.java @@ -70,154 +70,154 @@ import java.io.IOException; */ public class LEDataInputStream extends FilterInputStream implements DataInput { - /** - * To reuse some of the non endian dependent methods from - * DataInputStreams methods. - */ - DataInputStream dataIn; - - public LEDataInputStream(InputStream in) - { - super(in); - dataIn = new DataInputStream(in); - } - - public void close() throws IOException - { - dataIn.close(); // better close as we create it. - // this will close underlying as well. - } - - public synchronized final int read(byte b[]) throws IOException - { - return dataIn.read(b, 0, b.length); - } - - public synchronized final int read(byte b[], int off, int len) throws IOException - { - int rl = dataIn.read(b, off, len); - return rl; - } - - public final void readFully(byte b[]) throws IOException - { - dataIn.readFully(b, 0, b.length); - } - - public final void readFully(byte b[], int off, int len) throws IOException - { - dataIn.readFully(b, off, len); - } - - public final int skipBytes(int n) throws IOException - { - return dataIn.skipBytes(n); - } - - public final boolean readBoolean() throws IOException - { - int ch = dataIn.read(); - if (ch < 0) - throw new EOFException(); - return (ch != 0); - } - - public final byte readByte() throws IOException - { - int ch = dataIn.read(); - if (ch < 0) - throw new EOFException(); - return (byte)(ch); - } - - public final int readUnsignedByte() throws IOException - { - int ch = dataIn.read(); - if (ch < 0) - throw new EOFException(); - return ch; - } - - public final short readShort() throws IOException - { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - if ((ch1 | ch2) < 0) - throw new EOFException(); - return (short)((ch1 << 0) + (ch2 << 8)); - } - - public final int readUnsignedShort() throws IOException - { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - if ((ch1 | ch2) < 0) - throw new EOFException(); - return (ch1 << 0) + (ch2 << 8); - } - - public final char readChar() throws IOException - { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - if ((ch1 | ch2) < 0) - throw new EOFException(); - return (char)((ch1 << 0) + (ch2 << 8)); - } - - public final int readInt() throws IOException - { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - int ch3 = dataIn.read(); - int ch4 = dataIn.read(); - if ((ch1 | ch2 | ch3 | ch4) < 0) - throw new EOFException(); - return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24)); - } - - public final long readLong() throws IOException - { - int i1 = readInt(); - int i2 = readInt(); - return ((long)(i1) & 0xFFFFFFFFL) + (i2 << 32); - } - - public final float readFloat() throws IOException - { - return Float.intBitsToFloat(readInt()); - } - - public final double readDouble() throws IOException - { - return Double.longBitsToDouble(readLong()); - } - - /** - * dont call this it is not implemented. - * @return empty new string - **/ - public final String readLine() throws IOException - { - return new String(); - } - - /** - * dont call this it is not implemented - * @return empty new string - **/ - public final String readUTF() throws IOException - { - return new String(); - } - - /** - * dont call this it is not implemented - * @return empty new string - **/ - public final static String readUTF(DataInput in) throws IOException - { - return new String(); - } + /** + * To reuse some of the non endian dependent methods from + * DataInputStreams methods. + */ + DataInputStream dataIn; + + public LEDataInputStream(InputStream in) + { + super(in); + dataIn = new DataInputStream(in); + } + + public void close() throws IOException + { + dataIn.close(); // better close as we create it. + // this will close underlying as well. + } + + public synchronized final int read(byte b[]) throws IOException + { + return dataIn.read(b, 0, b.length); + } + + public synchronized final int read(byte b[], int off, int len) throws IOException + { + int rl = dataIn.read(b, off, len); + return rl; + } + + public final void readFully(byte b[]) throws IOException + { + dataIn.readFully(b, 0, b.length); + } + + public final void readFully(byte b[], int off, int len) throws IOException + { + dataIn.readFully(b, off, len); + } + + public final int skipBytes(int n) throws IOException + { + return dataIn.skipBytes(n); + } + + public final boolean readBoolean() throws IOException + { + int ch = dataIn.read(); + if (ch < 0) + throw new EOFException(); + return (ch != 0); + } + + public final byte readByte() throws IOException + { + int ch = dataIn.read(); + if (ch < 0) + throw new EOFException(); + return (byte)(ch); + } + + public final int readUnsignedByte() throws IOException + { + int ch = dataIn.read(); + if (ch < 0) + throw new EOFException(); + return ch; + } + + public final short readShort() throws IOException + { + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (short)((ch1 << 0) + (ch2 << 8)); + } + + public final int readUnsignedShort() throws IOException + { + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (ch1 << 0) + (ch2 << 8); + } + + public final char readChar() throws IOException + { + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (char)((ch1 << 0) + (ch2 << 8)); + } + + public final int readInt() throws IOException + { + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + int ch3 = dataIn.read(); + int ch4 = dataIn.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EOFException(); + return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24)); + } + + public final long readLong() throws IOException + { + int i1 = readInt(); + int i2 = readInt(); + return ((long)(i1) & 0xFFFFFFFFL) + (i2 << 32); + } + + public final float readFloat() throws IOException + { + return Float.intBitsToFloat(readInt()); + } + + public final double readDouble() throws IOException + { + return Double.longBitsToDouble(readLong()); + } + + /** + * dont call this it is not implemented. + * @return empty new string + **/ + public final String readLine() throws IOException + { + return new String(); + } + + /** + * dont call this it is not implemented + * @return empty new string + **/ + public final String readUTF() throws IOException + { + return new String(); + } + + /** + * dont call this it is not implemented + * @return empty new string + **/ + public final static String readUTF(DataInput in) throws IOException + { + return new String(); + } } diff --git a/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java b/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java index 5360dc01d..284fa64bd 100755 --- a/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java +++ b/src/classes/com/sun/opengl/util/texture/spi/SGIImage.java @@ -53,618 +53,618 @@ import com.sun.opengl.util.*; */ public class SGIImage { - private Header header; - private int format; - private byte[] data; - // Used for decoding RLE-compressed images - private int[] rowStart; - private int[] rowSize; - private int rleEnd; - private byte[] tmpData; - private byte[] tmpRead; - - private static final int MAGIC = 474; - - static class Header { - short magic; // IRIS image file magic number - // This should be decimal 474 - byte storage; // Storage format - // 0 for uncompressed - // 1 for RLE compression - byte bpc; // Number of bytes per pixel channel - // Legally 1 or 2 - short dimension; // Number of dimensions - // Legally 1, 2, or 3 - // 1 means a single row, XSIZE long - // 2 means a single 2D image - // 3 means multiple 2D images - short xsize; // X size in pixels - short ysize; // Y size in pixels - short zsize; // Number of channels - // 1 indicates greyscale - // 3 indicates RGB - // 4 indicates RGB and Alpha - int pixmin; // Minimum pixel value - // This is the lowest pixel value in the image - int pixmax; // Maximum pixel value - // This is the highest pixel value in the image - int dummy; // Ignored - // Normally set to 0 - String imagename; // Image name; 80 bytes long - // Must be null terminated, therefore at most 79 bytes - int colormap; // Colormap ID - // 0 - normal mode - // 1 - dithered, 3 mits for red and green, 2 for blue, obsolete - // 2 - index colour, obsolete - // 3 - not an image but a colourmap - // 404 bytes char DUMMY Ignored - // Should be set to 0, makes the header 512 bytes. - - Header() { - magic = MAGIC; + private Header header; + private int format; + private byte[] data; + // Used for decoding RLE-compressed images + private int[] rowStart; + private int[] rowSize; + private int rleEnd; + private byte[] tmpData; + private byte[] tmpRead; + + private static final int MAGIC = 474; + + static class Header { + short magic; // IRIS image file magic number + // This should be decimal 474 + byte storage; // Storage format + // 0 for uncompressed + // 1 for RLE compression + byte bpc; // Number of bytes per pixel channel + // Legally 1 or 2 + short dimension; // Number of dimensions + // Legally 1, 2, or 3 + // 1 means a single row, XSIZE long + // 2 means a single 2D image + // 3 means multiple 2D images + short xsize; // X size in pixels + short ysize; // Y size in pixels + short zsize; // Number of channels + // 1 indicates greyscale + // 3 indicates RGB + // 4 indicates RGB and Alpha + int pixmin; // Minimum pixel value + // This is the lowest pixel value in the image + int pixmax; // Maximum pixel value + // This is the highest pixel value in the image + int dummy; // Ignored + // Normally set to 0 + String imagename; // Image name; 80 bytes long + // Must be null terminated, therefore at most 79 bytes + int colormap; // Colormap ID + // 0 - normal mode + // 1 - dithered, 3 mits for red and green, 2 for blue, obsolete + // 2 - index colour, obsolete + // 3 - not an image but a colourmap + // 404 bytes char DUMMY Ignored + // Should be set to 0, makes the header 512 bytes. + + Header() { + magic = MAGIC; + } + + Header(DataInputStream in) throws IOException { + magic = in.readShort(); + storage = in.readByte(); + bpc = in.readByte(); + dimension = in.readShort(); + xsize = in.readShort(); + ysize = in.readShort(); + zsize = in.readShort(); + pixmin = in.readInt(); + pixmax = in.readInt(); + dummy = in.readInt(); + byte[] tmpname = new byte[80]; + in.read(tmpname); + int numChars = 0; + while (tmpname[numChars++] != 0); + imagename = new String(tmpname, 0, numChars); + colormap = in.readInt(); + byte[] tmp = new byte[404]; + in.read(tmp); + } + + public String toString() { + return ("magic: " + magic + + " storage: " + (int) storage + + " bpc: " + (int) bpc + + " dimension: " + dimension + + " xsize: " + xsize + + " ysize: " + ysize + + " zsize: " + zsize + + " pixmin: " + pixmin + + " pixmax: " + pixmax + + " imagename: " + imagename + + " colormap: " + colormap); + } } - Header(DataInputStream in) throws IOException { - magic = in.readShort(); - storage = in.readByte(); - bpc = in.readByte(); - dimension = in.readShort(); - xsize = in.readShort(); - ysize = in.readShort(); - zsize = in.readShort(); - pixmin = in.readInt(); - pixmax = in.readInt(); - dummy = in.readInt(); - byte[] tmpname = new byte[80]; - in.read(tmpname); - int numChars = 0; - while (tmpname[numChars++] != 0); - imagename = new String(tmpname, 0, numChars); - colormap = in.readInt(); - byte[] tmp = new byte[404]; - in.read(tmp); + private SGIImage(Header header) { + this.header = header; } - public String toString() { - return ("magic: " + magic + - " storage: " + (int) storage + - " bpc: " + (int) bpc + - " dimension: " + dimension + - " xsize: " + xsize + - " ysize: " + ysize + - " zsize: " + zsize + - " pixmin: " + pixmin + - " pixmax: " + pixmax + - " imagename: " + imagename + - " colormap: " + colormap); + /** Reads an SGI image from the specified file. */ + public static SGIImage read(String filename) throws IOException { + return read(new FileInputStream(filename)); } - } - - private SGIImage(Header header) { - this.header = header; - } - - /** Reads an SGI image from the specified file. */ - public static SGIImage read(String filename) throws IOException { - return read(new FileInputStream(filename)); - } - - /** Reads an SGI image from the specified InputStream. */ - public static SGIImage read(InputStream in) throws IOException { - DataInputStream dIn = new DataInputStream(new BufferedInputStream(in)); - - Header header = new Header(dIn); - SGIImage res = new SGIImage(header); - res.decodeImage(dIn); - return res; - } - - /** Writes this SGIImage to the specified file name. If - flipVertically is set, outputs the scanlines from top to bottom - rather than the default bottom to top order. */ - public void write(String filename, boolean flipVertically) throws IOException { - write(new File(filename), flipVertically); - } - - /** Writes this SGIImage to the specified file. If flipVertically is - set, outputs the scanlines from top to bottom rather than the - default bottom to top order. */ - public void write(File file, boolean flipVertically) throws IOException { - writeImage(file, data, header.xsize, header.ysize, header.zsize, flipVertically); - } - - /** Creates an SGIImage from the specified data in either RGB or - RGBA format. */ - public static SGIImage createFromData(int width, - int height, - boolean hasAlpha, - byte[] data) { - Header header = new Header(); - header.xsize = (short) width; - header.ysize = (short) height; - header.zsize = (short) (hasAlpha ? 4 : 3); - SGIImage image = new SGIImage(header); - image.data = data; - return image; - } - - /** Determines from the magic number whether the given InputStream - points to an SGI RGB image. The given InputStream must return - true from markSupported() and support a minimum of two bytes - of read-ahead. */ - public static boolean isSGIImage(InputStream in) throws IOException { - if (!(in instanceof BufferedInputStream)) { - in = new BufferedInputStream(in); + + /** Reads an SGI image from the specified InputStream. */ + public static SGIImage read(InputStream in) throws IOException { + DataInputStream dIn = new DataInputStream(new BufferedInputStream(in)); + + Header header = new Header(dIn); + SGIImage res = new SGIImage(header); + res.decodeImage(dIn); + return res; } - if (!in.markSupported()) { - throw new IOException("Can not test non-destructively whether given InputStream is an SGI RGB image"); + + /** Writes this SGIImage to the specified file name. If + flipVertically is set, outputs the scanlines from top to bottom + rather than the default bottom to top order. */ + public void write(String filename, boolean flipVertically) throws IOException { + write(new File(filename), flipVertically); } - DataInputStream dIn = new DataInputStream(in); - dIn.mark(4); - short magic = dIn.readShort(); - dIn.reset(); - return (magic == MAGIC); - } - - /** Returns the width of the image. */ - public int getWidth() { - return header.xsize; - } - - /** Returns the height of the image. */ - public int getHeight() { - return header.ysize; - } - - /** Returns the OpenGL format for this texture; e.g. GL.GL_RGB or GL.GL_RGBA. */ - public int getFormat() { - return format; - } - - /** Returns the raw data for this texture in the correct - (bottom-to-top) order for calls to glTexImage2D. */ - public byte[] getData() { return data; } - - public String toString() { - return header.toString(); - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private void decodeImage(DataInputStream in) throws IOException { - if (header.storage == 1) { - // Read RLE compression data; row starts and sizes - int x = header.ysize * header.zsize; - rowStart = new int[x]; - rowSize = new int[x]; - rleEnd = 4 * 2 * x + 512; - for (int i = 0; i < x; i++) { - rowStart[i] = in.readInt(); - } - for (int i = 0; i < x; i++) { - rowSize[i] = in.readInt(); - } - tmpRead = new byte[header.xsize * 256]; + + /** Writes this SGIImage to the specified file. If flipVertically is + set, outputs the scanlines from top to bottom rather than the + default bottom to top order. */ + public void write(File file, boolean flipVertically) throws IOException { + writeImage(file, data, header.xsize, header.ysize, header.zsize, flipVertically); } - tmpData = readAll(in); - - int xsize = header.xsize; - int ysize = header.ysize; - int zsize = header.zsize; - int lptr = 0; - - data = new byte[xsize * ysize * 4]; - byte[] rbuf = new byte[xsize]; - byte[] gbuf = new byte[xsize]; - byte[] bbuf = new byte[xsize]; - byte[] abuf = new byte[xsize]; - for (int y = 0; y < ysize; y++) { - if (zsize >= 4) { - getRow(rbuf, y, 0); - getRow(gbuf, y, 1); - getRow(bbuf, y, 2); - getRow(abuf, y, 3); - rgbatorgba(rbuf, gbuf, bbuf, abuf, data, lptr); - } else if (zsize == 3) { - getRow(rbuf, y, 0); - getRow(gbuf, y, 1); - getRow(bbuf, y, 2); - rgbtorgba(rbuf, gbuf, bbuf, data, lptr); - } else if (zsize == 2) { - getRow(rbuf, y, 0); - getRow(abuf, y, 1); - latorgba(rbuf, abuf, data, lptr); - } else { - getRow(rbuf, y, 0); - bwtorgba(rbuf, data, lptr); - } - lptr += 4 * xsize; + + /** Creates an SGIImage from the specified data in either RGB or + RGBA format. */ + public static SGIImage createFromData(int width, + int height, + boolean hasAlpha, + byte[] data) { + Header header = new Header(); + header.xsize = (short) width; + header.ysize = (short) height; + header.zsize = (short) (hasAlpha ? 4 : 3); + SGIImage image = new SGIImage(header); + image.data = data; + return image; + } + + /** Determines from the magic number whether the given InputStream + points to an SGI RGB image. The given InputStream must return + true from markSupported() and support a minimum of two bytes + of read-ahead. */ + public static boolean isSGIImage(InputStream in) throws IOException { + if (!(in instanceof BufferedInputStream)) { + in = new BufferedInputStream(in); + } + if (!in.markSupported()) { + throw new IOException("Can not test non-destructively whether given InputStream is an SGI RGB image"); + } + DataInputStream dIn = new DataInputStream(in); + dIn.mark(4); + short magic = dIn.readShort(); + dIn.reset(); + return (magic == MAGIC); + } + + /** Returns the width of the image. */ + public int getWidth() { + return header.xsize; + } + + /** Returns the height of the image. */ + public int getHeight() { + return header.ysize; + } + + /** Returns the OpenGL format for this texture; e.g. GL.GL_RGB or GL.GL_RGBA. */ + public int getFormat() { + return format; } - rowStart = null; - rowSize = null; - tmpData = null; - tmpRead = null; - format = GL.GL_RGBA; - header.zsize = 4; - } - - private void getRow(byte[] buf, int y, int z) { - if (header.storage == 1) { - int offs = rowStart[y + z * header.ysize] - rleEnd; - System.arraycopy(tmpData, offs, tmpRead, 0, rowSize[y + z * header.ysize]); - int iPtr = 0; - int oPtr = 0; - for (;;) { - byte pixel = tmpRead[iPtr++]; - int count = (int) (pixel & 0x7F); - if (count == 0) { - return; + + /** Returns the raw data for this texture in the correct + (bottom-to-top) order for calls to glTexImage2D. */ + public byte[] getData() { return data; } + + public String toString() { + return header.toString(); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void decodeImage(DataInputStream in) throws IOException { + if (header.storage == 1) { + // Read RLE compression data; row starts and sizes + int x = header.ysize * header.zsize; + rowStart = new int[x]; + rowSize = new int[x]; + rleEnd = 4 * 2 * x + 512; + for (int i = 0; i < x; i++) { + rowStart[i] = in.readInt(); + } + for (int i = 0; i < x; i++) { + rowSize[i] = in.readInt(); + } + tmpRead = new byte[header.xsize * 256]; + } + tmpData = readAll(in); + + int xsize = header.xsize; + int ysize = header.ysize; + int zsize = header.zsize; + int lptr = 0; + + data = new byte[xsize * ysize * 4]; + byte[] rbuf = new byte[xsize]; + byte[] gbuf = new byte[xsize]; + byte[] bbuf = new byte[xsize]; + byte[] abuf = new byte[xsize]; + for (int y = 0; y < ysize; y++) { + if (zsize >= 4) { + getRow(rbuf, y, 0); + getRow(gbuf, y, 1); + getRow(bbuf, y, 2); + getRow(abuf, y, 3); + rgbatorgba(rbuf, gbuf, bbuf, abuf, data, lptr); + } else if (zsize == 3) { + getRow(rbuf, y, 0); + getRow(gbuf, y, 1); + getRow(bbuf, y, 2); + rgbtorgba(rbuf, gbuf, bbuf, data, lptr); + } else if (zsize == 2) { + getRow(rbuf, y, 0); + getRow(abuf, y, 1); + latorgba(rbuf, abuf, data, lptr); + } else { + getRow(rbuf, y, 0); + bwtorgba(rbuf, data, lptr); + } + lptr += 4 * xsize; } - if ((pixel & 0x80) != 0) { - while ((count--) > 0) { - buf[oPtr++] = tmpRead[iPtr++]; - } + rowStart = null; + rowSize = null; + tmpData = null; + tmpRead = null; + format = GL.GL_RGBA; + header.zsize = 4; + } + + private void getRow(byte[] buf, int y, int z) { + if (header.storage == 1) { + int offs = rowStart[y + z * header.ysize] - rleEnd; + System.arraycopy(tmpData, offs, tmpRead, 0, rowSize[y + z * header.ysize]); + int iPtr = 0; + int oPtr = 0; + for (;;) { + byte pixel = tmpRead[iPtr++]; + int count = (int) (pixel & 0x7F); + if (count == 0) { + return; + } + if ((pixel & 0x80) != 0) { + while ((count--) > 0) { + buf[oPtr++] = tmpRead[iPtr++]; + } + } else { + pixel = tmpRead[iPtr++]; + while ((count--) > 0) { + buf[oPtr++] = pixel; + } + } + } } else { - pixel = tmpRead[iPtr++]; - while ((count--) > 0) { - buf[oPtr++] = pixel; - } + int offs = (y * header.xsize) + (z * header.xsize * header.ysize); + System.arraycopy(tmpData, offs, buf, 0, header.xsize); } - } - } else { - int offs = (y * header.xsize) + (z * header.xsize * header.ysize); - System.arraycopy(tmpData, offs, buf, 0, header.xsize); } - } - - private void bwtorgba(byte[] b, byte[] dest, int lptr) { - for (int i = 0; i < b.length; i++) { - dest[4 * i + lptr + 0] = b[i]; - dest[4 * i + lptr + 1] = b[i]; - dest[4 * i + lptr + 2] = b[i]; - dest[4 * i + lptr + 3] = (byte) 0xFF; + + private void bwtorgba(byte[] b, byte[] dest, int lptr) { + for (int i = 0; i < b.length; i++) { + dest[4 * i + lptr + 0] = b[i]; + dest[4 * i + lptr + 1] = b[i]; + dest[4 * i + lptr + 2] = b[i]; + dest[4 * i + lptr + 3] = (byte) 0xFF; + } } - } - - private void latorgba(byte[] b, byte[] a, byte[] dest, int lptr) { - for (int i = 0; i < b.length; i++) { - dest[4 * i + lptr + 0] = b[i]; - dest[4 * i + lptr + 1] = b[i]; - dest[4 * i + lptr + 2] = b[i]; - dest[4 * i + lptr + 3] = a[i]; + + private void latorgba(byte[] b, byte[] a, byte[] dest, int lptr) { + for (int i = 0; i < b.length; i++) { + dest[4 * i + lptr + 0] = b[i]; + dest[4 * i + lptr + 1] = b[i]; + dest[4 * i + lptr + 2] = b[i]; + dest[4 * i + lptr + 3] = a[i]; + } } - } - - private void rgbtorgba(byte[] r, byte[] g, byte[] b, byte[] dest, int lptr) { - for (int i = 0; i < b.length; i++) { - dest[4 * i + lptr + 0] = r[i]; - dest[4 * i + lptr + 1] = g[i]; - dest[4 * i + lptr + 2] = b[i]; - dest[4 * i + lptr + 3] = (byte) 0xFF; + + private void rgbtorgba(byte[] r, byte[] g, byte[] b, byte[] dest, int lptr) { + for (int i = 0; i < b.length; i++) { + dest[4 * i + lptr + 0] = r[i]; + dest[4 * i + lptr + 1] = g[i]; + dest[4 * i + lptr + 2] = b[i]; + dest[4 * i + lptr + 3] = (byte) 0xFF; + } } - } - - private void rgbatorgba(byte[] r, byte[] g, byte[] b, byte[] a, byte[] dest, int lptr) { - for (int i = 0; i < b.length; i++) { - dest[4 * i + lptr + 0] = r[i]; - dest[4 * i + lptr + 1] = g[i]; - dest[4 * i + lptr + 2] = b[i]; - dest[4 * i + lptr + 3] = a[i]; + + private void rgbatorgba(byte[] r, byte[] g, byte[] b, byte[] a, byte[] dest, int lptr) { + for (int i = 0; i < b.length; i++) { + dest[4 * i + lptr + 0] = r[i]; + dest[4 * i + lptr + 1] = g[i]; + dest[4 * i + lptr + 2] = b[i]; + dest[4 * i + lptr + 3] = a[i]; + } } - } - - private static byte imgref(byte[] i, - int x, - int y, - int z, - int xs, - int ys, - int zs) { - return i[(xs*ys*z)+(xs*y)+x]; - } - - - private void writeHeader(DataOutputStream stream, - int xsize, int ysize, int zsize, boolean rle) throws IOException { - // effects: outputs the 512-byte IRIS RGB header to STREAM, using xsize, - // ysize, and depth as the dimensions of the image. NOTE that - // the following defaults are used: - // STORAGE = 1 (storage format = RLE) - // BPC = 1 (# bytes/channel) - // DIMENSION = 3 - // PIXMIN = 0 - // PIXMAX = 255 - // IMAGENAME = <80 nulls> - // COLORMAP = 0 - // See ftp://ftp.sgi.com/pub/sgi/SGIIMAGESPEC for more details. - - // write out MAGIC, STORAGE, BPC - stream.writeShort(474); - stream.write((rle ? 1 : 0)); - stream.write(1); - - // write out DIMENSION - stream.writeShort(3); - - // write XSIZE, YSIZE, ZSIZE - stream.writeShort(xsize); - stream.writeShort(ysize); - stream.writeShort(zsize); - - // write PIXMIN, PIXMAX - stream.writeInt(0); - stream.writeInt(255); - - // write DUMMY - stream.writeInt(0); - - // write IMAGENAME - for (int i = 0; i < 80; i++) - stream.write(0); - - // write COLORMAP - stream.writeInt(0); - - // write DUMMY (404 bytes) - for (int i = 0; i < 404; i++) - stream.write(0); - } - - private void writeImage(File file, - byte[] data, - int xsize, - int ysize, - int zsize, - boolean yflip) throws IOException { - // Input data is in RGBRGBRGB or RGBARGBARGBA format; first unswizzle it - byte[] tmpData = new byte[xsize * ysize * zsize]; - int dest = 0; - for (int i = 0; i < zsize; i++) { - for (int j = i; j < (xsize * ysize * zsize); j += zsize) { - tmpData[dest++] = data[j]; - } + + private static byte imgref(byte[] i, + int x, + int y, + int z, + int xs, + int ys, + int zs) { + return i[(xs*ys*z)+(xs*y)+x]; } - data = tmpData; - - // requires: DATA must be an array of size XSIZE * YSIZE * ZSIZE, - // indexed in the following manner: - // data[0] ...data[xsize-1] == first row of first channel - // data[xsize]...data[2*xsize-1] == second row of first channel - // ... data[(ysize - 1) * xsize]...data[(ysize * xsize) - 1] == - // last row of first channel - // Later channels follow the same format. - // *** NOTE that "first row" is defined by the BOTTOM ROW of - // the image. That is, the origin is in the lower left corner. - // effects: writes out an SGI image to FILE, RLE-compressed, INCLUDING - // header, of dimensions (xsize, ysize, zsize), and containing - // the data in DATA. If YFLIP is set, outputs the data in DATA - // in reverse order vertically (equivalent to a flip about the - // x axis). - - // Build the offset tables - int[] starttab = new int[ysize * zsize]; - int[] lengthtab = new int[ysize * zsize]; - - // Temporary buffer for holding RLE data. - // Note that this makes the assumption that RLE-compressed data will - // never exceed twice the size of the input data. - // There are surely formal proofs about how big the RLE buffer should - // be, as well as what the optimal look-ahead size is (i.e. don't switch - // copy/repeat modes for less than N repeats). However, I'm going from - // empirical evidence here; the break-even point seems to be a look- - // ahead of 3. (That is, if the three values following this one are all - // the same as the current value, switch to repeat mode.) - int lookahead = 3; - byte[] rlebuf = new byte[2 * xsize * ysize * zsize]; - - int cur_loc = 0; // current offset location. - int ptr = 0; - int total_size = 0; - int ystart = 0; - int yincr = 1; - int yend = ysize; - - if (yflip) { - ystart = ysize - 1; - yend = -1; - yincr = -1; + + + private void writeHeader(DataOutputStream stream, + int xsize, int ysize, int zsize, boolean rle) throws IOException { + // effects: outputs the 512-byte IRIS RGB header to STREAM, using xsize, + // ysize, and depth as the dimensions of the image. NOTE that + // the following defaults are used: + // STORAGE = 1 (storage format = RLE) + // BPC = 1 (# bytes/channel) + // DIMENSION = 3 + // PIXMIN = 0 + // PIXMAX = 255 + // IMAGENAME = <80 nulls> + // COLORMAP = 0 + // See ftp://ftp.sgi.com/pub/sgi/SGIIMAGESPEC for more details. + + // write out MAGIC, STORAGE, BPC + stream.writeShort(474); + stream.write((rle ? 1 : 0)); + stream.write(1); + + // write out DIMENSION + stream.writeShort(3); + + // write XSIZE, YSIZE, ZSIZE + stream.writeShort(xsize); + stream.writeShort(ysize); + stream.writeShort(zsize); + + // write PIXMIN, PIXMAX + stream.writeInt(0); + stream.writeInt(255); + + // write DUMMY + stream.writeInt(0); + + // write IMAGENAME + for (int i = 0; i < 80; i++) + stream.write(0); + + // write COLORMAP + stream.writeInt(0); + + // write DUMMY (404 bytes) + for (int i = 0; i < 404; i++) + stream.write(0); } - boolean DEBUG = false; + private void writeImage(File file, + byte[] data, + int xsize, + int ysize, + int zsize, + boolean yflip) throws IOException { + // Input data is in RGBRGBRGB or RGBARGBARGBA format; first unswizzle it + byte[] tmpData = new byte[xsize * ysize * zsize]; + int dest = 0; + for (int i = 0; i < zsize; i++) { + for (int j = i; j < (xsize * ysize * zsize); j += zsize) { + tmpData[dest++] = data[j]; + } + } + data = tmpData; + + // requires: DATA must be an array of size XSIZE * YSIZE * ZSIZE, + // indexed in the following manner: + // data[0] ...data[xsize-1] == first row of first channel + // data[xsize]...data[2*xsize-1] == second row of first channel + // ... data[(ysize - 1) * xsize]...data[(ysize * xsize) - 1] == + // last row of first channel + // Later channels follow the same format. + // *** NOTE that "first row" is defined by the BOTTOM ROW of + // the image. That is, the origin is in the lower left corner. + // effects: writes out an SGI image to FILE, RLE-compressed, INCLUDING + // header, of dimensions (xsize, ysize, zsize), and containing + // the data in DATA. If YFLIP is set, outputs the data in DATA + // in reverse order vertically (equivalent to a flip about the + // x axis). + + // Build the offset tables + int[] starttab = new int[ysize * zsize]; + int[] lengthtab = new int[ysize * zsize]; + + // Temporary buffer for holding RLE data. + // Note that this makes the assumption that RLE-compressed data will + // never exceed twice the size of the input data. + // There are surely formal proofs about how big the RLE buffer should + // be, as well as what the optimal look-ahead size is (i.e. don't switch + // copy/repeat modes for less than N repeats). However, I'm going from + // empirical evidence here; the break-even point seems to be a look- + // ahead of 3. (That is, if the three values following this one are all + // the same as the current value, switch to repeat mode.) + int lookahead = 3; + byte[] rlebuf = new byte[2 * xsize * ysize * zsize]; + + int cur_loc = 0; // current offset location. + int ptr = 0; + int total_size = 0; + int ystart = 0; + int yincr = 1; + int yend = ysize; + + if (yflip) { + ystart = ysize - 1; + yend = -1; + yincr = -1; + } + + boolean DEBUG = false; - for (int z = 0; z < zsize; z++) { - for (int y = ystart; y != yend; y += yincr) { - // RLE-compress each row. + for (int z = 0; z < zsize; z++) { + for (int y = ystart; y != yend; y += yincr) { + // RLE-compress each row. - int x = 0; - byte count = 0; - boolean repeat_mode = false; - boolean should_switch = false; - int start_ptr = ptr; - int num_ptr = ptr++; - byte repeat_val = 0; + int x = 0; + byte count = 0; + boolean repeat_mode = false; + boolean should_switch = false; + int start_ptr = ptr; + int num_ptr = ptr++; + byte repeat_val = 0; - while (x < xsize) { - // see if we should switch modes - should_switch = false; - if (repeat_mode) { - if (imgref(data, x, y, z, xsize, ysize, zsize) != repeat_val) { - should_switch = true; - } - } else { - // look ahead to see if we should switch to repeat mode. - // stay within the scanline for the lookahead - if ((x + lookahead) < xsize) { - should_switch = true; - for (int i = 1; i <= lookahead; i++) { - if (DEBUG) - System.err.println("left side was " + ((int) imgref(data, x, y, z, xsize, ysize, zsize)) + - ", right side was " + (int)imgref(data, x+i, y, z, xsize, ysize, zsize)); + while (x < xsize) { + // see if we should switch modes + should_switch = false; + if (repeat_mode) { + if (imgref(data, x, y, z, xsize, ysize, zsize) != repeat_val) { + should_switch = true; + } + } else { + // look ahead to see if we should switch to repeat mode. + // stay within the scanline for the lookahead + if ((x + lookahead) < xsize) { + should_switch = true; + for (int i = 1; i <= lookahead; i++) { + if (DEBUG) + System.err.println("left side was " + ((int) imgref(data, x, y, z, xsize, ysize, zsize)) + + ", right side was " + (int)imgref(data, x+i, y, z, xsize, ysize, zsize)); - if (imgref(data, x, y, z, xsize, ysize, zsize) != - imgref(data, x+i, y, z, xsize, ysize, zsize)) - should_switch = false; - } - } - } - - if (should_switch || (count == 127)) { - // update the number of elements we repeated/copied - if (x > 0) { - if (repeat_mode) - rlebuf[num_ptr] = count; - else - rlebuf[num_ptr] = (byte) (count | 0x80); - } - // perform mode switch if necessary; output repeat_val if - // switching FROM repeat mode, and set it if switching - // TO repeat mode. - if (repeat_mode) { - if (should_switch) - repeat_mode = false; - rlebuf[ptr++] = repeat_val; - } else { - if (should_switch) - repeat_mode = true; - repeat_val = imgref(data, x, y, z, xsize, ysize, zsize); - } + if (imgref(data, x, y, z, xsize, ysize, zsize) != + imgref(data, x+i, y, z, xsize, ysize, zsize)) + should_switch = false; + } + } + } + + if (should_switch || (count == 127)) { + // update the number of elements we repeated/copied + if (x > 0) { + if (repeat_mode) + rlebuf[num_ptr] = count; + else + rlebuf[num_ptr] = (byte) (count | 0x80); + } + // perform mode switch if necessary; output repeat_val if + // switching FROM repeat mode, and set it if switching + // TO repeat mode. + if (repeat_mode) { + if (should_switch) + repeat_mode = false; + rlebuf[ptr++] = repeat_val; + } else { + if (should_switch) + repeat_mode = true; + repeat_val = imgref(data, x, y, z, xsize, ysize, zsize); + } - if (x > 0) { - // reset the number pointer - num_ptr = ptr++; - // reset number of bytes copied - count = 0; - } - } + if (x > 0) { + // reset the number pointer + num_ptr = ptr++; + // reset number of bytes copied + count = 0; + } + } - // if not in repeat mode, copy element to ptr - if (!repeat_mode) { - rlebuf[ptr++] = imgref(data, x, y, z, xsize, ysize, zsize); - } - count++; - - if (x == xsize - 1) { - // Need to store the number of pixels we copied/repeated. - if (repeat_mode) { - rlebuf[num_ptr] = count; - // If we ended the row in repeat mode, store the - // repeated value - rlebuf[ptr++] = repeat_val; + // if not in repeat mode, copy element to ptr + if (!repeat_mode) { + rlebuf[ptr++] = imgref(data, x, y, z, xsize, ysize, zsize); + } + count++; + + if (x == xsize - 1) { + // Need to store the number of pixels we copied/repeated. + if (repeat_mode) { + rlebuf[num_ptr] = count; + // If we ended the row in repeat mode, store the + // repeated value + rlebuf[ptr++] = repeat_val; + } + else + rlebuf[num_ptr] = (byte) (count | 0x80); + + // output zero counter for the last value in the row + rlebuf[ptr++] = 0; + } + + x++; + } + // output this row's length into the length table + int rowlen = ptr - start_ptr; + if (yflip) + lengthtab[ysize*z+(ysize-y-1)] = rowlen; + else + lengthtab[ysize*z+y] = rowlen; + // add to the start table, and update the current offset + if (yflip) + starttab[ysize*z+(ysize-y-1)] = cur_loc; + else + starttab[ysize*z+y] = cur_loc; + cur_loc += rowlen; } - else - rlebuf[num_ptr] = (byte) (count | 0x80); - - // output zero counter for the last value in the row - rlebuf[ptr++] = 0; - } - - x++; } - // output this row's length into the length table - int rowlen = ptr - start_ptr; - if (yflip) - lengthtab[ysize*z+(ysize-y-1)] = rowlen; - else - lengthtab[ysize*z+y] = rowlen; - // add to the start table, and update the current offset - if (yflip) - starttab[ysize*z+(ysize-y-1)] = cur_loc; - else - starttab[ysize*z+y] = cur_loc; - cur_loc += rowlen; - } - } - // Now we have the offset tables computed, as well as the RLE data. - // Output this information to the file. - total_size = ptr; + // Now we have the offset tables computed, as well as the RLE data. + // Output this information to the file. + total_size = ptr; - if (DEBUG) - System.err.println("total_size was " + total_size); + if (DEBUG) + System.err.println("total_size was " + total_size); - DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); + DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); - writeHeader(stream, xsize, ysize, zsize, true); + writeHeader(stream, xsize, ysize, zsize, true); - int SIZEOF_INT = 4; - for (int i = 0; i < (ysize * zsize); i++) - stream.writeInt(starttab[i] + 512 + (2 * ysize * zsize * SIZEOF_INT)); - for (int i = 0; i < (ysize * zsize); i++) - stream.writeInt(lengthtab[i]); - for (int i = 0; i < total_size; i++) - stream.write(rlebuf[i]); + int SIZEOF_INT = 4; + for (int i = 0; i < (ysize * zsize); i++) + stream.writeInt(starttab[i] + 512 + (2 * ysize * zsize * SIZEOF_INT)); + for (int i = 0; i < (ysize * zsize); i++) + stream.writeInt(lengthtab[i]); + for (int i = 0; i < total_size; i++) + stream.write(rlebuf[i]); - stream.close(); - } + stream.close(); + } - private byte[] readAll(DataInputStream in) throws IOException { - byte[] dest = new byte[16384]; - int pos = 0; - int numRead = 0; + private byte[] readAll(DataInputStream in) throws IOException { + byte[] dest = new byte[16384]; + int pos = 0; + int numRead = 0; - boolean done = false; - - do { - numRead = in.read(dest, pos, dest.length - pos); - if (pos == dest.length) { - // Resize destination buffer - byte[] newDest = new byte[2 * dest.length]; - System.arraycopy(dest, 0, newDest, 0, pos); - dest = newDest; - } - if (numRead > 0) { - pos += numRead; - } + boolean done = false; + + do { + numRead = in.read(dest, pos, dest.length - pos); + if (pos == dest.length) { + // Resize destination buffer + byte[] newDest = new byte[2 * dest.length]; + System.arraycopy(dest, 0, newDest, 0, pos); + dest = newDest; + } + if (numRead > 0) { + pos += numRead; + } - done = ((numRead == -1) || (in.available() == 0)); - } while (!done); + done = ((numRead == -1) || (in.available() == 0)); + } while (!done); - // Trim destination buffer - if (pos != dest.length) { - byte[] finalDest = new byte[pos]; - System.arraycopy(dest, 0, finalDest, 0, pos); - dest = finalDest; - } + // Trim destination buffer + if (pos != dest.length) { + byte[] finalDest = new byte[pos]; + System.arraycopy(dest, 0, finalDest, 0, pos); + dest = finalDest; + } - return dest; - } + return dest; + } - // Test case - /* - import java.awt.image.*; - import javax.swing.*; + // Test case + /* + import java.awt.image.*; + import javax.swing.*; - public static void main(String[] args) { - for (int i = 0; i < args.length; i++) { + public static void main(String[] args) { + for (int i = 0; i < args.length; i++) { try { - System.out.println(args[i] + ":"); - SGIImage image = SGIImage.read(args[i]); - System.out.println(image); - BufferedImage img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); - WritableRaster raster = img.getRaster(); - DataBufferByte db = (DataBufferByte) raster.getDataBuffer(); - byte[] src = image.getData(); - byte[] dest = db.getData(); - for (int j = 0; j < src.length; j += 4) { - dest[j + 0] = src[j + 3]; - dest[j + 1] = src[j + 2]; - dest[j + 2] = src[j + 1]; - dest[j + 3] = src[j + 0]; - } - // System.arraycopy(src, 0, dest, 0, src.length); - ImageIcon icon = new ImageIcon(img); - JLabel label = new JLabel(); - label.setIcon(icon); - JFrame frame = new JFrame(args[i]); - frame.getContentPane().add(label); - frame.pack(); - frame.show(); + System.out.println(args[i] + ":"); + SGIImage image = SGIImage.read(args[i]); + System.out.println(image); + BufferedImage img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); + WritableRaster raster = img.getRaster(); + DataBufferByte db = (DataBufferByte) raster.getDataBuffer(); + byte[] src = image.getData(); + byte[] dest = db.getData(); + for (int j = 0; j < src.length; j += 4) { + dest[j + 0] = src[j + 3]; + dest[j + 1] = src[j + 2]; + dest[j + 2] = src[j + 1]; + dest[j + 3] = src[j + 0]; + } + // System.arraycopy(src, 0, dest, 0, src.length); + ImageIcon icon = new ImageIcon(img); + JLabel label = new JLabel(); + label.setIcon(icon); + JFrame frame = new JFrame(args[i]); + frame.getContentPane().add(label); + frame.pack(); + frame.show(); } catch (IOException e) { - e.printStackTrace(); + e.printStackTrace(); } - } - } - */ + } + } + */ } diff --git a/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java index e9e414891..2738536f0 100755 --- a/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java +++ b/src/classes/com/sun/opengl/util/texture/spi/TGAImage.java @@ -72,317 +72,317 @@ import com.sun.opengl.util.texture.*; */ public class TGAImage { - private Header header; - private int format; - private ByteBuffer data; - - private TGAImage(Header header) { - this.header = header; - } - - /** - * This class reads in all of the TGA image header in addition it also - * reads in the imageID field as it is convenient to handle that here. - * - * @author Robin Luiten - * @version 1.1 - */ - public static class Header { - /** Set of possible file format TGA types */ - public final static int TYPE_NEW = 0; - public final static int TYPE_OLD = 1; - public final static int TYPE_UNK = 2; // cant rewind stream so unknown for now. - - /** Set of possible image types in TGA file */ - public final static int NO_IMAGE = 0; // no image data - public final static int UCOLORMAPPED = 1; // uncompressed color mapped image - public final static int UTRUECOLOR = 2; // uncompressed true color image - public final static int UBLACKWHITE = 3; // uncompressed black and white image - public final static int COLORMAPPED = 9; // compressed color mapped image - public final static int TRUECOLOR = 10; // compressed true color image - public final static int BLACKWHITE = 11; // compressed black and white image - - /** Field image descriptor bitfield values definitions */ - public final static int ID_ATTRIBPERPIXEL = 0xF; - public final static int ID_RIGHTTOLEFT = 0x10; - public final static int ID_TOPTOBOTTOM = 0x20; - public final static int ID_INTERLEAVE = 0xC0; - - /** Field image descriptor / interleave values */ - public final static int I_NOTINTERLEAVED = 0; - public final static int I_TWOWAY = 1; - public final static int I_FOURWAY = 2; - - /** Type of this TGA file format */ - private int tgaType; - - /** initial TGA image data fields */ - private int idLength; // byte value - private int colorMapType; // byte value - private int imageType; // byte value - - /** TGA image colour map fields */ - private int firstEntryIndex; - private int colorMapLength; - private byte colorMapEntrySize; - - /** TGA image specification fields */ - private int xOrigin; - private int yOrigin; - private int width; - private int height; - private byte pixelDepth; - private byte imageDescriptor; - - private byte[] imageIDbuf; - private String imageID; - - // For construction from user data - Header() { - tgaType = TYPE_OLD; // dont try and get footer. - } + private Header header; + private int format; + private ByteBuffer data; - Header(LEDataInputStream in) throws IOException { - int ret; - - tgaType = TYPE_OLD; // dont try and get footer. - - // initial header fields - idLength = in.readUnsignedByte(); - colorMapType = in.readUnsignedByte(); - imageType = in.readUnsignedByte(); - - // color map header fields - firstEntryIndex = in.readUnsignedShort(); - colorMapLength = in.readUnsignedShort(); - colorMapEntrySize = in.readByte(); - - // TGA image specification fields - xOrigin = in.readUnsignedShort(); - yOrigin = in.readUnsignedShort(); - width = in.readUnsignedShort(); - height = in.readUnsignedShort(); - pixelDepth = in.readByte(); - imageDescriptor = in.readByte(); - - if (idLength > 0) { - imageIDbuf = new byte[idLength]; - in.read(imageIDbuf, 0, idLength); - imageID = new String(imageIDbuf, "US-ASCII"); - } + private TGAImage(Header header) { + this.header = header; } - public int tgaType() { return tgaType; } - - /** initial TGA image data fields */ - public int idLength() { return idLength; } - public int colorMapType() { return colorMapType; } - public int imageType() { return imageType; } - - /** TGA image colour map fields */ - public int firstEntryIndex() { return firstEntryIndex; } - public int colorMapLength() { return colorMapLength; } - public byte colorMapEntrySize() { return colorMapEntrySize; } - - /** TGA image specification fields */ - public int xOrigin() { return xOrigin; } - public int yOrigin() { return yOrigin; } - public int width() { return width; } - public int height() { return height; } - public byte pixelDepth() { return pixelDepth; } - public byte imageDescriptor() { return imageDescriptor; } - - /** bitfields in imageDescriptor */ - public byte attribPerPixel() { return (byte)(imageDescriptor & ID_ATTRIBPERPIXEL); } - public boolean rightToLeft() { return ((imageDescriptor & ID_RIGHTTOLEFT) != 0); } - public boolean topToBottom() { return ((imageDescriptor & ID_TOPTOBOTTOM) != 0); } - public byte interleave() { return (byte)((imageDescriptor & ID_INTERLEAVE) >> 6); } - - public byte[] imageIDbuf() { return imageIDbuf; } - public String imageID() { return imageID; } - - public String toString() { - return "TGA Header " + - " id length: " + idLength + - " color map type: "+ colorMapType + - " image type: "+ imageType + - " first entry index: " + firstEntryIndex + - " color map length: " + colorMapLength + - " color map entry size: " + colorMapEntrySize + - " x Origin: " + xOrigin + - " y Origin: " + yOrigin + - " width: "+ width + - " height: "+ height + - " pixel depth: "+ pixelDepth + - " image descriptor: "+ imageDescriptor + - (imageIDbuf == null ? "" : (" ID String: " + imageID)); - } + /** + * This class reads in all of the TGA image header in addition it also + * reads in the imageID field as it is convenient to handle that here. + * + * @author Robin Luiten + * @version 1.1 + */ + public static class Header { + /** Set of possible file format TGA types */ + public final static int TYPE_NEW = 0; + public final static int TYPE_OLD = 1; + public final static int TYPE_UNK = 2; // cant rewind stream so unknown for now. + + /** Set of possible image types in TGA file */ + public final static int NO_IMAGE = 0; // no image data + public final static int UCOLORMAPPED = 1; // uncompressed color mapped image + public final static int UTRUECOLOR = 2; // uncompressed true color image + public final static int UBLACKWHITE = 3; // uncompressed black and white image + public final static int COLORMAPPED = 9; // compressed color mapped image + public final static int TRUECOLOR = 10; // compressed true color image + public final static int BLACKWHITE = 11; // compressed black and white image + + /** Field image descriptor bitfield values definitions */ + public final static int ID_ATTRIBPERPIXEL = 0xF; + public final static int ID_RIGHTTOLEFT = 0x10; + public final static int ID_TOPTOBOTTOM = 0x20; + public final static int ID_INTERLEAVE = 0xC0; + + /** Field image descriptor / interleave values */ + public final static int I_NOTINTERLEAVED = 0; + public final static int I_TWOWAY = 1; + public final static int I_FOURWAY = 2; + + /** Type of this TGA file format */ + private int tgaType; + + /** initial TGA image data fields */ + private int idLength; // byte value + private int colorMapType; // byte value + private int imageType; // byte value + + /** TGA image colour map fields */ + private int firstEntryIndex; + private int colorMapLength; + private byte colorMapEntrySize; + + /** TGA image specification fields */ + private int xOrigin; + private int yOrigin; + private int width; + private int height; + private byte pixelDepth; + private byte imageDescriptor; + + private byte[] imageIDbuf; + private String imageID; + + // For construction from user data + Header() { + tgaType = TYPE_OLD; // dont try and get footer. + } + + Header(LEDataInputStream in) throws IOException { + int ret; + + tgaType = TYPE_OLD; // dont try and get footer. + + // initial header fields + idLength = in.readUnsignedByte(); + colorMapType = in.readUnsignedByte(); + imageType = in.readUnsignedByte(); + + // color map header fields + firstEntryIndex = in.readUnsignedShort(); + colorMapLength = in.readUnsignedShort(); + colorMapEntrySize = in.readByte(); + + // TGA image specification fields + xOrigin = in.readUnsignedShort(); + yOrigin = in.readUnsignedShort(); + width = in.readUnsignedShort(); + height = in.readUnsignedShort(); + pixelDepth = in.readByte(); + imageDescriptor = in.readByte(); + + if (idLength > 0) { + imageIDbuf = new byte[idLength]; + in.read(imageIDbuf, 0, idLength); + imageID = new String(imageIDbuf, "US-ASCII"); + } + } + + public int tgaType() { return tgaType; } + + /** initial TGA image data fields */ + public int idLength() { return idLength; } + public int colorMapType() { return colorMapType; } + public int imageType() { return imageType; } + + /** TGA image colour map fields */ + public int firstEntryIndex() { return firstEntryIndex; } + public int colorMapLength() { return colorMapLength; } + public byte colorMapEntrySize() { return colorMapEntrySize; } + + /** TGA image specification fields */ + public int xOrigin() { return xOrigin; } + public int yOrigin() { return yOrigin; } + public int width() { return width; } + public int height() { return height; } + public byte pixelDepth() { return pixelDepth; } + public byte imageDescriptor() { return imageDescriptor; } + + /** bitfields in imageDescriptor */ + public byte attribPerPixel() { return (byte)(imageDescriptor & ID_ATTRIBPERPIXEL); } + public boolean rightToLeft() { return ((imageDescriptor & ID_RIGHTTOLEFT) != 0); } + public boolean topToBottom() { return ((imageDescriptor & ID_TOPTOBOTTOM) != 0); } + public byte interleave() { return (byte)((imageDescriptor & ID_INTERLEAVE) >> 6); } + + public byte[] imageIDbuf() { return imageIDbuf; } + public String imageID() { return imageID; } + + public String toString() { + return "TGA Header " + + " id length: " + idLength + + " color map type: "+ colorMapType + + " image type: "+ imageType + + " first entry index: " + firstEntryIndex + + " color map length: " + colorMapLength + + " color map entry size: " + colorMapEntrySize + + " x Origin: " + xOrigin + + " y Origin: " + yOrigin + + " width: "+ width + + " height: "+ height + + " pixel depth: "+ pixelDepth + + " image descriptor: "+ imageDescriptor + + (imageIDbuf == null ? "" : (" ID String: " + imageID)); + } - public int size() { return 18 + idLength; } - - // buf must be in little-endian byte order - private void write(ByteBuffer buf) { - buf.put((byte) idLength); - buf.put((byte) colorMapType); - buf.put((byte) imageType); - buf.putShort((short) firstEntryIndex); - buf.putShort((short) colorMapLength); - buf.put((byte) colorMapEntrySize); - buf.putShort((short) xOrigin); - buf.putShort((short) yOrigin); - buf.putShort((short) width); - buf.putShort((short) height); - buf.put((byte) pixelDepth); - buf.put((byte) imageDescriptor); - if (idLength > 0) { - try { - byte[] chars = imageID.getBytes("US-ASCII"); - buf.put(chars); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + public int size() { return 18 + idLength; } + + // buf must be in little-endian byte order + private void write(ByteBuffer buf) { + buf.put((byte) idLength); + buf.put((byte) colorMapType); + buf.put((byte) imageType); + buf.putShort((short) firstEntryIndex); + buf.putShort((short) colorMapLength); + buf.put((byte) colorMapEntrySize); + buf.putShort((short) xOrigin); + buf.putShort((short) yOrigin); + buf.putShort((short) width); + buf.putShort((short) height); + buf.put((byte) pixelDepth); + buf.put((byte) imageDescriptor); + if (idLength > 0) { + try { + byte[] chars = imageID.getBytes("US-ASCII"); + buf.put(chars); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } } - } } - } - - - /** - * Identifies the image type of the tga image data and loads - * it into the JimiImage structure. This was taken from the - * prototype and modified for the new Jimi structure - */ - private void decodeImage(LEDataInputStream dIn) throws IOException { - switch (header.imageType()) { - case Header.UCOLORMAPPED: - throw new IOException("TGADecoder Uncompressed Colormapped images not supported"); - - case Header.UTRUECOLOR: // pixelDepth 15, 16, 24 and 32 - switch (header.pixelDepth) { - case 16: - throw new IOException("TGADecoder Compressed 16-bit True Color images not supported"); - - case 24: - case 32: - decodeRGBImageU24_32(dIn); - break; - } - break; - - case Header.UBLACKWHITE: - throw new IOException("TGADecoder Uncompressed Grayscale images not supported"); - - case Header.COLORMAPPED: - throw new IOException("TGADecoder Compressed Colormapped images not supported"); - - case Header.TRUECOLOR: - throw new IOException("TGADecoder Compressed True Color images not supported"); - - case Header.BLACKWHITE: - throw new IOException("TGADecoder Compressed Grayscale images not supported"); + + + /** + * Identifies the image type of the tga image data and loads + * it into the JimiImage structure. This was taken from the + * prototype and modified for the new Jimi structure + */ + private void decodeImage(LEDataInputStream dIn) throws IOException { + switch (header.imageType()) { + case Header.UCOLORMAPPED: + throw new IOException("TGADecoder Uncompressed Colormapped images not supported"); + + case Header.UTRUECOLOR: // pixelDepth 15, 16, 24 and 32 + switch (header.pixelDepth) { + case 16: + throw new IOException("TGADecoder Compressed 16-bit True Color images not supported"); + + case 24: + case 32: + decodeRGBImageU24_32(dIn); + break; + } + break; + + case Header.UBLACKWHITE: + throw new IOException("TGADecoder Uncompressed Grayscale images not supported"); + + case Header.COLORMAPPED: + throw new IOException("TGADecoder Compressed Colormapped images not supported"); + + case Header.TRUECOLOR: + throw new IOException("TGADecoder Compressed True Color images not supported"); + + case Header.BLACKWHITE: + throw new IOException("TGADecoder Compressed Grayscale images not supported"); + } } - } - /** - * This assumes that the body is for a 24 bit or 32 bit for a - * RGB or ARGB image respectively. - */ - private void decodeRGBImageU24_32(LEDataInputStream dIn) throws IOException { - int i; // row index - int j; // column index - int y; // output row index - int raw; // index through the raw input buffer - int rawWidth = header.width() * (header.pixelDepth() / 8); - byte[] rawBuf = new byte[rawWidth]; - byte[] tmpData = new byte[rawWidth * header.height()]; - - if (header.pixelDepth() == 24) { - format = GL2.GL_BGR; - } else { - assert header.pixelDepth() == 32; - format = GL2.GL_BGRA; + /** + * This assumes that the body is for a 24 bit or 32 bit for a + * RGB or ARGB image respectively. + */ + private void decodeRGBImageU24_32(LEDataInputStream dIn) throws IOException { + int i; // row index + int j; // column index + int y; // output row index + int raw; // index through the raw input buffer + int rawWidth = header.width() * (header.pixelDepth() / 8); + byte[] rawBuf = new byte[rawWidth]; + byte[] tmpData = new byte[rawWidth * header.height()]; + + if (header.pixelDepth() == 24) { + format = GL2.GL_BGR; + } else { + assert header.pixelDepth() == 32; + format = GL2.GL_BGRA; + } + + for (i = 0; i < header.height(); ++i) { + dIn.readFully(rawBuf, 0, rawWidth); + + if (header.topToBottom()) + y = header.height - i - 1; // range 0 to (header.height - 1) + else + y = i; + + System.arraycopy(rawBuf, 0, tmpData, y * rawWidth, rawBuf.length); + } + + data = ByteBuffer.wrap(tmpData); + } + + /** Returns the width of the image. */ + public int getWidth() { return header.width(); } + + /** Returns the height of the image. */ + public int getHeight() { return header.height(); } + + /** Returns the OpenGL format for this texture; e.g. GL.GL_BGR or GL.GL_BGRA. */ + public int getGLFormat() { return format; } + + /** Returns the raw data for this texture in the correct + (bottom-to-top) order for calls to glTexImage2D. */ + public ByteBuffer getData() { return data; } + + /** Reads a Targa image from the specified file. */ + public static TGAImage read(String filename) throws IOException { + return read(new FileInputStream(filename)); } - for (i = 0; i < header.height(); ++i) { - dIn.readFully(rawBuf, 0, rawWidth); + /** Reads a Targa image from the specified InputStream. */ + public static TGAImage read(InputStream in) throws IOException { + LEDataInputStream dIn = new LEDataInputStream(new BufferedInputStream(in)); - if (header.topToBottom()) - y = header.height - i - 1; // range 0 to (header.height - 1) - else - y = i; + Header header = new Header(dIn); + TGAImage res = new TGAImage(header); + res.decodeImage(dIn); + return res; + } + + /** Writes the image in Targa format to the specified file name. */ + public void write(String filename) throws IOException { + write(new File(filename)); + } - System.arraycopy(rawBuf, 0, tmpData, y * rawWidth, rawBuf.length); + /** Writes the image in Targa format to the specified file. */ + public void write(File file) throws IOException { + FileOutputStream stream = new FileOutputStream(file); + FileChannel chan = stream.getChannel(); + ByteBuffer buf = ByteBuffer.allocate(header.size()); + buf.order(ByteOrder.LITTLE_ENDIAN); + header.write(buf); + buf.rewind(); + chan.write(buf); + chan.write(data); + data.rewind(); + chan.force(true); + chan.close(); + stream.close(); } - data = ByteBuffer.wrap(tmpData); - } - - /** Returns the width of the image. */ - public int getWidth() { return header.width(); } - - /** Returns the height of the image. */ - public int getHeight() { return header.height(); } - - /** Returns the OpenGL format for this texture; e.g. GL.GL_BGR or GL.GL_BGRA. */ - public int getGLFormat() { return format; } - - /** Returns the raw data for this texture in the correct - (bottom-to-top) order for calls to glTexImage2D. */ - public ByteBuffer getData() { return data; } - - /** Reads a Targa image from the specified file. */ - public static TGAImage read(String filename) throws IOException { - return read(new FileInputStream(filename)); - } - - /** Reads a Targa image from the specified InputStream. */ - public static TGAImage read(InputStream in) throws IOException { - LEDataInputStream dIn = new LEDataInputStream(new BufferedInputStream(in)); - - Header header = new Header(dIn); - TGAImage res = new TGAImage(header); - res.decodeImage(dIn); - return res; - } - - /** Writes the image in Targa format to the specified file name. */ - public void write(String filename) throws IOException { - write(new File(filename)); - } - - /** Writes the image in Targa format to the specified file. */ - public void write(File file) throws IOException { - FileOutputStream stream = new FileOutputStream(file); - FileChannel chan = stream.getChannel(); - ByteBuffer buf = ByteBuffer.allocate(header.size()); - buf.order(ByteOrder.LITTLE_ENDIAN); - header.write(buf); - buf.rewind(); - chan.write(buf); - chan.write(data); - data.rewind(); - chan.force(true); - chan.close(); - stream.close(); - } - - /** Creates a TGAImage from data supplied by the end user. Shares - data with the passed ByteBuffer. Assumes the data is already in - the correct byte order for writing to disk, i.e., BGR or - BGRA. */ - public static TGAImage createFromData(int width, - int height, - boolean hasAlpha, - boolean topToBottom, - ByteBuffer data) { - Header header = new Header(); - header.imageType = Header.UTRUECOLOR; - header.width = width; - header.height = height; - header.pixelDepth = (byte) (hasAlpha ? 32 : 24); - header.imageDescriptor = (byte) (topToBottom ? Header.ID_TOPTOBOTTOM : 0); - // Note ID not supported - TGAImage ret = new TGAImage(header); - ret.data = data; - return ret; - } + /** Creates a TGAImage from data supplied by the end user. Shares + data with the passed ByteBuffer. Assumes the data is already in + the correct byte order for writing to disk, i.e., BGR or + BGRA. */ + public static TGAImage createFromData(int width, + int height, + boolean hasAlpha, + boolean topToBottom, + ByteBuffer data) { + Header header = new Header(); + header.imageType = Header.UTRUECOLOR; + header.width = width; + header.height = height; + header.pixelDepth = (byte) (hasAlpha ? 32 : 24); + header.imageDescriptor = (byte) (topToBottom ? Header.ID_TOPTOBOTTOM : 0); + // Note ID not supported + TGAImage ret = new TGAImage(header); + ret.data = data; + return ret; + } } diff --git a/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java b/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java index 1c822ef02..baa087289 100755 --- a/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java +++ b/src/classes/com/sun/opengl/util/texture/spi/TextureProvider.java @@ -52,114 +52,114 @@ import com.sun.opengl.util.texture.*; public interface TextureProvider { - /** - * Produces a TextureData object from a file, or returns null if the - * file format was not supported by this TextureProvider. Does not - * do any OpenGL-related work. The resulting TextureData can be - * converted into an OpenGL texture in a later step. - * - * @param file the file from which to read the texture data - * - * @param internalFormat the OpenGL internal format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param pixelFormat the OpenGL pixel format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param mipmap whether mipmaps should be produced for this - * texture either by autogenerating them or - * reading them from the file. Some file formats - * support multiple mipmaps in a single file in - * which case those mipmaps will be used rather - * than generating them. - * - * @param fileSuffix the file suffix to be used as a hint to the - * provider to more quickly decide whether it - * can handle the file, or null if the - * provider should infer the type from the - * file's contents - * - * @throws IOException if an error occurred while reading the file - */ - public TextureData newTextureData(File file, - int internalFormat, - int pixelFormat, - boolean mipmap, - String fileSuffix) throws IOException; + /** + * Produces a TextureData object from a file, or returns null if the + * file format was not supported by this TextureProvider. Does not + * do any OpenGL-related work. The resulting TextureData can be + * converted into an OpenGL texture in a later step. + * + * @param file the file from which to read the texture data + * + * @param internalFormat the OpenGL internal format to be used for + * the texture, or 0 if it should be inferred + * from the file's contents + * + * @param pixelFormat the OpenGL pixel format to be used for + * the texture, or 0 if it should be inferred + * from the file's contents + * + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. + * + * @param fileSuffix the file suffix to be used as a hint to the + * provider to more quickly decide whether it + * can handle the file, or null if the + * provider should infer the type from the + * file's contents + * + * @throws IOException if an error occurred while reading the file + */ + public TextureData newTextureData(File file, + int internalFormat, + int pixelFormat, + boolean mipmap, + String fileSuffix) throws IOException; - /** - * Produces a TextureData object from a stream, or returns null if - * the file format was not supported by this TextureProvider. Does - * not do any OpenGL-related work. The resulting TextureData can be - * converted into an OpenGL texture in a later step. - * - * @param stream the stream from which to read the texture data - * - * @param internalFormat the OpenGL internal format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param pixelFormat the OpenGL pixel format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param mipmap whether mipmaps should be produced for this - * texture either by autogenerating them or - * reading them from the file. Some file formats - * support multiple mipmaps in a single file in - * which case those mipmaps will be used rather - * than generating them. - * - * @param fileSuffix the file suffix to be used as a hint to the - * provider to more quickly decide whether it - * can handle the file, or null if the - * provider should infer the type from the - * file's contents - * - * @throws IOException if an error occurred while reading the stream - */ - public TextureData newTextureData(InputStream stream, - int internalFormat, - int pixelFormat, - boolean mipmap, - String fileSuffix) throws IOException; + /** + * Produces a TextureData object from a stream, or returns null if + * the file format was not supported by this TextureProvider. Does + * not do any OpenGL-related work. The resulting TextureData can be + * converted into an OpenGL texture in a later step. + * + * @param stream the stream from which to read the texture data + * + * @param internalFormat the OpenGL internal format to be used for + * the texture, or 0 if it should be inferred + * from the file's contents + * + * @param pixelFormat the OpenGL pixel format to be used for + * the texture, or 0 if it should be inferred + * from the file's contents + * + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. + * + * @param fileSuffix the file suffix to be used as a hint to the + * provider to more quickly decide whether it + * can handle the file, or null if the + * provider should infer the type from the + * file's contents + * + * @throws IOException if an error occurred while reading the stream + */ + public TextureData newTextureData(InputStream stream, + int internalFormat, + int pixelFormat, + boolean mipmap, + String fileSuffix) throws IOException; - /** - * Produces a TextureData object from a URL, or returns null if the - * file format was not supported by this TextureProvider. Does not - * do any OpenGL-related work. The resulting TextureData can be - * converted into an OpenGL texture in a later step. - * - * @param url the URL from which to read the texture data - * - * @param internalFormat the OpenGL internal format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param pixelFormat the OpenGL pixel format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param mipmap whether mipmaps should be produced for this - * texture either by autogenerating them or - * reading them from the file. Some file formats - * support multiple mipmaps in a single file in - * which case those mipmaps will be used rather - * than generating them. - * - * @param fileSuffix the file suffix to be used as a hint to the - * provider to more quickly decide whether it - * can handle the file, or null if the - * provider should infer the type from the - * file's contents - * - * @throws IOException if an error occurred while reading the URL - */ - public TextureData newTextureData(URL url, - int internalFormat, - int pixelFormat, - boolean mipmap, - String fileSuffix) throws IOException; + /** + * Produces a TextureData object from a URL, or returns null if the + * file format was not supported by this TextureProvider. Does not + * do any OpenGL-related work. The resulting TextureData can be + * converted into an OpenGL texture in a later step. + * + * @param url the URL from which to read the texture data + * + * @param internalFormat the OpenGL internal format to be used for + * the texture, or 0 if it should be inferred + * from the file's contents + * + * @param pixelFormat the OpenGL pixel format to be used for + * the texture, or 0 if it should be inferred + * from the file's contents + * + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. + * + * @param fileSuffix the file suffix to be used as a hint to the + * provider to more quickly decide whether it + * can handle the file, or null if the + * provider should infer the type from the + * file's contents + * + * @throws IOException if an error occurred while reading the URL + */ + public TextureData newTextureData(URL url, + int internalFormat, + int pixelFormat, + boolean mipmap, + String fileSuffix) throws IOException; } diff --git a/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java b/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java index 423a3b3e5..cdad15bb2 100755 --- a/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java +++ b/src/classes/com/sun/opengl/util/texture/spi/TextureWriter.java @@ -47,11 +47,11 @@ import com.sun.opengl.util.texture.*; to new file formats. */ public interface TextureWriter { - /** Writes the given TextureData to the passed file. Returns true if - this TextureWriter successfully handled the writing of the file, - otherwise false. May throw IOException if either this writer did - not support certain parameters of the TextureData or if an I/O - error occurred. */ - public boolean write(File file, - TextureData data) throws IOException; + /** Writes the given TextureData to the passed file. Returns true if + this TextureWriter successfully handled the writing of the file, + otherwise false. May throw IOException if either this writer did + not support certain parameters of the TextureData or if an I/O + error occurred. */ + public boolean write(File file, + TextureData data) throws IOException; } |