aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/graph
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/graph')
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java147
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/OutlineShapeXForm.java5
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/Region.java150
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java2
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java340
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java218
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java35
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java10
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/Font.java26
9 files changed, 675 insertions, 258 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
index 44744584d..d4977669e 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
@@ -111,6 +111,9 @@ public class OutlineShape implements Comparable<OutlineShape> {
}
}
+ /** Initial {@link #getSharpness()} value, which can be modified via {@link #setSharpness(float)}. */
+ public static final float DEFAULT_SHARPNESS = 0.5f;
+
public static final int DIRTY_BOUNDS = 1 << 0;
/**
* Modified shape, requires to update the vertices and triangles, here: vertices.
@@ -131,6 +134,7 @@ public class OutlineShape implements Comparable<OutlineShape> {
private final AABBox bbox;
private final ArrayList<Triangle> triangles;
private final ArrayList<Vertex> vertices;
+ private int addedVerticeCount;
private VerticesState outlineState;
@@ -153,12 +157,24 @@ public class OutlineShape implements Comparable<OutlineShape> {
this.bbox = new AABBox();
this.triangles = new ArrayList<Triangle>();
this.vertices = new ArrayList<Vertex>();
+ this.addedVerticeCount = 0;
this.dirtyBits = 0;
- this.sharpness = 0.5f;
+ this.sharpness = DEFAULT_SHARPNESS;
+ }
+
+ /**
+ * Return the number of newly added vertices during {@link #getTriangles(VerticesState)}
+ * while transforming the outlines to {@link VerticesState#QUADRATIC_NURBS} and triangulation.
+ * @see #setIsQuadraticNurbs()
+ */
+ public int getAddedVerticeCount() {
+ return addedVerticeCount;
}
+ /** Sharpness value, defaults to {@link #DEFAULT_SHARPNESS}. */
public float getSharpness() { return sharpness; }
+ /** Sets sharpness, defaults to {@link #DEFAULT_SHARPNESS}. */
public void setSharpness(final float s) {
if( this.sharpness != s ) {
clearCache();
@@ -174,6 +190,7 @@ public class OutlineShape implements Comparable<OutlineShape> {
bbox.reset();
vertices.clear();
triangles.clear();
+ addedVerticeCount = 0;
dirtyBits = 0;
}
@@ -418,21 +435,12 @@ public class OutlineShape implements Comparable<OutlineShape> {
}
/**
- * Ensure the outlines represent
- * the specified destinationType.
- * and removes all overlaps in boundary triangles
- * @param destinationType the target outline's vertices state. Currently only
- * {@link OutlineShape.VerticesState#QUADRATIC_NURBS} are supported.
+ * Claim this outline's vertices are all {@link OutlineShape.VerticesState#QUADRATIC_NURBS},
+ * hence no cubic transformations will be performed.
*/
- protected final void transformOutlines(VerticesState destinationType) {
- if(outlineState != destinationType){
- if(destinationType == VerticesState.QUADRATIC_NURBS){
- transformOutlines2Quadratic();
- checkOverlaps();
- } else {
- throw new IllegalStateException("destinationType "+destinationType.name()+" not supported (currently "+outlineState.name()+")");
- }
- }
+ public final void setIsQuadraticNurbs() {
+ outlineState = VerticesState.QUADRATIC_NURBS;
+ // checkPossibleOverlaps = false;
}
private void subdivideTriangle(final Outline outline, Vertex a, Vertex b, Vertex c, int index){
@@ -446,6 +454,8 @@ public class OutlineShape implements Comparable<OutlineShape> {
outline.addVertex(index, vertexFactory.create(tmpV1, 0, 3, false));
outline.addVertex(index+2, vertexFactory.create(tmpV3, 0, 3, false));
+
+ addedVerticeCount += 2;
}
/**
@@ -470,21 +480,24 @@ public class OutlineShape implements Comparable<OutlineShape> {
if ( !currentVertex.isOnCurve()) {
final Vertex nextV = outline.getVertex((i+1)%vertexCount);
final Vertex prevV = outline.getVertex((i+vertexCount-1)%vertexCount);
- Vertex overlap =null;
-
- //check for overlap even if already set for subdivision
- //ensuring both trianglur overlaps get divided
- //for pref. only check in first pass
- //second pass to clear the overlaps arrray(reduces precision errors)
- if(firstpass) {
- overlap = checkTriOverlaps(prevV, currentVertex, nextV);
+ final Vertex overlap;
+
+ // check for overlap even if already set for subdivision
+ // ensuring both triangular overlaps get divided
+ // for pref. only check in first pass
+ // second pass to clear the overlaps array(reduces precision errors)
+ if( firstpass ) {
+ overlap = checkTriOverlaps0(prevV, currentVertex, nextV);
+ } else {
+ overlap = null;
}
- if(overlaps.contains(currentVertex) || overlap != null) {
+ if( overlaps.contains(currentVertex) || overlap != null ) {
overlaps.remove(currentVertex);
subdivideTriangle(outline, prevV, currentVertex, nextV, i);
i+=3;
vertexCount+=2;
+ addedVerticeCount+=2;
if(overlap != null && !overlap.isOnCurve()) {
if(!overlaps.contains(overlap)) {
@@ -496,11 +509,11 @@ public class OutlineShape implements Comparable<OutlineShape> {
}
}
firstpass = false;
- }while(!overlaps.isEmpty());
+ } while( !overlaps.isEmpty() );
}
- private Vertex checkTriOverlaps(Vertex a, Vertex b, Vertex c) {
- int count = getOutlineNumber();
+ private Vertex checkTriOverlaps0(final Vertex a, final Vertex b, final Vertex c) {
+ final int count = getOutlineNumber();
for (int cc = 0; cc < count; cc++) {
final Outline outline = getOutline(cc);
int vertexCount = outline.getVertexCount();
@@ -524,45 +537,81 @@ public class OutlineShape implements Comparable<OutlineShape> {
}
if(VectorUtil.testTri2SegIntersection(a, b, c, prevV, current) ||
VectorUtil.testTri2SegIntersection(a, b, c, current, nextV) ||
- VectorUtil.testTri2SegIntersection(a, b, c, prevV, nextV)) {
+ VectorUtil.testTri2SegIntersection(a, b, c, prevV, nextV) ) {
return current;
}
}
}
return null;
}
+ @SuppressWarnings("unused")
+ private Vertex checkTriOverlaps1(final Vertex a, final Vertex b, final Vertex c) {
+ final int count = getOutlineNumber();
+ for (int cc = 0; cc < count; cc++) {
+ final Outline outline = getOutline(cc);
+ int vertexCount = outline.getVertexCount();
+ for(int i=0; i < vertexCount; i++) {
+ final Vertex current = outline.getVertex(i);
+ if(current.isOnCurve() || current == a || current == b || current == c) {
+ continue;
+ }
+ final Vertex nextV = outline.getVertex((i+1)%vertexCount);
+ final Vertex prevV = outline.getVertex((i+vertexCount-1)%vertexCount);
- private void transformOutlines2Quadratic() {
+ //skip neighboring triangles
+ if(prevV == c || nextV == a) {
+ continue;
+ }
+
+ if( VectorUtil.isVec3InTriangle3(a.getCoord(), b.getCoord(), c.getCoord(),
+ current.getCoord(), nextV.getCoord(), prevV.getCoord(),
+ tmpV1, tmpV2, tmpV3, FloatUtil.EPSILON) ) {
+ return current;
+ }
+ if(VectorUtil.testTri2SegIntersection(a, b, c, prevV, current, FloatUtil.EPSILON) ||
+ VectorUtil.testTri2SegIntersection(a, b, c, current, nextV, FloatUtil.EPSILON) ||
+ VectorUtil.testTri2SegIntersection(a, b, c, prevV, nextV, FloatUtil.EPSILON) ) {
+ return current;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void cleanupOutlines() {
+ final boolean transformOutlines2Quadratic = VerticesState.QUADRATIC_NURBS != outlineState;
int count = getOutlineNumber();
for (int cc = 0; cc < count; cc++) {
final Outline outline = getOutline(cc);
int vertexCount = outline.getVertexCount();
- for(int i=0; i < vertexCount; i++) {
- final Vertex currentVertex = outline.getVertex(i);
- final Vertex nextVertex = outline.getVertex((i+1)%vertexCount);
- if ( !currentVertex.isOnCurve() && !nextVertex.isOnCurve() ) {
- VectorUtil.midVec3(tmpV1, currentVertex.getCoord(), nextVertex.getCoord());
- final Vertex v = vertexFactory.create(tmpV1, 0, 3, true);
- i++;
- vertexCount++;
- outline.addVertex(i, v);
+ if( transformOutlines2Quadratic ) {
+ for(int i=0; i < vertexCount; i++) {
+ final Vertex currentVertex = outline.getVertex(i);
+ final int j = (i+1)%vertexCount;
+ final Vertex nextVertex = outline.getVertex(j);
+ if ( !currentVertex.isOnCurve() && !nextVertex.isOnCurve() ) {
+ VectorUtil.midVec3(tmpV1, currentVertex.getCoord(), nextVertex.getCoord());
+ System.err.println("XXX: Cubic: "+i+": "+currentVertex+", "+j+": "+nextVertex);
+ final Vertex v = vertexFactory.create(tmpV1, 0, 3, true);
+ i++;
+ vertexCount++;
+ addedVerticeCount++;
+ outline.addVertex(i, v);
+ }
}
}
- if(vertexCount <= 0) {
+ if( 0 >= vertexCount ) {
outlines.remove(outline);
cc--;
count--;
- continue;
- }
-
- if( vertexCount > 0 ) {
- if(VectorUtil.isVec3Equal( outline.getVertex(0).getCoord(), 0, outline.getLastVertex().getCoord(), 0, FloatUtil.EPSILON )) {
- outline.removeVertex(vertexCount-1);
- }
+ } else if( 0 < vertexCount &&
+ VectorUtil.isVec3Equal( outline.getVertex(0).getCoord(), 0, outline.getLastVertex().getCoord(), 0, FloatUtil.EPSILON )) {
+ outline.removeVertex(vertexCount-1);
}
}
outlineState = VerticesState.QUADRATIC_NURBS;
+ checkOverlaps();
}
private int generateVertexIds() {
@@ -616,6 +665,7 @@ public class OutlineShape implements Comparable<OutlineShape> {
triangulator2d.addCurve(triangles, outlines.get(index), sharpness);
}
triangulator2d.generate(triangles);
+ addedVerticeCount += triangulator2d.getAddedVerticeCount();
triangulator2d.reset();
}
}
@@ -631,8 +681,11 @@ public class OutlineShape implements Comparable<OutlineShape> {
*/
public ArrayList<Triangle> getTriangles(VerticesState destinationType) {
final boolean updated;
+ if(destinationType != VerticesState.QUADRATIC_NURBS) {
+ throw new IllegalStateException("destinationType "+destinationType.name()+" not supported (currently "+outlineState.name()+")");
+ }
if( 0 != ( DIRTY_TRIANGLES & dirtyBits ) ) {
- transformOutlines(destinationType);
+ cleanupOutlines();
triangulateImpl();
updated = true;
dirtyBits |= DIRTY_VERTICES;
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShapeXForm.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShapeXForm.java
index b1c99f5ed..cf4d38450 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShapeXForm.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShapeXForm.java
@@ -4,10 +4,13 @@ import jogamp.graph.geom.plane.AffineTransform;
public class OutlineShapeXForm {
public final OutlineShape shape;
- public final AffineTransform t;
+ private AffineTransform t;
public OutlineShapeXForm(final OutlineShape shape, final AffineTransform t) {
this.shape = shape;
this.t = t;
}
+
+ public final AffineTransform getTransform() { return t; }
+ public final void setTransform(final AffineTransform t) { this.t = t; }
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/curve/Region.java b/src/jogl/classes/com/jogamp/graph/curve/Region.java
index 15a0d6bff..2cd68a806 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/Region.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/Region.java
@@ -78,11 +78,31 @@ public abstract class Region {
* being applied.
* </p>
*/
- public static final int VARIABLE_CURVE_WEIGHT_BIT = 1 << 8;
+ public static final int VARWEIGHT_RENDERING_BIT = 1 << 8;
+
+ /**
+ * Rendering-Mode bit for {@link Region#getRenderModes() Region} and {@link com.jogamp.graph.curve.opengl.RegionRenderer#getRenderModes() RegionRenderer}.
+ * <p>
+ * If set, a color channel attribute per vertex is added to the stream,
+ * otherwise only the
+ * {@link com.jogamp.graph.curve.opengl.RegionRenderer#setColorStatic(javax.media.opengl.GL2ES2, float, float, float, float) static color}
+ * is being used.
+ * </p>
+ */
+ public static final int COLORCHANNEL_RENDERING_BIT = 1 << 9;
+
+ /**
+ * Rendering-Mode bit for {@link Region#getRenderModes() Region} and {@link com.jogamp.graph.curve.opengl.RegionRenderer#getRenderModes() RegionRenderer}.
+ * <p>
+ * If set, a color texture is used to determine the color.
+ * </p>
+ */
+ public static final int COLORTEXTURE_RENDERING_BIT = 1 << 10;
public static final int TWO_PASS_DEFAULT_TEXTURE_UNIT = 0;
private final int renderModes;
+ private int quality;
private boolean dirty = true;
private int numVertices = 0;
protected final AABBox box = new AABBox();
@@ -91,48 +111,73 @@ public abstract class Region {
public static boolean isVBAA(int renderModes) {
return 0 != (renderModes & Region.VBAA_RENDERING_BIT);
}
+
public static boolean isMSAA(int renderModes) {
return 0 != (renderModes & Region.MSAA_RENDERING_BIT);
}
+ public static boolean isTwoPass(int renderModes) {
+ return 0 != ( renderModes & ( Region.VBAA_RENDERING_BIT | Region.MSAA_RENDERING_BIT) );
+ }
+
/**
- * Check if render mode capable of non uniform weights
- *
- * @param renderModes
- * bit-field of modes, e.g.
- * {@link Region#VARIABLE_CURVE_WEIGHT_BIT},
- * {@link Region#VBAA_RENDERING_BIT}
- * @return true of capable of non uniform weights */
- public static boolean isNonUniformWeight(int renderModes) {
- return 0 != (renderModes & Region.VARIABLE_CURVE_WEIGHT_BIT);
+ * Returns true if render mode capable of variable weights,
+ * i.e. the bit {@link #VARWEIGHT_RENDERING_BIT} is set,
+ * otherwise false.
+ */
+ public static boolean hasVariableWeight(int renderModes) {
+ return 0 != (renderModes & Region.VARWEIGHT_RENDERING_BIT);
+ }
+
+ /**
+ * Returns true if render mode has a color channel,
+ * i.e. the bit {@link #COLORCHANNEL_RENDERING_BIT} is set,
+ * otherwise false.
+ */
+ public static boolean hasColorChannel(int renderModes) {
+ return 0 != (renderModes & Region.COLORCHANNEL_RENDERING_BIT);
+ }
+
+ /**
+ * Returns true if render mode has a color texture,
+ * i.e. the bit {@link #COLORTEXTURE_RENDERING_BIT} is set,
+ * otherwise false.
+ */
+ public static boolean hasColorTexture(int renderModes) {
+ return 0 != (renderModes & Region.COLORTEXTURE_RENDERING_BIT);
}
public static String getRenderModeString(int renderModes) {
- final String curveS = isNonUniformWeight(renderModes) ? "-curve" : "";
+ final String curveS = hasVariableWeight(renderModes) ? "-curve" : "";
+ final String cChanS = hasColorChannel(renderModes) ? "-cols" : "";
+ final String cTexS = hasColorTexture(renderModes) ? "-ctex" : "";
if( Region.isVBAA(renderModes) ) {
- return "vbaa"+curveS;
+ return "vbaa"+curveS+cChanS+cTexS;
} else if( Region.isMSAA(renderModes) ) {
- return "msaa"+curveS;
+ return "msaa"+curveS+cChanS+cTexS;
} else {
- return "norm"+curveS;
+ return "norm"+curveS+cChanS+cTexS;
}
}
protected Region(int regionRenderModes) {
this.renderModes = regionRenderModes;
+ this.quality = 99;
}
// FIXME: Better handling of impl. buffer growth .. !
+ // protected abstract void setupInitialComponentCount(int attributeCount, int indexCount);
- protected abstract void pushVertex(float[] coords, float[] texParams);
+ protected abstract void pushVertex(final float[] coords, final float[] texParams, float[] rgba);
protected abstract void pushIndex(int idx);
/**
* Return bit-field of render modes, see {@link #create(int)}.
*/
- public final int getRenderModes() {
- return renderModes;
- }
+ public final int getRenderModes() { return renderModes; }
+
+ public final int getQuality() { return quality; }
+ public final void setQuality(int q) { quality=q; }
protected void clearImpl() {
dirty = true;
@@ -141,31 +186,50 @@ public abstract class Region {
}
/**
- * Return true if capable of two pass rendering - VBAA, otherwise false.
+ * Returns true if capable of two pass rendering - VBAA, otherwise false.
*/
public final boolean isVBAA() {
- return isVBAA(renderModes);
+ return Region.isVBAA(renderModes);
}
/**
- * Return true if capable of two pass rendering - MSAA, otherwise false.
+ * Returns true if capable of two pass rendering - MSAA, otherwise false.
*/
public final boolean isMSAA() {
- return isMSAA(renderModes);
+ return Region.isMSAA(renderModes);
+ }
+
+ /**
+ * Returns true if capable of variable weights, otherwise false.
+ */
+ public final boolean hasVariableWeight() {
+ return Region.hasVariableWeight(renderModes);
}
/**
- * Return true if capable of nonuniform weights, otherwise false.
+ * Returns true if render mode has a color channel,
+ * i.e. the bit {@link #COLORCHANNEL_RENDERING_BIT} is set,
+ * otherwise false.
*/
- public final boolean isNonUniformWeight() {
- return Region.isNonUniformWeight(renderModes);
+ public boolean hasColorChannel() {
+ return Region.hasColorChannel(renderModes);
}
+ /**
+ * Returns true if render mode has a color texture,
+ * i.e. the bit {@link #COLORTEXTURE_RENDERING_BIT} is set,
+ * otherwise false.
+ */
+ public boolean hasColorTexture() {
+ return Region.hasColorTexture(renderModes);
+ }
+
+
/** See {@link #setFrustum(Frustum)} */
public final Frustum getFrustum() { return frustum; }
/**
- * Set {@link Frustum} culling for {@link #addOutlineShape(OutlineShape, AffineTransform)}.
+ * Set {@link Frustum} culling for {@link #addOutlineShape(OutlineShape, AffineTransform, float[])}.
*/
public final void setFrustum(Frustum frustum) {
this.frustum = frustum;
@@ -173,23 +237,23 @@ public abstract class Region {
final float[] coordsEx = new float[3];
- private void pushNewVertexImpl(final Vertex vertIn, final AffineTransform transform) {
+ private void pushNewVertexImpl(final Vertex vertIn, final AffineTransform transform, float[] rgba) {
if( null != transform ) {
final float[] coordsIn = vertIn.getCoord();
transform.transform(coordsIn, coordsEx);
coordsEx[2] = coordsIn[2];
box.resize(coordsEx[0], coordsEx[1], coordsEx[2]);
- pushVertex(coordsEx, vertIn.getTexCoord());
+ pushVertex(coordsEx, vertIn.getTexCoord(), rgba);
} else {
box.resize(vertIn.getX(), vertIn.getY(), vertIn.getZ());
- pushVertex(vertIn.getCoord(), vertIn.getTexCoord());
+ pushVertex(vertIn.getCoord(), vertIn.getTexCoord(), rgba);
}
numVertices++;
}
- private void pushNewVertexIdxImpl(final Vertex vertIn, final AffineTransform transform) {
+ private void pushNewVertexIdxImpl(final Vertex vertIn, final AffineTransform transform, float[] rgba) {
pushIndex(numVertices);
- pushNewVertexImpl(vertIn, transform);
+ pushNewVertexImpl(vertIn, transform, rgba);
}
private final AABBox tmpBox = new AABBox();
@@ -201,8 +265,9 @@ public abstract class Region {
* is dropped if it's {@link OutlineShape#getBounds() bounding-box} is fully outside of the frustum.
* The optional {@link AffineTransform} is applied to the bounding-box beforehand.
* </p>
+ * @param rgbaColor TODO
*/
- public final void addOutlineShape(final OutlineShape shape, final AffineTransform t) {
+ public final void addOutlineShape(final OutlineShape shape, final AffineTransform t, final float[] rgbaColor) {
if( null != frustum ) {
final AABBox shapeBox = shape.getBounds();
final AABBox shapeBoxT;
@@ -222,8 +287,15 @@ public abstract class Region {
final List<Triangle> trisIn = shape.getTriangles(OutlineShape.VerticesState.QUADRATIC_NURBS);
final ArrayList<Vertex> vertsIn = shape.getVertices();
if(DEBUG_INSTANCE) {
+ final int addedVerticeCount = shape.getAddedVerticeCount();
+ final int verticeCount = vertsIn.size() + addedVerticeCount;
+ final int indexCount = trisIn.size() * 3;
System.err.println("Region.addOutlineShape().0: tris: "+trisIn.size()+", verts "+vertsIn.size()+", transform "+t);
+ System.err.println("Region.addOutlineShape().0: VerticeCount "+vertsIn.size()+" + "+addedVerticeCount+" = "+verticeCount);
+ System.err.println("Region.addOutlineShape().0: IndexCount "+indexCount);
}
+ // setupInitialComponentCount(verticeCount, indexCount); // FIXME: Use it ?
+
final int idxOffset = numVertices;
int vertsVNewIdxCount = 0, vertsTMovIdxCount = 0, vertsTNewIdxCount = 0, tris = 0;
int vertsDupCountV = 0, vertsDupCountT = 0, vertsKnownMovedT = 0;
@@ -232,7 +304,7 @@ public abstract class Region {
System.err.println("Region.addOutlineShape(): Processing Vertices");
}
for(int i=0; i<vertsIn.size(); i++) {
- pushNewVertexImpl(vertsIn.get(i), t);
+ pushNewVertexImpl(vertsIn.get(i), t, rgbaColor);
vertsVNewIdxCount++;
}
if(DEBUG_INSTANCE) {
@@ -261,9 +333,9 @@ public abstract class Region {
if(Region.DEBUG_INSTANCE) {
System.err.println("T["+i+"]: New Idx "+numVertices);
}
- pushNewVertexIdxImpl(triInVertices[0], t);
- pushNewVertexIdxImpl(triInVertices[1], t);
- pushNewVertexIdxImpl(triInVertices[2], t);
+ pushNewVertexIdxImpl(triInVertices[0], t, rgbaColor);
+ pushNewVertexIdxImpl(triInVertices[1], t, rgbaColor);
+ pushNewVertexIdxImpl(triInVertices[2], t, rgbaColor);
vertsTNewIdxCount+=3;
}
tris++;
@@ -280,9 +352,9 @@ public abstract class Region {
setDirty(true);
}
- public final void addOutlineShapes(final List<OutlineShape> shapes, final AffineTransform transform) {
+ public final void addOutlineShapes(final List<OutlineShape> shapes, final AffineTransform transform, final float[] rgbaColor) {
for (int i = 0; i < shapes.size(); i++) {
- addOutlineShape(shapes.get(i), transform);
+ addOutlineShape(shapes.get(i), transform, rgbaColor);
}
}
@@ -306,6 +378,6 @@ public abstract class Region {
}
public String toString() {
- return "Region["+getRenderModeString(this.renderModes)+", dirty "+dirty+", vertices "+numVertices+", box "+box+"]";
+ return "Region["+getRenderModeString(this.renderModes)+", q "+quality+", dirty "+dirty+", vertices "+numVertices+", box "+box+"]";
}
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java
index 96d285898..e305cc336 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java
@@ -56,7 +56,7 @@ public abstract class GLRegion extends Region {
* {@link Region#TWO_PASS_DEFAULT_TEXTURE_UNIT} is being used.</p>
*
* @param rs the RenderState to be used
- * @param renderModes bit-field of modes, e.g. {@link Region#VARIABLE_CURVE_WEIGHT_BIT}, {@link Region#VBAA_RENDERING_BIT}
+ * @param renderModes bit-field of modes, e.g. {@link Region#VARWEIGHT_RENDERING_BIT}, {@link Region#VBAA_RENDERING_BIT}
*/
public static GLRegion create(int renderModes) {
if( isVBAA(renderModes) ) {
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 8233d4262..8df34ead5 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
@@ -27,16 +27,21 @@
*/
package com.jogamp.graph.curve.opengl;
-import java.nio.FloatBuffer;
+import java.io.IOException;
+import java.util.Iterator;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLException;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
+import jogamp.graph.curve.opengl.shader.AttributeNames;
+
+import com.jogamp.opengl.GLExtensions;
import com.jogamp.opengl.util.glsl.ShaderCode;
-import com.jogamp.opengl.util.glsl.ShaderState;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.common.util.IntObjectHashMap;
import com.jogamp.graph.curve.Region;
/**
@@ -46,7 +51,7 @@ import com.jogamp.graph.curve.Region;
* are passed through an instance of this class.
* </p>
*/
-public abstract class RegionRenderer {
+public class RegionRenderer {
protected static final boolean DEBUG = Region.DEBUG;
protected static final boolean DEBUG_INSTANCE = Region.DEBUG_INSTANCE;
@@ -95,10 +100,6 @@ public abstract class RegionRenderer {
}
};
- public static boolean isWeightValid(float v) {
- return 0.0f <= v && v <= 1.9f ;
- }
-
/**
* Create a Hardware accelerated Region Renderer.
* <p>
@@ -108,7 +109,7 @@ public abstract class RegionRenderer {
* can be utilized to enable and disable {@link GL#GL_BLEND}.
* </p>
* @param rs the used {@link RenderState}
- * @param renderModes bit-field of modes, e.g. {@link Region#VARIABLE_CURVE_WEIGHT_BIT}, {@link Region#VBAA_RENDERING_BIT}
+ * @param renderModes bit-field of modes, e.g. {@link Region#VARWEIGHT_RENDERING_BIT}, {@link Region#VBAA_RENDERING_BIT}
* @param enableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at
* {@link #init(GL2ES2) init(gl)} and {@link #enable(GL2ES2, boolean) enable(gl, true)}.
* @param disableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at
@@ -118,7 +119,7 @@ public abstract class RegionRenderer {
*/
public static RegionRenderer create(final RenderState rs, final int renderModes,
final GLCallback enableCallback, final GLCallback disableCallback) {
- return new jogamp.graph.curve.opengl.RegionRendererImpl01(rs, renderModes, enableCallback, disableCallback);
+ return new RegionRenderer(rs, renderModes, enableCallback, disableCallback);
}
private final int renderModes;
@@ -139,19 +140,10 @@ public abstract class RegionRenderer {
/** Return height of current viewport */
public final int getHeight() { return vp_height; }
- public final float getWeight() { return rs.getWeight().floatValue(); }
- public final float getAlpha() { return rs.getAlpha().floatValue(); }
- public final PMVMatrix getMatrix() { return rs.pmvMatrix(); }
-
- /**
- * Implementation shall load, compile and link the shader program and leave it active.
- * @param gl referencing the current GLContext to which the ShaderState is bound to
- * @return
- */
- protected abstract boolean initImpl(GL2ES2 gl);
-
- /** Delete and clean the associated OGL objects */
- protected abstract void destroyImpl(GL2ES2 gl);
+ public final PMVMatrix getMatrix() { return rs.getMatrix(); }
+ public final PMVMatrix getMatrixMutable() { return rs.getMatrixMutable(); }
+ public final void setMatrixDirty() { rs.setMatrixDirty(); }
+ public final boolean isMatrixDirty() { return rs.isMatrixDirty(); }
//////////////////////////////////////
@@ -170,14 +162,14 @@ public abstract class RegionRenderer {
return renderModes;
}
- public final boolean usesVariableCurveWeight() { return Region.isNonUniformWeight(renderModes); }
+ public final boolean usesVariableCurveWeight() { return Region.hasVariableWeight(renderModes); }
/**
* @return true if Region's renderModes contains all bits as this Renderer's renderModes
- * except {@link Region#VARIABLE_CURVE_WEIGHT_BIT}, otherwise false.
+ * except {@link Region#VARWEIGHT_RENDERING_BIT}, otherwise false.
*/
public final boolean areRenderModesCompatible(final Region region) {
- final int cleanRenderModes = getRenderModes() & ( Region.VARIABLE_CURVE_WEIGHT_BIT );
+ final int cleanRenderModes = getRenderModes() & ( Region.VARWEIGHT_RENDERING_BIT );
return cleanRenderModes == ( region.getRenderModes() & cleanRenderModes );
}
@@ -217,28 +209,11 @@ public abstract class RegionRenderer {
enableCallback.run(gl, this);
}
- initialized = initImpl(gl);
+ useShaderProgram(gl, renderModes, true, 0, 0);
+ initialized = rs.update(gl, true, renderModes, true);
if(!initialized) {
throw new GLException("Shader initialization failed");
}
-
- if(!rs.getShaderState().uniform(gl, rs.getPMVMatrix())) {
- throw new GLException("Error setting PMVMatrix in shader: "+rs.getShaderState());
- }
-
- if( Region.isNonUniformWeight( getRenderModes() ) ) {
- if(!rs.getShaderState().uniform(gl, rs.getWeight())) {
- throw new GLException("Error setting weight in shader: "+rs.getShaderState());
- }
- }
-
- if(!rs.getShaderState().uniform(gl, rs.getAlpha())) {
- throw new GLException("Error setting global alpha in shader: "+rs.getShaderState());
- }
-
- if(!rs.getShaderState().uniform(gl, rs.getColorStatic())) {
- throw new GLException("Error setting global color in shader: "+rs.getShaderState());
- }
}
public final void destroy(GL2ES2 gl) {
@@ -248,18 +223,19 @@ public abstract class RegionRenderer {
}
return;
}
- rs.getShaderState().useProgram(gl, false);
- destroyImpl(gl);
+ for(final Iterator<IntObjectHashMap.Entry> i = shaderPrograms.iterator(); i.hasNext(); ) {
+ final ShaderProgram sp = (ShaderProgram) i.next().getValue();
+ sp.destroy(gl);
+ }
rs.destroy(gl);
initialized = false;
}
public final RenderState getRenderState() { return rs; }
- public final ShaderState getShaderState() { return rs.getShaderState(); }
/**
- * Enabling or disabling the {@link RenderState#getShaderState() RenderState}'s
- * {@link ShaderState#useProgram(GL2ES2, boolean) ShaderState program}.
+ * Enabling or disabling the {@link #getRenderState() RenderState}'s
+ * {@link RenderState#getShaderProgram() shader program}.
* <p>
* In case enable and disable {@link GLCallback}s are setup via {@link #create(RenderState, int, GLCallback, GLCallback)},
* they will be called before toggling the shader program.
@@ -276,103 +252,59 @@ public abstract class RegionRenderer {
disableCallback.run(gl, this);
}
}
- rs.getShaderState().useProgram(gl, enable);
- }
-
- public final void setWeight(GL2ES2 gl, float v) {
- if( !isWeightValid(v) ) {
- throw new IllegalArgumentException("Weight out of range");
- }
- rs.getWeight().setData(v);
- if(null != gl && rs.getShaderState().inUse() && Region.isNonUniformWeight( getRenderModes() ) ) {
- rs.getShaderState().uniform(gl, rs.getWeight());
- }
- }
-
- public final void setAlpha(GL2ES2 gl, float alpha_t) {
- rs.getAlpha().setData(alpha_t);
- if(null != gl && rs.getShaderState().inUse()) {
- rs.getShaderState().uniform(gl, rs.getAlpha());
- }
-
- }
-
- public final void getColorStatic(float[] rgb) {
- FloatBuffer fb = (FloatBuffer) rs.getColorStatic().getBuffer();
- rgb[0] = fb.get(0);
- rgb[1] = fb.get(1);
- rgb[2] = fb.get(2);
- }
-
- public final void setColorStatic(GL2ES2 gl, float r, float g, float b){
- FloatBuffer fb = (FloatBuffer) rs.getColorStatic().getBuffer();
- fb.put(0, r);
- fb.put(1, g);
- fb.put(2, b);
- if(null != gl && rs.getShaderState().inUse()) {
- rs.getShaderState().uniform(gl, rs.getColorStatic());
- }
- }
-
- public final void updateMatrix(GL2ES2 gl) {
- if(initialized && null != gl && rs.getShaderState().inUse()) {
- rs.getShaderState().uniform(gl, rs.getPMVMatrix());
+ if( !enable ) {
+ final ShaderProgram sp = rs.getShaderProgram();
+ if( null != sp ) {
+ sp.useProgram(gl, false);
+ }
}
}
- /** No PMVMatrix operation is performed here. PMVMatrix will be updated if gl is not null. */
- public final boolean reshapeNotify(GL2ES2 gl, int width, int height) {
+ /** No PMVMatrix operation is performed here. PMVMatrix is marked dirty. */
+ public final void reshapeNotify(int width, int height) {
this.vp_width = width;
this.vp_height = height;
- updateMatrix(gl);
- return true;
+ rs.setMatrixDirty();
}
- public final boolean reshapePerspective(GL2ES2 gl, float angle, int width, int height, float near, float far) {
+ public final void reshapePerspective(float angle, int width, int height, float near, float far) {
this.vp_width = width;
this.vp_height = height;
final float ratio = (float)width/(float)height;
- final PMVMatrix p = rs.pmvMatrix();
+ final PMVMatrix p = rs.getMatrixMutable();
p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
p.glLoadIdentity();
p.gluPerspective(angle, ratio, near, far);
- updateMatrix(gl);
- return true;
}
- public final boolean reshapeOrtho(GL2ES2 gl, int width, int height, float near, float far) {
+ public final void reshapeOrtho(int width, int height, float near, float far) {
this.vp_width = width;
this.vp_height = height;
- final PMVMatrix p = rs.pmvMatrix();
+ final PMVMatrix p = rs.getMatrixMutable();
p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
p.glLoadIdentity();
p.glOrthof(0, width, 0, height, near, far);
- updateMatrix(gl);
- return true;
}
- protected String getVertexShaderName() {
- return "curverenderer" + getImplVersion();
- }
+ //
+ // Shader Management
+ //
- protected String getFragmentShaderName() {
- final String version = getImplVersion();
- final String pass;
- if( Region.isVBAA(renderModes) ) {
- pass = "-2pass_vbaa";
- } else if( Region.isMSAA(renderModes) ) {
- pass = "-2pass_msaa";
- } else {
- pass = "-1pass_norm" ;
- }
- final String weight = Region.isNonUniformWeight(renderModes) ? "-weight" : "" ;
- return "curverenderer" + version + pass + weight;
+ private static final String SHADER_SRC_SUB = "";
+ private static final String SHADER_BIN_SUB = "bin";
+
+ private static String USE_COLOR_CHANNEL = "#define USE_COLOR_CHANNEL 1\n";
+ private static String USE_COLOR_TEXTURE = "#define USE_COLOR_TEXTURE 1\n";
+ private static String DEF_SAMPLE_COUNT = "#define SAMPLE_COUNT ";
+
+ private String getVersionedShaderName() {
+ return "curverenderer01";
}
// FIXME: Really required to have sampler2D def. precision ? If not, we can drop getFragmentShaderPrecision(..) and use default ShaderCode ..
- public static final String es2_precision_fp = "\nprecision mediump float;\nprecision mediump int;\nprecision mediump sampler2D;\n";
+ private static final String es2_precision_fp = "\nprecision mediump float;\nprecision mediump int;\nprecision mediump sampler2D;\n";
- protected String getFragmentShaderPrecision(GL2ES2 gl) {
+ private final String getFragmentShaderPrecision(GL2ES2 gl) {
if( gl.isGLES() ) {
return es2_precision_fp;
}
@@ -382,7 +314,173 @@ public abstract class RegionRenderer {
return null;
}
- protected String getImplVersion() {
- return "01";
+ private static enum ShaderModeSelector1 {
+ /** Pass-1: Curve Simple */
+ PASS1_SIMPLE("curve", "_simple", 0),
+ /** Pass-1: Curve Varying Weight */
+ PASS1_WEIGHT("curve", "_weight", 0),
+ /** Pass-2: MSAA */
+ PASS2_MSAA("msaa", "", 0),
+ /** Pass-2: VBAA Flipquad3, 1 sample */
+ PASS2_VBAA_QUAL0_SAMPLES1("vbaa", "_flipquad3", 1),
+ /** Pass-2: VBAA Flipquad3, 2 samples */
+ PASS2_VBAA_QUAL0_SAMPLES2("vbaa", "_flipquad3", 2),
+ /** Pass-2: VBAA Flipquad3, 4 samples */
+ PASS2_VBAA_QUAL0_SAMPLES4("vbaa", "_flipquad3", 4),
+ /** Pass-2: VBAA Flipquad3, 8 samples */
+ PASS2_VBAA_QUAL0_SAMPLES8("vbaa", "_flipquad3", 8),
+ /** Pass-2: VBAA All-Equal, 2 samples */
+ PASS2_VBAA_QUAL1_SAMPLES2("vbaa", "_allequal", 2),
+ /** Pass-2: VBAA All-Equal, 4 samples */
+ PASS2_VBAA_QUAL1_SAMPLES4("vbaa", "_allequal", 4),
+ /** Pass-2: VBAA All-Equal, 6 samples */
+ PASS2_VBAA_QUAL1_SAMPLES6("vbaa", "_allequal", 6),
+ /** Pass-2: VBAA All-Equal, 8 samples */
+ PASS2_VBAA_QUAL1_SAMPLES8("vbaa", "_allequal", 8);
+
+ public final String tech;
+ public final String sub;
+ public final int sampleCount;
+
+ ShaderModeSelector1(final String tech, final String sub, final int sampleCount) {
+ this.tech = tech;
+ this.sub= sub;
+ this.sampleCount = sampleCount;
+ }
+
+ public static ShaderModeSelector1 selectPass1(final int renderModes) {
+ return Region.hasVariableWeight(renderModes) ? PASS1_WEIGHT : PASS1_SIMPLE;
+ }
+
+ public static ShaderModeSelector1 selectPass2(final int renderModes, final int quality, final int sampleCount) {
+ if( Region.isMSAA(renderModes) ) {
+ return PASS2_MSAA;
+ } else if( Region.isVBAA(renderModes) ) {
+ if( 0 == quality ) {
+ if( sampleCount < 2 ) {
+ return PASS2_VBAA_QUAL0_SAMPLES1;
+ } else if( sampleCount < 4 ) {
+ return PASS2_VBAA_QUAL0_SAMPLES2;
+ } else if( sampleCount < 8 ) {
+ return PASS2_VBAA_QUAL0_SAMPLES4;
+ } else {
+ return PASS2_VBAA_QUAL0_SAMPLES8;
+ }
+ } else {
+ if( sampleCount < 4 ) {
+ return PASS2_VBAA_QUAL1_SAMPLES2;
+ } else if( sampleCount < 6 ) {
+ return PASS2_VBAA_QUAL1_SAMPLES4;
+ } else if( sampleCount < 8 ) {
+ return PASS2_VBAA_QUAL1_SAMPLES6;
+ } else {
+ return PASS2_VBAA_QUAL1_SAMPLES8;
+ }
+ }
+ } else {
+ return null;
+ }
+ }
}
+ private final IntObjectHashMap shaderPrograms = new IntObjectHashMap();
+
+ private static final int HIGH_MASK = Region.COLORCHANNEL_RENDERING_BIT | Region.COLORTEXTURE_RENDERING_BIT;
+
+ /**
+ * @param gl
+ * @param renderModes
+ * @param pass1
+ * @param quality
+ * @param sampleCount
+ * @return true if a new shader program is being used and hence external uniform-data and -location,
+ * as well as the attribute-location must be updated, otherwise false.
+ */
+ public final boolean useShaderProgram(final GL2ES2 gl, final int renderModes,
+ final boolean pass1, final int quality, final int sampleCount) {
+ final ShaderModeSelector1 sel1 = pass1 ? ShaderModeSelector1.selectPass1(renderModes) :
+ ShaderModeSelector1.selectPass2(renderModes, quality, sampleCount);
+ final int shaderKey = sel1.ordinal() | ( HIGH_MASK & renderModes );
+
+ /**
+ if(DEBUG) {
+ System.err.printf("RegionRendererImpl01.useShaderProgram.0: renderModes %s, sel1 %s, key 0x%X (pass1 %b, q %d, samples %d) - Thread %s%n",
+ Region.getRenderModeString(renderModes), sel1, shaderKey, pass1, quality, sampleCount, Thread.currentThread());
+ } */
+
+ ShaderProgram sp = (ShaderProgram) shaderPrograms.get( shaderKey );
+ if( null != sp ) {
+ final boolean spChanged = getRenderState().setShaderProgram(gl, sp);
+ if(DEBUG) {
+ if( spChanged ) {
+ System.err.printf("RegionRendererImpl01.useShaderProgram.X1: GOT renderModes %s, sel1 %s, key 0x%X (changed)%n", Region.getRenderModeString(renderModes), sel1, shaderKey);
+ }
+ }
+ return spChanged;
+ }
+ final String versionedBaseName = getVersionedShaderName();
+ final String vertexShaderName;
+ if( Region.isTwoPass( renderModes ) ) {
+ vertexShaderName = versionedBaseName+"-pass"+(pass1?1:2);
+ } else {
+ vertexShaderName = versionedBaseName+"-single";
+ }
+ final ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, AttributeNames.class, SHADER_SRC_SUB, SHADER_BIN_SUB, vertexShaderName, true);
+ final ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, AttributeNames.class, SHADER_SRC_SUB, SHADER_BIN_SUB, versionedBaseName+"-segment-head", true);
+ int posVp = rsVp.defaultShaderCustomization(gl, true, true);
+ // rsFp.defaultShaderCustomization(gl, true, true);
+ int posFp = rsFp.addGLSLVersion(gl);
+ if( gl.isGLES2() && ! gl.isGLES3() ) {
+ posFp = rsFp.insertShaderSource(0, posFp, ShaderCode.createExtensionDirective(GLExtensions.OES_standard_derivatives, ShaderCode.ENABLE));
+ }
+ final String rsFpDefPrecision = getFragmentShaderPrecision(gl);
+ if( null != rsFpDefPrecision ) {
+ rsFp.insertShaderSource(0, posFp, rsFpDefPrecision);
+ }
+ if( Region.hasColorChannel( renderModes ) ) {
+ posVp = rsVp.insertShaderSource(0, posVp, USE_COLOR_CHANNEL);
+ posFp = rsFp.insertShaderSource(0, posFp, USE_COLOR_CHANNEL);
+ }
+ if( Region.hasColorTexture( renderModes ) ) {
+ posVp = rsVp.insertShaderSource(0, posVp, USE_COLOR_TEXTURE);
+ posFp = rsFp.insertShaderSource(0, posFp, USE_COLOR_TEXTURE);
+ }
+ if( !pass1 ) {
+ posFp = rsFp.insertShaderSource(0, posFp, DEF_SAMPLE_COUNT+sel1.sampleCount+"\n");
+ }
+
+ final String passS = pass1 ? "-pass1-" : "-pass2-";
+ final String shaderSegment = versionedBaseName+passS+sel1.tech+sel1.sub+".glsl";
+ if(DEBUG) {
+ System.err.printf("RegionRendererImpl01.useShaderProgram.1: segment %s%n", shaderSegment);
+ }
+ try {
+ posFp = rsFp.insertShaderSource(0, -1, AttributeNames.class, shaderSegment);
+ } catch (IOException ioe) {
+ throw new RuntimeException("Failed to read: "+shaderSegment, ioe);
+ }
+ if( 0 > posFp ) {
+ throw new RuntimeException("Failed to read: "+shaderSegment);
+ }
+ posFp = rsFp.insertShaderSource(0, -1, "}\n");
+
+ sp = new ShaderProgram();
+ sp.add(rsVp);
+ sp.add(rsFp);
+
+ if( !sp.init(gl) ) {
+ throw new GLException("RegionRenderer: Couldn't init program: "+sp);
+ }
+ if( !sp.link(gl, System.err) ) {
+ throw new GLException("could not link program: "+sp);
+ }
+ getRenderState().setShaderProgram(gl, sp);
+
+ shaderPrograms.put(shaderKey, sp);
+ if(DEBUG) {
+ System.err.printf("RegionRendererImpl01.useShaderProgram.X1: PUT renderModes %s, sel1 %s, key 0x%X -> SP %s (changed)%n",
+ Region.getRenderModeString(renderModes), sel1, shaderKey, sp);
+ }
+ return true;
+ }
+
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java
index 490af140a..f915b7d49 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java
@@ -27,20 +27,22 @@
*/
package com.jogamp.graph.curve.opengl;
+import java.nio.FloatBuffer;
+
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLUniformData;
-import jogamp.graph.curve.opengl.RenderStateImpl;
import jogamp.graph.curve.opengl.shader.UniformNames;
import com.jogamp.common.os.Platform;
import com.jogamp.graph.curve.Region;
import com.jogamp.graph.geom.Vertex;
+import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.PMVMatrix;
-import com.jogamp.opengl.util.glsl.ShaderState;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
-public abstract class RenderState {
+public class RenderState {
private static final String thisKey = "jogamp.graph.curve.RenderState" ;
/**
@@ -51,7 +53,7 @@ public abstract class RenderState {
* </p>
* <p>
* Due to alpha blending and multipass rendering, e.g. {@link Region#VBAA_RENDERING_BIT},
- * the clear-color shall be set to the {@link #getColorStatic() foreground color} and <i>zero alpha</i>,
+ * the clear-color shall be set to the {@link #getColorStaticUniform() foreground color} and <i>zero alpha</i>,
* otherwise blending will amplify the scene's clear-color.
* </p>
* <p>
@@ -62,37 +64,192 @@ public abstract class RenderState {
*/
public static final int BITHINT_BLENDING_ENABLED = 1 << 0 ;
- public static RenderState createRenderState(ShaderState st, Vertex.Factory<? extends Vertex> pointFactory) {
- return new RenderStateImpl(st, pointFactory, null);
+ public static RenderState createRenderState(Vertex.Factory<? extends Vertex> pointFactory) {
+ return new RenderState(pointFactory, null);
}
- public static RenderState createRenderState(ShaderState st, Vertex.Factory<? extends Vertex> pointFactory, PMVMatrix pmvMatrix) {
- return new RenderStateImpl(st, pointFactory, pmvMatrix);
+ public static RenderState createRenderState(Vertex.Factory<? extends Vertex> pointFactory, PMVMatrix pmvMatrix) {
+ return new RenderState(pointFactory, pmvMatrix);
}
public static final RenderState getRenderState(GL2ES2 gl) {
return (RenderState) gl.getContext().getAttachedObject(thisKey);
}
- protected final ShaderState st;
- protected final Vertex.Factory<? extends Vertex> vertexFactory;
- protected final PMVMatrix pmvMatrix;
- protected final GLUniformData gcu_PMVMatrix;
- protected int hintBitfield;
+ private final Vertex.Factory<? extends Vertex> vertexFactory;
+ private final PMVMatrix pmvMatrix;
+ private final GLUniformData gcu_PMVMatrix01;
+ private final GLUniformData gcu_Weight;
+ private final GLUniformData gcu_ColorStatic;
+ private boolean gcu_PMVMatrix01_dirty = true;
+ private boolean gcu_Weight_dirty = true;
+ private boolean gcu_ColorStatic_dirty = true;
+ private ShaderProgram sp;
+ private int hintBitfield;
- protected RenderState(ShaderState st, Vertex.Factory<? extends Vertex> vertexFactory, PMVMatrix pmvMatrix) {
- this.st = st;
+ protected RenderState(Vertex.Factory<? extends Vertex> vertexFactory, PMVMatrix pmvMatrix) {
+ this.sp = null;
this.vertexFactory = vertexFactory;
this.pmvMatrix = null != pmvMatrix ? pmvMatrix : new PMVMatrix();
- this.gcu_PMVMatrix = new GLUniformData(UniformNames.gcu_PMVMatrix, 4, 4, this.pmvMatrix.glGetPMvMatrixf());
- st.ownUniform(gcu_PMVMatrix);
+ this.gcu_PMVMatrix01 = new GLUniformData(UniformNames.gcu_PMVMatrix01, 4, 4, this.pmvMatrix.glGetPMvMatrixf());
+ this.gcu_Weight = new GLUniformData(UniformNames.gcu_Weight, 1.0f);
+ this.gcu_ColorStatic = new GLUniformData(UniformNames.gcu_ColorStatic, 4, FloatBuffer.allocate(4));
this.hintBitfield = 0;
}
- public final ShaderState getShaderState() { return st; }
+ public final ShaderProgram getShaderProgram() { return sp; }
+ public final boolean isShaderProgramInUse() { return null != sp ? sp.inUse() : false; }
+
+ /**
+ * Set a {@link ShaderProgram} and enable it. If the given {@link ShaderProgram} is new,
+ * method returns true, otherwise false.
+ * @param gl
+ * @param sp
+ * @return true if a new shader program is being used and hence external uniform-data and -location,
+ * as well as the attribute-location must be updated, otherwise false.
+ */
+ public final boolean setShaderProgram(final GL2ES2 gl, final ShaderProgram sp) {
+ if( sp.equals(this.sp) ) {
+ sp.useProgram(gl, true);
+ return false;
+ }
+ this.sp = sp;
+ sp.useProgram(gl, true);
+ return true;
+ }
+
public final Vertex.Factory<? extends Vertex> getVertexFactory() { return vertexFactory; }
- public final PMVMatrix pmvMatrix() { return pmvMatrix; }
- public final GLUniformData getPMVMatrix() { return gcu_PMVMatrix; }
+
+ public final PMVMatrix getMatrix() { return pmvMatrix; }
+ public final PMVMatrix getMatrixMutable() {
+ gcu_PMVMatrix01_dirty = true;
+ return pmvMatrix;
+ }
+ public final GLUniformData getMatrixUniform() { return gcu_PMVMatrix01; }
+ public final void setMatrixDirty() { gcu_PMVMatrix01_dirty = true; }
+ public final boolean isMatrixDirty() { return gcu_PMVMatrix01_dirty;}
+
+ public final void updateMatrix(GL2ES2 gl) {
+ if( gcu_PMVMatrix01_dirty && sp.inUse() ) {
+ gl.glUniform( gcu_PMVMatrix01 );
+ gcu_PMVMatrix01_dirty = false;
+ }
+ }
+
+ public static boolean isWeightValid(float v) {
+ return 0.0f <= v && v <= 1.9f ;
+ }
+ public final float getWeight() { return gcu_Weight.floatValue(); }
+ public final void setWeight(float v) {
+ if( !isWeightValid(v) ) {
+ throw new IllegalArgumentException("Weight out of range");
+ }
+ gcu_Weight_dirty = true;
+ gcu_Weight.setData(v);
+ }
+
+
+ public final float[] getColorStatic(float[] rgbaColor) {
+ FloatBuffer fb = (FloatBuffer) gcu_ColorStatic.getBuffer();
+ rgbaColor[0] = fb.get(0);
+ rgbaColor[1] = fb.get(1);
+ rgbaColor[2] = fb.get(2);
+ rgbaColor[3] = fb.get(3);
+ return rgbaColor;
+ }
+ public final void setColorStatic(float r, float g, float b, float a){
+ final FloatBuffer fb = (FloatBuffer) gcu_ColorStatic.getBuffer();
+ fb.put(0, r);
+ fb.put(1, g);
+ fb.put(2, b);
+ fb.put(3, a);
+ gcu_ColorStatic_dirty = true;
+ }
+
+
+ /**
+ *
+ * @param gl
+ * @param updateLocation
+ * @param renderModes
+ * @return true if no error occurred, i.e. all locations found, otherwise false.
+ */
+ public final boolean update(GL2ES2 gl, final boolean updateLocation, final int renderModes, final boolean pass1) {
+ boolean res = true;
+ if( null != sp && sp.inUse() ) {
+ if( ( !Region.isTwoPass(renderModes) || !pass1 ) && ( gcu_PMVMatrix01_dirty || updateLocation ) ) {
+ final boolean r0 = updateUniformDataLoc(gl, updateLocation, gcu_PMVMatrix01_dirty, gcu_PMVMatrix01);
+ System.err.println("XXX gcu_PMVMatrix01.update: "+r0);
+ res = res && r0;
+ gcu_PMVMatrix01_dirty = !r0;
+ }
+ if( pass1 ) {
+ if( Region.hasVariableWeight( renderModes ) && ( gcu_Weight_dirty || updateLocation ) ) {
+ final boolean r0 = updateUniformDataLoc(gl, updateLocation, gcu_Weight_dirty, gcu_Weight);
+ System.err.println("XXX gcu_Weight.update: "+r0);
+ res = res && r0;
+ gcu_Weight_dirty = !r0;
+ }
+ if( gcu_ColorStatic_dirty || updateLocation ) {
+ final boolean r0 = updateUniformDataLoc(gl, updateLocation, gcu_ColorStatic_dirty, gcu_ColorStatic);
+ System.err.println("XXX gcu_ColorStatic.update: "+r0);
+ res = res && r0;
+ gcu_ColorStatic_dirty = false;
+ }
+ }
+ }
+ return res;
+ }
+
+ /**
+ *
+ * @param gl
+ * @param updateLocation
+ * @param data
+ * @return true if no error occured, i.e. all locations found, otherwise false.
+ */
+ public final boolean updateUniformLoc(final GL2ES2 gl, final boolean updateLocation, final GLUniformData data) {
+ if( updateLocation || 0 > data.getLocation() ) {
+ return 0 <= data.setLocation(gl, sp.program());
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ *
+ * @param gl
+ * @param updateLocation
+ * @param updateData TODO
+ * @param data
+ * @return true if no error occured, i.e. all locations found, otherwise false.
+ */
+ public final boolean updateUniformDataLoc(final GL2ES2 gl, boolean updateLocation, boolean updateData, final GLUniformData data) {
+ updateLocation = updateLocation || 0 > data.getLocation();
+ if( updateLocation ) {
+ updateData = 0 <= data.setLocation(gl, sp.program());
+ }
+ if( updateData ){
+ gl.glUniform(data);
+ return true;
+ } else {
+ return !updateLocation;
+ }
+ }
+
+ /**
+ * @param gl
+ * @param data
+ * @return true if no error occured, i.e. all locations found, otherwise false.
+ */
+ public final boolean updateAttributeLoc(final GL2ES2 gl, final boolean updateLocation, final GLArrayDataServer data) {
+ if( updateLocation || 0 > data.getLocation() ) {
+ return 0 <= data.setLocation(gl, sp.program());
+ } else {
+ return true;
+ }
+ }
+
public final boolean isHintMaskSet(int mask) {
return mask == ( hintBitfield & mask );
@@ -105,14 +262,12 @@ public abstract class RenderState {
}
public void destroy(GL2ES2 gl) {
- st.destroy(gl);
+ if( null != sp ) {
+ sp.destroy(gl);
+ sp = null;
+ }
}
- public abstract GLUniformData getWeight();
- public abstract GLUniformData getAlpha();
- public abstract GLUniformData getColorStatic();
- // public abstract GLUniformData getStrength();
-
public final RenderState attachTo(GL2ES2 gl) {
return (RenderState) gl.getContext().attachObject(thisKey, this);
}
@@ -130,11 +285,12 @@ public abstract class RenderState {
if(null==sb) {
sb = new StringBuilder();
}
-
- sb.append("RenderState[");
- st.toString(sb, alsoUnlocated).append(Platform.getNewline());
- sb.append("]");
-
+ sb.append("RenderState[").append(sp).append(Platform.NEWLINE);
+ // pmvMatrix.toString(sb, "%.2f");
+ sb.append(", dirty[pmv "+gcu_PMVMatrix01_dirty+", color "+gcu_ColorStatic_dirty+", weight "+gcu_Weight_dirty+"], ").append(Platform.NEWLINE);
+ sb.append(gcu_PMVMatrix01).append(", ").append(Platform.NEWLINE);
+ sb.append(gcu_ColorStatic).append(", ");
+ sb.append(gcu_Weight).append("]");
return sb;
}
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 140e03cfb..6d9fdab0b 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
@@ -68,7 +68,7 @@ public class TextRegionUtil {
* additionally passing the progressed {@link AffineTransform}.
* The latter reflects the given font metric, pixelSize and hence character position.
* @param visitor
- * @param transform
+ * @param transform optional given transform
* @param font the target {@link Font}
* @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size.
* @param str string text
@@ -82,7 +82,7 @@ public class TextRegionUtil {
final float lineHeight = font.getLineHeight(pixelSize);
final float scale = metrics.getScale(pixelSize);
- final AffineTransform t = new AffineTransform(transform);
+ final AffineTransform t = null != transform ? new AffineTransform(transform) : new AffineTransform();
float y = 0;
float advanceTotal = 0;
@@ -98,7 +98,12 @@ public class TextRegionUtil {
if(Region.DEBUG_INSTANCE) {
System.err.println("XXXXXXXXXXXXXXx char: "+character+", scale: "+scale+"; translate: "+advanceTotal+", "+y);
}
- t.setTransform(transform); // reset transform
+ // reset transform
+ if( null != transform ) {
+ t.setTransform(transform);
+ } else {
+ t.setToIdentity();
+ }
t.translate(advanceTotal, y);
t.scale(scale, scale);
@@ -121,14 +126,15 @@ public class TextRegionUtil {
* @param font the target {@link Font}
* @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size.
* @param str string text
+ * @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
*/
public static void addStringToRegion(final GLRegion region, final Factory<? extends Vertex> vertexFactory,
- final Font font, final float pixelSize, final CharSequence str) {
+ final Font font, final float pixelSize, final CharSequence str, final float[] rgbaColor) {
final ShapeVisitor visitor = new ShapeVisitor() {
public final void visit(final OutlineShape shape, final AffineTransform t) {
- region.addOutlineShape(shape, t);
+ region.addOutlineShape(shape, t, region.hasColorChannel() ? rgbaColor : null);
} };
- processString(visitor, new AffineTransform(), font, pixelSize, str);
+ processString(visitor, null, font, pixelSize, str);
}
/**
@@ -141,13 +147,14 @@ public class TextRegionUtil {
* @param font {@link Font} to be used
* @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size.
* @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.
* @throws Exception if TextRenderer not initialized
*/
public void drawString3D(final GL2ES2 gl,
final Font font, final float pixelSize, final CharSequence str,
- final int[/*1*/] sampleCount) {
+ final float[] rgbaColor, final int[/*1*/] sampleCount) {
if( !renderer.isInitialized() ) {
throw new GLException("TextRendererImpl01: not initialized!");
}
@@ -155,7 +162,7 @@ public class TextRegionUtil {
GLRegion region = getCachedRegion(font, str, pixelSize, special);
if(null == region) {
region = GLRegion.create(renderer.getRenderModes());
- addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str);
+ addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str, rgbaColor);
addCachedRegion(gl, font, str, pixelSize, special, region);
}
region.draw(gl, renderer, sampleCount);
@@ -167,25 +174,26 @@ public class TextRegionUtil {
* <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(GLRegion, RegionRenderer, GL2ES2, Font, float, CharSequence, int[])}
+ * In such case better use {@link #drawString3D(GLRegion, RegionRenderer, GL2ES2, Font, float, CharSequence, float[], int[])}
* instead.
* </p>
* @param gl the current GL state
* @param font {@link Font} to be used
* @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size.
* @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.
* @throws Exception if TextRenderer not initialized
*/
public static void drawString3D(final RegionRenderer renderer, final GL2ES2 gl,
final Font font, final float pixelSize, final CharSequence str,
- final int[/*1*/] sampleCount) {
+ final float[] rgbaColor, final int[/*1*/] sampleCount) {
if(!renderer.isInitialized()){
throw new GLException("TextRendererImpl01: not initialized!");
}
final GLRegion region = GLRegion.create(renderer.getRenderModes());
- addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str);
+ addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str, rgbaColor);
region.draw(gl, renderer, sampleCount);
region.destroy(gl, renderer);
}
@@ -197,18 +205,19 @@ public class TextRegionUtil {
* @param font {@link Font} to be used
* @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size.
* @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.
* @throws Exception if TextRenderer not initialized
*/
public static void drawString3D(final GLRegion region, final RegionRenderer renderer, final GL2ES2 gl,
final Font font, final float pixelSize, final CharSequence str,
- final int[/*1*/] sampleCount) {
+ final float[] rgbaColor, final int[/*1*/] sampleCount) {
if(!renderer.isInitialized()){
throw new GLException("TextRendererImpl01: not initialized!");
}
region.clear(gl, renderer);
- addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str);
+ addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str, rgbaColor);
region.draw(gl, renderer, sampleCount);
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java b/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java
index 96ff4bbb8..20fe9bfd9 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java
@@ -64,8 +64,14 @@ public interface Triangulator {
*/
public void generate(List<Triangle> sink);
- /** Reset the triangulation to initial state
- * Clearing cached data
+ /**
+ * Reset the triangulation to initial state
+ * Clearing cached data
*/
public void reset();
+
+ /**
+ * Return the number of newly added vertices during {@link #addCurve(List, Outline, float)}.
+ */
+ public int getAddedVerticeCount();
}
diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java
index ac7a904e7..811ab9d94 100644
--- a/src/jogl/classes/com/jogamp/graph/font/Font.java
+++ b/src/jogl/classes/com/jogamp/graph/font/Font.java
@@ -27,7 +27,10 @@
*/
package com.jogamp.graph.font;
+import jogamp.graph.geom.plane.AffineTransform;
+
import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.TextRegionUtil.ShapeVisitor;
import com.jogamp.opengl.math.geom.AABBox;
/**
@@ -155,9 +158,26 @@ public interface Font {
public int getNumGlyphs();
public float getLineHeight(float pixelSize);
- public float getStringWidth(CharSequence string, float pixelSize);
- public float getStringHeight(CharSequence string, float pixelSize);
- public AABBox getStringBounds(CharSequence string, float pixelSize);
+ public float getMetricWidth(CharSequence string, float pixelSize);
+ public float getMetricHeight(CharSequence string, float pixelSize);
+ /**
+ * Return the <i>layout</i> bounding box as computed by each glyph's metrics.
+ * The result is not pixel correct, bit reflects layout specific metrics.
+ * <p>
+ * See {@link #getPointsBounds(AffineTransform, CharSequence, float)} for pixel correct results.
+ * </p>
+ * @param string string text
+ * @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size.
+ */
+ public AABBox getMetricBounds(CharSequence string, float pixelSize);
+
+ /**
+ * Return the bounding box by taking each glyph's point-based bounding box into account.
+ * @param transform optional given transform
+ * @param string string text
+ * @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size.
+ */
+ public AABBox getPointsBounds(final AffineTransform transform, CharSequence string, float pixelSize);
public boolean isPrintableChar( char c );