SourceForge: sf3jswing/sf3jswing: sf3jswing-jigaxtended/src/all/net/sf/jiga/xtended/impl/game/gl/GLText.java@4bdc82814598
sf3jswing-jigaxtended/src/all/net/sf/jiga/xtended/impl/game/gl/GLText.java
author b23prodtm
Sun Jan 08 22:26:11 2012 +0100 (4 months ago)
changeset 29 4bdc82814598
parent 27 d234d03be0d9
child 30 8959d4337b05
permissions -rw-r--r--
head-tailmaps, values(), entrySet() integrity fix
     1 /*
     2  * To change this template, choose Tools | Templates
     3  * and open the template in the editor.
     4  */
     5 package net.sf.jiga.xtended.impl.game.gl;
     6 
     7 import java.awt.Color;
     8 import java.awt.Font;
     9 import java.awt.FontMetrics;
    10 import java.awt.Point;
    11 import java.awt.Rectangle;
    12 import java.awt.Shape;
    13 import java.awt.font.FontRenderContext;
    14 import java.awt.font.GlyphVector;
    15 import java.awt.geom.AffineTransform;
    16 import java.awt.geom.Area;
    17 import java.awt.geom.PathIterator;
    18 import java.awt.geom.Point2D;
    19 import java.awt.geom.Rectangle2D;
    20 import java.nio.DoubleBuffer;
    21 import java.nio.FloatBuffer;
    22 import java.util.Collections;
    23 import java.util.HashMap;
    24 import java.util.Map;
    25 import net.sf.jiga.xtended.impl.game.RenderingScene;
    26 import net.sf.jiga.xtended.impl.system.BufferIO;
    27 import org.lwjgl.opengl.GL11;
    28 
    29 /**
    30  * This class actually renders the text in a hardware mode, using GLList's. It's way faster than rendering textures as character maps when handling ASCII/Unicode character map.
    31  * It's based on the Font Glyphs that the Java SDK provides.
    32  * GLUtesselator renders the Glyphs.
    33  * @author www.b23prodtm.info
    34  */
    35 public class GLText {
    36 
    37     private static class GLGlyphVector implements GL2DObject {
    38 
    39         static Map<Integer, GLGlyph> _glyphs = Collections.synchronizedMap(new HashMap<Integer, GLGlyph>());
    40         public int size;
    41         private Point2D.Float renderAt;
    42         public String text;
    43         public Font font;
    44 
    45         public GLGlyphVector(Point2D.Float renderAt, String text, Font font, int size) {
    46             this.renderAt = renderAt;
    47             this.text = text;
    48             this.font = font;
    49             this.size = size;
    50         }
    51 
    52         @Override
    53         public boolean equals(Object o) {
    54             return o != null ? o.hashCode() == hashCode() : false;
    55         }
    56 
    57         @Override
    58         public int hashCode() {
    59             return getUID();
    60         }
    61         GlyphVector gv = null;
    62 
    63         /** this method costs big resources usage, use it as little as possible*/
    64         public GlyphVector getGlyphVector() {
    65             if (gv == null) {
    66                 gv = font.createGlyphVector(new FontRenderContext(font.getTransform(), true, false), text);
    67             }
    68             return gv;
    69         }
    70 
    71         public GLGlyph getGlyph(int charAt) {
    72             if (!Character.isWhitespace(text.charAt(charAt))) {
    73                 int uid = GLGlyph._calcUID(text, charAt, font, size);
    74                 GLGlyph gly = _glyphs.get(uid);
    75                 if (gly == null) {
    76                     _glyphs.put(uid, gly = new GLGlyph(this, charAt));
    77                     assert uid == gly.getUID() : "integrity error with getUID()";
    78                 }
    79                 return gly;
    80             } else {
    81                 return null;
    82             }
    83         }
    84         private Shape s = null;
    85 
    86         public Shape getShape() {
    87             if (s == null) {
    88                 final Area a = new Area();
    89                 for (int i = 0; i < text.length(); i++) {
    90                     GLGlyph gly = getGlyph(i);
    91                     if (gly != null) {
    92                         a.add(new Area(gly.getShape()));
    93                     }
    94                 }
    95                 s = new Shape() {
    96 
    97                     public Rectangle getBounds() {
    98                         return a.getBounds();
    99                     }
   100 
   101                     public Rectangle2D getBounds2D() {
   102                         return a.getBounds2D();
   103                     }
   104 
   105                     public boolean contains(double x, double y) {
   106                         return a.contains(x, y);
   107                     }
   108 
   109                     public boolean contains(Point2D p) {
   110                         return a.contains(p);
   111                     }
   112 
   113                     public boolean intersects(double x, double y, double w, double h) {
   114                         return a.intersects(x, y, w, h);
   115                     }
   116 
   117                     public boolean intersects(Rectangle2D r) {
   118                         return a.contains(r);
   119                     }
   120 
   121                     public boolean contains(double x, double y, double w, double h) {
   122                         return a.intersects(x, y, w, h);
   123                     }
   124 
   125                     public boolean contains(Rectangle2D r) {
   126                         return a.contains(r);
   127                     }
   128 
   129                     public PathIterator getPathIterator(AffineTransform at) {
   130                         return a.getPathIterator(at);
   131                     }
   132 
   133                     public PathIterator getPathIterator(AffineTransform at, double flatness) {
   134                         return a.getPathIterator(at, flatness);
   135                     }
   136                 };
   137             }
   138             return s;
   139         }
   140 
   141         public boolean isFill() {
   142             return true;
   143         }
   144 
   145         public int getResolution() {
   146             return size;
   147         }
   148 
   149         public int getUID() {
   150             return (text + "++" + text.length() + "++" + size + "++" + font.toString()).hashCode();
   151         }
   152 
   153         /** makes FontMetrics calculations to return the location where it must render the glyph character (the {@linkplain #getShape() shape} 
   154          * should be rendered after translating to this location)*/
   155         public static Point2D _getRenderCharLocation(RenderingScene gld, GLGlyphVector gv, int charAt) {
   156             FontMetrics fm = gld.getFontMetrics(gv.font);
   157             Point2D.Float p = new Point2D.Float(fm.stringWidth(gv.text.substring(0, charAt)), 0);
   158             p.x += gv.renderAt.x;
   159             p.y += gv.renderAt.y;
   160             return p;
   161         }
   162     }
   163 
   164     private static class GLGlyph extends GLList implements GL2DObject {
   165 
   166         static Map<Integer, Shape> _glyphs = Collections.synchronizedMap(new HashMap<Integer, Shape>());
   167         int charAt;
   168         int uid;
   169         /*public GLGlyph(Point2D.Float textRenderAt, String text, int charAt, Font font, int size) {
   170         
   171         }*/
   172         GLGlyphVector parentVector;
   173 
   174         public GLGlyph(GLGlyphVector parentVector, int charAt) {
   175             super();
   176             this.charAt = charAt;
   177             this.parentVector = parentVector;
   178             uid = _calcUID(parentVector.text, charAt, parentVector.font, parentVector.size);
   179         }
   180 
   181         /** computes a GlyphVector and returns the Shape corresponding to the selected character (charAt) in String (text) for the font*/
   182         public Shape getShape() {
   183             Shape s = _glyphs.get(getUID());
   184             if (s == null) {
   185                 GlyphVector gv = parentVector.getGlyphVector();
   186                 Rectangle2D glyphBounds = gv.getGlyphOutline(charAt).getBounds2D();
   187                 _glyphs.put(getUID(), s = gv.getGlyphOutline(charAt, -(float) glyphBounds.getX(), 0));/* -(float) glyphBounds.getY()));*/
   188             }
   189             return s;
   190         }
   191 
   192         @Override
   193         public boolean equals(Object o) {
   194             return o != null ? o.hashCode() == hashCode() : false;
   195         }
   196 
   197         @Override
   198         public int hashCode() {
   199             return getUID();
   200         }
   201 
   202         public int getResolution() {
   203             return parentVector.getResolution();
   204         }
   205 
   206         @Override
   207         public Runnable getList() {
   208             return new Runnable() {
   209 
   210                 public void run() {
   211                     GLGeom._renderShape(getShape(), getResolution());
   212                 }
   213             };
   214         }
   215 
   216         public boolean isFill() {
   217             return parentVector.isFill();
   218         }
   219 
   220         public int getUID() {
   221             return uid;
   222         }
   223 
   224         public static int _calcUID(String text, int charAt, Font font, int size) {
   225             return (text.charAt(charAt) + "++" + size + "++" + font.toString()).hashCode();
   226         }
   227     }
   228     private static GLFX fx = new GLFX() {
   229 
   230         @Override
   231         protected void _GLRender2D(final RenderingScene gld, boolean keepBinding, final GL2DObject mySp, double z, int transform, DoubleBuffer scaleArgs, DoubleBuffer rotateArgs, DoubleBuffer translateArgs, FloatBuffer colorBlend, FloatBuffer alphaBlend) {
   232 
   233             Rectangle sBounds = mySp.getShape().getBounds();
   234             GLHandler._transformBegin(sBounds, z, transform, scaleArgs, translateArgs, rotateArgs);
   235             GL11.glTranslatef(-sBounds.x, -sBounds.y, 0);
   236             /** render attribute */
   237             Blending blend = GLHandler._blendingBegin(colorBlend, alphaBlend, true);
   238 
   239             /** glyphvector */
   240             GLGlyphVector gl = null;
   241             if (mySp instanceof GL2DFXObject) {
   242                 final GLGlyphVector s = (GLGlyphVector) ((GL2DFXObject) mySp).getSrc();
   243                 gl = new GLGlyphVector(s.renderAt, s.text, s.font, s.size) {
   244 
   245                     @Override
   246                     public Shape getShape() {
   247                         return mySp.getShape();
   248                     }
   249 
   250                     @Override
   251                     public int getUID() {
   252                         return (s.getUID() + "++" + ((GL2DFXObject) mySp).getFX()).hashCode();
   253                     }
   254                 };
   255             } else if (mySp instanceof GLGlyphVector) {
   256                 gl = (GLGlyphVector) mySp;
   257             }
   258             if (gl.isFill()) {
   259                 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
   260             } else {
   261                 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
   262             }
   263             GL11.glPushAttrib(GL11.GL_LINE_BIT);
   264             GL11.glLineWidth(.2f);
   265             GL11.glEnable(GL11.GL_LINE_SMOOTH);
   266             GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_FASTEST);
   267 
   268             /** glyphs */
   269             if (mySp instanceof GL2DFXObject) {
   270                 GL11.glMatrixMode(GL11.GL_MODELVIEW);
   271                 GL11.glPushMatrix();
   272                 GL11.glTranslatef((float) gl.renderAt.getX(), (float) gl.renderAt.getY(), 0);
   273                 GLGeom._renderShape(gl.getShape(), gl.getResolution());
   274                 GL11.glPopMatrix();
   275             } else {
   276                 for (int i = 0; i < gl.text.length(); i++) {
   277                     if (!Character.isWhitespace(gl.text.charAt(i))) {
   278                         GL11.glMatrixMode(GL11.GL_MODELVIEW);
   279                         GL11.glPushMatrix();
   280                         Point2D p = GLGlyphVector._getRenderCharLocation(gld, gl, i);
   281                         GL11.glTranslatef((float) p.getX(), (float) p.getY(), 0);
   282                         GLGlyph gly = gl.getGlyph(i);
   283                         if (gly != null) {
   284                             GLList._GLListCallback(gly);
   285                         }
   286                         GL11.glPopMatrix();
   287                     }
   288                 }
   289             }
   290             /**/
   291 
   292             GL11.glPopAttrib();
   293             GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
   294             GLHandler._blendingEnd(blend);
   295             GLHandler._transformEnd();
   296         }
   297     };
   298 
   299     public static void _GLRenderText2D(final RenderingScene gld, String text, float x, float y, double z, Color clr) {
   300         _GLRenderText2D(gld, text, x, y, z, clr, 0, null);
   301     }
   302 
   303     /** fx can be added (e.g. color render, alpha blend, background, etc.), but it can slow down very much rendering speed (e.g. reflexion-transform effects) */
   304     public static void _GLRenderText2D(final RenderingScene gld, String text, float x, float y, double z, Color clr, int fx, Point fx_loc) {
   305         final Font font = gld.getFont();
   306         clr = clr instanceof Color ? clr : gld.getForeground();
   307         /** render glyphs*/
   308         GLText.fx._GLRender2D(gld, new GLGlyphVector(new Point2D.Float(x, y), text, font, font.getSize()), z, fx, fx_loc, clr, 0, null, null, null);
   309         /*for (int i = 0; i < /*gv.getNumGlyphs()* text.length(); i++) {
   310         /*final Rectangle2D glyphBounds = gv.getGlyphOutline(i).getBounds2D();*
   311         if (!Character.isWhitespace(text.charAt(i))) {
   312         GLGlyph glGlyph = new GLGlyph(new Point2D.Float(x, y), text, i, font, font.getSize());
   313         GLText.fx._GLRender2D(gld, glGlyph, z, fx, fx_loc, clr, 0, null, null, null);
   314         }
   315         }*/
   316     }
   317 }