aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/graph/font
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-02-24 13:32:34 +0100
committerSven Gothel <[email protected]>2014-02-24 13:32:34 +0100
commitc3621221b9a563495b4f54fe60e18e8db8cc57fb (patch)
tree00aded20f3582e517372c12f58e19d3524582099 /src/jogl/classes/jogamp/graph/font
parentf69df875d0b9f969a816d143ed589b25e50cd9e7 (diff)
Bug 802: Graph TextRenderer Performance Part-1 (incomplete, rendering artifacts)
Strategy Change: - Font.Glyph itself holds it's OutlineShape with it's default scaling. Triangulation is done only once per glyph! - A CharSequence produces a Region by translating and scaling each Glyphs's OutlineShape. This removes the need for re-triangulate - see above. See: TextRendererUtil - The indices of re-added Triangles are offset to the new vertices (FIXME, seems not be be accurate yet). - OutlineShape's vertices and triangles are reused if 'clean'. - Simplified code - Reduced copies API Changes: - OutlineShape, Region, ...: See above - Removed TextRenderer, GlyphShape and GlyphString: Redundant - Added TextRendererUtil to produce the Region from CharSequence Result: - Over 600 fps while changing text for each frame. Previously only ~60fps max. TODO: - Region shall not hold the triangles itself, but the indices instead. This will remove the need to swizzle w/ vertices in the Region Renderer impl and easies reusage of OutlineShapes.
Diffstat (limited to 'src/jogl/classes/jogamp/graph/font')
-rw-r--r--src/jogl/classes/jogamp/graph/font/FontInt.java3
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java15
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java27
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java137
4 files changed, 157 insertions, 25 deletions
diff --git a/src/jogl/classes/jogamp/graph/font/FontInt.java b/src/jogl/classes/jogamp/graph/font/FontInt.java
index 1f4eaf20d..f87a00251 100644
--- a/src/jogl/classes/jogamp/graph/font/FontInt.java
+++ b/src/jogl/classes/jogamp/graph/font/FontInt.java
@@ -31,6 +31,9 @@ import jogamp.graph.geom.plane.Path2D;
import com.jogamp.graph.font.Font;
+/**
+ * @deprecated
+ */
public interface FontInt extends Font {
public interface GlyphInt extends Font.Glyph {
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
index 250778f06..41fa6c223 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
@@ -44,19 +44,20 @@ import com.jogamp.common.util.IntObjectHashMap;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.font.Font;
import com.jogamp.graph.font.FontFactory;
+import com.jogamp.graph.geom.SVertex;
import com.jogamp.graph.geom.Vertex;
import com.jogamp.graph.geom.Vertex.Factory;
import com.jogamp.opengl.math.geom.AABBox;
class TypecastFont implements FontInt {
static final boolean DEBUG = false;
+ private static final Vertex.Factory<SVertex> vertexFactory = SVertex.factory();
final OTFontCollection fontset;
final OTFont font;
TypecastHMetrics metrics;
final CmapFormat cmapFormat;
int cmapentries;
-
// FIXME: Add cache size to limit memory usage ??
IntObjectHashMap char2Glyph;
@@ -201,8 +202,10 @@ class TypecastFont implements FontInt {
if(null == glyph) {
throw new RuntimeException("Could not retrieve glyph for symbol: <"+symbol+"> "+(int)symbol+" -> glyph id "+code);
}
- Path2D path = TypecastRenderer.buildPath(glyph);
- result = new TypecastGlyph(this, symbol, code, glyph.getBBox(), glyph.getAdvanceWidth(), path);
+ final OutlineShape shape = TypecastRenderer.buildShape(glyph, vertexFactory);
+ // FIXME: Remove Path2D
+ final Path2D path = TypecastRenderer.buildPath(glyph);
+ result = new TypecastGlyph(this, symbol, code, glyph.getBBox(), glyph.getAdvanceWidth(), path, shape);
if(DEBUG) {
System.err.println("New glyph: " + (int)symbol + " ( " + symbol +" ) -> " + code + ", contours " + glyph.getPointCount() + ": " + path);
}
@@ -225,11 +228,7 @@ class TypecastFont implements FontInt {
return result;
}
- @Override
- public OutlineShape getOutlineShape(Glyph glyph, Factory<? extends Vertex> vertexFactory) {
- return TypecastRenderer.getOutlineShape(this, glyph, vertexFactory);
- }
-
+ // FIXME: Remove altogether
@Override
public List<OutlineShape> getOutlineShapes(List<OutlineShape> shapes, CharSequence string, float pixelSize, Factory<? extends Vertex> vertexFactory) {
AffineTransform transform = new AffineTransform(vertexFactory);
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
index 302366647..40727826b 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
@@ -33,6 +33,7 @@ import jogamp.graph.font.FontInt;
import jogamp.graph.geom.plane.AffineTransform;
import jogamp.graph.geom.plane.Path2D;
+import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.font.Font;
import com.jogamp.opengl.math.geom.AABBox;
@@ -136,30 +137,36 @@ public class TypecastGlyph implements FontInt.GlyphInt {
public static final short MAX_ID = (short)((1 << 16) - 2);
private final Font font;
+ protected final char symbol;
+ protected final OutlineShape shape; // in EM units
+
+ protected final Path2D path; // in EM units FIXME remove!
- char symbol;
short id;
int advance;
Metrics metrics;
- protected Path2D path; // in EM units
- protected Path2D pathSized;
- protected float numberSized;
+ protected Path2D pathSized; // FIXME remove!
+ protected float numberSized; // FIXME remove!
protected TypecastGlyph(Font font, char symbol) {
this.font = font;
this.symbol = symbol;
+ this.shape = null;
+ this.path = null;
}
protected TypecastGlyph(Font font,
- char symbol, short id, AABBox bbox, int advance, Path2D path) {
+ char symbol, short id, AABBox bbox, int advance, Path2D path, OutlineShape shape) {
this.font = font;
this.symbol = symbol;
+ this.shape = shape;
+ this.path = path;
+
this.advance = advance;
init(id, bbox, advance);
- this.path = path;
this.pathSized = null;
this.numberSized = 0.0f;
}
@@ -170,10 +177,11 @@ public class TypecastGlyph implements FontInt.GlyphInt {
this.metrics = new Metrics(this.font, bbox, this.advance);
}
+ /**
public void reset(Path2D path) {
this.path = path;
this.metrics.reset();
- }
+ } */
@Override
public Font getFont() {
@@ -223,6 +231,11 @@ public class TypecastGlyph implements FontInt.GlyphInt {
}
@Override
+ public OutlineShape getShape() {
+ return this.shape;
+ }
+
+ @Override
public Path2D getPath() {
return this.path;
}
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java
index d7f8497b3..83ccadab3 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java
@@ -55,25 +55,27 @@ public class TypecastRenderer {
if (string == null) {
return;
}
- Font.Metrics metrics = font.getMetrics();
- float advanceTotal = 0;
- float lineGap = metrics.getLineGap(pixelSize) ;
- float ascent = metrics.getAscent(pixelSize) ;
- float descent = metrics.getDescent(pixelSize) ;
+ final Font.Metrics metrics = font.getMetrics();
+ final float lineGap = metrics.getLineGap(pixelSize) ;
+ final float ascent = metrics.getAscent(pixelSize) ;
+ final float descent = metrics.getDescent(pixelSize) ;
+ final float advanceY = lineGap - descent + ascent;
+ final float scale = metrics.getScale(pixelSize);
if (transform == null) {
transform = new AffineTransform();
}
- AffineTransform t = new AffineTransform();
+ final AffineTransform t = new AffineTransform(transform.getFactory());
final int len = string.length();
- float advanceY = lineGap - descent + ascent;
+
+ float advanceTotal = 0;
float y = 0;
+
for (int i=0; i<len; i++)
{
p[i] = new Path2D();
p[i].reset();
- t.setTransform(transform);
- char character = string.charAt(i);
+ final char character = string.charAt(i);
if (character == '\n') {
y += advanceY;
advanceTotal = 0;
@@ -82,7 +84,7 @@ public class TypecastRenderer {
} else {
final Glyph glyph = font.getGlyph(character);
final Path2D gp = ((GlyphInt)glyph).getPath();
- final float scale = metrics.getScale(pixelSize);
+ t.setTransform(transform); // reset transform
t.translate(advanceTotal, y);
t.scale(scale, scale);
p[i].append(gp.iterator(t), false);
@@ -92,6 +94,7 @@ public class TypecastRenderer {
}
public static OutlineShape getOutlineShape(TypecastFont font, Glyph glyph, Factory<? extends Vertex> vertexFactory) {
+ // FIXME: Remove Path2D
Path2D path = ((GlyphInt)glyph).getPath();
AffineTransform transform = new AffineTransform(vertexFactory);
OutlineShape shape = new OutlineShape(vertexFactory);
@@ -109,6 +112,8 @@ public class TypecastRenderer {
}
public static List<OutlineShape> getOutlineShapes(List<OutlineShape> shapes, TypecastFont font, CharSequence string, float pixelSize, AffineTransform transform, Factory<? extends Vertex> vertexFactory) {
+ // FIXME: Remove Path2D
+ // FIXME: Remove altogether
Path2D[] paths = new Path2D[string.length()];
getPaths(font, string, pixelSize, transform, paths);
@@ -161,6 +166,118 @@ public class TypecastRenderer {
}
}
+ private static void addShapeMoveTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1) {
+ shape.closeLastOutline();
+ shape.addEmptyOutline();
+ shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, true)); // p1.onCurve));
+ // shape.addVertex(0, vertexFactory.create(coords, 0, 2, true));
+ }
+ private static void addShapeLineTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1) {
+ shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, true)); // p1.onCurve));
+ // shape.addVertex(0, vertexFactory.create(coords, 0, 2, true));
+ }
+ private static void addShapeQuadTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1, Point p2) {
+ shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, false)); // p1.onCurve));
+ shape.addVertex(0, vertexFactory.create(p2.x, p2.y, 0, true)); // p2.onCurve));
+ // shape.addVertex(0, vertexFactory.create(coords, 0, 2, false));
+ // shape.addVertex(0, vertexFactory.create(coords, 2, 2, true));
+ }
+ private static void addShapeQuadTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1, int p2x, int p2y) {
+ shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, false)); // p1.onCurve));
+ shape.addVertex(0, vertexFactory.create(p2x, p2y, 0, true)); // p2.onCurve));
+ // shape.addVertex(0, vertexFactory.create(coords, 0, 2, false));
+ // shape.addVertex(0, vertexFactory.create(coords, 2, 2, true));
+ }
+ /**
+ private static void addShapeCubicTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1, Point p2, Point p3) {
+ shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, false)); // p1.onCurve));
+ shape.addVertex(0, vertexFactory.create(p2.x, p2.y, 0, false)); // p2.onCurve));
+ shape.addVertex(0, vertexFactory.create(p3.x, p3.y, 0, true)); // p3.onCurve));
+ // shape.addVertex(0, vertexFactory.create(coords, 0, 2, false));
+ // shape.addVertex(0, vertexFactory.create(coords, 2, 2, false));
+ // shape.addVertex(0, vertexFactory.create(coords, 4, 2, true));
+
+ }
+ private static void addShapeClose(final OutlineShape shape, Factory<? extends Vertex> vertexFactory) {
+ shape.closeLastOutline();
+ } */
+
+ public static OutlineShape buildShape(OTGlyph glyph, Factory<? extends Vertex> vertexFactory) {
+
+ if (glyph == null) {
+ return null;
+ }
+
+ final OutlineShape shape = new OutlineShape(vertexFactory);
+
+ // Iterate through all of the points in the glyph. Each time we find a
+ // contour end point, add the point range to the path.
+ int startIndex = 0;
+ int count = 0;
+ for (int i = 0; i < glyph.getPointCount(); i++) {
+ count++;
+ if (glyph.getPoint(i).endOfContour) {
+ {
+ int offset = 0;
+ while (offset < count) {
+ final Point point = glyph.getPoint(startIndex + offset%count);
+ final Point point_plus1 = glyph.getPoint(startIndex + (offset+1)%count);
+ final Point point_plus2 = glyph.getPoint(startIndex + (offset+2)%count);
+ if(offset == 0)
+ {
+ addShapeMoveTo(shape, vertexFactory, point);
+ // gp.moveTo(point.x, point.y);
+ }
+
+ if (point.onCurve) {
+ if (point_plus1.onCurve) {
+ // s = new Line2D.Float(point.x, point.y, point_plus1.x, point_plus1.y);
+ addShapeLineTo(shape, vertexFactory, point_plus1);
+ // gp.lineTo( point_plus1.x, point_plus1.y );
+ offset++;
+ } else {
+ if (point_plus2.onCurve) {
+ // s = new QuadCurve2D.Float( point.x, point.y, point_plus1.x, point_plus1.y, point_plus2.x, point_plus2.y);
+ addShapeQuadTo(shape, vertexFactory, point_plus1, point_plus2);
+ // gp.quadTo(point_plus1.x, point_plus1.y, point_plus2.x, point_plus2.y);
+ offset+=2;
+ } else {
+ // s = new QuadCurve2D.Float(point.x,point.y,point_plus1.x,point_plus1.y,
+ // midValue(point_plus1.x, point_plus2.x), midValue(point_plus1.y, point_plus2.y));
+ addShapeQuadTo(shape, vertexFactory, point_plus1, midValue(point_plus1.x, point_plus2.x), midValue(point_plus1.y, point_plus2.y));
+ // gp.quadTo(point_plus1.x, point_plus1.y, midValue(point_plus1.x, point_plus2.x), midValue(point_plus1.y, point_plus2.y));
+ offset+=2;
+ }
+ }
+ } else {
+ if (point_plus1.onCurve) {
+ // s = new QuadCurve2D.Float(midValue(point_minus1.x, point.x), midValue(point_minus1.y, point.y),
+ // point.x, point.y, point_plus1.x, point_plus1.y);
+ //gp.curve3(point_plus1.x, point_plus1.y, point.x, point.y);
+ addShapeQuadTo(shape, vertexFactory, point, point_plus1);
+ // gp.quadTo(point.x, point.y, point_plus1.x, point_plus1.y);
+ offset++;
+
+ } else {
+ // s = new QuadCurve2D.Float(midValue(point_minus1.x, point.x), midValue(point_minus1.y, point.y), point.x, point.y,
+ // midValue(point.x, point_plus1.x), midValue(point.y, point_plus1.y));
+ //gp.curve3(midValue(point.x, point_plus1.x), midValue(point.y, point_plus1.y), point.x, point.y);
+ addShapeQuadTo(shape, vertexFactory, point, midValue(point.x, point_plus1.x), midValue(point.y, point_plus1.y));
+ // gp.quadTo(point.x, point.y, midValue(point.x, point_plus1.x), midValue(point.y, point_plus1.y));
+ offset++;
+ }
+ }
+ }
+
+ }
+ startIndex = i + 1;
+ count = 0;
+ }
+ }
+ shape.closeLastOutline();
+ return shape;
+ }
+
/**
* Build a {@link com.jogamp.graph.geom.Path2D Path2D} from a
* {@link jogamp.graph.font.typecast.ot.OTGlyph Glyph}. This glyph path can then