int[] contourCounts = new int[1];
int currCoordIndex = 0, vertOffset = 0;
ArrayList<GeometryArray> triangData = new ArrayList<GeometryArray>();
Point3f q1 = new Point3f(), q2 = new Point3f(), q3 = new Point3f();
Vector3f n1 = new Vector3f(), n2 = new Vector3f();
numPoints = 0;
//Now loop thru each island, calling triangulator once per island.
//Combine triangle data for all islands together in one object.
NormalGenerator ng = new NormalGenerator();
for (i = 0; i < islandCounts.length; i++) {
contourCounts[0] = islandCounts[i].length;
numPoints += outVerts[i].length;
GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
gi.setCoordinates(outVerts[i]);
gi.setStripCounts(islandCounts[i]);
gi.setContourCounts(contourCounts);
ng.generateNormals(gi);
GeometryArray ga = gi.getGeometryArray(false, false, false);
vertOffset += ga.getVertexCount();
triangData.add(ga);
}
// Multiply by 2 since we create 2 faces of the font
// Second term is for side-faces along depth of the font
if (fontExtrusion == null)
vertCnt = vertOffset;
else{
if (fontExtrusion.shape == null)
vertCnt = vertOffset * 2 + numPoints *6;
else{
vertCnt = vertOffset * 2 + numPoints * 6 *
(fontExtrusion.pnts.length -1);
}
}
// XXXX: Should use IndexedTriangleArray to avoid
// duplication of vertices. To create triangles for
// side faces, every vertex is duplicated currently.
TriangleArray triAry = new TriangleArray(vertCnt,
GeometryArray.COORDINATES |
GeometryArray.NORMALS);
boolean flip_orient[] = new boolean[islandCounts.length];
boolean findOrient;
// last known non-degenerate normal
Vector3f goodNormal = new Vector3f();
for (j=0;j < islandCounts.length;j++) {
GeometryArray ga = triangData.get(j);
vertOffset = ga.getVertexCount();
findOrient = false;
//Create the triangle array
for (i= 0; i < vertOffset; i+= 3, currCoordIndex += 3){
//Get 3 points. Since triangle is known to be flat, normal
// must be same for all 3 points.
ga.getCoordinate(i, p1);
ga.getNormal(i, n1);
ga.getCoordinate(i+1, p2);
ga.getCoordinate(i+2, p3);
if (!findOrient) {
//Check here if triangles are wound incorrectly and need
//to be flipped.
if (!getNormal(p1,p2, p3, n2)) {
continue;
}
if (n2.z >= EPS) {
flip_orient[j] = false;
} else if (n2.z <= -EPS) {
flip_orient[j] = true;
} else {
continue;
}
findOrient = true;
}
if (flip_orient[j]){
//New Triangulator preserves contour orientation. If contour
//input is wound incorrectly, swap 2nd and 3rd points to
//sure all triangles are wound correctly for j3d.
q1.x = p2.x; q1.y = p2.y; q1.z = p2.z;
p2.x = p3.x; p2.y = p3.y; p2.z = p3.z;
p3.x = q1.x; p3.y = q1.y; p3.z = q1.z;
n1.x = -n1.x; n1.y = -n1.y; n1.z = -n1.z;
}
if (fontExtrusion != null) {
n2.x = -n1.x;n2.y = -n1.y;n2.z = -n1.z;
triAry.setCoordinate(currCoordIndex, p1);
triAry.setNormal(currCoordIndex, n2);
triAry.setCoordinate(currCoordIndex+1, p3);
triAry.setNormal(currCoordIndex+1, n2);
triAry.setCoordinate(currCoordIndex+2, p2);
triAry.setNormal(currCoordIndex+2, n2);
q1.x = p1.x; q1.y = p1.y; q1.z = p1.z + fontExtrusion.length;
q2.x = p2.x; q2.y = p2.y; q2.z = p2.z + fontExtrusion.length;
q3.x = p3.x; q3.y = p3.y; q3.z = p3.z + fontExtrusion.length;
triAry.setCoordinate(currCoordIndex+vertOffset, q1);
triAry.setNormal(currCoordIndex+vertOffset, n1);
triAry.setCoordinate(currCoordIndex+1+vertOffset, q2);
triAry.setNormal(currCoordIndex+1+vertOffset, n1);
triAry.setCoordinate(currCoordIndex+2+vertOffset, q3);
triAry.setNormal(currCoordIndex+2+vertOffset, n1);
} else {
triAry.setCoordinate(currCoordIndex, p1);
triAry.setNormal(currCoordIndex, n1);
triAry.setCoordinate(currCoordIndex+1, p2);
triAry.setNormal(currCoordIndex+1, n1);
triAry.setCoordinate(currCoordIndex+2, p3);
triAry.setNormal(currCoordIndex+2, n1);
}
}
if (fontExtrusion != null) {
currCoordIndex += vertOffset;
}
}
//Now add side triangles in both cases.
// Since we duplicated triangles with different Z, make sure
// currCoordIndex points to correct location.
if (fontExtrusion != null){
if (fontExtrusion.shape == null){
boolean smooth;
// we'll put a crease if the angle between the normals is
// greater than 44 degrees
float threshold = (float) Math.cos(44.0*Math.PI/180.0);
float cosine;
// need the previous normals to check for smoothing
Vector3f pn1 = null, pn2 = null;
// need the next normals to check for smoothing
Vector3f n3 = new Vector3f(), n4 = new Vector3f();
// store the normals for each point because they are
// the same for both triangles
Vector3f p1Normal = new Vector3f();
Vector3f p2Normal = new Vector3f();
Vector3f p3Normal = new Vector3f();
Vector3f q1Normal = new Vector3f();
Vector3f q2Normal = new Vector3f();
Vector3f q3Normal = new Vector3f();
for (i=0;i < islandCounts.length;i++){
for (j=0, k=0, num =0;j < islandCounts[i].length;j++){
num += islandCounts[i][j];
p1.x = outVerts[i][num - 1].x;
p1.y = outVerts[i][num - 1].y;
p1.z = 0.0f;
q1.x = p1.x; q1.y = p1.y; q1.z = p1.z+fontExtrusion.length;
p2.z = 0.0f;
q2.z = p2.z+fontExtrusion.length;
for (int m=0; m < num;m++) {
p2.x = outVerts[i][m].x;
p2.y = outVerts[i][m].y;
q2.x = p2.x;
q2.y = p2.y;
if (getNormal(p1, q1, p2, n1)) {
if (!flip_side_orient) {
n1.negate();
}
goodNormal.set(n1);
break;
}
}
for (;k < num;k++){
p2.x = outVerts[i][k].x;p2.y = outVerts[i][k].y;p2.z = 0.0f;
q2.x = p2.x; q2.y = p2.y; q2.z = p2.z+fontExtrusion.length;
if (!getNormal(p1, q1, p2, n1)) {
n1.set(goodNormal);
} else {
if (!flip_side_orient) {
n1.negate();
}
goodNormal.set(n1);
}
if (!getNormal(p2, q1, q2, n2)) {
n2.set(goodNormal);
} else {
if (!flip_side_orient) {
n2.negate();
}
goodNormal.set(n2);
}
// if there is a previous normal, see if we need to smooth
// this normal or make a crease
if (pn1 != null) {
cosine = n1.dot(pn2);
smooth = cosine > threshold;
if (smooth) {
p1Normal.x = (pn1.x + pn2.x + n1.x);
p1Normal.y = (pn1.y + pn2.y + n1.y);
p1Normal.z = (pn1.z + pn2.z + n1.z);
normalize(p1Normal);
q1Normal.x = (pn2.x + n1.x + n2.x);
q1Normal.y = (pn2.y + n1.y + n2.y);
q1Normal.z = (pn2.z + n1.z + n2.z);
normalize(q1Normal);
} // if smooth
else {
p1Normal.x = n1.x; p1Normal.y = n1.y; p1Normal.z = n1.z;
q1Normal.x = n1.x+n2.x;
q1Normal.y = n1.y+n2.y;
q1Normal.z = n1.z+ n2.z;
normalize(q1Normal);
} // else
} // if pn1 != null
else {
pn1 = new Vector3f();
pn2 = new Vector3f();
p1Normal.x = n1.x;
p1Normal.y = n1.y;
p1Normal.z = n1.z;
q1Normal.x = (n1.x + n2.x);
q1Normal.y = (n1.y + n2.y);
q1Normal.z = (n1.z + n2.z);
normalize(q1Normal);
} // else
// if there is a next, check if we should smooth normal
if (k+1 < num) {
p3.x = outVerts[i][k+1].x; p3.y = outVerts[i][k+1].y;
p3.z = 0.0f;
q3.x = p3.x; q3.y = p3.y; q3.z = p3.z + fontExtrusion.length;
if (!getNormal(p2, q2, p3, n3)) {
n3.set(goodNormal);
} else {
if (!flip_side_orient) {
n3.negate();
}
goodNormal.set(n3);
}
if (!getNormal(p3, q2, q3, n4)) {
n4.set(goodNormal);
} else {
if (!flip_side_orient) {
n4.negate();
}
goodNormal.set(n4);
}
cosine = n2.dot(n3);
smooth = cosine > threshold;
if (smooth) {
p2Normal.x = (n1.x + n2.x + n3.x);
p2Normal.y = (n1.y + n2.y + n3.y);
p2Normal.z = (n1.z + n2.z + n3.z);
normalize(p2Normal);
q2Normal.x = (n2.x + n3.x + n4.x);
q2Normal.y = (n2.y + n3.y + n4.y);
q2Normal.z = (n2.z + n3.z + n4.z);
normalize(q2Normal);
} else { // if smooth
p2Normal.x = n1.x + n2.x;
p2Normal.y = n1.y + n2.y;
p2Normal.z = n1.z + n2.z;
normalize(p2Normal);
q2Normal.x = n2.x; q2Normal.y = n2.y; q2Normal.z = n2.z;
} // else
} else { // if k+1 < num
p2Normal.x = (n1.x + n2.x);
p2Normal.y = (n1.y + n2.y);
p2Normal.z = (n1.z + n2.z);
normalize(p2Normal);
q2Normal.x = n2.x;
q2Normal.y = n2.y;
q2Normal.z = n2.z;
} // else
// add pts for the 2 tris
// p1, q1, p2 and p2, q1, q2
if (flip_side_orient) {
triAry.setCoordinate(currCoordIndex, p1);
triAry.setNormal(currCoordIndex, p1Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, q1);
triAry.setNormal(currCoordIndex, q1Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, p2);
triAry.setNormal(currCoordIndex, p2Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, p2);
triAry.setNormal(currCoordIndex, p2Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, q1);
triAry.setNormal(currCoordIndex, q1Normal);
currCoordIndex++;
} else {
triAry.setCoordinate(currCoordIndex, q1);
triAry.setNormal(currCoordIndex, q1Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, p1);
triAry.setNormal(currCoordIndex, p1Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, p2);
triAry.setNormal(currCoordIndex, p2Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, q1);
triAry.setNormal(currCoordIndex, q1Normal);
currCoordIndex++;
triAry.setCoordinate(currCoordIndex, p2);
triAry.setNormal(currCoordIndex, p2Normal);
currCoordIndex++;
}
triAry.setCoordinate(currCoordIndex, q2);
triAry.setNormal(currCoordIndex, q2Normal);
currCoordIndex++;
pn1.x = n1.x; pn1.y = n1.y; pn1.z = n1.z;
pn2.x = n2.x; pn2.y = n2.y; pn2.z = n2.z;
p1.x = p2.x; p1.y = p2.y; p1.z = p2.z;
q1.x = q2.x; q1.y = q2.y; q1.z = q2.z;
}// for k
// set the previous normals to null when we are done
pn1 = null;
pn2 = null;
}// for j
}//for i
} else { // if shape
int m, offset=0;
Point3f P2 = new Point3f(), Q2 = new Point3f(), P1=new Point3f();
Vector3f nn = new Vector3f(), nn1= new Vector3f(),
nn2= new Vector3f(), nn3= new Vector3f();
Vector3f nna = new Vector3f(), nnb=new Vector3f();
float length;
boolean validNormal = false;
// fontExtrusion.shape is specified, and is NOT straight line
for (i=0;i < islandCounts.length;i++){