@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
168 lines (127 loc) • 4.05 kB
JavaScript
import { assert } from "../../../../core/assert.js";
import { combine_hash } from "../../../../core/collection/array/combine_hash.js";
import { murmur3_32 } from "../../../../core/math/hash/murmur3_32.js";
import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";
import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
import { computeHtmlCanvasElementHash } from "../../../graphics/canvas/computeHtmlCanvasElementHash.js";
import { isImageBitmap } from "../../../graphics/texture/isImageBitmap.js";
import { computeImageBitmapHash } from "./computeImageBitmapHash.js";
/**
*
* @param {Vector2} v
* @return {number}
*/
function vector2Hash(v) {
const x = computeHashFloat(v.x);
const y = computeHashFloat(v.y);
return ((x << 5) - x) + y;
}
/**
*
* @type {WeakMap<object, number>}
*/
const data_cache = new WeakMap();
/**
*
* @param {ImageBitmap|HTMLImageElement|{data,width:number,height:number}} image
* @return {number}
*/
export function computeImageDataHash(image) {
const cached_value = data_cache.get(image);
if (cached_value !== undefined) {
return cached_value;
}
let result = 0;
if (isImageBitmap(image)) {
result = computeImageBitmapHash(image);
} else if (image instanceof HTMLImageElement) {
result = computeStringHash(image.src);
} else if (image instanceof HTMLCanvasElement) {
result = computeHtmlCanvasElementHash(image);
}
let width = 0;
let height = 0;
if (typeof image.width === "number") {
width = image.width;
}
if (typeof image.height === "number") {
height = image.height;
}
result = result ^ (((width & 0xFFFF) << 16) | (height & 0xFFFF));
// cache value
data_cache.set(image, result);
return result;
}
/**
*
* @param {Texture} texture
* @return {number}
*/
function computeSpecificHash(texture) {
let dataHash = 0;
let i;
if (texture.image !== null && texture.image !== undefined) {
const image = texture.image;
dataHash = computeImageDataHash(image);
}
const mipmaps = texture.mipmaps;
if (Array.isArray(mipmaps)) {
const nMipmaps = mipmaps.length;
for (i = 0; i < nMipmaps; i++) {
const mipmap = mipmaps[i];
const data = mipmap.data;
const dataSize = data.length;
if (dataSize > 1024) {
continue;
}
dataHash = ((dataHash << 5) - dataHash) + murmur3_32(data, 1337);
break;
}
}
return dataHash;
}
/**
*
* @param {Texture|THREE.Texture} t
* @returns {number}
*/
export function computeTextureHash(t) {
if (t === null) {
return 0;
}
if (t === undefined) {
return 1;
}
// special methods
if (typeof t.hash === "function") {
const hash = t.hash(); // must produce an integer value
assert.isInteger(hash, 'hash');
return hash;
}
// revert to generic check
const specificHash = computeSpecificHash(t);
return combine_hash(
t.mapping,
t.wrapS,
t.wrapT,
t.magFilter,
t.minFilter,
t.anisotropy,
t.format,
t.type,
vector2Hash(t.offset),
vector2Hash(t.repeat),
vector2Hash(t.center),
computeHashFloat(t.rotation),
t.generateMipmaps ? 1 : 0,
t.premultiplyAlpha ? 1 : 0,
t.flipY ? 1 : 0,
t.unpackAlignment,
/*
we are excluding encoding from hash, as this property has disappeared in later version of three.js
This property is rarely going to have the deciding role for the hash anyway. This notice is left for historical purposes only
*/
// t.encoding,
specificHash
);
}