UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

1,865 lines (1,840 loc) 2.9 MB
/** * @license * PlayCanvas Engine v2.5.0 revision 2abde2e (PROFILE) * Copyright 2011-2025 PlayCanvas Ltd. All rights reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var TRACEID_RENDER_FRAME = 'RenderFrame'; var TRACEID_RENDER_FRAME_TIME = 'RenderFrameTime'; var TRACEID_RENDER_PASS = 'RenderPass'; var TRACEID_RENDER_PASS_DETAIL = 'RenderPassDetail'; var TRACEID_RENDER_ACTION = 'RenderAction'; var TRACEID_RENDER_TARGET_ALLOC = 'RenderTargetAlloc'; var TRACEID_TEXTURE_ALLOC = 'TextureAlloc'; var TRACEID_SHADER_ALLOC = 'ShaderAlloc'; var TRACEID_SHADER_COMPILE = 'ShaderCompile'; var TRACEID_VRAM_TEXTURE = 'VRAM.Texture'; var TRACEID_VRAM_VB = 'VRAM.Vb'; var TRACEID_VRAM_IB = 'VRAM.Ib'; var TRACEID_VRAM_SB = 'VRAM.Sb'; var TRACEID_BINDGROUP_ALLOC = 'BindGroupAlloc'; var TRACEID_BINDGROUPFORMAT_ALLOC = 'BindGroupFormatAlloc'; var TRACEID_RENDERPIPELINE_ALLOC = 'RenderPipelineAlloc'; var TRACEID_COMPUTEPIPELINE_ALLOC = 'ComputePipelineAlloc'; var TRACEID_PIPELINELAYOUT_ALLOC = 'PipelineLayoutAlloc'; var TRACE_ID_ELEMENT = 'Element'; var TRACEID_TEXTURES = 'Textures'; var TRACEID_RENDER_QUEUE = 'RenderQueue'; var TRACEID_GPU_TIMINGS = 'GpuTimings'; var version = '2.5.0'; var revision = '2abde2e'; function extend(target, ex) { for(var prop in ex){ var copy = ex[prop]; if (Array.isArray(copy)) { target[prop] = extend([], copy); } else if (copy && typeof copy === 'object') { target[prop] = extend({}, copy); } else { target[prop] = copy; } } return target; } var guid = { create () { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c)=>{ var r = Math.random() * 16 | 0; var v = c === 'x' ? r : r & 0x3 | 0x8; return v.toString(16); }); } }; var path = { delimiter: '/', join () { for(var _len = arguments.length, sections = new Array(_len), _key = 0; _key < _len; _key++){ sections[_key] = arguments[_key]; } var result = sections[0]; for(var i = 0; i < sections.length - 1; i++){ var one = sections[i]; var two = sections[i + 1]; if (two[0] === path.delimiter) { result = two; continue; } if (one && two && one[one.length - 1] !== path.delimiter && two[0] !== path.delimiter) { result += path.delimiter + two; } else { result += two; } } return result; }, normalize (pathname) { var lead = pathname.startsWith(path.delimiter); var trail = pathname.endsWith(path.delimiter); var parts = pathname.split('/'); var result = ''; var cleaned = []; for(var i = 0; i < parts.length; i++){ if (parts[i] === '') continue; if (parts[i] === '.') continue; if (parts[i] === '..' && cleaned.length > 0) { cleaned = cleaned.slice(0, cleaned.length - 2); continue; } if (i > 0) cleaned.push(path.delimiter); cleaned.push(parts[i]); } result = cleaned.join(''); if (!lead && result[0] === path.delimiter) { result = result.slice(1); } if (trail && result[result.length - 1] !== path.delimiter) { result += path.delimiter; } return result; }, split (pathname) { var lastDelimiterIndex = pathname.lastIndexOf(path.delimiter); if (lastDelimiterIndex !== -1) { return [ pathname.substring(0, lastDelimiterIndex), pathname.substring(lastDelimiterIndex + 1) ]; } return [ '', pathname ]; }, getBasename (pathname) { return path.split(pathname)[1]; }, getDirectory (pathname) { return path.split(pathname)[0]; }, getExtension (pathname) { var ext = pathname.split('?')[0].split('.').pop(); if (ext !== pathname) { return "." + ext; } return ''; }, isRelativePath (pathname) { return pathname.charAt(0) !== '/' && pathname.match(/:\/\//) === null; }, extractPath (pathname) { var result = ''; var parts = pathname.split('/'); var i = 0; if (parts.length > 1) { if (path.isRelativePath(pathname)) { if (parts[0] === '.') { for(i = 0; i < parts.length - 1; ++i){ result += i === 0 ? parts[i] : "/" + parts[i]; } } else if (parts[0] === '..') { for(i = 0; i < parts.length - 1; ++i){ result += i === 0 ? parts[i] : "/" + parts[i]; } } else { result = '.'; for(i = 0; i < parts.length - 1; ++i){ result += "/" + parts[i]; } } } else { for(i = 0; i < parts.length - 1; ++i){ result += i === 0 ? parts[i] : "/" + parts[i]; } } } return result; } }; var detectPassiveEvents = ()=>{ var result = false; try { var opts = Object.defineProperty({}, 'passive', { get: function get() { result = true; return false; } }); window.addEventListener('testpassive', null, opts); window.removeEventListener('testpassive', null, opts); } catch (e) {} return result; }; var ua = typeof navigator !== 'undefined' ? navigator.userAgent : ''; var environment = typeof window !== 'undefined' ? 'browser' : typeof global !== 'undefined' ? 'node' : 'worker'; var platformName = /android/i.test(ua) ? 'android' : /ip(?:[ao]d|hone)/i.test(ua) ? 'ios' : /windows/i.test(ua) ? 'windows' : /mac os/i.test(ua) ? 'osx' : /linux/i.test(ua) ? 'linux' : /cros/i.test(ua) ? 'cros' : null; var browserName = environment !== 'browser' ? null : /Chrome\/|Chromium\/|Edg.*\//.test(ua) ? 'chrome' : /Safari\//.test(ua) ? 'safari' : /Firefox\//.test(ua) ? 'firefox' : 'other'; var xbox = /xbox/i.test(ua); var touch = environment === 'browser' && ('ontouchstart' in window || 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 0); var gamepads = environment === 'browser' && (!!navigator.getGamepads || !!navigator.webkitGetGamepads); var workers = typeof Worker !== 'undefined'; var passiveEvents = detectPassiveEvents(); var _ref, _ref1, _ref2; var platform = { name: platformName, environment: environment, global: (_ref2 = (_ref1 = (_ref = typeof globalThis !== 'undefined' && globalThis) != null ? _ref : environment === 'browser' && window) != null ? _ref1 : environment === 'node' && global) != null ? _ref2 : environment === 'worker' && self, browser: environment === 'browser', worker: environment === 'worker', desktop: [ 'windows', 'osx', 'linux', 'cros' ].includes(platformName), mobile: [ 'android', 'ios' ].includes(platformName), ios: platformName === 'ios', android: platformName === 'android', xbox: xbox, gamepads: gamepads, touch: touch, workers: workers, passiveEvents: passiveEvents, browserName: browserName }; var ASCII_LOWERCASE = 'abcdefghijklmnopqrstuvwxyz'; var ASCII_UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; var ASCII_LETTERS = ASCII_LOWERCASE + ASCII_UPPERCASE; var HIGH_SURROGATE_BEGIN = 0xD800; var HIGH_SURROGATE_END = 0xDBFF; var LOW_SURROGATE_BEGIN = 0xDC00; var LOW_SURROGATE_END = 0xDFFF; var ZERO_WIDTH_JOINER = 0x200D; var REGIONAL_INDICATOR_BEGIN = 0x1F1E6; var REGIONAL_INDICATOR_END = 0x1F1FF; var FITZPATRICK_MODIFIER_BEGIN = 0x1F3FB; var FITZPATRICK_MODIFIER_END = 0x1F3FF; var DIACRITICAL_MARKS_BEGIN = 0x20D0; var DIACRITICAL_MARKS_END = 0x20FF; var VARIATION_MODIFIER_BEGIN = 0xFE00; var VARIATION_MODIFIER_END = 0xFE0F; function getCodePointData(string, i) { if (i === undefined) i = 0; var size = string.length; if (i < 0 || i >= size) { return null; } var first = string.charCodeAt(i); if (size > 1 && first >= HIGH_SURROGATE_BEGIN && first <= HIGH_SURROGATE_END) { var second = string.charCodeAt(i + 1); if (second >= LOW_SURROGATE_BEGIN && second <= LOW_SURROGATE_END) { return { code: (first - HIGH_SURROGATE_BEGIN) * 0x400 + second - LOW_SURROGATE_BEGIN + 0x10000, long: true }; } } return { code: first, long: false }; } function isCodeBetween(string, begin, end) { if (!string) { return false; } var codeData = getCodePointData(string); if (codeData) { var code = codeData.code; return code >= begin && code <= end; } return false; } function numCharsToTakeForNextSymbol(string, index) { if (index === string.length - 1) { return 1; } if (isCodeBetween(string[index], HIGH_SURROGATE_BEGIN, HIGH_SURROGATE_END)) { var first = string.substring(index, index + 2); var second = string.substring(index + 2, index + 4); if (isCodeBetween(second, FITZPATRICK_MODIFIER_BEGIN, FITZPATRICK_MODIFIER_END) || isCodeBetween(first, REGIONAL_INDICATOR_BEGIN, REGIONAL_INDICATOR_END) && isCodeBetween(second, REGIONAL_INDICATOR_BEGIN, REGIONAL_INDICATOR_END)) { return 4; } if (isCodeBetween(second, VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { return 3; } return 2; } if (isCodeBetween(string[index + 1], VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { return 2; } return 1; } var string = { ASCII_LOWERCASE: ASCII_LOWERCASE, ASCII_UPPERCASE: ASCII_UPPERCASE, ASCII_LETTERS: ASCII_LETTERS, format (s) { for(var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++){ args[_key - 1] = arguments[_key]; } for(var i = 0; i < args.length; i++){ s = s.replace("{" + i + "}", args[i]); } return s; }, getCodePoint (string, i) { var codePointData = getCodePointData(string, i); return codePointData && codePointData.code; }, getCodePoints (string) { if (typeof string !== 'string') { throw new TypeError('Not a string'); } var i = 0; var arr = []; var codePoint; while(!!(codePoint = getCodePointData(string, i))){ arr.push(codePoint.code); i += codePoint.long ? 2 : 1; } return arr; }, getSymbols (string) { if (typeof string !== 'string') { throw new TypeError('Not a string'); } var index = 0; var length = string.length; var output = []; var take = 0; var ch; while(index < length){ take += numCharsToTakeForNextSymbol(string, index + take); ch = string[index + take]; if (isCodeBetween(ch, DIACRITICAL_MARKS_BEGIN, DIACRITICAL_MARKS_END)) { ch = string[index + take++]; } if (isCodeBetween(ch, VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { ch = string[index + take++]; } if (ch && ch.charCodeAt(0) === ZERO_WIDTH_JOINER) { ch = string[index + take++]; continue; } var char = string.substring(index, index + take); output.push(char); index += take; take = 0; } return output; }, fromCodePoint () { var chars = []; var current; var codePoint; var units; for(var i = 0; i < arguments.length; ++i){ current = Number(arguments[i]); codePoint = current - 0x10000; units = current > 0xFFFF ? [ (codePoint >> 10) + 0xD800, codePoint % 0x400 + 0xDC00 ] : [ current ]; chars.push(String.fromCharCode.apply(null, units)); } return chars.join(''); } }; class EventHandle { off() { if (this._removed) return; this.handler.offByHandle(this); } on(name, callback, scope) { if (scope === undefined) scope = this; return this.handler._addCallback(name, callback, scope, false); } once(name, callback, scope) { if (scope === undefined) scope = this; return this.handler._addCallback(name, callback, scope, true); } set removed(value) { if (!value) return; this._removed = true; } get removed() { return this._removed; } constructor(handler, name, callback, scope, once = false){ this._removed = false; this.handler = handler; this.name = name; this.callback = callback; this.scope = scope; this._once = once; } } class EventHandler { initEventHandler() { this._callbacks = new Map(); this._callbackActive = new Map(); } _addCallback(name, callback, scope, once) { if (!this._callbacks.has(name)) { this._callbacks.set(name, []); } if (this._callbackActive.has(name)) { var callbackActive = this._callbackActive.get(name); if (callbackActive && callbackActive === this._callbacks.get(name)) { this._callbackActive.set(name, callbackActive.slice()); } } var evt = new EventHandle(this, name, callback, scope, once); this._callbacks.get(name).push(evt); return evt; } on(name, callback, scope) { if (scope === undefined) scope = this; return this._addCallback(name, callback, scope, false); } once(name, callback, scope) { if (scope === undefined) scope = this; return this._addCallback(name, callback, scope, true); } off(name, callback, scope) { if (name) { if (this._callbackActive.has(name) && this._callbackActive.get(name) === this._callbacks.get(name)) { this._callbackActive.set(name, this._callbackActive.get(name).slice()); } } else { for (var [key, callbacks] of this._callbackActive){ if (!this._callbacks.has(key)) { continue; } if (this._callbacks.get(key) !== callbacks) { continue; } this._callbackActive.set(key, callbacks.slice()); } } if (!name) { for (var callbacks1 of this._callbacks.values()){ for(var i = 0; i < callbacks1.length; i++){ callbacks1[i].removed = true; } } this._callbacks.clear(); } else if (!callback) { var callbacks2 = this._callbacks.get(name); if (callbacks2) { for(var i1 = 0; i1 < callbacks2.length; i1++){ callbacks2[i1].removed = true; } this._callbacks.delete(name); } } else { var callbacks3 = this._callbacks.get(name); if (!callbacks3) { return this; } for(var i2 = 0; i2 < callbacks3.length; i2++){ if (callbacks3[i2].callback !== callback) { continue; } if (scope && callbacks3[i2].scope !== scope) { continue; } callbacks3[i2].removed = true; callbacks3.splice(i2, 1); i2--; } if (callbacks3.length === 0) { this._callbacks.delete(name); } } return this; } offByHandle(handle) { var name = handle.name; handle.removed = true; if (this._callbackActive.has(name) && this._callbackActive.get(name) === this._callbacks.get(name)) { this._callbackActive.set(name, this._callbackActive.get(name).slice()); } var callbacks = this._callbacks.get(name); if (!callbacks) { return this; } var ind = callbacks.indexOf(handle); if (ind !== -1) { callbacks.splice(ind, 1); if (callbacks.length === 0) { this._callbacks.delete(name); } } return this; } fire(name, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { if (!name) { return this; } var callbacksInitial = this._callbacks.get(name); if (!callbacksInitial) { return this; } var callbacks; if (!this._callbackActive.has(name)) { this._callbackActive.set(name, callbacksInitial); } else if (this._callbackActive.get(name) !== callbacksInitial) { callbacks = callbacksInitial.slice(); } for(var i = 0; (callbacks || this._callbackActive.get(name)) && i < (callbacks || this._callbackActive.get(name)).length; i++){ var evt = (callbacks || this._callbackActive.get(name))[i]; if (!evt.callback) continue; evt.callback.call(evt.scope, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); if (evt._once) { var existingCallback = this._callbacks.get(name); var ind = existingCallback ? existingCallback.indexOf(evt) : -1; if (ind !== -1) { if (this._callbackActive.get(name) === existingCallback) { this._callbackActive.set(name, this._callbackActive.get(name).slice()); } var callbacks1 = this._callbacks.get(name); if (!callbacks1) continue; callbacks1[ind].removed = true; callbacks1.splice(ind, 1); if (callbacks1.length === 0) { this._callbacks.delete(name); } } } } if (!callbacks) { this._callbackActive.delete(name); } return this; } hasEvent(name) { var _this__callbacks_get; return !!((_this__callbacks_get = this._callbacks.get(name)) == null ? undefined : _this__callbacks_get.length); } constructor(){ this._callbacks = new Map(); this._callbackActive = new Map(); } } class IndexedList { push(key, item) { if (this._index[key]) { throw Error("Key already in index " + key); } var location = this._list.push(item) - 1; this._index[key] = location; } has(key) { return this._index[key] !== undefined; } get(key) { var location = this._index[key]; if (location !== undefined) { return this._list[location]; } return null; } remove(key) { var location = this._index[key]; if (location !== undefined) { this._list.splice(location, 1); delete this._index[key]; for(key in this._index){ var idx = this._index[key]; if (idx > location) { this._index[key] = idx - 1; } } return true; } return false; } list() { return this._list; } clear() { this._list.length = 0; for(var prop in this._index){ delete this._index[prop]; } } constructor(){ this._list = []; this._index = {}; } } var cachedResult = (func)=>{ var uninitToken = {}; var result = uninitToken; return ()=>{ if (result === uninitToken) { result = func(); } return result; }; }; class Impl { static loadScript(url, callback) { var s = document.createElement("script"); s.setAttribute('src', url); s.onload = ()=>{ callback(null); }; s.onerror = ()=>{ callback("Failed to load script='" + url + "'"); }; document.body.appendChild(s); } static loadWasm(moduleName, config, callback) { var loadUrl = Impl.wasmSupported() && config.glueUrl && config.wasmUrl ? config.glueUrl : config.fallbackUrl; if (loadUrl) { Impl.loadScript(loadUrl, (err)=>{ if (err) { callback(err, null); } else { var module = window[moduleName]; window[moduleName] = undefined; module({ locateFile: ()=>config.wasmUrl, onAbort: ()=>{ callback('wasm module aborted.'); } }).then((instance)=>{ callback(null, instance); }); } }); } else { callback('No supported wasm modules found.', null); } } static getModule(name) { if (!Impl.modules.hasOwnProperty(name)) { Impl.modules[name] = { config: null, initializing: false, instance: null, callbacks: [] }; } return Impl.modules[name]; } static initialize(moduleName, module) { if (module.initializing) { return; } var config = module.config; if (config.glueUrl || config.wasmUrl || config.fallbackUrl) { module.initializing = true; Impl.loadWasm(moduleName, config, (err, instance)=>{ if (err) { if (config.errorHandler) { config.errorHandler(err); } else { console.error("failed to initialize module=" + moduleName + " error=" + err); } } else { module.instance = instance; module.callbacks.forEach((callback)=>{ callback(instance); }); } }); } } } Impl.modules = {}; Impl.wasmSupported = cachedResult(()=>{ try { if (typeof WebAssembly === 'object' && typeof WebAssembly.instantiate === 'function') { var module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); if (module instanceof WebAssembly.Module) { return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; } } } catch (e) {} return false; }); class WasmModule { static setConfig(moduleName, config) { var module = Impl.getModule(moduleName); module.config = config; if (module.callbacks.length > 0) { Impl.initialize(moduleName, module); } } static getConfig(moduleName) { var _Impl_modules_moduleName, _Impl_modules; return (_Impl_modules = Impl.modules) == null ? undefined : (_Impl_modules_moduleName = _Impl_modules[moduleName]) == null ? undefined : _Impl_modules_moduleName.config; } static getInstance(moduleName, callback) { var module = Impl.getModule(moduleName); if (module.instance) { callback(module.instance); } else { module.callbacks.push(callback); if (module.config) { Impl.initialize(moduleName, module); } } } } class ReadStream { get remainingBytes() { return this.dataView.byteLength - this.offset; } reset(offset) { if (offset === undefined) offset = 0; this.offset = offset; } skip(bytes) { this.offset += bytes; } align(bytes) { this.offset = this.offset + bytes - 1 & ~(bytes - 1); } _inc(amount) { this.offset += amount; return this.offset - amount; } readChar() { return String.fromCharCode(this.dataView.getUint8(this.offset++)); } readChars(numChars) { var result = ''; for(var i = 0; i < numChars; ++i){ result += this.readChar(); } return result; } readU8() { return this.dataView.getUint8(this.offset++); } readU16() { return this.dataView.getUint16(this._inc(2), true); } readU32() { return this.dataView.getUint32(this._inc(4), true); } readU64() { return this.readU32() + 2 ** 32 * this.readU32(); } readU32be() { return this.dataView.getUint32(this._inc(4), false); } readArray(result) { for(var i = 0; i < result.length; ++i){ result[i] = this.readU8(); } } readLine() { var view = this.dataView; var result = ''; while(true){ if (this.offset >= view.byteLength) { break; } var c = String.fromCharCode(this.readU8()); if (c === '\n') { break; } result += c; } return result; } constructor(arraybuffer){ this.offset = 0; this.arraybuffer = arraybuffer; this.dataView = new DataView(arraybuffer); } } class SortedLoopArray { _binarySearch(item) { var left = 0; var right = this.items.length - 1; var search = item[this._sortBy]; var middle; var current; while(left <= right){ middle = Math.floor((left + right) / 2); current = this.items[middle][this._sortBy]; if (current <= search) { left = middle + 1; } else if (current > search) { right = middle - 1; } } return left; } _doSort(a, b) { var sortBy = this._sortBy; return a[sortBy] - b[sortBy]; } insert(item) { var index = this._binarySearch(item); this.items.splice(index, 0, item); this.length++; if (this.loopIndex >= index) { this.loopIndex++; } } append(item) { this.items.push(item); this.length++; } remove(item) { var idx = this.items.indexOf(item); if (idx < 0) return; this.items.splice(idx, 1); this.length--; if (this.loopIndex >= idx) { this.loopIndex--; } } sort() { var current = this.loopIndex >= 0 ? this.items[this.loopIndex] : null; this.items.sort(this._sortHandler); if (current !== null) { this.loopIndex = this.items.indexOf(current); } } constructor(args){ this.items = []; this.length = 0; this.loopIndex = -1; this._sortBy = args.sortBy; this._sortHandler = this._doSort.bind(this); } } class Tags extends EventHandler { add() { for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){ args[_key] = arguments[_key]; } var changed = false; var tags = this._processArguments(args, true); if (!tags.length) { return changed; } for(var i = 0; i < tags.length; i++){ if (this._index[tags[i]]) { continue; } changed = true; this._index[tags[i]] = true; this._list.push(tags[i]); this.fire('add', tags[i], this._parent); } if (changed) { this.fire('change', this._parent); } return changed; } remove() { for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){ args[_key] = arguments[_key]; } var changed = false; if (!this._list.length) { return changed; } var tags = this._processArguments(args, true); if (!tags.length) { return changed; } for(var i = 0; i < tags.length; i++){ if (!this._index[tags[i]]) { continue; } changed = true; delete this._index[tags[i]]; this._list.splice(this._list.indexOf(tags[i]), 1); this.fire('remove', tags[i], this._parent); } if (changed) { this.fire('change', this._parent); } return changed; } clear() { if (!this._list.length) { return; } var tags = this._list.slice(0); this._list = []; this._index = {}; for(var i = 0; i < tags.length; i++){ this.fire('remove', tags[i], this._parent); } this.fire('change', this._parent); } has() { for(var _len = arguments.length, query = new Array(_len), _key = 0; _key < _len; _key++){ query[_key] = arguments[_key]; } if (!this._list.length) { return false; } return this._has(this._processArguments(query)); } _has(tags) { if (!this._list.length || !tags.length) { return false; } for(var i = 0; i < tags.length; i++){ if (tags[i].length === 1) { if (this._index[tags[i][0]]) { return true; } } else { var multiple = true; for(var t = 0; t < tags[i].length; t++){ if (this._index[tags[i][t]]) { continue; } multiple = false; break; } if (multiple) { return true; } } } return false; } list() { return this._list.slice(0); } _processArguments(args, flat) { var tags = []; var tmp = []; if (!args || !args.length) { return tags; } for(var i = 0; i < args.length; i++){ if (args[i] instanceof Array) { if (!flat) { tmp = []; } for(var t = 0; t < args[i].length; t++){ if (typeof args[i][t] !== 'string') { continue; } if (flat) { tags.push(args[i][t]); } else { tmp.push(args[i][t]); } } if (!flat && tmp.length) { tags.push(tmp); } } else if (typeof args[i] === 'string') { if (flat) { tags.push(args[i]); } else { tags.push([ args[i] ]); } } } return tags; } get size() { return this._list.length; } constructor(parent){ super(), this._index = {}, this._list = []; this._parent = parent; } } Tags.EVENT_ADD = 'add'; Tags.EVENT_REMOVE = 'remove'; Tags.EVENT_CHANGE = 'change'; var now = typeof window !== 'undefined' && window.performance && window.performance.now ? performance.now.bind(performance) : Date.now; function createURI(options) { var s = ''; if ((options.authority || options.scheme) && (options.host || options.hostpath)) { throw new Error('Can\'t have \'scheme\' or \'authority\' and \'host\' or \'hostpath\' option'); } if (options.host && options.hostpath) { throw new Error('Can\'t have \'host\' and \'hostpath\' option'); } if (options.path && options.hostpath) { throw new Error('Can\'t have \'path\' and \'hostpath\' option'); } if (options.scheme) { s += "" + options.scheme + ":"; } if (options.authority) { s += "//" + options.authority; } if (options.host) { s += options.host; } if (options.path) { s += options.path; } if (options.hostpath) { s += options.hostpath; } if (options.query) { s += "?" + options.query; } if (options.fragment) { s += "#" + options.fragment; } return s; } var re = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; class URI { toString() { var s = ''; if (this.scheme) { s += "" + this.scheme + ":"; } if (this.authority) { s += "//" + this.authority; } s += this.path; if (this.query) { s += "?" + this.query; } if (this.fragment) { s += "#" + this.fragment; } return s; } getQuery() { var result = {}; if (this.query) { var queryParams = decodeURIComponent(this.query).split('&'); for (var queryParam of queryParams){ var pair = queryParam.split('='); result[pair[0]] = pair[1]; } } return result; } setQuery(params) { var q = ''; for(var key in params){ if (params.hasOwnProperty(key)) { if (q !== '') { q += '&'; } q += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]); } } this.query = q; } constructor(uri){ var result = uri.match(re); this.scheme = result[2]; this.authority = result[4]; this.path = result[5]; this.query = result[7]; this.fragment = result[9]; } } class Tracing { static set(channel, enabled) { } static get(channel) { return Tracing._traceChannels.has(channel); } } Tracing._traceChannels = new Set(); Tracing.stack = false; var CURVE_LINEAR = 0; var CURVE_SMOOTHSTEP = 1; var CURVE_SPLINE = 4; var CURVE_STEP = 5; var math = { DEG_TO_RAD: Math.PI / 180, RAD_TO_DEG: 180 / Math.PI, clamp (value, min, max) { if (value >= max) return max; if (value <= min) return min; return value; }, intToBytes24 (i) { var r = i >> 16 & 0xff; var g = i >> 8 & 0xff; var b = i & 0xff; return [ r, g, b ]; }, intToBytes32 (i) { var r = i >> 24 & 0xff; var g = i >> 16 & 0xff; var b = i >> 8 & 0xff; var a = i & 0xff; return [ r, g, b, a ]; }, bytesToInt24 (r, g, b) { if (r.length) { b = r[2]; g = r[1]; r = r[0]; } return r << 16 | g << 8 | b; }, bytesToInt32 (r, g, b, a) { if (r.length) { a = r[3]; b = r[2]; g = r[1]; r = r[0]; } return (r << 24 | g << 16 | b << 8 | a) >>> 0; }, lerp (a, b, alpha) { return a + (b - a) * math.clamp(alpha, 0, 1); }, lerpAngle (a, b, alpha) { if (b - a > 180) { b -= 360; } if (b - a < -180) { b += 360; } return math.lerp(a, b, math.clamp(alpha, 0, 1)); }, powerOfTwo (x) { return x !== 0 && !(x & x - 1); }, nextPowerOfTwo (val) { val--; val |= val >> 1; val |= val >> 2; val |= val >> 4; val |= val >> 8; val |= val >> 16; val++; return val; }, nearestPowerOfTwo (val) { return Math.pow(2, Math.round(Math.log(val) / Math.log(2))); }, random (min, max) { var diff = max - min; return Math.random() * diff + min; }, smoothstep (min, max, x) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * (3 - 2 * x); }, smootherstep (min, max, x) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * x * (x * (x * 6 - 15) + 10); }, roundUp (numToRound, multiple) { if (multiple === 0) { return numToRound; } return Math.ceil(numToRound / multiple) * multiple; }, between (num, a, b, inclusive) { var min = Math.min(a, b); var max = Math.max(a, b); return inclusive ? num >= min && num <= max : num > min && num < max; } }; class Color { clone() { var cstr = this.constructor; return new cstr(this.r, this.g, this.b, this.a); } copy(rhs) { this.r = rhs.r; this.g = rhs.g; this.b = rhs.b; this.a = rhs.a; return this; } equals(rhs) { return this.r === rhs.r && this.g === rhs.g && this.b === rhs.b && this.a === rhs.a; } set(r, g, b, a) { if (a === undefined) a = 1; this.r = r; this.g = g; this.b = b; this.a = a; return this; } lerp(lhs, rhs, alpha) { this.r = lhs.r + alpha * (rhs.r - lhs.r); this.g = lhs.g + alpha * (rhs.g - lhs.g); this.b = lhs.b + alpha * (rhs.b - lhs.b); this.a = lhs.a + alpha * (rhs.a - lhs.a); return this; } linear(src) { if (src === undefined) src = this; this.r = Math.pow(src.r, 2.2); this.g = Math.pow(src.g, 2.2); this.b = Math.pow(src.b, 2.2); this.a = src.a; return this; } gamma(src) { if (src === undefined) src = this; this.r = Math.pow(src.r, 1 / 2.2); this.g = Math.pow(src.g, 1 / 2.2); this.b = Math.pow(src.b, 1 / 2.2); this.a = src.a; return this; } mulScalar(scalar) { this.r *= scalar; this.g *= scalar; this.b *= scalar; return this; } fromString(hex) { var i = parseInt(hex.replace('#', '0x'), 16); var bytes; if (hex.length > 7) { bytes = math.intToBytes32(i); } else { bytes = math.intToBytes24(i); bytes[3] = 255; } this.set(bytes[0] / 255, bytes[1] / 255, bytes[2] / 255, bytes[3] / 255); return this; } fromArray(arr, offset) { if (offset === undefined) offset = 0; var _arr_offset; this.r = (_arr_offset = arr[offset]) != null ? _arr_offset : this.r; var _arr_; this.g = (_arr_ = arr[offset + 1]) != null ? _arr_ : this.g; var _arr_1; this.b = (_arr_1 = arr[offset + 2]) != null ? _arr_1 : this.b; var _arr_2; this.a = (_arr_2 = arr[offset + 3]) != null ? _arr_2 : this.a; return this; } toString(alpha, asArray) { var { r, g, b, a } = this; if (asArray || r > 1 || g > 1 || b > 1) { return r.toFixed(3) + ", " + g.toFixed(3) + ", " + b.toFixed(3) + ", " + a.toFixed(3); } var s = "#" + ((1 << 24) + (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255)).toString(16).slice(1); if (alpha === true) { var aa = Math.round(a * 255).toString(16); if (this.a < 16 / 255) { s += "0" + aa; } else { s += aa; } } return s; } toArray(arr, offset, alpha) { if (arr === undefined) arr = []; if (offset === undefined) offset = 0; if (alpha === undefined) alpha = true; arr[offset] = this.r; arr[offset + 1] = this.g; arr[offset + 2] = this.b; if (alpha) { arr[offset + 3] = this.a; } return arr; } constructor(r = 0, g = 0, b = 0, a = 1){ var length = r.length; if (length === 3 || length === 4) { this.r = r[0]; this.g = r[1]; this.b = r[2]; var _r_; this.a = (_r_ = r[3]) != null ? _r_ : 1; } else { this.r = r; this.g = g; this.b = b; this.a = a; } } } Color.BLACK = Object.freeze(new Color(0, 0, 0, 1)); Color.BLUE = Object.freeze(new Color(0, 0, 1, 1)); Color.CYAN = Object.freeze(new Color(0, 1, 1, 1)); Color.GRAY = Object.freeze(new Color(0.5, 0.5, 0.5, 1)); Color.GREEN = Object.freeze(new Color(0, 1, 0, 1)); Color.MAGENTA = Object.freeze(new Color(1, 0, 1, 1)); Color.RED = Object.freeze(new Color(1, 0, 0, 1)); Color.WHITE = Object.freeze(new Color(1, 1, 1, 1)); Color.YELLOW = Object.freeze(new Color(1, 1, 0, 1)); class CurveEvaluator { evaluate(time, forceReset) { if (forceReset === undefined) forceReset = false; if (forceReset || time < this._left || time >= this._right) { this._reset(time); } var result; var type = this._curve.type; if (type === CURVE_STEP) { result = this._p0; } else { var t = this._recip === 0 ? 0 : (time - this._left) * this._recip; if (type === CURVE_LINEAR) { result = math.lerp(this._p0, this._p1, t); } else if (type === CURVE_SMOOTHSTEP) { result = math.lerp(this._p0, this._p1, t * t * (3 - 2 * t)); } else { result = this._evaluateHermite(this._p0, this._p1, this._m0, this._m1, t); } } return result; } _reset(time) { var keys = this._curve.keys; var len = keys.length; if (!len) { this._left = -Infinity; this._right = Infinity; this._recip = 0; this._p0 = this._p1 = this._m0 = this._m1 = 0; } else { if (time < keys[0][0]) { this._left = -Infinity; this._right = keys[0][0]; this._recip = 0; this._p0 = this._p1 = keys[0][1]; this._m0 = this._m1 = 0; } else if (time >= keys[len - 1][0]) { this._left = keys[len - 1][0]; this._right = Infinity; this._recip = 0; this._p0 = this._p1 = keys[len - 1][1]; this._m0 = this._m1 = 0; } else { var index = 0; while(time >= keys[index + 1][0]){ index++; } this._left = keys[index][0]; this._right = keys[index + 1][0]; var diff = 1.0 / (this._right - this._left); this._recip = isFinite(diff) ? diff : 0; this._p0 = keys[index][1]; this._p1 = keys[index + 1][1]; if (this._curve.type === CURVE_SPLINE) { this._calcTangents(keys, index); } } } } _calcTangents(keys, index) { var a; var b = keys[index]; var c = keys[index + 1]; var d; if (index === 0) { a = [ keys[0][0] + (keys[0][0] - keys[1][0]), keys[0][1] + (keys[0][1] - keys[1][1]) ]; } else { a = keys[index - 1]; } if (index === keys.length - 2) { d = [ keys[index + 1][0] + (keys[index + 1][0] - keys[index][0]), keys[index + 1][1] + (keys[index + 1][1] - keys[index][1]) ]; } else { d = keys[index + 2]; } if (this._curve.type === CURVE_SPLINE) { var s1_ = 2 * (c[0] - b[0]) / (c[0] - a[0]); var s2_ = 2 * (c[0] - b[0]) / (d[0] - b[0]); this._m0 = this._curve.tension * (isFinite(s1_) ? s1_ : 0) * (c[1] - a[1]); this._m1 = this._curve.tension * (isFinite(s2_) ? s2_ : 0) * (d[1] - b[1]); } else { var s1 = (c[0] - b[0]) / (b[0] - a[0]); var s2 = (c[0] - b[0]) / (d[0] - c[0]); var a_ = b[1] + (a[1] - b[1]) * (isFinite(s1) ? s1 : 0); var d_ = c[1] + (d[1] - c[1]) * (isFinite(s2) ? s2 : 0); var tension = this._curve.tension; this._m0 = tension * (c[1] - a_); this._m1 = tension * (d_ - b[1]); } } _evaluateHermite(p0, p1, m0, m1, t) { var t2 = t * t; var twot = t + t; var omt = 1 - t; var omt2 = omt * omt; return p0 * ((1 + twot) * omt2) + m0 * (t * omt2) + p1 * (t2 * (3 - twot)) + m1 * (t2 * (t - 1)); } constructor(curve, time = 0){ this._left = -Infinity; this._right = Infinity; this._recip = 0; this._p0 = 0; this._p1 = 0; this._m0 = 0; this._m1 = 0; this._curve = curve; this._reset(time); } } class Curve { get length() { return this.keys.length; } add(time, value) { var keys = this.keys; var len = keys.length; var i = 0; for(; i < len; i++){ if (keys[i][0] > time) { break; } } var key = [ time, value ]; this.keys.splice(i, 0, key); return key; } get(index) { return this.keys[index]; } sort() { this.keys.sort((a, b)=>a[0] - b[0]); } value(time) { return this._eval.evaluate(time, true); } closest(time) { var keys = this.keys; var length = keys.length; var min = 2; var result = null; for(var i = 0; i < length; i++){ var diff = Math.abs(time - keys[i][0]); if (min >= diff) { min = diff; result = keys[i]; } else { break; } } return result; } clone() { var result = new this.constructor(); result.keys = this.keys.map((key)=>[ ...key ]); result.type = this.type; result.tension = this.tension; return result; } quantize(precision) { precision = Math.max(precision, 2); var values = new Float32Array(precision); var step = 1.0 / (precision - 1); values[0] = this._eval.evaluate(0, true); for(var i = 1; i < precision; i++){ values[i] = this._eval.evaluate(step * i); } return values; } quantizeClamped(precision, min, max) { var result = this.quantize(precision); for(var i = 0; i < result.length; ++i){ result[i] = Math.min(max, Math.max(min, result[i])); } return result; } constructor(data){ this.keys = []; this.type = CURVE_SMOOTHSTEP; this.tension = 0.5; this._eval = new CurveEvaluator(this); if (data) { for(var i = 0; i < data.length - 1; i += 2){ this.keys.push([ data[i], data[i + 1] ]); } } this.sort(); } } class CurveSet { get length() { return this.curves.length; } set type(value) { this._type = value; for(var i = 0; i < this.curves.length; i++){ this.curves[i].type = value; } } get type() { return this._type; } get(index) { return this.curves[index]; } value(time, result) { if (result === undefined) result = []; var length = this.curves.length; result.length = length; for(var i = 0; i < length; i++){ result[i] = this.curves[i].value(time); } return result; } clone() { var result = new this.constructor(); result.curves = []; for(var i = 0; i < this.curves.length; i++){ result.curves.push(this.curves[i].clone()); } result._type = this._type; return result; } quantize(precision) { precision = Math.max(precision, 2); var numCurves = this.curves.length; var values = new Float32Array(precision * numCurves); var step = 1.0 / (precision - 1); for(var c = 0; c < numCurves; c++){ var ev = new CurveEvaluator(this.curves[c]); for(var i = 0; i < precision; i++){ values[i * numCurves + c] = ev.evaluate(step * i); } } return values; } quantizeClamped(precision, min, max) { var result = this.quantize(precision); for(var i = 0; i < result.length; ++i){ result[i] = Math.min(max, Math.max(min, result[i])); } return result; } constructor(){ this.curves = []; this._type = CURVE_SMOOTHSTEP; if (arguments.length > 1) { for(var i = 0; i < arguments.length; i++){ this.curves.push(new Curve(arguments[i])); } } else { if (arguments.length === 0) { this.curves.push(new Curve()); } else { var arg = arguments[0]; if (typeof arg === 'number') { for(var i1 = 0; i1 < arg; i1++){ this.curves.push(new Curve()); } } else { for(var i2 = 0; i2 < arg.length; i2++){ this.curves.push(new Curve(arg[i2])); } } } } } } var oneDiv255 = 1 / 255; var floatView = new Float32Array(1); var int32View = new Int32Array(floatView.buffer); class FloatPacking { static float2Half(value) { floatView[0] = value; var x = int32View[0]; var bits = x >> 16 & 0x8000; var m = x >> 12 & 0x07ff; var e = x >> 23 & 0xff; if (e < 103) { return bits; } if (e > 142) { bits |= 0x7c00; bits |= (e === 255 ? 0 : 1) && x & 0x007fffff; return bits; } if (e < 113) { m |= 0x0800; bits |= (m >> 114 - e) + (m >> 113 - e & 1); return bits; } bits |= e - 112 << 10 | m >> 1; bits += m & 1; return bits; } static float2Bytes(value, array, offset, numBytes) { var enc1 = 255.0 * value % 1; array[offset + 0] = Math.round((value % 1 - oneDiv255 * enc1) * 255); if (numBytes > 1) { var enc2 = 65025.0 * value % 1; array[offset + 1] = Math.round((enc1 - oneDiv255 * enc2) * 255); if (numBytes > 2) { var enc3 = 16581375.0 * value % 1; array[offset + 2] = Math.round((enc2 - oneDiv255 * enc3) * 255); if (numBytes > 3) { array[offset + 3] = Math.round(enc3 * 255); } } } } static float2BytesRange(value, array, offset, min, max, numBytes) { value = math.clamp((value - min) / (max - min), 0, 1); FloatPacking.float2Bytes(value, array, offset, numBytes); } static float2RGBA8(value, data) { floatView[0] = value; var intBits = int32View[0]; data.r = (intBits >> 24 & 0xFF) / 255.0; data.g = (intBits >> 16 & 0xFF) / 255.0; data.b = (intBits >> 8 & 0xFF) / 255.0; data.a = (intBits & 0xFF) / 255.0; } } class Kernel { static concentric(numRings, numPoints) { var kernel = []; kernel.push(0, 0); var spacing = 2 * Math.PI / numRings / numPoints; for(var ring = 1; ring <= numRings; ring++){ var radius = ring / numRings; var circumference = 2 * Math.PI * radius; var pointsPerRing = Math.max(1, Math.floor(circumference / spacing)); var angleStep = 2 * Math.PI / pointsPerRing; for(var point = 0; point < pointsPerRing; point++){ var angle = point * angleStep; var x = radius * Math.cos(angle); var y = radius * Math.sin(angle); kernel.push(x, y); } } return kernel; } } class Vec3 { add(rhs) { this.x += rhs.x; this.y += rhs.y; this.z += rhs.z; return this; } add2(lhs, rhs) { this.x = lhs.x + rhs.x; this.y = lhs.y + rhs.y; this.z = lhs.z + rhs.z; return this; } addScalar(scalar) { this.x += scalar; this.y += scalar; this.z += scalar; return this; } addScaled(rhs, scalar) { this.x += rhs.x * scalar; this.y += rhs.y * scalar; this.z += rhs.z * scalar; return this; } clone() { var cstr = this.constructor; return new cstr(this.x, this.y, this.z); } copy(rhs) { this.x = rhs.x; this.y = rhs.y; this.z = rhs.z; return this; } cross(lhs, rhs) { var lx = lhs.x; var ly = lhs.y; var lz = lhs.z; var rx = rhs.x; var ry = rhs.y; var rz = rhs.z; this.x = ly * rz - ry * lz; this.y = lz * rx - rz * lx; this.z = lx * ry - rx * ly; return this; } distance(rhs) { var x = this.x - rhs.x; var y = this.y - rhs.y; var z = this.z - rhs.z; return Math.sqrt(x * x + y * y + z * z); } div(rhs) { this.x /= rhs.x; this.y /= rhs.y; this.z /= rhs.z; return this; } div2(lhs, rhs) { this.x = lhs.x / rhs.x; this.y = lhs.y / rhs.y; this.z = lhs.z / rhs.z; return this; } divScalar(scalar) { this.x /= scalar; this.y /= scalar; this.z /= scalar; return this; } dot(rhs) { return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z; } equals(rhs) { return this.x === rhs.x && this.y === rhs.y && this.z === rhs.z; } equalsApprox(rhs, epsilon) { if (epsilon === undefined) epsilon = 1e-6; return Math.abs(this.x - rhs.x) < epsilon && Math.abs(this.y - rhs.y) < epsilon && Math.abs(this.z - rhs.z) < epsilon; } length() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); } lengthSq() { return this.x * this.x + this.y * this.y + this.z * this.z; } lerp(lhs, rhs, alpha) { this.x = lhs.x + alpha * (rhs.x - lhs.x); this.y = lhs.y + alpha * (rhs.y - lhs.y); this.z = lhs.z + alpha * (rhs.z - lhs.z); return this; } mul(rhs) { this.x *= rhs.x; this.y *= rhs.y; this.z *= rhs.z; return this; } mul2(lhs, rhs) { this.x = lhs.x * rhs.x; this.y = lhs.y * rhs.y; this.z = lhs.z * rhs.z; return this; } mulScalar(scalar) { this.x *= scalar; this.y *= scalar; this.z *= scalar; return this; } normalize(src) { if (src === undefined) src = this; var lengthSq = src.x * src.x + src.y * src.y + src.z * src.z; if (lengthSq > 0) { var invLength = 1 / Math.sqrt(lengthSq); this.x = src.x * invLength; this.y = src.y * invLength; this.z = src.z * invLength; } return this; } floor(src) { if (src === undefined) src = this; this.x = Math.floor(src.x); this.y = Math.floor(src.y); this.z = Math.floor(src.z); return this; } ceil(src) { if (src === undefined) src = this; this.x = Math.ceil(src.x); this.y = Math.ceil(src.y); this.z = Math.ceil(src.z); return this; } round(src) { if (src === undefined) src = this; this.x = Math.round(src.x); this.y = Math.round(src.y); this.z = Math.round(src.z); return this; } min(rhs) { if (rhs.x < this.x) this.x = rhs.x; if (rhs.y < this.y) this.y = rhs.y; if (rhs.z < this.z) this.z = rhs.z; return this; } max(rhs) { if (rhs.x > this.x) this.x = rhs.x; if (rhs.y > this.y) this.y = rhs.y; if (rhs.z > this.z) this.z = rhs.z; return this; } project(rhs) { var a_dot_b = this.x * rhs.x + this.y * rhs.y + this.z * rhs.z; var b_dot_b = rhs.x * rhs.x + rhs.y * rhs.y + rhs.z * rhs.z; var s = a_dot_b / b_dot_b; this.x = rhs.x * s; this.y = rhs.y * s; this.z = rhs.z * s; return this; } set(x, y, z) { this.x = x; this.y = y; this.z = z; return this; } sub(rhs) { this.x -= rhs.x; this.y -= rhs.y; this.z -= rhs.z; return this; } sub2(lhs, rhs) { this.x = lhs.x - rhs.x; this.y = lhs.y - rhs.y; this.z = lhs.z - rhs.z; return this; } subScalar(scalar) { this.x -= scalar; this.y -= scalar; this.z -= scalar;