UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

137 lines (105 loc) 3.42 kB
import { assert } from "../../../../../core/assert.js"; import { BitSet } from "../../../../../core/binary/BitSet.js"; /** * Naive flood implementation of a distance field computation algorithm * @param {Sampler2D} source * @param {Sampler2D} destination * @param {number} emptyValue * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export function computeSignedDistanceField_NaiveFlood( source, destination, emptyValue ) { assert.equal(source.itemSize, 1, `unsupported source.itemSize, expected 1, got '${source.itemSize}'`); assert.isNumber(emptyValue, 'emptyValue'); let i, j; const distanceData = destination.data; const visited = new BitSet(); const openSet = new BitSet(); //use "flood" algorithm //mark all visible tiles as visited const samplerData = source.data; const totalCellCount = samplerData.length; function traverseNeighbours(index, visitor) { let i = index - (width + 1); const top = index > width; const bottom = index < (totalCellCount - width); const x = index % width; const left = x > 0; const right = x < width - 1; if (top) { if (left) { visitor(i); } visitor(i + 1); if (right) { visitor(i + 2); } } i += width; if (left) { visitor(i); } if (right) { visitor(i + 2); } i += width; if (bottom) { if (left) { visitor(i); } visitor(i + 1); if (right) { visitor(i + 2); } } } const width = destination.width; for (i = 0; i < totalCellCount; i++) { const sampleValue = samplerData[i]; if (sampleValue !== emptyValue) { visited.set(i, true); //write distance data distanceData[i] = 0; } else { distanceData[i] = 255; } } //populate initial open set for (i = visited.nextSetBit(0); i !== -1; i = visited.nextSetBit(i + 1)) { j = 0; traverseNeighbours(i, function (neighbourIndex) { if (!visited.get(neighbourIndex)) { //increment number of not visited j++; } }); if (j === 0) { //all neighbours are visited, we can safely ignore this cell } else { openSet.set(i, true); } } for (i = openSet.nextSetBit(0); i !== -1; i = openSet.nextSetBit(0)) { //remove from open set openSet.set(i, false); const value = distanceData[i]; traverseNeighbours(i, function (neighbourIndex) { const neighbourValue = value + 1; if (visited.get(neighbourIndex)) { if (distanceData[neighbourIndex] <= neighbourValue) { return; } } else { visited.set(neighbourIndex, true); } distanceData[neighbourIndex] = neighbourValue; //add neighbour to open set openSet.set(neighbourIndex, true); }); } }