diff options
Diffstat (limited to 'src/classes/com/sun/opengl/util/awt/gl2/GL2TextureRenderer.java')
-rwxr-xr-x | src/classes/com/sun/opengl/util/awt/gl2/GL2TextureRenderer.java | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/src/classes/com/sun/opengl/util/awt/gl2/GL2TextureRenderer.java b/src/classes/com/sun/opengl/util/awt/gl2/GL2TextureRenderer.java new file mode 100755 index 000000000..54ff96648 --- /dev/null +++ b/src/classes/com/sun/opengl/util/awt/gl2/GL2TextureRenderer.java @@ -0,0 +1,701 @@ +/* + * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.sun.opengl.util.awt.gl2; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.image.*; + +import javax.media.opengl.*; +import javax.media.opengl.glu.*; +import javax.media.opengl.glu.gl2.*; +import com.sun.opengl.util.texture.*; +import com.sun.opengl.util.texture.spi.*; +import com.sun.opengl.util.texture.awt.*; +import com.sun.opengl.util.gl2.*; +import com.sun.opengl.util.awt.*; +import com.sun.opengl.util.awt.gl2.*; + +/** Provides the ability to render into an OpenGL {@link + com.sun.opengl.util.texture.Texture Texture} using the Java 2D + APIs. This renderer class uses an internal Java 2D image (of + unspecified type) for its backing store and flushes portions of + that image to an OpenGL texture on demand. The resulting OpenGL + texture can then be mapped on to a polygon for display. */ + +public class GL2TextureRenderer { + // For now, we supply only a BufferedImage back-end for this + // renderer. In theory we could use the Java 2D/JOGL bridge to fully + // accelerate the rendering paths, but there are restrictions on + // what work can be done where; for example, Graphics2D-related work + // must not be done on the Queue Flusher Thread, but JOGL's + // OpenGL-related work must be. This implies that the user's code + // would need to be split up into multiple callbacks run from the + // appropriate threads, which would be somewhat unfortunate. + + // Whether we have an alpha channel in the (RGB/A) backing store + private boolean alpha; + + // 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; + private boolean smoothingChanged; + + // The backing store itself + private BufferedImage image; + + private Texture texture; + private AWTTextureData textureData; + private boolean mustReallocateTexture; + private Rectangle dirtyRegion; + + private GLUgl2 glu = new GLUgl2(); + + // Current color + private float r = 1.0f; + private float g = 1.0f; + private float b = 1.0f; + private float a = 1.0f; + + /** Creates a new renderer with backing store of the specified width + and height. If <CODE>alpha</CODE> 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 + @param alpha whether to allocate an alpha channel for the texture + */ + public GL2TextureRenderer(int width, int height, boolean alpha) { + this(width, height, alpha, false); + } + + /** Creates a new renderer with backing store of the specified width + and height. If <CODE>alpha</CODE> is true, allocates an alpha channel in the + backing store image. If <CODE>mipmap</CODE> 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 GL2TextureRenderer(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 GL2TextureRenderer(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. No mipmap support is + requested. Internally, this associates a GL_INTENSITY OpenGL + texture with the backing store. */ + public static GL2TextureRenderer createAlphaOnlyRenderer(int width, int height) { + return createAlphaOnlyRenderer(width, height, false); + } + + /** Creates a new renderer with a special kind of backing store + which acts only as an alpha channel. If <CODE>mipmap</CODE> 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 GL2TextureRenderer createAlphaOnlyRenderer(int width, int height, boolean mipmap) { + return new GL2TextureRenderer(width, height, false, true, mipmap); + } + + /** Returns the width of the backing store of this renderer. + + @return the width of the backing store of this renderer + */ + public int getWidth() { + return image.getWidth(); + } + + /** Returns the height of the backing store of this renderer. + + @return the height of the backing store of this renderer + */ + public int getHeight() { + return image.getHeight(); + } + + /** Returns the size of the backing store of this renderer in a + newly-allocated {@link java.awt.Dimension Dimension} object. + + @return the size of the backing store of this renderer + */ + public Dimension getSize() { + return getSize(null); + } + + /** Returns the size of the backing store of this renderer. Uses the + {@link java.awt.Dimension Dimension} object if one is supplied, + or allocates a new one if null is passed. + + @param d a {@link java.awt.Dimension Dimension} object in which + to store the results, or null to allocate a new one + + @return the size of the backing store of this renderer + */ + public Dimension getSize(Dimension d) { + if (d == null) + d = new Dimension(); + d.setSize(image.getWidth(), image.getHeight()); + return d; + } + + /** Sets the size of the backing store of this renderer. This may + cause the OpenGL texture object associated with this renderer to + be invalidated; it is not recommended to cache this texture + object outside this class but to instead call {@link #getTexture + getTexture} when it is needed. + + @param width the new width of the backing store of this renderer + @param height the new height of the backing store of this renderer + @throws GLException If an OpenGL context is not current when this method is called + */ + public void setSize(int width, int height) throws GLException { + init(width, height); + } + + /** Sets the size of the backing store of this renderer. This may + cause the OpenGL texture object associated with this renderer to + be invalidated. + + @param d the new size of the backing store of this renderer + @throws GLException If an OpenGL context is not current when this method is called + */ + public void setSize(Dimension d) throws GLException { + setSize(d.width, d.height); + } + + /** Sets whether smoothing is enabled for the OpenGL texture; if so, + uses GL_LINEAR interpolation for the minification and + magnification filters. Defaults to true. Changes to this setting + will not take effect until the next call to {@link + #beginOrthoRendering beginOrthoRendering}. + + @param smoothing whether smoothing is enabled for the OpenGL texture + */ + public void setSmoothing(boolean smoothing) { + this.smoothing = smoothing; + smoothingChanged = true; + } + + /** Returns whether smoothing is enabled for the OpenGL texture; see + {@link #setSmoothing setSmoothing}. Defaults to true. + + @return whether smoothing is enabled for the OpenGL texture + */ + public boolean getSmoothing() { + return smoothing; + } + + /** Creates a {@link java.awt.Graphics2D Graphics2D} instance for + rendering to the backing store of this renderer. The returned + object should be disposed of using the normal {@link + java.awt.Graphics#dispose() Graphics.dispose()} method once it + is no longer being used. + + @return a new {@link java.awt.Graphics2D Graphics2D} object for + rendering into the backing store of this renderer + */ + public Graphics2D createGraphics() { + return image.createGraphics(); + } + + /** Returns the underlying Java 2D {@link java.awt.Image Image} + being rendered into. */ + public Image getImage() { + return image; + } + + /** Marks the given region of the TextureRenderer as dirty. This + region, and any previously set dirty regions, will be + automatically synchronized with the underlying Texture during + the next {@link #getTexture getTexture} operation, at which + point the dirty region will be cleared. It is not necessary for + an OpenGL context to be current when this method is called. + + @param x the x coordinate (in Java 2D coordinates -- relative to + upper left) of the region to update + @param y the y coordinate (in Java 2D coordinates -- relative to + upper left) of the region to update + @param width the width of the region to update + @param height the height of the region to update + */ + public void markDirty(int x, int y, int width, int height) { + Rectangle curRegion = new Rectangle(x, y, width, height); + if (dirtyRegion == null) { + dirtyRegion = curRegion; + } else { + dirtyRegion.add(curRegion); + } + } + + /** Returns the underlying OpenGL Texture object associated with + this renderer, synchronizing any dirty regions of the + TextureRenderer with the underlying OpenGL texture. + + @throws GLException If an OpenGL context is not current when this method is called + */ + public Texture getTexture() throws GLException { + if (dirtyRegion != null) { + sync(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height); + dirtyRegion = null; + } + + ensureTexture(); + return texture; + } + + /** Disposes all resources associated with this renderer. It is not + valid to use this renderer after calling this method. + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void dispose() throws GLException { + if (texture != null) { + texture.dispose(); + texture = null; + } + if (image != null) { + image.flush(); + image = null; + } + } + + /** Convenience method which assists in rendering portions of the + OpenGL texture to the screen, if the application intends to draw + them as a flat overlay on to the screen. Pushes OpenGL state + bits (GL_ENABLE_BIT, GL_DEPTH_BUFFER_BIT and GL_TRANSFORM_BIT); + disables the depth test, back-face culling, and lighting; + enables the texture in this renderer; and sets up the viewing + matrices for orthographic rendering where the coordinates go + from (0, 0) at the lower left to (width, height) at the upper + right. Equivalent to beginOrthoRendering(width, height, true). + {@link #endOrthoRendering} must be used in conjunction with this + method to restore all OpenGL states. + + @param width the width of the current on-screen OpenGL drawable + @param height the height of the current on-screen OpenGL drawable + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void beginOrthoRendering(int width, int height) throws GLException { + beginOrthoRendering(width, height, true); + } + + /** Convenience method which assists in rendering portions of the + OpenGL texture to the screen, if the application intends to draw + them as a flat overlay on to the screen. Pushes OpenGL state + bits (GL_ENABLE_BIT, GL_DEPTH_BUFFER_BIT and GL_TRANSFORM_BIT); + disables the depth test (if the "disableDepthTest" argument is + true), back-face culling, and lighting; enables the texture in + this renderer; and sets up the viewing matrices for orthographic + rendering where the coordinates go from (0, 0) at the lower left + to (width, height) at the upper right. {@link + #endOrthoRendering} must be used in conjunction with this method + to restore all OpenGL states. + + @param width the width of the current on-screen OpenGL drawable + @param height the height of the current on-screen OpenGL drawable + @param disableDepthTest whether the depth test should be disabled + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void beginOrthoRendering(int width, int height, boolean disableDepthTest) throws GLException { + beginRendering(true, width, height, disableDepthTest); + } + + /** Convenience method which assists in rendering portions of the + OpenGL texture to the screen as 2D quads in 3D space. Pushes + OpenGL state (GL_ENABLE_BIT); disables lighting; and enables the + texture in this renderer. Unlike {@link #beginOrthoRendering + beginOrthoRendering}, does not modify the depth test, back-face + culling, lighting, or the modelview or projection matrices. The + user is responsible for setting up the view matrices for correct + results of {@link #draw3DRect draw3DRect}. {@link + #end3DRendering} must be used in conjunction with this method to + restore all OpenGL states. + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void begin3DRendering() throws GLException { + beginRendering(false, 0, 0, false); + } + + /** Changes the color of the polygons, and therefore the drawn + images, this TextureRenderer produces. Use of this method is + optional. The TextureRenderer uses the GL_MODULATE texture + environment mode, which causes the portions of the rendered + texture to be multiplied by the color of the rendered + polygons. The polygon color can be varied to achieve effects + like tinting of the overall output or fading in and out by + changing the alpha of the color. <P> + + Each component ranges from 0.0f - 1.0f. The alpha component, if + used, does not need to be premultiplied into the color channels + as described in the documentation for {@link + com.sun.opengl.util.texture.Texture Texture}, although + premultiplied colors are used internally. The default color is + opaque white. + + @param r the red component of the new color + @param g the green component of the new color + @param b the blue component of the new color + @param a the alpha component of the new color, 0.0f = completely + transparent, 1.0f = completely opaque + @throws GLException If an OpenGL context is not current when this method is called + */ + public void setColor(float r, float g, float b, float a) throws GLException { + GL2 gl = GLUgl2.getCurrentGL2(); + this.r = r * a; + this.g = g * a; + this.b = b * a; + this.a = a; + + gl.glColor4f(this.r, this.g, this.b, this.a); + } + + private float[] compArray; + /** Changes the current color of this TextureRenderer to the + supplied one. The default color is opaque white. See {@link + #setColor(float,float,float,float) setColor} for more details. + + @param color the new color to use for rendering + @throws GLException If an OpenGL context is not current when this method is called + */ + public void setColor(Color color) throws GLException { + // Get color's RGBA components as floats in the range [0,1]. + if (compArray == null) { + compArray = new float[4]; + } + color.getRGBComponents(compArray); + setColor(compArray[0], compArray[1], compArray[2], compArray[3]); + } + + /** Draws an orthographically projected rectangle containing all of + the underlying texture to the specified location on the + screen. All (x, y) coordinates are specified relative to the + lower left corner of either the texture image or the current + OpenGL drawable. This method is equivalent to + <code>drawOrthoRect(screenx, screeny, 0, 0, getWidth(), + getHeight());</code>. + + @param screenx the on-screen x coordinate at which to draw the rectangle + @param screeny the on-screen y coordinate (relative to lower left) at + which to draw the rectangle + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void drawOrthoRect(int screenx, int screeny) throws GLException { + drawOrthoRect(screenx, screeny, 0, 0, getWidth(), getHeight()); + } + + /** Draws an orthographically projected rectangle of the underlying + texture to the specified location on the screen. All (x, y) + coordinates are specified relative to the lower left corner of + either the texture image or the current OpenGL drawable. + + @param screenx the on-screen x coordinate at which to draw the rectangle + @param screeny the on-screen y coordinate (relative to lower left) at + which to draw the rectangle + @param texturex the x coordinate of the pixel in the texture of + the lower left portion of the rectangle to draw + @param texturey the y coordinate of the pixel in the texture + (relative to lower left) of the lower left portion of the + rectangle to draw + @param width the width of the rectangle to draw + @param height the height of the rectangle to draw + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void drawOrthoRect(int screenx, int screeny, + int texturex, int texturey, + int width, int height) throws GLException { + draw3DRect(screenx, screeny, 0, texturex, texturey, width, height, 1); + } + + /** Draws a rectangle of the underlying texture to the specified 3D + location. In the current coordinate system, the lower left + corner of the rectangle is placed at (x, y, z), and the upper + right corner is placed at (x + width * scaleFactor, y + height * + scaleFactor, z). The lower left corner of the sub-rectangle of + the texture is (texturex, texturey) and the upper right corner + is (texturex + width, texturey + height). For back-face culling + purposes, the rectangle is drawn with counterclockwise + orientation of the vertices when viewed from the front. + + @param x the x coordinate at which to draw the rectangle + @param y the y coordinate at which to draw the rectangle + @param z the z coordinate at which to draw the rectangle + @param texturex the x coordinate of the pixel in the texture of + the lower left portion of the rectangle to draw + @param texturey the y coordinate of the pixel in the texture + (relative to lower left) of the lower left portion of the + rectangle to draw + @param width the width in texels of the rectangle to draw + @param height the height in texels of the rectangle to draw + @param scaleFactor the scale factor to apply (multiplicatively) + to the size of the drawn rectangle + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void draw3DRect(float x, float y, float z, + int texturex, int texturey, + int width, int height, + float scaleFactor) throws GLException { + GL2 gl = GLUgl2.getCurrentGL2(); + Texture texture = getTexture(); + TextureCoords coords = texture.getSubImageTexCoords(texturex, texturey, + texturex + width, + texturey + height); + gl.glBegin(GL2.GL_QUADS); + gl.glTexCoord2f(coords.left(), coords.bottom()); + gl.glVertex3f(x, y, z); + gl.glTexCoord2f(coords.right(), coords.bottom()); + gl.glVertex3f(x + width * scaleFactor, y, z); + gl.glTexCoord2f(coords.right(), coords.top()); + gl.glVertex3f(x + width * scaleFactor, y + height * scaleFactor, z); + gl.glTexCoord2f(coords.left(), coords.top()); + gl.glVertex3f(x, y + height * scaleFactor, z); + gl.glEnd(); + } + + /** Convenience method which assists in rendering portions of the + OpenGL texture to the screen, if the application intends to draw + them as a flat overlay on to the screen. Must be used if {@link + #beginOrthoRendering} is used to set up the rendering stage for + this overlay. + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void endOrthoRendering() throws GLException { + endRendering(true); + } + + /** Convenience method which assists in rendering portions of the + OpenGL texture to the screen as 2D quads in 3D space. Must be + used if {@link #begin3DRendering} is used to set up the + rendering stage for this overlay. + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void end3DRendering() throws GLException { + 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 + // + + private void beginRendering(boolean ortho, int width, int height, boolean disableDepthTestForOrtho) { + GL2 gl = GLUgl2.getCurrentGL2(); + int attribBits = + GL2.GL_ENABLE_BIT | GL2.GL_TEXTURE_BIT | GL2.GL_COLOR_BUFFER_BIT | + (ortho ? (GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_TRANSFORM_BIT) : 0); + gl.glPushAttrib(attribBits); + gl.glDisable(GL2.GL_LIGHTING); + if (ortho) { + if (disableDepthTestForOrtho) { + gl.glDisable(GL2.GL_DEPTH_TEST); + } + gl.glDisable(GL2.GL_CULL_FACE); + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glPushMatrix(); + gl.glLoadIdentity(); + glu.gluOrtho2D(0, width, 0, height); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glMatrixMode(GL2.GL_TEXTURE); + gl.glPushMatrix(); + gl.glLoadIdentity(); + } + gl.glEnable(GL2.GL_BLEND); + gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE_MINUS_SRC_ALPHA); + Texture texture = getTexture(); + texture.enable(); + texture.bind(); + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE); + // Change polygon color to last saved + gl.glColor4f(r, g, b, a); + if (smoothingChanged) { + smoothingChanged = false; + if (smoothing) { + texture.setTexParameteri(GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR); + if (mipmap) { + texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR_MIPMAP_LINEAR); + } else { + texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR); + } + } else { + texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); + texture.setTexParameteri(GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); + } + } + } + + private void endRendering(boolean ortho) { + GL2 gl = GLUgl2.getCurrentGL2(); + Texture texture = getTexture(); + texture.disable(); + if (ortho) { + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glPopMatrix(); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPopMatrix(); + gl.glMatrixMode(GL2.GL_TEXTURE); + gl.glPopMatrix(); + } + gl.glPopAttrib(); + } + + private void init(int width, int height) { + // Discard previous BufferedImage if any + if (image != null) { + image.flush(); + image = null; + } + + // Infer the internal format if not an intensity texture + int internalFormat = (intensity ? GL2.GL_INTENSITY : 0); + int imageType = + (intensity ? BufferedImage.TYPE_BYTE_GRAY : + (alpha ? BufferedImage.TYPE_INT_ARGB_PRE : BufferedImage.TYPE_INT_RGB)); + image = new BufferedImage(width, height, imageType); + // Always realllocate the TextureData associated with this + // 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 AWTTextureData(internalFormat, 0, mipmap, image); + // For now, always reallocate the underlying OpenGL texture when + // the backing store size changes + mustReallocateTexture = true; + } + + /** Synchronizes the specified region of the backing store down to + the underlying OpenGL texture. If {@link #markDirty markDirty} + is used instead to indicate the regions that are out of sync, + this method does not need to be called. + + @param x the x coordinate (in Java 2D coordinates -- relative to + upper left) of the region to update + @param y the y coordinate (in Java 2D coordinates -- relative to + upper left) of the region to update + @param width the width of the region to update + @param height the height of the region to update + + @throws GLException If an OpenGL context is not current when this method is called + */ + private void sync(int x, int y, int width, int height) throws GLException { + // Force allocation if necessary + boolean canSkipUpdate = ensureTexture(); + + if (!canSkipUpdate) { + // Update specified region. + // NOTE that because BufferedImage-based TextureDatas now don't + // do anything to their contents, the coordinate systems for + // OpenGL and Java 2D actually line up correctly for + // updateSubImage calls, so we don't need to do any argument + // conversion here (i.e., flipping the Y coordinate). + texture.updateSubImage(textureData, 0, x, y, x, y, width, height); + } + } + + // Returns true if the texture was newly allocated, false if not + private boolean ensureTexture() { + if (mustReallocateTexture) { + if (texture != null) { + texture.dispose(); + texture = null; + } + mustReallocateTexture = false; + } + + if (texture == null) { + texture = AWTTextureReader.newTexture(textureData); + if (mipmap && !texture.isUsingAutoMipmapGeneration()) { + // Only try this once + texture.dispose(); + mipmap = false; + textureData.setMipmap(false); + texture = AWTTextureReader.newTexture(textureData); + } + + if (!smoothing) { + // The TextureIO classes default to GL_LINEAR filtering + texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); + texture.setTexParameteri(GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); + } + return true; + } + + return false; + } +} |