From d1c3191328fe9d1c15b1ac27cf0f0a05b176c300 Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Sun, 8 Apr 2007 15:35:31 +0000 Subject: Added automatic mipmap generation support via GL_GENERATE_MIPMAP texture parameter to Texture class. Exposed this support up through the TextureRenderer and TextRenderer classes. Tested by temporarily enabling mipmap support for TextCube demo; no visual improvement, however, so left it disabled for now. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1194 232f8b59-042b-4e1e-8c03-345bb8c30851 --- .../com/sun/opengl/util/j2d/TextRenderer.java | 68 +++++++++++++++++++--- .../com/sun/opengl/util/j2d/TextureRenderer.java | 68 +++++++++++++++++++--- .../com/sun/opengl/util/texture/Texture.java | 65 ++++++++++++++++++--- 3 files changed, 179 insertions(+), 22 deletions(-) diff --git a/src/classes/com/sun/opengl/util/j2d/TextRenderer.java b/src/classes/com/sun/opengl/util/j2d/TextRenderer.java index d25888be2..468590b7d 100755 --- a/src/classes/com/sun/opengl/util/j2d/TextRenderer.java +++ b/src/classes/com/sun/opengl/util/j2d/TextRenderer.java @@ -113,6 +113,9 @@ public class TextRenderer { private boolean antialiased; private boolean useFractionalMetrics; + // Whether we're attempting to use automatic mipmap generation support + private boolean mipmap; + private RectanglePacker packer; private boolean haveMaxSize; private RenderDelegate renderDelegate; @@ -227,15 +230,30 @@ public class TextRenderer { @param font the font to render with */ public TextRenderer(Font font) { - this(font, false, false); + this(font, false, false, null, false); + } + + /** Creates a new TextRenderer with the given font, using no + antialiasing or fractional metrics, and the default + RenderDelegate. If mipmap is true, attempts to use + OpenGL's automatic mipmap generation for better smoothing when + rendering the TextureRenderer's contents at a distance. + Equivalent to TextRenderer(font, false, false). + + @param font the font to render with + @param mipmap whether to attempt use of automatic mipmap generation + */ + public TextRenderer(Font font, boolean mipmap) { + this(font, false, false, null, mipmap); } /** Creates a new TextRenderer with the given Font, specified font properties, and default RenderDelegate. The antialiased and useFractionalMetrics flags provide control over the same properties at the Java 2D - level. Equivalent to TextRenderer(font, antialiased, - useFractionalMetrics, null). + level. No mipmap support is requested. Equivalent to + TextRenderer(font, antialiased, useFractionalMetrics, + null). @param font the font to render with @param antialiased whether to use antialiased fonts @@ -245,7 +263,7 @@ public class TextRenderer { public TextRenderer(Font font, boolean antialiased, boolean useFractionalMetrics) { - this(font, antialiased, useFractionalMetrics, null); + this(font, antialiased, useFractionalMetrics, null, false); } /** Creates a new TextRenderer with the given Font, specified font @@ -253,7 +271,7 @@ public class TextRenderer { antialiased and useFractionalMetrics flags provide control over the same properties at the Java 2D level. The renderDelegate provides more control - over the text rendered. + over the text rendered. No mipmap support is requested. @param font the font to render with @param antialiased whether to use antialiased fonts @@ -266,9 +284,35 @@ public class TextRenderer { boolean antialiased, boolean useFractionalMetrics, RenderDelegate renderDelegate) { + this(font, antialiased, useFractionalMetrics, renderDelegate, false); + } + + /** Creates a new TextRenderer with the given Font, specified font + properties, and given RenderDelegate. The + antialiased and useFractionalMetrics + flags provide control over the same properties at the Java 2D + level. The renderDelegate provides more control + over the text rendered. If mipmap is true, attempts + to use OpenGL's automatic mipmap generation for better smoothing + when rendering the TextureRenderer's contents at a distance. + + @param font the font to render with + @param antialiased whether to use antialiased fonts + @param useFractionalMetrics whether to use fractional font + metrics at the Java 2D level + @param renderDelegate the render delegate to use to draw the + text's bitmap, or null to use the default one + @param mipmap whether to attempt use of automatic mipmap generation + */ + public TextRenderer(Font font, + boolean antialiased, + boolean useFractionalMetrics, + RenderDelegate renderDelegate, + boolean mipmap) { this.font = font; this.antialiased = antialiased; this.useFractionalMetrics = useFractionalMetrics; + this.mipmap = mipmap; // FIXME: consider adjusting the size based on font size // (it will already automatically resize if necessary) @@ -631,6 +675,15 @@ public class TextRenderer { } needToResetColor = false; } + + // Disable future attempts to use mipmapping if TextureRenderer + // doesn't support it + if (mipmap && !getBackingStore().isUsingAutoMipmapGeneration()) { + if (DEBUG) { + System.err.println("Disabled mipmapping in TextRenderer"); + } + mipmap = false; + } } private void endRendering(boolean ortho) throws GLException { @@ -741,10 +794,11 @@ public class TextRenderer { // store (i.e., non-default Paint, foreground color, etc.), but // for now, let's just be more efficient TextureRenderer renderer; + if (renderDelegate.intensityOnly()) { - renderer = TextureRenderer.createAlphaOnlyRenderer(w, h); + renderer = TextureRenderer.createAlphaOnlyRenderer(w, h, mipmap); } else { - renderer = new TextureRenderer(w, h, true); + renderer = new TextureRenderer(w, h, true, mipmap); } if (DEBUG) { System.err.println(" TextRenderer allocating backing store " + w + " x " + h); diff --git a/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java b/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java index be4b8b629..4ca3d03e0 100755 --- a/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java +++ b/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java @@ -73,6 +73,9 @@ public class TextureRenderer { // Whether we're using only a GL_INTENSITY backing store private boolean intensity; + // Whether we're attempting to use automatic mipmap generation support + private boolean mipmap; + // Whether smoothing is enabled for the OpenGL texture (switching // between GL_LINEAR and GL_NEAREST filtering) private boolean smoothing = true; @@ -95,8 +98,9 @@ public class TextureRenderer { private float a = 1.0f; /** Creates a new renderer with backing store of the specified width - and height. If alpha is true, allocates an alpha channel in the - backing store image. + and height. If alpha is true, allocates an alpha + channel in the backing store image. No mipmap support is + requested. @param width the width of the texture to render into @param height the height of the texture to render into @@ -106,19 +110,46 @@ public class TextureRenderer { this(width, height, alpha, false); } + /** Creates a new renderer with backing store of the specified width + and height. If alpha is true, allocates an alpha channel in the + backing store image. If mipmap is true, attempts to use OpenGL's + automatic mipmap generation for better smoothing when rendering + the TextureRenderer's contents at a distance. + + @param width the width of the texture to render into + @param height the height of the texture to render into + @param alpha whether to allocate an alpha channel for the texture + @param mipmap whether to attempt use of automatic mipmap generation + */ + public TextureRenderer(int width, int height, boolean alpha, boolean mipmap) { + this(width, height, alpha, false, mipmap); + } + // Internal constructor to avoid confusion since alpha only makes // sense when intensity is not set - private TextureRenderer(int width, int height, boolean alpha, boolean intensity) { + private TextureRenderer(int width, int height, boolean alpha, boolean intensity, boolean mipmap) { this.alpha = alpha; this.intensity = intensity; + this.mipmap = mipmap; init(width, height); } /** Creates a new renderer with a special kind of backing store - which acts only as an alpha channel. Internally, this associates - a GL_INTENSITY OpenGL texture with the backing store. */ + which acts only as an alpha channel. No mipmap support is + requested. Internally, this associates a GL_INTENSITY OpenGL + texture with the backing store. */ public static TextureRenderer createAlphaOnlyRenderer(int width, int height) { - return new TextureRenderer(width, height, false, true); + return createAlphaOnlyRenderer(width, height, false); + } + + /** Creates a new renderer with a special kind of backing store + which acts only as an alpha channel. If mipmap is + true, attempts to use OpenGL's automatic mipmap generation for + better smoothing when rendering the TextureRenderer's contents + at a distance. Internally, this associates a GL_INTENSITY OpenGL + texture with the backing store. */ + public static TextureRenderer createAlphaOnlyRenderer(int width, int height, boolean mipmap) { + return new TextureRenderer(width, height, false, true, mipmap); } /** Returns the width of the backing store of this renderer. @@ -504,6 +535,15 @@ public class TextureRenderer { endRendering(false); } + /** Indicates whether automatic mipmap generation is in use for this + TextureRenderer. The result of this method may change from true + to false if it is discovered during allocation of the + TextureRenderer's backing store that automatic mipmap generation + is not supported at the OpenGL level. */ + public boolean isUsingAutoMipmapGeneration() { + return mipmap; + } + //---------------------------------------------------------------------- // Internals only below this point // @@ -542,8 +582,12 @@ public class TextureRenderer { if (smoothingChanged) { smoothingChanged = false; if (smoothing) { - texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + if (mipmap) { + texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); + } else { + texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + } } else { texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); @@ -583,7 +627,7 @@ public class TextureRenderer { // BufferedImage; it's just a reference to the contents but we // need it in order to update sub-regions of the underlying // texture - textureData = new TextureData(internalFormat, 0, false, image); + textureData = new TextureData(internalFormat, 0, mipmap, image); // For now, always reallocate the underlying OpenGL texture when // the backing store size changes mustReallocateTexture = true; @@ -630,6 +674,14 @@ public class TextureRenderer { if (texture == null) { texture = TextureIO.newTexture(textureData); + if (mipmap && !texture.isUsingAutoMipmapGeneration()) { + // Only try this once + texture.dispose(); + mipmap = false; + textureData.setMipmap(false); + texture = TextureIO.newTexture(textureData); + } + if (!smoothing) { // The TextureIO classes default to GL_LINEAR filtering texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); diff --git a/src/classes/com/sun/opengl/util/texture/Texture.java b/src/classes/com/sun/opengl/util/texture/Texture.java index 9ceff7cd8..85c2da52e 100755 --- a/src/classes/com/sun/opengl/util/texture/Texture.java +++ b/src/classes/com/sun/opengl/util/texture/Texture.java @@ -133,6 +133,9 @@ public class Texture { /** Indicates whether the TextureData requires a vertical flip of the texture coords. */ private boolean mustFlipVertically; + /** Indicates whether we're using automatic mipmap generation + support (GL_GENERATE_MIPMAP). */ + private boolean usingAutoMipmapGeneration; /** The texture coordinates corresponding to the entire image. */ private TextureCoords coords; @@ -358,9 +361,10 @@ public class Texture { /** * Indicates whether this texture's texture coordinates must be * flipped vertically in order to properly display the texture. This - * is handled automatically by {@link #getImageTexCoords} and {@link - * #getSubImageTexCoords}, but applications may generate or - * otherwise produce texture coordinates which must be corrected. + * is handled automatically by {@link #getImageTexCoords + * getImageTexCoords} and {@link #getSubImageTexCoords + * getSubImageTexCoords}, but applications may generate or otherwise + * produce texture coordinates which must be corrected. */ public boolean getMustFlipVertically() { return mustFlipVertically; @@ -384,7 +388,12 @@ public class Texture { int newTarget = 0; - if (data.getMipmap()) { + // See whether we have automatic mipmap generation support + boolean haveAutoMipmapGeneration = + (gl.isExtensionAvailable("GL_VERSION_1_4") || + gl.isExtensionAvailable("GL_SGIS_generate_mipmap")); + + 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 // width and height are because the texture coords are always @@ -457,7 +466,7 @@ public class Texture { } } - if (data.getMipmap()) { + if (data.getMipmap() && !haveAutoMipmapGeneration) { int[] align = new int[1]; gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment()); @@ -504,6 +513,15 @@ public class Texture { texWidth, texHeight, data.getBorder(), data.getBuffer().capacity(), data.getBuffer()); } else { + if (data.getMipmap() && haveAutoMipmapGeneration) { + // For now, only use hardware mipmapping for uncompressed 2D + // textures where the user hasn't explicitly specified + // mipmap data; don't know about interactions between + // GL_GENERATE_MIPMAP and glCompressedTexImage2D + gl.glTexParameteri(newTarget, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); + usingAutoMipmapGeneration = true; + } + gl.glTexImage2D(newTarget, 0, data.getInternalFormat(), texWidth, texHeight, data.getBorder(), data.getPixelFormat(), data.getPixelType(), null); @@ -526,7 +544,12 @@ public class Texture { /** * Updates a subregion of the content area of this texture using the - * given data. Only updates the specified mipmap level and does not + * given data. If automatic mipmap generation is in use (see {@link + * #isUsingAutoMipmapGeneration isUsingAutoMipmapGeneration}), + * updates to the base (level 0) mipmap will cause the lower-level + * mipmaps to be regenerated, and updates to other mipmap levels + * will be ignored. Otherwise, if automatic mipmap generation is not + * in use, 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 @@ -542,12 +565,22 @@ public class Texture { * OpenGL-related errors occurred */ public void updateSubImage(TextureData data, int mipmapLevel, int x, int y) throws GLException { + if (usingAutoMipmapGeneration && mipmapLevel != 0) { + // When we're using mipmap generation via GL_GENERATE_MIPMAP, we + // don't need to update other mipmap levels + return; + } updateSubImageImpl(data, target, mipmapLevel, x, y, 0, 0, data.getWidth(), data.getHeight()); } /** * Updates a subregion of the content area of this texture using the - * specified sub-region of the given data. Only updates the + * specified sub-region of the given data. If automatic mipmap + * generation is in use (see {@link #isUsingAutoMipmapGeneration + * isUsingAutoMipmapGeneration}), updates to the base (level 0) + * mipmap will cause the lower-level mipmaps to be regenerated, and + * updates to other mipmap levels will be ignored. Otherwise, if + * automatic mipmap generation is not in use, only updates the * specified mipmap level and does not re-generate mipmaps if they * were originally produced or loaded. This method is only supported * for uncompressed TextureData sources. @@ -577,6 +610,11 @@ public class Texture { if (data.isDataCompressed()) { throw new GLException("updateSubImage specifying a sub-rectangle is not supported for compressed TextureData"); } + if (usingAutoMipmapGeneration && mipmapLevel != 0) { + // When we're using mipmap generation via GL_GENERATE_MIPMAP, we + // don't need to update other mipmap levels + return; + } updateSubImageImpl(data, target, mipmapLevel, dstx, dsty, srcx, srcy, width, height); } @@ -692,6 +730,19 @@ public class Texture { return estimatedMemorySize; } + /** Indicates whether this Texture is using automatic mipmap + generation (via the OpenGL texture parameter + GL_GENERATE_MIPMAP). This will automatically be used when + mipmapping is requested via the TextureData and either OpenGL + 1.4 or the GL_SGIS_generate_mipmap extension is available. If + so, updates to the base image (mipmap level 0) will + automatically propagate down to the lower mipmap levels. Manual + updates of the mipmap data at these lower levels will be + ignored. */ + public boolean isUsingAutoMipmapGeneration() { + return usingAutoMipmapGeneration; + } + //---------------------------------------------------------------------- // Internals only below this point // -- cgit v1.2.3