@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
210 lines (161 loc) • 5.99 kB
JavaScript
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);
}