/**
* Copyright 2014 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
package jogamp.graph.curve.tess;
import com.jogamp.graph.geom.Triangle;
import com.jogamp.graph.geom.Vertex;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.VectorUtil;
/**
* Experimental Add-On ..
*
* Disabled by default
*/
public class CDTriangulator2DExpAddOn {
private final float[] tempV3a = new float[3];
private final float[] tempV3b = new float[3];
protected final void markLineInTriangle(final Triangle tri1, final float[] tempV2) {
if( !tri1.isOnCurve() || !tri1.isLine() ) {
return;
}
final boolean[] boundVs = tri1.getVerticesBoundary();
final Vertex[] triVs = tri1.getVertices();
final Vertex v0 = triVs[0];
final Vertex v1 = triVs[1];
final Vertex v2 = triVs[2];
int lineSegCount = 0;
final boolean v0IsLS, v1IsLS, v2IsLS;
if( v0.isOnCurve() && VectorUtil.isVec2Zero(v0.getTexCoord(), 0) && !boundVs[0] ) {
v0IsLS = true;
lineSegCount++;
} else {
v0IsLS = false;
}
if( v1.isOnCurve() && VectorUtil.isVec2Zero(v1.getTexCoord(), 0) && !boundVs[1] ) {
v1IsLS = true;
lineSegCount++;
} else {
v1IsLS = false;
}
if( v2.isOnCurve() && VectorUtil.isVec2Zero(v2.getTexCoord(), 0) && !boundVs[2] ) {
v2IsLS = true;
lineSegCount++;
} else {
v2IsLS = false;
}
if( 2 > lineSegCount ) {
return;
} else {
if(CDTriangulator2D.DEBUG) {
System.err.println("CDTri.markLine.1: "+tri1);
System.err.println("CDTri.markLine.1: count "+lineSegCount+", v0IsLS "+v0IsLS+", v1IsLS "+v1IsLS+", v2IsLS "+v2IsLS);
}
final float texZTag = 2f;
if( true ) {
if( v0IsLS ) {
v0.setTexCoord(0f, 0f, texZTag);
}
if( v1IsLS ) {
v1.setTexCoord(0f, 0f, texZTag);
}
if( v2IsLS ) {
v2.setTexCoord(0f, 0f, texZTag);
}
} else {
if( v0IsLS ) {
final Vertex v = v0.clone();
v.setTexCoord(0f, 0f, texZTag);
triVs[0] = v;
}
if( v1IsLS ) {
final Vertex v = v1.clone();
v.setTexCoord(0f, 0f, texZTag);
triVs[1] = v;
}
if( v2IsLS ) {
final Vertex v = v2.clone();
v.setTexCoord(0f, 0f, texZTag);
triVs[2] = v;
}
}
if ( false ) {
final Vertex vL1, vL2, vL3, vO;
if( 3 == lineSegCount ) {
vL1 = v0; vL2=v1; vL3=v2; vO=null;
} else if( v0IsLS && v1IsLS ) {
vL1 = v0; vL2=v1; vL3=null; vO=v2;
} else if( v0IsLS && v2IsLS ) {
vL1 = v0; vL2=v2; vL3=null; vO=v1;
} else if( v1IsLS && v2IsLS ) {
vL1 = v1; vL2=v2; vL3=null; vO=v0;
} else {
return; // unreachable
}
if( null != vL1 ) {
vL1.setTexCoord(texZTag, 0f, 0f);
}
if( null != vL2 ) {
vL2.setTexCoord(texZTag, 0f, 0f);
}
if( null != vL3 ) {
vL3.setTexCoord(texZTag, 0f, 0f);
}
}
}
}
/**
* If this and the other triangle compose a rectangle return the
* given <code>tempV2</code> array w/ shortest side first.
* Otherwise return null;
* <p>
* Experimental CODE, enabled only if {@link #TEST_LINE_AA} is set .. WIP
* </p>
* <p>
One test uses method: ROESSLER-2012-OGLES <http://www.cg.tuwien.ac.at/research/publications/2012/ROESSLER-2012-OGLES/>
* </p>
* <p>
* However, we would need to tesselate all lines appropriately,
* i.e. create 2 triangles sharing the middle actual line using thickness+radius.
*
* This test simply used our default font w/ a line thickness of 2 pixels,
* which produced mentioned rectangles.
* This is of course not the case for arbitrary Outline shapes.
* </p>
* @param tri2
* @param checkThisOnCurve
* @param tempV2 temp float[2] storage
*/
protected final float[] processLineAA(final int i, final Triangle tri1, final Triangle tri2, final float[] tempV2) {
if(CDTriangulator2D.DEBUG){
System.err.println("CDTri.genP2["+i+"].1: ? t1 "+tri1);
System.err.println("CDTri.genP2["+i+"].1: ? t2 "+tri2);
}
final float[] rect = processLineAAImpl(tri1, tri2, tempV2);
if(CDTriangulator2D.DEBUG){
if( null != rect ) {
System.err.println("CDTri.genP2["+i+"].1: RECT ["+rect[0]+", "+rect[1]+"]");
System.err.println("CDTri.genP2["+i+"].1: RECT t1 "+tri1);
System.err.println("CDTri.genP2["+i+"].1: RECT t2 "+tri2);
} else {
System.err.println("CDTri.genP2["+i+"].1: RECT NOPE, t1 "+tri1);
System.err.println("CDTri.genP2["+i+"].1: RECT NOPE, t2 "+tri2);
}
}
return rect;
}
private final float[] processLineAAImpl(final Triangle tri1, final Triangle tri2, final float[] tempV2) {
if( !tri1.isOnCurve() || !tri2.isOnCurve() || !tri1.isLine() || !tri2.isLine() ) {
return null;
}
final float[] rect;
int eqCount = 0;
final int[] commonIdxA = { -1, -1 };
final int[] commonIdxB = { -1, -1 };
final Vertex[] verts1 = tri1.getVertices();
final Vertex[] verts2 = tri2.getVertices();
float[] coord = verts1[0].getCoord();
if( VectorUtil.isVec3Equal(coord, 0, verts2[0].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 0;
commonIdxB[eqCount] = 0;
eqCount++;
} else if( VectorUtil.isVec3Equal(coord, 0, verts2[1].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 0;
commonIdxB[eqCount] = 1;
eqCount++;
} else if( VectorUtil.isVec3Equal(coord, 0, verts2[2].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 0;
commonIdxB[eqCount] = 2;
eqCount++;
}
coord = verts1[1].getCoord();
if( VectorUtil.isVec3Equal(coord, 0, verts2[0].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 1;
commonIdxB[eqCount] = 0;
eqCount++;
} else if( VectorUtil.isVec3Equal(coord, 0, verts2[1].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 1;
commonIdxB[eqCount] = 1;
eqCount++;
} else if( VectorUtil.isVec3Equal(coord, 0, verts2[2].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 1;
commonIdxB[eqCount] = 2;
eqCount++;
}
final int otherIdxA;
if( 2 == eqCount ) {
otherIdxA = 3 - ( commonIdxA[0] + commonIdxA[1] );
} else {
coord = verts1[2].getCoord();
if( VectorUtil.isVec3Equal(coord, 0, verts2[0].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 2;
commonIdxB[eqCount] = 0;
eqCount++;
} else if( VectorUtil.isVec3Equal(coord, 0, verts2[1].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 2;
commonIdxB[eqCount] = 1;
eqCount++;
} else if( VectorUtil.isVec3Equal(coord, 0, verts2[2].getCoord(), 0, FloatUtil.EPSILON) ) {
commonIdxA[eqCount] = 2;
commonIdxB[eqCount] = 2;
eqCount++;
}
if( 2 == eqCount ) {
otherIdxA = 3 - ( commonIdxA[0] + commonIdxA[1] );
} else {
otherIdxA = -1;
}
}
if( 0 <= otherIdxA && commonIdxB[0] != commonIdxB[1] ) {
final int otherIdxB = 3 - ( commonIdxB[0] + commonIdxB[1] );
// Reference must be equal, i.e. sharing the actual same vertices!
if( verts1[commonIdxA[0]] != verts2[commonIdxB[0]] || verts1[commonIdxA[1]] != verts2[commonIdxB[1]] ) {
throw new InternalError("XXX: diff shared verts"); // FIXME remove when clear
}
final Vertex vC0A, vC1A, vOA, vOB;
if( false ) {
// Fetch only!
vC0A = verts1[commonIdxA[0]];
vC1A = verts1[commonIdxA[1]];
vOA = verts1[otherIdxA];
vOB = verts2[otherIdxB];
} else {
// Fetch and clone, write-back to triangles
vC0A = verts1[commonIdxA[0]].clone();
verts1[commonIdxA[0]] = vC0A;
verts2[commonIdxB[0]] = vC0A;
vC1A = verts1[commonIdxA[1]].clone();
verts1[commonIdxA[1]] = vC1A;
verts2[commonIdxB[1]] = vC1A;
vOA = verts1[otherIdxA].clone();
verts1[otherIdxA] = vOA;
vOB = verts2[otherIdxB].clone();
verts2[otherIdxB] = vOB;
}
final float texZTag = 2f;
final float[] vOACoords = vOA.getCoord();
final float dOC0A = VectorUtil.distVec3(vOACoords, vC0A.getCoord());
final float dOC1A = VectorUtil.distVec3(vOACoords, vC1A.getCoord());
if( false ) {
final float[] vec3Z = { 0f, 0f, -1f };
final float[] vecLongSide, vecLineHeight;
if( dOC0A < dOC1A ) {
tempV2[0] = dOC0A; // line width
tempV2[1] = dOC1A; // long side
vecLongSide = VectorUtil.normalizeVec3( VectorUtil.subVec2(tempV3a, vOACoords, vC1A.getCoord()) ); // normal long side vector
vecLineHeight = VectorUtil.crossVec3(tempV3b, vec3Z, tempV3a); // the line-height vector (normal)
vOA.setTexCoord(-1f, -1f, texZTag);
vC1A.setTexCoord(1f, -1f, texZTag);
vOB.setTexCoord(0f, 1f, texZTag);
vC0A.setTexCoord(0f, 1f, texZTag);
} else {
tempV2[0] = dOC1A; // line width
tempV2[1] = dOC0A; // long side
vecLongSide = VectorUtil.normalizeVec3( VectorUtil.subVec2(tempV3a, vOACoords, vC0A.getCoord()) ); // normal long side vector
vecLineHeight = VectorUtil.crossVec3(tempV3b, vec3Z, tempV3a); // the line-height vector (normal)
}
if(CDTriangulator2D.DEBUG){
System.err.println("RECT.0 : long-side-vec "+vecLongSide[0]+", "+vecLongSide[1]+", "+vecLongSide[2]);
System.err.println("RECT.0 : line-height-vec "+vecLineHeight[0]+", "+vecLineHeight[1]+", "+vecLineHeight[2]);
}
} else {
/**
* Using method: ROESSLER-2012-OGLES <http://www.cg.tuwien.ac.at/research/publications/2012/ROESSLER-2012-OGLES/>
*
* Arbitrary but consistently pick left/right and set texCoords, FIXME: validate
*
* Testing w/ fixed line-width 1, and radius 1/3.
*/
final float lineWidth;
final Vertex vL1, vL2, vR1, vR2;
if( dOC0A < dOC1A ) {
lineWidth = dOC0A; // line width
tempV2[0] = dOC0A; // line width
tempV2[1] = dOC1A; // long side
// Left: vOA, vC1A
// Right: vOB, vC0A
vL1 = vOA; vL2 = vC1A;
vR1 = vOB; vR2 = vC0A;
} else {
lineWidth = dOC1A; // line width
tempV2[0] = dOC1A; // line width
tempV2[1] = dOC0A; // long side
// Left: vOB, vC1A
// Right: vOA, vC0A
vL1 = vOB; vL2 = vC1A;
vR1 = vOA; vR2 = vC0A;
}
final float r = lineWidth/3f;
final float wa = lineWidth + r;
final float waHalf = wa / 2f;
vL1.setTexCoord(lineWidth, waHalf, texZTag);
vL2.setTexCoord(lineWidth, waHalf, texZTag);
vR1.setTexCoord(lineWidth, -waHalf, texZTag);
vR2.setTexCoord(lineWidth, -waHalf, texZTag);
if(CDTriangulator2D.DEBUG){
System.err.println("RECT.0 : lineWidth: "+lineWidth+", dim "+dOC0A+" x "+dOC1A+", radius "+r);
System.err.println("RECT Left.0: "+vL1+", "+vL2);
System.err.println("RECT Right.0: "+vR1+", "+vR2);
}
}
rect = tempV2;
} else {
rect = null;
}
return rect;
}
}