UNPKG

elation-engine

Version:
1,682 lines (1,538 loc) 257 kB
/** * @license * webxr-polyfill * Copyright (c) 2017 Google * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @license * cardboard-vr-display * Copyright (c) 2015-2017 Google * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @license * webvr-polyfill-dpdb * Copyright (c) 2017 Google * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @license * wglu-preserve-state * Copyright (c) 2016, Brandon Jones. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * @license * nosleep.js * Copyright (c) 2017, Rich Tibbett * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.WebXRPolyfill = factory()); }(this, (function () { 'use strict'; const _global = typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : {}; const PRIVATE = Symbol('@@webxr-polyfill/EventTarget'); class EventTarget { constructor() { this[PRIVATE] = { listeners: new Map(), }; } addEventListener(type, listener) { if (typeof type !== 'string') { throw new Error('`type` must be a string'); } if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } const typedListeners = this[PRIVATE].listeners.get(type) || []; typedListeners.push(listener); this[PRIVATE].listeners.set(type, typedListeners); } removeEventListener(type, listener) { if (typeof type !== 'string') { throw new Error('`type` must be a string'); } if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } const typedListeners = this[PRIVATE].listeners.get(type) || []; for (let i = typedListeners.length; i >= 0; i--) { if (typedListeners[i] === listener) { typedListeners.pop(); } } } dispatchEvent(type, event) { const typedListeners = this[PRIVATE].listeners.get(type) || []; const queue = []; for (let i = 0; i < typedListeners.length; i++) { queue[i] = typedListeners[i]; } for (let listener of queue) { listener(event); } if (typeof this[`on${type}`] === 'function') { this[`on${type}`](event); } } } const EPSILON = 0.000001; let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; const degree = Math.PI / 180; function create() { let out = new ARRAY_TYPE(16); if(ARRAY_TYPE != Float32Array) { out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; } out[0] = 1; out[5] = 1; out[10] = 1; out[15] = 1; return out; } function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; } function identity(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } function invert(out, a) { let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; let b00 = a00 * a11 - a01 * a10; let b01 = a00 * a12 - a02 * a10; let b02 = a00 * a13 - a03 * a10; let b03 = a01 * a12 - a02 * a11; let b04 = a01 * a13 - a03 * a11; let b05 = a02 * a13 - a03 * a12; let b06 = a20 * a31 - a21 * a30; let b07 = a20 * a32 - a22 * a30; let b08 = a20 * a33 - a23 * a30; let b09 = a21 * a32 - a22 * a31; let b10 = a21 * a33 - a23 * a31; let b11 = a22 * a33 - a23 * a32; let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (!det) { return null; } det = 1.0 / det; out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; return out; } function multiply(out, a, b) { let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; return out; } function fromRotationTranslation(out, q, v) { let x = q[0], y = q[1], z = q[2], w = q[3]; let x2 = x + x; let y2 = y + y; let z2 = z + z; let xx = x * x2; let xy = x * y2; let xz = x * z2; let yy = y * y2; let yz = y * z2; let zz = z * z2; let wx = w * x2; let wy = w * y2; let wz = w * z2; out[0] = 1 - (yy + zz); out[1] = xy + wz; out[2] = xz - wy; out[3] = 0; out[4] = xy - wz; out[5] = 1 - (xx + zz); out[6] = yz + wx; out[7] = 0; out[8] = xz + wy; out[9] = yz - wx; out[10] = 1 - (xx + yy); out[11] = 0; out[12] = v[0]; out[13] = v[1]; out[14] = v[2]; out[15] = 1; return out; } function getTranslation(out, mat) { out[0] = mat[12]; out[1] = mat[13]; out[2] = mat[14]; return out; } function getRotation(out, mat) { let trace = mat[0] + mat[5] + mat[10]; let S = 0; if (trace > 0) { S = Math.sqrt(trace + 1.0) * 2; out[3] = 0.25 * S; out[0] = (mat[6] - mat[9]) / S; out[1] = (mat[8] - mat[2]) / S; out[2] = (mat[1] - mat[4]) / S; } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) { S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; out[3] = (mat[6] - mat[9]) / S; out[0] = 0.25 * S; out[1] = (mat[1] + mat[4]) / S; out[2] = (mat[8] + mat[2]) / S; } else if (mat[5] > mat[10]) { S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; out[3] = (mat[8] - mat[2]) / S; out[0] = (mat[1] + mat[4]) / S; out[1] = 0.25 * S; out[2] = (mat[6] + mat[9]) / S; } else { S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; out[3] = (mat[1] - mat[4]) / S; out[0] = (mat[8] + mat[2]) / S; out[1] = (mat[6] + mat[9]) / S; out[2] = 0.25 * S; } return out; } function perspective(out, fovy, aspect, near, far) { let f = 1.0 / Math.tan(fovy / 2), nf; out[0] = f / aspect; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = f; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = -1; out[12] = 0; out[13] = 0; out[15] = 0; if (far != null && far !== Infinity) { nf = 1 / (near - far); out[10] = (far + near) * nf; out[14] = (2 * far * near) * nf; } else { out[10] = -1; out[14] = -2 * near; } return out; } function create$1() { let out = new ARRAY_TYPE(3); if(ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; } return out; } function clone$1(a) { var out = new ARRAY_TYPE(3); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; } function length(a) { let x = a[0]; let y = a[1]; let z = a[2]; return Math.sqrt(x*x + y*y + z*z); } function fromValues$1(x, y, z) { let out = new ARRAY_TYPE(3); out[0] = x; out[1] = y; out[2] = z; return out; } function copy$1(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; } function add$1(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; return out; } function scale$1(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; return out; } function normalize(out, a) { let x = a[0]; let y = a[1]; let z = a[2]; let len = x*x + y*y + z*z; if (len > 0) { len = 1 / Math.sqrt(len); out[0] = a[0] * len; out[1] = a[1] * len; out[2] = a[2] * len; } return out; } function dot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } function cross(out, a, b) { let ax = a[0], ay = a[1], az = a[2]; let bx = b[0], by = b[1], bz = b[2]; out[0] = ay * bz - az * by; out[1] = az * bx - ax * bz; out[2] = ax * by - ay * bx; return out; } function transformQuat(out, a, q) { let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; let x = a[0], y = a[1], z = a[2]; let uvx = qy * z - qz * y, uvy = qz * x - qx * z, uvz = qx * y - qy * x; let uuvx = qy * uvz - qz * uvy, uuvy = qz * uvx - qx * uvz, uuvz = qx * uvy - qy * uvx; let w2 = qw * 2; uvx *= w2; uvy *= w2; uvz *= w2; uuvx *= 2; uuvy *= 2; uuvz *= 2; out[0] = x + uvx + uuvx; out[1] = y + uvy + uuvy; out[2] = z + uvz + uuvz; return out; } function angle(a, b) { let tempA = fromValues$1(a[0], a[1], a[2]); let tempB = fromValues$1(b[0], b[1], b[2]); normalize(tempA, tempA); normalize(tempB, tempB); let cosine = dot(tempA, tempB); if(cosine > 1.0) { return 0; } else if(cosine < -1.0) { return Math.PI; } else { return Math.acos(cosine); } } const len = length; const forEach = (function() { let vec = create$1(); return function(a, stride, offset, count, fn, arg) { let i, l; if(!stride) { stride = 3; } if(!offset) { offset = 0; } if(count) { l = Math.min((count * stride) + offset, a.length); } else { l = a.length; } for(i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; fn(vec, vec, arg); a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; } return a; }; })(); function create$2() { let out = new ARRAY_TYPE(9); if(ARRAY_TYPE != Float32Array) { out[1] = 0; out[2] = 0; out[3] = 0; out[5] = 0; out[6] = 0; out[7] = 0; } out[0] = 1; out[4] = 1; out[8] = 1; return out; } function create$3() { let out = new ARRAY_TYPE(4); if(ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0; } return out; } function clone$3(a) { let out = new ARRAY_TYPE(4); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; return out; } function fromValues$3(x, y, z, w) { let out = new ARRAY_TYPE(4); out[0] = x; out[1] = y; out[2] = z; out[3] = w; return out; } function copy$3(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; return out; } function normalize$1(out, a) { let x = a[0]; let y = a[1]; let z = a[2]; let w = a[3]; let len = x*x + y*y + z*z + w*w; if (len > 0) { len = 1 / Math.sqrt(len); out[0] = x * len; out[1] = y * len; out[2] = z * len; out[3] = w * len; } return out; } const forEach$1 = (function() { let vec = create$3(); return function(a, stride, offset, count, fn, arg) { let i, l; if(!stride) { stride = 4; } if(!offset) { offset = 0; } if(count) { l = Math.min((count * stride) + offset, a.length); } else { l = a.length; } for(i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; fn(vec, vec, arg); a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; } return a; }; })(); function create$4() { let out = new ARRAY_TYPE(4); if(ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; } out[3] = 1; return out; } function setAxisAngle(out, axis, rad) { rad = rad * 0.5; let s = Math.sin(rad); out[0] = s * axis[0]; out[1] = s * axis[1]; out[2] = s * axis[2]; out[3] = Math.cos(rad); return out; } function multiply$4(out, a, b) { let ax = a[0], ay = a[1], az = a[2], aw = a[3]; let bx = b[0], by = b[1], bz = b[2], bw = b[3]; out[0] = ax * bw + aw * bx + ay * bz - az * by; out[1] = ay * bw + aw * by + az * bx - ax * bz; out[2] = az * bw + aw * bz + ax * by - ay * bx; out[3] = aw * bw - ax * bx - ay * by - az * bz; return out; } function slerp(out, a, b, t) { let ax = a[0], ay = a[1], az = a[2], aw = a[3]; let bx = b[0], by = b[1], bz = b[2], bw = b[3]; let omega, cosom, sinom, scale0, scale1; cosom = ax * bx + ay * by + az * bz + aw * bw; if ( cosom < 0.0 ) { cosom = -cosom; bx = - bx; by = - by; bz = - bz; bw = - bw; } if ( (1.0 - cosom) > EPSILON ) { omega = Math.acos(cosom); sinom = Math.sin(omega); scale0 = Math.sin((1.0 - t) * omega) / sinom; scale1 = Math.sin(t * omega) / sinom; } else { scale0 = 1.0 - t; scale1 = t; } out[0] = scale0 * ax + scale1 * bx; out[1] = scale0 * ay + scale1 * by; out[2] = scale0 * az + scale1 * bz; out[3] = scale0 * aw + scale1 * bw; return out; } function invert$2(out, a) { let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; let dot$$1 = a0*a0 + a1*a1 + a2*a2 + a3*a3; let invDot = dot$$1 ? 1.0/dot$$1 : 0; out[0] = -a0*invDot; out[1] = -a1*invDot; out[2] = -a2*invDot; out[3] = a3*invDot; return out; } function fromMat3(out, m) { let fTrace = m[0] + m[4] + m[8]; let fRoot; if ( fTrace > 0.0 ) { fRoot = Math.sqrt(fTrace + 1.0); out[3] = 0.5 * fRoot; fRoot = 0.5/fRoot; out[0] = (m[5]-m[7])*fRoot; out[1] = (m[6]-m[2])*fRoot; out[2] = (m[1]-m[3])*fRoot; } else { let i = 0; if ( m[4] > m[0] ) i = 1; if ( m[8] > m[i*3+i] ) i = 2; let j = (i+1)%3; let k = (i+2)%3; fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); out[i] = 0.5 * fRoot; fRoot = 0.5 / fRoot; out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; } return out; } function fromEuler(out, x, y, z) { let halfToRad = 0.5 * Math.PI / 180.0; x *= halfToRad; y *= halfToRad; z *= halfToRad; let sx = Math.sin(x); let cx = Math.cos(x); let sy = Math.sin(y); let cy = Math.cos(y); let sz = Math.sin(z); let cz = Math.cos(z); out[0] = sx * cy * cz - cx * sy * sz; out[1] = cx * sy * cz + sx * cy * sz; out[2] = cx * cy * sz - sx * sy * cz; out[3] = cx * cy * cz + sx * sy * sz; return out; } const clone$4 = clone$3; const fromValues$4 = fromValues$3; const copy$4 = copy$3; const normalize$2 = normalize$1; const rotationTo = (function() { let tmpvec3 = create$1(); let xUnitVec3 = fromValues$1(1,0,0); let yUnitVec3 = fromValues$1(0,1,0); return function(out, a, b) { let dot$$1 = dot(a, b); if (dot$$1 < -0.999999) { cross(tmpvec3, xUnitVec3, a); if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a); normalize(tmpvec3, tmpvec3); setAxisAngle(out, tmpvec3, Math.PI); return out; } else if (dot$$1 > 0.999999) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 1; return out; } else { cross(tmpvec3, a, b); out[0] = tmpvec3[0]; out[1] = tmpvec3[1]; out[2] = tmpvec3[2]; out[3] = 1 + dot$$1; return normalize$2(out, out); } }; })(); const sqlerp = (function () { let temp1 = create$4(); let temp2 = create$4(); return function (out, a, b, c, d, t) { slerp(temp1, a, d, t); slerp(temp2, b, c, t); slerp(out, temp1, temp2, 2 * t * (1 - t)); return out; }; }()); const setAxes = (function() { let matr = create$2(); return function(out, view, right, up) { matr[0] = right[0]; matr[3] = right[1]; matr[6] = right[2]; matr[1] = up[0]; matr[4] = up[1]; matr[7] = up[2]; matr[2] = -view[0]; matr[5] = -view[1]; matr[8] = -view[2]; return normalize$2(out, fromMat3(out, matr)); }; })(); const PRIVATE$1 = Symbol('@@webxr-polyfill/XRRigidTransform'); class XRRigidTransform$1 { constructor() { this[PRIVATE$1] = { matrix: null, position: null, orientation: null, inverse: null, }; if (arguments.length === 0) { this[PRIVATE$1].matrix = identity(new Float32Array(16)); } else if (arguments.length === 1) { if (arguments[0] instanceof Float32Array) { this[PRIVATE$1].matrix = arguments[0]; } else { this[PRIVATE$1].position = this._getPoint(arguments[0]); this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ x: 0, y: 0, z: 0, w: 1 }); } } else if (arguments.length === 2) { this[PRIVATE$1].position = this._getPoint(arguments[0]); this[PRIVATE$1].orientation = this._getPoint(arguments[1]); } else { throw new Error("Too many arguments!"); } if (this[PRIVATE$1].matrix) { let position = create$1(); getTranslation(position, this[PRIVATE$1].matrix); this[PRIVATE$1].position = DOMPointReadOnly.fromPoint({ x: position[0], y: position[1], z: position[2] }); let orientation = create$4(); getRotation(orientation, this[PRIVATE$1].matrix); this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ x: orientation[0], y: orientation[1], z: orientation[2], w: orientation[3] }); } else { this[PRIVATE$1].matrix = identity(new Float32Array(16)); fromRotationTranslation( this[PRIVATE$1].matrix, fromValues$4( this[PRIVATE$1].orientation.x, this[PRIVATE$1].orientation.y, this[PRIVATE$1].orientation.z, this[PRIVATE$1].orientation.w), fromValues$1( this[PRIVATE$1].position.x, this[PRIVATE$1].position.y, this[PRIVATE$1].position.z) ); } } _getPoint(arg) { if (arg instanceof DOMPointReadOnly) { return arg; } return DOMPointReadOnly.fromPoint(arg); } get matrix() { return this[PRIVATE$1].matrix; } get position() { return this[PRIVATE$1].position; } get orientation() { return this[PRIVATE$1].orientation; } get inverse() { if (this[PRIVATE$1].inverse === null) { let invMatrix = identity(new Float32Array(16)); invert(invMatrix, this[PRIVATE$1].matrix); this[PRIVATE$1].inverse = new XRRigidTransform$1(invMatrix); this[PRIVATE$1].inverse[PRIVATE$1].inverse = this; } return this[PRIVATE$1].inverse; } } const PRIVATE$2 = Symbol('@@webxr-polyfill/XRSpace'); class XRSpace { constructor(specialType = null, inputSource = null) { this[PRIVATE$2] = { specialType, inputSource, baseMatrix: null, inverseBaseMatrix: null, lastFrameId: -1 }; } get _specialType() { return this[PRIVATE$2].specialType; } get _inputSource() { return this[PRIVATE$2].inputSource; } _ensurePoseUpdated(device, frameId) { if (frameId == this[PRIVATE$2].lastFrameId) return; this[PRIVATE$2].lastFrameId = frameId; this._onPoseUpdate(device); } _onPoseUpdate(device) { if (this[PRIVATE$2].specialType == 'viewer') { this._baseMatrix = device.getBasePoseMatrix(); } } set _baseMatrix(matrix) { this[PRIVATE$2].baseMatrix = matrix; this[PRIVATE$2].inverseBaseMatrix = null; } get _baseMatrix() { if (!this[PRIVATE$2].baseMatrix) { if (this[PRIVATE$2].inverseBaseMatrix) { this[PRIVATE$2].baseMatrix = new Float32Array(16); invert(this[PRIVATE$2].baseMatrix, this[PRIVATE$2].inverseBaseMatrix); } } return this[PRIVATE$2].baseMatrix; } set _inverseBaseMatrix(matrix) { this[PRIVATE$2].inverseBaseMatrix = matrix; this[PRIVATE$2].baseMatrix = null; } get _inverseBaseMatrix() { if (!this[PRIVATE$2].inverseBaseMatrix) { if (this[PRIVATE$2].baseMatrix) { this[PRIVATE$2].inverseBaseMatrix = new Float32Array(16); invert(this[PRIVATE$2].inverseBaseMatrix, this[PRIVATE$2].baseMatrix); } } return this[PRIVATE$2].inverseBaseMatrix; } _getSpaceRelativeTransform(space) { if (!this._inverseBaseMatrix || !space._baseMatrix) { return null; } let out = new Float32Array(16); multiply(out, this._inverseBaseMatrix, space._baseMatrix); return new XRRigidTransform$1(out); } } const DEFAULT_EMULATION_HEIGHT = 1.6; const PRIVATE$3 = Symbol('@@webxr-polyfill/XRReferenceSpace'); const XRReferenceSpaceTypes = [ 'viewer', 'local', 'local-floor', 'bounded-floor', 'unbounded' ]; function isFloor(type) { return type === 'bounded-floor' || type === 'local-floor'; } class XRReferenceSpace extends XRSpace { constructor(type, transform = null) { if (!XRReferenceSpaceTypes.includes(type)) { throw new Error(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); } super(type); if (type === 'bounded-floor' && !transform) { throw new Error(`XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level`); } if (isFloor(type) && !transform) { transform = identity(new Float32Array(16)); transform[13] = DEFAULT_EMULATION_HEIGHT; } this._inverseBaseMatrix = transform || identity(new Float32Array(16)); this[PRIVATE$3] = { type, transform, originOffset : identity(new Float32Array(16)), }; } _transformBasePoseMatrix(out, pose) { multiply(out, this._inverseBaseMatrix, pose); } _originOffsetMatrix() { return this[PRIVATE$3].originOffset; } _adjustForOriginOffset(transformMatrix) { let inverseOriginOffsetMatrix = new Float32Array(16); invert(inverseOriginOffsetMatrix, this[PRIVATE$3].originOffset); multiply(transformMatrix, inverseOriginOffsetMatrix, transformMatrix); } _getSpaceRelativeTransform(space) { let transform = super._getSpaceRelativeTransform(space); this._adjustForOriginOffset(transform.matrix); return new XRRigidTransform(transform.matrix); } getOffsetReferenceSpace(additionalOffset) { let newSpace = new XRReferenceSpace( this[PRIVATE$3].type, this[PRIVATE$3].transform, this[PRIVATE$3].bounds); multiply(newSpace[PRIVATE$3].originOffset, this[PRIVATE$3].originOffset, additionalOffset.matrix); return newSpace; } } const PRIVATE$4 = Symbol('@@webxr-polyfill/XR'); const XRSessionModes = ['inline', 'immersive-vr', 'immersive-ar']; const DEFAULT_SESSION_OPTIONS = { 'inline': { requiredFeatures: ['viewer'], optionalFeatures: [], }, 'immersive-vr': { requiredFeatures: ['viewer', 'local'], optionalFeatures: [], }, 'immersive-ar': { requiredFeatures: ['viewer', 'local'], optionalFeatures: [], } }; const POLYFILL_REQUEST_SESSION_ERROR = `Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode or navigator.xr.requestSession('inline') prior to requesting an immersive session. This is a limitation specific to the WebXR Polyfill and does not apply to native implementations of the API.`; class XRSystem extends EventTarget { constructor(devicePromise) { super(); this[PRIVATE$4] = { device: null, devicePromise, immersiveSession: null, inlineSessions: new Set(), }; devicePromise.then((device) => { this[PRIVATE$4].device = device; }); } async isSessionSupported(mode) { if (!this[PRIVATE$4].device) { await this[PRIVATE$4].devicePromise; } if (mode != 'inline') { return Promise.resolve(this[PRIVATE$4].device.isSessionSupported(mode)); } return Promise.resolve(true); } async requestSession(mode, options) { if (!this[PRIVATE$4].device) { if (mode != 'inline') { throw new Error(POLYFILL_REQUEST_SESSION_ERROR); } else { await this[PRIVATE$4].devicePromise; } } if (!XRSessionModes.includes(mode)) { throw new TypeError( `The provided value '${mode}' is not a valid enum value of type XRSessionMode`); } const defaultOptions = DEFAULT_SESSION_OPTIONS[mode]; const requiredFeatures = defaultOptions.requiredFeatures.concat( options && options.requiredFeatures ? options.requiredFeatures : []); const optionalFeatures = defaultOptions.optionalFeatures.concat( options && options.optionalFeatures ? options.optionalFeatures : []); const enabledFeatures = new Set(); let requirementsFailed = false; for (let feature of requiredFeatures) { if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { console.error(`The required feature '${feature}' is not supported`); requirementsFailed = true; } else { enabledFeatures.add(feature); } } if (requirementsFailed) { throw new DOMException('Session does not support some required features', 'NotSupportedError'); } for (let feature of optionalFeatures) { if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { console.log(`The optional feature '${feature}' is not supported`); } else { enabledFeatures.add(feature); } } const sessionId = await this[PRIVATE$4].device.requestSession(mode, enabledFeatures); const session = new XRSession(this[PRIVATE$4].device, mode, sessionId); if (mode == 'inline') { this[PRIVATE$4].inlineSessions.add(session); } else { this[PRIVATE$4].immersiveSession = session; } const onSessionEnd = () => { if (mode == 'inline') { this[PRIVATE$4].inlineSessions.delete(session); } else { this[PRIVATE$4].immersiveSession = null; } session.removeEventListener('end', onSessionEnd); }; session.addEventListener('end', onSessionEnd); return session; } } let now; if ('performance' in _global === false) { let startTime = Date.now(); now = () => Date.now() - startTime; } else { now = () => performance.now(); } var now$1 = now; const PRIVATE$5 = Symbol('@@webxr-polyfill/XRPose'); class XRPose$1 { constructor(transform, emulatedPosition) { this[PRIVATE$5] = { transform, emulatedPosition, }; } get transform() { return this[PRIVATE$5].transform; } get emulatedPosition() { return this[PRIVATE$5].emulatedPosition; } } const PRIVATE$6 = Symbol('@@webxr-polyfill/XRViewerPose'); class XRViewerPose extends XRPose$1 { constructor(transform, views, emulatedPosition = false) { super(transform, emulatedPosition); this[PRIVATE$6] = { views }; } get views() { return this[PRIVATE$6].views; } } const PRIVATE$7 = Symbol('@@webxr-polyfill/XRViewport'); class XRViewport { constructor(target) { this[PRIVATE$7] = { target }; } get x() { return this[PRIVATE$7].target.x; } get y() { return this[PRIVATE$7].target.y; } get width() { return this[PRIVATE$7].target.width; } get height() { return this[PRIVATE$7].target.height; } } const XREyes = ['left', 'right', 'none']; const PRIVATE$8 = Symbol('@@webxr-polyfill/XRView'); class XRView { constructor(device, transform, eye, sessionId) { if (!XREyes.includes(eye)) { throw new Error(`XREye must be one of: ${XREyes}`); } const temp = Object.create(null); const viewport = new XRViewport(temp); this[PRIVATE$8] = { device, eye, viewport, temp, sessionId, transform, }; } get eye() { return this[PRIVATE$8].eye; } get projectionMatrix() { return this[PRIVATE$8].device.getProjectionMatrix(this.eye); } get transform() { return this[PRIVATE$8].transform; } _getViewport(layer) { if (this[PRIVATE$8].device.getViewport(this[PRIVATE$8].sessionId, this.eye, layer, this[PRIVATE$8].temp)) { return this[PRIVATE$8].viewport; } return undefined; } } const PRIVATE$9 = Symbol('@@webxr-polyfill/XRFrame'); const NON_ACTIVE_MSG = "XRFrame access outside the callback that produced it is invalid."; const NON_ANIMFRAME_MSG = "getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks."; let NEXT_FRAME_ID = 0; class XRFrame { constructor(device, session, sessionId) { this[PRIVATE$9] = { id: ++NEXT_FRAME_ID, active: false, animationFrame: false, device, session, sessionId }; } get session() { return this[PRIVATE$9].session; } getViewerPose(referenceSpace) { if (!this[PRIVATE$9].animationFrame) { throw new DOMException(NON_ANIMFRAME_MSG, 'InvalidStateError'); } if (!this[PRIVATE$9].active) { throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); } const device = this[PRIVATE$9].device; const session = this[PRIVATE$9].session; session[PRIVATE$15].viewerSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); referenceSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); let viewerTransform = referenceSpace._getSpaceRelativeTransform(session[PRIVATE$15].viewerSpace); const views = []; for (let viewSpace of session[PRIVATE$15].viewSpaces) { viewSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); let viewTransform = referenceSpace._getSpaceRelativeTransform(viewSpace); let view = new XRView(device, viewTransform, viewSpace.eye, this[PRIVATE$9].sessionId); views.push(view); } let viewerPose = new XRViewerPose(viewerTransform, views, false ); return viewerPose; } getPose(space, baseSpace) { if (!this[PRIVATE$9].active) { throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); } const device = this[PRIVATE$9].device; if (space._specialType === "target-ray" || space._specialType === "grip") { return device.getInputPose( space._inputSource, baseSpace, space._specialType); } else { space._ensurePoseUpdated(device, this[PRIVATE$9].id); baseSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); let transform = baseSpace._getSpaceRelativeTransform(space); if (!transform) { return null; } return new XRPose(transform, false ); } return null; } } const PRIVATE$10 = Symbol('@@webxr-polyfill/XRRenderState'); const XRRenderStateInit = Object.freeze({ depthNear: 0.1, depthFar: 1000.0, inlineVerticalFieldOfView: null, baseLayer: null }); class XRRenderState { constructor(stateInit = {}) { const config = Object.assign({}, XRRenderStateInit, stateInit); this[PRIVATE$10] = { config }; } get depthNear() { return this[PRIVATE$10].config.depthNear; } get depthFar() { return this[PRIVATE$10].config.depthFar; } get inlineVerticalFieldOfView() { return this[PRIVATE$10].config.inlineVerticalFieldOfView; } get baseLayer() { return this[PRIVATE$10].config.baseLayer; } } const POLYFILLED_XR_COMPATIBLE = Symbol('@@webxr-polyfill/polyfilled-xr-compatible'); const XR_COMPATIBLE = Symbol('@@webxr-polyfill/xr-compatible'); const PRIVATE$11 = Symbol('@@webxr-polyfill/XRWebGLLayer'); const XRWebGLLayerInit = Object.freeze({ antialias: true, depth: false, stencil: false, alpha: true, multiview: false, ignoreDepthValues: false, framebufferScaleFactor: 1.0, }); class XRWebGLLayer { constructor(session, context, layerInit={}) { const config = Object.assign({}, XRWebGLLayerInit, layerInit); if (!(session instanceof XRSession$1)) { throw new Error('session must be a XRSession'); } if (session.ended) { throw new Error(`InvalidStateError`); } if (context[POLYFILLED_XR_COMPATIBLE]) { if (context[XR_COMPATIBLE] !== true) { throw new Error(`InvalidStateError`); } } const framebuffer = context.getParameter(context.FRAMEBUFFER_BINDING); this[PRIVATE$11] = { context, config, framebuffer, session, }; } get context() { return this[PRIVATE$11].context; } get antialias() { return this[PRIVATE$11].config.antialias; } get ignoreDepthValues() { return true; } get framebuffer() { return this[PRIVATE$11].framebuffer; } get framebufferWidth() { return this[PRIVATE$11].context.drawingBufferWidth; } get framebufferHeight() { return this[PRIVATE$11].context.drawingBufferHeight; } get _session() { return this[PRIVATE$11].session; } getViewport(view) { return view._getViewport(this); } static getNativeFramebufferScaleFactor(session) { if (!session) { throw new TypeError('getNativeFramebufferScaleFactor must be passed a session.') } if (session[PRIVATE$15].ended) { return 0.0; } return 1.0; } } const PRIVATE$12 = Symbol('@@webxr-polyfill/XRInputSourceEvent'); class XRInputSourceEvent extends Event { constructor(type, eventInitDict) { super(type, eventInitDict); this[PRIVATE$12] = { frame: eventInitDict.frame, inputSource: eventInitDict.inputSource }; Object.setPrototypeOf(this, XRInputSourceEvent.prototype); } get frame() { return this[PRIVATE$12].frame; } get inputSource() { return this[PRIVATE$12].inputSource; } } const PRIVATE$13 = Symbol('@@webxr-polyfill/XRSessionEvent'); class XRSessionEvent extends Event { constructor(type, eventInitDict) { super(type, eventInitDict); this[PRIVATE$13] = { session: eventInitDict.session }; Object.setPrototypeOf(this, XRSessionEvent.prototype); } get session() { return this[PRIVATE$13].session; } } const PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSourcesChangeEvent'); class XRInputSourcesChangeEvent extends Event { constructor(type, eventInitDict) { super(type, eventInitDict); this[PRIVATE$14] = { session: eventInitDict.session, added: eventInitDict.added, removed: eventInitDict.removed }; Object.setPrototypeOf(this, XRInputSourcesChangeEvent.prototype); } get session() { return this[PRIVATE$14].session; } get added() { return this[PRIVATE$14].added; } get removed() { return this[PRIVATE$14].removed; } } const PRIVATE$15 = Symbol('@@webxr-polyfill/XRSession'); class XRViewSpace extends XRSpace { constructor(eye) { super(eye); } get eye() { return this._specialType; } _onPoseUpdate(device) { this._inverseBaseMatrix = device.getBaseViewMatrix(this._specialType); } } class XRSession$1 extends EventTarget { constructor(device, mode, id) { super(); let immersive = mode != 'inline'; let initialRenderState = new XRRenderState({ inlineVerticalFieldOfView: immersive ? null : Math.PI * 0.5 }); this[PRIVATE$15] = { device, mode, immersive, ended: false, suspended: false, frameCallbacks: [], currentFrameCallbacks: null, frameHandle: 0, deviceFrameHandle: null, id, activeRenderState: initialRenderState, pendingRenderState: null, viewerSpace: new XRReferenceSpace("viewer"), viewSpaces: [], currentInputSources: [] }; if (immersive) { this[PRIVATE$15].viewSpaces.push(new XRViewSpace('left'), new XRViewSpace('right')); } else { this[PRIVATE$15].viewSpaces.push(new XRViewSpace('none')); } this[PRIVATE$15].onDeviceFrame = () => { if (this[PRIVATE$15].ended || this[PRIVATE$15].suspended) { return; } this[PRIVATE$15].deviceFrameHandle = null; this[PRIVATE$15].startDeviceFrameLoop(); if (this[PRIVATE$15].pendingRenderState !== null) { this[PRIVATE$15].activeRenderState = new XRRenderState(this[PRIVATE$15].pendingRenderState); this[PRIVATE$15].pendingRenderState = null; if (this[PRIVATE$15].activeRenderState.baseLayer) { this[PRIVATE$15].device.onBaseLayerSet( this[PRIVATE$15].id, this[PRIVATE$15].activeRenderState.baseLayer); } } if (this[PRIVATE$15].activeRenderState.baseLayer === null) { return; } const frame = new XRFrame(device, this, this[PRIVATE$15].id); const callbacks = this[PRIVATE$15].currentFrameCallbacks = this[PRIVATE$15].frameCallbacks; this[PRIVATE$15].frameCallbacks = []; frame[PRIVATE$9].active = true; frame[PRIVATE$9].animationFrame = true; this[PRIVATE$15].device.onFrameStart(this[PRIVATE$15].id, this[PRIVATE$15].activeRenderState); this._checkInputSourcesChange(); const rightNow = now$1(); for (let i = 0; i < callbacks.length; i++) { try { if (!callbacks[i].cancelled && typeof callbacks[i].callback === 'function') { callbacks[i].callback(rightNow, frame); } } catch(err) { console.error(err); } } this[PRIVATE$15].currentFrameCallbacks = null; frame[PRIVATE$9].active = false; this[PRIVATE$15].device.onFrameEnd(this[PRIVATE$15].id); }; this[PRIVATE$15].startDeviceFrameLoop = () => { if (this[PRIVATE$15].deviceFrameHandle === null) { this[PRIVATE$15].deviceFrameHandle = this[PRIVATE$15].device.requestAnimationFrame( this[PRIVATE$15].onDeviceFrame ); } }; this[PRIVATE$15].stopDeviceFrameLoop = () => { const handle = this[PRIVATE$15].deviceFrameHandle; if (handle !== null) { this[PRIVATE$15].device.cancelAnimationFrame(handle); this[PRIVATE$15].deviceFrameHandle = null; } }; this[PRIVATE$15].onPresentationEnd = sessionId => { if (sessionId !== this[PRIVATE$15].id) { this[PRIVATE$15].suspended = false; this[PRIVATE$15].startDeviceFrameLoop(); this.dispatchEvent('focus', { session: this }); return; } this[PRIVATE$15].ended = true; this[PRIVATE$15].stopDeviceFrameLoop(); device.removeEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); device.removeEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); device.removeEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); device.removeEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); }; device.addEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); this[PRIVATE$15].onPresentationStart = sessionId => { if (sessionId === this[PRIVATE$15].id) { return; } this[PRIVATE$15].suspended = true; this[PRIVATE$15].stopDeviceFrameLoop(); this.dispatchEvent('blur', { session: this }); }; device.addEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); this[PRIVATE$15].onSelectStart = evt => { if (evt.sessionId !== this[PRIVATE$15].id) { return; } this[PRIVATE$15].dispatchInputSourceEvent('selectstart', evt.inputSource); }; device.addEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); this[PRIVATE$15].onSelectEnd = evt => { if (evt.sessionId !== this[PRIVATE$15].id) { return; } this[PRIVATE$15].dispatchInputSourceEvent('selectend', evt.inputSource); this[PRIVATE$15].dispatchInputSourceEvent('select', evt.inputSource); }; device.addEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); this[PRIVATE$15].onSqueezeStart = evt => { if (evt.sessionId !== this[PRIVATE$15].id) { return; } this[PRIVATE$15].dispatchInputSourceEvent('squeezestart', evt.inputSource); }; device.addEventListener('@@webxr-polyfill/input-squeeze-start', this[PRIVATE$15].onSqueezeStart); this[PRIVATE$15].onSqueezeEnd = evt => { if (evt.sessionId !== this[PRIVATE$15].id) { return; } this[PRIVATE$15].dispatchInputSourceEvent('squeezeend', evt.inputSource); this[PRIVATE$15].dispatchInputSourceEvent('squeeze', evt.inputSource); }; device.addEventListener('@@webxr-polyfill/input-squeeze-end', this[PRIVATE$15].onSqueezeEnd); this[PRIVATE$15].dispatchInputSourceEvent = (type, inputSource) => { const frame = new XRFrame(device, this, this[PRIVATE$15].id); const event = new XRInputSourceEvent(type, { frame, inputSource }); frame[PRIVATE$9].active = true; this.dispatchEvent(type, event); frame[PRIVATE$9].active = false; }; this[PRIVATE$15].startDeviceFrameLoop(); this.onblur = undefined; this.onfocus = undefined; this.onresetpose = undefined; this.onend = undefined; this.onselect = undefined; this.onselectstart = undefined; this.onselectend = undefined; } get renderState() { return this[PRIVATE$15].activeRenderState; } get environmentBlendMode() { return this[PRIVATE$15].device.environmentBlendMode || 'opaque'; } async requestReferenceSpace(type) { if (this[PRIVATE$15].ended) { return; } if (!XRReferenceSpaceTypes.includes(type)) { throw new TypeError(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); } if (!this[PRIVATE$15].device.doesSessionSupportReferenceSpace(this[PRIVATE$15].id, type)) { throw new DOMException(`The ${type} reference space is not supported by this session.`, 'NotSupportedError'); } if (type === 'viewer') { return this[PRIVATE$15].viewerSpace; } let transform = await this[PRIVATE$15].device.requestFrameOfReferenceTransform(type); if (type === 'bounded-floor') { if (!transform) { throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); } let bounds = this[PRIVATE$15].device.requestStageBounds(); if (!bounds) { throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); } throw new DOMException(`The WebXR polyfill does not support the ${type} reference space yet.`, 'NotSupportedError'); } return new XRReferenceSpace(type, transform); } requestAnimationFrame(callback) { if (this[PRIVATE$15].ended) { return; } const handle = ++this[PRIVATE$15].frameHandle; this[PRIVATE$15].frameCallbacks.push({ handle, callback, cancelled: false }); return handle; } cancelAnimationFrame(handle) { let callbacks = this[PRIVATE$15].frameCallbacks; let index = callbacks.findIndex(d => d && d.handle === handle); if (index > -1) { callbacks[index].cancelled = true; callbacks.splice(index, 1); } callbacks = this[PRIVATE$15].currentFrameCallbacks; if (callbacks) { index = callbacks.findIndex(d => d && d.handle === handle); if (index > -1) { callbacks[index].cancelled = true; } } } get inputSources() { return this[PRIVATE$15].device.getInputSources(); } async end() { if (this[PRIVATE$15].ended) { return; } if (this[PRIVATE$15].immersive) { this[PRIVATE$15].ended = true; this[PRIVATE$15].device.removeEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); this[PRIVATE$15].device.removeEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); this[PRIVATE$15].device.removeEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); this[PRIVATE$15].device.removeEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); } this[PRIVATE$15].stopDeviceFrameLoop(); return this[PRIVATE$15].device.endSession(this[PRIVATE$15].id); } updateRenderState(newState) { if (this[PRIVATE$15].ended) { const message = "Can't call updateRenderState on an XRSession " + "that has already ended."; throw new Error(message); } if (newState.baseLayer && (newState.baseLayer._session !== this)) { const message = "Called updateRenderState with a base layer that was " + "created by a different session."; throw new Error(message); } const fovSet = (newState.inlineVerticalFieldOfView !== null) && (newState.inlineVerticalFieldOfView !== undefined); if (fovSet) { if (this[PRIVATE$15].immersive) { const message = "inlineVerticalFieldOfVi