playcanvas
Version:
PlayCanvas WebGL game engine
1,865 lines (1,840 loc) • 2.9 MB
JavaScript
/**
* @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;