UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

227 lines (169 loc) • 6.98 kB
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; } }