@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
222 lines (177 loc) • 5.59 kB
JavaScript
import { fastArrayEquals } from "../../../../core/collection/array/fastArrayEquals.js";
import { isArrayLike } from "../../../../core/collection/array/isArrayLike.js";
import { computeImageCanvasEquality } from "../../../graphics/canvas/computeImageCanvasEquality.js";
import { isImageBitmap } from "../../../graphics/texture/isImageBitmap.js";
import { computeImageBitmapEquality } from "./computeImageBitmapEquality.js";
/**
* Compare two three.js textures for equality
* @param {THREE.Texture} a
* @param {THREE.Texture} b
* @returns {boolean}
*/
export function computeTextureEquality(a, b) {
if (a === b) {
return true;
}
if (
a === null
|| b === null
|| a === undefined
|| b === undefined
) {
return false;
}
// special methods
if (typeof a.equals === "function" && typeof b.equals === "function") {
// can check for equality using custom methods
return a.equals(b);
}
// revert to generic check
if (
a.mapping !== b.mapping
|| a.wrapS !== b.wrapS
|| a.wrapT !== b.wrapT
|| a.magFilter !== b.magFilter
|| a.minFilter !== b.minFilter
|| a.anisotropy !== b.anisotropy
|| a.format !== b.format
|| a.type !== b.type
|| !a.offset.equals(b.offset)
|| !a.repeat.equals(b.repeat)
|| !a.center.equals(b.center)
|| a.rotation !== b.rotation
|| a.generateMipmaps !== b.generateMipmaps
|| a.premultiplyAlpha !== b.premultiplyAlpha
|| a.flipY !== b.flipY
|| a.unpackAlignment !== b.unpackAlignment
|| a.encoding !== b.encoding
|| !textureImagesEqual(a.image, b.image)
) {
return false;
}
if (a.isCompressedTexture && b.isCompressedTexture) {
const aMipmaps = a.mipmaps;
const bMipmaps = b.mipmaps;
if (!textureMipChainEqual(aMipmaps, bMipmaps)) {
return false;
}
}
//TODO implement support for other texture types
// checks up until now were for rejection, so if we got until this point - textures must be equal
return true;
}
/**
*
* @param {Image|ImageBitmap|HTMLCanvasElement|[]|{width:number, height:number}} a
* @param {Image|ImageBitmap|HTMLCanvasElement|[]|{width:number, height:number}} b
* @returns {boolean}
*/
export function textureImagesEqual(a, b) {
if (a === b) {
return true;
}
if (a instanceof Image && b instanceof Image) {
//both are images
if (a.src === b.src) {
//same source
return true;
} else {
// different source, assume images are different too
return false;
}
}
if (
(typeof a.width === "number" && a.width !== b.width)
|| (typeof a.height === "number" && a.height !== b.height)
) {
// dimensions are present, but are inconsistent
return false;
}
if (isImageBitmap(a) && isImageBitmap(b)) {
return computeImageBitmapEquality(a, b);
}
if (a instanceof HTMLCanvasElement && b instanceof HTMLCanvasElement) {
return computeImageCanvasEquality(a, b);
}
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
const ai = a[i];
const bi = b[i];
if (ai.format !== bi.format) {
return false;
}
const aMipmaps = ai.mipmaps;
const bMipmaps = bi.mipmaps;
//TODO should we ignore mipmaps if they are absent?
if (!textureMipChainEqual(aMipmaps, bMipmaps)) {
return false;
}
}
return true;
}
const a_data = a.data;
const b_data = b.data;
if (a_data === null && b_data === null) {
// special case, empty texture
return true;
}
if (isArrayLike(a_data) && isArrayLike(b_data)) {
return textureMipmapEqual(a, b);
}
// assume different
return false;
}
/**
*
* @param {Array} a
* @param {Array} b
* @returns {boolean}
*/
function textureMipChainEqual(a, b) {
if (a === undefined) {
if (b === undefined) {
return true;
} else {
return false;
}
} else if (b === undefined) {
return false;
}
const a_length = a.length;
if (a_length !== b.length) {
// different mip chain length
return false;
}
for (let j = a_length - 1; j >= 0; j--) { //traverse chain top to bottom, starting from smallest mip for faster rejection
const aMipmap = a[j];
const bMipmap = b[j];
if (!textureMipmapEqual(aMipmap, bMipmap)) {
return false;
}
}
return true;
}
/**
*
* @param {{data:Uint8Array, width:number, height:number}} a
* @param {{data:Uint8Array, width:number, height:number}} b
* @returns {boolean}
*/
function textureMipmapEqual(a, b) {
if (a.width !== b.width) {
return false;
}
if (a.height !== b.width) {
return false;
}
const aData = a.data;
const bData = b.data;
if (aData === bData) {
// special case
return true;
}
return fastArrayEquals(aData, bData);
}