From c3621221b9a563495b4f54fe60e18e8db8cc57fb Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Mon, 24 Feb 2014 13:32:34 +0100 Subject: 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. --- .../graph/curve/opengl/TextRendererImpl01.java | 108 ---------- .../jogamp/graph/curve/opengl/VBORegionSPES2.java | 49 +++-- .../jogamp/graph/curve/tess/CDTriangulator2D.java | 45 ++-- src/jogl/classes/jogamp/graph/curve/tess/Loop.java | 6 +- .../jogamp/graph/curve/text/GlyphShape.java | 112 ---------- .../jogamp/graph/curve/text/GlyphString.java | 234 --------------------- src/jogl/classes/jogamp/graph/font/FontInt.java | 3 + .../jogamp/graph/font/typecast/TypecastFont.java | 15 +- .../jogamp/graph/font/typecast/TypecastGlyph.java | 27 ++- .../graph/font/typecast/TypecastRenderer.java | 137 +++++++++++- .../jogamp/graph/geom/plane/AffineTransform.java | 32 ++- .../classes/jogamp/graph/geom/plane/Path2D.java | 2 +- 12 files changed, 226 insertions(+), 544 deletions(-) delete mode 100644 src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java delete mode 100644 src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java delete mode 100644 src/jogl/classes/jogamp/graph/curve/text/GlyphString.java (limited to 'src/jogl/classes/jogamp') diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java b/src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java deleted file mode 100644 index c3c7e0cac..000000000 --- a/src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions 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. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package jogamp.graph.curve.opengl; - -import javax.media.opengl.GL2ES2; -import javax.media.opengl.GLException; - -import jogamp.graph.curve.opengl.shader.AttributeNames; -import jogamp.graph.curve.text.GlyphString; - -import com.jogamp.graph.curve.opengl.RenderState; -import com.jogamp.graph.curve.opengl.TextRenderer; -import com.jogamp.graph.font.Font; -import com.jogamp.opengl.GLExtensions; -import com.jogamp.opengl.util.glsl.ShaderCode; -import com.jogamp.opengl.util.glsl.ShaderProgram; -import com.jogamp.opengl.util.glsl.ShaderState; - -public class TextRendererImpl01 extends TextRenderer { - public TextRendererImpl01(RenderState rs, int type) { - super(rs, type); - } - - @Override - protected boolean initShaderProgram(GL2ES2 gl){ - final ShaderState st = rs.getShaderState(); - - final ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, TextRendererImpl01.class, "shader", - "shader/bin", getVertexShaderName(), true); - final ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, TextRendererImpl01.class, "shader", - "shader/bin", getFragmentShaderName(), true); - rsVp.defaultShaderCustomization(gl, true, true); - // rsFp.defaultShaderCustomization(gl, true, true); - int pos = rsFp.addGLSLVersion(gl); - if( gl.isGLES() ) { - pos = rsFp.insertShaderSource(0, pos, ShaderCode.createExtensionDirective(GLExtensions.OES_standard_derivatives, ShaderCode.ENABLE)); - } - final String rsFpDefPrecision = getFragmentShaderPrecision(gl); - if( null != rsFpDefPrecision ) { - rsFp.insertShaderSource(0, pos, rsFpDefPrecision); - } - - final ShaderProgram sp = new ShaderProgram(); - sp.add(rsVp); - sp.add(rsFp); - - if( !sp.init(gl) ) { - throw new GLException("RegionRenderer: Couldn't init program: "+sp); - } - st.attachShaderProgram(gl, sp, false); - st.bindAttribLocation(gl, AttributeNames.VERTEX_ATTR_IDX, AttributeNames.VERTEX_ATTR_NAME); - st.bindAttribLocation(gl, AttributeNames.TEXCOORD_ATTR_IDX, AttributeNames.TEXCOORD_ATTR_NAME); - - if(!sp.link(gl, System.err)) { - throw new GLException("TextRendererImpl01: Couldn't link program: "+sp); - } - st.useProgram(gl, true); - - if(DEBUG) { - System.err.println("TextRendererImpl01 initialized: " + Thread.currentThread()+" "+st); - } - return true; - } - - @Override - protected void destroyImpl(GL2ES2 gl) { - super.destroyImpl(gl); - } - - @Override - public void drawString3D(GL2ES2 gl, Font font, String str, int fontSize, int[/*1*/] texSize) { - if(!isInitialized()){ - throw new GLException("TextRendererImpl01: not initialized!"); - } - GlyphString glyphString = getCachedGlyphString(font, str, fontSize); - if(null == glyphString) { - glyphString = createString(gl, font, fontSize, str); - addCachedGlyphString(gl, font, str, fontSize, glyphString); - } - - glyphString.renderString3D(gl, rs, vp_width, vp_height, texSize); - } -} diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java index 9feb18a12..3cc6152b2 100644 --- a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java +++ b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java @@ -42,7 +42,7 @@ import com.jogamp.opengl.util.glsl.ShaderState; public class VBORegionSPES2 extends GLRegion { private GLArrayDataServer verticeAttr = null; private GLArrayDataServer texCoordAttr = null; - private GLArrayDataServer indices = null; + private GLArrayDataServer indicesBuffer = null; protected VBORegionSPES2(int renderModes) { super(renderModes); @@ -54,11 +54,11 @@ public class VBORegionSPES2 extends GLRegion { return; } - if(null == indices) { + if(null == indicesBuffer) { final int initialElementCount = 256; final ShaderState st = rs.getShaderState(); - indices = GLArrayDataServer.createData(3, GL2ES2.GL_SHORT, initialElementCount, GL.GL_STATIC_DRAW, GL.GL_ELEMENT_ARRAY_BUFFER); + indicesBuffer = GLArrayDataServer.createData(3, GL2ES2.GL_SHORT, initialElementCount, GL.GL_STATIC_DRAW, GL.GL_ELEMENT_ARRAY_BUFFER); verticeAttr = GLArrayDataServer.createGLSL(AttributeNames.VERTEX_ATTR_NAME, 3, GL2ES2.GL_FLOAT, false, initialElementCount, GL.GL_STATIC_DRAW); @@ -73,9 +73,12 @@ public class VBORegionSPES2 extends GLRegion { } } + if(DEBUG_INSTANCE) { + System.err.println("VBORegionSPES2 Indices of "+triangles.size()+", triangles"); + } // process triangles - indices.seal(gl, false); - indices.rewind(); + indicesBuffer.seal(gl, false); + indicesBuffer.rewind(); for(int i=0; i loops; - private ArrayList vertices; + // FIXME ? private ArrayList vertices; - private ArrayList triangles; private int maxTriID = 0; @@ -68,13 +67,12 @@ public class CDTriangulator2D implements Triangulator{ @Override public void reset() { maxTriID = 0; - vertices = new ArrayList(); - triangles = new ArrayList(3); + // vertices = new ArrayList(); loops = new ArrayList(); } @Override - public void addCurve(Outline polyline) { + public void addCurve(List sink, Outline polyline) { Loop loop = null; if(!loops.isEmpty()) { @@ -82,27 +80,27 @@ public class CDTriangulator2D implements Triangulator{ } if(loop == null) { - GraphOutline outline = new GraphOutline(polyline); - GraphOutline innerPoly = extractBoundaryTriangles(outline, false); - vertices.addAll(polyline.getVertices()); + final GraphOutline outline = new GraphOutline(polyline); + final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, false); + // vertices.addAll(polyline.getVertices()); loop = new Loop(innerPoly, VectorUtil.Winding.CCW); loops.add(loop); } else { - GraphOutline outline = new GraphOutline(polyline); - GraphOutline innerPoly = extractBoundaryTriangles(outline, true); - vertices.addAll(innerPoly.getVertices()); + final GraphOutline outline = new GraphOutline(polyline); + final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, true); + // vertices.addAll(innerPoly.getVertices()); loop.addConstraintCurve(innerPoly); } } @Override - public ArrayList generate() { + public void generate(List sink) { for(int i=0;i size){ tri = loop.cut(false); } @@ -115,7 +113,7 @@ public class CDTriangulator2D implements Triangulator{ numTries = 0; size--; tri.setId(maxTriID++); - triangles.add(tri); + sink.add(tri); if(DEBUG){ System.err.println(tri); } @@ -127,15 +125,14 @@ public class CDTriangulator2D implements Triangulator{ break; } } - Triangle tri = loop.cut(true); + final Triangle tri = loop.cut(true); if(tri != null) { - triangles.add(tri); + sink.add(tri); } } - return triangles; } - private GraphOutline extractBoundaryTriangles(GraphOutline outline, boolean hole) { + private GraphOutline extractBoundaryTriangles(List sink, GraphOutline outline, boolean hole) { GraphOutline innerOutline = new GraphOutline(); ArrayList outVertices = outline.getGraphPoint(); int size = outVertices.size(); @@ -146,9 +143,9 @@ public class CDTriangulator2D implements Triangulator{ GraphVertex gv1 = currentVertex; if(!currentVertex.getPoint().isOnCurve()) { - Vertex v0 = gv0.getPoint().clone(); - Vertex v2 = gv2.getPoint().clone(); - Vertex v1 = gv1.getPoint().clone(); + final Vertex v0 = gv0.getPoint().clone(); + final Vertex v2 = gv2.getPoint().clone(); + final Vertex v1 = gv1.getPoint().clone(); gv0.setBoundaryContained(true); gv1.setBoundaryContained(true); @@ -164,7 +161,7 @@ public class CDTriangulator2D implements Triangulator{ t = new Triangle(v2, v1, v0); } t.setId(maxTriID++); - triangles.add(t); + sink.add(t); if(DEBUG){ System.err.println(t); } diff --git a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java index c1dafc0d1..5810e3bc9 100644 --- a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java +++ b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java @@ -37,7 +37,7 @@ import com.jogamp.opengl.math.geom.AABBox; public class Loop { private HEdge root = null; - private AABBox box = new AABBox(); + private final AABBox box = new AABBox(); private GraphOutline initialOutline = null; public Loop(GraphOutline polyline, VectorUtil.Winding winding){ @@ -272,13 +272,13 @@ public class Loop { * @return the triangle iff it satisfies, null otherwise */ private Triangle createTriangle(Vertex v1, Vertex v2, Vertex v3, HEdge rootT){ - Triangle t = new Triangle(v1, v2, v3); + final Triangle t = new Triangle(v1, v2, v3); t.setVerticesBoundary(checkVerticesBoundary(rootT)); return t; } private boolean[] checkVerticesBoundary(HEdge rootT) { - boolean[] boundary = new boolean[3]; + final boolean[] boundary = new boolean[3]; HEdge e1 = rootT; HEdge e2 = rootT.getNext(); HEdge e3 = rootT.getNext().getNext(); diff --git a/src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java b/src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java deleted file mode 100644 index 8c214dd0b..000000000 --- a/src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions 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. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package jogamp.graph.curve.text; - -import java.util.ArrayList; - -import com.jogamp.graph.font.Font.Glyph; -import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.Triangle; -import com.jogamp.graph.geom.Vertex.Factory; -import com.jogamp.graph.curve.OutlineShape; -// import com.jogamp.opengl.math.Quaternion; - -public class GlyphShape { - - // private Quaternion quat= null; - private Glyph glyph; - private OutlineShape shape; - - /** Create a new Glyph shape - * based on Parametric curve control polyline - */ - public GlyphShape(Vertex.Factory factory){ - this.shape = new OutlineShape(factory); - this.glyph = null; - } - - /** Create a new GlyphShape from a {@link OutlineShape} - * @param factory vertex impl factory {@link Factory} - * @param shape {@link OutlineShape} representation of the Glyph - */ - public GlyphShape(Vertex.Factory factory, Glyph glyph, OutlineShape shape){ - this(factory); - this.shape = shape; - this.shape.transformOutlines(OutlineShape.VerticesState.QUADRATIC_NURBS); - this.glyph = glyph; - } - - public final void destroy() { - shape.clear(); - shape = null; - glyph = null; - } - - public final Vertex.Factory vertexFactory() { return shape.vertexFactory(); } - - public final Glyph getGlyph() { - return glyph; - } - - public final OutlineShape getShape() { - return shape; - } - - public final int getNumVertices() { - return shape.getVertices().size(); - } - - /** Get the rotational quaternion attached to this Shape. - * @return the Quaternion Object - public final Quaternion getQuat() { - return quat; - } - - /** - * Set the Quaternion that shall define the rotation - * of this shape. - * @param quat - public final void setQuat(Quaternion quat) { - this.quat = quat; - } - */ - - /** Triangluate the glyph shape - * @return ArrayList of triangles which define this shape - */ - public final ArrayList triangulate(){ - return shape.triangulate(); - } - - /** Get the list of Vertices of this Object - * @return arrayList of Vertices - */ - public final ArrayList getVertices(){ - return shape.getVertices(); - } -} diff --git a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java deleted file mode 100644 index 5fb547e69..000000000 --- a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java +++ /dev/null @@ -1,234 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions 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. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package jogamp.graph.curve.text; - -import java.util.ArrayList; -import java.util.List; - -import com.jogamp.graph.font.Font; -import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.Triangle; -import com.jogamp.graph.geom.Vertex.Factory; -import com.jogamp.graph.geom.opengl.SVertex; - -import javax.media.opengl.GL2ES2; - -import jogamp.graph.curve.opengl.RegionFactory; -import jogamp.graph.geom.plane.AffineTransform; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.curve.opengl.GLRegion; -import com.jogamp.graph.curve.opengl.RenderState; -import com.jogamp.opengl.math.geom.AABBox; -import com.jogamp.opengl.util.PMVMatrix; - -/** - * @deprecated use {@link com.jogamp.graph.font.Font#getOutlineShapes(java.util.List, CharSequence, float, Factory)}, - * {@link com.jogamp.graph.curve.Region#create(OutlineShape, int)} - * and a {@link com.jogamp.graph.curve.opengl.RegionRenderer}. - */ -public class GlyphString { - /** Static font size for all default font OutlineShape generations via {@link #createString(OutlineShape, Factory, Font, String)}. - *

The actual font size shall be accomplished by the GL PMV matrix.

- */ - public static final int STATIC_FONT_SIZE = 10; - - private final ArrayList glyphs = new ArrayList(); - private final CharSequence str; - private final String fontname; - private GLRegion region; - - private final SVertex origin = new SVertex(); - - /** - *

Uses {@link #STATIC_FONT_SIZE}.

- *

No caching is performed.

- * - * @param shape is not null, add all {@link GlyphShape}'s {@link Outline} to this instance. - * @param vertexFactory vertex impl factory {@link Factory} - * @param font the target {@link Font} - * @param str string text - * @return the created {@link GlyphString} instance - */ - public static GlyphString createString(OutlineShape shape, Factory vertexFactory, Font font, String str) { - return createString(shape, vertexFactory, font, STATIC_FONT_SIZE, str); - } - - /** - *

No caching is performed.

- * - * @param shape is not null, add all {@link GlyphShape}'s {@link Outline} to this instance. - * @param vertexFactory vertex impl factory {@link Factory} - * @param font the target {@link Font} - * @param fontSize font size - * @param str string text - * @return the created {@link GlyphString} instance - */ - public static GlyphString createString(OutlineShape shape, Factory vertexFactory, Font font, int fontSize, CharSequence str) { - List shapes = font.getOutlineShapes(null, str, fontSize, vertexFactory); - - GlyphString glyphString = new GlyphString(font.getName(Font.NAME_UNIQUNAME), str); - glyphString.createfromOutlineShapes(vertexFactory, font, str, shapes); - if(null != shape) { - for(int i=0; i vertexFactory, Font font, CharSequence str, List shapes) { - if(shapes.size() != str.length()) { - throw new InternalError("XXX"); - } - final int numGlyps = shapes.size(); - for (int index=0;index gtris = glyphShape.triangulate(); - region.addTriangles(gtris); - - final ArrayList gVertices = glyphShape.getVertices(); - for(int j=0; j 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 vertexFactory) { - return TypecastRenderer.getOutlineShape(this, glyph, vertexFactory); - } - + // FIXME: Remove altogether @Override public List getOutlineShapes(List shapes, CharSequence string, float pixelSize, Factory 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() { @@ -222,6 +230,11 @@ public class TypecastGlyph implements FontInt.GlyphInt { return this.metrics.getAdvance(pixelSize, useFrationalMetrics); } + @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 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 getOutlineShapes(List shapes, TypecastFont font, CharSequence string, float pixelSize, AffineTransform transform, Factory 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 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 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 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 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 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 vertexFactory) { + shape.closeLastOutline(); + } */ + + public static OutlineShape buildShape(OTGlyph glyph, Factory 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 diff --git a/src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java b/src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java index 32e2b6a39..f5cf8dd95 100644 --- a/src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java +++ b/src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java @@ -121,6 +121,8 @@ public class AffineTransform implements Cloneable, Serializable { } } + public final Vertex.Factory getFactory() { return pointFactory; } + /* * Method returns type of affine transformation. * @@ -403,12 +405,10 @@ public class AffineTransform implements Cloneable, Serializable { public Vertex transform(Vertex src, Vertex dst) { if (dst == null) { - dst = pointFactory.create(); + dst = pointFactory.create(src.getId(), src.isOnCurve(), src.getTexCoord()); } - - float x = src.getX(); - float y = src.getY(); - + final float x = src.getX(); + final float y = src.getY(); dst.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, 0f); return dst; } @@ -416,12 +416,12 @@ public class AffineTransform implements Cloneable, Serializable { public void transform(Vertex[] src, int srcOff, Vertex[] dst, int dstOff, int length) { while (--length >= 0) { Vertex srcPoint = src[srcOff++]; - float x = srcPoint.getX(); - float y = srcPoint.getY(); Vertex dstPoint = dst[dstOff]; if (dstPoint == null) { throw new IllegalArgumentException("dst["+dstOff+"] is null"); } + final float x = srcPoint.getX(); + final float y = srcPoint.getY(); dstPoint.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, 0f); dst[dstOff++] = dstPoint; } @@ -446,12 +446,10 @@ public class AffineTransform implements Cloneable, Serializable { public Vertex deltaTransform(Vertex src, Vertex dst) { if (dst == null) { - dst = pointFactory.create(); + dst = pointFactory.create(src.getId(), src.isOnCurve(), src.getTexCoord()); } - - float x = src.getX(); - float y = src.getY(); - + final float x = src.getX(); + final float y = src.getY(); dst.setCoord(x * m00 + y * m01, x * m10 + y * m11, 0f); return dst; } @@ -471,12 +469,10 @@ public class AffineTransform implements Cloneable, Serializable { throw new NoninvertibleTransformException(determinantIsZero); } if (dst == null) { - dst = pointFactory.create(); + dst = pointFactory.create(src.getId(), src.isOnCurve(), src.getTexCoord()); } - - float x = src.getX() - m02; - float y = src.getY() - m12; - + final float x = src.getX() - m02; + final float y = src.getY() - m12; dst.setCoord((x * m11 - y * m01) / det, (y * m00 - x * m10) / det, 0f); return dst; } @@ -502,7 +498,7 @@ public class AffineTransform implements Cloneable, Serializable { return null; } if (src instanceof Path2D) { - return ((Path2D)src).createTransformedShape(this); + return src.createTransformedShape(this); } PathIterator path = src.iterator(this); Path2D dst = new Path2D(path.getWindingRule()); diff --git a/src/jogl/classes/jogamp/graph/geom/plane/Path2D.java b/src/jogl/classes/jogamp/graph/geom/plane/Path2D.java index 33b80d6b8..a87c0a0a1 100644 --- a/src/jogl/classes/jogamp/graph/geom/plane/Path2D.java +++ b/src/jogl/classes/jogamp/graph/geom/plane/Path2D.java @@ -21,8 +21,8 @@ package jogamp.graph.geom.plane; import java.util.NoSuchElementException; +import com.jogamp.graph.geom.SVertex; import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.opengl.SVertex; import com.jogamp.opengl.math.geom.AABBox; -- cgit v1.2.3