UNPKG

@google/model-viewer

Version:

Easily display interactive 3D models on the web and in AR!

1,596 lines (1,592 loc) 2.29 MB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ModelViewerElement = {})); })(this, (function (exports) { 'use strict'; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const t$2 = globalThis, e$2 = t$2.ShadowRoot && (void 0 === t$2.ShadyCSS || t$2.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$1 = Symbol(), o$3 = new WeakMap; let n$4 = class n { get styleSheet() { let t = this.o; const s = this.t; if (e$2 && void 0 === t) { const e = void 0 !== s && 1 === s.length; e && (t = o$3.get(s)), void 0 === t && ((this.o = t = new CSSStyleSheet).replaceSync(this.cssText), e && o$3.set(s, t)); } return t; } toString() { return this.cssText; } constructor(t, e, o){ if (this._$cssResult$ = true, o !== s$1) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); this.cssText = t, this.t = e; } }; const r$4 = (t)=>new n$4("string" == typeof t ? t : t + "", void 0, s$1), S$1 = (s, o)=>{ if (e$2) s.adoptedStyleSheets = o.map((t)=>t instanceof CSSStyleSheet ? t : t.styleSheet); else for (const e of o){ const o = document.createElement("style"), n = t$2.litNonce; void 0 !== n && o.setAttribute("nonce", n), o.textContent = e.cssText, s.appendChild(o); } }, c$3 = e$2 ? (t)=>t : (t)=>t instanceof CSSStyleSheet ? ((t)=>{ let e = ""; for (const s of t.cssRules)e += s.cssText; return r$4(e); })(t) : t; var _Symbol, _a$a, _a1; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const { is: i$3, defineProperty: e$1, getOwnPropertyDescriptor: r$3, getOwnPropertyNames: h$1, getOwnPropertySymbols: o$2, getPrototypeOf: n$3 } = Object, a$2 = globalThis, c$2 = a$2.trustedTypes, l$1 = c$2 ? c$2.emptyScript : "", p$1 = a$2.reactiveElementPolyfillSupport, d$1 = (t, s)=>t, u$2 = { toAttribute (t, s) { switch(s){ case Boolean: t = t ? l$1 : null; break; case Object: case Array: t = null == t ? t : JSON.stringify(t); } return t; }, fromAttribute (t, s) { let i = t; switch(s){ case Boolean: i = null !== t; break; case Number: i = null === t ? null : Number(t); break; case Object: case Array: try { i = JSON.parse(t); } catch (t) { i = null; } } return i; } }, f$1 = (t, s)=>!i$3(t, s), y$1 = { attribute: true, type: String, converter: u$2, reflect: false, hasChanged: f$1 }; (_Symbol = Symbol).metadata ?? (_Symbol.metadata = Symbol("metadata")), (_a$a = a$2).litPropertyMetadata ?? (_a$a.litPropertyMetadata = new WeakMap); let b$1 = class b extends HTMLElement { static addInitializer(t) { this._$Ei(), (this.l ?? (this.l = [])).push(t); } static get observedAttributes() { return this.finalize(), this._$Eh && [ ...this._$Eh.keys() ]; } static createProperty(t, s = y$1) { if (s.state && (s.attribute = false), this._$Ei(), this.elementProperties.set(t, s), !s.noAccessor) { const i = Symbol(), r = this.getPropertyDescriptor(t, i, s); void 0 !== r && e$1(this.prototype, t, r); } } static getPropertyDescriptor(t, s, i) { const { get: e, set: h } = r$3(this.prototype, t) ?? { get () { return this[s]; }, set (t) { this[s] = t; } }; return { get () { return e?.call(this); }, set (s) { const r = e?.call(this); h.call(this, s), this.requestUpdate(t, r, i); }, configurable: true, enumerable: true }; } static getPropertyOptions(t) { return this.elementProperties.get(t) ?? y$1; } static _$Ei() { if (this.hasOwnProperty(d$1("elementProperties"))) return; const t = n$3(this); t.finalize(), void 0 !== t.l && (this.l = [ ...t.l ]), this.elementProperties = new Map(t.elementProperties); } static finalize() { if (this.hasOwnProperty(d$1("finalized"))) return; if (this.finalized = true, this._$Ei(), this.hasOwnProperty(d$1("properties"))) { const t = this.properties, s = [ ...h$1(t), ...o$2(t) ]; for (const i of s)this.createProperty(i, t[i]); } const t = this[Symbol.metadata]; if (null !== t) { const s = litPropertyMetadata.get(t); if (void 0 !== s) for (const [t, i] of s)this.elementProperties.set(t, i); } this._$Eh = new Map; for (const [t, s] of this.elementProperties){ const i = this._$Eu(t, s); void 0 !== i && this._$Eh.set(i, t); } this.elementStyles = this.finalizeStyles(this.styles); } static finalizeStyles(s) { const i = []; if (Array.isArray(s)) { const e = new Set(s.flat(1 / 0).reverse()); for (const s of e)i.unshift(c$3(s)); } else void 0 !== s && i.push(c$3(s)); return i; } static _$Eu(t, s) { const i = s.attribute; return false === i ? void 0 : "string" == typeof i ? i : "string" == typeof t ? t.toLowerCase() : void 0; } _$Ev() { this._$ES = new Promise((t)=>this.enableUpdating = t), this._$AL = new Map, this._$E_(), this.requestUpdate(), this.constructor.l?.forEach((t)=>t(this)); } addController(t) { (this._$EO ?? (this._$EO = new Set)).add(t), void 0 !== this.renderRoot && this.isConnected && t.hostConnected?.(); } removeController(t) { this._$EO?.delete(t); } _$E_() { const t = new Map, s = this.constructor.elementProperties; for (const i of s.keys())this.hasOwnProperty(i) && (t.set(i, this[i]), delete this[i]); t.size > 0 && (this._$Ep = t); } createRenderRoot() { const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); return S$1(t, this.constructor.elementStyles), t; } connectedCallback() { this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(true), this._$EO?.forEach((t)=>t.hostConnected?.()); } enableUpdating(t) {} disconnectedCallback() { this._$EO?.forEach((t)=>t.hostDisconnected?.()); } attributeChangedCallback(t, s, i) { this._$AK(t, i); } _$EC(t, s) { const i = this.constructor.elementProperties.get(t), e = this.constructor._$Eu(t, i); if (void 0 !== e && true === i.reflect) { const r = (void 0 !== i.converter?.toAttribute ? i.converter : u$2).toAttribute(s, i.type); this._$Em = t, null == r ? this.removeAttribute(e) : this.setAttribute(e, r), this._$Em = null; } } _$AK(t, s) { const i = this.constructor, e = i._$Eh.get(t); if (void 0 !== e && this._$Em !== e) { const t = i.getPropertyOptions(e), r = "function" == typeof t.converter ? { fromAttribute: t.converter } : void 0 !== t.converter?.fromAttribute ? t.converter : u$2; this._$Em = e, this[e] = r.fromAttribute(s, t.type), this._$Em = null; } } requestUpdate(t, s, i) { if (void 0 !== t) { if (i ?? (i = this.constructor.getPropertyOptions(t)), !(i.hasChanged ?? f$1)(this[t], s)) return; this.P(t, s, i); } false === this.isUpdatePending && (this._$ES = this._$ET()); } P(t, s, i) { this._$AL.has(t) || this._$AL.set(t, s), true === i.reflect && this._$Em !== t && (this._$Ej ?? (this._$Ej = new Set)).add(t); } async _$ET() { this.isUpdatePending = true; try { await this._$ES; } catch (t) { Promise.reject(t); } const t = this.scheduleUpdate(); return null != t && await t, !this.isUpdatePending; } scheduleUpdate() { return this.performUpdate(); } performUpdate() { if (!this.isUpdatePending) return; if (!this.hasUpdated) { if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) { for (const [t, s] of this._$Ep)this[t] = s; this._$Ep = void 0; } const t = this.constructor.elementProperties; if (t.size > 0) for (const [s, i] of t) true !== i.wrapped || this._$AL.has(s) || void 0 === this[s] || this.P(s, this[s], i); } let t = false; const s = this._$AL; try { t = this.shouldUpdate(s), t ? (this.willUpdate(s), this._$EO?.forEach((t)=>t.hostUpdate?.()), this.update(s)) : this._$EU(); } catch (s) { throw t = false, this._$EU(), s; } t && this._$AE(s); } willUpdate(t) {} _$AE(t) { this._$EO?.forEach((t)=>t.hostUpdated?.()), this.hasUpdated || (this.hasUpdated = true, this.firstUpdated(t)), this.updated(t); } _$EU() { this._$AL = new Map, this.isUpdatePending = false; } get updateComplete() { return this.getUpdateComplete(); } getUpdateComplete() { return this._$ES; } shouldUpdate(t) { return true; } update(t) { this._$Ej && (this._$Ej = this._$Ej.forEach((t)=>this._$EC(t, this[t]))), this._$EU(); } updated(t) {} firstUpdated(t) {} constructor(){ super(), this._$Ep = void 0, this.isUpdatePending = false, this.hasUpdated = false, this._$Em = null, this._$Ev(); } }; b$1.elementStyles = [], b$1.shadowRootOptions = { mode: "open" }, b$1[d$1("elementProperties")] = new Map, b$1[d$1("finalized")] = new Map, p$1?.({ ReactiveElement: b$1 }), ((_a1 = a$2).reactiveElementVersions ?? (_a1.reactiveElementVersions = [])).push("2.0.4"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const o$1 = { attribute: true, type: String, converter: u$2, reflect: false, hasChanged: f$1 }, r$2 = (t = o$1, e, r)=>{ const { kind: n, metadata: i } = r; let s = globalThis.litPropertyMetadata.get(i); if (void 0 === s && globalThis.litPropertyMetadata.set(i, s = new Map), s.set(r.name, t), "accessor" === n) { const { name: o } = r; return { set (r) { const n = e.get.call(this); e.set.call(this, r), this.requestUpdate(o, n, t); }, init (e) { return void 0 !== e && this.P(o, void 0, t), e; } }; } if ("setter" === n) { const { name: o } = r; return function(r) { const n = this[o]; e.call(this, r), this.requestUpdate(o, n, t); }; } throw Error("Unsupported decorator location: " + n); }; function n$2(t) { return (e, o)=>"object" == typeof o ? r$2(t, e, o) : ((t, e, o)=>{ const r = e.hasOwnProperty(o); return e.constructor.createProperty(o, r ? { ...t, wrapped: true } : t), r ? Object.getOwnPropertyDescriptor(e, o) : void 0; })(t, e, o); } /** * @license * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ const REVISION = '174'; const CullFaceNone = 0; const CullFaceBack = 1; const CullFaceFront = 2; const PCFShadowMap = 1; const PCFSoftShadowMap = 2; const VSMShadowMap = 3; const FrontSide = 0; const BackSide = 1; const DoubleSide = 2; const NoBlending = 0; const NormalBlending = 1; const AdditiveBlending = 2; const SubtractiveBlending = 3; const MultiplyBlending = 4; const CustomBlending = 5; const AddEquation = 100; const SubtractEquation = 101; const ReverseSubtractEquation = 102; const MinEquation = 103; const MaxEquation = 104; const ZeroFactor = 200; const OneFactor = 201; const SrcColorFactor = 202; const OneMinusSrcColorFactor = 203; const SrcAlphaFactor = 204; const OneMinusSrcAlphaFactor = 205; const DstAlphaFactor = 206; const OneMinusDstAlphaFactor = 207; const DstColorFactor = 208; const OneMinusDstColorFactor = 209; const SrcAlphaSaturateFactor = 210; const ConstantColorFactor = 211; const OneMinusConstantColorFactor = 212; const ConstantAlphaFactor = 213; const OneMinusConstantAlphaFactor = 214; const NeverDepth = 0; const AlwaysDepth = 1; const LessDepth = 2; const LessEqualDepth = 3; const EqualDepth = 4; const GreaterEqualDepth = 5; const GreaterDepth = 6; const NotEqualDepth = 7; const MultiplyOperation = 0; const MixOperation = 1; const AddOperation = 2; const NoToneMapping = 0; const LinearToneMapping = 1; const ReinhardToneMapping = 2; const CineonToneMapping = 3; const ACESFilmicToneMapping = 4; const CustomToneMapping = 5; const AgXToneMapping = 6; const NeutralToneMapping = 7; const AttachedBindMode = 'attached'; const DetachedBindMode = 'detached'; const UVMapping = 300; const CubeReflectionMapping = 301; const CubeRefractionMapping = 302; const EquirectangularReflectionMapping = 303; const EquirectangularRefractionMapping = 304; const CubeUVReflectionMapping = 306; const RepeatWrapping = 1000; const ClampToEdgeWrapping = 1001; const MirroredRepeatWrapping = 1002; const NearestFilter = 1003; const NearestMipmapNearestFilter = 1004; const NearestMipmapLinearFilter = 1005; const LinearFilter = 1006; const LinearMipmapNearestFilter = 1007; const LinearMipmapLinearFilter = 1008; const LinearMipMapLinearFilter = 1008; const UnsignedByteType = 1009; const ByteType = 1010; const ShortType = 1011; const UnsignedShortType = 1012; const IntType = 1013; const UnsignedIntType = 1014; const FloatType = 1015; const HalfFloatType = 1016; const UnsignedShort4444Type = 1017; const UnsignedShort5551Type = 1018; const UnsignedInt248Type = 1020; const UnsignedInt5999Type = 35902; const AlphaFormat = 1021; const RGBFormat = 1022; const RGBAFormat = 1023; const LuminanceFormat = 1024; const LuminanceAlphaFormat = 1025; const DepthFormat = 1026; const DepthStencilFormat = 1027; const RedFormat = 1028; const RedIntegerFormat = 1029; const RGFormat = 1030; const RGIntegerFormat = 1031; const RGBAIntegerFormat = 1033; const RGB_S3TC_DXT1_Format = 33776; const RGBA_S3TC_DXT1_Format = 33777; const RGBA_S3TC_DXT3_Format = 33778; const RGBA_S3TC_DXT5_Format = 33779; const RGB_PVRTC_4BPPV1_Format = 35840; const RGB_PVRTC_2BPPV1_Format = 35841; const RGBA_PVRTC_4BPPV1_Format = 35842; const RGBA_PVRTC_2BPPV1_Format = 35843; const RGB_ETC1_Format = 36196; const RGB_ETC2_Format = 37492; const RGBA_ETC2_EAC_Format = 37496; const RGBA_ASTC_4x4_Format = 37808; const RGBA_ASTC_5x4_Format = 37809; const RGBA_ASTC_5x5_Format = 37810; const RGBA_ASTC_6x5_Format = 37811; const RGBA_ASTC_6x6_Format = 37812; const RGBA_ASTC_8x5_Format = 37813; const RGBA_ASTC_8x6_Format = 37814; const RGBA_ASTC_8x8_Format = 37815; const RGBA_ASTC_10x5_Format = 37816; const RGBA_ASTC_10x6_Format = 37817; const RGBA_ASTC_10x8_Format = 37818; const RGBA_ASTC_10x10_Format = 37819; const RGBA_ASTC_12x10_Format = 37820; const RGBA_ASTC_12x12_Format = 37821; const RGBA_BPTC_Format = 36492; const RGB_BPTC_SIGNED_Format = 36494; const RGB_BPTC_UNSIGNED_Format = 36495; const RED_RGTC1_Format = 36283; const SIGNED_RED_RGTC1_Format = 36284; const RED_GREEN_RGTC2_Format = 36285; const SIGNED_RED_GREEN_RGTC2_Format = 36286; const LoopOnce = 2200; const LoopRepeat = 2201; const LoopPingPong = 2202; const InterpolateDiscrete = 2300; const InterpolateLinear = 2301; const InterpolateSmooth = 2302; const ZeroCurvatureEnding = 2400; const ZeroSlopeEnding = 2401; const WrapAroundEnding = 2402; const NormalAnimationBlendMode = 2500; const AdditiveAnimationBlendMode = 2501; const TrianglesDrawMode = 0; const TriangleStripDrawMode = 1; const TriangleFanDrawMode = 2; const BasicDepthPacking = 3200; const RGBADepthPacking = 3201; const TangentSpaceNormalMap = 0; const ObjectSpaceNormalMap = 1; // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. const NoColorSpace = ''; const SRGBColorSpace = 'srgb'; const LinearSRGBColorSpace = 'srgb-linear'; const LinearTransfer = 'linear'; const SRGBTransfer = 'srgb'; const KeepStencilOp = 7680; const AlwaysStencilFunc = 519; const NeverCompare = 512; const LessCompare = 513; const EqualCompare = 514; const LessEqualCompare = 515; const GreaterCompare = 516; const NotEqualCompare = 517; const GreaterEqualCompare = 518; const AlwaysCompare = 519; const StaticDrawUsage = 35044; const GLSL3 = '300 es'; const WebGLCoordinateSystem = 2000; const WebGPUCoordinateSystem = 2001; /** * This modules allows to dispatch event objects on custom JavaScript objects. * * Main repository: [eventdispatcher.js]{@link https://github.com/mrdoob/eventdispatcher.js/} * * Code Example: * ```js * class Car extends EventDispatcher { * start() { * this.dispatchEvent( { type: 'start', message: 'vroom vroom!' } ); * } *}; * * // Using events with the custom object * const car = new Car(); * car.addEventListener( 'start', function ( event ) { * alert( event.message ); * } ); * * car.start(); * ``` */ class EventDispatcher { /** * Adds the given event listener to the given event type. * * @param {string} type - The type of event to listen to. * @param {Function} listener - The function that gets called when the event is fired. */ addEventListener(type, listener) { if (this._listeners === undefined) this._listeners = {}; const listeners = this._listeners; if (listeners[type] === undefined) { listeners[type] = []; } if (listeners[type].indexOf(listener) === -1) { listeners[type].push(listener); } } /** * Returns `true` if the given event listener has been added to the given event type. * * @param {string} type - The type of event. * @param {Function} listener - The listener to check. * @return {boolean} Whether the given event listener has been added to the given event type. */ hasEventListener(type, listener) { const listeners = this._listeners; if (listeners === undefined) return false; return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1; } /** * Removes the given event listener from the given event type. * * @param {string} type - The type of event. * @param {Function} listener - The listener to remove. */ removeEventListener(type, listener) { const listeners = this._listeners; if (listeners === undefined) return; const listenerArray = listeners[type]; if (listenerArray !== undefined) { const index = listenerArray.indexOf(listener); if (index !== -1) { listenerArray.splice(index, 1); } } } /** * Dispatches an event object. * * @param {Object} event - The event that gets fired. */ dispatchEvent(event) { const listeners = this._listeners; if (listeners === undefined) return; const listenerArray = listeners[event.type]; if (listenerArray !== undefined) { event.target = this; // Make a copy, in case listeners are removed while iterating. const array = listenerArray.slice(0); for(let i = 0, l = array.length; i < l; i++){ array[i].call(this, event); } event.target = null; } } } const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; let _seed = 1234567; const DEG2RAD = Math.PI / 180; const RAD2DEG = 180 / Math.PI; /** * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} * (universally unique identifier). * * @return {string} The UUID. */ function generateUUID() { // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 const d0 = Math.random() * 0xffffffff | 0; const d1 = Math.random() * 0xffffffff | 0; const d2 = Math.random() * 0xffffffff | 0; const d3 = Math.random() * 0xffffffff | 0; const uuid = _lut[d0 & 0xff] + _lut[d0 >> 8 & 0xff] + _lut[d0 >> 16 & 0xff] + _lut[d0 >> 24 & 0xff] + '-' + _lut[d1 & 0xff] + _lut[d1 >> 8 & 0xff] + '-' + _lut[d1 >> 16 & 0x0f | 0x40] + _lut[d1 >> 24 & 0xff] + '-' + _lut[d2 & 0x3f | 0x80] + _lut[d2 >> 8 & 0xff] + '-' + _lut[d2 >> 16 & 0xff] + _lut[d2 >> 24 & 0xff] + _lut[d3 & 0xff] + _lut[d3 >> 8 & 0xff] + _lut[d3 >> 16 & 0xff] + _lut[d3 >> 24 & 0xff]; // .toLowerCase() here flattens concatenated strings to save heap memory space. return uuid.toLowerCase(); } /** * Clamps the given value between min and max. * * @param {number} value - The value to clamp. * @param {number} min - The min value. * @param {number} max - The max value. * @return {number} The clamped value. */ function clamp$1(value, min, max) { return Math.max(min, Math.min(max, value)); } /** * Computes the Euclidean modulo of the given parameters that * is `( ( n % m ) + m ) % m`. * * @param {number} n - The first parameter. * @param {number} m - The second parameter. * @return {number} The Euclidean modulo. */ function euclideanModulo(n, m) { // https://en.wikipedia.org/wiki/Modulo_operation return (n % m + m) % m; } /** * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>` * for the given value. * * @param {number} x - The value to be mapped. * @param {number} a1 - Minimum value for range A. * @param {number} a2 - Maximum value for range A. * @param {number} b1 - Minimum value for range B. * @param {number} b2 - Maximum value for range B. * @return {number} The mapped value. */ function mapLinear(x, a1, a2, b1, b2) { return b1 + (x - a1) * (b2 - b1) / (a2 - a1); } /** * Returns the percentage in the closed interval `[0, 1]` of the given value * between the start and end point. * * @param {number} x - The start point * @param {number} y - The end point. * @param {number} value - A value between start and end. * @return {number} The interpolation factor. */ function inverseLerp(x, y, value) { // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ if (x !== y) { return (value - x) / (y - x); } else { return 0; } } /** * Returns a value linearly interpolated from two known points based on the given interval - * `t = 0` will return `x` and `t = 1` will return `y`. * * @param {number} x - The start point * @param {number} y - The end point. * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. * @return {number} The interpolated value. */ function lerp$1(x, y, t) { return (1 - t) * x + t * y; } /** * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta * time to maintain frame rate independent movement. For details, see * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}. * * @param {number} x - The current point. * @param {number} y - The target point. * @param {number} lambda - A higher lambda value will make the movement more sudden, * and a lower value will make the movement more gradual. * @param {number} dt - Delta time in seconds. * @return {number} The interpolated value. */ function damp(x, y, lambda, dt) { return lerp$1(x, y, 1 - Math.exp(-lambda * dt)); } /** * Returns a value that alternates between `0` and the given `length` parameter. * * @param {number} x - The value to pingpong. * @param {number} [length=1] - The positive value the function will pingpong to. * @return {number} The alternated value. */ function pingpong(x, length = 1) { // https://www.desmos.com/calculator/vcsjnyz7x4 return length - Math.abs(euclideanModulo(x, length * 2) - length); } /** * Returns a value in the range `[0,1]` that represents the percentage that `x` has * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to * the `min` and `max`. * * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details. * * @param {number} x - The value to evaluate based on its position between min and max. * @param {number} min - The min value. Any x value below min will be `0`. * @param {number} max - The max value. Any x value above max will be `1`. * @return {number} The alternated value. */ function smoothstep(x, min, max) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * (3 - 2 * x); } /** * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations} * that has zero 1st and 2nd order derivatives at x=0 and x=1. * * @param {number} x - The value to evaluate based on its position between min and max. * @param {number} min - The min value. Any x value below min will be `0`. * @param {number} max - The max value. Any x value above max will be `1`. * @return {number} The alternated value. */ function smootherstep(x, min, max) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * x * (x * (x * 6 - 15) + 10); } /** * Returns a random integer from `<low, high>` interval. * * @param {number} low - The lower value boundary. * @param {number} high - The upper value boundary * @return {number} A random integer. */ function randInt(low, high) { return low + Math.floor(Math.random() * (high - low + 1)); } /** * Returns a random float from `<low, high>` interval. * * @param {number} low - The lower value boundary. * @param {number} high - The upper value boundary * @return {number} A random float. */ function randFloat(low, high) { return low + Math.random() * (high - low); } /** * Returns a random integer from `<-range/2, range/2>` interval. * * @param {number} range - Defines the value range. * @return {number} A random float. */ function randFloatSpread(range) { return range * (0.5 - Math.random()); } /** * Returns a deterministic pseudo-random float in the interval `[0, 1]`. * * @param {number} [s] - The integer seed. * @return {number} A random float. */ function seededRandom(s) { if (s !== undefined) _seed = s; // Mulberry32 generator let t = _seed += 0x6D2B79F5; t = Math.imul(t ^ t >>> 15, t | 1); t ^= t + Math.imul(t ^ t >>> 7, t | 61); return ((t ^ t >>> 14) >>> 0) / 4294967296; } /** * Converts degrees to radians. * * @param {number} degrees - A value in degrees. * @return {number} The converted value in radians. */ function degToRad(degrees) { return degrees * DEG2RAD; } /** * Converts radians to degrees. * * @param {number} radians - A value in radians. * @return {number} The converted value in degrees. */ function radToDeg(radians) { return radians * RAD2DEG; } /** * Returns `true` if the given number is a power of two. * * @param {number} value - The value to check. * @return {boolean} Whether the given number is a power of two or not. */ function isPowerOfTwo(value) { return (value & value - 1) === 0 && value !== 0; } /** * Returns the smallest power of two that is greater than or equal to the given number. * * @param {number} value - The value to find a POT for. * @return {number} The smallest power of two that is greater than or equal to the given number. */ function ceilPowerOfTwo(value) { return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2)); } /** * Returns the largest power of two that is less than or equal to the given number. * * @param {number} value - The value to find a POT for. * @return {number} The largest power of two that is less than or equal to the given number. */ function floorPowerOfTwo(value) { return Math.pow(2, Math.floor(Math.log(value) / Math.LN2)); } /** * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles} * defined by the given angles and order. * * Rotations are applied to the axes in the order specified by order: * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`. * * @param {Quaternion} q - The quaternion to set. * @param {number} a - The rotation applied to the first axis, in radians. * @param {number} b - The rotation applied to the second axis, in radians. * @param {number} c - The rotation applied to the third axis, in radians. * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order. */ function setQuaternionFromProperEuler(q, a, b, c, order) { const cos = Math.cos; const sin = Math.sin; const c2 = cos(b / 2); const s2 = sin(b / 2); const c13 = cos((a + c) / 2); const s13 = sin((a + c) / 2); const c1_3 = cos((a - c) / 2); const s1_3 = sin((a - c) / 2); const c3_1 = cos((c - a) / 2); const s3_1 = sin((c - a) / 2); switch(order){ case 'XYX': q.set(c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13); break; case 'YZY': q.set(s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13); break; case 'ZXZ': q.set(s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13); break; case 'XZX': q.set(c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13); break; case 'YXY': q.set(s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13); break; case 'ZYZ': q.set(s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13); break; default: console.warn('THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order); } } /** * Denormalizes the given value according to the given typed array. * * @param {number} value - The value to denormalize. * @param {TypedArray} array - The typed array that defines the data type of the value. * @return {number} The denormalize (float) value in the range `[0,1]`. */ function denormalize(value, array) { switch(array.constructor){ case Float32Array: return value; case Uint32Array: return value / 4294967295.0; case Uint16Array: return value / 65535.0; case Uint8Array: return value / 255.0; case Int32Array: return Math.max(value / 2147483647.0, -1); case Int16Array: return Math.max(value / 32767.0, -1); case Int8Array: return Math.max(value / 127.0, -1); default: throw new Error('Invalid component type.'); } } /** * Normalizes the given value according to the given typed array. * * @param {number} value - The float value in the range `[0,1]` to normalize. * @param {TypedArray} array - The typed array that defines the data type of the value. * @return {number} The normalize value. */ function normalize(value, array) { switch(array.constructor){ case Float32Array: return value; case Uint32Array: return Math.round(value * 4294967295.0); case Uint16Array: return Math.round(value * 65535.0); case Uint8Array: return Math.round(value * 255.0); case Int32Array: return Math.round(value * 2147483647.0); case Int16Array: return Math.round(value * 32767.0); case Int8Array: return Math.round(value * 127.0); default: throw new Error('Invalid component type.'); } } const MathUtils = { DEG2RAD: DEG2RAD, RAD2DEG: RAD2DEG, generateUUID: generateUUID, clamp: clamp$1, euclideanModulo: euclideanModulo, mapLinear: mapLinear, inverseLerp: inverseLerp, lerp: lerp$1, damp: damp, pingpong: pingpong, smoothstep: smoothstep, smootherstep: smootherstep, randInt: randInt, randFloat: randFloat, randFloatSpread: randFloatSpread, seededRandom: seededRandom, degToRad: degToRad, radToDeg: radToDeg, isPowerOfTwo: isPowerOfTwo, ceilPowerOfTwo: ceilPowerOfTwo, floorPowerOfTwo: floorPowerOfTwo, setQuaternionFromProperEuler: setQuaternionFromProperEuler, normalize: normalize, denormalize: denormalize }; /** * Class representing a 2D vector. A 2D vector is an ordered pair of numbers * (labeled x and y), which can be used to represent a number of things, such as: * * - A point in 2D space (i.e. a position on a plane). * - A direction and length across a plane. In three.js the length will * always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)` * and the direction is also measured from `(0, 0)` towards `(x, y)`. * - Any arbitrary ordered pair of numbers. * * There are other things a 2D vector can be used to represent, such as * momentum vectors, complex numbers and so on, however these are the most * common uses in three.js. * * Iterating through a vector instance will yield its components `(x, y)` in * the corresponding order. * ```js * const a = new THREE.Vector2( 0, 1 ); * * //no arguments; will be initialised to (0, 0) * const b = new THREE.Vector2( ); * * const d = a.distanceTo( b ); * ``` */ class Vector2 { /** * Alias for {@link Vector2#x}. * * @type {number} */ get width() { return this.x; } set width(value) { this.x = value; } /** * Alias for {@link Vector2#y}. * * @type {number} */ get height() { return this.y; } set height(value) { this.y = value; } /** * Sets the vector components. * * @param {number} x - The value of the x component. * @param {number} y - The value of the y component. * @return {Vector2} A reference to this vector. */ set(x, y) { this.x = x; this.y = y; return this; } /** * Sets the vector components to the same value. * * @param {number} scalar - The value to set for all vector components. * @return {Vector2} A reference to this vector. */ setScalar(scalar) { this.x = scalar; this.y = scalar; return this; } /** * Sets the vector's x component to the given value * * @param {number} x - The value to set. * @return {Vector2} A reference to this vector. */ setX(x) { this.x = x; return this; } /** * Sets the vector's y component to the given value * * @param {number} y - The value to set. * @return {Vector2} A reference to this vector. */ setY(y) { this.y = y; return this; } /** * Allows to set a vector component with an index. * * @param {number} index - The component index. `0` equals to x, `1` equals to y. * @param {number} value - The value to set. * @return {Vector2} A reference to this vector. */ setComponent(index, value) { switch(index){ case 0: this.x = value; break; case 1: this.y = value; break; default: throw new Error('index is out of range: ' + index); } return this; } /** * Returns the value of the vector component which matches the given index. * * @param {number} index - The component index. `0` equals to x, `1` equals to y. * @return {number} A vector component value. */ getComponent(index) { switch(index){ case 0: return this.x; case 1: return this.y; default: throw new Error('index is out of range: ' + index); } } /** * Returns a new vector with copied values from this instance. * * @return {Vector2} A clone of this instance. */ clone() { return new this.constructor(this.x, this.y); } /** * Copies the values of the given vector to this instance. * * @param {Vector2} v - The vector to copy. * @return {Vector2} A reference to this vector. */ copy(v) { this.x = v.x; this.y = v.y; return this; } /** * Adds the given vector to this instance. * * @param {Vector2} v - The vector to add. * @return {Vector2} A reference to this vector. */ add(v) { this.x += v.x; this.y += v.y; return this; } /** * Adds the given scalar value to all components of this instance. * * @param {number} s - The scalar to add. * @return {Vector2} A reference to this vector. */ addScalar(s) { this.x += s; this.y += s; return this; } /** * Adds the given vectors and stores the result in this instance. * * @param {Vector2} a - The first vector. * @param {Vector2} b - The second vector. * @return {Vector2} A reference to this vector. */ addVectors(a, b) { this.x = a.x + b.x; this.y = a.y + b.y; return this; } /** * Adds the given vector scaled by the given factor to this instance. * * @param {Vector2} v - The vector. * @param {number} s - The factor that scales `v`. * @return {Vector2} A reference to this vector. */ addScaledVector(v, s) { this.x += v.x * s; this.y += v.y * s; return this; } /** * Subtracts the given vector from this instance. * * @param {Vector2} v - The vector to subtract. * @return {Vector2} A reference to this vector. */ sub(v) { this.x -= v.x; this.y -= v.y; return this; } /** * Subtracts the given scalar value from all components of this instance. * * @param {number} s - The scalar to subtract. * @return {Vector2} A reference to this vector. */ subScalar(s) { this.x -= s; this.y -= s; return this; } /** * Subtracts the given vectors and stores the result in this instance. * * @param {Vector2} a - The first vector. * @param {Vector2} b - The second vector. * @return {Vector2} A reference to this vector. */ subVectors(a, b) { this.x = a.x - b.x; this.y = a.y - b.y; return this; } /** * Multiplies the given vector with this instance. * * @param {Vector2} v - The vector to multiply. * @return {Vector2} A reference to this vector. */ multiply(v) { this.x *= v.x; this.y *= v.y; return this; } /** * Multiplies the given scalar value with all components of this instance. * * @param {number} scalar - The scalar to multiply. * @return {Vector2} A reference to this vector. */ multiplyScalar(scalar) { this.x *= scalar; this.y *= scalar; return this; } /** * Divides this instance by the given vector. * * @param {Vector2} v - The vector to divide. * @return {Vector2} A reference to this vector. */ divide(v) { this.x /= v.x; this.y /= v.y; return this; } /** * Divides this vector by the given scalar. * * @param {number} scalar - The scalar to divide. * @return {Vector2} A reference to this vector. */ divideScalar(scalar) { return this.multiplyScalar(1 / scalar); } /** * Multiplies this vector (with an implicit 1 as the 3rd component) by * the given 3x3 matrix. * * @param {Matrix3} m - The matrix to apply. * @return {Vector2} A reference to this vector. */ applyMatrix3(m) { const x = this.x, y = this.y; const e = m.elements; this.x = e[0] * x + e[3] * y + e[6]; this.y = e[1] * x + e[4] * y + e[7]; return this; } /** * If this vector's x or y value is greater than the given vector's x or y * value, replace that value with the corresponding min value. * * @param {Vector2} v - The vector. * @return {Vector2} A reference to this vector. */ min(v) { this.x = Math.min(this.x, v.x); this.y = Math.min(this.y, v.y); return this; } /** * If this vector's x or y value is less than the given vector's x or y * value, replace that value with the corresponding max value. * * @param {Vector2} v - The vector. * @return {Vector2} A reference to this vector. */ max(v) { this.x = Math.max(this.x, v.x); this.y = Math.max(this.y, v.y); return this; } /** * If this vector's x or y value is greater than the max vector's x or y * value, it is replaced by the corresponding value. * If this vector's x or y value is less than the min vector's x or y value, * it is replaced by the corresponding value. * * @param {Vector2} min - The minimum x and y values. * @param {Vector2} max - The maximum x and y values in the desired range. * @return {Vector2} A reference to this vector. */ clamp(min, max) { // assumes min < max, componentwise this.x = clamp$1(this.x, min.x, max.x); this.y = clamp$1(this.y, min.y, max.y); return this; } /** * If this vector's x or y values are greater than the max value, they are * replaced by the max value. * If this vector's x or y values are less than the min value, they are * replaced by the min value. * * @param {number} minVal - The minimum value the components will be clamped to. * @param {number} maxVal - The maximum value the components will be clamped to. * @return {Vector2} A reference to this vector. */ clampScalar(minVal, maxVal) { this.x = clamp$1(this.x, minVal, maxVal); this.y = clamp$1(this.y, minVal, maxVal); return this; } /** * If this vector's length is greater than the max value, it is replaced by * the max value. * If this vector's length is less than the min value, it is replaced by the * min value. * * @param {number} min - The minimum value the vector length will be clamped to. * @param {number} max - The maximum value the vector length will be clamped to. * @return {Vector2} A reference to this vector. */ clampLength(min, max) { const length = this.length(); return this.divideScalar(length || 1).multiplyScalar(clamp$1(length, min, max)); } /** * The components of this vector are rounded down to the nearest integer value. * * @return {Vector2} A reference to this vector. */ floor() { this.x = Math.floor(this.x); this.y = Math.floor(this.y); return this; } /** * The components of this vector are rounded up to the nearest integer value. * * @return {Vector2} A reference to this vector. */ ceil() { this.x = Math.ceil(this.x); this.y = Math.ceil(this.y); return this; } /** * The components of this vector are rounded to the nearest integer value * * @return {Vector2} A reference to this vector. */ round() { this.x = Math.round(this.x); this.y = Math.round(this.y); return this; } /** * The components of this vector are rounded towards zero (up if negative, * down if positive) to an integer value. * * @return {Vector2} A reference to this vector. */ roundToZero() { this.x = Math.trunc(this.x); this.y = Math.trunc(this.y); return this; } /** * Inverts this vector - i.e. sets x = -x and y = -y. * * @return {Vector2} A reference to this vector. */ negate() { this.x = -this.x; this.y = -this.y; return this; } /** * Calculates the dot product of the given vector with this instance. * * @param {Vector2} v - The vector to compute the dot product with. * @return {number} The result of the dot product. */ dot(v) { return this.x * v.x + this.y * v.y; } /** * Calculates the cross product of the given vector with this instance. * * @param {Vector2} v - The vector to compute the cross product with. * @return {number} The result of the cross product. */ cross(v) { return this.x * v.y - this.y * v.x; } /** * Computes the square of the Euclidean length (straight-line length) from * (0, 0) to (x, y). If you are comparing the lengths of vectors, you should * compare the length squared instead as it is slightly more efficient to calculate. * * @return {number} The square length of this vector. */ lengthSq() { return this.x * this.x + this.y * this.y; } /** * Computes the Euclidean length (straight-line length) from (0, 0) to (x, y). * * @return {number} The length of this vector. */ length() { return Math.sqrt(this.x * this.x + this.y * this.y); } /** * Computes the Manhattan length of this vector. * * @return {number} The length of this vector. */ manhattanLength() { return Math.abs(this.x) + Math.abs(this.y); } /** * Converts this vector to a unit vector - that is, sets it equal to a vector * with the same direction as this one, but with a vector length of `1`. * * @return {Vector2} A reference to this vector. */ normalize() { return this.divideScalar(this.length() || 1); } /** * Computes the angle in radians of this vector with respect to the positive x-axis. * * @return {number} The angle in radians. */ angle() { const a