/*
* Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.prism.impl;
import com.sun.javafx.geom.Vec3f;
TODO: 3D - Need documentation
Utility routines for dealing with mesh computation.
/**
* TODO: 3D - Need documentation
* Utility routines for dealing with mesh computation.
*/
class MeshVertex {
int smGroup;
int pVert; // vertexBuffer
int tVert; // vertexBuffer
int fIdx;
int index; // indexBuffer
Vec3f[] norm; // {N, T, B}
MeshVertex next = null;
static final int IDX_UNDEFINED = -1;
static final int IDX_SET_SMOOTH = -2;
static final int IDX_UNITE = -3;
MeshVertex() {
norm = new Vec3f[3];
for (int i = 0; i < norm.length; i++) {
norm[i] = new Vec3f();
}
}
static void avgSmNormals(MeshVertex v) {
Vec3f normalSum = MeshTempState.getInstance().vec3f1;
for (; v != null; v = v.next) {
if (v.index == IDX_UNDEFINED) {
normalSum.set(v.norm[0]);
int sm = v.smGroup;
for (MeshVertex i = v.next; i != null; i = i.next) {
if (i.smGroup == sm) {
assert (i.index == IDX_UNDEFINED);
i.index = IDX_SET_SMOOTH;
normalSum.add(i.norm[0]);
}
}
if (MeshUtil.isNormalOkAfterWeld(normalSum)) {
normalSum.normalize();
for (MeshVertex i = v; i != null; i = i.next) {
if (i.smGroup == sm) {
i.norm[0].set(normalSum);
}
}
}
}
}
}
static boolean okToWeldVertsTB(MeshVertex a, MeshVertex b) {
return a.tVert == b.tVert && MeshUtil.isTangentOk(a.norm, b.norm);
}
/*
* Weld points, assign new indexes and calculate new TB
* return current number of points (last index +1)
*/
static int weldWithTB(MeshVertex v, int index) {
Vec3f[] nSum = MeshTempState.getInstance().triNormals;
for (; v != null; v = v.next) {
if (v.index < 0) {
int nuLocal = 0;
for (int i = 0; i < 3; i++) {
nSum[i].set(v.norm[i]);
}
for (MeshVertex i = v.next; i != null; i = i.next) {
if (i.index < 0) {
if (okToWeldVertsTB(v, i)) {
i.index = IDX_UNITE;
nuLocal++;
for (int j = 0; j < 3; ++j) {
nSum[j].add(i.norm[j]);
}
}
}
}
if (nuLocal != 0) {
if (MeshUtil.isTangentOK(nSum)) {
MeshUtil.fixTSpace(nSum);
v.index = index;
for (int i = 0; i < 3; ++i) {
v.norm[i].set(nSum[i]);
}
for (MeshVertex i = v.next; i != null; i = i.next) {
if (i.index == IDX_UNITE) {
i.index = index;
i.norm[0].set(0, 0, 0);
}
}
} else {
// roll all back, unite failed
nuLocal = 0;
}
}
if (nuLocal == 0) {
// nothing to join, fix in-place
MeshUtil.fixTSpace(v.norm);
v.index = index;
}
index++;
}
}
return index;
}
static void mergeSmIndexes(MeshVertex n) {
for (MeshVertex l = n; l != null;) {
boolean change = false;
for (MeshVertex i = l.next; i != null; i = i.next) {
if (((l.smGroup & i.smGroup) != 0) && (l.smGroup != i.smGroup)) {
l.smGroup = i.smGroup | l.smGroup;
i.smGroup = l.smGroup;
change = true;
}
}
if (!change) {
l = l.next;
}
}
}
/*
* Check for normals in one smoothing group and remove points from the group
* if they are opposite looking in order to prevent a normal to be zero in
* one SM group. Opposite looking normals are normals which angle is more
* than 110 degrees.
*/
static void correctSmNormals(MeshVertex n) {
// remove opposite looking normals from one smoothing group
for (MeshVertex l = n; l != null; l = l.next) {
if (l.smGroup != 0) {
for (MeshVertex i = l.next; i != null; i = i.next) {
if (((i.smGroup & l.smGroup) != 0)
&& MeshUtil.isOppositeLookingNormals(i.norm, l.norm)) {
l.smGroup = 0;
i.smGroup = 0;
break;
}
}
}
}
}
static int processVertices(MeshVertex[] pVerts, int nVertex,
boolean allHardEdges, boolean allSameSmoothing) {
int nNewVerts = 0;
Vec3f normalSum = MeshTempState.getInstance().vec3f1;
for (int i = 0; i < nVertex; ++i) {
if (pVerts[i] != null) {
if (!allHardEdges) {
if (allSameSmoothing) {
// calculate average normal for one smoothing group
normalSum.set(pVerts[i].norm[0]);
for (MeshVertex v = pVerts[i].next; v != null; v = v.next) {
normalSum.add(v.norm[0]);
}
if (MeshUtil.isNormalOkAfterWeld(normalSum)) {
normalSum.normalize();
for (MeshVertex v = pVerts[i]; v != null; v = v.next) {
v.norm[0].set(normalSum);
}
}
} else {
// various Sm
mergeSmIndexes(pVerts[i]);
avgSmNormals(pVerts[i]);
}
}
// weld points based on texture and assign new indexes
nNewVerts = weldWithTB(pVerts[i], nNewVerts);
}
}
return nNewVerts;
}
@Override
public String toString() {
return "MeshVertex : " + getClass().getName()
+ "@0x" + Integer.toHexString(hashCode())
+ ":: smGroup = " + smGroup + "\n"
+ "\tnorm[0] = " + norm[0] + "\n"
+ "\tnorm[1] = " + norm[1] + "\n"
+ "\tnorm[2] = " + norm[2] + "\n"
+ "\ttIndex = " + tVert + ", fIndex = " + fIdx + "\n"
+ "\tpIdx = " + index + "\n"
+ "\tnext = " + ((next == null) ? next : next.getClass().getName()
+ "@0x" + Integer.toHexString(next.hashCode())) + "\n";
}
static void dumpInfo(MeshVertex v) {
System.err.println("** dumpInfo: ");
for (MeshVertex q = v; q != null; q = q.next) {
System.err.println(q);
}
System.err.println("***********************************");
}
}