@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
180 lines (137 loc) • 5.95 kB
JavaScript
import { GROUP_WITH_ANY } from "./constants/GROUP_WITH_ANY.js";
import { vec3 } from "gl-matrix";
import { GetPosition } from "./GetPosition.js";
import { GetTexCoord } from "./GetTexCoord.js";
import { ORIENT_PRESERVING } from "./constants/ORIENT_PRESERVING.js";
import { NotZero } from "./NotZero.js";
import { fabsf } from "../../../../core/math/fabsf.js";
import { MARK_DEGENERATE } from "./constants/MARK_DEGENERATE.js";
import { CalcTexArea } from "./CalcTexArea.js";
import { BuildNeighborsFast } from "./BuildNeighborsFast.js";
const t1 = vec3.create();
const t2 = vec3.create();
const t3 = vec3.create();
const d1 = vec3.create();
const d2 = vec3.create();
const vOs = vec3.create();
const vOt = vec3.create();
const v1 = vec3.create();
const v2 = vec3.create();
const v3 = vec3.create();
const v_temp_0 = vec3.create();
const v_temp_1 = vec3.create();
/**
*
* @param {STriInfo[]} pTriInfos
* @param {number[]|Int32Array} piTriListIn
* @param {SMikkTSpaceContext} pContext
* @param {number} iNrTrianglesIn
* @returns {void}
*/
export function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
let f = 0, i = 0, t = 0;
// pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function.
// generate neighbor info list
for (f = 0; f < iNrTrianglesIn; f++) {
const tri = pTriInfos[f];
for (i = 0; i < 3; i++) {
tri.FaceNeighbors[i] = -1;
tri.AssignedGroup[i] = null;
}
tri.vOs[0] = 0.0;
tri.vOs[1] = 0.0;
tri.vOs[2] = 0.0;
tri.vOt[0] = 0.0;
tri.vOt[1] = 0.0;
tri.vOt[2] = 0.0;
tri.fMagS = 0;
tri.fMagT = 0;
// assumed bad
tri.iFlag |= GROUP_WITH_ANY;
}
// evaluate first order derivatives
for (f = 0; f < iNrTrianglesIn; f++) {
// initial values
const f3 = f * 3;
GetPosition(v1, 0, pContext, piTriListIn[f3 + 0]);
GetPosition(v2, 0, pContext, piTriListIn[f3 + 1]);
GetPosition(v3, 0, pContext, piTriListIn[f3 + 2]);
GetTexCoord(t1, pContext, piTriListIn[f3 + 0]);
GetTexCoord(t2, pContext, piTriListIn[f3 + 1]);
GetTexCoord(t3, pContext, piTriListIn[f3 + 2]);
const t21x = t2[0] - t1[0];
const t21y = t2[1] - t1[1];
const t31x = t3[0] - t1[0];
const t31y = t3[1] - t1[1];
vec3.sub(d1, v2, v1);
vec3.sub(d2, v3, v1);
const fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
//assert(fSignedAreaSTx2!=0);
vec3.scale(v_temp_0, d1, t31y);
vec3.scale(v_temp_1, d2, t21y);
vec3.sub(vOs, v_temp_0, v_temp_1); // eq 18
vec3.scale(v_temp_0, d1, -t31x);
vec3.scale(v_temp_1, d2, t21x);
vec3.add(vOt, v_temp_0, v_temp_1); // eq 19
const tri_info = pTriInfos[f];
tri_info.iFlag |= (fSignedAreaSTx2 > 0 ? ORIENT_PRESERVING : 0);
if (NotZero(fSignedAreaSTx2)) {
const fAbsArea = fabsf(fSignedAreaSTx2);
const fLenOs = vec3.length(vOs);
const fLenOt = vec3.length(vOt);
const fS = (tri_info.iFlag & ORIENT_PRESERVING) === 0 ? (-1.0) : 1.0;
if (NotZero(fLenOs)) {
vec3.scale(tri_info.vOs, vOs, fS / fLenOs);
}
if (NotZero(fLenOt)) {
vec3.scale(tri_info.vOt, vOt, fS / fLenOt);
}
// evaluate magnitudes prior to normalization of vOs and vOt
tri_info.fMagS = fLenOs / fAbsArea;
tri_info.fMagT = fLenOt / fAbsArea;
// if this is a good triangle
if (NotZero(tri_info.fMagS) && NotZero(tri_info.fMagT)) {
tri_info.iFlag &= (~GROUP_WITH_ANY);
}
}
}
// force otherwise healthy quads to a fixed orientation
while (t < (iNrTrianglesIn - 1)) {
const tri_0 = pTriInfos[t];
const tri_1 = pTriInfos[t + 1];
const iFO_a = tri_0.iOrgFaceNumber;
const iFO_b = tri_1.iOrgFaceNumber;
if (iFO_a === iFO_b) {
// this is a quad
const bIsDeg_a = (tri_0.iFlag & MARK_DEGENERATE) !== 0;
const bIsDeg_b = (tri_1.iFlag & MARK_DEGENERATE) !== 0;
// bad triangles should already have been removed by
// DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false
if ((bIsDeg_a || bIsDeg_b) === false) {
const bOrientA = (tri_0.iFlag & ORIENT_PRESERVING) !== 0;
const bOrientB = (tri_1.iFlag & ORIENT_PRESERVING) !== 0;
// if this happens the quad has extremely bad mapping!!
if (bOrientA !== bOrientB) {
//printf("found quad with bad mapping\n");
let bChooseOrientFirstTri = false;
if ((tri_1.iFlag & GROUP_WITH_ANY) !== 0) {
bChooseOrientFirstTri = true;
} else if (CalcTexArea(pContext, piTriListIn, t * 3) >= CalcTexArea(pContext, piTriListIn, (t + 1) * 3 + 0)) {
bChooseOrientFirstTri = true;
}
// force match
const t0 = bChooseOrientFirstTri ? tri_0 : tri_1;
const t1 = bChooseOrientFirstTri ? tri_1 : tri_0;
t1.iFlag &= (~ORIENT_PRESERVING); // clear first
t1.iFlag |= (t0.iFlag & ORIENT_PRESERVING); // copy bit
}
}
t += 2;
} else {
++t;
}
}
// match up edge pairs
const pEdges = new Float32Array(iNrTrianglesIn * 3 * 3);
BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn);
}