@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
227 lines (169 loc) • 6.98 kB
JavaScript
import { malloc } from "./malloc.js";
import { STSpace } from "./STSpace.js";
import { SSubGroup } from "./SSubGroup.js";
import { vec3 } from "gl-matrix";
import { assert } from "../../../../core/assert.js";
import { GetNormal } from "./GetNormal.js";
import { GROUP_WITH_ANY } from "./constants/GROUP_WITH_ANY.js";
import { INTERNAL_RND_SORT_SEED } from "./constants/INTERNAL_RND_SORT_SEED.js";
import { QuickSort } from "./QuickSort.js";
import { CompareSubGroups } from "./CompareSubGroups.js";
import { array_copy } from "../../../../core/collection/array/array_copy.js";
import { EvalTspace } from "./EvalTspace.js";
import { ORIENT_PRESERVING } from "./constants/ORIENT_PRESERVING.js";
import { AvgTSpace } from "./AvgTSpace.js";
import { v3_scale_dot_sub_normalize } from "./v3_scale_dot_sub_normalize.js";
const vOs = vec3.create();
const vOt = vec3.create();
const vOs2 = vec3.create();
const vOt2 = vec3.create();
/**
* @type {vec3}
*/
const n = vec3.create();
/**
* @type {SSubGroup}
*/
const tmp_group = new SSubGroup();
/**
*
* @param {STSpace[]} psTspace
* @param {STriInfo[]} pTriInfos
* @param {SGroup[]} pGroups
* @param {number} iNrActiveGroups
* @param {number[]|Int32Array} piTriListIn
* @param {number} fThresCos
* @param {SMikkTSpaceContext} pContext
*/
export function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriListIn, fThresCos, pContext) {
let iMaxNrFaces = 0, iUniqueTspaces = 0;
for (let g = 0; g < iNrActiveGroups; g++) {
const sGroup = pGroups[g];
if (iMaxNrFaces < sGroup.iNrFaces) {
iMaxNrFaces = sGroup.iNrFaces;
}
}
if (iMaxNrFaces === 0) {
// no faces, nothing to do
return;
}
// make initial allocations
/**
* @type {STSpace[]}
*/
const pSubGroupTspace = malloc(STSpace, iMaxNrFaces);
/**
*
* @type {SSubGroup[]}
*/
const pUniSubGroups = malloc(SSubGroup, iMaxNrFaces);
/**
*
* @type {Int32Array|null}
*/
const pTmpMembers = new Int32Array(iMaxNrFaces);
iUniqueTspaces = 0;
for (let g = 0; g < iNrActiveGroups; g++) {
const pGroup = pGroups[g];
let iUniqueSubGroups = 0;
for (let i = 0; i < pGroup.iNrFaces; i++) {
// triangles
const f = pGroup.pFaceIndices[i]; // triangle number
let bFound = false;
const tri_info = pTriInfos[f];
let index = -1;
if (tri_info.AssignedGroup[0] === pGroup) {
index = 0;
} else if (tri_info.AssignedGroup[1] === pGroup) {
index = 1;
} else if (tri_info.AssignedGroup[2] === pGroup) {
index = 2;
}
assert(index >= 0 && index < 3);
const iVertIndex = piTriListIn[f * 3 + index];
assert.equal(iVertIndex, pGroup.iVertexRepresentitive);
// is normalized already
GetNormal(n, pContext, iVertIndex);
// project
v3_scale_dot_sub_normalize(vOs, n, tri_info.vOs);
v3_scale_dot_sub_normalize(vOt, n, tri_info.vOt);
// original face number
const iOF_1 = tri_info.iOrgFaceNumber;
let iMembers = 0;
for (let j = 0; j < pGroup.iNrFaces; j++) {
const t = pGroup.pFaceIndices[j]; // triangle number
const iOF_2 = pTriInfos[t].iOrgFaceNumber;
// project
v3_scale_dot_sub_normalize(vOs2, n, pTriInfos[t].vOs);
v3_scale_dot_sub_normalize(vOt2, n, pTriInfos[t].vOt);
const bAny = ((tri_info.iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY) !== 0;
// make sure triangles which belong to the same quad are joined.
const bSameOrgFace = iOF_1 === iOF_2;
const fCosS = vec3.dot(vOs, vOs2);
const fCosT = vec3.dot(vOt, vOt2);
assert(f !== t || bSameOrgFace); // sanity check
if (bAny || bSameOrgFace || (fCosS > fThresCos && fCosT > fThresCos)) {
pTmpMembers[iMembers++] = t;
}
}
// sort pTmpMembers
tmp_group.iNrFaces = iMembers;
tmp_group.pTriMembers = pTmpMembers;
if (iMembers > 1) {
// could replace with a random seed?
QuickSort(pTmpMembers, 0, iMembers - 1, INTERNAL_RND_SORT_SEED);
}
// look for an existing match
bFound = false;
let l = 0;
while (l < iUniqueSubGroups && !bFound) {
bFound = CompareSubGroups(tmp_group, pUniSubGroups[l]);
if (!bFound) {
++l;
}
}
// assign tangent space index
assert(bFound || l === iUniqueSubGroups);
//piTempTangIndices[f*3+index] = iUniqueTspaces+l;
// if no match was found we allocate a new subgroup
if (!bFound) {
// insert new subgroup
const pIndices = new Int32Array(iMembers);
pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers;
pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices;
array_copy(tmp_group.pTriMembers, 0, pIndices, 0, iMembers);
EvalTspace(
pSubGroupTspace[iUniqueSubGroups],
tmp_group.pTriMembers,
iMembers,
piTriListIn,
pTriInfos,
pContext,
pGroup.iVertexRepresentitive
);
++iUniqueSubGroups;
}
// output tspace
const iOffs = tri_info.iTSpacesOffs;
const iVert = tri_info.vert_num[index];
/**
* @type {STSpace}
*/
const pTS_out = psTspace[iOffs + iVert];
assert.lessThan(pTS_out.iCounter, 2);
assert.equal(((tri_info.iFlag & ORIENT_PRESERVING) !== 0), pGroup.bOrientPreservering);
if (pTS_out.iCounter === 1) {
AvgTSpace(pTS_out, pTS_out, pSubGroupTspace[l]);
pTS_out.iCounter = 2; // update counter
pTS_out.bOrient = pGroup.bOrientPreservering;
} else {
assert.equal(pTS_out.iCounter, 0);
pTS_out.copy(pSubGroupTspace[l]);
pTS_out.iCounter = 1; // update counter
pTS_out.bOrient = pGroup.bOrientPreservering;
}
}
// clean up and offset iUniqueTspaces
iUniqueTspaces += iUniqueSubGroups;
}
}