From 6cead503317fa6e771b371bfb4dd381472b60113 Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Tue, 4 Sep 2007 02:35:52 +0000 Subject: Added support for loading non-mipmapped, non-power-of-two compressed textures on pre-OpenGL 2.0 hardware by first loading an "empty" compressed texture and then updating a sub-rectangle of its image. Straightforward port of this code to the mipmapped case did not work; added error checking for this case and throwing of GLException. Bug pointed out by Dave Collins from NASA World Wind Java project. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1354 232f8b59-042b-4e1e-8c03-345bb8c30851 --- .../com/sun/opengl/util/texture/Texture.java | 44 +++++++++++++++++++--- .../com/sun/opengl/util/texture/spi/DDSImage.java | 36 ++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/classes/com/sun/opengl/util/texture/Texture.java b/src/classes/com/sun/opengl/util/texture/Texture.java index 3518d8c38..d634f66fb 100755 --- a/src/classes/com/sun/opengl/util/texture/Texture.java +++ b/src/classes/com/sun/opengl/util/texture/Texture.java @@ -41,6 +41,7 @@ import java.nio.*; import javax.media.opengl.*; import javax.media.opengl.glu.*; import com.sun.opengl.impl.*; +import com.sun.opengl.util.texture.spi.*; /** * Represents an OpenGL texture object. Contains convenience routines @@ -405,6 +406,7 @@ public class Texture { haveAutoMipmapGeneration = false; } + boolean expandingCompressedTexture = false; if (data.getMipmap() && !haveAutoMipmapGeneration) { // GLU always scales the texture's dimensions to be powers of // two. It also doesn't really matter exactly what the texture @@ -428,7 +430,8 @@ public class Texture { texWidth = imgWidth; texHeight = imgHeight; texTarget = GL.GL_TEXTURE_2D; - } else if (haveTexRect(gl)) { + } else if (haveTexRect(gl) && !data.isDataCompressed()) { + // GL_ARB_texture_rectangle does not work for compressed textures if (DEBUG) { System.err.println("Using GL_ARB_texture_rectangle"); } @@ -437,6 +440,25 @@ public class Texture { texHeight = imgHeight; texTarget = GL.GL_TEXTURE_RECTANGLE_ARB; } else { + // If we receive non-power-of-two compressed texture data and + // don't have true hardware support for compressed textures, we + // can fake this support by producing an empty "compressed" + // texture image, using glCompressedTexImage2D with that to + // allocate the texture, and glCompressedTexSubImage2D with the + // incoming data. + if (data.isDataCompressed()) { + if (data.getMipmapData() != null) { + + // We don't currently support expanding of compressed, + // mipmapped non-power-of-two textures to the nearest power + // of two; the obvious port of the non-mipmapped code didn't + // work + throw new GLException("Mipmapped non-power-of-two compressed textures only supported on OpenGL 2.0 hardware (GL_ARB_texture_non_power_of_two)"); + } + + expandingCompressedTexture = true; + } + if (DEBUG) { System.err.println("Expanding texture to power-of-two dimensions"); } @@ -491,6 +513,7 @@ public class Texture { for (int i = 0; i < mipmapData.length; i++) { if (data.isDataCompressed()) { // Need to use glCompressedTexImage2D directly to allocate and fill this image + // Avoid spurious memory allocation when possible gl.glCompressedTexImage2D(texTarget, i, data.getInternalFormat(), width, height, data.getBorder(), mipmapData[i].remaining(), mipmapData[i]); @@ -507,10 +530,21 @@ public class Texture { } } else { if (data.isDataCompressed()) { - // Need to use glCompressedTexImage2D directly to allocate and fill this image - gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(), - texWidth, texHeight, data.getBorder(), - data.getBuffer().capacity(), data.getBuffer()); + if (!expandingCompressedTexture) { + // Need to use glCompressedTexImage2D directly to allocate and fill this image + // Avoid spurious memory allocation when possible + gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(), + texWidth, texHeight, data.getBorder(), + data.getBuffer().capacity(), data.getBuffer()); + } else { + ByteBuffer buf = DDSImage.allocateBlankBuffer(texWidth, + texHeight, + data.getInternalFormat()); + gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(), + texWidth, texHeight, data.getBorder(), + buf.capacity(), buf); + updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight()); + } } else { if (data.getMipmap() && haveAutoMipmapGeneration) { // For now, only use hardware mipmapping for uncompressed 2D diff --git a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java index 52dbc25b1..835025b5c 100755 --- a/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java +++ b/src/classes/com/sun/opengl/util/texture/spi/DDSImage.java @@ -43,6 +43,9 @@ import java.io.*; import java.nio.*; import java.nio.channels.*; +import javax.media.opengl.*; +import com.sun.opengl.util.*; + /** A reader and writer for DirectDraw Surface (.dds) files, which are used to describe textures. These files can contain multiple mipmap levels in one file. This class is currently minimal and does not @@ -469,6 +472,39 @@ public class DDSImage { return buf.toString(); } + /** Allocates a temporary, empty ByteBuffer suitable for use in a + call to glCompressedTexImage2D. This is used by the Texture + class to expand non-power-of-two DDS compressed textures to + power-of-two sizes on hardware not supporting OpenGL 2.0 and the + NPOT texture extension. The specified OpenGL internal format + must be one of GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, or + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT. + */ + public static ByteBuffer allocateBlankBuffer(int width, + int height, + int openGLInternalFormat) { + int size = width * height; + switch (openGLInternalFormat) { + case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + size /= 2; + break; + + case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + break; + + default: + throw new IllegalArgumentException("Illegal OpenGL texture internal format " + + openGLInternalFormat); + } + if (size == 0) + size = 1; + return BufferUtil.newByteBuffer(size); + } + public void debugPrint() { PrintStream tty = System.err; tty.println("Compressed texture: " + isCompressed()); -- cgit v1.2.3