UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

180 lines (137 loc) 5.95 kB
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); }