diff options
Diffstat (limited to 'src/classes/com/sun/opengl/utils')
-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; } |