UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

312 lines (295 loc) 9.33 kB
import { Color } from '../../math/Color.js'; import { Matrix2 } from '../../math/Matrix2.js'; import { Matrix3 } from '../../math/Matrix3.js'; import { Matrix4 } from '../../math/Matrix4.js'; import { Vector2 } from '../../math/Vector2.js'; import { Vector3 } from '../../math/Vector3.js'; import { Vector4 } from '../../math/Vector4.js'; // cyrb53 (c) 2018 bryc (github.com/bryc). License: Public domain. Attribution appreciated. // A fast and simple 64-bit (or 53-bit) string hash function with decent collision resistance. // Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity. // See https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript/52171480#52171480 // https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js function cyrb53(value, seed = 0) { let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; if (value instanceof Array) { for (let i = 0, val; i < value.length; i++) { val = value[i]; h1 = Math.imul(h1 ^ val, 2654435761); h2 = Math.imul(h2 ^ val, 1597334677); } } else { for (let i = 0, ch; i < value.length; i++) { ch = value.charCodeAt(i); h1 = Math.imul(h1 ^ ch, 2654435761); h2 = Math.imul(h2 ^ ch, 1597334677); } } h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507); h1 ^= Math.imul(h2 ^ h2 >>> 13, 3266489909); h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507); h2 ^= Math.imul(h1 ^ h1 >>> 13, 3266489909); return 4294967296 * (2097151 & h2) + (h1 >>> 0); } /** * Computes a hash for the given string. * * @method * @param {string} str - The string to be hashed. * @return {number} The hash. */ export const hashString = str => cyrb53(str); /** * Computes a hash for the given array. * * @method * @param {Array<number>} array - The array to be hashed. * @return {number} The hash. */ export const hashArray = array => cyrb53(array); /** * Computes a hash for the given list of parameters. * * @method * @param {...number} params - A list of parameters. * @return {number} The hash. */ export const hash = (...params) => cyrb53(params); /** * Computes a cache key for the given node. * * @method * @param {Object|Node} object - The object to be hashed. * @param {boolean} [force=false] - Whether to force a cache key computation or not. * @return {number} The hash. */ export function getCacheKey(object, force = false) { const values = []; if (object.isNode === true) { values.push(object.id); object = object.getSelf(); } for (const { property, childNode } of getNodeChildren(object)) { values.push(cyrb53(property.slice(0, -4)), childNode.getCacheKey(force)); } return cyrb53(values); } /** * This generator function can be used to iterate over the node children * of the given object. * * @generator * @param {Object} node - The object to be hashed. * @param {boolean} [toJSON=false] - Whether to return JSON or not. * @yields {Object} A result node holding the property, index (if available) and the child node. */ export function* getNodeChildren(node, toJSON = false) { for (const property in node) { // Ignore private properties. if (property.startsWith('_') === true) continue; const object = node[property]; if (Array.isArray(object) === true) { for (let i = 0; i < object.length; i++) { const child = object[i]; if (child && (child.isNode === true || toJSON && typeof child.toJSON === 'function')) { yield { property, index: i, childNode: child }; } } } else if (object && object.isNode === true) { yield { property, childNode: object }; } else if (typeof object === 'object') { for (const subProperty in object) { const child = object[subProperty]; if (child && (child.isNode === true || toJSON && typeof child.toJSON === 'function')) { yield { property, index: subProperty, childNode: child }; } } } } } const typeFromLength = /*@__PURE__*/new Map([[1, 'float'], [2, 'vec2'], [3, 'vec3'], [4, 'vec4'], [9, 'mat3'], [16, 'mat4']]); const dataFromObject = /*@__PURE__*/new WeakMap(); /** * Returns the data type for the given the length. * * @method * @param {number} length - The length. * @return {string} The data type. */ export function getTypeFromLength(length) { return typeFromLength.get(length); } /** * Returns the typed array for the given data type. * * @method * @param {string} type - The data type. * @return {TypedArray} The typed array. */ export function getTypedArrayFromType(type) { // Handle component type for vectors and matrices if (/[iu]?vec\d/.test(type)) { // Handle int vectors if (type.startsWith('ivec')) return Int32Array; // Handle uint vectors if (type.startsWith('uvec')) return Uint32Array; // Default to float vectors return Float32Array; } // Handle matrices (always float) if (/mat\d/.test(type)) return Float32Array; // Basic types if (/float/.test(type)) return Float32Array; if (/uint/.test(type)) return Uint32Array; if (/int/.test(type)) return Int32Array; throw new Error(`THREE.NodeUtils: Unsupported type: ${type}`); } /** * Returns the length for the given data type. * * @method * @param {string} type - The data type. * @return {number} The length. */ export function getLengthFromType(type) { if (/float|int|uint/.test(type)) return 1; if (/vec2/.test(type)) return 2; if (/vec3/.test(type)) return 3; if (/vec4/.test(type)) return 4; if (/mat2/.test(type)) return 4; if (/mat3/.test(type)) return 9; if (/mat4/.test(type)) return 16; console.error('THREE.TSL: Unsupported type:', type); } /** * Returns the data type for the given value. * * @method * @param {any} value - The value. * @return {?string} The data type. */ export function getValueType(value) { if (value === undefined || value === null) return null; const typeOf = typeof value; if (value.isNode === true) { return 'node'; } else if (typeOf === 'number') { return 'float'; } else if (typeOf === 'boolean') { return 'bool'; } else if (typeOf === 'string') { return 'string'; } else if (typeOf === 'function') { return 'shader'; } else if (value.isVector2 === true) { return 'vec2'; } else if (value.isVector3 === true) { return 'vec3'; } else if (value.isVector4 === true) { return 'vec4'; } else if (value.isMatrix2 === true) { return 'mat2'; } else if (value.isMatrix3 === true) { return 'mat3'; } else if (value.isMatrix4 === true) { return 'mat4'; } else if (value.isColor === true) { return 'color'; } else if (value instanceof ArrayBuffer) { return 'ArrayBuffer'; } return null; } /** * Returns the value/object for the given data type and parameters. * * @method * @param {string} type - The given type. * @param {...any} params - A parameter list. * @return {any} The value/object. */ export function getValueFromType(type, ...params) { const last4 = type ? type.slice(-4) : undefined; if (params.length === 1) { // ensure same behaviour as in NodeBuilder.format() if (last4 === 'vec2') params = [params[0], params[0]];else if (last4 === 'vec3') params = [params[0], params[0], params[0]];else if (last4 === 'vec4') params = [params[0], params[0], params[0], params[0]]; } if (type === 'color') { return new Color(...params); } else if (last4 === 'vec2') { return new Vector2(...params); } else if (last4 === 'vec3') { return new Vector3(...params); } else if (last4 === 'vec4') { return new Vector4(...params); } else if (last4 === 'mat2') { return new Matrix2(...params); } else if (last4 === 'mat3') { return new Matrix3(...params); } else if (last4 === 'mat4') { return new Matrix4(...params); } else if (type === 'bool') { return params[0] || false; } else if (type === 'float' || type === 'int' || type === 'uint') { return params[0] || 0; } else if (type === 'string') { return params[0] || ''; } else if (type === 'ArrayBuffer') { return base64ToArrayBuffer(params[0]); } return null; } /** * Gets the object data that can be shared between different rendering steps. * * @param {Object} object - The object to get the data for. * @return {Object} The object data. */ export function getDataFromObject(object) { let data = dataFromObject.get(object); if (data === undefined) { data = {}; dataFromObject.set(object, data); } return data; } /** * Converts the given array buffer to a Base64 string. * * @method * @param {ArrayBuffer} arrayBuffer - The array buffer. * @return {string} The Base64 string. */ export function arrayBufferToBase64(arrayBuffer) { let chars = ''; const array = new Uint8Array(arrayBuffer); for (let i = 0; i < array.length; i++) { chars += String.fromCharCode(array[i]); } return btoa(chars); } /** * Converts the given Base64 string to an array buffer. * * @method * @param {string} base64 - The Base64 string. * @return {ArrayBuffer} The array buffer. */ export function base64ToArrayBuffer(base64) { return Uint8Array.from(atob(base64), c => c.charCodeAt(0)).buffer; }