@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
221 lines (173 loc) • 5.66 kB
JavaScript
import { QUAD_ONE_DEGEN_TRI } from "./constants/QUAD_ONE_DEGEN_TRI.js";
import { vec3 } from "gl-matrix";
import { GetPosition } from "./GetPosition.js";
import { MakeIndex } from "./MakeIndex.js";
import { assert } from "../../../../core/assert.js";
/**
* @type {vec3}
*/
const vDstP = vec3.create();
const vSrcP = vec3.create();
class VertReverseLookupContext {
/**
*
* @type {boolean}
*/
bIsInitialized = false;
/**
* int*
* @type {Int32Array|null}
*/
pLookup = null;
/**
* int
* @type {number}
*/
iMaxVertIndex = 0;
}
/**
*
* @param {number[]} piTriListIn
* @param {number} iNrTrianglesIn
* @param {VertReverseLookupContext} pLookupCtx
*/
function GenerateReverseLookup(
piTriListIn,
iNrTrianglesIn,
pLookupCtx
) {
let t;
// Figure out what size of lookup array we need.
pLookupCtx.iMaxVertIndex = -1;
for (t = 0; t < 3 * iNrTrianglesIn; t++) {
const iVertIndex = piTriListIn[t];
if (iVertIndex > pLookupCtx.iMaxVertIndex) {
pLookupCtx.iMaxVertIndex = iVertIndex;
}
}
// Allocate memory.
if (pLookupCtx.iMaxVertIndex < 1) {
// Nothing to allocate, all triangles are degenerate.
return;
}
pLookupCtx.pLookup = new Int32Array(pLookupCtx.iMaxVertIndex + 1);
// Fill in lookup.
for (t = 0; t <= pLookupCtx.iMaxVertIndex; t++) {
pLookupCtx.pLookup[t] = -1;
}
for (t = 0; t < 3 * iNrTrianglesIn; t++) {
const iVertIndex = piTriListIn[t];
if (pLookupCtx.pLookup[iVertIndex] !== -1) {
continue;
}
pLookupCtx.pLookup[iVertIndex] = t;
}
}
/**
*
* @param {VertReverseLookupContext} pLookupCtx
* @param {number[]} piTriListIn
* @param {number} iNrTrianglesIn
* @param {number} iVertexIndex
* @returns {number}
*/
function LookupVertexIndexFromGoodTriangle(
pLookupCtx,
piTriListIn,
iNrTrianglesIn,
iVertexIndex
) {
// Allocate lookup on demand.
if (!pLookupCtx.bIsInitialized) {
GenerateReverseLookup(piTriListIn, iNrTrianglesIn, pLookupCtx);
pLookupCtx.bIsInitialized = true;
}
// Make sure vertex index is in the mapping.
if (iVertexIndex > pLookupCtx.iMaxVertIndex) {
return -1;
}
if (pLookupCtx.pLookup === null) {
return -1;
}
// Perform actual lookup.
return pLookupCtx.pLookup[iVertexIndex];
}
/**
*
* @param {STSpace[]} psTspace
* @param {STriInfo[]} pTriInfos
* @param {number[]|Int32Array} piTriListIn
* @param {SMikkTSpaceContext} pContext
* @param {number} iNrTrianglesIn
* @param {number} iTotTris
* @returns {void}
*/
export function DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris) {
// deal with degenerate triangles
// punishment for degenerate triangles is O(N^2)
const lookupCtx = new VertReverseLookupContext();
for (let t = iNrTrianglesIn; t < iTotTris; t++) {
const tri0 = pTriInfos[t];
// degenerate triangles on a quad with one good triangle are skipped
// here but processed in the next loop
const bSkip = (tri0.iFlag & QUAD_ONE_DEGEN_TRI) !== 0;
if (bSkip) {
continue;
}
for (let i = 0; i < 3; i++) {
const index1 = piTriListIn[t * 3 + i];
const j = LookupVertexIndexFromGoodTriangle(lookupCtx, piTriListIn, iNrTrianglesIn, index1);
if (j < 0) {
// Matching vertex from good triangle is not found.
continue;
}
const iTri = Math.floor(j / 3);
const iVert = j % 3;
const tri1 = pTriInfos[iTri];
const iSrcVert = tri1.vert_num[iVert];
const iSrcOffs = tri1.iTSpacesOffs;
const iDstVert = tri0.vert_num[i];
const iDstOffs = tri0.iTSpacesOffs;
// copy tspace
const dst_tspace = psTspace[iDstOffs + iDstVert];
const src_tspace = psTspace[iSrcOffs + iSrcVert];
dst_tspace.copy(src_tspace);
}
}
// deal with degenerate quads with one good triangle
for (let t = 0; t < iNrTrianglesIn; t++) {
// this triangle belongs to a quad where the
// other triangle is degenerate
const tri = pTriInfos[t];
if ((tri.iFlag & QUAD_ONE_DEGEN_TRI) === 0) {
continue;
}
const pV = tri.vert_num;
const iFlag = (1 << pV[0]) | (1 << pV[1]) | (1 << pV[2]);
let iMissingIndex = 0;
if ((iFlag & 2) === 0) {
iMissingIndex = 1;
} else if ((iFlag & 4) === 0) {
iMissingIndex = 2;
} else if ((iFlag & 8) === 0) {
iMissingIndex = 3;
}
const iOrgF = tri.iOrgFaceNumber;
GetPosition(vDstP, 0, pContext, MakeIndex(iOrgF, iMissingIndex));
let bNotFound = true;
let i = 0;
while (i < 3) {
const iVert = pV[i];
GetPosition(vSrcP, 0, pContext, MakeIndex(iOrgF, iVert));
if (vec3.exactEquals(vSrcP, vDstP)) {
const iOffs = tri.iTSpacesOffs;
psTspace[iOffs + iMissingIndex].copy(psTspace[iOffs + iVert]);
bNotFound = false;
break;
} else {
++i;
}
}
assert(!bNotFound);
}
}