diff options
-rwxr-xr-x | src/classes/com/sun/opengl/util/j2d/TextRenderer.java | 143 | ||||
-rwxr-xr-x | src/classes/com/sun/opengl/util/j2d/TextureRenderer.java | 177 |
2 files changed, 230 insertions, 90 deletions
diff --git a/src/classes/com/sun/opengl/util/j2d/TextRenderer.java b/src/classes/com/sun/opengl/util/j2d/TextRenderer.java index 7f47c011a..0ad84c90c 100755 --- a/src/classes/com/sun/opengl/util/j2d/TextRenderer.java +++ b/src/classes/com/sun/opengl/util/j2d/TextRenderer.java @@ -262,26 +262,23 @@ public class TextRenderer { @throws GLException If an OpenGL context is not current when this method is called */ public void beginRendering(int width, int height) throws GLException { - if (DEBUG && !debugged) { - debug(); - } + beginRendering(true, width, height); + } - getBackingStore().beginOrthoRendering(width, height); - GL gl = GLU.getCurrentGL(); + /** Begins rendering of 2D text in 3D with this {@link TextRenderer + TextRenderer} into the current OpenGL drawable. Assumes the end + user is responsible for setting up the modelview and projection + matrices, and will render text using the {@link #draw3D draw3D} + method. This method pushes some OpenGL state bits, binds and + enables the internal OpenGL texture object, sets the texture + environment mode to GL_MODULATE, and changes the current color + to the last color set with this TextRenderer via {@link + #setColor setColor}. - if (!haveMaxSize) { - // Query OpenGL for the maximum texture size and set it in the - // RectanglePacker to keep it from expanding too large - int[] sz = new int[1]; - gl.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, sz, 0); - packer.setMaxSize(sz[0], sz[0]); - haveMaxSize = true; - } - - // Change texture environment mode to MODULATE - gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); - // Change text color to last saved - gl.glColor4f(r, g, b, a); + @throws GLException If an OpenGL context is not current when this method is called + */ + public void begin3DRendering() throws GLException { + beginRendering(false, 0, 0); } /** Changes the current color of this TextRenderer to the supplied @@ -320,6 +317,23 @@ public class TextRenderer { @throws GLException If an OpenGL context is not current when this method is called */ public void draw(String str, int x, int y) throws GLException { + draw3D(str, x, y, 0, 1); + } + + /** Draws the supplied String at the desired 3D location using the + renderer's current color. The baseline of the leftmost character + is placed at position (x, y, z) in the current coordinate system. + + @param str the string to draw + @param x the x coordinate at which to draw + @param y the y coordinate at which to draw + @param z the z coordinate at which to draw + @param scaleFactor a uniform scale factor applied to the width and height of the drawn rectangle + @throws GLException If an OpenGL context is not current when this method is called + */ + public void draw3D(String str, + float x, float y, float z, + float scaleFactor) { // Split up the string into space-separated pieces tokenize(str); int xOffset = 0; @@ -369,33 +383,39 @@ public class TextRenderer { TextData data = (TextData) rect.getUserData(); data.markUsed(); - // Align the leftmost point of the baseline to the (x, y) coordinate requested - renderer.drawOrthoRect(x - data.origin().x + xOffset, - y - (rect.h() - data.origin().y), - rect.x(), - renderer.getHeight() - rect.y() - rect.h(), - rect.w(), rect.h()); - xOffset += rect.w(); + // Align the leftmost point of the baseline to the (x, y, z) coordinate requested + renderer.draw3DRect(x - scaleFactor * (data.origin().x + xOffset), + y - scaleFactor * ((rect.h() - data.origin().y)), + z, + rect.x(), + renderer.getHeight() - rect.y() - rect.h(), + rect.w(), rect.h(), + scaleFactor); + xOffset += rect.w() * scaleFactor; } - xOffset += getSpaceWidth(); + xOffset += getSpaceWidth() * scaleFactor; } } /** Ends a render cycle with this {@link TextRenderer TextRenderer}. Restores the projection and modelview matrices as well as - several OpenGL state bits. + several OpenGL state bits. Should be paired with {@link + #beginRendering beginRendering}. @throws GLException If an OpenGL context is not current when this method is called */ public void endRendering() throws GLException { - getBackingStore().endOrthoRendering(); - if (++numRenderCycles >= CYCLES_PER_FLUSH) { - numRenderCycles = 0; - if (DEBUG) { - System.err.println("Clearing unused entries in endRendering()"); - } - clearUnusedEntries(); - } + endRendering(true); + } + + /** Ends a 3D render cycle with this {@link TextRenderer TextRenderer}. + Restores several OpenGL state bits. Should be paired with {@link + #begin3DRendering begin3DRendering}. + + @throws GLException If an OpenGL context is not current when this method is called + */ + public void end3DRendering() throws GLException { + endRendering(false); } /** Disposes of all resources this TextRenderer is using. It is not @@ -416,10 +436,13 @@ public class TextRenderer { // private static Rectangle2D normalize(Rectangle2D src) { - return new Rectangle2D.Double((int) Math.floor(src.getMinX()), - (int) Math.floor(src.getMinY()), - (int) Math.ceil(src.getWidth()), - (int) Math.ceil(src.getHeight())); + // Give ourselves a one-pixel boundary around each string in order + // to prevent bleeding of nearby Strings due to the fact that we + // use linear filtering + return new Rectangle2D.Double((int) Math.floor(src.getMinX() - 1), + (int) Math.floor(src.getMinY() - 1), + (int) Math.ceil(src.getWidth() + 2), + (int) Math.ceil(src.getHeight()) + 2); } private TextureRenderer getBackingStore() { @@ -454,6 +477,48 @@ public class TextRenderer { return cachedGraphics; } + private void beginRendering(boolean ortho, int width, int height) { + if (DEBUG && !debugged) { + debug(); + } + + if (ortho) { + getBackingStore().beginOrthoRendering(width, height); + } else { + getBackingStore().begin3DRendering(); + } + GL gl = GLU.getCurrentGL(); + + if (!haveMaxSize) { + // Query OpenGL for the maximum texture size and set it in the + // RectanglePacker to keep it from expanding too large + int[] sz = new int[1]; + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, sz, 0); + packer.setMaxSize(sz[0], sz[0]); + haveMaxSize = true; + } + + // Change texture environment mode to MODULATE + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); + // Change text color to last saved + gl.glColor4f(r, g, b, a); + } + + private void endRendering(boolean ortho) throws GLException { + if (ortho) { + getBackingStore().endOrthoRendering(); + } else { + getBackingStore().end3DRendering(); + } + if (++numRenderCycles >= CYCLES_PER_FLUSH) { + numRenderCycles = 0; + if (DEBUG) { + System.err.println("Clearing unused entries in endRendering()"); + } + clearUnusedEntries(); + } + } + private int getSpaceWidth() { if (spaceWidth < 0) { Graphics2D g = getGraphics2D(); diff --git a/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java b/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java index 976806db3..3670d3c51 100755 --- a/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java +++ b/src/classes/com/sun/opengl/util/j2d/TextureRenderer.java @@ -274,13 +274,14 @@ public class TextureRenderer { /** 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. Sets up the viewing - matrices, for orthographic rendering where the coordinates go + 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; disables the depth test and lighting; and enables the - texture in this renderer. {@link #endOrthoRendering} must be - used in conjunction with this method to restore all OpenGL - states. + 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 @@ -288,37 +289,24 @@ public class TextureRenderer { @throws GLException If an OpenGL context is not current when this method is called */ public void beginOrthoRendering(int width, int height) throws GLException { - GL gl = GLU.getCurrentGL(); - gl.glPushAttrib(GL.GL_ENABLE_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_TRANSFORM_BIT); - gl.glDisable(GL.GL_DEPTH_TEST); - gl.glDisable(GL.GL_CULL_FACE); - gl.glDisable(GL.GL_LIGHTING); - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPushMatrix(); - gl.glLoadIdentity(); - glu.gluOrtho2D(0, width, 0, height); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glEnable(GL.GL_BLEND); - gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA); - Texture texture = getTexture(); - texture.enable(); - texture.bind(); - gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); - 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); - } else { - texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); - texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); - } - } + beginRendering(true, width, height); + } + + /** 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); } /** Draws an orthographically projected rectangle containing all of @@ -360,6 +348,38 @@ public class TextureRenderer { 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 { GL gl = GLU.getCurrentGL(); Texture texture = getTexture(); TextureCoords coords = texture.getSubImageTexCoords(texturex, texturey, @@ -367,13 +387,13 @@ public class TextureRenderer { texturey + height); gl.glBegin(GL.GL_QUADS); gl.glTexCoord2f(coords.left(), coords.bottom()); - gl.glVertex3f(screenx, screeny, 0); + gl.glVertex3f(x, y, z); gl.glTexCoord2f(coords.right(), coords.bottom()); - gl.glVertex3f(screenx + width, screeny, 0); + gl.glVertex3f(x + width * scaleFactor, y, z); gl.glTexCoord2f(coords.right(), coords.top()); - gl.glVertex3f(screenx + width, screeny + height, 0); + gl.glVertex3f(x + width * scaleFactor, y + height * scaleFactor, z); gl.glTexCoord2f(coords.left(), coords.top()); - gl.glVertex3f(screenx, screeny + height, 0); + gl.glVertex3f(x, y + height * scaleFactor, z); gl.glEnd(); } @@ -386,22 +406,77 @@ public class TextureRenderer { @throws GLException If an OpenGL context is not current when this method is called */ public void endOrthoRendering() throws GLException { - GL gl = GLU.getCurrentGL(); - Texture texture = getTexture(); - texture.disable(); - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPopMatrix(); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPopMatrix(); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - gl.glPopAttrib(); + 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); } //---------------------------------------------------------------------- // Internals only below this point // + private void beginRendering(boolean ortho, int width, int height) { + GL gl = GLU.getCurrentGL(); + int attribBits = + GL.GL_ENABLE_BIT | (ortho ? (GL.GL_DEPTH_BUFFER_BIT | GL.GL_TRANSFORM_BIT) : 0); + gl.glPushAttrib(attribBits); + gl.glDisable(GL.GL_LIGHTING); + if (ortho) { + gl.glDisable(GL.GL_DEPTH_TEST); + gl.glDisable(GL.GL_CULL_FACE); + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glPushMatrix(); + gl.glLoadIdentity(); + glu.gluOrtho2D(0, width, 0, height); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glPushMatrix(); + gl.glLoadIdentity(); + } + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA); + Texture texture = getTexture(); + texture.enable(); + texture.bind(); + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); + 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); + } else { + texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + } + } + } + + private void endRendering(boolean ortho) { + GL gl = GLU.getCurrentGL(); + Texture texture = getTexture(); + texture.disable(); + if (ortho) { + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glPopMatrix(); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glPopMatrix(); + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glPopMatrix(); + } + gl.glPopAttrib(); + } + private void init(int width, int height) { // Discard previous BufferedImage if any if (image != null) { |