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. --- .../com/jogamp/graph/curve/OutlineShape.java | 125 ++++++-- .../classes/com/jogamp/graph/curve/Region.java | 84 ++++-- .../jogamp/graph/curve/opengl/TextRenderUtil.java | 332 +++++++++++++++++++++ .../jogamp/graph/curve/opengl/TextRenderer.java | 199 ------------ .../com/jogamp/graph/curve/tess/Triangulator.java | 13 +- src/jogl/classes/com/jogamp/graph/font/Font.java | 9 +- .../classes/com/jogamp/graph/geom/Outline.java | 9 +- .../classes/com/jogamp/graph/geom/SVertex.java | 225 ++++++++++++++ .../classes/com/jogamp/graph/geom/Triangle.java | 67 ++++- src/jogl/classes/com/jogamp/graph/geom/Vertex.java | 4 + .../com/jogamp/graph/geom/opengl/SVertex.java | 201 ------------- 11 files changed, 796 insertions(+), 472 deletions(-) create mode 100644 src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java delete mode 100644 src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java create mode 100644 src/jogl/classes/com/jogamp/graph/geom/SVertex.java delete mode 100644 src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java (limited to 'src/jogl/classes/com/jogamp/graph') diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java index c8d5a9db6..ee1dae4ca 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java +++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java @@ -107,15 +107,27 @@ public class OutlineShape implements Comparable { } public static final int DIRTY_BOUNDS = 1 << 0; + /** + * Modified shape, requires to update the vertices and triangles, here: vertices. + */ + public static final int DIRTY_VERTICES = 1 << 1; + /** + * Modified shape, requires to update the vertices and triangles, here: triangulation. + */ + public static final int DIRTY_TRIANGLES = 1 << 2; private final Vertex.Factory vertexFactory; - private VerticesState outlineState; /** The list of {@link Outline}s that are part of this * outline shape. */ - /* pp */ ArrayList outlines; + /* pp */ final ArrayList outlines; + private final AABBox bbox; + private final ArrayList triangles; + private final ArrayList vertices; + + private VerticesState outlineState; /** dirty bits DIRTY_BOUNDS */ private int dirtyBits; @@ -128,6 +140,8 @@ public class OutlineShape implements Comparable { this.outlines.add(new Outline()); this.outlineState = VerticesState.UNDEFINED; this.bbox = new AABBox(); + this.triangles = new ArrayList(); + this.vertices = new ArrayList(); this.dirtyBits = 0; } @@ -137,6 +151,8 @@ public class OutlineShape implements Comparable { outlines.add(new Outline()); outlineState = VerticesState.UNDEFINED; bbox.reset(); + vertices.clear(); + triangles.clear(); dirtyBits = 0; } @@ -200,6 +216,8 @@ public class OutlineShape implements Comparable { if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { bbox.resize(outline.getBounds()); } + // vertices.addAll(outline.getVertices()); // FIXME: can do and remove DIRTY_VERTICES ? + dirtyBits |= DIRTY_TRIANGLES | DIRTY_VERTICES; return; } } @@ -207,6 +225,7 @@ public class OutlineShape implements Comparable { if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { bbox.resize(outline.getBounds()); } + dirtyBits |= DIRTY_TRIANGLES | DIRTY_VERTICES; } /** Insert the {@link OutlineShape} elements of type {@link Outline}, .. at the end of this shape, @@ -239,7 +258,7 @@ public class OutlineShape implements Comparable { throw new NullPointerException("outline is null"); } outlines.set(position, outline); - dirtyBits |= DIRTY_BOUNDS; + dirtyBits |= DIRTY_BOUNDS | DIRTY_TRIANGLES | DIRTY_VERTICES; } /** Removes the {@link Outline} element at the given {@code position}. @@ -249,7 +268,7 @@ public class OutlineShape implements Comparable { * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position >= getOutlineNumber()) */ public final Outline removeOutline(int position) throws IndexOutOfBoundsException { - dirtyBits |= DIRTY_BOUNDS; + dirtyBits |= DIRTY_BOUNDS | DIRTY_TRIANGLES | DIRTY_VERTICES; return outlines.remove(position); } @@ -278,6 +297,8 @@ public class OutlineShape implements Comparable { if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { bbox.resize(lo.getBounds()); } + // vertices.add(v); // FIXME: can do and remove DIRTY_VERTICES ? + dirtyBits |= DIRTY_TRIANGLES | DIRTY_VERTICES; } /** Adds a vertex to the last open outline in the shape. @@ -291,6 +312,7 @@ public class OutlineShape implements Comparable { if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { bbox.resize(lo.getBounds()); } + dirtyBits |= DIRTY_TRIANGLES | DIRTY_VERTICES; } /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute @@ -338,7 +360,9 @@ public class OutlineShape implements Comparable { * is equal to the first.

*/ public void closeLastOutline() { - getLastOutline().setClosed(true); + if( getLastOutline().setClosed(true) ) { + dirtyBits |= DIRTY_TRIANGLES | DIRTY_VERTICES; + } } /** @@ -348,7 +372,8 @@ public class OutlineShape implements Comparable { return outlineState; } - /** Ensure the outlines represent + /** + * Ensure the outlines represent * the specified destinationType. * and removes all overlaps in boundary triangles * @param destinationType the target outline's vertices state. Currently only @@ -376,6 +401,7 @@ public class OutlineShape implements Comparable { outline.addVertex(index, vertexFactory.create(v1, 0, 3, false)); outline.addVertex(index+2, vertexFactory.create(v3, 0, 3, false)); + dirtyBits |= DIRTY_VERTICES; } /** Check overlaps between curved triangles @@ -480,10 +506,12 @@ public class OutlineShape implements Comparable { i++; vertexCount++; outline.addVertex(i, v); + dirtyBits |= DIRTY_VERTICES; } } if(vertexCount <= 0) { outlines.remove(outline); + dirtyBits |= DIRTY_VERTICES; cc--; count--; continue; @@ -511,37 +539,90 @@ public class OutlineShape implements Comparable { } } - /** @return the list of concatenated vertices associated with all - * {@code Outline}s of this object + /** + * Return list of concatenated vertices associated with all + * {@code Outline}s of this object. + *

+ * Vertices are cached until marked dirty. + *

+ * FIXME: Add memory optimization, i.e. VBO layout */ public ArrayList getVertices() { - ArrayList vertices = new ArrayList(); - for(int i=0; i + * Triangles are cached until marked dirty. + *

* @return an arraylist of triangles representing the filled region * which is produced by the combination of the outlines + * FIXME: Add memory optimization, i.e. VBO layout */ - public ArrayList triangulate() { - if(outlines.size() == 0){ - return null; + public ArrayList getTriangles() { + final boolean updated; + if( 0 != ( DIRTY_TRIANGLES & dirtyBits ) ) { + transformOutlines(OutlineShape.VerticesState.QUADRATIC_NURBS); + triangulateImpl(); + updated = true; + } else { + updated = false; } - sortOutlines(); - generateVertexIds(); - - Triangulator triangulator2d = Triangulation.create(); - for(int index = 0; index triangles = triangulator2d.generate(); - triangulator2d.reset(); + return triangles; + } + /** + * Triangulate the {@link OutlineShape} generating a list of triangles, + * while {@link #transformOutlines(VerticesState)} beforehand. + *

+ * Triangles are cached until marked dirty. + *

+ * @return an arraylist of triangles representing the filled region + * which is produced by the combination of the outlines + * FIXME: Add memory optimization, i.e. VBO layout + */ + public ArrayList getTriangles(VerticesState destinationType) { + final boolean updated; + if( 0 != ( DIRTY_TRIANGLES & dirtyBits ) ) { + transformOutlines(destinationType); + triangulateImpl(); + updated = true; + } else { + updated = false; + } + if(Region.DEBUG_INSTANCE) { + System.err.println("OutlineShape.getTriangles().2: "+triangles.size()+", updated "+updated); + } return triangles; } diff --git a/src/jogl/classes/com/jogamp/graph/curve/Region.java b/src/jogl/classes/com/jogamp/graph/curve/Region.java index e36e37c26..2b6da2084 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/Region.java +++ b/src/jogl/classes/com/jogamp/graph/curve/Region.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import jogamp.graph.curve.opengl.RegionFactory; +import jogamp.graph.geom.plane.AffineTransform; import jogamp.opengl.Debug; import com.jogamp.graph.curve.opengl.GLRegion; @@ -46,8 +47,7 @@ public abstract class Region { /** Debug flag for region impl (graph.curve) */ public static final boolean DEBUG = Debug.debug("graph.curve"); - - public static final boolean DEBUG_INSTANCE = false; + public static final boolean DEBUG_INSTANCE = Debug.debug("graph.curve.instance"); /** View based Anti-Aliasing, A Two pass region rendering, slower and more * resource hungry (FBO), but AA is perfect. Otherwise the default fast one @@ -65,7 +65,9 @@ public abstract class Region { private boolean dirty = true; protected int numVertices = 0; protected final AABBox box = new AABBox(); + /** FIXME: Think about a rendering storage optimization (VBO ... )! */ protected ArrayList triangles = new ArrayList(); + /** FIXME: Think about a rendering storage optimization (VBO ... )! */ protected ArrayList vertices = new ArrayList(); public static boolean isVBAA(int renderModes) { @@ -99,7 +101,7 @@ public abstract class Region { */ public static Region create(OutlineShape outlineShape, int renderModes) { final Region region = RegionFactory.create(renderModes); - region.addOutlineShape(outlineShape); + region.addOutlineShape(outlineShape, null); return region; } @@ -136,27 +138,32 @@ public abstract class Region { return numVertices; } - /** Adds a {@link Triangle} object to the Region This triangle will be bound - * to OGL objects on the next call to {@code update} - * - * @param tri - * a triangle object - * - * @see update(GL2ES2) */ - public void addTriangle(Triangle tri) { - triangles.add(tri); - setDirty(true); - } - /** Adds a list of {@link Triangle} objects to the Region These triangles are * to be binded to OGL objects on the next call to {@code update} * * @param tris * a list of triangle objects + * @param idxOffset TODO * * @see update(GL2ES2) */ - public void addTriangles(List tris) { - triangles.addAll(tris); + public void addTriangles(List tris, AffineTransform t, int idxOffset) { + if( true && null != t ) { + for(int i=0; i verts) { vertices.addAll(verts); numVertices = vertices.size(); + if(DEBUG_INSTANCE) { + System.err.println("Region.addVertices(): tris: "+triangles.size()+", verts "+vertices.size()); + } setDirty(true); } - public void addOutlineShape(OutlineShape shape) { - shape.transformOutlines(OutlineShape.VerticesState.QUADRATIC_NURBS); - List tris = shape.triangulate(); + public void addOutlineShape(OutlineShape shape, AffineTransform t) { + final List tris = shape.getTriangles(OutlineShape.VerticesState.QUADRATIC_NURBS); if(null != tris) { - triangles.addAll(tris); + if( false && null != t ) { + for(int i=0; i verts = shape.getVertices(); + // vertices.addAll(verts); for (int j = 0; j < shape.outlines.size(); j++) { final ArrayList sovs = shape.outlines.get(j).getVertices(); for (int k = 0; k < sovs.size(); k++) { - final Vertex v = sovs.get(k); + final Vertex v; + if( null != t ) { + v = t.transform(sovs.get(k), null); + } else { + v = sovs.get(k); + } v.setId(numVertices++); vertices.add(v); } } + // numVertices = vertices.size(); + } + if(DEBUG_INSTANCE) { + System.err.println("Region.addOutlineShape(): tris: "+triangles.size()+", verts "+vertices.size()); } setDirty(true); } public void addOutlineShapes(List shapes) { for (int i = 0; i < shapes.size(); i++) { - addOutlineShape(shapes.get(i)); + addOutlineShape(shapes.get(i), null); + } + if(DEBUG_INSTANCE) { + System.err.println("Region.addOutlineShapes(): tris: "+triangles.size()+", verts "+vertices.size()); } setDirty(true); } diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java new file mode 100644 index 000000000..cef589f4f --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java @@ -0,0 +1,332 @@ +/** + * Copyright 2014 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 com.jogamp.graph.curve.opengl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLException; + +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.font.Font; +import com.jogamp.graph.font.Font.Glyph; +import com.jogamp.graph.geom.Triangle; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; + +/** + * + * FIXME: Add VBO Vertex Factory for drawString3D ! + * + */ +public class TextRenderUtil { + + public final Renderer renderer; + + public TextRenderUtil(final Renderer renderer) { + this.renderer = renderer; + } + + /** + * Generate a Region to represent this Object. + *

+ * Each glyph is cached and reused. + *

+ * + * @param renderModes bit-field of modes, e.g. {@link Region#VARIABLE_CURVE_WEIGHT_BIT}, {@link Region#VBAA_RENDERING_BIT} + * @param vertexFactory vertex impl factory {@link Factory} + * @param font the target {@link Font} + * @param str string text + * @param pixelSize + */ + public static GLRegion createRegion(final int renderModes, final Factory vertexFactory, + final Font font, final CharSequence str, final int pixelSize) { + final int charCount = str.length(); + + final GLRegion region = RegionFactory.create(renderModes); + // region.setFlipped(true); + 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); + final AffineTransform transform = new AffineTransform(vertexFactory); + final AffineTransform t = new AffineTransform(vertexFactory); + + float y = 0; + float advanceTotal = 0; + int numVertices = region.getNumVertices(); + + for(int i=0; i< charCount; i++) { + final char character = str.charAt(i); + if( '\n' == character ) { + y += advanceY; + advanceTotal = 0; + } else if (character == ' ') { + advanceTotal += font.getAdvanceWidth(Glyph.ID_SPACE, pixelSize); + } else { + if(Region.DEBUG_INSTANCE) { + System.err.println("XXXXXXXXXXXXXXx char: "+character+", scale: "+scale+"; translate: "+advanceTotal+", "+y); + } + t.setTransform(transform); // reset transform + t.translate(advanceTotal, y); + t.scale(scale, scale); + + final Font.Glyph glyph = font.getGlyph(character); + final OutlineShape glyphShape = glyph.getShape(); + if( null == glyphShape || glyphShape.getVertices().size() < 3 ) { + continue; + } + // glyphShape.closeLastOutline(); + + if( false ) { + region.addOutlineShape(glyphShape, t); + } else { + final ArrayList trisIn = glyphShape.getTriangles(); + region.addTriangles(trisIn, t, numVertices); + + final ArrayList gVertices = glyphShape.getVertices(); + for(int j=0; j vertexFactory, + final Font font, final CharSequence str, final int pixelSize) { + final List shapesIn = font.getOutlineShapes(null, str, pixelSize, vertexFactory); + final ArrayList shapesOut = new ArrayList(); + final int numGlyps = shapesIn.size(); + for (int index=0;index gtris = shape.getTriangles(); + region.addTriangles(gtris, null, 0); + + final ArrayList gVertices = shape.getVertices(); + for(int j=0; j iterator = stringCacheMap.values().iterator(); + while(iterator.hasNext()){ + GlyphString glyphString = iterator.next(); + glyphString.destroy(gl, rs); + } + stringCacheMap.clear(); + stringCacheArray.clear(); + } */ + + public void destroy(GL2ES2 gl) { + // fluchCache(gl) already called + final Iterator iterator = stringCacheMap.values().iterator(); + while(iterator.hasNext()){ + final GLRegion region = iterator.next(); + region.destroy(gl, renderer.getRenderState()); + } + stringCacheMap.clear(); + stringCacheArray.clear(); + } + + /** + *

Sets the cache limit for reusing GlyphString's and their Region. + * Default is {@link #DEFAULT_CACHE_LIMIT}, -1 unlimited, 0 turns cache off, >0 limited

+ * + *

The cache will be validate when the next string rendering happens.

+ * + * @param newLimit new cache size + * + * @see #DEFAULT_CACHE_LIMIT + */ + public final void setCacheLimit(int newLimit ) { stringCacheLimit = newLimit; } + + /** + * Sets the cache limit, see {@link #setCacheLimit(int)} and validates the cache. + * + * @see #setCacheLimit(int) + * + * @param gl current GL used to remove cached objects if required + * @param newLimit new cache size + */ + public final void setCacheLimit(GL2ES2 gl, int newLimit ) { stringCacheLimit = newLimit; validateCache(gl, 0); } + + /** + * @return the current cache limit + */ + public final int getCacheLimit() { return stringCacheLimit; } + + /** + * @return the current utilized cache size, <= {@link #getCacheLimit()} + */ + public final int getCacheSize() { return stringCacheArray.size(); } + + protected final void validateCache(GL2ES2 gl, int space) { + if ( getCacheLimit() > 0 ) { + while ( getCacheSize() + space > getCacheLimit() ) { + removeCachedRegion(gl, 0); + } + } + } + + protected final GLRegion getCachedRegion(Font font, CharSequence str, int fontSize) { + return stringCacheMap.get(getKey(font, str, fontSize)); + } + + protected final void addCachedRegion(GL2ES2 gl, Font font, CharSequence str, int fontSize, GLRegion glyphString) { + if ( 0 != getCacheLimit() ) { + final String key = getKey(font, str, fontSize); + final GLRegion oldRegion = stringCacheMap.put(key, glyphString); + if ( null == oldRegion ) { + // new entry .. + validateCache(gl, 1); + stringCacheArray.add(stringCacheArray.size(), key); + } /// else overwrite is nop .. + } + } + + protected final void removeCachedRegion(GL2ES2 gl, Font font, CharSequence str, int fontSize) { + final String key = getKey(font, str, fontSize); + GLRegion region = stringCacheMap.remove(key); + if(null != region) { + region.destroy(gl, renderer.getRenderState()); + } + stringCacheArray.remove(key); + } + + protected final void removeCachedRegion(GL2ES2 gl, int idx) { + final String key = stringCacheArray.remove(idx); + final GLRegion region = stringCacheMap.remove(key); + if(null != region) { + region.destroy(gl, renderer.getRenderState()); + } + } + + protected final String getKey(Font font, CharSequence str, int fontSize) { + final StringBuilder sb = new StringBuilder(); + return font.getName(sb, Font.NAME_UNIQUNAME) + .append(".").append(str.hashCode()).append(".").append(fontSize).toString(); + } + + /** Default cache limit, see {@link #setCacheLimit(int)} */ + public static final int DEFAULT_CACHE_LIMIT = 256; + + private final HashMap stringCacheMap = new HashMap(DEFAULT_CACHE_LIMIT); + private final ArrayList stringCacheArray = new ArrayList(DEFAULT_CACHE_LIMIT); + private int stringCacheLimit = DEFAULT_CACHE_LIMIT; +} \ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java deleted file mode 100644 index 44007ca79..000000000 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java +++ /dev/null @@ -1,199 +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 com.jogamp.graph.curve.opengl; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; - -import javax.media.opengl.GL2ES2; - -import jogamp.graph.curve.text.GlyphString; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.font.Font; -import com.jogamp.graph.geom.Vertex.Factory; - -/** - * @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 abstract class TextRenderer extends Renderer { - /** - * Create a Hardware accelerated Text Renderer. - * @param rs the used {@link RenderState} - * @param renderModes either {@link com.jogamp.graph.curve.opengl.GLRegion#SINGLE_PASS} or {@link com.jogamp.graph.curve.Region#VBAA_RENDERING_BIT} - */ - public static TextRenderer create(RenderState rs, int renderModes) { - return new jogamp.graph.curve.opengl.TextRendererImpl01(rs, renderModes); - } - - protected TextRenderer(RenderState rs, int type) { - super(rs, type); - } - - - /** Render the String in 3D space wrt to the font provided at the position provided - * the outlines will be generated, if not yet generated - * @param gl the current GL state - * @param font {@link Font} to be used - * @param str text to be rendered - * @param fontSize font size - * @param texWidth desired texture width for multipass-rendering. - * The actual used texture-width is written back when mp rendering is enabled, otherwise the store is untouched. - * @throws Exception if TextRenderer not initialized - */ - public abstract void drawString3D(GL2ES2 gl, Font font, - String str, int fontSize, int[/*1*/] texSize); - - /**Create the resulting {@link GlyphString} that represents - * the String wrt to the font. - * @param font {@link Font} to be used - * @param size font size - * @param str {@link String} to be created - * @return the resulting GlyphString inclusive the generated region - */ - public GlyphString createString(GL2ES2 gl, Font font, int size, String str) { - if(DEBUG_INSTANCE) { - System.err.println("createString: "+getCacheSize()+"/"+getCacheLimit()+" - "+Font.NAME_UNIQUNAME + " - " + str + " - " + size); - } - final GlyphString glyphString = GlyphString.createString(null, rs.getVertexFactory(), font, size, str); - glyphString.createRegion(gl, renderModes); - return glyphString; - } - - /** FIXME - public void flushCache(GL2ES2 gl) { - Iterator iterator = stringCacheMap.values().iterator(); - while(iterator.hasNext()){ - GlyphString glyphString = iterator.next(); - glyphString.destroy(gl, rs); - } - stringCacheMap.clear(); - stringCacheArray.clear(); - } */ - - @Override - protected void destroyImpl(GL2ES2 gl) { - // fluchCache(gl) already called - Iterator iterator = stringCacheMap.values().iterator(); - while(iterator.hasNext()){ - GlyphString glyphString = iterator.next(); - glyphString.destroy(gl, rs); - } - stringCacheMap.clear(); - stringCacheArray.clear(); - } - - /** - *

Sets the cache limit for reusing GlyphString's and their Region. - * Default is {@link #DEFAULT_CACHE_LIMIT}, -1 unlimited, 0 turns cache off, >0 limited

- * - *

The cache will be validate when the next string rendering happens.

- * - * @param newLimit new cache size - * - * @see #DEFAULT_CACHE_LIMIT - */ - public final void setCacheLimit(int newLimit ) { stringCacheLimit = newLimit; } - - /** - * Sets the cache limit, see {@link #setCacheLimit(int)} and validates the cache. - * - * @see #setCacheLimit(int) - * - * @param gl current GL used to remove cached objects if required - * @param newLimit new cache size - */ - public final void setCacheLimit(GL2ES2 gl, int newLimit ) { stringCacheLimit = newLimit; validateCache(gl, 0); } - - /** - * @return the current cache limit - */ - public final int getCacheLimit() { return stringCacheLimit; } - - /** - * @return the current utilized cache size, <= {@link #getCacheLimit()} - */ - public final int getCacheSize() { return stringCacheArray.size(); } - - protected final void validateCache(GL2ES2 gl, int space) { - if ( getCacheLimit() > 0 ) { - while ( getCacheSize() + space > getCacheLimit() ) { - removeCachedGlyphString(gl, 0); - } - } - } - - protected final GlyphString getCachedGlyphString(Font font, String str, int fontSize) { - return stringCacheMap.get(getKey(font, str, fontSize)); - } - - protected final void addCachedGlyphString(GL2ES2 gl, Font font, String str, int fontSize, GlyphString glyphString) { - if ( 0 != getCacheLimit() ) { - final String key = getKey(font, str, fontSize); - GlyphString oldGlyphString = stringCacheMap.put(key, glyphString); - if ( null == oldGlyphString ) { - // new entry .. - validateCache(gl, 1); - stringCacheArray.add(stringCacheArray.size(), key); - } /// else overwrite is nop .. - } - } - - protected final void removeCachedGlyphString(GL2ES2 gl, Font font, String str, int fontSize) { - final String key = getKey(font, str, fontSize); - GlyphString glyphString = stringCacheMap.remove(key); - if(null != glyphString) { - glyphString.destroy(gl, rs); - } - stringCacheArray.remove(key); - } - - protected final void removeCachedGlyphString(GL2ES2 gl, int idx) { - final String key = stringCacheArray.remove(idx); - final GlyphString glyphString = stringCacheMap.remove(key); - if(null != glyphString) { - glyphString.destroy(gl, rs); - } - } - - protected final String getKey(Font font, String str, int fontSize) { - final StringBuilder sb = new StringBuilder(); - return font.getName(sb, Font.NAME_UNIQUNAME) - .append(".").append(str.hashCode()).append(".").append(fontSize).toString(); - } - - /** Default cache limit, see {@link #setCacheLimit(int)} */ - public static final int DEFAULT_CACHE_LIMIT = 256; - - private final HashMap stringCacheMap = new HashMap(DEFAULT_CACHE_LIMIT); - private final ArrayList stringCacheArray = new ArrayList(DEFAULT_CACHE_LIMIT); - private int stringCacheLimit = DEFAULT_CACHE_LIMIT; -} \ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java b/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java index 4e8c400e0..39e84171b 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java +++ b/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java @@ -28,7 +28,7 @@ package com.jogamp.graph.curve.tess; -import java.util.ArrayList; +import java.util.List; import com.jogamp.graph.geom.Outline; import com.jogamp.graph.geom.Triangle; @@ -49,18 +49,19 @@ import com.jogamp.graph.geom.Triangle; */ public interface Triangulator { - /** Add a curve to the list of Outlines + /** + * Add a curve to the list of Outlines * describing the shape + * @param sink list where the generated triangles will be added * @param outline a bounding {@link Outline} */ - public void addCurve(Outline outline); + public void addCurve(List sink, Outline outline); /** Generate the triangulation of the provided * List of {@link Outline}s - * @return an arraylist of {@link Triangle}s resembling the - * final shape. + * @param sink list where the generated triangles will be added */ - public ArrayList generate(); + public void generate(List sink); /** Reset the triangulation to initial state * Clearing cached data diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java index 6c0041de9..1e0572037 100644 --- a/src/jogl/classes/com/jogamp/graph/font/Font.java +++ b/src/jogl/classes/com/jogamp/graph/font/Font.java @@ -91,6 +91,7 @@ public interface Font { public float getScale(float pixelSize); public AABBox getBBox(float pixelSize); public float getAdvance(float pixelSize, boolean useFrationalMetrics); + public OutlineShape getShape(); public int hashCode(); } @@ -117,13 +118,7 @@ public interface Font { public boolean isPrintableChar( char c ); /** - * @param glyph source of the created OutlineShape - * @param vertexFactory factory for vertices - * @return OutlineShape of the glyph - */ - public OutlineShape getOutlineShape(Glyph glyph, Factory vertexFactory); - - /** + * @deprecated Remove altogether - use {@link #getOutlineShape(Glyph, Factory) * @param shapes optional storage of OutlineShapes passed by user, new shapes are appended * @param string source of the created OutlineShapes * @param pixelSize diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java index 77a318078..26eba2741 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java @@ -156,17 +156,20 @@ public class Outline implements Cloneable, Comparable { * equal to the first vertex. If not Equal adds a * vertex at the end to the list. * @param closed + * @return true if closing performed, otherwise false for NOP */ - public final void setClosed(boolean closed) { + public final boolean setClosed(boolean closed) { this.closed = closed; if( closed && !isEmpty() ) { - Vertex first = vertices.get(0); - Vertex last = getLastVertex(); + final Vertex first = vertices.get(0); + final Vertex last = getLastVertex(); if(!VectorUtil.checkEquality(first.getCoord(), last.getCoord())){ Vertex v = first.clone(); vertices.add(v); + return true; } } + return false; } /** Compare two outlines with Bounding Box area diff --git a/src/jogl/classes/com/jogamp/graph/geom/SVertex.java b/src/jogl/classes/com/jogamp/graph/geom/SVertex.java new file mode 100644 index 000000000..99f10a694 --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/geom/SVertex.java @@ -0,0 +1,225 @@ +/** + * 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 com.jogamp.graph.geom; + +import com.jogamp.opengl.math.VectorUtil; + +/** A Simple Vertex Implementation. Where the coordinates, and other attributes are + * float based, and the coordinates and texture coordinates are saved in two float arrays. + * + */ +public class SVertex implements Vertex { + private int id; + protected final float[] coord = new float[3]; + protected boolean onCurve; + private final float[] texCoord = new float[2]; + + static final Factory factory = new Factory(); + + public static Factory factory() { return factory; } + + public static class Factory implements Vertex.Factory { + @Override + public SVertex create() { + return new SVertex(); + } + + public SVertex create(final Vertex src) { + return new SVertex(src); + } + + @Override + public SVertex create(final int id, final boolean onCurve, final float[] texCoordsBuffer) { + return new SVertex(id, onCurve, texCoordsBuffer); + } + + @Override + public SVertex create(final float x, final float y, final float z, final boolean onCurve) { + return new SVertex(x, y, z, onCurve); + } + + @Override + public SVertex create(float[] coordsBuffer, int offset, int length, boolean onCurve) { + return new SVertex(coordsBuffer, offset, length, onCurve); + } + } + + public SVertex() { + this.id = Integer.MAX_VALUE; + } + + public SVertex(final Vertex src) { + this.id = src.getId(); + System.arraycopy(src.getCoord(), 0, coord, 0, 3); + setOnCurve(src.isOnCurve()); + System.arraycopy(src.getTexCoord(), 0, texCoord, 0, 2); + } + + public SVertex(final int id, final boolean onCurve, final float[] texCoordsBuffer) { + this.id = id; + this.onCurve = onCurve; + System.arraycopy(texCoordsBuffer, 0, texCoord, 0, 2); + } + + public SVertex(final float x, final float y, final float z, final boolean onCurve) { + this.id = Integer.MAX_VALUE; + setCoord(x, y, z); + setOnCurve(onCurve); + } + + public SVertex(final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) { + this.id = Integer.MAX_VALUE; + setCoord(coordsBuffer, offset, length); + setOnCurve(onCurve); + } + + public SVertex(float[] coordsBuffer, float[] texCoordsBuffer, boolean onCurve) { + this.id = Integer.MAX_VALUE; + System.arraycopy(coordsBuffer, 0, coord, 0, 3); + System.arraycopy(texCoordsBuffer, 0, texCoord, 0, 2); + setOnCurve(onCurve); + } + + @Override + public final void setCoord(float x, float y, float z) { + coord[0] = x; + coord[1] = y; + coord[2] = z; + } + + @Override + public final void setCoord(float[] coordsBuffer, int offset, int length) { + System.arraycopy(coordsBuffer, offset, coord, 0, length); + } + + @Override + public int getCoordCount() { + return 3; + } + + @Override + public final float[] getCoord() { + return coord; + } + + @Override + public final void setX(float x) { + this.coord[0] = x; + } + + @Override + public final void setY(float y) { + this.coord[1] = y; + } + + @Override + public final void setZ(float z) { + this.coord[2] = z; + } + + @Override + public final float getX() { + return this.coord[0]; + } + + @Override + public final float getY() { + return this.coord[1]; + } + + @Override + public final float getZ() { + return this.coord[2]; + } + + @Override + public final boolean isOnCurve() { + return onCurve; + } + + @Override + public final void setOnCurve(boolean onCurve) { + this.onCurve = onCurve; + } + + @Override + public final int getId(){ + return id; + } + + @Override + public final void setId(int id){ + this.id = id; + } + + @Override + public boolean equals(Object obj) { + if( obj == this) { + return true; + } + if( null == obj || !(obj instanceof Vertex) ) { + return false; + } + final Vertex v = (Vertex) obj; + return this == v || + isOnCurve() == v.isOnCurve() && + VectorUtil.checkEqualityVec2(getTexCoord(), v.getTexCoord()) && + VectorUtil.checkEquality(getCoord(), v.getCoord()) ; + } + + @Override + public final float[] getTexCoord() { + return texCoord; + } + + @Override + public final void setTexCoord(float s, float t) { + texCoord[0] = s; + texCoord[1] = t; + } + + @Override + public final void setTexCoord(float[] texCoordsBuffer, int offset, int length) { + System.arraycopy(texCoordsBuffer, offset, texCoord, 0, length); + } + + /** + * @return deep clone of this Vertex elements + */ + @Override + public SVertex clone(){ + return new SVertex(this.coord, this.texCoord, this.onCurve); + } + + @Override + public String toString() { + return "[ID: " + id + ", onCurve: " + onCurve + + ": p " + coord[0] + ", " + coord[1] + ", " + coord[2] + + ", t " + texCoord[0] + ", " + texCoord[1] + "]"; + } +} diff --git a/src/jogl/classes/com/jogamp/graph/geom/Triangle.java b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java index a01cd834f..6de99c48b 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Triangle.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java @@ -27,14 +27,52 @@ */ package com.jogamp.graph.geom; +import com.jogamp.graph.curve.Region; + +import jogamp.graph.geom.plane.AffineTransform; + public class Triangle { - private int id = Integer.MAX_VALUE; - final private Vertex[] vertices; - private boolean[] boundaryEdges = new boolean[3]; + private final Vertex[] vertices = new Vertex[3]; + private final boolean[] boundaryEdges = new boolean[3]; private boolean[] boundaryVertices = null; + private int id; + + public Triangle(Vertex v1, Vertex v2, Vertex v3) { + id = Integer.MAX_VALUE; + vertices[0] = v1; + vertices[1] = v2; + vertices[2] = v3; + } + + public Triangle(Triangle src) { + id = src.id; + vertices[0] = src.vertices[0].clone(); + vertices[1] = src.vertices[1].clone(); + vertices[2] = src.vertices[2].clone(); + System.arraycopy(src.boundaryEdges, 0, boundaryEdges, 0, 3); + boundaryVertices = src.boundaryVertices; + } + + private Triangle(final int id, final boolean[] boundaryEdges, final boolean[] boundaryVertices){ + this.id = id; + System.arraycopy(boundaryEdges, 0, this.boundaryEdges, 0, 3); + this.boundaryVertices = boundaryVertices; + /** + if( null != boundaryVertices ) { + this.boundaryVertices = new boolean[3]; + System.arraycopy(boundaryVertices, 0, this.boundaryVertices, 0, 3); + } */ + } - public Triangle(Vertex ... v123){ - vertices = v123; + /** + * Returns a transformed a clone of this instance using the given AffineTransform. + */ + public Triangle transform(AffineTransform t) { + final Triangle tri = new Triangle(id, boundaryEdges, boundaryVertices); + tri.vertices[0] = t.transform(vertices[0], null); + tri.vertices[1] = t.transform(vertices[1], null); + tri.vertices[2] = t.transform(vertices[2], null); + return tri; } public int getId() { @@ -45,6 +83,21 @@ public class Triangle { this.id = id; } + public void addVertexIndicesOffset(int offset) { + if( 0 < offset ) { + final int i0 = vertices[0].getId(); + if( Integer.MAX_VALUE-offset > i0 ) { // Integer.MAX_VALUE != i0 // FIXME: renderer uses SHORT! + if(Region.DEBUG_INSTANCE) { + System.err.println("Triangle.addVertexIndicesOffset: "+i0+" + "+offset+" -> "+(i0+offset)); + } + vertices[0].setId(i0+offset); + vertices[1].setId(vertices[1].getId()+offset); + vertices[2].setId(vertices[2].getId()+offset); + } + } + } + + /** Returns array of 3 vertices, denominating the triangle. */ public Vertex[] getVertices() { return vertices; } @@ -57,10 +110,6 @@ public class Triangle { return boundaryVertices[0] || boundaryVertices[1] || boundaryVertices[2]; } - public void setEdgesBoundary(boolean[] boundary) { - this.boundaryEdges = boundary; - } - public boolean[] getEdgeBoundary() { return boundaryEdges; } diff --git a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java index 994253f71..fc9590ae7 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java @@ -37,6 +37,10 @@ public interface Vertex extends Vert3fImmutable, Cloneable { public static interface Factory { T create(); + T create(Vertex src); + + T create(int id, boolean onCurve, float[] texCoordsBuffer); + T create(float x, float y, float z, boolean onCurve); T create(float[] coordsBuffer, int offset, int length, boolean onCurve); diff --git a/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java b/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java deleted file mode 100644 index b27604a44..000000000 --- a/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java +++ /dev/null @@ -1,201 +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 com.jogamp.graph.geom.opengl; - -import com.jogamp.graph.geom.Vertex; -import com.jogamp.opengl.math.VectorUtil; - -/** A Simple Vertex Implementation. Where the coordinates, and other attributes are - * float based, and the coordinates and texture coordinates are saved in two float arrays. - * - */ -public class SVertex implements Vertex { - private int id = Integer.MAX_VALUE; - protected float[] coord = new float[3]; - protected boolean onCurve; - private float[] texCoord = new float[2]; - - static final Factory factory = new Factory(); - - public static Factory factory() { return factory; } - - public static class Factory implements Vertex.Factory { - @Override - public SVertex create() { - return new SVertex(); - } - - @Override - public SVertex create(float x, float y, float z, boolean onCurve) { - return new SVertex(x, y, z, onCurve); - } - - @Override - public SVertex create(float[] coordsBuffer, int offset, int length, boolean onCurve) { - return new SVertex(coordsBuffer, offset, length, onCurve); - } - } - - public SVertex() { - } - - public SVertex(float x, float y, float z, boolean onCurve) { - setCoord(x, y, z); - setOnCurve(onCurve); - } - - public SVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) { - setCoord(coordsBuffer, offset, length); - setOnCurve(onCurve); - } - - public SVertex(float[] coordsBuffer, int offset, int length, - float[] texCoordsBuffer, int offsetTC, int lengthTC, boolean onCurve) { - setCoord(coordsBuffer, offset, length); - setTexCoord(texCoordsBuffer, offsetTC, lengthTC); - setOnCurve(onCurve); - } - - @Override - public final void setCoord(float x, float y, float z) { - this.coord[0] = x; - this.coord[1] = y; - this.coord[2] = z; - } - - @Override - public final void setCoord(float[] coordsBuffer, int offset, int length) { - System.arraycopy(coordsBuffer, offset, coord, 0, length); - } - - @Override - public int getCoordCount() { - return 3; - } - - @Override - public final float[] getCoord() { - return coord; - } - - @Override - public final void setX(float x) { - this.coord[0] = x; - } - - @Override - public final void setY(float y) { - this.coord[1] = y; - } - - @Override - public final void setZ(float z) { - this.coord[2] = z; - } - - @Override - public final float getX() { - return this.coord[0]; - } - - @Override - public final float getY() { - return this.coord[1]; - } - - @Override - public final float getZ() { - return this.coord[2]; - } - - @Override - public final boolean isOnCurve() { - return onCurve; - } - - @Override - public final void setOnCurve(boolean onCurve) { - this.onCurve = onCurve; - } - - @Override - public final int getId(){ - return id; - } - - @Override - public final void setId(int id){ - this.id = id; - } - - @Override - public boolean equals(Object obj) { - if( obj == this) { - return true; - } - if( null == obj || !(obj instanceof Vertex) ) { - return false; - } - final Vertex v = (Vertex) obj; - return this == v || - isOnCurve() == v.isOnCurve() && - VectorUtil.checkEqualityVec2(getTexCoord(), v.getTexCoord()) && - VectorUtil.checkEquality(getCoord(), v.getCoord()) ; - } - - @Override - public final float[] getTexCoord() { - return texCoord; - } - - @Override - public final void setTexCoord(float s, float t) { - this.texCoord[0] = s; - this.texCoord[1] = t; - } - - @Override - public final void setTexCoord(float[] texCoordsBuffer, int offset, int length) { - System.arraycopy(texCoordsBuffer, offset, texCoord, 0, length); - } - - /** - * @return deep clone of this Vertex, but keeping the id blank - */ - @Override - public SVertex clone(){ - return new SVertex(this.coord, 0, 3, this.texCoord, 0, 2, this.onCurve); - } - - @Override - public String toString() { - return "[ID: " + id + ", onCurve: " + onCurve + - ": p " + coord[0] + ", " + coord[1] + ", " + coord[2] + - ", t " + texCoord[0] + ", " + texCoord[1] + "]"; - } -} -- cgit v1.2.3