aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com')
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java151
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java33
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java152
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/Font.java176
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/FontFactory.java2
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/FontSet.java2
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Outline.java83
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java30
8 files changed, 416 insertions, 213 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
index be5a1d1bf..fb0ff6a7e 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 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:
@@ -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
@@ -113,6 +128,18 @@ public final class OutlineShape implements Comparable<OutlineShape> {
}
}
+ /**
+ * General purpose {@link OutlineShape} visitor.
+ */
+ public static interface Visitor {
+ /**
+ * Visiting the given {@link OutlineShape} with it's corresponding {@link AffineTransform}.
+ * @param shape may be used as is, otherwise a copy shall be made if intended to be modified.
+ * @param t may be used immediately as is, otherwise a copy shall be made if stored.
+ */
+ public void visit(final OutlineShape shape, final AffineTransform t);
+ }
+
/** Initial {@link #getSharpness()} value, which can be modified via {@link #setSharpness(float)}. */
public static final float DEFAULT_SHARPNESS = 0.5f;
@@ -214,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>
@@ -346,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();
@@ -363,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();
@@ -381,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));
@@ -396,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));
@@ -411,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));
@@ -426,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));
@@ -442,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)
@@ -451,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));
@@ -461,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)
@@ -471,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));
@@ -647,72 +675,75 @@ 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) {
+ public final void moveTo(final float x, final float y, final float z) {
if ( 0 == getLastOutline().getVertexCount() ) {
- addVertex(x, y, true);
+ addVertex(x, y, z, true);
} else {
closeLastOutline(false);
addEmptyOutline();
- addVertex(x, y, true);
+ addVertex(x, y, z, true);
}
}
/**
* 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) {
- addVertex(x, y, true);
+ public final void lineTo(final float x, final float y, final float z) {
+ addVertex(x, y, z, true);
}
/**
* 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)
* @param x2 final interpolated control point (P2)
* @param y2 final interpolated control point (P2)
+ * @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 x2, final float y2) {
- addVertex(x1, y1, false);
- addVertex(x2, y2, true);
+ 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);
+ addVertex(x2, y2, z2, true);
}
/**
* 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)
* @param x2 Bézier control point (P2)
* @param y2 Bézier control point (P2)
+ * @param z2 Bézier control point (P2)
* @param x3 final interpolated control point (P3)
* @param y3 final interpolated control point (P3)
+ * @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 x2, final float y2, final float x3, final float y3) {
- addVertex(x1, y1, false);
- addVertex(x2, y2, false);
- addVertex(x3, y3, true);
+ 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);
+ addVertex(x2, y2, z2, false);
+ addVertex(x3, y3, z3, true);
}
/**
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
index 0c782d93e..1014553d3 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
@@ -152,17 +152,25 @@ public class RegionRenderer {
private final GLCallback enableCallback;
private final GLCallback disableCallback;
- private int vp_width;
- private int vp_height;
+ private final int[] viewport = new int[] { 0, 0, 0, 0 };
private boolean initialized;
private boolean vboSupported = false;
public final boolean isInitialized() { return initialized; }
+ /** Copies the current viewport in given target and returns it for chaining. */
+ public final int[/*4*/] getViewport(final int[/*4*/] target) {
+ System.arraycopy(viewport, 0, target, 0, 4);
+ return target;
+ }
+ /** Borrows the current viewport w/o copying. */
+ public final int[/*4*/] getViewport() {
+ return viewport;
+ }
/** Return width of current viewport */
- public final int getWidth() { return vp_width; }
+ public final int getWidth() { return viewport[2]; }
/** Return height of current viewport */
- public final int getHeight() { return vp_height; }
+ public final int getHeight() { return viewport[3]; }
public final PMVMatrix getMatrix() { return rs.getMatrix(); }
@@ -261,15 +269,16 @@ public class RegionRenderer {
}
}
- /** No PMVMatrix operation is performed here. PMVMatrix is marked dirty. */
+ /**
+ * No PMVMatrix operation is performed here.
+ */
public final void reshapeNotify(final int width, final int height) {
- this.vp_width = width;
- this.vp_height = height;
+ viewport[2] = width;
+ viewport[3] = height;
}
public final void reshapePerspective(final float angle, final int width, final int height, final float near, final float far) {
- this.vp_width = width;
- this.vp_height = height;
+ reshapeNotify(width, height);
final float ratio = (float)width/(float)height;
final PMVMatrix p = rs.getMatrix();
p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
@@ -277,9 +286,11 @@ public class RegionRenderer {
p.gluPerspective(angle, ratio, near, far);
}
+ /**
+ * Perspective orthogonal, method calls {@link #reshapeNotify(int, int, int, int)}.
+ */
public final void reshapeOrtho(final int width, final int height, final float near, final float far) {
- this.vp_width = width;
- this.vp_height = height;
+ reshapeNotify(width, height);
final PMVMatrix p = rs.getMatrix();
p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
p.glLoadIdentity();
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
index 4af40bf1c..fb77775ad 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 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:
@@ -33,12 +33,11 @@ import java.util.Iterator;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLException;
+import com.jogamp.opengl.math.geom.AABBox;
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.Vertex;
-import com.jogamp.graph.geom.Vertex.Factory;
import com.jogamp.graph.geom.plane.AffineTransform;
/**
@@ -55,18 +54,6 @@ public class TextRegionUtil {
this.renderModes = renderModes;
}
- public static interface ShapeVisitor {
- /**
- * Visiting the given {@link OutlineShape} with it's corresponding {@link AffineTransform}.
- * <p>
- * The shape is in font em-size [0..1].
- * </p>
- * @param shape may be used as is, otherwise a copy shall be made if intended to be modified.
- * @param t may be used immediately as is, otherwise a copy shall be made if stored.
- */
- public void visit(final OutlineShape shape, final AffineTransform t);
- }
-
public static int getCharCount(final String s, final char c) {
final int sz = s.length();
int count = 0;
@@ -79,85 +66,53 @@ public class TextRegionUtil {
}
/**
- * Visit each {@link Font.Glyph}'s {@link OutlineShape} with the given {@link ShapeVisitor}
- * additionally passing the progressed {@link AffineTransform}.
+ * Add the string in 3D space w.r.t. the font in font em-size [0..1] at the end of the {@link GLRegion}
+ * while passing the progressed {@link AffineTransform}.
* <p>
- * The produced shapes are in font em-size [0..1], but can be adjusted with the given transform, progressed and passed to the visitor.
+ * The shapes added to the GLRegion are in font em-size [0..1], but can be adjusted with the given transform, progressed and passed to the visitor.
* </p>
- * @param visitor
- * @param transform optional given transform
+ * <p>
+ * Origin of rendered text is 0/0 at bottom left.
+ * </p>
+ * @param region the {@link GLRegion} sink
* @param font the target {@link Font}
+ * @param transform optional given transform
* @param str string text
- * @param temp1 temporary AffineTransform storage, mandatory
- * @param temp2 temporary AffineTransform storage, mandatory
+ * @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
+ * @return the bounding box of the given string by taking each glyph's font em-sized [0..1] OutlineShape into account.
*/
- public static void processString(final ShapeVisitor visitor, final AffineTransform transform,
- final Font font, final CharSequence str,
- final AffineTransform temp1, final AffineTransform temp2) {
- final int charCount = str.length();
-
- // region.setFlipped(true);
- final float lineHeight = font.getLineHeight();
-
- float y = 0;
- float advanceTotal = 0;
- Font.Glyph left_glyph = null;
-
- for(int i=0; i< charCount; i++) {
- final char character = str.charAt(i);
- if( '\n' == character ) {
- y -= lineHeight;
- advanceTotal = 0;
- left_glyph = null;
- } else if (character == ' ') {
- advanceTotal += font.getAdvanceWidth(Glyph.ID_SPACE);
- left_glyph = null;
- } else {
- // reset transform
- if( null != transform ) {
- temp1.setTransform(transform);
- } else {
- temp1.setToIdentity();
- }
- final Font.Glyph glyph = font.getGlyph(character);
- final OutlineShape glyphShape = glyph.getShape();
- if( null == glyphShape ) {
- left_glyph = null;
- continue;
- }
- if( null != left_glyph ) {
- advanceTotal += left_glyph.getKerning(glyph.getID());
- }
- temp1.translate(advanceTotal, y, temp2);
- visitor.visit(glyphShape, temp1);
- advanceTotal += glyph.getAdvance();
- left_glyph = glyph;
- }
- }
+ public static AABBox addStringToRegion(final Region region, final Font font, final AffineTransform transform,
+ final CharSequence str, final float[] rgbaColor) {
+ return addStringToRegion(region, font, transform, str, rgbaColor, new AffineTransform(), new AffineTransform());
}
/**
- * Add the string in 3D space w.r.t. the font in font em-size [0..1] at the end of the {@link GLRegion}.
+ * Add the string in 3D space w.r.t. the font in font em-size [0..1] at the end of the {@link GLRegion}
+ * while passing the progressed {@link AffineTransform}.
* <p>
- * The shapes added to the GLRegion are in font em-size [0..1].
+ * The shapes added to the GLRegion are in font em-size [0..1], but can be adjusted with the given transform, progressed and passed to the visitor.
+ * </p>
+ * <p>
+ * Origin of rendered text is 0/0 at bottom left.
* </p>
* @param region the {@link GLRegion} sink
- * @param vertexFactory vertex impl factory {@link Factory}
* @param font the target {@link Font}
+ * @param transform optional given transform
* @param str string text
* @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
* @param temp1 temporary AffineTransform storage, mandatory
* @param temp2 temporary AffineTransform storage, mandatory
+ * @return the bounding box of the given string by taking each glyph's font em-sized [0..1] OutlineShape into account.
*/
- public static void addStringToRegion(final GLRegion region, final Factory<? extends Vertex> vertexFactory,
- final Font font, final CharSequence str, final float[] rgbaColor,
- final AffineTransform temp1, final AffineTransform temp2) {
- final ShapeVisitor visitor = new ShapeVisitor() {
+ public static AABBox addStringToRegion(final Region region, final Font font, final AffineTransform transform,
+ final CharSequence str, final float[] rgbaColor,
+ final AffineTransform temp1, final AffineTransform temp2) {
+ final OutlineShape.Visitor visitor = new OutlineShape.Visitor() {
@Override
public final void visit(final OutlineShape shape, final AffineTransform t) {
region.addOutlineShape(shape, t, region.hasColorChannel() ? rgbaColor : null);
} };
- processString(visitor, null, font, str, temp1, temp2);
+ return font.processString(visitor, transform, str, temp1, temp2);
}
/**
@@ -166,6 +121,9 @@ public class TextRegionUtil {
* The shapes added to the GLRegion are in font em-size [0..1].
* </p>
* <p>
+ * Origin of rendered text is 0/0 at bottom left.
+ * </p>
+ * <p>
* Cached {@link GLRegion}s will be destroyed w/ {@link #clear(GL2ES2)} or to free memory.
* </p>
* @param gl the current GL state
@@ -175,22 +133,28 @@ public class TextRegionUtil {
* @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
* @param sampleCount desired multisampling sample count for msaa-rendering.
* The actual used scample-count is written back when msaa-rendering is enabled, otherwise the store is untouched.
+ * @return the bounding box of the given string from the produced and rendered GLRegion
* @throws Exception if TextRenderer not initialized
*/
- public void drawString3D(final GL2ES2 gl,
- final RegionRenderer renderer, final Font font, final CharSequence str,
- final float[] rgbaColor, final int[/*1*/] sampleCount) {
+ public AABBox drawString3D(final GL2ES2 gl,
+ final RegionRenderer renderer, final Font font, final CharSequence str,
+ final float[] rgbaColor, final int[/*1*/] sampleCount) {
if( !renderer.isInitialized() ) {
throw new GLException("TextRendererImpl01: not initialized!");
}
final int special = 0;
GLRegion region = getCachedRegion(font, str, special);
+ AABBox res;
if(null == region) {
region = GLRegion.create(renderModes, null);
- addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, str, rgbaColor, tempT1, tempT2);
+ res = addStringToRegion(region, font, null, str, rgbaColor, tempT1, tempT2);
addCachedRegion(gl, font, str, special, region);
+ } else {
+ res = new AABBox();
+ res.copy(region.getBounds());
}
region.draw(gl, renderer, sampleCount);
+ return res;
}
/**
@@ -199,9 +163,12 @@ public class TextRegionUtil {
* The shapes added to the GLRegion are in font em-size [0..1].
* </p>
* <p>
+ * Origin of rendered text is 0/0 at bottom left.
+ * </p>
+ * <p>
* In case of a multisampling region renderer, i.e. {@link Region#VBAA_RENDERING_BIT}, recreating the {@link GLRegion}
* is a huge performance impact.
- * In such case better use {@link #drawString3D(GL2ES2, GLRegion, RegionRenderer, Font, CharSequence, float[], int[], AffineTransform, AffineTransform)}
+ * In such case better use {@link #drawString3D(GL2ES2, GLRegion, RegionRenderer, Font, CharSequence, float[], int[])}
* instead.
* </p>
* @param gl the current GL state
@@ -211,21 +178,20 @@ public class TextRegionUtil {
* @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
* @param sampleCount desired multisampling sample count for msaa-rendering.
* The actual used scample-count is written back when msaa-rendering is enabled, otherwise the store is untouched.
- * @param temp1 temporary AffineTransform storage, mandatory
- * @param temp2 temporary AffineTransform storage, mandatory
* @throws Exception if TextRenderer not initialized
+ * @return the bounding box of the given string from the produced and rendered GLRegion
*/
- public static void drawString3D(final GL2ES2 gl, final int renderModes,
- final RegionRenderer renderer, final Font font, final CharSequence str,
- final float[] rgbaColor, final int[/*1*/] sampleCount, final AffineTransform temp1,
- final AffineTransform temp2) {
+ public static AABBox drawString3D(final GL2ES2 gl, final int renderModes,
+ final RegionRenderer renderer, final Font font, final CharSequence str,
+ final float[] rgbaColor, final int[/*1*/] sampleCount) {
if(!renderer.isInitialized()){
throw new GLException("TextRendererImpl01: not initialized!");
}
final GLRegion region = GLRegion.create(renderModes, null);
- addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, str, rgbaColor, temp1, temp2);
+ final AABBox res = addStringToRegion(region, font, null, str, rgbaColor);
region.draw(gl, renderer, sampleCount);
region.destroy(gl);
+ return res;
}
/**
@@ -234,26 +200,28 @@ public class TextRegionUtil {
* <p>
* The shapes added to the GLRegion are in font em-size [0..1].
* </p>
+ * <p>
+ * Origin of rendered text is 0/0 at bottom left.
+ * </p>
* @param gl the current GL state
* @param font {@link Font} to be used
* @param str text to be rendered
* @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
* @param sampleCount desired multisampling sample count for msaa-rendering.
* The actual used scample-count is written back when msaa-rendering is enabled, otherwise the store is untouched.
- * @param temp1 temporary AffineTransform storage, mandatory
- * @param temp2 temporary AffineTransform storage, mandatory
+ * @return the bounding box of the given string from the produced and rendered GLRegion
* @throws Exception if TextRenderer not initialized
*/
- public static void drawString3D(final GL2ES2 gl, final GLRegion region, final RegionRenderer renderer,
- final Font font, final CharSequence str, final float[] rgbaColor,
- final int[/*1*/] sampleCount, final AffineTransform temp1,
- final AffineTransform temp2) {
+ public static AABBox drawString3D(final GL2ES2 gl, final GLRegion region, final RegionRenderer renderer,
+ final Font font, final CharSequence str, final float[] rgbaColor,
+ final int[/*1*/] sampleCount) {
if(!renderer.isInitialized()){
throw new GLException("TextRendererImpl01: not initialized!");
}
region.clear(gl);
- addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, str, rgbaColor, temp1, temp2);
+ final AABBox res = addStringToRegion(region, font, null, str, rgbaColor);
region.draw(gl, renderer, sampleCount);
+ return res;
}
/**
diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java
index 2d26b1a85..fdef6a612 100644
--- a/src/jogl/classes/com/jogamp/graph/font/Font.java
+++ b/src/jogl/classes/com/jogamp/graph/font/Font.java
@@ -1,5 +1,5 @@
/**
-// * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 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:
@@ -81,42 +81,42 @@ public interface Font {
*/
public interface Metrics {
/**
- * @return ascent in font-units to be divided by {@link #getUnitsPerEM()}
+ * @return ascent in font-units, sourced from `hheaTable' table.
*/
int getAscentFU();
/**
- * @return ascent in font em-size [0..1]
+ * @return ascent in font em-size [0..1], sourced from `hheaTable' table.
*/
float getAscent();
/**
- * @return descent in font-units to be divided by {@link #getUnitsPerEM()}
+ * @return descent in font-units, sourced from `hheaTable' table.
*/
int getDescentFU();
/**
- * @return descend in font em-size [0..1]
+ * @return descend in font em-size [0..1], sourced from `hheaTable' table.
*/
float getDescent();
/**
- * @return line-gap in font-units to be divided by {@link #getUnitsPerEM()}
+ * @return line-gap in font-units, sourced from `hheaTable' table.
*/
int getLineGapFU();
/**
- * @return line-gap in font em-size [0..1]
+ * @return line-gap in font em-size [0..1], sourced from `hheaTable' table.
*/
float getLineGap();
/**
- * @return max-extend in font-units to be divided by {@link #getUnitsPerEM()}
+ * @return max-extend in font-units, sourced from `hheaTable' table.
*/
int getMaxExtendFU();
/**
- * @return max-extend in font em-size [0..1]
+ * @return max-extend in font em-size [0..1], sourced from `hheaTable' table.
*/
float getMaxExtend();
@@ -161,7 +161,6 @@ public interface Font {
public static final int ID_SPACE = 3;
Font getFont();
- char getSymbol();
/** Return this glyph's ID */
int getID();
@@ -177,25 +176,31 @@ public interface Font {
float getScale(final int funits);
/**
- * Return the AABBox in font-units to be divided by unitsPerEM
+ * Return the AABBox in font-units, borrowing internal instance.
*/
AABBox getBBoxFU();
/**
- * Return the AABBox in font-units to be divided by unitsPerEM
+ * Return the AABBox in font-units, copying into given dest.
* @param dest AABBox instance set to this metrics boundary in font-units
* @return the given and set AABBox 'dest' in font-units
*/
AABBox getBBoxFU(final AABBox dest);
/**
+ * Return the AABBox in font em-size [0..1], copying into given dest.
* @param dest AABBox instance set to this metrics boundary in font em-size [0..1]
* @param tmpV3 caller provided temporary 3-component vector
* @return the given and set AABBox 'dest' in font em-size [0..1]
*/
AABBox getBBox(final AABBox dest, float[] tmpV3);
- /** Return advance in font units to be divided by unitsPerEM */
+ /**
+ * Return the AABBox in font em-size [0..1], creating a new copy.
+ */
+ AABBox getBBox();
+
+ /** Return advance in font units, sourced from `hmtx` table. */
int getAdvanceFU();
/** Return advance in font em-size [0..1] */
@@ -210,10 +215,10 @@ public interface Font {
int getKerningPairCount();
/**
- * Returns the optional kerning inter-glyph distance within words between this glyph and the given right glyph_id in font-units to be divided by unitsPerEM
+ * Returns the optional kerning inter-glyph distance within words between this glyph and the given right glyph_id in font-units.
*
* @param right_glyphid right glyph code id
- * @return font-units to be divided by unitsPerEM
+ * @return font-units
*/
int getKerningFU(final int right_glyphid);
@@ -247,7 +252,7 @@ public interface Font {
StringBuilder getAllNames(final StringBuilder string, final String separator);
/**
- * Return advance-width of given glyphID in font-units to be divided by unitsPerEM
+ * Return advance-width of given glyphID in font-units, sourced from `hmtx` table.
* @param glyphID
*/
int getAdvanceWidthFU(final int glyphID);
@@ -262,12 +267,22 @@ public interface Font {
int getGlyphID(final char symbol);
- Glyph getGlyph(final char symbol);
+ Glyph getGlyph(final int glyph_id);
int getNumGlyphs();
/**
- * Return line height in font-units to be divided by unitsPerEM
+ * Return line height in font-units, composed from `hheaTable' table entries.
+ * <pre>
+ * return abs(lineGap) + abs(descent) abs(ascent);
+ * </pre>
+ * or
+ * <pre>
+ * // lineGap negative value
+ * // descent positive value
+ * // ascent negative value
+ * return -1 * ( lineGap - descent + ascent );
+ * </pre>
*/
int getLineHeightFU();
@@ -276,43 +291,126 @@ public interface Font {
*/
float getLineHeight();
- /** Return metric-width in font-units */
- int getMetricWidthFU(final CharSequence string);
-
- /** Return metric-width in font em-size */
- float getMetricWidth(final CharSequence string);
-
- /** Return metric-height in font-units */
- int getMetricHeightFU(final CharSequence string);
-
- /** Return metric-height in font em-size */
- float getMetricHeight(final CharSequence string);
-
- /** Return layout metric-bounds in font-units, see {@link #getMetricBounds(CharSequence, float)} */
+ /**
+ * Returns metric-bounds in font-units.
+ * <p>
+ * Metric bounds is based on the `hmtx` table's advance of each glyph and `hheaTable' composed line height.
+ * </p>
+ * <p>
+ * For accurate layout consider using {@link #getGlyphBoundsFU(CharSequence)}.
+ * </p>
+ * @see #getMetricBounds(CharSequence)
+ * @see #getGlyphBoundsFU(CharSequence)
+ */
AABBox getMetricBoundsFU(final CharSequence string);
- /** Return layout metric-bounds in font em-size, see {@link #getMetricBounds(CharSequence, float)} */
+ /**
+ * Returns metric-bounds in font em-size.
+ * <p>
+ * Metric bounds is based on the `hmtx` table's advance of each glyph and `hheaTable' composed line height.
+ * </p>
+ * <p>
+ * For accurate layout consider using {@link #getGlyphBounds(CharSequence)}.
+ * </p>
+ * @see #getMetricBoundsFU(CharSequence)
+ * @see #getGlyphBounds(CharSequence)
+ * @see #getGlyphShapeBounds(CharSequence)
+ */
AABBox getMetricBounds(final CharSequence string);
/**
- * Return the bounding box by taking each glyph's font-unit sized bounding box into account.
- * @param transform optional given transform
+ * Returns accurate bounding box by taking each glyph's font em-sized bounding box into account.
+ * <p>
+ * Glyph bounds is based on each glyph's bounding box and `hheaTable' composed line height.
+ * </p>
+ * @param string string text
+ * @return the bounding box of the given string in font em-size [0..1]
+ * @see #getGlyphBoundsFU(CharSequence)
+ * @see #getGlyphShapeBounds(CharSequence)
+ * @see #getMetricBounds(CharSequence)
+ */
+ AABBox getGlyphBounds(final CharSequence string);
+
+ /**
+ * Returns accurate bounding box by taking each glyph's font-units sized bounding box into account.
+ * <p>
+ * Glyph bounds is based on each glyph's bounding box and `hheaTable' composed line height.
+ * </p>
* @param string string text
* @return the bounding box of the given string in font-units [0..1]
+ * @see #getGlyphBounds(CharSequence)
*/
- AABBox getPointsBoundsFU(final AffineTransform transform, final CharSequence string);
+ AABBox getGlyphBoundsFU(final CharSequence string);
/**
- * Return the bounding box by taking each glyph's font em-sized bounding box into account.
+ * Returns accurate bounding box by taking each glyph's font em-sized {@link OutlineShape} into account.
+ * <p>
+ * Glyph shape bounds is based on each glyph's {@link OutlineShape} and `hheaTable' composed line height.
+ * </p>
+ * <p>
+ * This method is only exposed to validate the produced {@link OutlineShape} against {@link #getGlyphBounds(CharSequence)}.
+ * </p>
* @param transform optional given transform
* @param string string text
- * @return the bounding box of the given string in font em-size [0..1]
+ * @return the bounding box of the given string in font-units [0..1]
+ * @see #getGlyphShapeBounds(CharSequence)
+ * @see #getGlyphBounds(CharSequence)
+ * @see #getMetricBounds(CharSequence)
*/
- AABBox getPointsBounds(final AffineTransform transform, final CharSequence string);
+ AABBox getGlyphShapeBounds(final AffineTransform transform, final CharSequence string);
+
+ /**
+ * Returns accurate bounding box by taking each glyph's font em-sized {@link OutlineShape} into account.
+ * <p>
+ * Glyph shape bounds is based on each glyph's {@link OutlineShape} and `hheaTable' composed line height.
+ * </p>
+ * <p>
+ * This method is only exposed to validate the produced {@link OutlineShape} against {@link #getGlyphBounds(CharSequence)}.
+ * </p>
+ * @param string string text
+ * @return the bounding box of the given string in font-units [0..1]
+ * @see #getGlyphShapeBounds(AffineTransform, CharSequence)
+ * @see #getGlyphBounds(CharSequence)
+ * @see #getMetricBounds(CharSequence)
+ */
+ AABBox getGlyphShapeBounds(final CharSequence string);
boolean isPrintableChar(final char c);
- /** Shall return {@link #getFullFamilyName()} */
+ /**
+ * Visit each {@link Glyph}'s {@link OutlineShape} of the string with the {@link OutlineShape.Visitor}
+ * while passing the progressed {@link AffineTransform}.
+ * <p>
+ * The produced shapes are in font em-size [0..1], but can be adjusted with the given transform, progressed and passed to the visitor.
+ * </p>
+ * @param visitor handling each glyph's outline shape in font em-size [0..1] and the given {@link AffineTransform}
+ * @param transform optional given transform
+ * @param font the target {@link Font}
+ * @param string string text
+ * @return the bounding box of the given string by taking each glyph's font em-sized [0..1] {@link OutlineShape} into account.
+ */
+ AABBox processString(final OutlineShape.Visitor visitor, final AffineTransform transform,
+ final CharSequence string);
+
+ /**
+ * Visit each {@link Glyph}'s {@link OutlineShape} of the string with the {@link OutlineShape.Visitor}
+ * while passing the progressed {@link AffineTransform}.
+ * <p>
+ * The produced shapes are in font em-size [0..1], but can be adjusted with the given transform, progressed and passed to the visitor.
+ * </p>
+ * @param visitor handling each glyph's outline shape in font em-size [0..1] and the given {@link AffineTransform}
+ * @param transform optional given transform
+ * @param font the target {@link Font}
+ * @param string string text
+ * @param temp1 temporary AffineTransform storage, mandatory
+ * @param temp2 temporary AffineTransform storage, mandatory
+ * @return the bounding box of the given string by taking each glyph's font em-sized [0..1] {@link OutlineShape} into account.
+ */
+ AABBox processString(final OutlineShape.Visitor visitor, final AffineTransform transform,
+ final CharSequence string,
+ final AffineTransform temp1, final AffineTransform temp2);
+
+ /** Returns {@link #getFullFamilyName()} */
@Override
public String toString();
diff --git a/src/jogl/classes/com/jogamp/graph/font/FontFactory.java b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
index 5c317bd2b..ac42274f6 100644
--- a/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
+++ b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2011 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 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:
diff --git a/src/jogl/classes/com/jogamp/graph/font/FontSet.java b/src/jogl/classes/com/jogamp/graph/font/FontSet.java
index 60a16b241..607aab433 100644
--- a/src/jogl/classes/com/jogamp/graph/font/FontSet.java
+++ b/src/jogl/classes/com/jogamp/graph/font/FontSet.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2011 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 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:
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 ;