diff options
author | Kenneth Russel <[email protected]> | 2006-01-07 23:47:47 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2006-01-07 23:47:47 +0000 |
commit | 31c51bc71190ba7bbb28f3706e31b8a3c17a1f00 (patch) | |
tree | 56e1eda26b28b1526dccc37027e6dc587993a494 /src/classes/com/sun/opengl/utils/Texture.java | |
parent | 986e62cfaf516ac2b03c5c7c39c68d6900482c00 (diff) |
Reorganized and added code in TextureIO and Texture classes to support
cubemap generation as well as complete replacement of the texture's
image, not just a sub-image. Added setTexParameteri to provide control
over things like the GL_TEXTURE_WRAP_ modes. Ported JOGL demos to use
new TextureIO class instead of TGAImage and ImageIO directly. Fixed
longstanding bug in ExaminerViewer's setting up of inverse rotation
causing errors in loading of uffizi cubemap.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@523 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/classes/com/sun/opengl/utils/Texture.java')
-rwxr-xr-x | src/classes/com/sun/opengl/utils/Texture.java | 338 |
1 files changed, 213 insertions, 125 deletions
diff --git a/src/classes/com/sun/opengl/utils/Texture.java b/src/classes/com/sun/opengl/utils/Texture.java index fc3b0d604..efecdffea 100755 --- a/src/classes/com/sun/opengl/utils/Texture.java +++ b/src/classes/com/sun/opengl/utils/Texture.java @@ -80,89 +80,17 @@ public class Texture { // number of public APIs we commit to Texture(TextureData data) throws GLException { GL gl = getCurrentGL(); + texID = createTextureID(gl); - imgWidth = data.getWidth(); - imgHeight = data.getHeight(); - mustFlipVertically = data.getMustFlipVertically(); - - 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"); - } else { - System.err.println("Using GL_ARB_texture_non_power_of_two"); - } - } - - texWidth = imgWidth; - texHeight = imgHeight; - target = GL.GL_TEXTURE_2D; - } else if (gl.isExtensionAvailable("GL_ARB_texture_rectangle")) { - if (DEBUG) { - System.err.println("Using GL_ARB_texture_rectangle"); - } - - texWidth = imgWidth; - texHeight = imgHeight; - target = GL.GL_TEXTURE_RECTANGLE_ARB; - } else { - if (DEBUG) { - System.err.println("Expanding texture to power-of-two dimensions"); - } - - if (data.getBorder() != 0) { - throw new RuntimeException("Scaling up a non-power-of-two texture which has a border won't work"); - } - texWidth = nextPowerOfTwo(imgWidth); - texHeight = nextPowerOfTwo(imgHeight); - target = GL.GL_TEXTURE_2D; - } - - // REMIND: let the user specify these, optionally - int minFilter = GL.GL_LINEAR; - int magFilter = GL.GL_LINEAR; - int wrapMode = GL.GL_CLAMP_TO_EDGE; + updateImage(data); + } + // Constructor for use when creating e.g. cube maps, where there is + // no initial texture data + Texture(int target) throws GLException { + GL gl = getCurrentGL(); texID = createTextureID(gl); - setImageSize(imgWidth, imgHeight); - gl.glBindTexture(target, texID); - // 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); - gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, magFilter); - gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, wrapMode); - gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, wrapMode); - } - - 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); - } - } + this.target = target; } /** @@ -173,7 +101,7 @@ public class Texture { * OpenGL-related errors occurred */ public void enable() throws GLException { - getCurrentGL().glEnable(target); + getCurrentGL().glEnable(target); } /** @@ -205,6 +133,7 @@ public class Texture { */ public void dispose() throws GLException { getCurrentGL().glDeleteTextures(1, new int[] {texID}, 0); + texID = 0; } /** @@ -301,6 +230,135 @@ public class Texture { } } + /** + * Updates the entire content area of this texture using the data in + * the given image. + * + * @throws GLException if no OpenGL context was current or if any + * OpenGL-related errors occurred + */ + public void updateImage(TextureData data) throws GLException { + updateImage(data, 0); + } + + /** + * Updates the content area of the specified target of this texture + * using the data in the given image. In general this is intended + * for construction of cube maps. + * + * @throws GLException if no OpenGL context was current or if any + * OpenGL-related errors occurred + */ + public void updateImage(TextureData data, int target) throws GLException { + GL gl = getCurrentGL(); + + imgWidth = data.getWidth(); + imgHeight = data.getHeight(); + mustFlipVertically = data.getMustFlipVertically(); + + int newTarget = 0; + + if (data.getMipmap()) { + // GLU always scales the texture's dimensions to be powers of + // two. It also doesn't really matter exactly what the texture + // width and height are because the texture coords are always + // between 0.0 and 1.0. + imgWidth = nextPowerOfTwo(imgWidth); + imgHeight = nextPowerOfTwo(imgHeight); + texWidth = imgWidth; + texHeight = imgHeight; + newTarget = 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"); + } else { + System.err.println("Using GL_ARB_texture_non_power_of_two"); + } + } + + texWidth = imgWidth; + texHeight = imgHeight; + newTarget = GL.GL_TEXTURE_2D; + } else if (gl.isExtensionAvailable("GL_ARB_texture_rectangle")) { + if (DEBUG) { + System.err.println("Using GL_ARB_texture_rectangle"); + } + + texWidth = imgWidth; + texHeight = imgHeight; + newTarget = GL.GL_TEXTURE_RECTANGLE_ARB; + } else { + if (DEBUG) { + System.err.println("Expanding texture to power-of-two dimensions"); + } + + if (data.getBorder() != 0) { + throw new RuntimeException("Scaling up a non-power-of-two texture which has a border won't work"); + } + texWidth = nextPowerOfTwo(imgWidth); + texHeight = nextPowerOfTwo(imgHeight); + newTarget = GL.GL_TEXTURE_2D; + } + + setImageSize(imgWidth, imgHeight); + + if (target != 0) { + // Allow user to override auto detection and skip bind step (for + // cubemap construction) + newTarget = target; + if (this.target == 0) { + throw new GLException("Override of target failed; no target specified yet"); + } + gl.glBindTexture(this.target, texID); + } else { + gl.glBindTexture(newTarget, texID); + } + + // REMIND: let the user specify these, optionally + int minFilter = (data.getMipmap() ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR); + int magFilter = GL.GL_LINEAR; + int wrapMode = GL.GL_CLAMP_TO_EDGE; + + // REMIND: figure out what to do for GL_TEXTURE_RECTANGLE_ARB + if (newTarget != GL.GL_TEXTURE_RECTANGLE_ARB) { + gl.glTexParameteri(newTarget, GL.GL_TEXTURE_MIN_FILTER, minFilter); + gl.glTexParameteri(newTarget, GL.GL_TEXTURE_MAG_FILTER, magFilter); + gl.glTexParameteri(newTarget, GL.GL_TEXTURE_WRAP_S, wrapMode); + gl.glTexParameteri(newTarget, GL.GL_TEXTURE_WRAP_T, wrapMode); + if (newTarget == GL.GL_TEXTURE_CUBE_MAP) { + gl.glTexParameteri(newTarget, GL.GL_TEXTURE_WRAP_R, wrapMode); + } + } + + if (data.getMipmap()) { + GLU glu = new GLU(); + glu.gluBuild2DMipmaps(newTarget, data.getInternalFormat(), + data.getWidth(), data.getHeight(), + data.getPixelFormat(), data.getPixelType(), data.getBuffer()); + } else { + gl.glTexImage2D(newTarget, 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++) { + updateSubImageImpl(data, newTarget, i, 0, 0); + } + } else { + updateSubImageImpl(data, newTarget, 0, 0, 0); + } + } + + // Don't overwrite target if we're loading e.g. faces of a cube + // map + if ((this.target == 0) || + (this.target == GL.GL_TEXTURE_2D) || + (this.target == GL.GL_TEXTURE_RECTANGLE_ARB)) { + this.target = newTarget; + } + } /** * Updates a subregion of the content area of this texture using the @@ -321,52 +379,33 @@ public class Texture { * OpenGL-related errors occurred */ 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()) { - 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; - } + updateSubImageImpl(data, target, mipmapLevel, x, y); + } - 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()); + /** + * Sets the OpenGL integer texture parameter for the texture's + * target. This gives control over parameters such as + * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T, which by default are set + * to GL_CLAMP_TO_EDGE. Causes this texture to be bound to the + * current texture state. + * + * @throws GLException if no OpenGL context was current or if any + * OpenGL-related errors occurred + */ + public void setTexParameteri(int parameterName, + int value) { + bind(); + GL gl = getCurrentGL(); + gl.glTexParameteri(target, parameterName, value); + } - gl.glTexSubImage2D(target, mipmapLevel, - x, y, width, height, - data.getPixelFormat(), data.getPixelType(), - buffer); - gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore align - } + /** + * Returns the underlying OpenGL texture object for this texture. + * Most applications will not need to access this, since it is + * handled automatically by the bind() and dispose() APIs. + */ + public int getTextureObject() { + return texID; } //---------------------------------------------------------------------- @@ -435,6 +474,55 @@ public class Texture { } } + private void updateSubImageImpl(TextureData data, int newTarget, int mipmapLevel, int x, int y) throws GLException { + GL gl = getCurrentGL(); + gl.glBindTexture(newTarget, texID); + 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()) { + 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(newTarget, 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(newTarget, mipmapLevel, + x, y, width, height, + data.getPixelFormat(), data.getPixelType(), + buffer); + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore align + } + } + /** * Creates a new texture ID. * |