diff options
author | Kenneth Russel <[email protected]> | 2006-01-07 01:13:44 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2006-01-07 01:13:44 +0000 |
commit | a295d66a868c897b71104f3dd4c94601c7463840 (patch) | |
tree | aa73f2c18fc0d343724d747eb0142d5213749579 | |
parent | c7c06d846e217bff8deac1914cd18cf8b3b6d6c4 (diff) |
Fixed mipmap handling in TextureIO and associated classes. Top-level
mipmap argument is now a boolean indicating whether mipmaps should be
generated or used if available. Added mipmap argument to newTexture
APIs. Added support for reading mipmaps from files which support them,
in particular DDS files. Updated TestTexture demo to generate mipmaps.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@521 232f8b59-042b-4e1e-8c03-345bb8c30851
-rwxr-xr-x | src/classes/com/sun/opengl/utils/Texture.java | 96 | ||||
-rwxr-xr-x | src/classes/com/sun/opengl/utils/TextureData.java | 114 | ||||
-rwxr-xr-x | src/classes/com/sun/opengl/utils/TextureIO.java | 300 | ||||
-rwxr-xr-x | src/classes/com/sun/opengl/utils/TextureProvider.java | 36 |
4 files changed, 376 insertions, 170 deletions
diff --git a/src/classes/com/sun/opengl/utils/Texture.java b/src/classes/com/sun/opengl/utils/Texture.java index a21facb65..fc3b0d604 100755 --- a/src/classes/com/sun/opengl/utils/Texture.java +++ b/src/classes/com/sun/opengl/utils/Texture.java @@ -36,7 +36,10 @@ package com.sun.opengl.utils; +import java.nio.*; + import javax.media.opengl.*; +import javax.media.opengl.glu.*; import com.sun.opengl.impl.*; /** @@ -68,8 +71,7 @@ public class Texture { the texture coords. */ private boolean mustFlipVertically; - /** The texture coordinates corresponding to the entire texture - image. */ + /** The texture coordinates corresponding to the entire image. */ private TextureCoords coords; private static final boolean DEBUG = Debug.debug("Texture"); @@ -83,8 +85,18 @@ public class Texture { imgHeight = data.getHeight(); mustFlipVertically = data.getMustFlipVertically(); - if ((isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) || - gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two")) { + if (data.getMipmap()) { + // GLU always targets GL_TEXTURE_2D and scales the texture to be + // a power of two. It also doesn't really matter exactly what + // the texture width and height are because the texture coords + // are always between 0.0 and 1.0. + imgWidth = nextPowerOfTwo(imgWidth); + imgHeight = nextPowerOfTwo(imgHeight); + texWidth = imgWidth; + texHeight = imgHeight; + target = GL.GL_TEXTURE_2D; + } else if ((isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) || + gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two")) { if (DEBUG) { if (isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) { System.err.println("Power-of-two texture"); @@ -125,10 +137,6 @@ public class Texture { texID = createTextureID(gl); setImageSize(imgWidth, imgHeight); gl.glBindTexture(target, texID); - gl.glTexImage2D(target, 0, data.getInternalFormat(), - texWidth, texHeight, data.getBorder(), - data.getPixelFormat(), data.getPixelType(), null); - // REMIND: figure out what to do for GL_TEXTURE_RECTANGLE_ARB if (target == GL.GL_TEXTURE_2D) { gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, minFilter); @@ -137,7 +145,24 @@ public class Texture { gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, wrapMode); } - updateSubImage(data, 0, 0); + if (data.getMipmap()) { + GLU glu = new GLU(); + glu.gluBuild2DMipmaps(target, data.getInternalFormat(), + data.getWidth(), data.getHeight(), + data.getPixelFormat(), data.getPixelType(), data.getBuffer()); + } else { + gl.glTexImage2D(target, 0, data.getInternalFormat(), + texWidth, texHeight, data.getBorder(), + data.getPixelFormat(), data.getPixelType(), null); + Buffer[] mipmapData = data.getMipmapData(); + if (mipmapData != null) { + for (int i = 0; i < mipmapData.length; i++) { + updateSubImage(data, i, 0, 0); + } + } else { + updateSubImage(data, 0, 0, 0); + } + } } /** @@ -279,9 +304,14 @@ public class Texture { /** * Updates a subregion of the content area of this texture using the - * data in the given image. + * data in the given image. Only updates the specified mipmap level + * and does not re-generate mipmaps if they were originally produced + * or loaded. * * @param data the image data to be uploaded to this texture + * @param mipmapLevel the mipmap level of the texture to set. If + * this is non-zero and the TextureData contains mipmap data, the + * appropriate mipmap level will be selected. * @param x the x offset (in pixels) relative to the lower-left corner * of this texture * @param y the y offset (in pixels) relative to the lower-left corner @@ -290,25 +320,51 @@ public class Texture { * @throws GLException if no OpenGL context was current or if any * OpenGL-related errors occurred */ - public void updateSubImage(TextureData data, int x, int y) throws GLException { + public void updateSubImage(TextureData data, int mipmapLevel, int x, int y) throws GLException { GL gl = getCurrentGL(); bind(); + int width = data.getWidth(); + int height = data.getHeight(); + Buffer buffer = data.getBuffer(); + if (data.getMipmapData() != null) { + // Compute the width and height at the specified mipmap level + for (int i = 0; i < mipmapLevel; i++) { + width /= 2; + height /= 2; + } + buffer = data.getMipmapData()[mipmapLevel]; + } + if (data.isDataCompressed()) { - // FIXME: should test availability of appropriate texture - // compression extension here - gl.glCompressedTexSubImage2D(target, data.getMipmapLevel(), - x, y, data.getWidth(), data.getHeight(), - data.getInternalFormat(), data.getBuffer().remaining(), - data.getBuffer()); + switch (data.getInternalFormat()) { + case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + if (!gl.isExtensionAvailable("GL_EXT_texture_compression_s3tc") && + !gl.isExtensionAvailable("GL_NV_texture_compression_vtc")) { + throw new GLException("DXTn compressed textures not supported by this graphics card"); + } + break; + default: + // FIXME: should test availability of more texture + // compression extensions here + break; + } + + gl.glCompressedTexSubImage2D(target, mipmapLevel, + x, y, width, height, + data.getInternalFormat(), + buffer.remaining(), buffer); } else { int[] align = new int[1]; gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment()); - gl.glTexSubImage2D(target, data.getMipmapLevel(), - x, y, data.getWidth(), data.getHeight(), + gl.glTexSubImage2D(target, mipmapLevel, + x, y, width, height, data.getPixelFormat(), data.getPixelType(), - data.getBuffer()); + buffer); gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore align } } diff --git a/src/classes/com/sun/opengl/utils/TextureData.java b/src/classes/com/sun/opengl/utils/TextureData.java index d88a18233..a6fcd9073 100755 --- a/src/classes/com/sun/opengl/utils/TextureData.java +++ b/src/classes/com/sun/opengl/utils/TextureData.java @@ -63,12 +63,14 @@ public class TextureData { private int pixelFormat; private int pixelType; private int internalFormat; // perhaps inferred from pixelFormat? - private int mipmapLevel; + private boolean mipmap; // indicates whether mipmaps should be generated + // (ignored if mipmaps are supplied from the file) private boolean dataIsCompressed; private boolean mustFlipVertically; // Must flip texture coordinates // vertically to get OpenGL output // to look correct - private Buffer buffer; // the actual data + private Buffer buffer; // the actual data... + private Buffer[] mipmapData; // ...or a series of mipmaps private Flusher flusher; private int alignment; // 1, 2, or 4 bytes @@ -91,9 +93,6 @@ public class TextureData { * memory-mapped files that might otherwise require a garbage * collection to reclaim and close. * - * @param mipmapLevel the mipmap level for the resulting texture - * this data represents (FIXME: needs - * rethinking, currently unused) * @param internalFormat the OpenGL internal format for the * resulting texture; must be specified, may * not be 0 @@ -105,6 +104,10 @@ public class TextureData { * resulting texture; must be specified, may * not be 0 * @param pixelType the OpenGL type of the pixels of the texture + * @param mipmap indicates whether mipmaps should be + * autogenerated (using GLU) for the resulting + * texture. Currently if mipmap is true then + * dataIsCompressed may not be true. * @param dataIsCompressed indicates whether the texture data is in * compressed form * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT) @@ -115,25 +118,33 @@ public class TextureData { * @param buffer the buffer containing the texture data * @param flusher optional flusher to perform cleanup tasks * upon call to flush() + * + * @throws IllegalArgumentException if any parameters of the texture + * data were invalid, such as requesting mipmap generation for a + * compressed texture */ - public TextureData(int mipmapLevel, - int internalFormat, + public TextureData(int internalFormat, int width, int height, int border, int pixelFormat, int pixelType, + boolean mipmap, boolean dataIsCompressed, boolean mustFlipVertically, Buffer buffer, - Flusher flusher) { + Flusher flusher) throws IllegalArgumentException { + if (mipmap && dataIsCompressed) { + throw new IllegalArgumentException("Can not generate mipmaps for compressed textures"); + } + this.width = width; this.height = height; this.border = border; this.pixelFormat = pixelFormat; this.pixelType = pixelType; this.internalFormat = internalFormat; - this.mipmapLevel = mipmapLevel; + this.mipmap = mipmap; this.dataIsCompressed = dataIsCompressed; this.mustFlipVertically = mustFlipVertically; this.buffer = buffer; @@ -143,11 +154,68 @@ public class TextureData { /** * Constructs a new TextureData object with the specified parameters + * and data for multiple mipmap levels contained in the given array + * of Buffers. The optional Flusher can be used to clean up native + * resources associated with this TextureData when processing is + * complete; for example, closing of memory-mapped files that might + * otherwise require a garbage collection to reclaim and close. + * + * @param internalFormat the OpenGL internal format for the + * resulting texture; must be specified, may + * not be 0 + * @param width the width in pixels of the topmost mipmap + * level of the texture + * @param height the height in pixels of the topmost mipmap + * level of the texture + * @param border the number of pixels of border this texture + * data has (0 or 1) + * @param pixelFormat the OpenGL pixel format for the + * resulting texture; must be specified, may + * not be 0 + * @param pixelType the OpenGL type of the pixels of the texture + * @param dataIsCompressed indicates whether the texture data is in + * compressed form + * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT) + * @param mustFlipVertically indicates whether the texture + * coordinates must be flipped vertically + * in order to properly display the + * texture + * @param mipmapData the buffers containing all mipmap levels + * of the texture's data + * @param flusher optional flusher to perform cleanup tasks + * upon call to flush() + * + * @throws IllegalArgumentException if any parameters of the texture + * data were invalid, such as requesting mipmap generation for a + * compressed texture + */ + public TextureData(int internalFormat, + int width, + int height, + int border, + int pixelFormat, + int pixelType, + boolean dataIsCompressed, + boolean mustFlipVertically, + Buffer[] mipmapData, + Flusher flusher) throws IllegalArgumentException { + this.width = width; + this.height = height; + this.border = border; + this.pixelFormat = pixelFormat; + this.pixelType = pixelType; + this.internalFormat = internalFormat; + this.dataIsCompressed = dataIsCompressed; + this.mustFlipVertically = mustFlipVertically; + this.mipmapData = (Buffer[]) mipmapData.clone(); + this.flusher = flusher; + alignment = 1; // FIXME: is this correct enough in all situations? + } + + /** + * Constructs a new TextureData object with the specified parameters * and data contained in the given BufferedImage. * - * @param mipmapLevel the mipmap level for the resulting texture - * this data represents (FIXME: needs - * rethinking, currently unused) * @param internalFormat the OpenGL internal format for the * resulting texture; may be 0, in which case * it is inferred from the image's type @@ -155,11 +223,14 @@ public class TextureData { * resulting texture; may be 0, in which case * it is inferred from the image's type (note: * this argument is currently always ignored) + * @param mipmap indicates whether mipmaps should be + * autogenerated (using GLU) for the resulting + * texture * @param image the image containing the texture data */ - public TextureData(int mipmapLevel, - int internalFormat, + public TextureData(int internalFormat, int pixelFormat, + boolean mipmap, BufferedImage image) { if (internalFormat == 0) { this.internalFormat = image.getColorModel().hasAlpha() ? GL.GL_RGBA : GL.GL_RGB; @@ -167,7 +238,7 @@ public class TextureData { this.internalFormat = internalFormat; } createFromImage(image); - this.mipmapLevel = mipmapLevel; + this.mipmap = mipmap; } /** Returns the width in pixels of the texture data. */ @@ -182,15 +253,18 @@ public class TextureData { public int getPixelType() { return pixelType; } /** Returns the intended OpenGL internal format of the texture data. */ public int getInternalFormat() { return internalFormat; } - /** Returns the intended mipmap level of the texture data. */ - public int getMipmapLevel() { return mipmapLevel; } + /** Returns whether mipmaps should be generated for the texture data. */ + public boolean getMipmap() { return mipmap; } /** Indicates whether the texture data is in compressed form. */ public boolean isDataCompressed() { return dataIsCompressed; } /** Indicates whether the texture coordinates must be flipped vertically for proper display. */ public boolean getMustFlipVertically() { return mustFlipVertically; } - /** Returns the texture data. */ + /** Returns the texture data, or null if it is specified as a set of mipmaps. */ public Buffer getBuffer() { return buffer; } + /** Returns all mipmap levels for the texture data, or null if it is + specified as a single image. */ + public Buffer[] getMipmapData() { return mipmapData; } /** Returns the required byte alignment for the texture data. */ public int getAlignment() { return alignment; } @@ -206,8 +280,8 @@ public class TextureData { public void setPixelType(int pixelType) { this.pixelType = pixelType; } /** Sets the intended OpenGL internal format of the texture data. */ public void setInternalFormat(int internalFormat) { this.internalFormat = internalFormat; } - /** Sets the intended mipmap level of the texture data. */ - public void setMipmapLevel(int mipmapLevel) { this.mipmapLevel = mipmapLevel; } + /** Sets whether mipmaps should be generated for the texture data. */ + public void setMipmap(boolean mipmap) { this.mipmap = mipmap; } /** Sets whether the texture data is in compressed form. */ public void setIsDataCompressed(boolean compressed) { this.dataIsCompressed = compressed; } /** Sets whether the texture coordinates must be flipped vertically diff --git a/src/classes/com/sun/opengl/utils/TextureIO.java b/src/classes/com/sun/opengl/utils/TextureIO.java index c39cf65e1..aa2e3c0ac 100755 --- a/src/classes/com/sun/opengl/utils/TextureIO.java +++ b/src/classes/com/sun/opengl/utils/TextureIO.java @@ -129,12 +129,15 @@ public class TextureIO { // i.e., reading from a file as opposed to a stream. /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given file. Does no OpenGL work. + * Creates a TextureData from the given file. Does no OpenGL work. * * @param file the file from which to read the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @param fileSuffix the suffix of the file name to be used as a * hint of the file format to the underlying * texture provider, or null if none and should be @@ -145,18 +148,21 @@ public class TextureIO { * @throws IOException if an error occurred while reading the file */ public static TextureData newTextureData(File file, - int mipmapLevel, + boolean mipmap, String fileSuffix) throws IOException { - return newTextureDataImpl(file, mipmapLevel, 0, 0, fileSuffix); + return newTextureDataImpl(file, 0, 0, mipmap, fileSuffix); } /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given stream. Does no OpenGL work. + * Creates a TextureData from the given stream. Does no OpenGL work. * * @param stream the stream from which to read the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @param fileSuffix the suffix of the file name to be used as a * hint of the file format to the underlying * texture provider, or null if none and should be @@ -167,18 +173,21 @@ public class TextureIO { * @throws IOException if an error occurred while reading the stream */ public static TextureData newTextureData(InputStream stream, - int mipmapLevel, + boolean mipmap, String fileSuffix) throws IOException { - return newTextureDataImpl(stream, mipmapLevel, 0, 0, fileSuffix); + return newTextureDataImpl(stream, 0, 0, mipmap, fileSuffix); } /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given URL. Does no OpenGL work. + * Creates a TextureData from the given URL. Does no OpenGL work. * * @param url the URL from which to read the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @param fileSuffix the suffix of the file name to be used as a * hint of the file format to the underlying * texture provider, or null if none and should be @@ -189,23 +198,23 @@ public class TextureIO { * @throws IOException if an error occurred while reading the URL */ public static TextureData newTextureData(URL url, - int mipmapLevel, + boolean mipmap, String fileSuffix) throws IOException { - return newTextureDataImpl(url, mipmapLevel, 0, 0, fileSuffix); + return newTextureDataImpl(url, 0, 0, mipmap, fileSuffix); } /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given BufferedImage. Does no OpenGL work. + * Creates a TextureData from the given BufferedImage. Does no + * OpenGL work. * * @param image the BufferedImage containing the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) + * @param mipmap whether mipmaps should be produced for this + * texture by autogenerating them * @return the texture data from the image */ public static TextureData newTextureData(BufferedImage image, - int mipmapLevel) { - return newTextureDataImpl(image, mipmapLevel, 0, 0); + boolean mipmap) { + return newTextureDataImpl(image, 0, 0, mipmap); } //---------------------------------------------------------------------- @@ -216,21 +225,24 @@ public class TextureIO { // IllegalArgumentException will be thrown in this case. /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given file, using the specified OpenGL - * internal format and pixel format for the texture which will - * eventually result. The internalFormat and pixelFormat must be - * specified and may not be zero; to use default values, use the + * Creates a TextureData from the given file, using the specified + * OpenGL internal format and pixel format for the texture which + * will eventually result. The internalFormat and pixelFormat must + * be specified and may not be zero; to use default values, use the * variant of this method which does not take these arguments. Does * no OpenGL work. * * @param file the file from which to read the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) * @param internalFormat the OpenGL internal format of the texture * which will eventually result from the TextureData * @param pixelFormat the OpenGL pixel format of the texture * which will eventually result from the TextureData + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @param fileSuffix the suffix of the file name to be used as a * hint of the file format to the underlying * texture provider, or null if none and should be @@ -243,33 +255,36 @@ public class TextureIO { * @throws IOException if an error occurred while reading the file */ public static TextureData newTextureData(File file, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException, IllegalArgumentException { if ((internalFormat == 0) || (pixelFormat == 0)) { throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero"); } - return newTextureDataImpl(file, mipmapLevel, internalFormat, pixelFormat, fileSuffix); + return newTextureDataImpl(file, internalFormat, pixelFormat, mipmap, fileSuffix); } /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given stream, using the specified OpenGL - * internal format and pixel format for the texture which will - * eventually result. The internalFormat and pixelFormat must be - * specified and may not be zero; to use default values, use the + * Creates a TextureData from the given stream, using the specified + * OpenGL internal format and pixel format for the texture which + * will eventually result. The internalFormat and pixelFormat must + * be specified and may not be zero; to use default values, use the * variant of this method which does not take these arguments. Does * no OpenGL work. * * @param stream the stream from which to read the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) * @param internalFormat the OpenGL internal format of the texture * which will eventually result from the TextureData * @param pixelFormat the OpenGL pixel format of the texture * which will eventually result from the TextureData + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @param fileSuffix the suffix of the file name to be used as a * hint of the file format to the underlying * texture provider, or null if none and should be @@ -282,33 +297,36 @@ public class TextureIO { * @throws IOException if an error occurred while reading the stream */ public static TextureData newTextureData(InputStream stream, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException, IllegalArgumentException { if ((internalFormat == 0) || (pixelFormat == 0)) { throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero"); } - return newTextureDataImpl(stream, mipmapLevel, internalFormat, pixelFormat, fileSuffix); + return newTextureDataImpl(stream, internalFormat, pixelFormat, mipmap, fileSuffix); } /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given URL, using the specified OpenGL - * internal format and pixel format for the texture which will - * eventually result. The internalFormat and pixelFormat must be - * specified and may not be zero; to use default values, use the + * Creates a TextureData from the given URL, using the specified + * OpenGL internal format and pixel format for the texture which + * will eventually result. The internalFormat and pixelFormat must + * be specified and may not be zero; to use default values, use the * variant of this method which does not take these arguments. Does * no OpenGL work. * * @param url the URL from which to read the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) * @param internalFormat the OpenGL internal format of the texture * which will eventually result from the TextureData * @param pixelFormat the OpenGL pixel format of the texture * which will eventually result from the TextureData + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @param fileSuffix the suffix of the file name to be used as a * hint of the file format to the underlying * texture provider, or null if none and should be @@ -321,46 +339,49 @@ public class TextureIO { * @throws IOException if an error occurred while reading the URL */ public static TextureData newTextureData(URL url, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException, IllegalArgumentException { if ((internalFormat == 0) || (pixelFormat == 0)) { throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero"); } - return newTextureDataImpl(url, mipmapLevel, internalFormat, pixelFormat, fileSuffix); + return newTextureDataImpl(url, internalFormat, pixelFormat, mipmap, fileSuffix); } /** - * Creates a TextureData representing the specified mipmap level of - * a texture from the given BufferedImage, using the specified - * OpenGL internal format and pixel format for the texture which - * will eventually result. The internalFormat and pixelFormat must - * be specified and may not be zero; to use default values, use the - * variant of this method which does not take these arguments. Does - * no OpenGL work. + * Creates a TextureData from the given BufferedImage, using the + * specified OpenGL internal format and pixel format for the texture + * which will eventually result. The internalFormat and pixelFormat + * must be specified and may not be zero; to use default values, use + * the variant of this method which does not take these + * arguments. Does no OpenGL work. * * @param image the BufferedImage containing the texture data - * @param mipmapLevel the mipmap level this data represents (FIXME: - * not currently used, needs to be rethought) * @param internalFormat the OpenGL internal format of the texture * which will eventually result from the TextureData * @param pixelFormat the OpenGL pixel format of the texture * which will eventually result from the TextureData + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @return the texture data from the image * @throws IllegalArgumentException if either internalFormat or * pixelFormat was 0 */ public static TextureData newTextureData(BufferedImage image, - int mipmapLevel, int internalFormat, - int pixelFormat) throws IllegalArgumentException { + int pixelFormat, + boolean mipmap) throws IllegalArgumentException { if ((internalFormat == 0) || (pixelFormat == 0)) { throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero"); } - return newTextureDataImpl(image, mipmapLevel, internalFormat, pixelFormat); + return newTextureDataImpl(image, internalFormat, pixelFormat, mipmap); } //---------------------------------------------------------------------- @@ -369,7 +390,8 @@ public class TextureIO { /** * Creates an OpenGL texture object from the specified TextureData - * using the current OpenGL context. + * using the current OpenGL context. Does not automatically generate + * mipmaps for the resulting texture. * * @param data the texture data to turn into an OpenGL texture * @throws GLException if no OpenGL context is current or if an @@ -384,15 +406,22 @@ public class TextureIO { /** * Creates an OpenGL texture object from the specified file using - * the current OpenGL context. + * the current OpenGL context. Does not automatically generate + * mipmaps for the resulting texture. * * @param file the file from which to read the texture data + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @throws IOException if an error occurred while reading the file * @throws GLException if no OpenGL context is current or if an * OpenGL error occurred */ - public static Texture newTexture(File file) throws IOException, GLException { - TextureData data = newTextureData(file, 0, getFileSuffix(file)); + public static Texture newTexture(File file, boolean mipmap) throws IOException, GLException { + TextureData data = newTextureData(file, mipmap, getFileSuffix(file)); Texture texture = newTexture(data); data.flush(); return texture; @@ -400,31 +429,45 @@ public class TextureIO { /** * Creates an OpenGL texture object from the specified stream using - * the current OpenGL context. + * the current OpenGL context. Does not automatically generate + * mipmaps for the resulting texture. * * @param stream the stream from which to read the texture data + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @throws IOException if an error occurred while reading the stream * @throws GLException if no OpenGL context is current or if an * OpenGL error occurred */ - public static Texture newTexture(InputStream stream) throws IOException, GLException { - TextureData data = newTextureData(stream, 0, null); + public static Texture newTexture(InputStream stream, boolean mipmap) throws IOException, GLException { + TextureData data = newTextureData(stream, mipmap, null); Texture texture = newTexture(data); data.flush(); return texture; } /** - * Creates an OpenGL texture object from the specified URL using - * the current OpenGL context. + * Creates an OpenGL texture object from the specified URL using the + * current OpenGL context. Does not automatically generate mipmaps + * for the resulting texture. * * @param url the URL from which to read the texture data + * @param mipmap whether mipmaps should be produced for this + * texture either by autogenerating them or + * reading them from the file. Some file formats + * support multiple mipmaps in a single file in + * which case those mipmaps will be used rather + * than generating them. * @throws IOException if an error occurred while reading the URL * @throws GLException if no OpenGL context is current or if an * OpenGL error occurred */ - public static Texture newTexture(URL url) throws IOException, GLException { - TextureData data = newTextureData(url, 0, null); + public static Texture newTexture(URL url, boolean mipmap) throws IOException, GLException { + TextureData data = newTextureData(url, mipmap, null); Texture texture = newTexture(data); data.flush(); return texture; @@ -435,11 +478,13 @@ public class TextureIO { * using the current OpenGL context. * * @param image the BufferedImage from which to read the texture data + * @param mipmap whether mipmaps should be produced for this + * texture by autogenerating them * @throws GLException if no OpenGL context is current or if an * OpenGL error occurred */ - public static Texture newTexture(BufferedImage image) throws GLException { - TextureData data = newTextureData(image, 0); + public static Texture newTexture(BufferedImage image, boolean mipmap) throws GLException { + TextureData data = newTextureData(image, mipmap); Texture texture = newTexture(data); data.flush(); return texture; @@ -479,16 +524,16 @@ public class TextureIO { // Implementation methods private static TextureData newTextureDataImpl(File file, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) { TextureProvider provider = (TextureProvider) iter.next(); TextureData data = provider.newTextureData(file, - mipmapLevel, internalFormat, pixelFormat, + mipmap, fileSuffix); if (data != null) { return data; @@ -498,16 +543,16 @@ public class TextureIO { } private static TextureData newTextureDataImpl(InputStream stream, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) { TextureProvider provider = (TextureProvider) iter.next(); TextureData data = provider.newTextureData(stream, - mipmapLevel, internalFormat, pixelFormat, + mipmap, fileSuffix); if (data != null) { return data; @@ -518,16 +563,16 @@ public class TextureIO { } private static TextureData newTextureDataImpl(URL url, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) { TextureProvider provider = (TextureProvider) iter.next(); TextureData data = provider.newTextureData(url, - mipmapLevel, internalFormat, pixelFormat, + mipmap, fileSuffix); if (data != null) { return data; @@ -538,47 +583,47 @@ public class TextureIO { } private static TextureData newTextureDataImpl(BufferedImage image, - int mipmapLevel, int internalFormat, - int pixelFormat) { - return new TextureData(mipmapLevel, internalFormat, pixelFormat, image); + int pixelFormat, + boolean mipmap) { + return new TextureData(internalFormat, pixelFormat, mipmap, image); } //---------------------------------------------------------------------- // Base provider - used last static class IIOTextureProvider implements TextureProvider { public TextureData newTextureData(File file, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { BufferedImage img = ImageIO.read(file); if (img == null) { return null; } - return new TextureData(mipmapLevel, internalFormat, pixelFormat, img); + return new TextureData(internalFormat, pixelFormat, mipmap, img); } public TextureData newTextureData(InputStream stream, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { BufferedImage img = ImageIO.read(stream); if (img == null) { return null; } - return new TextureData(mipmapLevel, internalFormat, pixelFormat, img); + return new TextureData(internalFormat, pixelFormat, mipmap, img); } public TextureData newTextureData(URL url, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { InputStream stream = url.openStream(); try { - return newTextureData(stream, mipmapLevel, internalFormat, pixelFormat, fileSuffix); + return newTextureData(stream, internalFormat, pixelFormat, mipmap, fileSuffix); } finally { stream.close(); } @@ -589,17 +634,15 @@ public class TextureIO { // DDS provider -- supports files only for now static class DDSTextureProvider implements TextureProvider { public TextureData newTextureData(File file, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { if (DDS.equals(fileSuffix) || DDS.equals(getFileSuffix(file))) { final DDSReader reader = new DDSReader(); reader.loadFile(file); - // FIXME: handle case where all mipmaps are requested -- this - // will require API changes - DDSReader.ImageInfo info = reader.getMipMap(mipmapLevel); + DDSReader.ImageInfo info = reader.getMipMap(0); if (pixelFormat == 0) { switch (reader.getPixelFormat()) { case DDSReader.D3DFMT_R8G8B8: @@ -641,17 +684,38 @@ public class TextureIO { reader.close(); } }; - TextureData data = new TextureData(mipmapLevel, - internalFormat, - info.getWidth(), - info.getHeight(), - 0, - pixelFormat, - GL.GL_UNSIGNED_BYTE, - info.isCompressed(), - true, - info.getData(), - flusher); + TextureData data; + if (mipmap && reader.getNumMipMaps() > 0) { + Buffer[] mipmapData = new Buffer[reader.getNumMipMaps()]; + for (int i = 0; i < reader.getNumMipMaps(); i++) { + mipmapData[i] = reader.getMipMap(i).getData(); + } + data = new TextureData(internalFormat, + info.getWidth(), + info.getHeight(), + 0, + pixelFormat, + GL.GL_UNSIGNED_BYTE, + info.isCompressed(), + true, + mipmapData, + flusher); + } else { + // Fix this up for the end user because we can't generate + // mipmaps for compressed textures + mipmap = false; + data = new TextureData(internalFormat, + info.getWidth(), + info.getHeight(), + 0, + pixelFormat, + GL.GL_UNSIGNED_BYTE, + mipmap, + info.isCompressed(), + true, + info.getData(), + flusher); + } return data; } @@ -659,17 +723,17 @@ public class TextureIO { } public TextureData newTextureData(InputStream stream, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { return null; } public TextureData newTextureData(URL url, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { return null; } @@ -679,9 +743,9 @@ public class TextureIO { // Base class for SGI RGB and TGA image providers static abstract class StreamBasedTextureProvider implements TextureProvider { public TextureData newTextureData(File file, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { InputStream inStream = new BufferedInputStream(new FileInputStream(file)); try { @@ -689,9 +753,9 @@ public class TextureIO { // anyway so there isn't much point in having a separate code // path for files return newTextureData(inStream, - mipmapLevel, internalFormat, pixelFormat, + mipmap, ((fileSuffix != null) ? fileSuffix : getFileSuffix(file))); } finally { inStream.close(); @@ -699,13 +763,13 @@ public class TextureIO { } public TextureData newTextureData(URL url, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { InputStream stream = url.openStream(); try { - return newTextureData(stream, mipmapLevel, internalFormat, pixelFormat, fileSuffix); + return newTextureData(stream, internalFormat, pixelFormat, mipmap, fileSuffix); } finally { stream.close(); } @@ -716,9 +780,9 @@ public class TextureIO { // SGI RGB image provider static class SGITextureProvider extends StreamBasedTextureProvider { public TextureData newTextureData(InputStream stream, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { if (SGI.equals(fileSuffix) || SGI_RGB.equals(fileSuffix) || @@ -730,13 +794,13 @@ public class TextureIO { if (internalFormat == 0) { internalFormat = image.getFormat(); } - return new TextureData(mipmapLevel, - internalFormat, + return new TextureData(internalFormat, image.getWidth(), image.getHeight(), 0, pixelFormat, GL.GL_UNSIGNED_BYTE, + mipmap, false, false, ByteBuffer.wrap(image.getData()), @@ -751,9 +815,9 @@ public class TextureIO { // TGA (Targa) image provider static class TGATextureProvider extends StreamBasedTextureProvider { public TextureData newTextureData(InputStream stream, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException { if (TGA.equals(fileSuffix)) { TGAImage image = TGAImage.read(stream); @@ -763,13 +827,13 @@ public class TextureIO { if (internalFormat == 0) { internalFormat = GL.GL_RGBA8; } - return new TextureData(mipmapLevel, - internalFormat, + return new TextureData(internalFormat, image.getWidth(), image.getHeight(), 0, pixelFormat, GL.GL_UNSIGNED_BYTE, + mipmap, false, false, ByteBuffer.wrap(image.getData()), diff --git a/src/classes/com/sun/opengl/utils/TextureProvider.java b/src/classes/com/sun/opengl/utils/TextureProvider.java index 4b71ae982..fcc62c894 100755 --- a/src/classes/com/sun/opengl/utils/TextureProvider.java +++ b/src/classes/com/sun/opengl/utils/TextureProvider.java @@ -58,9 +58,6 @@ public interface TextureProvider { * * @param file the file from which to read the texture data * - * @param mipmapLevel the mipmap level of the resulting texture being - * read (FIXME: needs rethinking, not yet working) - * * @param internalFormat the OpenGL internal format to be used for * the texture, or 0 if it should be inferred * from the file's contents @@ -69,6 +66,13 @@ public interface TextureProvider { * 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 @@ -78,9 +82,9 @@ public interface TextureProvider { * @throws IOException if an error occurred while reading the file */ public TextureData newTextureData(File file, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException; /** @@ -91,9 +95,6 @@ public interface TextureProvider { * * @param stream the stream from which to read the texture data * - * @param mipmapLevel the mipmap level of the resulting texture being - * read (FIXME: needs rethinking, not yet working) - * * @param internalFormat the OpenGL internal format to be used for * the texture, or 0 if it should be inferred * from the file's contents @@ -102,6 +103,13 @@ public interface TextureProvider { * 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 @@ -111,9 +119,9 @@ public interface TextureProvider { * @throws IOException if an error occurred while reading the stream */ public TextureData newTextureData(InputStream stream, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException; /** @@ -124,9 +132,6 @@ public interface TextureProvider { * * @param url the URL from which to read the texture data * - * @param mipmapLevel the mipmap level of the resulting texture being - * read (FIXME: needs rethinking, not yet working) - * * @param internalFormat the OpenGL internal format to be used for * the texture, or 0 if it should be inferred * from the file's contents @@ -135,6 +140,13 @@ public interface TextureProvider { * 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 @@ -144,8 +156,8 @@ public interface TextureProvider { * @throws IOException if an error occurred while reading the URL */ public TextureData newTextureData(URL url, - int mipmapLevel, int internalFormat, int pixelFormat, + boolean mipmap, String fileSuffix) throws IOException; } |