diff options
Diffstat (limited to 'src')
11 files changed, 654 insertions, 157 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java index 1369061d3..fb0ff6a7e 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java +++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java @@ -43,19 +43,32 @@ import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.VectorUtil; import com.jogamp.opengl.math.geom.AABBox; - /** * A Generic shape objects which is defined by a list of Outlines. * This Shape can be transformed to triangulations. * The list of triangles generated are render-able by a Region object. * The triangulation produced by this Shape will define the * closed region defined by the outlines. - * + * <p> * One or more OutlineShape Object can be associated to a region * this is left as a high-level representation of the Objects. For * optimizations, flexibility requirements for future features. - * - * <br><br> + * </p> + * <p> + * <a name="windingrules"> + * Outline shape general {@link Winding} rules + * <ul> + * <li>Outer boundary shapes are required as {@link Winding#CCW}, if unsure + * <ul> + * <li>You may check {@link Winding} via {@link #getWindingOfLastOutline()} or {@link Outline#getWinding()} (optional)</li> + * <li>Use {@link #setWindingOfLastOutline(Winding)} before {@link #closeLastOutline(boolean)} or {@link #closePath()} } to enforce {@link Winding#CCW}, or</li> + * <li>use {@link Outline#setWinding(Winding)} on a specific {@link Outline} to enforce {@link Winding#CCW}.</li> + * <li>If e.g. the {@link Winding} has changed for an {@link Outline} by above operations, its vertices have been reversed.</li> + * </ul></li> + * <li>Inner shapes or holes are adjusted to be {@link Winding#CW}, no user consideration is required here.</li> + * <li>Safe path: Simply create all shapes with {@link Winding#CCW} or apply {@link Outline#setWinding(Winding)}.</li> + * </ul> + * </p> * Example to creating an Outline Shape: * <pre> addVertex(...) @@ -67,33 +80,35 @@ import com.jogamp.opengl.math.geom.AABBox; addVertex(...) * </pre> * + * <p> * The above will create two outlines each with three vertices. By adding these two outlines to * the OutlineShape, we are stating that the combination of the two outlines represent the shape. - * <br> - * + * </p> + * <p> * To specify that the shape is curved at a region, the on-curve flag should be set to false * for the vertex that is in the middle of the curved region (if the curved region is defined by 3 * vertices (quadratic curve). - * <br> + * </p> + * <p> * In case the curved region is defined by 4 or more vertices the middle vertices should both have * the on-curve flag set to false. - * - * <br>Example: <br> + * </p> + * Example: * <pre> addVertex(0,0, true); addVertex(0,1, false); addVertex(1,1, false); addVertex(1,0, true); * </pre> - * + * <p> * The above snippet defines a cubic nurbs curve where (0,1 and 1,1) * do not belong to the final rendered shape. + * </p> * * <i>Implementation Notes:</i><br> * <ul> * <li> The first vertex of any outline belonging to the shape should be on-curve</li> * <li> Intersections between off-curved parts of the outline is not handled</li> - * <li> Outline shape winding shall be constructed counter clock wise ({@link Winding#CCW}).</li> * </ul> * * @see Outline @@ -226,6 +241,21 @@ public final class OutlineShape implements Comparable<OutlineShape> { } /** + * Compute the {@link Winding} of the {@link #getLastOutline()} using the {@link #area(ArrayList)} function over all of its vertices. + * @return {@link Winding#CCW} or {@link Winding#CW} + */ + public final Winding getWindingOfLastOutline() { + return getLastOutline().getWinding(); + } + + /** + * Sets the enforced {@link Winding} of the {@link #getLastOutline()}. + */ + public final void setWindingOfLastOutline(final Winding enforced) { + getLastOutline().setWinding(enforced); + } + + /** * Add a new empty {@link Outline} * to the end of this shape's outline list. * <p>If the {@link #getLastOutline()} is empty already, no new one will be added.</p> @@ -358,9 +388,8 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Adds a vertex to the last open outline to the shape's tail. * - * The constructed shape should be {@link Winding#CCW}. - * * @param v the vertex to be added to the OutlineShape + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final Vertex v) { final Outline lo = getLastOutline(); @@ -375,10 +404,9 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Adds a vertex to the last open outline to the shape at {@code position} * - * The constructed shape should be {@link Winding#CCW}. - * * @param position index within the last open outline, at which the vertex will be added * @param v the vertex to be added to the OutlineShape + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final int position, final Vertex v) { final Outline lo = getLastOutline(); @@ -393,12 +421,10 @@ public final class OutlineShape implements Comparable<OutlineShape> { * Add a 2D {@link Vertex} to the last open outline to the shape's tail. * The 2D vertex will be represented as Z=0. * - * The constructed shape should be {@link Winding#CCW}. - * * @param x the x coordinate * @param y the y coordniate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + * @param onCurve flag if this vertex is on the final curve or defines a curved region of the shape around this vertex. + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final float x, final float y, final boolean onCurve) { addVertex(vertexFactory.create(x, y, 0f, onCurve)); @@ -408,13 +434,11 @@ public final class OutlineShape implements Comparable<OutlineShape> { * Add a 2D {@link Vertex} to the last open outline to the shape at {@code position}. * The 2D vertex will be represented as Z=0. * - * The constructed shape should be {@link Winding#CCW}. - * * @param position index within the last open outline, at which the vertex will be added * @param x the x coordinate * @param y the y coordniate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + * @param onCurve flag if this vertex is on the final curve or defines a curved region of the shape around this vertex. + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final int position, final float x, final float y, final boolean onCurve) { addVertex(position, vertexFactory.create(x, y, 0f, onCurve)); @@ -423,13 +447,11 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Add a 3D {@link Vertex} to the last open outline to the shape's tail. * - * The constructed shape should be {@link Winding#CCW}. - * * @param x the x coordinate * @param y the y coordinate * @param z the z coordinate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + * @param onCurve flag if this vertex is on the final curve or defines a curved region of the shape around this vertex. + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final float x, final float y, final float z, final boolean onCurve) { addVertex(vertexFactory.create(x, y, z, onCurve)); @@ -438,14 +460,12 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Add a 3D {@link Vertex} to the last open outline to the shape at {@code position}. * - * The constructed shape should be {@link Winding#CCW}. - * * @param position index within the last open outline, at which the vertex will be added * @param x the x coordinate * @param y the y coordniate * @param z the z coordinate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + * @param onCurve flag if this vertex is on the final curve or defines a curved region of the shape around this vertex. + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final int position, final float x, final float y, final float z, final boolean onCurve) { addVertex(position, vertexFactory.create(x, y, z, onCurve)); @@ -454,8 +474,6 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Add a vertex to the last open outline to the shape's tail. * - * The constructed shape should be {@link Winding#CCW}. - * * The vertex is passed as a float array and its offset where its attributes are located. * The attributes should be continuous (stride = 0). * Attributes which value are not set (when length less than 3) @@ -463,8 +481,8 @@ public final class OutlineShape implements Comparable<OutlineShape> { * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from * @param offset the offset in the buffer to the x coordinate * @param length the number of attributes to pick from the buffer (maximum 3) - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + * @param onCurve flag if this vertex is on the final curve or defines a curved region of the shape around this vertex. + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) { addVertex(vertexFactory.create(coordsBuffer, offset, length, onCurve)); @@ -473,8 +491,6 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Add a vertex to the last open outline to the shape at {@code position}. * - * The constructed shape should be {@link Winding#CCW}. - * * The vertex is passed as a float array and its offset where its attributes are located. * The attributes should be continuous (stride = 0). * Attributes which value are not set (when length less than 3) @@ -483,8 +499,8 @@ public final class OutlineShape implements Comparable<OutlineShape> { * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from * @param offset the offset in the buffer to the x coordinate * @param length the number of attributes to pick from the buffer (maximum 3) - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + * @param onCurve flag if this vertex is on the final curve or defines a curved region of the shape around this vertex. + * @see <a href="#windingrules">see winding rules</a> */ public final void addVertex(final int position, final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) { addVertex(position, vertexFactory.create(coordsBuffer, offset, length, onCurve)); @@ -659,13 +675,12 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Start a new position for the next line segment at given point x/y (P1). * - * The constructed shape should be {@link Winding#CCW}. - * * @param x point (P1) * @param y point (P1) * @param z point (P1) * @see Path2F#moveTo(float, float) * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean) + * @see <a href="#windingrules">see winding rules</a> */ public final void moveTo(final float x, final float y, final float z) { if ( 0 == getLastOutline().getVertexCount() ) { @@ -680,13 +695,12 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Add a line segment, intersecting the last point and the given point x/y (P1). * - * The constructed shape should be {@link Winding#CCW}. - * * @param x final point (P1) * @param y final point (P1) * @param z final point (P1) * @see Path2F#lineTo(float, float) * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean) + * @see <a href="#windingrules">see winding rules</a> */ public final void lineTo(final float x, final float y, final float z) { addVertex(x, y, z, true); @@ -695,8 +709,6 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Add a quadratic curve segment, intersecting the last point and the second given point x2/y2 (P2). * - * The constructed shape should be {@link Winding#CCW}. - * * @param x1 quadratic parametric control point (P1) * @param y1 quadratic parametric control point (P1) * @param z1 quadratic parametric control point (P1) @@ -705,6 +717,7 @@ public final class OutlineShape implements Comparable<OutlineShape> { * @param z2 quadratic parametric control point (P2) * @see Path2F#quadTo(float, float, float, float) * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean) + * @see <a href="#windingrules">see winding rules</a> */ public final void quadTo(final float x1, final float y1, final float z1, final float x2, final float y2, final float z2) { addVertex(x1, y1, z1, false); @@ -714,8 +727,6 @@ public final class OutlineShape implements Comparable<OutlineShape> { /** * Add a cubic Bézier curve segment, intersecting the last point and the second given point x3/y3 (P3). * - * The constructed shape should be {@link Winding#CCW}. - * * @param x1 Bézier control point (P1) * @param y1 Bézier control point (P1) * @param z1 Bézier control point (P1) @@ -727,6 +738,7 @@ public final class OutlineShape implements Comparable<OutlineShape> { * @param z3 final interpolated control point (P3) * @see Path2F#cubicTo(float, float, float, float, float, float) * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean) + * @see <a href="#windingrules">see winding rules</a> */ public final void cubicTo(final float x1, final float y1, final float z1, final float x2, final float y2, final float z2, final float x3, final float y3, final float z3) { addVertex(x1, y1, z1, false); diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java index b18d51849..7c9cb69c9 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java @@ -30,6 +30,7 @@ package com.jogamp.graph.geom; import java.util.ArrayList; import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.geom.plane.Winding; import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.curve.Region; import com.jogamp.opengl.math.FloatUtil; @@ -54,6 +55,8 @@ public class Outline implements Comparable<Outline> { private boolean closed; private final AABBox bbox; private boolean dirtyBBox; + private Winding winding; + private boolean dirtyWinding; /**Create an outline defined by control vertices. * An outline can contain off Curve vertices which define curved @@ -64,14 +67,19 @@ public class Outline implements Comparable<Outline> { closed = false; bbox = new AABBox(); dirtyBBox = false; + winding = Winding.CCW; + dirtyWinding = false; } /** * Copy ctor */ public Outline(final Outline src) { - vertices = new ArrayList<Vertex>(src.vertices.size()); - for(int i=0; i<vertices.size(); i++) { + final int count = src.vertices.size(); + vertices = new ArrayList<Vertex>(count); + winding = src.getWinding(); + dirtyWinding = false; + for(int i=0; i<count; i++) { vertices.add( src.vertices.get(i).clone() ); } closed = src.closed; @@ -79,6 +87,74 @@ public class Outline implements Comparable<Outline> { dirtyBBox = src.dirtyBBox; } + /** + * Copy ctor w/ enforced Winding + * <p> + * If the enforced {@link Winding} doesn't match the source Outline, the vertices reversed copied into this new instance. + * </p> + * @param src the source Outline + * @param enforce {@link Winding} to be enforced on this copy + */ + public Outline(final Outline src, final Winding enforce) { + final int count = src.vertices.size(); + vertices = new ArrayList<Vertex>(count); + final Winding had_winding = src.getWinding();; + winding = had_winding; + dirtyWinding = false; + if( enforce != had_winding ) { + for(int i=count-1; i>=0; --i) { + vertices.add( src.vertices.get(i).clone() ); + } + winding = enforce; + } else { + for(int i=0; i<count; ++i) { + vertices.add( src.vertices.get(i).clone() ); + } + } + closed = src.closed; + bbox = new AABBox(src.bbox); + dirtyBBox = src.dirtyBBox; + } + + /** + * Sets {@link Winding} to this outline + * <p> + * If the enforced {@link Winding} doesn't match this Outline, the vertices are reversed. + * </p> + * @param enforce to be enforced {@link Winding} + */ + public final void setWinding(final Winding enforce) { + final Winding had_winding = getWinding(); + if( enforce != had_winding ) { + final int count = vertices.size(); + final ArrayList<Vertex> ccw = new ArrayList<Vertex>(count); + for(int i=count-1; i>=0; --i) { + ccw.add(vertices.get(i)); + } + vertices = ccw; + winding = enforce; + } + } + + /** + * Compute the winding of the {@link #getLastOutline()} using the {@link #area(ArrayList)} function over all of its vertices. + * @return {@link Winding#CCW} or {@link Winding#CW} + */ + public final Winding getWinding() { + if( !dirtyWinding ) { + return winding; + } + final int count = getVertexCount(); + if( 3 > count ) { + winding = Winding.CCW; + } else { + final ArrayList<Vertex> vertices = getVertices(); + winding = VectorUtil.getWinding(vertices); + } + dirtyWinding = false; + return winding; + } + public final int getVertexCount() { return vertices.size(); } @@ -107,6 +183,7 @@ public class Outline implements Comparable<Outline> { if(!dirtyBBox) { bbox.resize(vertex.getCoord()); } + dirtyWinding = true; } /** Replaces the {@link Vertex} element at the given {@code position}. @@ -123,6 +200,7 @@ public class Outline implements Comparable<Outline> { } vertices.set(position, vertex); dirtyBBox = true; + dirtyWinding = true; } public final Vertex getVertex(final int index){ @@ -141,6 +219,7 @@ public class Outline implements Comparable<Outline> { */ public final Vertex removeVertex(final int position) throws IndexOutOfBoundsException { dirtyBBox = true; + dirtyWinding = true; return vertices.remove(position); } diff --git a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java index 3ee504a29..d7e72e245 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java @@ -888,25 +888,35 @@ public final class VectorUtil { return triAreaVec2(a,b,c) > 0; } - /** Compute the winding of given points + /** + * Compute the winding of the 3 given points + * <p> + * Consider using {@link #getWinding(ArrayList)} using the {@link #area(ArrayList)} function over all points + * on complex shapes for a reliable result! + * </p> * @param a first vertex * @param b second vertex * @param c third vertex - * @return Winding + * @return {@link Winding#CCW} or {@link Winding#CW} + * @see #getWinding(ArrayList) */ public static Winding getWinding(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c) { return triAreaVec2(a,b,c) > 0 ? Winding.CCW : Winding.CW ; } - /** Computes the area of a list of vertices to check if ccw + /** + * Computes the area of a list of vertices. + * <p> + * This method is utilized e.g. to reliably compute the {@link Winding} of complex shapes. + * </p> * @param vertices * @return positive area if ccw else negative area value + * @see #getWinding(ArrayList) */ public static float area(final ArrayList<? extends Vert2fImmutable> vertices) { final int n = vertices.size(); float area = 0.0f; - for (int p = n - 1, q = 0; q < n; p = q++) - { + for (int p = n - 1, q = 0; q < n; p = q++) { final float[] pCoord = vertices.get(p).getCoord(); final float[] qCoord = vertices.get(q).getCoord(); area += pCoord[0] * qCoord[1] - qCoord[0] * pCoord[1]; @@ -914,9 +924,15 @@ public final class VectorUtil { return area; } - /** Compute the general winding of the vertices + /** + * Compute the winding using the {@link #area(ArrayList)} function over all vertices for complex shapes. + * <p> + * Uses the {@link #area(ArrayList)} function over all points + * on complex shapes for a reliable result! + * </p> * @param vertices array of Vertices - * @return CCW or CW {@link Winding} + * @return {@link Winding#CCW} or {@link Winding#CW} + * @see #area(ArrayList) */ public static Winding getWinding(final ArrayList<? extends Vert2fImmutable> vertices) { return area(vertices) >= 0 ? Winding.CCW : Winding.CW ; diff --git a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java index 369d0b493..331116f7e 100644 --- a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java +++ b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java @@ -80,20 +80,20 @@ public class CDTriangulator2D implements Triangulator { @Override public final void addCurve(final List<Triangle> sink, final Outline polyline, final float sharpness) { - Loop loop = null; - - if(!loops.isEmpty()) { - loop = getContainerLoop(polyline); - } + Loop loop = getContainerLoop(polyline); if(loop == null) { - final GraphOutline outline = new GraphOutline(polyline); + final Winding winding = Winding.CCW; // -> HEdge.BOUNDARY + // Too late: polyline.setWinding(winding); + final GraphOutline outline = new GraphOutline(polyline); // , winding); final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, false, sharpness); // vertices.addAll(polyline.getVertices()); - loop = new Loop(innerPoly, Winding.CCW); + loop = new Loop(innerPoly, winding); loops.add(loop); } else { - final GraphOutline outline = new GraphOutline(polyline); + // final Winding winding = Winding.CW; // -> HEdge.HOLE + // Not required, handled in Loop.initFromPolyline(): polyline.setWinding(winding); + final GraphOutline outline = new GraphOutline(polyline); // , winding); final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, true, sharpness); // vertices.addAll(innerPoly.getVertices()); loop.addConstraintCurve(innerPoly); @@ -221,12 +221,15 @@ public class CDTriangulator2D implements Triangulator { } private Loop getContainerLoop(final Outline polyline) { - final ArrayList<Vertex> vertices = polyline.getVertices(); - for(int i=0; i < loops.size(); i++) { - final Loop loop = loops.get(i); - for(int j=0; j < vertices.size(); j++) { - if( loop.checkInside( vertices.get(j) ) ) { - return loop; + final int count = loops.size(); + if( 0 < count ) { + final ArrayList<Vertex> vertices = polyline.getVertices(); + for(int i=0; i < count; i++) { + final Loop loop = loops.get(i); + for(int j=0; j < vertices.size(); j++) { + if( loop.checkInside( vertices.get(j) ) ) { + return loop; + } } } } diff --git a/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java b/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java index 81e6efdad..75192d45a 100644 --- a/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java +++ b/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import com.jogamp.graph.geom.Outline; import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.plane.Winding; public class GraphOutline { final private Outline outline; @@ -40,11 +41,14 @@ public class GraphOutline { this.outline = new Outline(); } - /**Create a control polyline of control vertices + /** + * Create a control polyline of control vertices * the curve pieces can be identified by onCurve flag * of each cp the control polyline is open by default + * + * @param ol the source {@link Outline} */ - public GraphOutline(final Outline ol){ + public GraphOutline(final Outline ol) { this.outline = ol; final ArrayList<Vertex> vertices = this.outline.getVertices(); for(int i = 0; i< vertices.size(); i++){ diff --git a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java index 5d1bc051f..1d8264607 100644 --- a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java +++ b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java @@ -34,6 +34,7 @@ import com.jogamp.graph.geom.Vertex; import com.jogamp.graph.geom.plane.Winding; import com.jogamp.graph.geom.Triangle; import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.math.Vert2fImmutable; import com.jogamp.opengl.math.geom.AABBox; public class Loop { @@ -91,9 +92,24 @@ public class Loop { return (root.getNext().getNext().getNext() == root); } - /**Create a connected list of half edges (loop) + private static float area(final ArrayList<GraphVertex> vertices) { + final int n = vertices.size(); + float area = 0.0f; + for (int p = n - 1, q = 0; q < n; p = q++) { + final float[] pCoord = vertices.get(p).getCoord(); + final float[] qCoord = vertices.get(q).getCoord(); + area += pCoord[0] * qCoord[1] - qCoord[0] * pCoord[1]; + } + return area; + } + private static Winding getWinding(final ArrayList<GraphVertex> vertices) { + return area(vertices) >= 0 ? Winding.CCW : Winding.CW ; + } + + /** + * Create a connected list of half edges (loop) * from the boundary profile - * @param reqWinding requested winding of edges (CCW or CW) + * @param reqWinding requested winding of edges, either {@link Winding#CCW} for {@link HEdge#BOUNDARY} or {@link Winding#CW} for {@link HEdge#HOLE} */ private HEdge initFromPolyline(final GraphOutline outline, final Winding reqWinding){ final ArrayList<GraphVertex> vertices = outline.getGraphPoint(); @@ -101,57 +117,64 @@ public class Loop { if(vertices.size()<3) { throw new IllegalArgumentException("outline's vertices < 3: " + vertices.size()); } - final Winding hasWinding = VectorUtil.getWinding( - vertices.get(0).getPoint(), - vertices.get(1).getPoint(), - vertices.get(2).getPoint()); - //FIXME: handle case when vertices come inverted - Rami - // skips inversion CW -> CCW - final boolean invert = hasWinding != reqWinding && - reqWinding == Winding.CW; - - final int max; + final Winding hasWinding = getWinding( vertices ); // requires area-winding detection + final int edgeType = reqWinding == Winding.CCW ? HEdge.BOUNDARY : HEdge.HOLE ; - int index; HEdge firstEdge = null; HEdge lastEdge = null; - if(!invert) { - max = vertices.size(); - index = 0; - } else { - max = -1; - index = vertices.size() -1; - } - - while(index != max){ - final GraphVertex v1 = vertices.get(index); - box.resize(v1.getX(), v1.getY(), v1.getZ()); - - final HEdge edge = new HEdge(v1, edgeType); - - v1.addEdge(edge); - if(lastEdge != null) { - lastEdge.setNext(edge); - edge.setPrev(lastEdge); - } else { - firstEdge = edge; - } - - if(!invert) { - if(index == vertices.size()-1) { + /** + * The winding conversion CW -> CCW can't be resolved here (-> Rami?) + * Therefore we require outline boundaries to be in CCW, see API-doc comment in OutlineShape. + * + * Original comment: + * FIXME: handle case when vertices come inverted - Rami + * Skips inversion CW -> CCW + */ + if( hasWinding == reqWinding || reqWinding == Winding.CCW ) { + // Correct Winding or skipped CW -> CCW (no inversion possible here, too late ??) + final int max = vertices.size() - 1; + for(int index = 0; index <= max; ++index) { + final GraphVertex v1 = vertices.get(index); + box.resize(v1.getX(), v1.getY(), v1.getZ()); + + final HEdge edge = new HEdge(v1, edgeType); + + v1.addEdge(edge); + if(lastEdge != null) { + lastEdge.setNext(edge); + edge.setPrev(lastEdge); + } else { + firstEdge = edge; + } + if(index == max ) { edge.setNext(firstEdge); firstEdge.setPrev(edge); } - index++; - } else { + lastEdge = edge; + } + } else { // if( reqWinding == Winding.CW ) { + // CCW -> CW + for(int index = vertices.size() - 1; index >= 0; --index) { + final GraphVertex v1 = vertices.get(index); + box.resize(v1.getX(), v1.getY(), v1.getZ()); + + final HEdge edge = new HEdge(v1, edgeType); + + v1.addEdge(edge); + if(lastEdge != null) { + lastEdge.setNext(edge); + edge.setPrev(lastEdge); + } else { + firstEdge = edge; + } + if (index == 0) { edge.setNext(firstEdge); firstEdge.setPrev(edge); } - index--; + lastEdge = edge; } - lastEdge = edge; } return firstEdge; } @@ -159,7 +182,7 @@ public class Loop { public void addConstraintCurve(final GraphOutline polyline) { // GraphOutline outline = new GraphOutline(polyline); /**needed to generate vertex references.*/ - initFromPolyline(polyline, Winding.CW); + initFromPolyline(polyline, Winding.CW); // -> HEdge.HOLE final GraphVertex v3 = locateClosestVertex(polyline); final HEdge v3Edge = v3.findBoundEdge(); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java index 8826275b1..52ca9041b 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java @@ -48,6 +48,7 @@ import org.junit.runners.MethodSorters; import com.jogamp.common.os.Platform; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.font.Font; import com.jogamp.graph.font.FontFactory; import com.jogamp.graph.font.FontSet; import com.jogamp.graph.geom.SVertex; @@ -142,51 +143,87 @@ public class TestTextRendererNEWT01 extends UITestCase { final Runnable action_per_font = new Runnable() { @Override public void run() { + if( false ) { + textGLListener.setHeadBox(1, false); + textGLListener.setSampleCount(2); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + + textGLListener.setHeadBox(2, false); + textGLListener.setSampleCount(2); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + } + textGLListener.setHeadBox(1, false); - textGLListener.setSampleCount(2); + textGLListener.setSampleCount(4); window.display(); textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); sleep(); textGLListener.setHeadBox(2, false); - textGLListener.setSampleCount(2); + textGLListener.setSampleCount(4); window.display(); textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); sleep(); + } }; - textGLListener.setHeadBox(1, false); - textGLListener.setSampleCount(3); - window.display(); - textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); - sleep(); + final Font[] fonts = FontSet01.getSet01(); + for(final Font f : fonts) { + if( textGLListener.setFont(f) ) { + action_per_font.run(); + } + } + if(textGLListener.setFontSet(FontFactory.JAVA, 0, 0)) { + action_per_font.run(); + } + destroyWindow(window); + } - textGLListener.setHeadBox(2, false); - textGLListener.setSampleCount(3); - window.display(); - textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); - sleep(); + @Test + public void testTextRendererMSAA01() throws InterruptedException, GLException, IOException { + final GLProfile glp = GLProfile.get(GLProfile.GL2ES2); + final GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(4); + caps.setSampleBuffers(true); + caps.setNumSamples(4); + System.err.println("Requested: "+caps); + + final GLWindow window = createWindow("text-vbaa0-msaa1", caps, 1024, 640); + window.display(); + System.err.println("Chosen: "+window.getChosenGLCapabilities()); + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final TextGLListener textGLListener = new TextGLListener(rs, 0, 0 /* sampleCount */, DEBUG, TRACE); + textGLListener.attachInputListenerTo(window); + window.addGLEventListener(textGLListener); + textGLListener.setHeadBox(2, true); + window.display(); + + final Runnable action_per_font = new Runnable() { + @Override + public void run() { textGLListener.setHeadBox(1, false); - textGLListener.setSampleCount(4); + textGLListener.setSampleCount(0); window.display(); textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); sleep(); textGLListener.setHeadBox(2, false); - textGLListener.setSampleCount(4); + textGLListener.setSampleCount(0); window.display(); textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); sleep(); } }; - if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_LIGHT, FontSet.STYLE_NONE)) { - action_per_font.run(); - } - - if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_REGULAR, FontSet.STYLE_NONE)) { - action_per_font.run(); + final Font[] fonts = FontSet01.getSet01(); + for(final Font f : fonts) { + if( textGLListener.setFont(f) ) { + action_per_font.run(); + } } - if(textGLListener.setFontSet(FontFactory.JAVA, 0, 0)) { action_per_font.run(); } @@ -195,15 +232,13 @@ public class TestTextRendererNEWT01 extends UITestCase { } @Test - public void testTextRendererMSAA01() throws InterruptedException, GLException, IOException { + public void testTextRendererNoSampling() throws InterruptedException, GLException, IOException { final GLProfile glp = GLProfile.get(GLProfile.GL2ES2); final GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); - caps.setSampleBuffers(true); - caps.setNumSamples(4); System.err.println("Requested: "+caps); - final GLWindow window = createWindow("text-vbaa0-msaa1", caps, 1024, 640); + final GLWindow window = createWindow("text-vbaa0-msaa0", caps, 1024, 640); window.display(); System.err.println("Chosen: "+window.getChosenGLCapabilities()); @@ -230,14 +265,12 @@ public class TestTextRendererNEWT01 extends UITestCase { sleep(); } }; - if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_LIGHT, FontSet.STYLE_NONE)) { - action_per_font.run(); - } - - if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_REGULAR, FontSet.STYLE_NONE)) { - action_per_font.run(); + final Font[] fonts = FontSet01.getSet01(); + for(final Font f : fonts) { + if( textGLListener.setFont(f) ) { + action_per_font.run(); + } } - if(textGLListener.setFontSet(FontFactory.JAVA, 0, 0)) { action_per_font.run(); } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java index b86cc60aa..7b1fe6177 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java @@ -34,7 +34,6 @@ import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLAnimatorControl; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLException; -import com.jogamp.opengl.GLRunnable; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.Region; @@ -46,7 +45,6 @@ import com.jogamp.graph.font.Font; import com.jogamp.graph.font.FontFactory; import com.jogamp.graph.font.FontScale; import com.jogamp.graph.font.FontSet; -import com.jogamp.graph.font.Font.Glyph; import com.jogamp.newt.Window; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; @@ -114,21 +112,21 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB "in lorem. Maecenas in ipsum ac justo scelerisque sollicitudin. Quisque sit amet neque lorem, \n" + "-------Press H to change text---------"; - public static final String textX2 = // Kvæven -> Kvaven (error) + public static final String textX2 = "I “Ask Jeff” or ‘Ask Jeff’. Take the chef d’œuvre! Two of [of] (of) ‘of’ “of” of? of! of*. X\n"+ "Les Woëvres, the Fôret de Wœvres, the Voire and Vauvise. Yves is in heaven; D’Amboise is in jail. X\n"+ "Lyford’s in Texas & L’Anse-aux-Griffons in Québec; the Łyna in Poland. Yriarte, Yciar and Ysaÿe are at Yale. X\n"+ - "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvaven in Norway, Kyulu in Kenya, not in Rwanda.… X\n"+ + "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvæven in Norway, Kyulu in Kenya, not in Rwanda.… X\n"+ "Von-Vincke-Straße in Münster, Vdovino in Russia, Ytterbium in the periodic table. Are Toussaint L’Ouverture, Wölfflin, Wolfe, X\n"+ "Miłosz and Wū Wŭ all in the library? 1510–1620, 11:00 pm, and the 1980s are over. X\n"+ "-------Press H to change text---------"; - public static final String textX20 = // Kvæven -> Kvaven (error) + public static final String textX20 = "I “Ask Jeff” or ‘Ask Jeff’. Take the chef d’œuvre! Two of [of] (of) ‘of’ “of” of? of! of*.\n"+ "Two of [of] (of) ‘of’ “of” of? of! of*. Ydes, Yffignac and Ygrande are in France: so are Ypres,\n"+ "Les Woëvres, the Fôret de Wœvres, the Voire and Vauvise. Yves is in heaven; D’Amboise is in jail.\n"+ "Lyford’s in Texas & L’Anse-aux-Griffons in Québec; the Łyna in Poland. Yriarte, Yciar and Ysaÿe are at Yale.\n"+ - "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvaven in Norway, Kyulu in Kenya, not in Rwanda.…\n"+ + "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvæven in Norway, Kyulu in Kenya, not in Rwanda.…\n"+ "Walton’s in West Virginia, but «Wren» is in Oregon. Tlálpan is near Xochimilco in México.\n"+ "The Zygos & Xylophagou are in Cyprus, Zwettl in Austria, Fænø in Denmark, the Vøringsfossen and Værøy in Norway.\n"+ "Tchula is in Mississippi, the Tittabawassee in Michigan. Twodot is here in Montana, Ywamun in Burma.\n"+ @@ -448,6 +446,17 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB return false; } + public boolean setFont(final Font _font) { + if(null != _font) { + // fontSet = ??? + font = _font; + fontName = font.getFullFamilyName()+" (head "+fontSizeHead+"pt)"; + fontNameBox = font.getMetricBounds(fontName); + return true; + } + return false; + } + public boolean isUserInputMode() { return userInput; } void dumpMatrix(final boolean bbox) { diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject01.java index c3df7c7ed..d2bff1fee 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject01.java @@ -33,6 +33,7 @@ import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.geom.Vertex; import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.graph.geom.plane.Winding; /** * GPU based resolution independent test object @@ -51,13 +52,17 @@ public class TestObject01 extends UIShape { protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { } + @SuppressWarnings("unused") @Override protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); // lower case 'o' // Start TTF Shape for Glyph 82 - if( true ) { + if( false ) { + // Original Outer shape: Winding.CW + // Moved into OutlineShape reverse -> Winding.CCW -> OK + // // Shape.MoveTo: shape.closeLastOutline(false); shape.addEmptyOutline(); @@ -126,8 +131,12 @@ public class TestObject01 extends UIShape { // Shape.QuadTo: shape.addVertex(0, 0.527000f, 0.319000f, false); shape.addVertex(0, 0.527000f, 0.258000f, true); + System.err.println("TestObject01.shape01a.winding_area: "+shape.getWindingOfLastOutline()); shape.closeLastOutline(false); } else { + // Outer shape: Winding.CW + // Moved into OutlineShape same-order -> Winding.CW -> ERROR (so we fix it in the end, see below) + // // Shape.MoveTo: shape.closeLastOutline(false); shape.addEmptyOutline(); @@ -196,10 +205,16 @@ public class TestObject01 extends UIShape { // Shape.QuadTo: shape.addVertex(0.527000f, 0.319000f, false); shape.addVertex(0.527000f, 0.258000f, true); + System.err.println("TestObject01.shape01b.1.winding_area: "+shape.getWindingOfLastOutline()); + shape.setWindingOfLastOutline(Winding.CCW); + System.err.println("TestObject01.shape01b.2.winding_area: "+shape.getWindingOfLastOutline()); shape.closeLastOutline(false); } - if( false ) { + if( true ) { + // Original Inner shape: Winding.CCW + // Moved into OutlineShape reverse -> Winding.CW -> OK + // // Shape.MoveTo: shape.closeLastOutline(false); shape.addEmptyOutline(); @@ -236,8 +251,12 @@ public class TestObject01 extends UIShape { // Shape.QuadTo: shape.addVertex(0, 0.458000f, 0.161000f, false); shape.addVertex(0, 0.458000f, 0.258000f, true); + System.err.println("TestObject01.shape02a.winding_area: "+shape.getWindingOfLastOutline()); shape.closeLastOutline(false); } else { + // Inner shape: Winding.CCW + // Moved into OutlineShape same-order -> Winding.CCW -> OK + // // Shape.MoveTo: shape.closeLastOutline(false); shape.addEmptyOutline(); @@ -276,6 +295,7 @@ public class TestObject01 extends UIShape { shape.addVertex(0.458000f, 0.161000f, false); shape.addVertex(0.458000f, 0.258000f, true); + System.err.println("TestObject01.shape02b.winding_area: "+shape.getWindingOfLastOutline()); shape.closeLastOutline(false); } // End Shape for Glyph 82 diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject02.java index 34aec67c3..fe1d965ee 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject02.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/TestObject02.java @@ -51,6 +51,7 @@ public class TestObject02 extends UIShape { protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { } + @SuppressWarnings("unused") @Override protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); @@ -58,7 +59,10 @@ public class TestObject02 extends UIShape { // lower case 'æ' // Start TTF Shape for Glyph 193 - { + if( true ) { + // Original Inner e-shape: Winding.CCW + // Moved into OutlineShape reverse -> Winding.CW -> OK + // // Shape.MoveTo: shape.closeLastOutline(false); shape.addEmptyOutline(); @@ -90,10 +94,51 @@ public class TestObject02 extends UIShape { // 008: B1: line-to p0-p1 // Shape.LineTo: shape.addVertex(0, 0.728000f, 0.300000f, true); + System.err.println("TestObject02.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Inner e-shape: Winding.CCW + // Moved into OutlineShape same-order -> Winding.CCW -> ?? + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0.728000f, 0.300000f, true); + // 000: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.726000f, 0.381000f, false); + shape.addVertex(0.690000f, 0.426000f, true); + // 002: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.654000f, 0.471000f, false); + shape.addVertex(0.588000f, 0.471000f, true); + // 003: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.553000f, 0.471000f, false); + shape.addVertex(0.526000f, 0.457000f, true); + // 005: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.498000f, 0.443000f, false); + shape.addVertex(0.478000f, 0.420000f, true); + // 006: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.457000f, 0.396000f, false); + shape.addVertex(0.446000f, 0.365000f, true); + // 007: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.434000f, 0.334000f, false); + shape.addVertex(0.432000f, 0.300000f, true); + // 008: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.728000f, 0.300000f, true); + System.err.println("TestObject02.shape01b.winding_area: "+shape.getWindingOfLastOutline()); shape.closeLastOutline(false); } - { + if( true ) { + // Original Outer shape: Winding.CW + // Moved into OutlineShape reverse -> Winding.CCW -> OK + // // Shape.MoveTo: shape.closeLastOutline(false); shape.addEmptyOutline(); @@ -270,10 +315,196 @@ public class TestObject02 extends UIShape { // Shape.QuadTo: shape.addVertex(0, 0.289000f, -0.011000f, false); shape.addVertex(0, 0.252000f, -0.011000f, true); + System.err.println("TestObject02.shape02a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Outer shape: Winding.CW + // Moved into OutlineShape same-order -> Winding.CW -> OK now + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0.252000f, -0.011000f, true); + // 009: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.208000f, -0.011000f, false); + shape.addVertex(0.171000f, -0.002000f, true); + // 011: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.133000f, 0.007000f, false); + shape.addVertex(0.106000f, 0.026000f, true); + // 012: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.079000f, 0.046000f, false); + shape.addVertex(0.064000f, 0.076000f, true); + // 013: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.048000f, 0.107000f, false); + shape.addVertex(0.048000f, 0.151000f, true); + // 014: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.048000f, 0.193000f, false); + shape.addVertex(0.064000f, 0.223000f, true); + // 016: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.080000f, 0.253000f, false); + shape.addVertex(0.109000f, 0.272000f, true); + // 017: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.138000f, 0.292000f, false); + shape.addVertex(0.178000f, 0.301000f, true); + // 018: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.218000f, 0.310000f, false); + shape.addVertex(0.265000f, 0.310000f, true); + // 019: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.279000f, 0.310000f, false); + shape.addVertex(0.294000f, 0.309000f, true); + // 021: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.310000f, 0.307000f, false); + shape.addVertex(0.324000f, 0.305000f, true); + // 022: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.339000f, 0.302000f, false); + shape.addVertex(0.349000f, 0.300000f, true); + // 023: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.360000f, 0.297000f, false); + shape.addVertex(0.364000f, 0.295000f, true); + // 024: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.364000f, 0.327000f, true); + // 025: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.364000f, 0.354000f, false); + shape.addVertex(0.360000f, 0.379000f, true); + // 027: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.356000f, 0.405000f, false); + shape.addVertex(0.343000f, 0.425000f, true); + // 028: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.329000f, 0.446000f, false); + shape.addVertex(0.305000f, 0.458000f, true); + // 029: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.280000f, 0.471000f, false); + shape.addVertex(0.240000f, 0.471000f, true); + // 030: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.186000f, 0.471000f, false); + shape.addVertex(0.156000f, 0.464000f, true); + // 032: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.126000f, 0.456000f, false); + shape.addVertex(0.113000f, 0.451000f, true); + // 033: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.105000f, 0.507000f, true); + // 034: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.122000f, 0.515000f, false); + shape.addVertex(0.158000f, 0.522000f, true); + // 036: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.194000f, 0.529000f, false); + shape.addVertex(0.243000f, 0.529000f, true); + // 037: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.314000f, 0.529000f, false); + shape.addVertex(0.354000f, 0.503000f, true); + // 039: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.395000f, 0.476000f, false); + shape.addVertex(0.412000f, 0.431000f, true); + // 040: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.445000f, 0.480000f, false); + shape.addVertex(0.491000f, 0.504000f, true); + // 042: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.537000f, 0.529000f, false); + shape.addVertex(0.587000f, 0.529000f, true); + // 043: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.682000f, 0.529000f, false); + shape.addVertex(0.738000f, 0.467000f, true); + // 045: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.795000f, 0.405000f, false); + shape.addVertex(0.795000f, 0.276000f, true); + // 046: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.795000f, 0.268000f, false); + shape.addVertex(0.795000f, 0.260000f, true); + // 048: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.794000f, 0.252000f, false); + shape.addVertex(0.793000f, 0.245000f, true); + // 049: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.430000f, 0.245000f, true); + // 050: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.433000f, 0.150000f, false); + shape.addVertex(0.477000f, 0.099000f, true); + // 052: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.521000f, 0.048000f, false); + shape.addVertex(0.617000f, 0.048000f, true); + // 053: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.670000f, 0.048000f, false); + shape.addVertex(0.701000f, 0.058000f, true); + // 055: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.732000f, 0.068000f, false); + shape.addVertex(0.746000f, 0.075000f, true); + // 056: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.758000f, 0.019000f, true); + // 057: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.744000f, 0.011000f, false); + shape.addVertex(0.706000f, 0.000000f, true); + // 059: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.667000f, -0.011000f, false); + shape.addVertex(0.615000f, -0.011000f, true); + // 060: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.558000f, -0.011000f, false); + shape.addVertex(0.514000f, 0.003000f, true); + // 062: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.470000f, 0.017000f, false); + shape.addVertex(0.437000f, 0.049000f, true); + // 063: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.426000f, 0.040000f, false); + shape.addVertex(0.410000f, 0.030000f, true); + // 065: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.393000f, 0.019000f, false); + shape.addVertex(0.370000f, 0.010000f, true); + // 066: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.347000f, 0.001000f, false); + shape.addVertex(0.318000f, -0.005000f, true); + // 067: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.289000f, -0.011000f, false); + shape.addVertex(0.252000f, -0.011000f, true); + System.err.println("TestObject02.shape02b.winding_area: "+shape.getWindingOfLastOutline()); shape.closeLastOutline(false); } if( true ) { + // Original Inner a-shape: Winding.CCW + // Moved into OutlineShape reverse -> Winding.CW -> OK now + // // Shape.MoveTo: shape.closeLastOutline(false); shape.addEmptyOutline(); @@ -334,6 +565,73 @@ public class TestObject02 extends UIShape { // Shape.QuadTo: shape.addVertex(0, 0.366000f, 0.190000f, false); shape.addVertex(0, 0.365000f, 0.238000f, true); + System.err.println("TestObject02.shape03a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Inner a-shape: Winding.CCW + // Moved into OutlineShape same-order -> Winding.CCW -> OK + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0.365000f, 0.238000f, true); + // 068: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.354000f, 0.243000f, false); + shape.addVertex(0.330000f, 0.248000f, true); + // 070: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.305000f, 0.254000f, false); + shape.addVertex(0.263000f, 0.254000f, true); + // 071: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.239000f, 0.254000f, false); + shape.addVertex(0.213000f, 0.251000f, true); + // 073: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.187000f, 0.247000f, false); + shape.addVertex(0.165000f, 0.236000f, true); + // 074: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.143000f, 0.224000f, false); + shape.addVertex(0.129000f, 0.204000f, true); + // 075: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.115000f, 0.184000f, false); + shape.addVertex(0.115000f, 0.151000f, true); + // 076: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.115000f, 0.122000f, false); + shape.addVertex(0.125000f, 0.102000f, true); + // 078: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.135000f, 0.082000f, false); + shape.addVertex(0.153000f, 0.070000f, true); + // 079: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.172000f, 0.058000f, false); + shape.addVertex(0.197000f, 0.053000f, true); + // 080: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.222000f, 0.047000f, false); + shape.addVertex(0.252000f, 0.047000f, true); + // 081: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.314000f, 0.047000f, false); + shape.addVertex(0.350000f, 0.063000f, true); + // 083: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.386000f, 0.080000f, false); + shape.addVertex(0.400000f, 0.093000f, true); + // 084: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.384000f, 0.119000f, false); + shape.addVertex(0.375000f, 0.154000f, true); + // 086: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.366000f, 0.190000f, false); + shape.addVertex(0.365000f, 0.238000f, true); + System.err.println("TestObject02.shape03b.winding_area: "+shape.getWindingOfLastOutline()); shape.closeLastOutline(false); } // End Shape for Glyph 193 diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UITypeDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UITypeDemo01.java index 0fe9b300e..b3a56d9b7 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UITypeDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UITypeDemo01.java @@ -204,7 +204,7 @@ public class UITypeDemo01 implements GLEventListener { } else { final float scale = 0.15312886f; final float size_xz = 0.541f; - final UIShape o = new TestObject01(SVertex.factory(), renderModes); + final UIShape o = new TestObject02(SVertex.factory(), renderModes); o.scale(scale, scale, 1f); // o.translate(size_xz, -size_xz, 0f); testObj = o; |