2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
5 package net.sf.jiga.xtended.impl.game.gl;
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;
25 import net.sf.jiga.xtended.impl.game.RenderingScene;
26 import net.sf.jiga.xtended.impl.system.BufferIO;
27 import org.lwjgl.opengl.GL11;
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
37 private static class GLGlyphVector implements GL2DObject {
39 static Map<Integer, GLGlyph> _glyphs = Collections.synchronizedMap(new HashMap<Integer, GLGlyph>());
41 private Point2D.Float renderAt;
45 public GLGlyphVector(Point2D.Float renderAt, String text, Font font, int size) {
46 this.renderAt = renderAt;
53 public boolean equals(Object o) {
54 return o != null ? o.hashCode() == hashCode() : false;
58 public int hashCode() {
61 GlyphVector gv = null;
63 /** this method costs big resources usage, use it as little as possible*/
64 public GlyphVector getGlyphVector() {
66 gv = font.createGlyphVector(new FontRenderContext(font.getTransform(), true, false), text);
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);
76 _glyphs.put(uid, gly = new GLGlyph(this, charAt));
77 assert uid == gly.getUID() : "integrity error with getUID()";
84 private Shape s = null;
86 public Shape getShape() {
88 final Area a = new Area();
89 for (int i = 0; i < text.length(); i++) {
90 GLGlyph gly = getGlyph(i);
92 a.add(new Area(gly.getShape()));
97 public Rectangle getBounds() {
101 public Rectangle2D getBounds2D() {
102 return a.getBounds2D();
105 public boolean contains(double x, double y) {
106 return a.contains(x, y);
109 public boolean contains(Point2D p) {
110 return a.contains(p);
113 public boolean intersects(double x, double y, double w, double h) {
114 return a.intersects(x, y, w, h);
117 public boolean intersects(Rectangle2D r) {
118 return a.contains(r);
121 public boolean contains(double x, double y, double w, double h) {
122 return a.intersects(x, y, w, h);
125 public boolean contains(Rectangle2D r) {
126 return a.contains(r);
129 public PathIterator getPathIterator(AffineTransform at) {
130 return a.getPathIterator(at);
133 public PathIterator getPathIterator(AffineTransform at, double flatness) {
134 return a.getPathIterator(at, flatness);
141 public boolean isFill() {
145 public int getResolution() {
149 public int getUID() {
150 return (text + "++" + text.length() + "++" + size + "++" + font.toString()).hashCode();
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;
164 private static class GLGlyph extends GLList implements GL2DObject {
166 static Map<Integer, Shape> _glyphs = Collections.synchronizedMap(new HashMap<Integer, Shape>());
169 /*public GLGlyph(Point2D.Float textRenderAt, String text, int charAt, Font font, int size) {
172 GLGlyphVector parentVector;
174 public GLGlyph(GLGlyphVector parentVector, int charAt) {
176 this.charAt = charAt;
177 this.parentVector = parentVector;
178 uid = _calcUID(parentVector.text, charAt, parentVector.font, parentVector.size);
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());
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()));*/
193 public boolean equals(Object o) {
194 return o != null ? o.hashCode() == hashCode() : false;
198 public int hashCode() {
202 public int getResolution() {
203 return parentVector.getResolution();
207 public Runnable getList() {
208 return new Runnable() {
211 GLGeom._renderShape(getShape(), getResolution());
216 public boolean isFill() {
217 return parentVector.isFill();
220 public int getUID() {
224 public static int _calcUID(String text, int charAt, Font font, int size) {
225 return (text.charAt(charAt) + "++" + size + "++" + font.toString()).hashCode();
228 private static GLFX fx = new GLFX() {
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) {
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);
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) {
246 public Shape getShape() {
247 return mySp.getShape();
251 public int getUID() {
252 return (s.getUID() + "++" + ((GL2DFXObject) mySp).getFX()).hashCode();
255 } else if (mySp instanceof GLGlyphVector) {
256 gl = (GLGlyphVector) mySp;
259 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
261 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
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);
269 if (mySp instanceof GL2DFXObject) {
270 GL11.glMatrixMode(GL11.GL_MODELVIEW);
272 GL11.glTranslatef((float) gl.renderAt.getX(), (float) gl.renderAt.getY(), 0);
273 GLGeom._renderShape(gl.getShape(), gl.getResolution());
276 for (int i = 0; i < gl.text.length(); i++) {
277 if (!Character.isWhitespace(gl.text.charAt(i))) {
278 GL11.glMatrixMode(GL11.GL_MODELVIEW);
280 Point2D p = GLGlyphVector._getRenderCharLocation(gld, gl, i);
281 GL11.glTranslatef((float) p.getX(), (float) p.getY(), 0);
282 GLGlyph gly = gl.getGlyph(i);
284 GLList._GLListCallback(gly);
293 GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
294 GLHandler._blendingEnd(blend);
295 GLHandler._transformEnd();
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);
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();
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);