From 208b84ae11288b4edd190364528289240303cb5d Mon Sep 17 00:00:00 2001 From: eteq Date: Wed, 7 Feb 2007 11:10:38 +0000 Subject: Re-vamped internals of FontDrawer class, improved FontDrawerDemo, and changed FontDrawer to use an enum for specifying normal calculations git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/joglutils/trunk@43 83d24430-9974-4f80-8418-2cc3294053b9 --- src/net/java/joglutils/jogltext/FontDrawer.java | 220 ++++++++++++++++++------ 1 file changed, 170 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/net/java/joglutils/jogltext/FontDrawer.java b/src/net/java/joglutils/jogltext/FontDrawer.java index d50e1a8..1bf148b 100644 --- a/src/net/java/joglutils/jogltext/FontDrawer.java +++ b/src/net/java/joglutils/jogltext/FontDrawer.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2006 Erik Tollerud (erik.tollerud@gmail.com) 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. - * + * * The names of Erik Tollerud, Davide Raccagni, Sun Microsystems, Inc. or the names of * contributors may not 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 @@ -23,12 +23,12 @@ * SUN MICROSYSTEMS, INC. ("SUN"), AND SUN'S 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 ERIK - * TOLLERUD, SUN, OR SUN'S LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT + * TOLLERUD, SUN, OR SUN'S 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 ERIK * TOLLERUD OR 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. @@ -52,27 +52,45 @@ import javax.media.opengl.glu.*; */ public class FontDrawer { + public enum NormalMode {NONE, FLAT, AVERAGED}; + private Font font; private float depth; private boolean edgeOnly; - private boolean flatNorm; + private NormalMode normalMode; + /** + * Intstantiates a new FontDrawer initially rendering in the specified font. + * @param font the initial font for this FontDrawer + */ public FontDrawer(Font font) { this.font = font; depth = 0; edgeOnly = false; - flatNorm = true; + normalMode = NormalMode.FLAT; } + /** + * Specifies which font to render with this FontDrawer + * @param font a font to use for rendering + */ public void setFont(Font font) { this.font = font; } + /** + * Retrieves the Font currently associated with this FontDrawer + * @return the Font in which this object renders strings + */ public Font getFont() { return this.font; } + /** + * Determines how long the sides of the rendered text is. In the special case of 0, the rendering is 2D. + * @param depth specifies the z-size of the rendered 3D text. Negative numbers will be set to 0. + */ public void setDepth(float depth) { if (depth <= 0) this.depth = 0; @@ -80,47 +98,126 @@ public class FontDrawer { this.depth = depth; } + /** + * Retrieves the z-depth used for this FontDrawer's text rendering. + * @return the z-depth of the rendered 3D text. + */ public float getDepth() { return this.depth; } + /** + * Sets if the text should be rendered as filled polygons or wireframe. + * @param fill if true, uses filled polygons, if false, renderings are wireframe. + */ public void setFill(boolean fill) { this.edgeOnly = !fill; } + /** + * Determines if the text is being rendered as filled polygons or wireframes. + * @return if true, uses filled polygons, if false, renderings are wireframe. + */ public boolean isFill() { return !this.edgeOnly; } - public void setFlatNormals( boolean flat ) { - this.flatNorm = flat; + /** + * Sets technique for rendering Normals. Available options: + * None: Performs no calls to glNormal* - best performance + * Flat: Computes the normal as pointing straight away from the text face. + * Averaged: Determines side edge normals as the average direction of the two sides (smoother shading). Faces are still flat. + * + * @param mode the mode to render in. Default is flat. + */ + public void setNormal( NormalMode mode ) { + this.normalMode = mode; } - public boolean isFlatNormals() { - return this.flatNorm; + /** + * Determines which normal-calculation technique is being used. + * @see setNormal + * @return the normal technique for this FontDrawer. + */ + public NormalMode getNormal() { + return this.normalMode; } + /** + * Renders a string into the specified GL object, starting at the (0,0,0) point in OpenGL coordinates. + * Note that this creates a new GLU instance everytime it is called, which will negatively impact performance. + * + * @param str the string to render. + * @param gl the OpenGL context in which to render the text. + */ + public void drawString(String str, GL gl) { + drawString(str,new GLU(),gl); + } + + /** + * Renders a string into the specified GL object, starting at the (0,0,0) point in OpenGL coordinates. + * + * @param str the string to render. + * @param glu a GLU instance to use for the text rendering (provided to prevent continuous re-instantiation of a GLU object) + * @param gl the OpenGL context in which to render the text. + */ public void drawString(String str, GLU glu, GL gl) { GlyphVector gv = font.createGlyphVector( new FontRenderContext(new AffineTransform(), true, true), new StringCharacterIterator(str)); GeneralPath gp = (GeneralPath)gv.getOutline(); PathIterator pi = gp.getPathIterator(AffineTransform.getScaleInstance(1.0, -1.0), 1.0f); - gl.glNormal3i(0,0,-1); + + if (this.normalMode != NormalMode.NONE) + gl.glNormal3f(0,0,-1.0f); tesselateFace(glu, gl, pi, pi.getWindingRule(), this.edgeOnly); if (this.depth != 0.0) { pi = gp.getPathIterator(AffineTransform.getScaleInstance(1.0, -1.0), 1.0f); - gl.glNormal3i(0,0,1); + if (this.normalMode != NormalMode.NONE) + gl.glNormal3f(0,0,1.0f); tesselateFace(glu, gl, pi, pi.getWindingRule(), this.edgeOnly, this.depth); pi = gp.getPathIterator(AffineTransform.getScaleInstance(1.0, -1.0), 1.0f); - if (this.flatNorm) - drawSidesFlatNorm(gl,pi,this.edgeOnly,this.depth); - else - drawSidesAvgNorm(gl,pi,this.edgeOnly,this.depth); + switch (this.normalMode) { + //TODO: add diagonal corner/VBO technique + case NONE: + drawSidesNoNorm(gl,pi,this.edgeOnly,this.depth); + break; + case FLAT: + drawSidesFlatNorm(gl,pi,this.edgeOnly,this.depth); + break; + case AVERAGED: + drawSidesAvgNorm(gl,pi,this.edgeOnly,this.depth); + break; + } } + } + /** + * Renders a string into the specified GL object, starting at the (xOff,yOff,zOff) point in OpenGL coordinates. + * Note that this creates a new GLU instance everytime it is called, which will negatively impact performance. + * + * @param xOff the distance to translate the text in the x-direction + * @param yOff the distance to translate the text in the y-direction + * @param zOff the distance to translate the text in the z-direction + * @param str the string to render. + * @param gl the OpenGL context in which to render the text. + */ + public void drawString(String str, GL gl, float xOff, float yOff, float zOff) { + drawString(str,new GLU(),gl,xOff,yOff,zOff); + } + + /** + * Renders a string into the specified GL object, starting at the (xOff,yOff,zOff) point in OpenGL coordinates. + * + * @param xOff the distance to translate the text in the x-direction + * @param yOff the distance to translate the text in the y-direction + * @param zOff the distance to translate the text in the z-direction + * @param str the string to render. + * @param glu a GLU instance to use for the text rendering (provided to prevent continuous re-instantiation of a GLU object) + * @param gl the OpenGL context in which to render the text. + */ public void drawString(String str, GLU glu, GL gl, float xOff, float yOff, float zOff) { gl.glPushAttrib(GL.GL_TRANSFORM_BIT); gl.glMatrixMode(GL.GL_MODELVIEW); @@ -185,9 +282,51 @@ public class FontDrawer { glu.gluDeleteTess(tess); } + private void drawSidesNoNorm(GL gl, PathIterator pi, boolean justBoundary,float tessZ) { + //TODO: texture coords + + if (justBoundary) + gl.glPolygonMode(GL.GL_FRONT_AND_BACK,GL.GL_LINE); + else + gl.glPolygonMode(GL.GL_FRONT_AND_BACK,GL.GL_FILL); + + for(float[] coords = new float[6];!pi.isDone();pi.next()) { + float[] currRender = new float[3]; + switch(pi.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + gl.glBegin(GL.GL_QUAD_STRIP); + currRender[0] = coords[0]; + currRender[1] = coords[1]; + currRender[2] = 0; + gl.glVertex3fv(currRender,0); + currRender[2] = tessZ; + gl.glVertex3fv(currRender,0); + break; + case PathIterator.SEG_LINETO: + currRender[0] = coords[0]; + currRender[1] = coords[1]; + currRender[2] = 0; + gl.glVertex3fv(currRender,0); + currRender[2] = tessZ; + gl.glVertex3fv(currRender,0); + break; + case PathIterator.SEG_CLOSE: + currRender[0] = coords[0]; + currRender[1] = coords[1]; + currRender[2] = 0; + gl.glVertex3fv(currRender,0); + currRender[2] = tessZ; + gl.glVertex3fv(currRender,0); + gl.glEnd(); + break; + default: + throw new JogltextException("PathIterator segment not SEG_MOVETO, SEG_LINETO, SEG_CLOSE; Inappropriate font."); + } + } + } + private void drawSidesFlatNorm(GL gl, PathIterator pi, boolean justBoundary,float tessZ) { - //TODO: work out texture coords - //TODO:work out double vs. float + //TODO: texture coords if (justBoundary) gl.glPolygonMode(GL.GL_FRONT_AND_BACK,GL.GL_LINE); @@ -234,15 +373,16 @@ public class FontDrawer { gl.glEnd(); break; default: - throw new JogltextException("PathIterator segment not SEG_MOVETO, SEG_LINETO, SEG_CLOSE"); + throw new JogltextException("PathIterator segment not SEG_MOVETO, SEG_LINETO, SEG_CLOSE; Inappropriate font."); } } } private void drawSidesAvgNorm(GL gl, PathIterator pi, boolean justBoundary,float tessZ) { - //TODO: work out texture coords - //TODO: improve performance + //TODO: improve performance with some form of caching? + //TODO: texture coords + //TODO: check last coord - might not quite be correct? if (justBoundary) gl.glPolygonMode(GL.GL_FRONT_AND_BACK,GL.GL_LINE); @@ -253,8 +393,6 @@ public class FontDrawer { float[] firstCoord = null; float[] secondCoord = null; float[] thirdCoord = null; - float[] secondNorm = null; - float[] thirdNorm = null; float[] twoBackCoord = null; float[] oneBackCoord = null; for(float[] coords = new float[6];!pi.isDone();pi.next()) { @@ -279,19 +417,9 @@ public class FontDrawer { thirdCoord = new float[3]; thirdCoord[0] = coords[0]; thirdCoord[1] = coords[1]; + } - if (secondNorm == null) { - secondNorm = new float[3]; - secondNorm[0] = avgdeltay; - secondNorm[1] = -avgdeltax; - secondNorm[2] = 0; - } else if (thirdNorm == null) { - thirdNorm = new float[3]; - thirdNorm[0] = avgdeltay; - thirdNorm[1] = -avgdeltax; - thirdNorm[2] = 0; - } - gl.glNormal3f(avgdeltay,-avgdeltax,0); + gl.glNormal3f(-avgdeltay,avgdeltax,0); oneBackCoord[2] = 0.0f; gl.glVertex3fv(oneBackCoord,0); oneBackCoord[2] = tessZ; @@ -307,7 +435,7 @@ public class FontDrawer { case PathIterator.SEG_CLOSE: float avgdeltax = oneBackCoord[0] - twoBackCoord[0] + firstCoord[0] - oneBackCoord[0]; float avgdeltay = oneBackCoord[1] - twoBackCoord[1] + firstCoord[1] - oneBackCoord[1]; - gl.glNormal3f(avgdeltay,-avgdeltax,0); + gl.glNormal3f(-avgdeltay,avgdeltax,0); oneBackCoord[2] = 0.0f; gl.glVertex3fv(oneBackCoord,0); oneBackCoord[2] = tessZ; @@ -315,7 +443,7 @@ public class FontDrawer { avgdeltax = firstCoord[0] - oneBackCoord[0] + secondCoord[0] - firstCoord[0]; avgdeltay = firstCoord[1] - oneBackCoord[1] + secondCoord[1] - firstCoord[1]; - gl.glNormal3f(avgdeltay,-avgdeltax,0); + gl.glNormal3f(-avgdeltay,avgdeltax,0); firstCoord[2] = 0.0f; gl.glVertex3fv(firstCoord,0); firstCoord[2] = tessZ; @@ -323,29 +451,21 @@ public class FontDrawer { avgdeltax = secondCoord[0] - firstCoord[0] + thirdCoord[0] - secondCoord[0]; avgdeltay = secondCoord[1] - firstCoord[1] + thirdCoord[1] - secondCoord[1]; - gl.glNormal3f(avgdeltay,-avgdeltax,0); - //gl.glNormal3fv(secondNorm,0); + gl.glNormal3f(-avgdeltay,avgdeltax,0); secondCoord[2] = 0.0f; gl.glVertex3fv(secondCoord,0); secondCoord[2] = tessZ; gl.glVertex3fv(secondCoord,0); - /*gl.glNormal3fv(thirdNorm,0); - thirdCoord[2] = 0.0f; - gl.glVertex3fv(thirdCoord,0); - thirdCoord[2] = tessZ; - gl.glVertex3fv(thirdCoord,0);*/ gl.glEnd(); firstCoord = null; secondCoord = null; thirdCoord = null; - secondNorm = null; - thirdNorm = null; twoBackCoord = null; oneBackCoord = null; break; default: - throw new JogltextException("PathIterator segment not SEG_MOVETO, SEG_LINETO, SEG_CLOSE"); + throw new JogltextException("PathIterator segment not SEG_MOVETO, SEG_LINETO, SEG_CLOSEE; Inappropriate font."); } } } -- cgit v1.2.3