UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

210 lines (161 loc) • 5.99 kB
import { vec3 } from "gl-matrix"; import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js"; import { GetNormal } from "./GetNormal.js"; import { GetPosition } from "./GetPosition.js"; import { GetTexCoord } from "./GetTexCoord.js"; /** * * @param {number} x * @param {number} y * @param {number} z * @returns {number} */ function HASH(x, y, z) { return (x * 73856093) ^ (y * 19349663) ^ (z * 83492791); } /** * * @param {number} x * @param {number} y * @param {number} z * @returns {number} */ function HASH_F(x, y, z) { return HASH(computeHashFloat(x), computeHashFloat(y), computeHashFloat(z)); } /** * Sort comp and data based on comp. * comp2 and data2 are used as temporary storage. * * @param {Uint32Array} comp * @param {Int32Array} data * @param {Uint32Array} comp2 * @param {Int32Array} data2 * @param {number} n */ function radixsort_pair(comp, data, comp2, data2, n) { let _data_0 = data; let _data_1 = data2; let _comp_0 = comp; let _comp_1 = comp2; const data_size = 4; // 4 bytes const bins = new Uint32Array(257 * data_size); /* Count number of elements per bin. */ for (let i = 0; i < n; i++) { for (let pass = 0; pass < data_size; pass++) { const shift = 8 * pass; const key = _comp_0[i]; const index = pass * 257 + ((key >> shift) & 0xff) + 1; bins[index]++; } } /* Compute prefix sum to find position of each bin in the sorted array. */ for (let pass = 0; pass < data_size; pass++) { for (let i = 2; i < 256; i++) { const offset = pass * 257 + i; bins[offset] += bins[offset - 1]; } } let shift = 0; for (let pass = 0; pass < data_size; pass++, shift += 8) { /* Insert the elements in their correct location based on their bin. */ for (let i = 0; i < n; i++) { const bin_index = pass * 257 + (_comp_0[i] >> shift) & 0xff; const pos = bins[bin_index]++; _comp_1[pos] = _comp_0[i]; _data_1[pos] = _data_0[i]; } /* Swap arrays. */ let tmpdata = _data_0; _data_0 = _data_1; _data_1 = tmpdata; let tmpcomp = _comp_0; _comp_0 = _comp_1; _comp_1 = tmpcomp; } } /** * * @param {number[]|Int32Array} piTriList_in_and_out * @param {SMikkTSpaceContext} pContext * @param {number} iNrTrianglesIn * @returns {void} */ export function GenerateSharedVerticesIndexList( piTriList_in_and_out, pContext, iNrTrianglesIn ) { const numVertices = iNrTrianglesIn * 3; const _buffer = new ArrayBuffer(numVertices * 4 * 4); const hashes = new Uint32Array(_buffer, 0, numVertices); const indices = new Int32Array(_buffer, numVertices * 4, numVertices); const temp_hashes = new Uint32Array(_buffer, numVertices * 2 * 4, numVertices); const temp_indices = new Int32Array(_buffer, numVertices * 3 * 4, numVertices); const v = vec3.create(); for (let i = 0; i < numVertices; i++) { const index = piTriList_in_and_out[i]; GetPosition(v, 0, pContext, index); const hashP = HASH_F(v[0], v[1], v[2]); GetNormal(v, pContext, index); const hashN = HASH_F(v[0], v[1], v[2]); GetTexCoord(v, pContext, index); const hashT = HASH_F(v[0], v[1], v[2]); hashes[i] = HASH(hashP, hashN, hashT); indices[i] = i; } radixsort_pair(hashes, indices, temp_hashes, temp_indices, numVertices); // free(temp_hashes); // free(temp_indices); const vT = vec3.create(); const vP = vec3.create(); const vT2 = vec3.create(); const vP2 = vec3.create(); const vN = vec3.create(); const vN2 = vec3.create(); /* * Process blocks of vertices with the same hash. * Vertices in the block might still be separate, but we know for sure that * vertices in different blocks will never be identical. */ let blockstart = 0; while (blockstart < numVertices) { /* Find end of this block (exclusive). */ const hash = hashes[blockstart]; let blockend = blockstart + 1; for (; blockend < numVertices; blockend++) { if (hashes[blockend] !== hash) break; } for (let i = blockstart; i < blockend; i++) { const index1 = piTriList_in_and_out[indices[i]]; GetPosition(vP, 0, pContext, index1); GetNormal(vN, pContext, index1); GetTexCoord(vT, pContext, index1); for (let i2 = i + 1; i2 < blockend; i2++) { const index2 = piTriList_in_and_out[indices[i2]]; if (index1 === index2) { continue; } GetPosition(vP2, 0, pContext, index2); GetNormal(vN2, pContext, index2); GetTexCoord(vT2, pContext, index2); if ( vP[0] === vP2[0] && vP[1] === vP2[1] && vP[2] === vP2[2] && vN[0] === vN2[0] && vN[1] === vN2[1] && vN[2] === vN2[2] && vT[0] === vT2[0] && vT[1] === vT2[1] && vT[2] === vT2[2] ) { piTriList_in_and_out[indices[i2]] = index1; /* Once i2>i has been identified as a duplicate, we can stop since any * i3>i2>i that is a duplicate of i (and therefore also i2) will also be * compared to i2 and therefore be identified there anyways. */ break; } } } /* Advance to next block. */ blockstart = blockend; } // free(hashes); // free(indices); }