summaryrefslogtreecommitdiff
path: root/chromium/third_party/webxr_test_pages
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 10:22:43 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 12:36:28 +0000
commit271a6c3487a14599023a9106329505597638d793 (patch)
treee040d58ffc86c1480b79ca8528020ca9ec919bf8 /chromium/third_party/webxr_test_pages
parent7b2ffa587235a47d4094787d72f38102089f402a (diff)
downloadqtwebengine-chromium-271a6c3487a14599023a9106329505597638d793.tar.gz
BASELINE: Update Chromium to 77.0.3865.59
Change-Id: I1e89a5f3b009a9519a6705102ad65c92fe736f21 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/webxr_test_pages')
-rw-r--r--chromium/third_party/webxr_test_pages/README.chromium9
-rwxr-xr-xchromium/third_party/webxr_test_pages/make_ot_samples_folder.py52
-rwxr-xr-xchromium/third_party/webxr_test_pages/update_bucket.py21
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/attribution.html154
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/css/stylesheet.css9
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/gamepad.html327
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/index.html28
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/index.published.html179
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html9
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/renderer.js2
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/plane-node.js99
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/gamepad-data-tables.js197
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/hit-test.js21
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js25
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js4898
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.min.js95
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.module.js6129
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js12
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/magic-window.html193
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/positional-audio.html14
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/proposals/index.html4
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection.html65
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html6
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/room-scale.html56
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html13
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/teleportation.html (renamed from chromium/third_party/webxr_test_pages/webxr-samples/input-selection.html)465
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html96
27 files changed, 10169 insertions, 3009 deletions
diff --git a/chromium/third_party/webxr_test_pages/README.chromium b/chromium/third_party/webxr_test_pages/README.chromium
index 5bb9adc5474..b5f5f719e68 100644
--- a/chromium/third_party/webxr_test_pages/README.chromium
+++ b/chromium/third_party/webxr_test_pages/README.chromium
@@ -42,3 +42,12 @@ In order to serve the samples locally, few steps are required:
serving media like the gltf files, try using "npm serve".
To install: `sudo npm install -g serve`
To run: `serve .` in src/third_party/webxr_test_pages/webxr-samples
+
+To publish samples for OT:
+
+1. python make_ot_samples_folder.py webxr-samples <dest-folder>
+ That copies just the subset of samples that we want to publish.
+
+2. Serve <dest-folder> locally and make sure everything works.
+
+3. python update_bucket.py --direct-publish-samples-source=<dest-folder> --direct-publish-samples-dest=<bucket-dest-subfolder>
diff --git a/chromium/third_party/webxr_test_pages/make_ot_samples_folder.py b/chromium/third_party/webxr_test_pages/make_ot_samples_folder.py
new file mode 100755
index 00000000000..93ad0c99d11
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/make_ot_samples_folder.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import sys
+
+samples_pages = [
+ 'xr-barebones.html',
+ 'magic-window.html',
+ 'teleportation.html',
+ 'gamepad.html'
+]
+
+other_pages = [
+ 'attribution.html',
+ 'favicon-32x32.png',
+ 'favicon-96x96.png',
+ 'favicon.ico',
+ 'LICENSE.md'
+]
+
+copy_folders = [
+ 'css',
+ 'js'
+]
+
+def make_ot_samples_folder(source, dest):
+ os.mkdir(dest)
+ for f in samples_pages:
+ shutil.copy(os.path.join(source, f), dest)
+ for f in other_pages:
+ shutil.copy(os.path.join(source, f), dest)
+ for f in copy_folders:
+ shutil.copytree(os.path.join(source, f), os.path.join(dest, f))
+ shutil.copy(
+ os.path.join(source, 'index.published.html'),
+ os.path.join(dest, 'index.html'))
+ shutil.make_archive('source', 'zip', dest)
+ shutil.move('source.zip', dest)
+
+ # media folder won't be included in the zip file or uploaded in any way as
+ # part of this process
+ shutil.copytree(os.path.join(source, 'media'), os.path.join(dest, 'media'))
+
+def main():
+ make_ot_samples_folder(sys.argv[1], sys.argv[2])
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/third_party/webxr_test_pages/update_bucket.py b/chromium/third_party/webxr_test_pages/update_bucket.py
index f06b94cce0c..3b42cc000a0 100755
--- a/chromium/third_party/webxr_test_pages/update_bucket.py
+++ b/chromium/third_party/webxr_test_pages/update_bucket.py
@@ -137,6 +137,15 @@ def write_to_bucket(cr_position):
# misconfigured. Sanity check and fix if needed.
check_and_fix_content_types(destination)
+def direct_publish_samples(source, dest_subfolder):
+ destination = 'gs://chromium-webxr-samples' + '/' + dest_subfolder
+ run_modify('gsutil.py', '-m', 'rsync', '-x', 'media', '-r', './' + source,
+ destination)
+
+ # The copy used mime types based on system-local mappings which may be
+ # misconfigured. Sanity check and fix if needed.
+ check_and_fix_content_types(destination)
+
def check_and_fix_content_types(destination):
mimetypes.init()
for suffix, content_type in SUFFIX_TYPES.iteritems():
@@ -269,6 +278,12 @@ content from failed uploads using the cloud console before retrying.
parser.add_argument('--bucket', default=BUCKET,
help=("Destination Cloud Storage location, including "
"'gs://' prefix"))
+ parser.add_argument('--direct-publish-samples-source', default=None,
+ help=("Publish samples from this folder directly to a "
+ "bucket."))
+ parser.add_argument('--direct-publish-samples-dest', default=None,
+ help=("Publish samples directly to this subfolder in the "
+ "chromium-webxr-samples bucket."))
global g_flags
g_flags = parser.parse_args()
@@ -283,6 +298,12 @@ content from failed uploads using the cloud console before retrying.
if os.path.isdir(node_modules):
raise Exception('Please delete the obsolete directory "%s"' % node_modules)
+ if g_flags.direct_publish_samples_source and g_flags.direct_publish_samples_dest:
+ direct_publish_samples(
+ g_flags.direct_publish_samples_source,
+ g_flags.direct_publish_samples_dest)
+ return
+
need_index_update = False
if g_flags.update_index_only:
need_index_update = True
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/attribution.html b/chromium/third_party/webxr_test_pages/webxr-samples/attribution.html
new file mode 100644
index 00000000000..d3db77151ba
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/attribution.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <meta http-equiv='X-UA-Compatible' content='chrome=1'>
+ <meta name='viewport' content='width=device-width, initial-scale=1'>
+ <meta name='mobile-web-app-capable' content='yes'>
+ <meta name='apple-mobile-web-app-capable' content='yes'>
+
+ <meta name='twitter:card' content='summary'>
+ <meta name='twitter:title' content='WebXR Samples'>
+ <meta name='twitter:description' content='Sample WebXR pages for testing and reference'>
+
+ <link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
+ <link rel="icon" type="image/png" sizes="96x96" href="favicon-96x96.png">
+
+ <link rel='stylesheet' href='css/stylesheet.css'>
+ <link rel='stylesheet' href='css/pygment_trac.css'>
+
+ <style>
+ article {
+ position: relative;
+ padding: 0.5em;
+ background-color: rgba(255, 255, 255, 0.90);
+ margin-bottom: 1em;
+ border-radius: 3px;
+ }
+
+ article h3 {
+ font-size: 1.0em;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+
+ article h3::before {
+ display: inline-block;
+ content: attr(data-index) ' - ';
+ font-weight: bold;
+ white-space: nowrap;
+ margin-right: 0.2em;
+ }
+
+ article h4 {
+ position: absolute;
+ right: 0.5em;
+ top: 0.5em;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+
+ article p {
+ margin: 0.5em;
+ }
+
+ article .links {
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ }
+
+ article a {
+ display: inline-block;
+ }
+
+ article a:not(:first-child)::before {
+ display: inline-block;
+ content: '•';
+ font-weight: bold;
+ white-space: nowrap;
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ }
+
+ .github-link {
+ font-size: 0.8em;
+ }
+ </style>
+
+ <!--[if lt IE 9]>
+ <script src='https://html5shiv.googlecode.com/svn/trunk/html5.js'></script>
+ <![endif]-->
+ <title>Models Attribution</title>
+ </head>
+ <body>
+ <p>
+ <b>Camp</b><br>
+ All models used in this scene are licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+"Campground" scene by Brandon Jones.<br>
+"[Lowpoly Squirrel](https://poly.google.com/view/eGdXC-5V2wM)" model by Tipatat Chennavasin.<br>
+"[Fox](https://poly.google.com/view/1DsQKS4G-aj)" model by Jake Blakeley.<br>
+"[Tent](https://poly.google.com/view/2tvQrMLf_tP)" model by Jarlan Perez.<br>
+"[Pine Tree](https://poly.google.com/view/2Qo-fmVKuSG)" and "[Pastel Plume Flowers](https://poly.google.com/view/eLVv17bTyB-)" models by Danny Bittman.<br>
+ </p>
+ <p>
+ <b>Cave</b><br>
+ All models used in this scene are licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+"Cave" scene by Brandon Jones.<br>
+"[Mushroom](https://poly.google.com/view/2DAaKHD48ZP)" and "[Bat](https://poly.google.com/view/fzJn9xTT-UO)" models by Poly by Google.<br>
+"[Crystal Cluster](https://poly.google.com/view/6NY2BPvOISW)" model by Lee Mason.<br>
+"[Tree-2](https://poly.google.com/view/cRipmFHCEVU)" model by Trackball.<br>
+ </p>
+ <p>
+ <b>Controller</b><br>
+ "[controller](https://poly.google.com/view/cdts4fBVXe7)" model by Jack Brookes is licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+ Minor edits by Brandon Jones.<br>
+ </p>
+ <p>
+ <b>Cube Room</b><br>
+ "[Cube Room](https://poly.google.com/view/1fahMeqZOw_)" model by Naomi Chen is licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+ </p>
+ <p>
+ <b>Garage</b><br>
+All models used in this scene are licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+"Garage" scene by Brandon Jones.<br>
+"[Light Switch](https://poly.google.com/view/7yVvvpp-ftQ)", "[CRT Monitor](https://poly.google.com/view/8jVB0zIXKCv)", "[Fire Extinguisher](https://poly.google.com/view/71rR7PaeXNN)", "[Wooden Stool](https://poly.google.com/view/dn419U6vWYx)", "[Cork Board](https://poly.google.com/view/5Ql0Sdq6fmy)", "[Industrial Broom](https://poly.google.com/view/eH6PcHmWOdK)", "[Wall Shelf](https://poly.google.com/view/7544dJq1UVu)", and "[HTC Vive Headset](https://poly.google.com/view/bFZbl-mmCeD)" models by Jarlan Perez.<br>
+"[Red Cooler](https://poly.google.com/view/f7q6m6IL8UI)" model by S. Paul Michael.<br>
+"[Ladder](https://poly.google.com/view/32UszyQQLtJ)" model by Carwyn Pelley.<br>
+"[Window](https://poly.google.com/view/dwBpM-aSA_t)" model by Justin Randall.<br>
+"[SNES](https://poly.google.com/view/7yVvvpp-ftQ)" model by Gabriel Valdivia.<br>
+ </p>
+ <p>
+ <b>Headset</b><br>
+ "[VR Headset](https://poly.google.com/view/bvd33G7Q66m)" model by Poly by Google is licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+ </p>
+ <p>
+ <b>Home Theater</b><br>
+All models used in this scene are licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+"[Home Theater](https://poly.google.com/view/6wJboiESaWR)" scene by Brandon Jones.<br>
+"[Projector](https://poly.google.com/view/4oVHZbDvwV8)" and "[Window](https://poly.google.com/view/9FqbXmzB-CS)" models by Jonathan Granskog.<br>
+"[Woonkamerkast](https://poly.google.com/view/70n22Lhssat)" model by Vincent van de Goolberg.<br>
+"[Nice Door](https://poly.google.com/view/00xFHE4LR_6)" model by Wesley Thompson.<br>
+ </p>
+ <p>
+ <b>Space</b><br>
+ "[Solar System](https://poly.google.com/view/8hnnpNiQMmy)" model by Jarlan Perez is licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+ </p>
+ <p>
+ <b>Stereo</b><br>
+ "[Stereo](https://poly.google.com/view/5gXgHgP-dmh)" model by Poly by Google is licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+ </p>
+ <p>
+ <b>Sunflower</b><br>
+ All models used in this application are licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+ "[Sunflower](https://poly.google.com/view/ce4GXw3VYE5)" by Poly by Google.<br>
+ </p>
+ <p>
+ <b>Textures</b><br>
+ "[Le panorama de la Voie Lactée](http://www.eso.org/public/images/eso0932a/)" image by European Southern Observatory is licensed under [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/legalcode).<br>
+ </p>
+ <p>
+ <b>Video</b><br>
+ "[Big Buck Bunny](https://peach.blender.org/about/)" by the [Blender Foundation](www.blender.org) is licensed under [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode).<br>
+ </p>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/css/stylesheet.css b/chromium/third_party/webxr_test_pages/webxr-samples/css/stylesheet.css
index d63a1194948..322727307fb 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/css/stylesheet.css
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/css/stylesheet.css
@@ -69,13 +69,12 @@ a:hover {
}
.wordmark > span {
- background: #2ea;
+ background: #369;
box-shadow: 3px 3px 0 0 rgba(0,0,0,.15);
color: #fff;
display: inline-block;
- font-size: 64px;
- font-size: calc(16px + 1vh + 3vw); /* Responsive font-size for mobile */
- font-style: italic;
+ font-size: 48px;
+ /*font-size: calc(16px + 1vh + 3vw);*/ /* Responsive font-size for mobile */
font-weight: 300;
margin-bottom: 15px;
max-width: 100%;
@@ -88,7 +87,7 @@ a:hover {
}
.wordmark:hover > span {
- background: #2ea;
+ background: #369;
box-shadow: 3px 3px 0 0 rgba(0,0,0,.25);
}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/gamepad.html b/chromium/third_party/webxr_test_pages/webxr-samples/gamepad.html
new file mode 100644
index 00000000000..0685c48669d
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/gamepad.html
@@ -0,0 +1,327 @@
+<!doctype html>
+<!--
+Copyright 2018 The Immersive Web Community Group
+
+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.
+-->
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <meta name='viewport' content='width=device-width, initial-scale=1, user-scalable=no'>
+ <meta name='mobile-web-app-capable' content='yes'>
+ <meta name='apple-mobile-web-app-capable' content='yes'>
+
+ <!-- Origin Trial Token, feature = WebXR Device API (For Chrome M76+), origin = storage.googleapis.com, expires = 2019-07-24 -->
+ <meta http-equiv="origin-trial" data-feature="WebXR Device API (For Chrome M76+)" data-expires="2019-07-24" content="Ap6io/uhkGK7vXCD+golNnQfj8wJ4so790EzZoqb8YOljMXIBTvBEQFPTHYIz5d/BgtuwZTKOLrmHAOt30f38g8AAABxeyJvcmlnaW4iOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb206NDQzIiwiZmVhdHVyZSI6IldlYlhSRGV2aWNlTTc2IiwiZXhwaXJ5IjoxNTY0MDA5MzU2LCJpc1N1YmRvbWFpbiI6dHJ1ZX0=">
+
+ <title>Gamepad</title>
+
+ <link href='css/common.css' rel='stylesheet'></link>
+
+ <!--The polyfill is not needed for browser that have native API support,
+ but is linked by these samples for wider compatibility.-->
+ <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script-->
+ <script src='js/xrray-polyfill.js' type='module'></script>
+ <script src='js/webxr-polyfill.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Gamepad</summary>
+ <p>
+ This sample demonstrates using XRInputSource Gamepad button presses
+ to change box color and joystick/touchpad input to move boxes in 2
+ dimensions.
+ <a class="back" href="./index.html">Back</a>
+ </p>
+ </details>
+ </header>
+ <div id="gamepad-details">
+ <!-- Tables updated in real-time data from WebXR gamepads will be
+ displayed here if requested. -->
+ </div>
+ <script type="module">
+ import {Scene} from './js/cottontail/src/scenes/scene.js';
+ import {Renderer, createWebGLContext} from './js/cottontail/src/core/renderer.js';
+ import {Gltf2Node} from './js/cottontail/src/nodes/gltf2.js';
+ import {QueryArgs} from './js/cottontail/src/util/query-args.js';
+ import {FallbackHelper} from './js/cottontail/src/util/fallback-helper.js';
+ import {Node} from './js/cottontail/src/core/node.js';
+ import {PbrMaterial} from './js/cottontail/src/materials/pbr.js';
+ import {BoxBuilder} from './js/cottontail/src/geometry/box-builder.js';
+ import {mat4, vec3, quat} from './js/cottontail/src/math/gl-matrix.js';
+ import {GamepadTableManager} from './js/gamepad-data-tables.js';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+
+ // If requested, don't display the frame rate info.
+ let hideStats = QueryArgs.getBool('hideStats', false);
+
+ // Display HTML tables updated in real-time with gamepad data. Useful for
+ // testing + debugging.
+ let displayTables = QueryArgs.getBool('displayTables', false);
+ let tableManager = null;
+ if (displayTables) {
+ tableManager = new GamepadTableManager();
+ }
+
+ // XR globals.
+ let xrButton = null;
+ let xrRefSpace = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ if (hideStats) {
+ scene.enableStats(false);
+ }
+ scene.addNode(new Gltf2Node({url: '../media/gltf/cube-room/cube-room.gltf'}));
+ scene.standingStats(true);
+
+ let floorSize = 10;
+ let floorPosition = [0, -floorSize / 2 + 0.01, 0];
+ let floorNode = null;
+
+ let boxTable = {};
+
+ class GamepadBox {
+ constructor(position) {
+ this.position = position;
+ let boxBuilder = new BoxBuilder();
+ boxBuilder.pushCube([0, 0, 0], 0.4);
+ let boxPrimitive = boxBuilder.finishPrimitive(renderer);
+ let boxMaterial = new PbrMaterial();
+ boxMaterial.baseColorFactor.value = [1, 0, 0, 1]; // red
+ this.renderPrimitive = renderer.createRenderPrimitive(boxPrimitive, boxMaterial);
+
+ this.node = new Node();
+ this.node.addRenderPrimitive(this.renderPrimitive);
+ scene.addNode(this.node);
+
+ this.color_state = true;
+ this.is_button_pressed = false;
+ }
+
+ toggle_color() {
+ this.renderPrimitive.uniforms.baseColorFactor.value = this.color_state ?
+ [0, 1, 0, 1] : // green
+ [1, 0, 0, 1]; // red
+ this.color_state = !this.color_state;
+ }
+
+ // If this was something like a full-fledged game instead of just a
+ // sample, timestamps should be used when calculating how much to move
+ // on each frame. The way this code is right now, having a higher frame
+ // rate means the boxes move faster.
+ move(dx, dy) {
+ const inv_speed = 100;
+ let translation = [dx / inv_speed, dy / inv_speed, 0];
+ vec3.add(this.position, this.position, translation);
+ }
+
+ // Returns true iff button which was previously pressed is not pressed
+ // anymore. The WebXR + Gamepad APIs don't support button press events
+ // (yet) which is why keeping track of the state this way is necessary.
+ update_button_state(is_button_pressed) {
+ let did_button_fire = this.is_button_pressed && !is_button_pressed;
+ this.is_button_pressed = is_button_pressed;
+ return did_button_fire;
+ }
+ }
+
+ class GamepadBoxSet {
+ constructor(button_count, y) {
+ // Place the boxes in a horizontal line 2 meters in front of the user.
+ this.boxes = [];
+ let x_shift = button_count / 2;
+ for (let x = 1; x <= button_count; ++x) {
+ this.boxes.push(new GamepadBox([x - x_shift, y, -2]));
+ }
+ }
+
+ update_state(gamepad) {
+ // A button press (pressing and then releasing a button) will change
+ // the associated box's color from red to green (or from green to red
+ // if it's currently green).
+ for (let i = 0; i < gamepad.buttons.length; ++i) {
+ if (this.boxes[i].update_button_state(gamepad.buttons[i].pressed)) {
+ this.boxes[i].toggle_color();
+ }
+ }
+
+ if (gamepad.mapping == "xr-standard") {
+ // Invert the y axis because gamepads follow the convention that -1
+ // is up/forwards, but we want to have a forward joystick/touchpad
+ // input result in forward motion for the box.
+
+ // xr-standard Gamepads always have at least one touchpad/joystick.
+ // Its button will always be in the second slot.
+ let dx = gamepad.axes[0];
+ let dy = -gamepad.axes[1];
+ this.boxes[1].move(dx, dy);
+
+ if (gamepad.axes.length >= 4 && gamepad.buttons.length >= 4) {
+ // If an xr-standard Gamepad has a secondary touchpad/joystick, its
+ // button will be in the 4th slot and it will use the second pair
+ // of input axes.
+ dx = gamepad.axes[2];
+ dy = -gamepad.axes[3];
+ this.boxes[3].move(dx, dy);
+ }
+ }
+ }
+
+ update() {
+ // Update the matrix for each box so that they are rendered in the
+ // correct positions.
+ for (let box of this.boxes) {
+ mat4.identity(box.node.matrix);
+ mat4.translate(box.node.matrix, box.node.matrix, box.position);
+ }
+ }
+ }
+
+ function ProcessGamepad(gamepad, hand) {
+ if (displayTables) {
+ tableManager.update(gamepad, hand);
+ }
+
+ if (!(hand in boxTable)) {
+ const y_positions = {
+ "left" : 1,
+ "right" : 2,
+ "none" : 3,
+ };
+ boxTable[hand] = new GamepadBoxSet(gamepad.buttons.length, y_positions[hand]);
+ }
+
+ boxTable[hand].update_state(gamepad);
+ }
+
+ // Don't bother starting an inline session in this sample since WebXR
+ // gamepads are not available during inline sessions.
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: (session) => session.end(),
+ supportedSessionTypes: ['immersive-vr']
+ });
+ xrButton.addToHeader();
+ }
+
+ function initGL() {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ xrCompatible: true
+ });
+ document.body.appendChild(gl.canvas);
+
+ function onResize() {
+ gl.canvas.width = (gl.canvas.offsetWidth * window.devicePixelRatio);
+ gl.canvas.height = (gl.canvas.offsetHeight * window.devicePixelRatio);
+ }
+ window.addEventListener('resize', onResize);
+ onResize();
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: '../media/gltf/controller/controller.gltf'}));
+
+ addFloorBox();
+ }
+
+ function addFloorBox() {
+ let boxBuilder = new BoxBuilder();
+ boxBuilder.pushCube([0, 0, 0], floorSize);
+ let boxPrimitive = boxBuilder.finishPrimitive(renderer);
+
+ let boxMaterial = new PbrMaterial();
+ boxMaterial.baseColorFactor.value = [0.3, 0.3, 0.3, 1.0];
+ let boxRenderPrimitive = renderer.createRenderPrimitive(boxPrimitive, boxMaterial);
+
+ floorNode = new Node();
+ floorNode.addRenderPrimitive(boxRenderPrimitive);
+ floorNode.selectable = true;
+ scene.addNode(floorNode);
+ mat4.identity(floorNode.matrix);
+ mat4.translate(floorNode.matrix, floorNode.matrix, floorPosition);
+ }
+
+ function onRequestSession() {
+ navigator.xr.requestSession('immersive-vr').then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', () => xrButton.setSession(null));
+
+ initGL();
+
+ session.updateRenderState({
+ baseLayer : new XRWebGLLayer(session, gl)
+ });
+
+ session.requestReferenceSpace('local-floor').then((refSpace) => {
+ // Save the session-specific reference space.
+ xrRefSpace = refSpace;
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onXRFrame(time, frame) {
+ let session = frame.session;
+ let pose = frame.getViewerPose(xrRefSpace);
+ scene.startFrame();
+ session.requestAnimationFrame(onXRFrame);
+
+ // Check for and respond to any gamepad state changes.
+ for (let source of session.inputSources) {
+ if (source.gamepad) {
+ ProcessGamepad(source.gamepad, source.handedness);
+ }
+ }
+
+ if (displayTables) {
+ tableManager.nextFrame();
+ }
+
+ for (let hand in boxTable) {
+ boxTable[hand].update();
+ }
+
+ scene.updateInputSources(frame, xrRefSpace);
+ scene.drawXRFrame(frame, pose);
+ scene.endFrame();
+ }
+
+ // Start the XR application.
+ initXR();
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/index.html b/chromium/third_party/webxr_test_pages/webxr-samples/index.html
index 12bcb477498..57d1a8eb38e 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/index.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/index.html
@@ -100,6 +100,13 @@
<script>
let pages = [
+ { title: 'Barebones', category: 'Basics',
+ path: 'xr-barebones.html',
+ description: 'Extremely simple use of WebXR with no library dependencies. Doesn\'t render anything exciting.' },
+
+ { tag: 'hr' },
+ { tag: 'br' },
+
{ title: 'XR Presentation', category: 'Basics',
path: 'xr-presentation.html',
description: 'Demonstrates how to present a simple WebGL scene to a XRDevice.' },
@@ -127,9 +134,13 @@
path: 'input-tracking.html',
description: 'Demonstrates basic tracking and rendering of XRInputSources.'},
- { title: 'Input Selection', category: 'Input',
- path: 'input-selection.html',
- description: 'Demonstrates handling \'select\' events generated by XRInputSources.'},
+ { title: 'Teleportation', category: 'Input',
+ path: 'teleportation.html',
+ description: 'Demonstrates teleporting the viewer by updating the XRSession reference space.' },
+
+ { title: 'Gamepad', category: 'Input',
+ path: 'gamepad.html',
+ description: 'Demonstrates handling input from Gamepads attached to XRInputSources.' },
{ title: 'Framebuffer Scaling', category: 'Performance',
path: 'framebuffer-scaling.html',
@@ -150,22 +161,17 @@
{ title: 'Spectator Mode', category: 'Advanced Techniques',
path: 'spectator-mode.html',
description: 'Demonstrates rendering a 3rd person view of the scene to an external monitor.' },
-
- { tag: 'hr' },
- { tag: 'br' },
-
- { title: 'Barebones', category: 'WIN32_LEAN_AND_MEAN',
- path: 'xr-barebones.html',
- description: 'Extremely simple use of WebXR with no library dependencies. Doesn\'t render anything exciting.' },
];
let mainElement = document.getElementById("main");
// Append an element for every item in the pages list.
+ let tag_count = 0;
for (var i = 0; i < pages.length; ++i) {
var page = pages[i];
if (page.tag) {
+ tag_count++;
mainElement.appendChild(document.createElement(page.tag));
continue;
}
@@ -173,7 +179,7 @@
let article = document.createElement('article');
let title = document.createElement('h3');
- title.setAttribute('data-index', i + 1);
+ title.setAttribute('data-index', i + 1 - tag_count);
let titleLink = document.createElement('a');
titleLink.href = page.path;
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/index.published.html b/chromium/third_party/webxr_test_pages/webxr-samples/index.published.html
new file mode 100644
index 00000000000..3ed2391eb3f
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/index.published.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <meta http-equiv='X-UA-Compatible' content='chrome=1'>
+ <meta name='viewport' content='width=device-width, initial-scale=1'>
+ <meta name='mobile-web-app-capable' content='yes'>
+ <meta name='apple-mobile-web-app-capable' content='yes'>
+
+ <meta name='twitter:card' content='summary'>
+ <meta name='twitter:title' content='WebXR Samples'>
+ <meta name='twitter:description' content='Sample WebXR pages for testing and reference'>
+
+ <link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
+ <link rel="icon" type="image/png" sizes="96x96" href="favicon-96x96.png">
+
+ <link rel='stylesheet' href='css/stylesheet.css'>
+ <link rel='stylesheet' href='css/pygment_trac.css'>
+
+ <style>
+ article {
+ position: relative;
+ padding: 0.5em;
+ background-color: rgba(255, 255, 255, 0.90);
+ margin-bottom: 1em;
+ border-radius: 3px;
+ }
+
+ article h3 {
+ font-size: 1.0em;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+
+ article h3::before {
+ display: inline-block;
+ content: attr(data-index) ' - ';
+ font-weight: bold;
+ white-space: nowrap;
+ margin-right: 0.2em;
+ }
+
+ article h4 {
+ position: absolute;
+ right: 0.5em;
+ top: 0.5em;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+
+ article p {
+ margin: 0.5em;
+ }
+
+ article .links {
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ }
+
+ article a {
+ display: inline-block;
+ }
+
+ article a:not(:first-child)::before {
+ display: inline-block;
+ content: '•';
+ font-weight: bold;
+ white-space: nowrap;
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ }
+
+ .github-link {
+ font-size: 0.8em;
+ }
+ </style>
+
+ <!--[if lt IE 9]>
+ <script src='https://html5shiv.googlecode.com/svn/trunk/html5.js'></script>
+ <![endif]-->
+ <title>WebXR - Samples</title>
+ </head>
+ <body>
+
+ <div class='container' id='container'>
+ <h1><a href='' class='wordmark'><span>WebXR Samples for Chrome</span></a></h1>
+ </header>
+
+ <main class='main' id='main'>
+ <p>Sample pages demonstrating how to use various aspects of the WebXR API <b><em>as implemented in Chrome versions 76-77.</b></em><br/>
+ Note: these samples will only work when visiting this site securely (https://).</p>
+
+ <script>
+ let pages = [
+ { title: 'Barebones', category: 'Basics',
+ path: 'xr-barebones.html',
+ description: 'Extremely simple use of WebXR with no library dependencies. Doesn\'t render anything exciting.' },
+
+ { title: 'Magic Window', category: 'Basics',
+ path: 'magic-window.html',
+ description: 'Demonstrates use of a non-exclusive XRSession to present "Magic Window" content.' },
+
+ { title: 'Teleportation', category: 'Spatial Tracking, Input',
+ path: 'teleportation.html',
+ description: 'Demonstrates teleporting the viewer by updating the XRSession reference space.' },
+
+ { title: 'Gamepad', category: 'Input',
+ path: 'gamepad.html',
+ description: 'Demonstrates handling input from Gamepads attached to XRInputSources.' }
+ ];
+
+ let mainElement = document.getElementById("main");
+
+ // Append an element for every item in the pages list.
+ let tag_count = 0;
+ for (var i = 0; i < pages.length; ++i) {
+ var page = pages[i];
+
+ if (page.tag) {
+ tag_count++;
+ mainElement.appendChild(document.createElement(page.tag));
+ continue;
+ }
+
+ let article = document.createElement('article');
+
+ let title = document.createElement('h3');
+ title.setAttribute('data-index', i + 1 - tag_count);
+
+ let titleLink = document.createElement('a');
+ titleLink.href = page.path;
+ titleLink.innerHTML = page.title;
+ title.appendChild(titleLink);
+ article.appendChild(title);
+
+ let category = document.createElement('h4');
+ category.innerHTML = page.category;
+ article.appendChild(category);
+
+ let description = document.createElement('p');
+ description.innerHTML = page.description;
+ article.appendChild(description);
+
+ let links = document.createElement('div');
+ links.classList.add('links');
+
+ let liveLink = document.createElement('a');
+ liveLink.href = page.path;
+ liveLink.innerHTML = 'Open';
+ links.appendChild(liveLink);
+
+ let polyfillLink = document.createElement('a');
+ polyfillLink.href = page.path + '?allowPolyfill=1';
+ polyfillLink.innerHTML = 'Open with Polyfill';
+ links.appendChild(polyfillLink);
+
+ article.appendChild(links);
+
+ mainElement.appendChild(article);
+ }
+ </script>
+ </main>
+
+ <p>Models used in these samples come from <a href="https://poly.google.com">Poly</a>, and many were modeled in <a href="https://vr.google.com/blocks/">Blocks</a>.<br/>
+ They are stored and loaded using the <a href="https://www.khronos.org/gltf/">glTF 2.0 format</a>.<br/>
+ Attribution for individual models can be found <a href="attribution.html">here</a>.</p>
+
+ <p>To host these samples locally:<br></p>
+ <ol>
+ <li>Download and unzip <a href="source.zip">source</a></li>
+ <li>Download and unzip <a href="../media.zip">media</a> to a subfolder in your local source.</li>
+ <li>Run a command in your local source directory, such as "python -m SimpleHTTPServer"</li>
+ </ol>
+
+ <footer class='footer'>
+ </footer>
+ </div>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html b/chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html
index 6b5d7fd72de..c5ae2658211 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html
@@ -154,8 +154,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}, (e) => {
if (!session.mode.startsWith('immersive')) {
// If we're in inline mode, our underlying platform may not support
- // the stationary reference space, but an identity space is guaranteed.
- return session.requestReferenceSpace('viewer');
+ // the local-floor reference space, but a viewer space is guaranteed.
+ return session.requestReferenceSpace('viewer').then((viewerRefSpace) => {
+ // Adjust the viewer space for an estimated user height. Otherwise,
+ // the poses queried with this space will originate from the floor.
+ let xform = new XRRigidTransform({x: 0, y: -1.5, z: 0});
+ return viewerRefSpace.getOffsetReferenceSpace(xform);
+ });
} else {
throw e;
}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/renderer.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/renderer.js
index 04ebf2d66a1..c4d7c346180 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/renderer.js
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/renderer.js
@@ -557,7 +557,7 @@ export class Renderer {
if (buffer._buffer) {
let gl = this._gl;
gl.bindBuffer(buffer._target, buffer._buffer);
- if (offset == 0 && buffer._length == data.byteLength) {
+ if (offset == 0 && buffer._length <= data.byteLength) {
gl.bufferData(buffer._target, data, buffer._usage);
} else {
gl.bufferSubData(buffer._target, offset, data);
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/plane-node.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/plane-node.js
index 95d59e44ee2..ad28946229c 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/plane-node.js
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/plane-node.js
@@ -18,8 +18,9 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import {Material, RENDER_ORDER} from '../core/material.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
import {Node} from '../core/node.js';
-import {GeometryBuilderBase} from '../geometry/primitive-stream.js';
+import {vec3} from '../math/gl-matrix.js';
const GL = WebGLRenderingContext; // For enums
@@ -45,7 +46,6 @@ class PlaneMaterial extends Material {
get vertexSource() {
return `
attribute vec3 POSITION;
- attribute vec3 NORMAL;
varying vec3 vLight;
@@ -54,7 +54,7 @@ class PlaneMaterial extends Material {
const vec3 lightColor = vec3(0.75, 0.75, 0.75);
vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
- vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));
+ vec3 normalRotated = vec3(model * vec4(0.0, 0.0, 1.0, 0.0));
float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);
vLight = ambientColor + (lightColor * lightFactor);
return proj * view * model * vec4(POSITION, 1.0);
@@ -87,28 +87,85 @@ export class PlaneNode extends Node {
this.baseColor = options.baseColor;
this.polygon = options.polygon;
+ // ring buffer containing last 3 plane primitives (meshes)
+ this.primitives = [null, null, null];
+ this.primitiveIndex = -1;
+
this._material = new PlaneMaterial({baseColor : options.baseColor});
this._renderer = null;
}
createPlanePrimitive(polygon) {
- // TODO: create new builder class for planes
- let planeBuilder = new GeometryBuilderBase();
+ let vertices = [];
+ let indices = [];
+ let min = null;
+ let max = null;
- planeBuilder.primitiveStream.startGeometry();
- let numVertices = polygon.length;
- let firstVertex = planeBuilder.primitiveStream.nextVertexIndex;
+ // first, collect all polygon vertices
polygon.forEach(vertex => {
- planeBuilder.primitiveStream.pushVertex(vertex.x, vertex.y, vertex.z);
+ vertices.push(vertex.x, vertex.y, vertex.z);
+
+ if(min) {
+ min[0] = Math.min(min[0], vertex.x);
+ min[1] = Math.min(min[1], vertex.y);
+ min[2] = Math.min(min[2], vertex.z);
+ } else {
+ min = vec3.fromValues(vertex.x, vertex.y, vertex.z);
+ }
+
+ if(max) {
+ max[0] = Math.min(min[0], vertex.x);
+ max[1] = Math.min(max[1], vertex.y);
+ max[2] = Math.min(max[2], vertex.z);
+ } else {
+ max = vec3.fromValues(vertex.x, vertex.y, vertex.z);
+ }
});
- for(let i = 0; i < numVertices - 2; i++) {
- planeBuilder.primitiveStream.pushTriangle(firstVertex, firstVertex + i + 1, firstVertex + i + 2);
+ // then indices
+ for(let i = 0; i < polygon.length - 2; i++) {
+ indices.push(0, i + 1, i + 2);
+ }
+
+ let newPrimitiveIndex = (this.primitiveIndex + 1) % this.primitives.length;
+ if(this.primitives[newPrimitiveIndex]) {
+ // update
+ let oldPrimitive = this.primitives[newPrimitiveIndex];
+
+ this._renderer.updateRenderBuffer(oldPrimitive.attributes[0].buffer, new Float32Array(vertices));
+ this._renderer.updateRenderBuffer(oldPrimitive.indexBuffer, new Uint16Array(indices));
+
+ // attribs are still set, no need to re-set them
+
+ // index buffer is still set, no need to re-set it
+ oldPrimitive.setBounds(min, max);
+ oldPrimitive.elementCount = indices.length;
+ } else {
+ // add
+ let vertexBuffer = this._renderer.createRenderBuffer(
+ GL.ARRAY_BUFFER, new Float32Array(vertices));
+ let indexBuffer = this._renderer.createRenderBuffer(
+ GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ let position_attribute = new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 12, 0);
+
+ let newPrimitive = new Primitive([position_attribute], indices.length);
+ newPrimitive.setIndexBuffer(indexBuffer);
+ newPrimitive.setBounds(min, max);
+
+ this.primitives[newPrimitiveIndex] = newPrimitive;
}
- planeBuilder.primitiveStream.endGeometry();
- return planeBuilder.finishPrimitive(this._renderer);
+ this.primitiveIndex = newPrimitiveIndex;
+ }
+
+ get primitive() {
+ if(!this.primitives[this.primitiveIndex]) {
+ throw new Error(`Primitive is not set! Call createPlanePrimitive first!`);
+ }
+
+ return this.primitives[this.primitiveIndex];
}
onRendererChanged(renderer) {
@@ -117,8 +174,9 @@ export class PlaneNode extends Node {
this._renderer = renderer;
- this.planeNode = this._renderer.createRenderPrimitive(
- this.createPlanePrimitive(this.polygon), this._material);
+ this.createPlanePrimitive(this.polygon);
+
+ this.planeNode = this._renderer.createRenderPrimitive(this.primitive, this._material);
this.addRenderPrimitive(this.planeNode);
this.polygon = null;
@@ -130,9 +188,16 @@ export class PlaneNode extends Node {
if(this.polygon)
throw new Error(`Polygon is set on a plane where it shouldn't be!`);
- let updatedPrimitive = this.createPlanePrimitive(polygon);
+ this.createPlanePrimitive(polygon);
+
+ // eagerly clean up render primitive's VAO
+ if(this.planeNode._vao) {
+ this._renderer._vaoExt.deleteVertexArrayOES(this.planeNode._vao);
+ this.planeNode._vao = null;
+ }
+
+ this.planeNode.setPrimitive(this.primitive);
- this.planeNode.setPrimitive(updatedPrimitive);
return this.planeNode.waitForComplete();
}
}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/gamepad-data-tables.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/gamepad-data-tables.js
new file mode 100644
index 00000000000..55f13761518
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/gamepad-data-tables.js
@@ -0,0 +1,197 @@
+// Copyright 2018 The Immersive Web Community Group
+//
+// 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.
+
+class GamepadTable {
+ constructor(title, cols, parent) {
+ this.table = document.createElement("table");
+ this.table.setAttribute("border", 1);
+ this.body = document.createElement("tbody");
+ this.AddHeader(title, cols);
+ this.table.appendChild(this.body);
+ parent.appendChild(this.table);
+ }
+
+ AddHeader(title, cols) {
+ let row = document.createElement("tr");
+ let th = document.createElement("th");
+ th.setAttribute("colspan", cols);
+ th.appendChild(document.createTextNode(title));
+ row.appendChild(th);
+ this.body.appendChild(row);
+ }
+
+ AddCell(row, text) {
+ let cell = document.createElement("td");
+ cell.appendChild(document.createTextNode(text));
+ row.appendChild(cell);
+ return cell;
+ }
+
+ AddRow(values) {
+ let cells = [];
+ let row = document.createElement("tr");
+ for (let i = 0; i < values.length; ++i) {
+ cells.push(this.AddCell(row, values[i]));
+ }
+ this.body.appendChild(row);
+ return cells;
+ }
+}
+
+class ButtonTable extends GamepadTable {
+ constructor(buttons, parent) {
+ super("button data", 3, parent);
+
+ this.AddRow(["pressed", "touched", "value"]);
+
+ this.pressed_cells = [];
+ this.touched_cells = [];
+ this.value_cells = [];
+
+ this.pressed = [];
+ this.touched = [];
+ this.values = [];
+
+ for (let i = 0; i < buttons.length; ++i) {
+ this.pressed.push(buttons[i].pressed);
+ this.touched.push(buttons[i].touched);
+ this.values.push(buttons[i].value);
+ let cells = this.AddRow([buttons[i].pressed, buttons[i].touched, buttons[i].value.toFixed(3)]);
+ this.pressed_cells.push(cells[0]);
+ this.touched_cells.push(cells[1]);
+ this.value_cells.push(cells[2]);
+ }
+ }
+
+ update(buttons) {
+ for (let i = 0; i < buttons.length; ++i) {
+ const is_pressed = buttons[i].pressed;
+ if (this.pressed[i] != is_pressed) {
+ this.pressed_cells[i].innerHTML = is_pressed;
+ this.pressed[i] = is_pressed;
+ }
+ const is_touched = buttons[i].touched;
+ if (this.touched[i] != is_touched) {
+ this.touched_cells[i].innerHTML = is_touched;
+ this.touched[i] = is_touched;
+ }
+ const value = buttons[i].value;
+ if (this.values[i] != value) {
+ this.value_cells[i].innerHTML = value.toFixed(3);
+ this.values[i] = value;
+ }
+ }
+ }
+}
+
+class AxesTable extends GamepadTable {
+ constructor(axes, parent) {
+ super("axis values", 1, parent);
+
+ this.values = [];
+ for (let i = 0; i < axes.length; ++i) {
+ this.values.push(axes[i]);
+ }
+
+ this.cells = [];
+ for (let i = 0; i < axes.length; ++i) {
+ let temp_cells = this.AddRow([axes[i].toFixed(3)]);
+ this.cells.push(temp_cells[0]);
+ }
+ }
+
+ update(axes) {
+ // assumes length is still the same
+ for (let i = 0; i < axes.length; ++i) {
+ if (this.values[i] != axes[i]) {
+ this.cells[i].innerHTML = axes[i].toFixed(3);
+ this.values[i] = axes[i];
+ }
+ }
+ }
+}
+
+class InfoTable extends GamepadTable {
+ constructor(gamepad, parent) {
+ super("Gamepad", 2, parent);
+
+ this.id = gamepad.id;
+ this.mapping = gamepad.mapping;
+
+ this.id_cell = this.AddRow(["id", gamepad.id])[1];
+ this.mapping_cell = this.AddRow(["mapping", gamepad.mapping])[1];
+ }
+
+ update(gamepad) {
+ if (this.id != gamepad.id) {
+ this.id_cell.innerHTML = gamepad.id;
+ this.id = gamepad.id;
+ }
+ if (this.mapping != gamepad.mapping) {
+ this.mapping_cell.innerHTML = gamepad.mapping;
+ this.mapping = gamepad.mapping;
+ }
+ }
+}
+
+export class GamepadTableManager {
+ constructor() {
+ this.frame_number = 0;
+ this.tables = {};
+ }
+
+ nextFrame() {
+ this.frame_number++;
+ }
+
+ update(gamepad, hand) {
+ // Construct the tables if necessary. Must check this every frame
+ // because otherwise, the table doesn't get created until the gamepad
+ // has an input change on a frame that's a multiple of 10.
+ if (!(hand in this.tables)) {
+ let div = document.getElementById("gamepad-details");
+ let header = document.createElement("header");
+ let details = document.createElement("details");
+ details.setAttribute("id", "gamepad-details-hand-" + hand);
+ details.setAttribute("open", "");
+ let summary = document.createElement("summary");
+ summary.innerHTML = hand + "-hand Gamepad";
+ let p = document.createElement("p");
+ p.innerHTML = "Real-time info for gamepad associated with " + hand + " hand.";
+ details.appendChild(summary);
+ details.appendChild(p);
+ header.appendChild(details);
+ div.appendChild(header);
+
+ this.tables[hand] = {
+ info : new InfoTable(gamepad, details),
+ axes : new AxesTable(gamepad.axes, details),
+ buttons : new ButtonTable(gamepad.buttons, details)
+ };
+ }
+
+ // Only update the gamepad tables once every 10 frames for perf reasons.
+ if ((this.frame_number % 10) == 0) {
+ this.tables[hand].info.update(gamepad);
+ this.tables[hand].axes.update(gamepad.axes);
+ this.tables[hand].buttons.update(gamepad.buttons);
+ }
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/hit-test.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/hit-test.js
index e88a69d058b..00cd512c90f 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/js/hit-test.js
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/hit-test.js
@@ -117,8 +117,8 @@ let calculateHitMatrix = function(ray_vector, plane_normal, point) {
}
// single plane hit test - doesn't take into account the plane's polygon
-function hitTestPlane(ray, plane, frameOfReference) {
- const plane_pose = plane.getPose(frameOfReference);
+function hitTestPlane(frame, ray, plane, frameOfReference) {
+ const plane_pose = frame.getPose(plane.planeSpace, frameOfReference);
const plane_normal = transform_point_by_matrix(
plane_pose.transform.matrix, {x : 0, y : 1.0, z : 0, w : 0});
const plane_center = normalize_perspective(
@@ -174,12 +174,21 @@ function hitTestPlane(ray, plane, frameOfReference) {
}
// multiple planes hit test
-export function hitTest(ray, planes, frameOfReference) {
- const hit_test_results = planes.map(plane => hitTestPlane(ray, plane, frameOfReference));
+export function hitTest(frame, ray, frameOfReference) {
+ const planes = frame.worldInformation.detectedPlanes;
+
+ let hit_test_results = [];
+ planes.forEach(plane => {
+ let result = hitTestPlane(frame, ray, plane, frameOfReference);
+ if(result) {
+ // throw away results with no intersection with plane
+ hit_test_results.push(result);
+ }
+ });
- // throw away all strange results (no intersection with plane, ray lies on plane)
+ // throw away all strange results (ray lies on plane)
let hit_test_results_with_points = hit_test_results.filter(
- maybe_plane => maybe_plane && typeof maybe_plane.point != "undefined");
+ maybe_plane => typeof maybe_plane.point != "undefined");
// sort results by distance
hit_test_results_with_points.sort((l, r) => l.distance - r.distance);
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
index 3db79c793a6..a3f33cdb7c5 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
@@ -260,6 +260,14 @@ const generateCSS = (options, fontSize=18)=> {
button.${cssPrefix}-button[disabled=true] > .${cssPrefix}-logo > .${cssPrefix}-svg-error {
display:initial;
}
+
+ /*
+ * warning
+ */
+ div.webxrWarning {
+ color: #f00;
+ font-weight: bold;
+ }
`);
};
@@ -431,6 +439,23 @@ class EnterXRButton {
}
/**
+ * Add the button to the document header. WebXR is only available in secure
+ * contexts, so include a warning message above the button when using an
+ * insecure context.
+ * @return {EnterXRButton}
+ */
+ addToHeader() {
+ if (!window.isSecureContext) {
+ let warning_elem = document.createElement("div");
+ warning_elem.setAttribute("class", "webxrWarning");
+ warning_elem.innerText = "WebXR unavailable due to insecure context";
+ document.querySelector('header').appendChild(warning_elem);
+ }
+ document.querySelector('header').appendChild(this.domElement);
+ return this;
+ }
+
+ /**
* clean up object for garbage collection
*/
remove() {
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
index 0ef2fe18f70..8c43ca6535f 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
@@ -34,7 +34,7 @@
/**
* @license
- * webvr-polyfill-dpdb
+ * 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.
@@ -103,233 +103,153 @@
(global.WebXRPolyfill = factory());
}(this, (function () { 'use strict';
-var _global = typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : {};
+const _global = typeof global !== 'undefined' ? global :
+ typeof self !== 'undefined' ? self :
+ typeof window !== 'undefined' ? window : {};
-var classCallCheck = function (instance, Constructor) {
- if (!(instance instanceof Constructor)) {
- throw new TypeError("Cannot call a class as a function");
+const PRIVATE = Symbol('@@webxr-polyfill/EventTarget');
+class EventTarget {
+ constructor() {
+ this[PRIVATE] = {
+ listeners: new Map(),
+ };
}
-};
-
-var createClass = function () {
- function defineProperties(target, props) {
- for (var i = 0; i < props.length; i++) {
- var descriptor = props[i];
- descriptor.enumerable = descriptor.enumerable || false;
- descriptor.configurable = true;
- if ("value" in descriptor) descriptor.writable = true;
- Object.defineProperty(target, descriptor.key, descriptor);
+ 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();
+ }
}
}
-
- return function (Constructor, protoProps, staticProps) {
- if (protoProps) defineProperties(Constructor.prototype, protoProps);
- if (staticProps) defineProperties(Constructor, staticProps);
- return Constructor;
- };
-}();
-
-
-
-
-
-
-
-
-
-var inherits = function (subClass, superClass) {
- if (typeof superClass !== "function" && superClass !== null) {
- throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
- }
-
- subClass.prototype = Object.create(superClass && superClass.prototype, {
- constructor: {
- value: subClass,
- enumerable: false,
- writable: true,
- configurable: true
+ 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);
}
- });
- if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
-};
-
-
-
-
-
-
-
-
-
-
-
-var possibleConstructorReturn = function (self, call) {
- if (!self) {
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
+}
- return call && (typeof call === "object" || typeof call === "function") ? call : self;
-};
-
-var PRIVATE = Symbol('@@webxr-polyfill/EventTarget');
-var EventTarget = function () {
- function EventTarget() {
- classCallCheck(this, EventTarget);
- this[PRIVATE] = {
- listeners: new Map()
+const PRIVATE$1 = Symbol('@@webxr-polyfill/XR');
+const XRSessionModes = ['inline', 'immersive-vr', 'immersive-ar'];
+const POLYFILL_REQUEST_SESSION_ERROR =
+`Polyfill Error: Must call navigator.xr.supportsSession() 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 XR$1 extends EventTarget {
+ constructor(devicePromise) {
+ super();
+ this[PRIVATE$1] = {
+ device: null,
+ devicePromise,
+ immersiveSession: null,
+ inlineSessions: new Set(),
};
+ devicePromise.then((device) => { this[PRIVATE$1].device = device; });
}
- createClass(EventTarget, [{
- key: 'addEventListener',
- value: function 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');
- }
- var typedListeners = this[PRIVATE].listeners.get(type) || [];
- typedListeners.push(listener);
- this[PRIVATE].listeners.set(type, typedListeners);
+ async supportsSession(mode) {
+ if (!this[PRIVATE$1].device) {
+ await this[PRIVATE$1].devicePromise;
}
- }, {
- key: 'removeEventListener',
- value: function 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');
- }
- var typedListeners = this[PRIVATE].listeners.get(type) || [];
- for (var i = typedListeners.length; i >= 0; i--) {
- if (typedListeners[i] === listener) {
- typedListeners.pop();
- }
+ if (mode != 'inline') {
+ if (!this[PRIVATE$1].device.supportsSession(mode)) {
+ return Promise.reject(null);
}
}
- }, {
- key: 'dispatchEvent',
- value: function dispatchEvent(type, event) {
- var typedListeners = this[PRIVATE].listeners.get(type) || [];
- var queue = [];
- for (var i = 0; i < typedListeners.length; i++) {
- queue[i] = typedListeners[i];
- }
- var _iteratorNormalCompletion = true;
- var _didIteratorError = false;
- var _iteratorError = undefined;
- try {
- for (var _iterator = queue[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
- var listener = _step.value;
- listener(event);
- }
- } catch (err) {
- _didIteratorError = true;
- _iteratorError = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion && _iterator.return) {
- _iterator.return();
- }
- } finally {
- if (_didIteratorError) {
- throw _iteratorError;
- }
- }
- }
- if (typeof this['on' + type] === 'function') {
- this['on' + type](event);
+ return Promise.resolve(null);
+ }
+ async requestSession(mode) {
+ if (!this[PRIVATE$1].device) {
+ if (mode != 'inline') {
+ throw new Error(POLYFILL_REQUEST_SESSION_ERROR);
+ } else {
+ await this[PRIVATE$1].devicePromise;
}
}
- }]);
- return EventTarget;
-}();
-
-var PRIVATE$1 = Symbol('@@webxr-polyfill/XR');
-var XR = function (_EventTarget) {
- inherits(XR, _EventTarget);
- function XR(device) {
- classCallCheck(this, XR);
- var _this = possibleConstructorReturn(this, (XR.__proto__ || Object.getPrototypeOf(XR)).call(this));
- _this[PRIVATE$1] = {
- device: device
- };
- return _this;
- }
- createClass(XR, [{
- key: 'requestDevice',
- value: function requestDevice() {
- return new Promise(function ($return, $error) {
- var device;
- return Promise.resolve(this[PRIVATE$1].device).then(function ($await_1) {
- try {
- device = $await_1;
- if (device) {
- return $return(device);
- }
- return $error(new Error('NotFoundError'));
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this), $error);
- }.bind(this));
+ const sessionId = await this[PRIVATE$1].device.requestSession(mode);
+ const session = new XRSession(this[PRIVATE$1].device, mode, sessionId);
+ if (mode == 'inline') {
+ this[PRIVATE$1].inlineSessions.add(session);
+ } else {
+ this[PRIVATE$1].immersiveSession = session;
}
- }]);
- return XR;
-}(EventTarget);
+ const onSessionEnd = () => {
+ if (mode == 'inline') {
+ this[PRIVATE$1].inlineSessions.delete(session);
+ } else {
+ this[PRIVATE$1].immersiveSession = null;
+ }
+ session.removeEventListener('end', onSessionEnd);
+ };
+ session.addEventListener('end', onSessionEnd);
+ return session;
+ }
+}
-var now = void 0;
+let now;
if ('performance' in _global === false) {
- var startTime = Date.now();
- now = function now() {
- return Date.now() - startTime;
- };
+ let startTime = Date.now();
+ now = () => Date.now() - startTime;
} else {
- now = function now() {
- return performance.now();
- };
+ now = () => performance.now();
}
var now$1 = now;
-var PRIVATE$2 = Symbol('@@webxr-polyfill/XRPresentationContext');
-var XRPresentationContext = function () {
- function XRPresentationContext(canvas, ctx, glAttribs) {
- classCallCheck(this, XRPresentationContext);
- this[PRIVATE$2] = { canvas: canvas, ctx: ctx, glAttribs: glAttribs };
- Object.assign(this, ctx);
+const PRIVATE$2 = Symbol('@@webxr-polyfill/XRPose');
+class XRPose$1 {
+ constructor(transform, emulatedPosition) {
+ this[PRIVATE$2] = {
+ transform,
+ emulatedPosition,
+ };
}
- createClass(XRPresentationContext, [{
- key: 'canvas',
- get: function get$$1() {
- return this[PRIVATE$2].canvas;
- }
- }]);
- return XRPresentationContext;
-}();
+ get transform() { return this[PRIVATE$2].transform; }
+ get emulatedPosition() { return this[PRIVATE$2].emulatedPosition; }
+ _setTransform(transform) { this[PRIVATE$2].transform = transform; }
+}
-var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+const EPSILON = 0.000001;
+let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
-var degree = Math.PI / 180;
+const degree = Math.PI / 180;
function create() {
- var out = new ARRAY_TYPE(16);
+ 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[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;
}
@@ -376,35 +296,23 @@ function identity(out) {
}
function invert(out, a) {
- var a00 = a[0],
- a01 = a[1],
- a02 = a[2],
- a03 = a[3];
- var a10 = a[4],
- a11 = a[5],
- a12 = a[6],
- a13 = a[7];
- var a20 = a[8],
- a21 = a[9],
- a22 = a[10],
- a23 = a[11];
- var a30 = a[12],
- a31 = a[13],
- a32 = a[14],
- a33 = a[15];
- var b00 = a00 * a11 - a01 * a10;
- var b01 = a00 * a12 - a02 * a10;
- var b02 = a00 * a13 - a03 * a10;
- var b03 = a01 * a12 - a02 * a11;
- var b04 = a01 * a13 - a03 * a11;
- var b05 = a02 * a13 - a03 * a12;
- var b06 = a20 * a31 - a21 * a30;
- var b07 = a20 * a32 - a22 * a30;
- var b08 = a20 * a33 - a23 * a30;
- var b09 = a21 * a32 - a22 * a31;
- var b10 = a21 * a33 - a23 * a31;
- var b11 = a22 * a33 - a23 * a32;
- var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+ 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;
}
@@ -430,45 +338,30 @@ function invert(out, a) {
function multiply(out, a, b) {
- var a00 = a[0],
- a01 = a[1],
- a02 = a[2],
- a03 = a[3];
- var a10 = a[4],
- a11 = a[5],
- a12 = a[6],
- a13 = a[7];
- var a20 = a[8],
- a21 = a[9],
- a22 = a[10],
- a23 = a[11];
- var a30 = a[12],
- a31 = a[13],
- a32 = a[14],
- a33 = a[15];
- var 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;
+ 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;
}
@@ -484,22 +377,19 @@ function multiply(out, a, b) {
function fromRotationTranslation(out, q, v) {
- var x = q[0],
- y = q[1],
- z = q[2],
- w = q[3];
- var x2 = x + x;
- var y2 = y + y;
- var z2 = z + z;
- var xx = x * x2;
- var xy = x * y2;
- var xz = x * z2;
- var yy = y * y2;
- var yz = y * z2;
- var zz = z * z2;
- var wx = w * x2;
- var wy = w * y2;
- var wz = w * z2;
+ 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;
@@ -527,15 +417,15 @@ function getTranslation(out, mat) {
}
function getRotation(out, mat) {
- var trace = mat[0] + mat[5] + mat[10];
- var S = 0;
+ 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]) {
+ } 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;
@@ -561,8 +451,7 @@ function getRotation(out, mat) {
function perspective(out, fovy, aspect, near, far) {
- var f = 1.0 / Math.tan(fovy / 2);
- var nf = 1 / (near - far);
+ let f = 1.0 / Math.tan(fovy / 2), nf;
out[0] = f / aspect;
out[1] = 0;
out[2] = 0;
@@ -573,973 +462,722 @@ function perspective(out, fovy, aspect, near, far) {
out[7] = 0;
out[8] = 0;
out[9] = 0;
- out[10] = (far + near) * nf;
out[11] = -1;
out[12] = 0;
out[13] = 0;
- out[14] = 2 * far * near * nf;
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;
}
-var PRIVATE$3 = Symbol('@@webxr-polyfill/XRDevicePose');
-var XRDevicePose = function () {
- function XRDevicePose(polyfill) {
- classCallCheck(this, XRDevicePose);
- this[PRIVATE$3] = {
- polyfill: polyfill,
- leftViewMatrix: identity(new Float32Array(16)),
- rightViewMatrix: identity(new Float32Array(16)),
- poseModelMatrix: identity(new Float32Array(16))
- };
+function create$1() {
+ let out = new ARRAY_TYPE(3);
+ if(ARRAY_TYPE != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
}
- createClass(XRDevicePose, [{
- key: 'getViewMatrix',
- value: function getViewMatrix(view) {
- switch (view.eye) {
- case 'left':
- return this[PRIVATE$3].leftViewMatrix;
- case 'right':
- return this[PRIVATE$3].rightViewMatrix;
- }
- throw new Error('view is not a valid XREye');
- }
- }, {
- key: 'updateFromFrameOfReference',
- value: function updateFromFrameOfReference(frameOfRef) {
- var pose = this[PRIVATE$3].polyfill.getBasePoseMatrix();
- var leftViewMatrix = this[PRIVATE$3].polyfill.getBaseViewMatrix('left');
- var rightViewMatrix = this[PRIVATE$3].polyfill.getBaseViewMatrix('right');
- if (pose) {
- frameOfRef.transformBasePoseMatrix(this[PRIVATE$3].poseModelMatrix, pose);
- }
- if (leftViewMatrix && rightViewMatrix) {
- frameOfRef.transformBaseViewMatrix(this[PRIVATE$3].leftViewMatrix, leftViewMatrix, this[PRIVATE$3].poseModelMatrix);
- frameOfRef.transformBaseViewMatrix(this[PRIVATE$3].rightViewMatrix, rightViewMatrix, this[PRIVATE$3].poseModelMatrix);
- }
- }
- }, {
- key: 'poseModelMatrix',
- get: function get$$1() {
- return this[PRIVATE$3].poseModelMatrix;
- }
- }]);
- return XRDevicePose;
-}();
+ 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;
+}
-var PRIVATE$4 = Symbol('@@webxr-polyfill/XRViewport');
-var XRViewport = function () {
- function XRViewport(target) {
- classCallCheck(this, XRViewport);
- this[PRIVATE$4] = { target: target };
- }
- createClass(XRViewport, [{
- key: 'x',
- get: function get$$1() {
- return this[PRIVATE$4].target.x;
- }
- }, {
- key: 'y',
- get: function get$$1() {
- return this[PRIVATE$4].target.y;
- }
- }, {
- key: 'width',
- get: function get$$1() {
- return this[PRIVATE$4].target.width;
- }
- }, {
- key: 'height',
- get: function get$$1() {
- return this[PRIVATE$4].target.height;
- }
- }]);
- return XRViewport;
-}();
+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;
+}
-var XREyes = ['left', 'right'];
-var PRIVATE$5 = Symbol('@@webxr-polyfill/XRView');
-var XRView = function () {
- function XRView(polyfill, eye, sessionId) {
- classCallCheck(this, XRView);
- if (!XREyes.includes(eye)) {
- throw new Error('XREye must be one of: ' + XREyes);
- }
- var temp = Object.create(null);
- var viewport = new XRViewport(temp);
- this[PRIVATE$5] = {
- polyfill: polyfill,
- eye: eye,
- viewport: viewport,
- temp: temp,
- sessionId: sessionId
- };
+
+
+
+
+
+
+
+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;
}
- createClass(XRView, [{
- key: '_getViewport',
- value: function _getViewport(layer) {
- var viewport = this[PRIVATE$5].viewport;
- if (this[PRIVATE$5].polyfill.getViewport(this[PRIVATE$5].sessionId, this.eye, layer, this[PRIVATE$5].temp)) {
- return this[PRIVATE$5].viewport;
- }
- return undefined;
- }
- }, {
- key: 'eye',
- get: function get$$1() {
- return this[PRIVATE$5].eye;
- }
- }, {
- key: 'projectionMatrix',
- get: function get$$1() {
- return this[PRIVATE$5].polyfill.getProjectionMatrix(this.eye);
- }
- }]);
- return XRView;
-}();
+ 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;
+}
-var PRIVATE$6 = Symbol('@@webxr-polyfill/XRFrame');
-var XRFrame = function () {
- function XRFrame(polyfill, session, sessionId) {
- classCallCheck(this, XRFrame);
- var devicePose = new XRDevicePose(polyfill);
- var views = [new XRView(polyfill, 'left', sessionId)];
- if (session.immersive) {
- views.push(new XRView(polyfill, 'right', sessionId));
- }
- this[PRIVATE$6] = {
- polyfill: polyfill,
- devicePose: devicePose,
- views: views,
- session: session
- };
+
+
+
+
+
+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;
}
- createClass(XRFrame, [{
- key: 'getDevicePose',
- value: function getDevicePose(coordinateSystem) {
- this[PRIVATE$6].devicePose.updateFromFrameOfReference(coordinateSystem);
- return this[PRIVATE$6].devicePose;
+ 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;
}
- }, {
- key: 'getInputPose',
- value: function getInputPose(inputSource, coordinateSystem) {
- return this[PRIVATE$6].polyfill.getInputPose(inputSource, coordinateSystem);
+ if(!offset) {
+ offset = 0;
}
- }, {
- key: 'session',
- get: function get$$1() {
- return this[PRIVATE$6].session;
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
}
- }, {
- key: 'views',
- get: function get$$1() {
- return this[PRIVATE$6].views;
+ 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 XRFrame;
-}();
+ return a;
+ };
+})();
-var PRIVATE$7 = Symbol('@@webxr-polyfill/XRStageBoundsPoint');
-var XRStageBoundsPoint = function () {
- function XRStageBoundsPoint(x, z) {
- classCallCheck(this, XRStageBoundsPoint);
- this[PRIVATE$7] = { x: x, z: z };
+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;
}
- createClass(XRStageBoundsPoint, [{
- key: 'x',
- get: function get$$1() {
- return this[PRIVATE$7].x;
- }
- }, {
- key: 'z',
- get: function get$$1() {
- return this[PRIVATE$7].z;
- }
- }]);
- return XRStageBoundsPoint;
-}();
+ out[0] = 1;
+ out[4] = 1;
+ out[8] = 1;
+ return out;
+}
-var PRIVATE$8 = Symbol('@@webxr-polyfill/XRStageBounds');
-var XRStageBounds = function () {
- function XRStageBounds(boundsData) {
- classCallCheck(this, XRStageBounds);
- var geometry = [];
- for (var i = 0; i < boundsData.length; i += 2) {
- geometry.push(new XRStageBoundsPoint(boundsData[i], boundsData[i + 1]));
- }
- this[PRIVATE$8] = { geometry: geometry };
+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;
}
- createClass(XRStageBounds, [{
- key: 'geometry',
- get: function get$$1() {
- return this[PRIVATE$8].geometry;
- }
- }]);
- return XRStageBounds;
-}();
+ 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;
+}
-var XRCoordinateSystem = function () {
- function XRCoordinateSystem() {
- classCallCheck(this, XRCoordinateSystem);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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;
}
- createClass(XRCoordinateSystem, [{
- key: 'getTransformTo',
- value: function getTransformTo(other) {
- throw new Error('Not yet supported');
- }
- }]);
- return XRCoordinateSystem;
-}();
+ return out;
+}
-var DEFAULT_EMULATION_HEIGHT = 1.6;
-var PRIVATE$9 = Symbol('@@webxr-polyfill/XRFrameOfReference');
-var XRFrameOfReferenceTypes = ['head-model', 'eye-level', 'stage'];
-var XRFrameOfReferenceOptions = Object.freeze({
- disableStageEmulation: false,
- stageEmulationHeight: 0
-});
-var XRFrameOfReference = function (_XRCoordinateSystem) {
- inherits(XRFrameOfReference, _XRCoordinateSystem);
- function XRFrameOfReference(polyfill, type, options, transform, bounds) {
- classCallCheck(this, XRFrameOfReference);
- options = Object.assign({}, XRFrameOfReferenceOptions, options);
- if (!XRFrameOfReferenceTypes.includes(type)) {
- throw new Error('XRFrameOfReferenceType must be one of ' + XRFrameOfReferenceTypes);
- }
- var _this = possibleConstructorReturn(this, (XRFrameOfReference.__proto__ || Object.getPrototypeOf(XRFrameOfReference)).call(this));
- if (type === 'stage' && options.disableStageEmulation && !transform) {
- throw new Error('XRFrameOfReference cannot use \'stage\' type, if disabling emulation and platform does not provide');
- }
- var _options = options,
- disableStageEmulation = _options.disableStageEmulation,
- stageEmulationHeight = _options.stageEmulationHeight;
- var emulatedHeight = 0;
- if (type === 'stage' && !transform) {
- emulatedHeight = stageEmulationHeight !== 0 ? stageEmulationHeight : DEFAULT_EMULATION_HEIGHT;
- }
- if (type === 'stage' && !transform) {
- transform = identity(new Float32Array(16));
- transform[13] = emulatedHeight;
- }
- _this[PRIVATE$9] = {
- disableStageEmulation: disableStageEmulation,
- stageEmulationHeight: stageEmulationHeight,
- emulatedHeight: emulatedHeight,
- type: type,
- transform: transform,
- polyfill: polyfill,
- bounds: bounds
- };
- _this.onboundschange = undefined;
- return _this;
- }
- createClass(XRFrameOfReference, [{
- key: 'transformBasePoseMatrix',
- value: function transformBasePoseMatrix(out, pose) {
- if (this[PRIVATE$9].transform) {
- multiply(out, this[PRIVATE$9].transform, pose);
- return;
- }
- switch (this.type) {
- case 'head-model':
- if (out !== pose) {
- copy(out, pose);
- }
- out[12] = out[13] = out[14] = 0;
- return;
- case 'eye-level':
- if (out !== pose) {
- copy(out, pose);
- }
- return;
- }
- }
- }, {
- key: 'transformBaseViewMatrix',
- value: function transformBaseViewMatrix(out, view) {
- var frameOfRef = this[PRIVATE$9].transform;
- if (frameOfRef) {
- invert(out, frameOfRef);
- multiply(out, view, out);
- }
- else if (this.type === 'head-model') {
- invert(out, view);
- out[12] = 0;
- out[13] = 0;
- out[14] = 0;
- invert(out, out);
- return out;
- }
- else {
- copy(out, view);
- }
- 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;
}
- }, {
- key: 'bounds',
- get: function get$$1() {
- return this[PRIVATE$9].bounds;
+ if(!offset) {
+ offset = 0;
}
- }, {
- key: 'emulatedHeight',
- get: function get$$1() {
- return this[PRIVATE$9].emulatedHeight;
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
}
- }, {
- key: 'type',
- get: function get$$1() {
- return this[PRIVATE$9].type;
+ 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 XRFrameOfReference;
-}(XRCoordinateSystem);
+ return a;
+ };
+})();
-var PRIVATE$10 = Symbol('@@webxr-polyfill/XRSession');
-var XRSessionCreationOptions = Object.freeze({
- immersive: false,
- outputContext: undefined
-});
-var validateSessionOptions = function validateSessionOptions(options) {
- var immersive = options.immersive,
- outputContext = options.outputContext;
- if (!immersive && !outputContext) {
- return false;
+function create$4() {
+ let out = new ARRAY_TYPE(4);
+ if(ARRAY_TYPE != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
}
- if (outputContext !== undefined && !(outputContext instanceof XRPresentationContext)) {
- return false;
+ 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;
}
- return true;
-};
-var XRSession = function (_EventTarget) {
- inherits(XRSession, _EventTarget);
- function XRSession(polyfill, device, sessionOptions, id) {
- classCallCheck(this, XRSession);
- sessionOptions = Object.assign({}, XRSessionCreationOptions, sessionOptions);
- var _this = possibleConstructorReturn(this, (XRSession.__proto__ || Object.getPrototypeOf(XRSession)).call(this));
- var _sessionOptions = sessionOptions,
- immersive = _sessionOptions.immersive,
- outputContext = _sessionOptions.outputContext;
- _this[PRIVATE$10] = {
- polyfill: polyfill,
- device: device,
- immersive: immersive,
- outputContext: outputContext,
- ended: false,
- suspended: false,
- suspendedCallback: null,
- id: id
- };
- var frame = new XRFrame(polyfill, _this, _this[PRIVATE$10].id);
- _this[PRIVATE$10].frame = frame;
- _this[PRIVATE$10].onPresentationEnd = function (sessionId) {
- if (sessionId !== _this[PRIVATE$10].id) {
- _this[PRIVATE$10].suspended = false;
- _this.dispatchEvent('focus', { session: _this });
- var suspendedCallback = _this[PRIVATE$10].suspendedCallback;
- _this[PRIVATE$10].suspendedCallback = null;
- if (suspendedCallback) {
- _this.requestAnimationFrame(suspendedCallback);
- }
- return;
- }
- _this[PRIVATE$10].ended = true;
- polyfill.removeEventListener('@webvr-polyfill/vr-present-end', _this[PRIVATE$10].onPresentationEnd);
- polyfill.removeEventListener('@webvr-polyfill/vr-present-start', _this[PRIVATE$10].onPresentationStart);
- polyfill.removeEventListener('@@webvr-polyfill/input-select-start', _this[PRIVATE$10].onSelectStart);
- polyfill.removeEventListener('@@webvr-polyfill/input-select-end', _this[PRIVATE$10].onSelectEnd);
- _this.dispatchEvent('end', { session: _this });
- };
- polyfill.addEventListener('@@webxr-polyfill/vr-present-end', _this[PRIVATE$10].onPresentationEnd);
- _this[PRIVATE$10].onPresentationStart = function (sessionId) {
- if (sessionId === _this[PRIVATE$10].id) {
- return;
- }
- _this[PRIVATE$10].suspended = true;
- _this.dispatchEvent('blur', { session: _this });
- };
- polyfill.addEventListener('@@webxr-polyfill/vr-present-start', _this[PRIVATE$10].onPresentationStart);
- _this[PRIVATE$10].onSelectStart = function (evt) {
- if (evt.sessionId !== _this[PRIVATE$10].id) {
- return;
- }
- _this.dispatchEvent('selectstart', {
- frame: _this[PRIVATE$10].frame,
- inputSource: evt.inputSource
- });
- };
- polyfill.addEventListener('@@webxr-polyfill/input-select-start', _this[PRIVATE$10].onSelectStart);
- _this[PRIVATE$10].onSelectEnd = function (evt) {
- if (evt.sessionId !== _this[PRIVATE$10].id) {
- return;
- }
- _this.dispatchEvent('selectend', {
- frame: _this[PRIVATE$10].frame,
- inputSource: evt.inputSource
- });
- _this.dispatchEvent('select', {
- frame: _this[PRIVATE$10].frame,
- inputSource: evt.inputSource
- });
- };
- polyfill.addEventListener('@@webxr-polyfill/input-select-end', _this[PRIVATE$10].onSelectEnd);
- _this.onblur = undefined;
- _this.onfocus = undefined;
- _this.onresetpose = undefined;
- _this.onend = undefined;
- _this.onselect = undefined;
- _this.onselectstart = undefined;
- _this.onselectend = undefined;
- return _this;
- }
- createClass(XRSession, [{
- key: 'requestFrameOfReference',
- value: function requestFrameOfReference(type) {
- var $args = arguments;return new Promise(function ($return, $error) {
- var options, transform, bounds;
- options = $args.length > 1 && $args[1] !== undefined ? $args[1] : {};
- if (this[PRIVATE$10].ended) {
- return $return();
- }
- options = Object.assign({}, XRFrameOfReferenceOptions, options);
- if (!XRFrameOfReferenceTypes.includes(type)) {
- return $error(new TypeError('XRFrameOfReferenceType must be one of ' + XRFrameOfReferenceTypes));
- }
- transform = null;
- bounds = null;
- var $Try_1_Post = function () {
- try {
- if (type === 'stage' && transform) {
- bounds = this[PRIVATE$10].polyfill.requestStageBounds();
- if (bounds) {
- bounds = new XRStageBounds(bounds);
- }
- }
- return $return(new XRFrameOfReference(this[PRIVATE$10].polyfill, type, options, transform, bounds));
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this);var $Try_1_Catch = function (e) {
- try {
- if (type !== 'stage' || options.disableStageEmulation) {
- throw e;
- }
- return $Try_1_Post();
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this);
- try {
- return Promise.resolve(this[PRIVATE$10].polyfill.requestFrameOfReferenceTransform(type, options)).then(function ($await_2) {
- try {
- transform = $await_2;
- return $Try_1_Post();
- } catch ($boundEx) {
- return $Try_1_Catch($boundEx);
- }
- }.bind(this), $Try_1_Catch);
- } catch (e) {
- $Try_1_Catch(e);
- }
- }.bind(this));
- }
- }, {
- key: 'requestAnimationFrame',
- value: function requestAnimationFrame(callback) {
- var _this2 = this;
- if (this[PRIVATE$10].ended) {
- return;
- }
- if (this[PRIVATE$10].suspended && this[PRIVATE$10].suspendedCallback) {
- return;
- }
- if (this[PRIVATE$10].suspended && !this[PRIVATE$10].suspendedCallback) {
- this[PRIVATE$10].suspendedCallback = callback;
- }
- return this[PRIVATE$10].polyfill.requestAnimationFrame(function () {
- _this2[PRIVATE$10].polyfill.onFrameStart(_this2[PRIVATE$10].id);
- callback(now$1(), _this2[PRIVATE$10].frame);
- _this2[PRIVATE$10].polyfill.onFrameEnd(_this2[PRIVATE$10].id);
- });
- }
- }, {
- key: 'cancelAnimationFrame',
- value: function cancelAnimationFrame(handle) {
- if (this[PRIVATE$10].ended) {
- return;
- }
- this[PRIVATE$10].polyfill.cancelAnimationFrame(handle);
- }
- }, {
- key: 'getInputSources',
- value: function getInputSources() {
- return this[PRIVATE$10].polyfill.getInputSources();
- }
- }, {
- key: 'end',
- value: function end() {
- return new Promise(function ($return, $error) {
- if (this[PRIVATE$10].ended) {
- return $return();
- }
- if (!this.immersive) {
- this[PRIVATE$10].ended = true;
- this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/vr-present-start', this[PRIVATE$10].onPresentationStart);
- this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/vr-present-end', this[PRIVATE$10].onPresentationEnd);
- this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$10].onSelectStart);
- this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$10].onSelectEnd);
- this.dispatchEvent('end', { session: this });
- }
- return $return(this[PRIVATE$10].polyfill.endSession(this[PRIVATE$10].id));
- }.bind(this));
- }
- }, {
- key: 'device',
- get: function get$$1() {
- return this[PRIVATE$10].device;
- }
- }, {
- key: 'immersive',
- get: function get$$1() {
- return this[PRIVATE$10].immersive;
- }
- }, {
- key: 'outputContext',
- get: function get$$1() {
- return this[PRIVATE$10].outputContext;
- }
- }, {
- key: 'depthNear',
- get: function get$$1() {
- return this[PRIVATE$10].polyfill.depthNear;
- }
- ,
- set: function set$$1(value) {
- this[PRIVATE$10].polyfill.depthNear = value;
- }
- }, {
- key: 'depthFar',
- get: function get$$1() {
- return this[PRIVATE$10].polyfill.depthFar;
- }
- ,
- set: function set$$1(value) {
- this[PRIVATE$10].polyfill.depthFar = value;
- }
- }, {
- key: 'environmentBlendMode',
- get: function get$$1() {
- return this[PRIVATE$10].polyfill.environmentBlendMode || 'opaque';
- }
- }, {
- key: 'baseLayer',
- get: function get$$1() {
- return this[PRIVATE$10].baseLayer;
- }
- ,
- set: function set$$1(value) {
- if (this[PRIVATE$10].ended) {
- return;
- }
- this[PRIVATE$10].baseLayer = value;
- this[PRIVATE$10].polyfill.onBaseLayerSet(this[PRIVATE$10].id, value);
+ 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);
}
- }]);
- return XRSession;
-}(EventTarget);
-
-var PRIVATE$11 = Symbol('@@webxr-polyfill/XRDevice');
-var XRDevice = function (_EventTarget) {
- inherits(XRDevice, _EventTarget);
- function XRDevice(polyfill) {
- classCallCheck(this, XRDevice);
- if (!polyfill) {
- throw new Error('XRDevice must receive a PolyfilledXRDevice.');
- }
- var _this = possibleConstructorReturn(this, (XRDevice.__proto__ || Object.getPrototypeOf(XRDevice)).call(this));
- _this[PRIVATE$11] = {
- polyfill: polyfill,
- immersiveSession: null,
- nonImmersiveSessions: new Set()
+ };
+})();
+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$3 = Symbol('@@webxr-polyfill/XRRigidTransform');
+class XRRigidTransform$1 {
+ constructor() {
+ this[PRIVATE$3] = {
+ matrix: null,
+ position: null,
+ orientation: null,
+ inverse: null,
};
- _this.ondeactive = undefined;
- return _this;
- }
- createClass(XRDevice, [{
- key: 'supportsSession',
- value: function supportsSession() {
- var $args = arguments;return new Promise(function ($return, $error) {
- var sessionOptions = $args.length > 0 && $args[0] !== undefined ? $args[0] : {};
- sessionOptions = Object.assign({}, XRSessionCreationOptions, sessionOptions);
- if (!validateSessionOptions(sessionOptions)) {
- return $return(Promise.reject(null));
- }
- if (!this[PRIVATE$11].polyfill.supportsSession(sessionOptions)) {
- return $return(Promise.reject(null));
- }
- return $return(null);
- }.bind(this));
- }
- }, {
- key: 'requestSession',
- value: function requestSession(sessionOptions) {
- return new Promise(function ($return, $error) {
- var _this2, sessionId, session, onSessionEnd;
- _this2 = this;
- sessionOptions = Object.assign({}, XRSessionCreationOptions, sessionOptions);
- if (!validateSessionOptions(sessionOptions)) {
- return $error(new Error('NotSupportedError'));
- }
- if (this[PRIVATE$11].immersiveSession && sessionOptions.immersive) {
- return $error(new Error('InvalidStateError'));
- }
- return Promise.resolve(this[PRIVATE$11].polyfill.requestSession(sessionOptions)).then(function ($await_1) {
- try {
- sessionId = $await_1;
- session = new XRSession(this[PRIVATE$11].polyfill, this, sessionOptions, sessionId);
- // TODO(crbug.com/958922): remove polyfill from tests.
- if (sessionOptions.immersive)
- session.mode = 'immersive-vr';
- else
- session.mode = 'inline';
- if (sessionOptions.immersive) {
- this[PRIVATE$11].immersiveSession = session;
- } else {
- this[PRIVATE$11].nonImmersiveSessions.add(session);
- }
- onSessionEnd = function onSessionEnd() {
- if (session.immersive) {
- _this2[PRIVATE$11].immersiveSession = null;
- } else {
- _this2[PRIVATE$11].nonImmersiveSessions.delete(session);
- }
- session.removeEventListener('end', onSessionEnd);
- };
- session.addEventListener('end', onSessionEnd);
- return $return(session);
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this), $error);
- }.bind(this));
- }
- }]);
- return XRDevice;
-}(EventTarget);
-
-var domPointROExport = 'DOMPointReadOnly' in _global ? DOMPointReadOnly : null;
-if (!domPointROExport) {
- var PRIVATE$12 = Symbol('@@webxr-polyfill/DOMPointReadOnly');
- domPointROExport = function () {
- function DOMPointReadOnly(x, y, z, w) {
- classCallCheck(this, DOMPointReadOnly);
- if (arguments.length === 1) {
- this[PRIVATE$12] = {
- x: x.x,
- y: x.y,
- z: x.z,
- w: x.w
- };
- } else if (arguments.length === 4) {
- this[PRIVATE$12] = {
- x: x,
- y: y,
- z: z,
- w: w
- };
+ if (arguments.length === 0) {
+ this[PRIVATE$3].matrix = identity(new Float32Array(16));
+ } else if (arguments.length === 1) {
+ if (arguments[0] instanceof Float32Array) {
+ this[PRIVATE$3].matrix = arguments[0];
} else {
- throw new TypeError('Must supply either 1 or 4 arguments');
- }
- }
- createClass(DOMPointReadOnly, [{
- key: 'x',
- get: function get$$1() {
- return this[PRIVATE$12].x;
- }
- }, {
- key: 'y',
- get: function get$$1() {
- return this[PRIVATE$12].y;
- }
- }, {
- key: 'z',
- get: function get$$1() {
- return this[PRIVATE$12].z;
- }
- }, {
- key: 'w',
- get: function get$$1() {
- return this[PRIVATE$12].w;
+ this[PRIVATE$3].position = this._getPoint(arguments[0]);
+ this[PRIVATE$3].orientation = DOMPointReadOnly.fromPoint({
+ x: 0, y: 0, z: 0, w: 1
+ });
}
- }]);
- return DOMPointReadOnly;
- }();
+ } else if (arguments.length === 2) {
+ this[PRIVATE$3].position = this._getPoint(arguments[0]);
+ this[PRIVATE$3].orientation = this._getPoint(arguments[1]);
+ } else {
+ throw new Error("Too many arguments!");
+ }
+ if (this[PRIVATE$3].matrix) {
+ let position = create$1();
+ getTranslation(position, this[PRIVATE$3].matrix);
+ this[PRIVATE$3].position = DOMPointReadOnly.fromPoint({
+ x: position[0],
+ y: position[1],
+ z: position[2]
+ });
+ let orientation = create$4();
+ getRotation(orientation, this[PRIVATE$3].matrix);
+ this[PRIVATE$3].orientation = DOMPointReadOnly.fromPoint({
+ x: orientation[0],
+ y: orientation[1],
+ z: orientation[2],
+ w: orientation[3]
+ });
+ } else {
+ this[PRIVATE$3].matrix = identity(new Float32Array(16));
+ fromRotationTranslation(
+ this[PRIVATE$3].matrix,
+ fromValues$4(
+ this[PRIVATE$3].orientation.x,
+ this[PRIVATE$3].orientation.y,
+ this[PRIVATE$3].orientation.z,
+ this[PRIVATE$3].orientation.w),
+ fromValues$1(
+ this[PRIVATE$3].position.x,
+ this[PRIVATE$3].position.y,
+ this[PRIVATE$3].position.z)
+ );
+ }
+ }
+ _getPoint(arg) {
+ if (arg instanceof DOMPointReadOnly) {
+ return arg;
+ }
+ return DOMPointReadOnly.fromPoint(arg);
+ }
+ get matrix() { return this[PRIVATE$3].matrix; }
+ get position() { return this[PRIVATE$3].position; }
+ get orientation() { return this[PRIVATE$3].orientation; }
+ get inverse() {
+ if (this[PRIVATE$3].inverse === null) {
+ let invMatrix = identity(new Float32Array(16));
+ invert(invMatrix, this[PRIVATE$3].matrix);
+ this[PRIVATE$3].inverse = new XRRigidTransform$1(invMatrix);
+ this[PRIVATE$3].inverse[PRIVATE$3].inverse = this;
+ }
+ return this[PRIVATE$3].inverse;
+ }
}
-var DOMPointReadOnly$1 = domPointROExport;
-var PRIVATE$13 = Symbol('@@webxr-polyfill/XRInputPose');
-var XRInputPose = function () {
- function XRInputPose(inputSourceImpl, hasGripMatrix) {
- classCallCheck(this, XRInputPose);
- this[PRIVATE$13] = {
- inputSourceImpl: inputSourceImpl,
- targetRay: new XRRay(),
- gripMatrix: hasGripMatrix ? create() : null
+const PRIVATE$4 = Symbol('@@webxr-polyfill/XRViewerPose');
+class XRViewerPose extends XRPose$1 {
+ constructor(device) {
+ super(new XRRigidTransform$1(), false);
+ this[PRIVATE$4] = {
+ device,
+ leftViewMatrix: identity(new Float32Array(16)),
+ rightViewMatrix: identity(new Float32Array(16)),
+ poseModelMatrix: identity(new Float32Array(16)),
};
}
- createClass(XRInputPose, [{
- key: 'targetRay',
- get: function get$$1() {
- return this[PRIVATE$13].targetRay;
- }
- ,
- set: function set$$1(value) {
- this[PRIVATE$13].targetRay = value;
- }
- }, {
- key: 'emulatedPosition',
- get: function get$$1() {
- return this[PRIVATE$13].inputSourceImpl.emulatedPosition;
- }
- }, {
- key: 'gripMatrix',
- get: function get$$1() {
- return this[PRIVATE$13].gripMatrix;
+ get poseModelMatrix() { return this[PRIVATE$4].poseModelMatrix; }
+ getViewMatrix(view) {
+ switch (view.eye) {
+ case 'left': return this[PRIVATE$4].leftViewMatrix;
+ case 'right': return this[PRIVATE$4].rightViewMatrix;
+ }
+ throw new Error(`view is not a valid XREye`);
+ }
+ get views() {
+ return this[PRIVATE$4].views;
+ }
+ set views(value) {
+ this[PRIVATE$4].views = value;
+ }
+ updateFromReferenceSpace(refSpace) {
+ const pose = this[PRIVATE$4].device.getBasePoseMatrix();
+ const leftViewMatrix = this[PRIVATE$4].device.getBaseViewMatrix('left');
+ const rightViewMatrix = this[PRIVATE$4].device.getBaseViewMatrix('right');
+ if (pose) {
+ refSpace.transformBasePoseMatrix(this[PRIVATE$4].poseModelMatrix, pose);
+ refSpace._adjustForOriginOffset(this[PRIVATE$4].poseModelMatrix);
+ super._setTransform(new XRRigidTransform$1(this[PRIVATE$4].poseModelMatrix));
+ }
+ if (leftViewMatrix && rightViewMatrix) {
+ refSpace.transformBaseViewMatrix(this[PRIVATE$4].leftViewMatrix,
+ leftViewMatrix,
+ this[PRIVATE$4].poseModelMatrix);
+ refSpace.transformBaseViewMatrix(this[PRIVATE$4].rightViewMatrix,
+ rightViewMatrix,
+ this[PRIVATE$4].poseModelMatrix);
+ multiply(this[PRIVATE$4].leftViewMatrix, this[PRIVATE$4].leftViewMatrix, refSpace._originOffsetMatrix());
+ multiply(this[PRIVATE$4].rightViewMatrix, this[PRIVATE$4].rightViewMatrix, refSpace._originOffsetMatrix());
+ }
+ for (let view of this[PRIVATE$4].views) {
+ if (view.eye == "left") {
+ view._updateViewMatrix(this[PRIVATE$4].leftViewMatrix);
+ } else if (view.eye == "right") {
+ view._updateViewMatrix(this[PRIVATE$4].rightViewMatrix);
+ }
}
- }]);
- return XRInputPose;
-}();
-
-var PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSource');
-var XRInputSource = function () {
- function XRInputSource(impl) {
- classCallCheck(this, XRInputSource);
- this[PRIVATE$14] = {
- impl: impl
- };
}
- createClass(XRInputSource, [{
- key: 'handedness',
- get: function get$$1() {
- return this[PRIVATE$14].impl.handedness;
- }
- }, {
- key: 'targetRayMode',
- get: function get$$1() {
- return this[PRIVATE$14].impl.targetRayMode;
- }
- }]);
- return XRInputSource;
-}();
+}
-var XRLayer = function () {
- function XRLayer() {
- classCallCheck(this, XRLayer);
+const PRIVATE$5 = Symbol('@@webxr-polyfill/XRViewport');
+class XRViewport {
+ constructor(target) {
+ this[PRIVATE$5] = { target };
}
- createClass(XRLayer, [{
- key: "getViewport",
- value: function getViewport(view) {
- return view._getViewport(this);
- }
- }]);
- return XRLayer;
-}();
-
-var POLYFILLED_COMPATIBLE_XR_DEVICE = Symbol('@@webxr-polyfill/polyfilled-compatible-xr-device');
-var COMPATIBLE_XR_DEVICE = Symbol('@@webxr-polyfill/compatible-xr-device');
+ get x() { return this[PRIVATE$5].target.x; }
+ get y() { return this[PRIVATE$5].target.y; }
+ get width() { return this[PRIVATE$5].target.width; }
+ get height() { return this[PRIVATE$5].target.height; }
+}
-var PRIVATE$15 = Symbol('@@webxr-polyfill/XRWebGLLayer');
-var XRWebGLLayerInit = Object.freeze({
- antialias: true,
- depth: false,
- stencil: false,
- alpha: true,
- multiview: false,
- framebufferScaleFactor: 0
-});
-var XRWebGLLayer = function (_XRLayer) {
- inherits(XRWebGLLayer, _XRLayer);
- function XRWebGLLayer(session, context) {
- var layerInit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
- classCallCheck(this, XRWebGLLayer);
- var config = Object.assign({}, XRWebGLLayerInit, layerInit);
- if (!(session instanceof XRSession)) {
- throw new Error('session must be a XRSession');
- }
- if (session.ended) {
- throw new Error('InvalidStateError');
- }
- if (context[POLYFILLED_COMPATIBLE_XR_DEVICE]) {
- if (context[COMPATIBLE_XR_DEVICE] !== session.device) {
- throw new Error('InvalidStateError');
- }
+const XREyes = ['left', 'right'];
+const PRIVATE$6 = Symbol('@@webxr-polyfill/XRView');
+class XRView {
+ constructor(device, eye, sessionId) {
+ if (!XREyes.includes(eye)) {
+ throw new Error(`XREye must be one of: ${XREyes}`);
}
- var framebuffer = context.getParameter(context.FRAMEBUFFER_BINDING);
- var _this = possibleConstructorReturn(this, (XRWebGLLayer.__proto__ || Object.getPrototypeOf(XRWebGLLayer)).call(this));
- _this[PRIVATE$15] = {
- context: context,
- config: config,
- framebuffer: framebuffer
+ const temp = Object.create(null);
+ const viewport = new XRViewport(temp);
+ this[PRIVATE$6] = {
+ device,
+ eye,
+ viewport,
+ temp,
+ sessionId,
+ transform: null,
};
- return _this;
}
- createClass(XRWebGLLayer, [{
- key: 'requestViewportScaling',
- value: function requestViewportScaling(viewportScaleFactor) {
- console.warn('requestViewportScaling is not yet implemented');
- }
- }, {
- key: 'context',
- get: function get$$1() {
- return this[PRIVATE$15].context;
- }
- }, {
- key: 'antialias',
- get: function get$$1() {
- return this[PRIVATE$15].config.antialias;
- }
- }, {
- key: 'depth',
- get: function get$$1() {
- return this[PRIVATE$15].config.depth;
- }
- }, {
- key: 'stencil',
- get: function get$$1() {
- return this[PRIVATE$15].config.stencil;
- }
- }, {
- key: 'alpha',
- get: function get$$1() {
- return this[PRIVATE$15].config.alpha;
- }
- }, {
- key: 'multiview',
- get: function get$$1() {
- return false;
- }
- }, {
- key: 'framebuffer',
- get: function get$$1() {
- return this[PRIVATE$15].framebuffer;
- }
- }, {
- key: 'framebufferWidth',
- get: function get$$1() {
- return this[PRIVATE$15].context.drawingBufferWidth;
- }
- }, {
- key: 'framebufferHeight',
- get: function get$$1() {
- return this[PRIVATE$15].context.drawingBufferHeight;
- }
- }]);
- return XRWebGLLayer;
-}(XRLayer);
-
-var API = {
- XR: XR,
- XRDevice: XRDevice,
- XRSession: XRSession,
- XRFrame: XRFrame,
- XRView: XRView,
- XRViewport: XRViewport,
- XRDevicePose: XRDevicePose,
- XRLayer: XRLayer,
- XRWebGLLayer: XRWebGLLayer,
- XRPresentationContext: XRPresentationContext,
- XRCoordinateSystem: XRCoordinateSystem,
- XRFrameOfReference: XRFrameOfReference,
- XRStageBounds: XRStageBounds,
- XRStageBoundsPoint: XRStageBoundsPoint,
- XRInputPose: XRInputPose,
- XRInputSource: XRInputSource,
-};
-
-var extendContextCompatibleXRDevice = function extendContextCompatibleXRDevice(Context) {
- if (typeof Context.prototype.setCompatibleXRDevice === 'function') {
- return false;
+ get eye() { return this[PRIVATE$6].eye; }
+ get projectionMatrix() { return this[PRIVATE$6].device.getProjectionMatrix(this.eye); }
+ get transform() { return this[PRIVATE$6].transform; }
+ _updateViewMatrix(viewMatrix) {
+ let invMatrix = identity(new Float32Array(16));
+ invert(invMatrix, viewMatrix);
+ this[PRIVATE$6].transform = new XRRigidTransform$1(invMatrix);
}
- Context.prototype.setCompatibleXRDevice = function (xrDevice) {
- var _this = this;
- return new Promise(function (resolve, reject) {
- if (xrDevice && typeof xrDevice.requestSession === 'function') {
- resolve();
- } else {
- reject();
- }
- }).then(function () {
- return _this[COMPATIBLE_XR_DEVICE] = xrDevice;
- });
- };
- return true;
-};
-var extendGetContext = function extendGetContext(Canvas) {
- var getContext = HTMLCanvasElement.prototype.getContext;
- HTMLCanvasElement.prototype.getContext = function (contextType, glAttribs) {
- if (contextType === 'xrpresent') {
- var _ctx = getContext.call(this, '2d', glAttribs);
- return new XRPresentationContext(this, _ctx, glAttribs);
- }
- var ctx = getContext.call(this, contextType, glAttribs);
- ctx[POLYFILLED_COMPATIBLE_XR_DEVICE] = true;
- if (glAttribs && 'compatibleXRDevice' in glAttribs) {
- ctx[COMPATIBLE_XR_DEVICE] = glAttribs.compatibleXRDevice;
+ _getViewport(layer) {
+ const viewport = this[PRIVATE$6].viewport;
+ if (this[PRIVATE$6].device.getViewport(this[PRIVATE$6].sessionId,
+ this.eye,
+ layer,
+ this[PRIVATE$6].temp)) {
+ return this[PRIVATE$6].viewport;
}
- return ctx;
- };
-};
+ return undefined;
+ }
+}
-function create$1() {
- var out = new ARRAY_TYPE(3);
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
+var EPSILON$1 = 0.000001;
+var ARRAY_TYPE$1 = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+
+
+var degree$1 = Math.PI / 180;
+
+function create$7() {
+ var out = new ARRAY_TYPE$1(9);
+ if (ARRAY_TYPE$1 != 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 clone$1(a) {
- var out = new ARRAY_TYPE(3);
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
+
+function create$9() {
+ var out = new ARRAY_TYPE$1(3);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ }
return out;
}
-function length(a) {
+
+function length$3(a) {
var x = a[0];
var y = a[1];
var z = a[2];
return Math.sqrt(x * x + y * y + z * z);
}
-function fromValues$1(x, y, z) {
- var out = new ARRAY_TYPE(3);
+function fromValues$9(x, y, z) {
+ var out = new ARRAY_TYPE$1(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 set$2(out, x, y, z) {
- out[0] = x;
- out[1] = y;
- out[2] = z;
- 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 subtract$1(out, a, b) {
- out[0] = a[0] - b[0];
- out[1] = a[1] - b[1];
- out[2] = a[2] - b[2];
- return out;
-}
@@ -1547,19 +1185,18 @@ function subtract$1(out, a, b) {
-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) {
+
+
+
+
+
+function normalize$3(out, a) {
var x = a[0];
var y = a[1];
var z = a[2];
@@ -1572,10 +1209,10 @@ function normalize(out, a) {
}
return out;
}
-function dot(a, b) {
+function dot$3(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
-function cross(out, a, b) {
+function cross$1(out, a, b) {
var ax = a[0],
ay = a[1],
az = a[2];
@@ -1591,78 +1228,354 @@ function cross(out, a, b) {
-function transformMat4(out, a, m) {
- var x = a[0],
- y = a[1],
- z = a[2];
- var w = m[3] * x + m[7] * y + m[11] * z + m[15];
- w = w || 1.0;
- out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
- out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
- out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var len$3 = length$3;
+
+var forEach$2 = function () {
+ var vec = create$9();
+ return function (a, stride, offset, count, fn, arg) {
+ var i = void 0,
+ l = void 0;
+ 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$10() {
+ var out = new ARRAY_TYPE$1(4);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ }
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function normalize$4(out, a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ var w = a[3];
+ var 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;
}
-function transformQuat(out, a, q) {
- var qx = q[0],
- qy = q[1],
- qz = q[2],
- qw = q[3];
- var x = a[0],
- y = a[1],
- z = a[2];
- var uvx = qy * z - qz * y,
- uvy = qz * x - qx * z,
- uvz = qx * y - qy * x;
- var uuvx = qy * uvz - qz * uvy,
- uuvy = qz * uvx - qx * uvz,
- uuvz = qx * uvy - qy * uvx;
- var 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;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var forEach$3 = function () {
+ var vec = create$10();
+ return function (a, stride, offset, count, fn, arg) {
+ var i = void 0,
+ l = void 0;
+ 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$11() {
+ var out = new ARRAY_TYPE$1(4);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ }
+ out[3] = 1;
return out;
}
+function setAxisAngle$1(out, axis, rad) {
+ rad = rad * 0.5;
+ var 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 angle(a, b) {
- var tempA = fromValues$1(a[0], a[1], a[2]);
- var tempB = fromValues$1(b[0], b[1], b[2]);
- normalize(tempA, tempA);
- normalize(tempB, tempB);
- var cosine = dot(tempA, tempB);
- if (cosine > 1.0) {
- return 0;
- } else if (cosine < -1.0) {
- return Math.PI;
+
+
+
+
+function slerp$1(out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ var bx = b[0],
+ by = b[1],
+ bz = b[2],
+ bw = b[3];
+ var omega = void 0,
+ cosom = void 0,
+ sinom = void 0,
+ scale0 = void 0,
+ scale1 = void 0;
+ 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$1) {
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
} else {
- return Math.acos(cosine);
+ 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 fromMat3$1(out, m) {
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot = void 0;
+ 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 {
+ var i = 0;
+ if (m[4] > m[0]) i = 1;
+ if (m[8] > m[i * 3 + i]) i = 2;
+ var j = (i + 1) % 3;
+ var 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;
}
-var sub$1 = subtract$1;
-var len = length;
-var forEach = function () {
- var vec = create$1();
+
+
+
+
+
+
+
+var normalize$5 = normalize$4;
+
+
+var rotationTo$1 = function () {
+ var tmpvec3 = create$9();
+ var xUnitVec3 = fromValues$9(1, 0, 0);
+ var yUnitVec3 = fromValues$9(0, 1, 0);
+ return function (out, a, b) {
+ var dot = dot$3(a, b);
+ if (dot < -0.999999) {
+ cross$1(tmpvec3, xUnitVec3, a);
+ if (len$3(tmpvec3) < 0.000001) cross$1(tmpvec3, yUnitVec3, a);
+ normalize$3(tmpvec3, tmpvec3);
+ setAxisAngle$1(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ cross$1(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return normalize$5(out, out);
+ }
+ };
+}();
+var sqlerp$1 = function () {
+ var temp1 = create$11();
+ var temp2 = create$11();
+ return function (out, a, b, c, d, t) {
+ slerp$1(temp1, a, d, t);
+ slerp$1(temp2, b, c, t);
+ slerp$1(out, temp1, temp2, 2 * t * (1 - t));
+ return out;
+ };
+}();
+var setAxes$1 = function () {
+ var matr = create$7();
+ 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$5(out, fromMat3$1(out, matr));
+ };
+}();
+
+function create$13() {
+ var out = new ARRAY_TYPE$1(2);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ }
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var forEach$4 = function () {
+ var vec = create$13();
return function (a, stride, offset, count, fn, arg) {
var i = void 0,
l = void 0;
if (!stride) {
- stride = 3;
+ stride = 2;
}
if (!offset) {
offset = 0;
@@ -1673,33 +1586,537 @@ var forEach = function () {
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[0] = a[i];vec[1] = a[i + 1];
fn(vec, vec, arg);
- a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];
+ a[i] = vec[0];a[i + 1] = vec[1];
}
return a;
};
}();
-var poseMatrixToXRRay = function poseMatrixToXRRay(poseMatrix) {
- var rayOrigin = [];
- var rayDirection = [];
- set$2(rayOrigin, 0, 0, 0);
- transformMat4(rayOrigin, rayOrigin, poseMatrix);
- set$2(rayDirection, 0, 0, -1);
- transformMat4(rayDirection, rayDirection, poseMatrix);
- sub$1(rayDirection, rayDirection, rayOrigin);
- normalize(rayDirection, rayDirection);
- return new XRRay(new DOMPointReadOnly$1(rayOrigin[0], rayOrigin[1], rayOrigin[2], 1.0), new DOMPointReadOnly$1(rayDirection[0], rayDirection[1], rayDirection[2], 0.0), poseMatrix);
-};
-var isMobile = function isMobile(global) {
+const PRIVATE$7 = Symbol('@@webxr-polyfill/XRFrame');
+class XRFrame {
+ constructor(device, session, sessionId) {
+ const viewerPose = new XRViewerPose(device);
+ const views = [
+ new XRView(device, 'left', sessionId),
+ ];
+ if (session.immersive) {
+ views.push(new XRView(device, 'right', sessionId));
+ }
+ viewerPose.views = views;
+ this[PRIVATE$7] = {
+ device,
+ viewerPose,
+ views,
+ session,
+ };
+ }
+ get session() { return this[PRIVATE$7].session; }
+ get views() { return this[PRIVATE$7].views; }
+ getViewerPose(space) {
+ this[PRIVATE$7].viewerPose.updateFromReferenceSpace(space);
+ return this[PRIVATE$7].viewerPose;
+ }
+ getPose(space, baseSpace) {
+ if (space._specialType === "viewer") {
+ let viewerPose = this.getViewerPose(baseSpace);
+ return new XRPose(
+ new XRRigidTransform(viewerPose.poseModelMatrix),
+ viewerPose.emulatedPosition);
+ }
+ if (space._specialType === "target-ray" || space._specialType === "grip") {
+ return this[PRIVATE$7].device.getInputPose(
+ space._inputSource, baseSpace, space._specialType);
+ }
+ return null;
+ }
+}
+
+const PRIVATE$8 = Symbol('@@webxr-polyfill/XRStageBoundsPoint');
+class XRStageBoundsPoint {
+ constructor(x, z) {
+ this[PRIVATE$8] = { x, z };
+ }
+ get x() { return this[PRIVATE$8].x; }
+ get z() { return this[PRIVATE$8].z; }
+}
+
+const PRIVATE$9 = Symbol('@@webxr-polyfill/XRStageBounds');
+class XRStageBounds {
+ constructor(boundsData) {
+ const geometry = [];
+ for (let i = 0; i < boundsData.length; i += 2) {
+ geometry.push(new XRStageBoundsPoint(boundsData[i], boundsData[i + 1]));
+ }
+ this[PRIVATE$9] = { geometry };
+ }
+ get geometry() { return this[PRIVATE$9].geometry; }
+}
+
+const PRIVATE$10 = Symbol('@@webxr-polyfill/XRSpace');
+class XRSpace {
+ constructor(specialType = null, inputSource = null) {
+ this[PRIVATE$10] = {
+ specialType,
+ inputSource,
+ };
+ }
+ get _specialType() {
+ return this[PRIVATE$10].specialType;
+ }
+ get _inputSource() {
+ return this[PRIVATE$10].inputSource;
+ }
+}
+
+const DEFAULT_EMULATION_HEIGHT = 1.6;
+const PRIVATE$11 = Symbol('@@webxr-polyfill/XRReferenceSpace');
+const XRReferenceSpaceTypes = [
+ 'viewer',
+ 'local',
+ 'local-floor',
+ 'bounded-floor',
+ 'unbounded'
+];
+const XRReferenceSpaceOptions = Object.freeze({
+ disableStageEmulation: false,
+ stageEmulationHeight: 0,
+});
+class XRReferenceSpace extends XRSpace {
+ constructor(device, type, options, transform, bounds) {
+ options = Object.assign({}, XRReferenceSpaceOptions, options);
+ if (!XRReferenceSpaceTypes.includes(type)) {
+ throw new Error(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`);
+ }
+ super((type === 'viewer') ? 'viewer' : null);
+ if (this._isFloor(type) && options.disableStageEmulation && !transform) {
+ throw new Error(`XRReferenceSpace cannot use 'bounded-floor' type, if disabling emulation and platform does not provide`);
+ }
+ const { disableStageEmulation, stageEmulationHeight } = options;
+ let emulatedHeight = 0;
+ if (this._isFloor(type) && !transform) {
+ emulatedHeight = stageEmulationHeight !== 0 ? stageEmulationHeight : DEFAULT_EMULATION_HEIGHT;
+ }
+ if (this._isFloor(type) && !transform) {
+ transform = identity(new Float32Array(16));
+ transform[13] = emulatedHeight;
+ }
+ if (!transform) {
+ transform = identity(new Float32Array(16));
+ }
+ this[PRIVATE$11] = {
+ disableStageEmulation,
+ stageEmulationHeight,
+ emulatedHeight,
+ type,
+ transform,
+ device,
+ bounds,
+ options,
+ originOffset : identity(new Float32Array(16)),
+ };
+ this.onboundschange = undefined;
+ }
+ _isFloor(type) {
+ return type === 'bounded-floor' || type === 'local-floor';
+ }
+ get bounds() { return this[PRIVATE$11].bounds; }
+ get emulatedHeight() { return this[PRIVATE$11].emulatedHeight; }
+ get type() { return this[PRIVATE$11].type; }
+ transformBasePoseMatrix(out, pose) {
+ if (this[PRIVATE$11].transform) {
+ multiply(out, this[PRIVATE$11].transform, pose);
+ return;
+ }
+ switch (this.type) {
+ case 'local':
+ if (out !== pose) {
+ copy(out, pose);
+ }
+ return;
+ }
+ }
+ transformBaseViewMatrix(out, view) {
+ let frameOfRef = this[PRIVATE$11].transform;
+ if (frameOfRef) {
+ invert(out, frameOfRef);
+ multiply(out, view, out);
+ }
+ else {
+ copy(out, view);
+ }
+ return out;
+ }
+ _inverseOriginOffsetMatrix() {
+ let result = identity(new Float32Array(16));
+ invert(result, this[PRIVATE$11].originOffset);
+ return result;
+ }
+ _originOffsetMatrix() {
+ return this[PRIVATE$11].originOffset;
+ }
+ _adjustForOriginOffset(transformMatrix) {
+ multiply(transformMatrix, this._inverseOriginOffsetMatrix(), transformMatrix);
+ }
+ getOffsetReferenceSpace(additionalOffset) {
+ let newSpace = new XRReferenceSpace(
+ this[PRIVATE$11].device,
+ this[PRIVATE$11].type,
+ this[PRIVATE$11].options,
+ this[PRIVATE$11].transform,
+ this[PRIVATE$11].bounds);
+ multiply(newSpace[PRIVATE$11].originOffset, this[PRIVATE$11].originOffset, additionalOffset.matrix);
+ return newSpace;
+ }
+}
+
+const POLYFILLED_XR_COMPATIBLE = Symbol('@@webxr-polyfill/polyfilled-xr-compatible');
+const XR_COMPATIBLE = Symbol('@@webxr-polyfill/xr-compatible');
+
+const PRIVATE$12 = 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$12] = {
+ context,
+ config,
+ framebuffer,
+ session,
+ };
+ }
+ get context() { return this[PRIVATE$12].context; }
+ get antialias() { return this[PRIVATE$12].config.antialias; }
+ get ignoreDepthValues() { return true; }
+ get framebuffer() { return this[PRIVATE$12].framebuffer; }
+ get framebufferWidth() { return this[PRIVATE$12].context.drawingBufferWidth; }
+ get framebufferHeight() { return this[PRIVATE$12].context.drawingBufferHeight; }
+ get _session() { return this[PRIVATE$12].session; }
+ getViewport(view) {
+ return view._getViewport(this);
+ }
+}
+
+const PRIVATE$13 = Symbol('@@webxr-polyfill/XRSession');
+class XRSession$1 extends EventTarget {
+ constructor(device, mode, id) {
+ super();
+ let immersive = mode != 'inline';
+ let outputContext = null;
+ this[PRIVATE$13] = {
+ device,
+ mode,
+ immersive,
+ outputContext,
+ ended: false,
+ suspended: false,
+ suspendedCallback: null,
+ id,
+ activeRenderState: null,
+ pendingRenderState: null,
+ };
+ const frame = new XRFrame(device, this, this[PRIVATE$13].id);
+ this[PRIVATE$13].frame = frame;
+ this[PRIVATE$13].onPresentationEnd = sessionId => {
+ if (sessionId !== this[PRIVATE$13].id) {
+ this[PRIVATE$13].suspended = false;
+ this.dispatchEvent('focus', { session: this });
+ const suspendedCallback = this[PRIVATE$13].suspendedCallback;
+ this[PRIVATE$13].suspendedCallback = null;
+ if (suspendedCallback) {
+ this.requestAnimationFrame(suspendedCallback);
+ }
+ return;
+ }
+ this[PRIVATE$13].ended = true;
+ device.removeEventListener('@webvr-polyfill/vr-present-end', this[PRIVATE$13].onPresentationEnd);
+ device.removeEventListener('@webvr-polyfill/vr-present-start', this[PRIVATE$13].onPresentationStart);
+ device.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$13].onSelectStart);
+ device.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$13].onSelectEnd);
+ this.dispatchEvent('end', { session: this });
+ };
+ device.addEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$13].onPresentationEnd);
+ this[PRIVATE$13].onPresentationStart = sessionId => {
+ if (sessionId === this[PRIVATE$13].id) {
+ return;
+ }
+ this[PRIVATE$13].suspended = true;
+ this.dispatchEvent('blur', { session: this });
+ };
+ device.addEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$13].onPresentationStart);
+ this[PRIVATE$13].onSelectStart = evt => {
+ if (evt.sessionId !== this[PRIVATE$13].id) {
+ return;
+ }
+ this.dispatchEvent('selectstart', {
+ frame: this[PRIVATE$13].frame,
+ inputSource: evt.inputSource
+ });
+ };
+ device.addEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$13].onSelectStart);
+ this[PRIVATE$13].onSelectEnd = evt => {
+ if (evt.sessionId !== this[PRIVATE$13].id) {
+ return;
+ }
+ this.dispatchEvent('selectend', {
+ frame: this[PRIVATE$13].frame,
+ inputSource: evt.inputSource
+ });
+ this.dispatchEvent('select', {
+ frame: this[PRIVATE$13].frame,
+ inputSource: evt.inputSource
+ });
+ };
+ device.addEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$13].onSelectEnd);
+ 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$13].activeRenderState; }
+ get immersive() { return this[PRIVATE$13].immersive; }
+ get outputContext() { return this[PRIVATE$13].outputContext; }
+ get depthNear() { return this[PRIVATE$13].device.depthNear; }
+ set depthNear(value) { this[PRIVATE$13].device.depthNear = value; }
+ get depthFar() { return this[PRIVATE$13].device.depthFar; }
+ set depthFar(value) { this[PRIVATE$13].device.depthFar = value; }
+ get environmentBlendMode() {
+ return this[PRIVATE$13].device.environmentBlendMode || 'opaque';
+ }
+ get baseLayer() { return this[PRIVATE$13].baseLayer; }
+ set baseLayer(value) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ this[PRIVATE$13].baseLayer = value;
+ this[PRIVATE$13].device.onBaseLayerSet(this[PRIVATE$13].id, value);
+ }
+ async requestReferenceSpace(type, options={}) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ options = Object.assign({}, XRReferenceSpaceOptions, options);
+ if (!XRReferenceSpaceTypes.includes(type)) {
+ throw new TypeError(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`);
+ }
+ let transform = null;
+ let bounds = null;
+ try {
+ transform = await this[PRIVATE$13].device.requestFrameOfReferenceTransform(type, options);
+ } catch (e) {
+ if (type !== 'stage' || options.disableStageEmulation) {
+ throw e;
+ }
+ }
+ if (type === 'stage' && transform) {
+ bounds = this[PRIVATE$13].device.requestStageBounds();
+ if (bounds) {
+ bounds = new XRStageBounds(bounds);
+ }
+ }
+ return new XRReferenceSpace(this[PRIVATE$13].device, type, options, transform, bounds);
+ }
+ requestAnimationFrame(callback) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ if (this[PRIVATE$13].suspended && this[PRIVATE$13].suspendedCallback) {
+ return;
+ }
+ if (this[PRIVATE$13].suspended && !this[PRIVATE$13].suspendedCallback) {
+ this[PRIVATE$13].suspendedCallback = callback;
+ }
+ return this[PRIVATE$13].device.requestAnimationFrame(() => {
+ if (this[PRIVATE$13].pendingRenderState !== null) {
+ this[PRIVATE$13].activeRenderState = this[PRIVATE$13].pendingRenderState;
+ this[PRIVATE$13].pendingRenderState = null;
+ if (this[PRIVATE$13].activeRenderState.baseLayer) {
+ this[PRIVATE$13].device.onBaseLayerSet(
+ this[PRIVATE$13].id,
+ this[PRIVATE$13].activeRenderState.baseLayer);
+ }
+ if (this[PRIVATE$13].activeRenderState.inlineVerticalFieldOfView) {
+ this[PRIVATE$13].device.onInlineVerticalFieldOfViewSet(
+ this[PRIVATE$13].id,
+ this[PRIVATE$13].activeRenderState.inlineVerticalFieldOfView);
+ }
+ }
+ this[PRIVATE$13].device.onFrameStart(this[PRIVATE$13].id);
+ callback(now$1(), this[PRIVATE$13].frame);
+ this[PRIVATE$13].device.onFrameEnd(this[PRIVATE$13].id);
+ });
+ }
+ cancelAnimationFrame(handle) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ this[PRIVATE$13].device.cancelAnimationFrame(handle);
+ }
+ get inputSources() {
+ return this[PRIVATE$13].device.getInputSources();
+ }
+ async end() {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ if (!this.immersive) {
+ this[PRIVATE$13].ended = true;
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/vr-present-start',
+ this[PRIVATE$13].onPresentationStart);
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/vr-present-end',
+ this[PRIVATE$13].onPresentationEnd);
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/input-select-start',
+ this[PRIVATE$13].onSelectStart);
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/input-select-end',
+ this[PRIVATE$13].onSelectEnd);
+ this.dispatchEvent('end', { session: this });
+ }
+ return this[PRIVATE$13].device.endSession(this[PRIVATE$13].id);
+ }
+ updateRenderState(newState) {
+ if (this[PRIVATE$13].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$13].immersive) {
+ const message = "inlineVerticalFieldOfView must not be set for an " +
+ "XRRenderState passed to updateRenderState for an " +
+ "immersive session.";
+ throw new Error(message);
+ } else {
+ newState.inlineVerticalFieldOfView = Math.min(
+ 3.13, Math.max(0.01, newState.inlineVerticalFieldOfView));
+ }
+ }
+ if (this[PRIVATE$13].pendingRenderState === null) {
+ this[PRIVATE$13].pendingRenderState = Object.assign(
+ {}, this[PRIVATE$13].activeRenderState, newState);
+ }
+ }
+}
+
+const PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSource');
+class XRInputSource {
+ constructor(impl) {
+ this[PRIVATE$14] = {
+ impl,
+ gripSpace: new XRSpace("grip", this),
+ targetRaySpace: new XRSpace("target-ray", this)
+ };
+ }
+ get handedness() { return this[PRIVATE$14].impl.handedness; }
+ get targetRayMode() { return this[PRIVATE$14].impl.targetRayMode; }
+ get gripSpace() {
+ let mode = this[PRIVATE$14].impl.targetRayMode;
+ if (mode === "gaze" || mode === "screen") {
+ return null;
+ }
+ return this[PRIVATE$14].gripSpace;
+ }
+ get targetRaySpace() { return this[PRIVATE$14].targetRaySpace; }
+ get gamepad() { return this[PRIVATE$14].impl.gamepad; }
+}
+
+const PRIVATE$15 = 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$15] = { config };
+ }
+ get depthNear() { return this[PRIVATE$15].depthNear; }
+ get depthFar() { return this[PRIVATE$15].depthFar; }
+ get inlineVerticalFieldOfView() { return this[PRIVATE$15].inlineVerticalFieldOfView; }
+ get baseLayer() { return this[PRIVATE$15].baseLayer; }
+}
+
+var API = {
+ XR: XR$1,
+ XRSession: XRSession$1,
+ XRFrame,
+ XRView,
+ XRViewport,
+ XRViewerPose,
+ XRWebGLLayer,
+ XRSpace,
+ XRReferenceSpace,
+ XRStageBounds,
+ XRStageBoundsPoint,
+ XRInputSource,
+ XRRenderState,
+ XRRigidTransform: XRRigidTransform$1,
+ XRPose: XRPose$1,
+};
+
+const polyfillMakeXRCompatible = Context => {
+ if (typeof Context.prototype.makeXRCompatible === 'function') {
+ return false;
+ }
+ Context.prototype.makeXRCompatible = function () {
+ this[XR_COMPATIBLE] = true;
+ return Promise.resolve();
+ };
+ return true;
+};
+const polyfillGetContext = (Canvas) => {
+ const getContext = Canvas.prototype.getContext;
+ Canvas.prototype.getContext = function (contextType, glAttribs) {
+ const ctx = getContext.call(this, contextType, glAttribs);
+ ctx[POLYFILLED_XR_COMPATIBLE] = true;
+ if (glAttribs && ('xrCompatible' in glAttribs)) {
+ ctx[XR_COMPATIBLE] = glAttribs.xrCompatible;
+ }
+ return ctx;
+ };
+};
+
+const isImageBitmapSupported = global =>
+ !!(global.ImageBitmapRenderingContext &&
+ global.createImageBitmap);
+const isMobile = global => {
var check = false;
- (function (a) {
- if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
- })(global.navigator.userAgent || global.navigator.vendor || global.opera);
+ (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(global.navigator.userAgent||global.navigator.vendor||global.opera);
return check;
};
-var applyCanvasStylesForMinimalRendering = function applyCanvasStylesForMinimalRendering(canvas) {
+const applyCanvasStylesForMinimalRendering = canvas => {
canvas.style.display = 'block';
canvas.style.position = 'absolute';
canvas.style.width = canvas.style.height = '1px';
@@ -1777,8 +2194,8 @@ var slicedToArray = function () {
}();
var MIN_TIMESTEP = 0.001;
var MAX_TIMESTEP = 1;
-var base64 = function base64(mimeType, _base) {
- return 'data:' + mimeType + ';base64,' + _base;
+var dataUri = function dataUri(mimeType, svg) {
+ return 'data:' + mimeType + ',' + encodeURIComponent(svg);
};
var lerp = function lerp(a, b, t) {
return a + (b - a) * t;
@@ -3381,8 +3798,8 @@ function CardboardViewer(params) {
}
DeviceInfo.Viewers = Viewers;
var format = 1;
-var last_updated = "2018-02-20T22:55:10Z";
-var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}];
+var last_updated = "2018-12-10T17:01:42Z";
+var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}];
var DPDB_CACHE = {
format: format,
last_updated: last_updated,
@@ -3457,7 +3874,7 @@ Dpdb.prototype.calcDeviceParams_ = function () {
var matched = false;
for (var j = 0; j < device.rules.length; j++) {
var rule = device.rules[j];
- if (this.matchRule_(rule, userAgent, width, height)) {
+ if (this.ruleMatches_(rule, userAgent, width, height)) {
matched = true;
break;
}
@@ -3470,8 +3887,9 @@ Dpdb.prototype.calcDeviceParams_ = function () {
console.warn('No DPDB device match.');
return null;
};
-Dpdb.prototype.matchRule_ = function (rule, ua, screenWidth, screenHeight) {
+Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) {
if (!rule.ua && !rule.res) return false;
+ if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7);
if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
if (rule.res) {
if (!rule.res[0] || !rule.res[1]) return false;
@@ -3807,18 +4225,6 @@ FusionPoseSensor.prototype.stop = function () {
var SENSOR_FREQUENCY = 60;
var X_AXIS = new Vector3(1, 0, 0);
var Z_AXIS = new Vector3(0, 0, 1);
-var orientation = {};
-if (screen.orientation) {
- orientation = screen.orientation;
-} else if (screen.msOrientation) {
- orientation = screen.msOrientation;
-} else {
- Object.defineProperty(orientation, 'angle', {
- get: function get$$1() {
- return window.orientation || 0;
- }
- });
-}
var SENSOR_TO_VR = new Quaternion();
SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2);
SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2));
@@ -3832,12 +4238,9 @@ var PoseSensor = function () {
this.api = null;
this.errors = [];
this._sensorQ = new Quaternion();
- this._worldToScreenQ = new Quaternion();
this._outQ = new Quaternion();
this._onSensorRead = this._onSensorRead.bind(this);
this._onSensorError = this._onSensorError.bind(this);
- this._onOrientationChange = this._onOrientationChange.bind(this);
- this._onOrientationChange();
this.init();
}
createClass(PoseSensor, [{
@@ -3845,7 +4248,10 @@ var PoseSensor = function () {
value: function init() {
var sensor = null;
try {
- sensor = new RelativeOrientationSensor({ frequency: SENSOR_FREQUENCY });
+ sensor = new RelativeOrientationSensor({
+ frequency: SENSOR_FREQUENCY,
+ referenceFrame: 'screen'
+ });
sensor.addEventListener('error', this._onSensorError);
} catch (error) {
this.errors.push(error);
@@ -3865,7 +4271,6 @@ var PoseSensor = function () {
this.sensor.addEventListener('reading', this._onSensorRead);
this.sensor.start();
}
- window.addEventListener('orientationchange', this._onOrientationChange);
}
}, {
key: 'useDeviceMotion',
@@ -3894,7 +4299,6 @@ var PoseSensor = function () {
var out = this._outQ;
out.copy(SENSOR_TO_VR);
out.multiply(this._sensorQ);
- out.multiply(this._worldToScreenQ);
if (this.config.YAW_ONLY) {
out.x = out.z = 0;
out.normalize();
@@ -3921,16 +4325,10 @@ var PoseSensor = function () {
}, {
key: '_onSensorRead',
value: function _onSensorRead() {}
- }, {
- key: '_onOrientationChange',
- value: function _onOrientationChange() {
- var angle = -orientation.angle * Math.PI / 180;
- this._worldToScreenQ.setFromAxisAngle(Z_AXIS, angle);
- }
}]);
return PoseSensor;
}();
-var rotateInstructionsAsset = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjE5OHB4IiBoZWlnaHQ9IjI0MHB4IiB2aWV3Qm94PSIwIDAgMTk4IDI0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDMuMy4zICgxMjA4MSkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+dHJhbnNpdGlvbjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHNrZXRjaDp0eXBlPSJNU1BhZ2UiPgogICAgICAgIDxnIGlkPSJ0cmFuc2l0aW9uIiBza2V0Y2g6dHlwZT0iTVNBcnRib2FyZEdyb3VwIj4KICAgICAgICAgICAgPGcgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTQtKy1JbXBvcnRlZC1MYXllcnMtQ29weS0rLUltcG9ydGVkLUxheWVycy1Db3B5LTItQ29weSIgc2tldGNoOnR5cGU9Ik1TTGF5ZXJHcm91cCI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHktNCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwNy4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjYyNSwyLjUyNyBDMTQ5LjYyNSwyLjUyNyAxNTUuODA1LDYuMDk2IDE1Ni4zNjIsNi40MTggTDE1Ni4zNjIsNy4zMDQgQzE1Ni4zNjIsNy40ODEgMTU2LjM3NSw3LjY2NCAxNTYuNCw3Ljg1MyBDMTU2LjQxLDcuOTM0IDE1Ni40Miw4LjAxNSAxNTYuNDI3LDguMDk1IEMxNTYuNTY3LDkuNTEgMTU3LjQwMSwxMS4wOTMgMTU4LjUzMiwxMi4wOTQgTDE2NC4yNTIsMTcuMTU2IEwxNjQuMzMzLDE3LjA2NiBDMTY0LjMzMywxNy4wNjYgMTY4LjcxNSwxNC41MzYgMTY5LjU2OCwxNC4wNDIgQzE3MS4wMjUsMTQuODgzIDE5NS41MzgsMjkuMDM1IDE5NS41MzgsMjkuMDM1IEwxOTUuNTM4LDgzLjAzNiBDMTk1LjUzOCw4My44MDcgMTk1LjE1Miw4NC4yNTMgMTk0LjU5LDg0LjI1MyBDMTk0LjM1Nyw4NC4yNTMgMTk0LjA5NSw4NC4xNzcgMTkzLjgxOCw4NC4wMTcgTDE2OS44NTEsNzAuMTc5IEwxNjkuODM3LDcwLjIwMyBMMTQyLjUxNSw4NS45NzggTDE0MS42NjUsODQuNjU1IEMxMzYuOTM0LDgzLjEyNiAxMzEuOTE3LDgxLjkxNSAxMjYuNzE0LDgxLjA0NSBDMTI2LjcwOSw4MS4wNiAxMjYuNzA3LDgxLjA2OSAxMjYuNzA3LDgxLjA2OSBMMTIxLjY0LDk4LjAzIEwxMTMuNzQ5LDEwMi41ODYgTDExMy43MTIsMTAyLjUyMyBMMTEzLjcxMiwxMzAuMTEzIEMxMTMuNzEyLDEzMC44ODUgMTEzLjMyNiwxMzEuMzMgMTEyLjc2NCwxMzEuMzMgQzExMi41MzIsMTMxLjMzIDExMi4yNjksMTMxLjI1NCAxMTEuOTkyLDEzMS4wOTQgTDY5LjUxOSwxMDYuNTcyIEM2OC41NjksMTA2LjAyMyA2Ny43OTksMTA0LjY5NSA2Ny43OTksMTAzLjYwNSBMNjcuNzk5LDEwMi41NyBMNjcuNzc4LDEwMi42MTcgQzY3LjI3LDEwMi4zOTMgNjYuNjQ4LDEwMi4yNDkgNjUuOTYyLDEwMi4yMTggQzY1Ljg3NSwxMDIuMjE0IDY1Ljc4OCwxMDIuMjEyIDY1LjcwMSwxMDIuMjEyIEM2NS42MDYsMTAyLjIxMiA2NS41MTEsMTAyLjIxNSA2NS40MTYsMTAyLjIxOSBDNjUuMTk1LDEwMi4yMjkgNjQuOTc0LDEwMi4yMzUgNjQuNzU0LDEwMi4yMzUgQzY0LjMzMSwxMDIuMjM1IDYzLjkxMSwxMDIuMjE2IDYzLjQ5OCwxMDIuMTc4IEM2MS44NDMsMTAyLjAyNSA2MC4yOTgsMTAxLjU3OCA1OS4wOTQsMTAwLjg4MiBMMTIuNTE4LDczLjk5MiBMMTIuNTIzLDc0LjAwNCBMMi4yNDUsNTUuMjU0IEMxLjI0NCw1My40MjcgMi4wMDQsNTEuMDM4IDMuOTQzLDQ5LjkxOCBMNTkuOTU0LDE3LjU3MyBDNjAuNjI2LDE3LjE4NSA2MS4zNSwxNy4wMDEgNjIuMDUzLDE3LjAwMSBDNjMuMzc5LDE3LjAwMSA2NC42MjUsMTcuNjYgNjUuMjgsMTguODU0IEw2NS4yODUsMTguODUxIEw2NS41MTIsMTkuMjY0IEw2NS41MDYsMTkuMjY4IEM2NS45MDksMjAuMDAzIDY2LjQwNSwyMC42OCA2Ni45ODMsMjEuMjg2IEw2Ny4yNiwyMS41NTYgQzY5LjE3NCwyMy40MDYgNzEuNzI4LDI0LjM1NyA3NC4zNzMsMjQuMzU3IEM3Ni4zMjIsMjQuMzU3IDc4LjMyMSwyMy44NCA4MC4xNDgsMjIuNzg1IEM4MC4xNjEsMjIuNzg1IDg3LjQ2NywxOC41NjYgODcuNDY3LDE4LjU2NiBDODguMTM5LDE4LjE3OCA4OC44NjMsMTcuOTk0IDg5LjU2NiwxNy45OTQgQzkwLjg5MiwxNy45OTQgOTIuMTM4LDE4LjY1MiA5Mi43OTIsMTkuODQ3IEw5Ni4wNDIsMjUuNzc1IEw5Ni4wNjQsMjUuNzU3IEwxMDIuODQ5LDI5LjY3NCBMMTAyLjc0NCwyOS40OTIgTDE0OS42MjUsMi41MjcgTTE0OS42MjUsMC44OTIgQzE0OS4zNDMsMC44OTIgMTQ5LjA2MiwwLjk2NSAxNDguODEsMS4xMSBMMTAyLjY0MSwyNy42NjYgTDk3LjIzMSwyNC41NDIgTDk0LjIyNiwxOS4wNjEgQzkzLjMxMywxNy4zOTQgOTEuNTI3LDE2LjM1OSA4OS41NjYsMTYuMzU4IEM4OC41NTUsMTYuMzU4IDg3LjU0NiwxNi42MzIgODYuNjQ5LDE3LjE1IEM4My44NzgsMTguNzUgNzkuNjg3LDIxLjE2OSA3OS4zNzQsMjEuMzQ1IEM3OS4zNTksMjEuMzUzIDc5LjM0NSwyMS4zNjEgNzkuMzMsMjEuMzY5IEM3Ny43OTgsMjIuMjU0IDc2LjA4NCwyMi43MjIgNzQuMzczLDIyLjcyMiBDNzIuMDgxLDIyLjcyMiA2OS45NTksMjEuODkgNjguMzk3LDIwLjM4IEw2OC4xNDUsMjAuMTM1IEM2Ny43MDYsMTkuNjcyIDY3LjMyMywxOS4xNTYgNjcuMDA2LDE4LjYwMSBDNjYuOTg4LDE4LjU1OSA2Ni45NjgsMTguNTE5IDY2Ljk0NiwxOC40NzkgTDY2LjcxOSwxOC4wNjUgQzY2LjY5LDE4LjAxMiA2Ni42NTgsMTcuOTYgNjYuNjI0LDE3LjkxMSBDNjUuNjg2LDE2LjMzNyA2My45NTEsMTUuMzY2IDYyLjA1MywxNS4zNjYgQzYxLjA0MiwxNS4zNjYgNjAuMDMzLDE1LjY0IDU5LjEzNiwxNi4xNTggTDMuMTI1LDQ4LjUwMiBDMC40MjYsNTAuMDYxIC0wLjYxMyw1My40NDIgMC44MTEsNTYuMDQgTDExLjA4OSw3NC43OSBDMTEuMjY2LDc1LjExMyAxMS41MzcsNzUuMzUzIDExLjg1LDc1LjQ5NCBMNTguMjc2LDEwMi4yOTggQzU5LjY3OSwxMDMuMTA4IDYxLjQzMywxMDMuNjMgNjMuMzQ4LDEwMy44MDYgQzYzLjgxMiwxMDMuODQ4IDY0LjI4NSwxMDMuODcgNjQuNzU0LDEwMy44NyBDNjUsMTAzLjg3IDY1LjI0OSwxMDMuODY0IDY1LjQ5NCwxMDMuODUyIEM2NS41NjMsMTAzLjg0OSA2NS42MzIsMTAzLjg0NyA2NS43MDEsMTAzLjg0NyBDNjUuNzY0LDEwMy44NDcgNjUuODI4LDEwMy44NDkgNjUuODksMTAzLjg1MiBDNjUuOTg2LDEwMy44NTYgNjYuMDgsMTAzLjg2MyA2Ni4xNzMsMTAzLjg3NCBDNjYuMjgyLDEwNS40NjcgNjcuMzMyLDEwNy4xOTcgNjguNzAyLDEwNy45ODggTDExMS4xNzQsMTMyLjUxIEMxMTEuNjk4LDEzMi44MTIgMTEyLjIzMiwxMzIuOTY1IDExMi43NjQsMTMyLjk2NSBDMTE0LjI2MSwxMzIuOTY1IDExNS4zNDcsMTMxLjc2NSAxMTUuMzQ3LDEzMC4xMTMgTDExNS4zNDcsMTAzLjU1MSBMMTIyLjQ1OCw5OS40NDYgQzEyMi44MTksOTkuMjM3IDEyMy4wODcsOTguODk4IDEyMy4yMDcsOTguNDk4IEwxMjcuODY1LDgyLjkwNSBDMTMyLjI3OSw4My43MDIgMTM2LjU1Nyw4NC43NTMgMTQwLjYwNyw4Ni4wMzMgTDE0MS4xNCw4Ni44NjIgQzE0MS40NTEsODcuMzQ2IDE0MS45NzcsODcuNjEzIDE0Mi41MTYsODcuNjEzIEMxNDIuNzk0LDg3LjYxMyAxNDMuMDc2LDg3LjU0MiAxNDMuMzMzLDg3LjM5MyBMMTY5Ljg2NSw3Mi4wNzYgTDE5Myw4NS40MzMgQzE5My41MjMsODUuNzM1IDE5NC4wNTgsODUuODg4IDE5NC41OSw4NS44ODggQzE5Ni4wODcsODUuODg4IDE5Ny4xNzMsODQuNjg5IDE5Ny4xNzMsODMuMDM2IEwxOTcuMTczLDI5LjAzNSBDMTk3LjE3MywyOC40NTEgMTk2Ljg2MSwyNy45MTEgMTk2LjM1NSwyNy42MTkgQzE5Ni4zNTUsMjcuNjE5IDE3MS44NDMsMTMuNDY3IDE3MC4zODUsMTIuNjI2IEMxNzAuMTMyLDEyLjQ4IDE2OS44NSwxMi40MDcgMTY5LjU2OCwxMi40MDcgQzE2OS4yODUsMTIuNDA3IDE2OS4wMDIsMTIuNDgxIDE2OC43NDksMTIuNjI3IEMxNjguMTQzLDEyLjk3OCAxNjUuNzU2LDE0LjM1NyAxNjQuNDI0LDE1LjEyNSBMMTU5LjYxNSwxMC44NyBDMTU4Ljc5NiwxMC4xNDUgMTU4LjE1NCw4LjkzNyAxNTguMDU0LDcuOTM0IEMxNTguMDQ1LDcuODM3IDE1OC4wMzQsNy43MzkgMTU4LjAyMSw3LjY0IEMxNTguMDA1LDcuNTIzIDE1Ny45OTgsNy40MSAxNTcuOTk4LDcuMzA0IEwxNTcuOTk4LDYuNDE4IEMxNTcuOTk4LDUuODM0IDE1Ny42ODYsNS4yOTUgMTU3LjE4MSw1LjAwMiBDMTU2LjYyNCw0LjY4IDE1MC40NDIsMS4xMTEgMTUwLjQ0MiwxLjExMSBDMTUwLjE4OSwwLjk2NSAxNDkuOTA3LDAuODkyIDE0OS42MjUsMC44OTIiIGlkPSJGaWxsLTEiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTYuMDI3LDI1LjYzNiBMMTQyLjYwMyw1Mi41MjcgQzE0My44MDcsNTMuMjIyIDE0NC41ODIsNTQuMTE0IDE0NC44NDUsNTUuMDY4IEwxNDQuODM1LDU1LjA3NSBMNjMuNDYxLDEwMi4wNTcgTDYzLjQ2LDEwMi4wNTcgQzYxLjgwNiwxMDEuOTA1IDYwLjI2MSwxMDEuNDU3IDU5LjA1NywxMDAuNzYyIEwxMi40ODEsNzMuODcxIEw5Ni4wMjcsMjUuNjM2IiBpZD0iRmlsbC0yIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYzLjQ2MSwxMDIuMTc0IEM2My40NTMsMTAyLjE3NCA2My40NDYsMTAyLjE3NCA2My40MzksMTAyLjE3MiBDNjEuNzQ2LDEwMi4wMTYgNjAuMjExLDEwMS41NjMgNTguOTk4LDEwMC44NjMgTDEyLjQyMiw3My45NzMgQzEyLjM4Niw3My45NTIgMTIuMzY0LDczLjkxNCAxMi4zNjQsNzMuODcxIEMxMi4zNjQsNzMuODMgMTIuMzg2LDczLjc5MSAxMi40MjIsNzMuNzcgTDk1Ljk2OCwyNS41MzUgQzk2LjAwNCwyNS41MTQgOTYuMDQ5LDI1LjUxNCA5Ni4wODUsMjUuNTM1IEwxNDIuNjYxLDUyLjQyNiBDMTQzLjg4OCw1My4xMzQgMTQ0LjY4Miw1NC4wMzggMTQ0Ljk1Nyw1NS4wMzcgQzE0NC45Nyw1NS4wODMgMTQ0Ljk1Myw1NS4xMzMgMTQ0LjkxNSw1NS4xNjEgQzE0NC45MTEsNTUuMTY1IDE0NC44OTgsNTUuMTc0IDE0NC44OTQsNTUuMTc3IEw2My41MTksMTAyLjE1OCBDNjMuNTAxLDEwMi4xNjkgNjMuNDgxLDEwMi4xNzQgNjMuNDYxLDEwMi4xNzQgTDYzLjQ2MSwxMDIuMTc0IFogTTEyLjcxNCw3My44NzEgTDU5LjExNSwxMDAuNjYxIEM2MC4yOTMsMTAxLjM0MSA2MS43ODYsMTAxLjc4MiA2My40MzUsMTAxLjkzNyBMMTQ0LjcwNyw1NS4wMTUgQzE0NC40MjgsNTQuMTA4IDE0My42ODIsNTMuMjg1IDE0Mi41NDQsNTIuNjI4IEw5Ni4wMjcsMjUuNzcxIEwxMi43MTQsNzMuODcxIEwxMi43MTQsNzMuODcxIFoiIGlkPSJGaWxsLTMiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ4LjMyNyw1OC40NzEgQzE0OC4xNDUsNTguNDggMTQ3Ljk2Miw1OC40OCAxNDcuNzgxLDU4LjQ3MiBDMTQ1Ljg4Nyw1OC4zODkgMTQ0LjQ3OSw1Ny40MzQgMTQ0LjYzNiw1Ni4zNCBDMTQ0LjY4OSw1NS45NjcgMTQ0LjY2NCw1NS41OTcgMTQ0LjU2NCw1NS4yMzUgTDYzLjQ2MSwxMDIuMDU3IEM2NC4wODksMTAyLjExNSA2NC43MzMsMTAyLjEzIDY1LjM3OSwxMDIuMDk5IEM2NS41NjEsMTAyLjA5IDY1Ljc0MywxMDIuMDkgNjUuOTI1LDEwMi4wOTggQzY3LjgxOSwxMDIuMTgxIDY5LjIyNywxMDMuMTM2IDY5LjA3LDEwNC4yMyBMMTQ4LjMyNyw1OC40NzEiIGlkPSJGaWxsLTQiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjkuMDcsMTA0LjM0NyBDNjkuMDQ4LDEwNC4zNDcgNjkuMDI1LDEwNC4zNCA2OS4wMDUsMTA0LjMyNyBDNjguOTY4LDEwNC4zMDEgNjguOTQ4LDEwNC4yNTcgNjguOTU1LDEwNC4yMTMgQzY5LDEwMy44OTYgNjguODk4LDEwMy41NzYgNjguNjU4LDEwMy4yODggQzY4LjE1MywxMDIuNjc4IDY3LjEwMywxMDIuMjY2IDY1LjkyLDEwMi4yMTQgQzY1Ljc0MiwxMDIuMjA2IDY1LjU2MywxMDIuMjA3IDY1LjM4NSwxMDIuMjE1IEM2NC43NDIsMTAyLjI0NiA2NC4wODcsMTAyLjIzMiA2My40NSwxMDIuMTc0IEM2My4zOTksMTAyLjE2OSA2My4zNTgsMTAyLjEzMiA2My4zNDcsMTAyLjA4MiBDNjMuMzM2LDEwMi4wMzMgNjMuMzU4LDEwMS45ODEgNjMuNDAyLDEwMS45NTYgTDE0NC41MDYsNTUuMTM0IEMxNDQuNTM3LDU1LjExNiAxNDQuNTc1LDU1LjExMyAxNDQuNjA5LDU1LjEyNyBDMTQ0LjY0Miw1NS4xNDEgMTQ0LjY2OCw1NS4xNyAxNDQuNjc3LDU1LjIwNCBDMTQ0Ljc4MSw1NS41ODUgMTQ0LjgwNiw1NS45NzIgMTQ0Ljc1MSw1Ni4zNTcgQzE0NC43MDYsNTYuNjczIDE0NC44MDgsNTYuOTk0IDE0NS4wNDcsNTcuMjgyIEMxNDUuNTUzLDU3Ljg5MiAxNDYuNjAyLDU4LjMwMyAxNDcuNzg2LDU4LjM1NSBDMTQ3Ljk2NCw1OC4zNjMgMTQ4LjE0Myw1OC4zNjMgMTQ4LjMyMSw1OC4zNTQgQzE0OC4zNzcsNTguMzUyIDE0OC40MjQsNTguMzg3IDE0OC40MzksNTguNDM4IEMxNDguNDU0LDU4LjQ5IDE0OC40MzIsNTguNTQ1IDE0OC4zODUsNTguNTcyIEw2OS4xMjksMTA0LjMzMSBDNjkuMTExLDEwNC4zNDIgNjkuMDksMTA0LjM0NyA2OS4wNywxMDQuMzQ3IEw2OS4wNywxMDQuMzQ3IFogTTY1LjY2NSwxMDEuOTc1IEM2NS43NTQsMTAxLjk3NSA2NS44NDIsMTAxLjk3NyA2NS45MywxMDEuOTgxIEM2Ny4xOTYsMTAyLjAzNyA2OC4yODMsMTAyLjQ2OSA2OC44MzgsMTAzLjEzOSBDNjkuMDY1LDEwMy40MTMgNjkuMTg4LDEwMy43MTQgNjkuMTk4LDEwNC4wMjEgTDE0Ny44ODMsNTguNTkyIEMxNDcuODQ3LDU4LjU5MiAxNDcuODExLDU4LjU5MSAxNDcuNzc2LDU4LjU4OSBDMTQ2LjUwOSw1OC41MzMgMTQ1LjQyMiw1OC4xIDE0NC44NjcsNTcuNDMxIEMxNDQuNTg1LDU3LjA5MSAxNDQuNDY1LDU2LjcwNyAxNDQuNTIsNTYuMzI0IEMxNDQuNTYzLDU2LjAyMSAxNDQuNTUyLDU1LjcxNiAxNDQuNDg4LDU1LjQxNCBMNjMuODQ2LDEwMS45NyBDNjQuMzUzLDEwMi4wMDIgNjQuODY3LDEwMi4wMDYgNjUuMzc0LDEwMS45ODIgQzY1LjQ3MSwxMDEuOTc3IDY1LjU2OCwxMDEuOTc1IDY1LjY2NSwxMDEuOTc1IEw2NS42NjUsMTAxLjk3NSBaIiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTIuMjA4LDU1LjEzNCBDMS4yMDcsNTMuMzA3IDEuOTY3LDUwLjkxNyAzLjkwNiw0OS43OTcgTDU5LjkxNywxNy40NTMgQzYxLjg1NiwxNi4zMzMgNjQuMjQxLDE2LjkwNyA2NS4yNDMsMTguNzM0IEw2NS40NzUsMTkuMTQ0IEM2NS44NzIsMTkuODgyIDY2LjM2OCwyMC41NiA2Ni45NDUsMjEuMTY1IEw2Ny4yMjMsMjEuNDM1IEM3MC41NDgsMjQuNjQ5IDc1LjgwNiwyNS4xNTEgODAuMTExLDIyLjY2NSBMODcuNDMsMTguNDQ1IEM4OS4zNywxNy4zMjYgOTEuNzU0LDE3Ljg5OSA5Mi43NTUsMTkuNzI3IEw5Ni4wMDUsMjUuNjU1IEwxMi40ODYsNzMuODg0IEwyLjIwOCw1NS4xMzQgWiIgaWQ9IkZpbGwtNiIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMi40ODYsNzQuMDAxIEMxMi40NzYsNzQuMDAxIDEyLjQ2NSw3My45OTkgMTIuNDU1LDczLjk5NiBDMTIuNDI0LDczLjk4OCAxMi4zOTksNzMuOTY3IDEyLjM4NCw3My45NCBMMi4xMDYsNTUuMTkgQzEuMDc1LDUzLjMxIDEuODU3LDUwLjg0NSAzLjg0OCw0OS42OTYgTDU5Ljg1OCwxNy4zNTIgQzYwLjUyNSwxNi45NjcgNjEuMjcxLDE2Ljc2NCA2Mi4wMTYsMTYuNzY0IEM2My40MzEsMTYuNzY0IDY0LjY2NiwxNy40NjYgNjUuMzI3LDE4LjY0NiBDNjUuMzM3LDE4LjY1NCA2NS4zNDUsMTguNjYzIDY1LjM1MSwxOC42NzQgTDY1LjU3OCwxOS4wODggQzY1LjU4NCwxOS4xIDY1LjU4OSwxOS4xMTIgNjUuNTkxLDE5LjEyNiBDNjUuOTg1LDE5LjgzOCA2Ni40NjksMjAuNDk3IDY3LjAzLDIxLjA4NSBMNjcuMzA1LDIxLjM1MSBDNjkuMTUxLDIzLjEzNyA3MS42NDksMjQuMTIgNzQuMzM2LDI0LjEyIEM3Ni4zMTMsMjQuMTIgNzguMjksMjMuNTgyIDgwLjA1MywyMi41NjMgQzgwLjA2NCwyMi41NTcgODAuMDc2LDIyLjU1MyA4MC4wODgsMjIuNTUgTDg3LjM3MiwxOC4zNDQgQzg4LjAzOCwxNy45NTkgODguNzg0LDE3Ljc1NiA4OS41MjksMTcuNzU2IEM5MC45NTYsMTcuNzU2IDkyLjIwMSwxOC40NzIgOTIuODU4LDE5LjY3IEw5Ni4xMDcsMjUuNTk5IEM5Ni4xMzgsMjUuNjU0IDk2LjExOCwyNS43MjQgOTYuMDYzLDI1Ljc1NiBMMTIuNTQ1LDczLjk4NSBDMTIuNTI2LDczLjk5NiAxMi41MDYsNzQuMDAxIDEyLjQ4Niw3NC4wMDEgTDEyLjQ4Niw3NC4wMDEgWiBNNjIuMDE2LDE2Ljk5NyBDNjEuMzEyLDE2Ljk5NyA2MC42MDYsMTcuMTkgNTkuOTc1LDE3LjU1NCBMMy45NjUsNDkuODk5IEMyLjA4Myw1MC45ODUgMS4zNDEsNTMuMzA4IDIuMzEsNTUuMDc4IEwxMi41MzEsNzMuNzIzIEw5NS44NDgsMjUuNjExIEw5Mi42NTMsMTkuNzgyIEM5Mi4wMzgsMTguNjYgOTAuODcsMTcuOTkgODkuNTI5LDE3Ljk5IEM4OC44MjUsMTcuOTkgODguMTE5LDE4LjE4MiA4Ny40ODksMTguNTQ3IEw4MC4xNzIsMjIuNzcyIEM4MC4xNjEsMjIuNzc4IDgwLjE0OSwyMi43ODIgODAuMTM3LDIyLjc4NSBDNzguMzQ2LDIzLjgxMSA3Ni4zNDEsMjQuMzU0IDc0LjMzNiwyNC4zNTQgQzcxLjU4OCwyNC4zNTQgNjkuMDMzLDIzLjM0NyA2Ny4xNDIsMjEuNTE5IEw2Ni44NjQsMjEuMjQ5IEM2Ni4yNzcsMjAuNjM0IDY1Ljc3NCwxOS45NDcgNjUuMzY3LDE5LjIwMyBDNjUuMzYsMTkuMTkyIDY1LjM1NiwxOS4xNzkgNjUuMzU0LDE5LjE2NiBMNjUuMTYzLDE4LjgxOSBDNjUuMTU0LDE4LjgxMSA2NS4xNDYsMTguODAxIDY1LjE0LDE4Ljc5IEM2NC41MjUsMTcuNjY3IDYzLjM1NywxNi45OTcgNjIuMDE2LDE2Ljk5NyBMNjIuMDE2LDE2Ljk5NyBaIiBpZD0iRmlsbC03IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTQyLjQzNCw0OC44MDggTDQyLjQzNCw0OC44MDggQzM5LjkyNCw0OC44MDcgMzcuNzM3LDQ3LjU1IDM2LjU4Miw0NS40NDMgQzM0Ljc3MSw0Mi4xMzkgMzYuMTQ0LDM3LjgwOSAzOS42NDEsMzUuNzg5IEw1MS45MzIsMjguNjkxIEM1My4xMDMsMjguMDE1IDU0LjQxMywyNy42NTggNTUuNzIxLDI3LjY1OCBDNTguMjMxLDI3LjY1OCA2MC40MTgsMjguOTE2IDYxLjU3MywzMS4wMjMgQzYzLjM4NCwzNC4zMjcgNjIuMDEyLDM4LjY1NyA1OC41MTQsNDAuNjc3IEw0Ni4yMjMsNDcuNzc1IEM0NS4wNTMsNDguNDUgNDMuNzQyLDQ4LjgwOCA0Mi40MzQsNDguODA4IEw0Mi40MzQsNDguODA4IFogTTU1LjcyMSwyOC4xMjUgQzU0LjQ5NSwyOC4xMjUgNTMuMjY1LDI4LjQ2MSA1Mi4xNjYsMjkuMDk2IEwzOS44NzUsMzYuMTk0IEMzNi41OTYsMzguMDg3IDM1LjMwMiw0Mi4xMzYgMzYuOTkyLDQ1LjIxOCBDMzguMDYzLDQ3LjE3MyA0MC4wOTgsNDguMzQgNDIuNDM0LDQ4LjM0IEM0My42NjEsNDguMzQgNDQuODksNDguMDA1IDQ1Ljk5LDQ3LjM3IEw1OC4yODEsNDAuMjcyIEM2MS41NiwzOC4zNzkgNjIuODUzLDM0LjMzIDYxLjE2NCwzMS4yNDggQzYwLjA5MiwyOS4yOTMgNTguMDU4LDI4LjEyNSA1NS43MjEsMjguMTI1IEw1NS43MjEsMjguMTI1IFoiIGlkPSJGaWxsLTgiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjU4OCwyLjQwNyBDMTQ5LjU4OCwyLjQwNyAxNTUuNzY4LDUuOTc1IDE1Ni4zMjUsNi4yOTcgTDE1Ni4zMjUsNy4xODQgQzE1Ni4zMjUsNy4zNiAxNTYuMzM4LDcuNTQ0IDE1Ni4zNjIsNy43MzMgQzE1Ni4zNzMsNy44MTQgMTU2LjM4Miw3Ljg5NCAxNTYuMzksNy45NzUgQzE1Ni41Myw5LjM5IDE1Ny4zNjMsMTAuOTczIDE1OC40OTUsMTEuOTc0IEwxNjUuODkxLDE4LjUxOSBDMTY2LjA2OCwxOC42NzUgMTY2LjI0OSwxOC44MTQgMTY2LjQzMiwxOC45MzQgQzE2OC4wMTEsMTkuOTc0IDE2OS4zODIsMTkuNCAxNjkuNDk0LDE3LjY1MiBDMTY5LjU0MywxNi44NjggMTY5LjU1MSwxNi4wNTcgMTY5LjUxNywxNS4yMjMgTDE2OS41MTQsMTUuMDYzIEwxNjkuNTE0LDEzLjkxMiBDMTcwLjc4LDE0LjY0MiAxOTUuNTAxLDI4LjkxNSAxOTUuNTAxLDI4LjkxNSBMMTk1LjUwMSw4Mi45MTUgQzE5NS41MDEsODQuMDA1IDE5NC43MzEsODQuNDQ1IDE5My43ODEsODMuODk3IEwxNTEuMzA4LDU5LjM3NCBDMTUwLjM1OCw1OC44MjYgMTQ5LjU4OCw1Ny40OTcgMTQ5LjU4OCw1Ni40MDggTDE0OS41ODgsMjIuMzc1IiBpZD0iRmlsbC05IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE5NC41NTMsODQuMjUgQzE5NC4yOTYsODQuMjUgMTk0LjAxMyw4NC4xNjUgMTkzLjcyMiw4My45OTcgTDE1MS4yNSw1OS40NzYgQzE1MC4yNjksNTguOTA5IDE0OS40NzEsNTcuNTMzIDE0OS40NzEsNTYuNDA4IEwxNDkuNDcxLDIyLjM3NSBMMTQ5LjcwNSwyMi4zNzUgTDE0OS43MDUsNTYuNDA4IEMxNDkuNzA1LDU3LjQ1OSAxNTAuNDUsNTguNzQ0IDE1MS4zNjYsNTkuMjc0IEwxOTMuODM5LDgzLjc5NSBDMTk0LjI2Myw4NC4wNCAxOTQuNjU1LDg0LjA4MyAxOTQuOTQyLDgzLjkxNyBDMTk1LjIyNyw4My43NTMgMTk1LjM4NCw4My4zOTcgMTk1LjM4NCw4Mi45MTUgTDE5NS4zODQsMjguOTgyIEMxOTQuMTAyLDI4LjI0MiAxNzIuMTA0LDE1LjU0MiAxNjkuNjMxLDE0LjExNCBMMTY5LjYzNCwxNS4yMiBDMTY5LjY2OCwxNi4wNTIgMTY5LjY2LDE2Ljg3NCAxNjkuNjEsMTcuNjU5IEMxNjkuNTU2LDE4LjUwMyAxNjkuMjE0LDE5LjEyMyAxNjguNjQ3LDE5LjQwNSBDMTY4LjAyOCwxOS43MTQgMTY3LjE5NywxOS41NzggMTY2LjM2NywxOS4wMzIgQzE2Ni4xODEsMTguOTA5IDE2NS45OTUsMTguNzY2IDE2NS44MTQsMTguNjA2IEwxNTguNDE3LDEyLjA2MiBDMTU3LjI1OSwxMS4wMzYgMTU2LjQxOCw5LjQzNyAxNTYuMjc0LDcuOTg2IEMxNTYuMjY2LDcuOTA3IDE1Ni4yNTcsNy44MjcgMTU2LjI0Nyw3Ljc0OCBDMTU2LjIyMSw3LjU1NSAxNTYuMjA5LDcuMzY1IDE1Ni4yMDksNy4xODQgTDE1Ni4yMDksNi4zNjQgQzE1NS4zNzUsNS44ODMgMTQ5LjUyOSwyLjUwOCAxNDkuNTI5LDIuNTA4IEwxNDkuNjQ2LDIuMzA2IEMxNDkuNjQ2LDIuMzA2IDE1NS44MjcsNS44NzQgMTU2LjM4NCw2LjE5NiBMMTU2LjQ0Miw2LjIzIEwxNTYuNDQyLDcuMTg0IEMxNTYuNDQyLDcuMzU1IDE1Ni40NTQsNy41MzUgMTU2LjQ3OCw3LjcxNyBDMTU2LjQ4OSw3LjggMTU2LjQ5OSw3Ljg4MiAxNTYuNTA3LDcuOTYzIEMxNTYuNjQ1LDkuMzU4IDE1Ny40NTUsMTAuODk4IDE1OC41NzIsMTEuODg2IEwxNjUuOTY5LDE4LjQzMSBDMTY2LjE0MiwxOC41ODQgMTY2LjMxOSwxOC43MiAxNjYuNDk2LDE4LjgzNyBDMTY3LjI1NCwxOS4zMzYgMTY4LDE5LjQ2NyAxNjguNTQzLDE5LjE5NiBDMTY5LjAzMywxOC45NTMgMTY5LjMyOSwxOC40MDEgMTY5LjM3NywxNy42NDUgQzE2OS40MjcsMTYuODY3IDE2OS40MzQsMTYuMDU0IDE2OS40MDEsMTUuMjI4IEwxNjkuMzk3LDE1LjA2NSBMMTY5LjM5NywxMy43MSBMMTY5LjU3MiwxMy44MSBDMTcwLjgzOSwxNC41NDEgMTk1LjU1OSwyOC44MTQgMTk1LjU1OSwyOC44MTQgTDE5NS42MTgsMjguODQ3IEwxOTUuNjE4LDgyLjkxNSBDMTk1LjYxOCw4My40ODQgMTk1LjQyLDgzLjkxMSAxOTUuMDU5LDg0LjExOSBDMTk0LjkwOCw4NC4yMDYgMTk0LjczNyw4NC4yNSAxOTQuNTUzLDg0LjI1IiBpZD0iRmlsbC0xMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDUuNjg1LDU2LjE2MSBMMTY5LjgsNzAuMDgzIEwxNDMuODIyLDg1LjA4MSBMMTQyLjM2LDg0Ljc3NCBDMTM1LjgyNiw4Mi42MDQgMTI4LjczMiw4MS4wNDYgMTIxLjM0MSw4MC4xNTggQzExNi45NzYsNzkuNjM0IDExMi42NzgsODEuMjU0IDExMS43NDMsODMuNzc4IEMxMTEuNTA2LDg0LjQxNCAxMTEuNTAzLDg1LjA3MSAxMTEuNzMyLDg1LjcwNiBDMTEzLjI3LDg5Ljk3MyAxMTUuOTY4LDk0LjA2OSAxMTkuNzI3LDk3Ljg0MSBMMTIwLjI1OSw5OC42ODYgQzEyMC4yNiw5OC42ODUgOTQuMjgyLDExMy42ODMgOTQuMjgyLDExMy42ODMgTDcwLjE2Nyw5OS43NjEgTDE0NS42ODUsNTYuMTYxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik05NC4yODIsMTEzLjgxOCBMOTQuMjIzLDExMy43ODUgTDY5LjkzMyw5OS43NjEgTDcwLjEwOCw5OS42NiBMMTQ1LjY4NSw1Ni4wMjYgTDE0NS43NDMsNTYuMDU5IEwxNzAuMDMzLDcwLjA4MyBMMTQzLjg0Miw4NS4yMDUgTDE0My43OTcsODUuMTk1IEMxNDMuNzcyLDg1LjE5IDE0Mi4zMzYsODQuODg4IDE0Mi4zMzYsODQuODg4IEMxMzUuNzg3LDgyLjcxNCAxMjguNzIzLDgxLjE2MyAxMjEuMzI3LDgwLjI3NCBDMTIwLjc4OCw4MC4yMDkgMTIwLjIzNiw4MC4xNzcgMTE5LjY4OSw4MC4xNzcgQzExNS45MzEsODAuMTc3IDExMi42MzUsODEuNzA4IDExMS44NTIsODMuODE5IEMxMTEuNjI0LDg0LjQzMiAxMTEuNjIxLDg1LjA1MyAxMTEuODQyLDg1LjY2NyBDMTEzLjM3Nyw4OS45MjUgMTE2LjA1OCw5My45OTMgMTE5LjgxLDk3Ljc1OCBMMTE5LjgyNiw5Ny43NzkgTDEyMC4zNTIsOTguNjE0IEMxMjAuMzU0LDk4LjYxNyAxMjAuMzU2LDk4LjYyIDEyMC4zNTgsOTguNjI0IEwxMjAuNDIyLDk4LjcyNiBMMTIwLjMxNyw5OC43ODcgQzEyMC4yNjQsOTguODE4IDk0LjU5OSwxMTMuNjM1IDk0LjM0LDExMy43ODUgTDk0LjI4MiwxMTMuODE4IEw5NC4yODIsMTEzLjgxOCBaIE03MC40MDEsOTkuNzYxIEw5NC4yODIsMTEzLjU0OSBMMTE5LjA4NCw5OS4yMjkgQzExOS42Myw5OC45MTQgMTE5LjkzLDk4Ljc0IDEyMC4xMDEsOTguNjU0IEwxMTkuNjM1LDk3LjkxNCBDMTE1Ljg2NCw5NC4xMjcgMTEzLjE2OCw5MC4wMzMgMTExLjYyMiw4NS43NDYgQzExMS4zODIsODUuMDc5IDExMS4zODYsODQuNDA0IDExMS42MzMsODMuNzM4IEMxMTIuNDQ4LDgxLjUzOSAxMTUuODM2LDc5Ljk0MyAxMTkuNjg5LDc5Ljk0MyBDMTIwLjI0Niw3OS45NDMgMTIwLjgwNiw3OS45NzYgMTIxLjM1NSw4MC4wNDIgQzEyOC43NjcsODAuOTMzIDEzNS44NDYsODIuNDg3IDE0Mi4zOTYsODQuNjYzIEMxNDMuMjMyLDg0LjgzOCAxNDMuNjExLDg0LjkxNyAxNDMuNzg2LDg0Ljk2NyBMMTY5LjU2Niw3MC4wODMgTDE0NS42ODUsNTYuMjk1IEw3MC40MDEsOTkuNzYxIEw3MC40MDEsOTkuNzYxIFoiIGlkPSJGaWxsLTEyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2Ny4yMywxOC45NzkgTDE2Ny4yMyw2OS44NSBMMTM5LjkwOSw4NS42MjMgTDEzMy40NDgsNzEuNDU2IEMxMzIuNTM4LDY5LjQ2IDEzMC4wMiw2OS43MTggMTI3LjgyNCw3Mi4wMyBDMTI2Ljc2OSw3My4xNCAxMjUuOTMxLDc0LjU4NSAxMjUuNDk0LDc2LjA0OCBMMTE5LjAzNCw5Ny42NzYgTDkxLjcxMiwxMTMuNDUgTDkxLjcxMiw2Mi41NzkgTDE2Ny4yMywxOC45NzkiIGlkPSJGaWxsLTEzIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTkxLjcxMiwxMTMuNTY3IEM5MS42OTIsMTEzLjU2NyA5MS42NzIsMTEzLjU2MSA5MS42NTMsMTEzLjU1MSBDOTEuNjE4LDExMy41MyA5MS41OTUsMTEzLjQ5MiA5MS41OTUsMTEzLjQ1IEw5MS41OTUsNjIuNTc5IEM5MS41OTUsNjIuNTM3IDkxLjYxOCw2Mi40OTkgOTEuNjUzLDYyLjQ3OCBMMTY3LjE3MiwxOC44NzggQzE2Ny4yMDgsMTguODU3IDE2Ny4yNTIsMTguODU3IDE2Ny4yODgsMTguODc4IEMxNjcuMzI0LDE4Ljg5OSAxNjcuMzQ3LDE4LjkzNyAxNjcuMzQ3LDE4Ljk3OSBMMTY3LjM0Nyw2OS44NSBDMTY3LjM0Nyw2OS44OTEgMTY3LjMyNCw2OS45MyAxNjcuMjg4LDY5Ljk1IEwxMzkuOTY3LDg1LjcyNSBDMTM5LjkzOSw4NS43NDEgMTM5LjkwNSw4NS43NDUgMTM5Ljg3Myw4NS43MzUgQzEzOS44NDIsODUuNzI1IDEzOS44MTYsODUuNzAyIDEzOS44MDIsODUuNjcyIEwxMzMuMzQyLDcxLjUwNCBDMTMyLjk2Nyw3MC42ODIgMTMyLjI4LDcwLjIyOSAxMzEuNDA4LDcwLjIyOSBDMTMwLjMxOSw3MC4yMjkgMTI5LjA0NCw3MC45MTUgMTI3LjkwOCw3Mi4xMSBDMTI2Ljg3NCw3My4yIDEyNi4wMzQsNzQuNjQ3IDEyNS42MDYsNzYuMDgyIEwxMTkuMTQ2LDk3LjcwOSBDMTE5LjEzNyw5Ny43MzggMTE5LjExOCw5Ny43NjIgMTE5LjA5Miw5Ny43NzcgTDkxLjc3LDExMy41NTEgQzkxLjc1MiwxMTMuNTYxIDkxLjczMiwxMTMuNTY3IDkxLjcxMiwxMTMuNTY3IEw5MS43MTIsMTEzLjU2NyBaIE05MS44MjksNjIuNjQ3IEw5MS44MjksMTEzLjI0OCBMMTE4LjkzNSw5Ny41OTggTDEyNS4zODIsNzYuMDE1IEMxMjUuODI3LDc0LjUyNSAxMjYuNjY0LDczLjA4MSAxMjcuNzM5LDcxLjk1IEMxMjguOTE5LDcwLjcwOCAxMzAuMjU2LDY5Ljk5NiAxMzEuNDA4LDY5Ljk5NiBDMTMyLjM3Nyw2OS45OTYgMTMzLjEzOSw3MC40OTcgMTMzLjU1NCw3MS40MDcgTDEzOS45NjEsODUuNDU4IEwxNjcuMTEzLDY5Ljc4MiBMMTY3LjExMywxOS4xODEgTDkxLjgyOSw2Mi42NDcgTDkxLjgyOSw2Mi42NDcgWiIgaWQ9IkZpbGwtMTQiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTY4LjU0MywxOS4yMTMgTDE2OC41NDMsNzAuMDgzIEwxNDEuMjIxLDg1Ljg1NyBMMTM0Ljc2MSw3MS42ODkgQzEzMy44NTEsNjkuNjk0IDEzMS4zMzMsNjkuOTUxIDEyOS4xMzcsNzIuMjYzIEMxMjguMDgyLDczLjM3NCAxMjcuMjQ0LDc0LjgxOSAxMjYuODA3LDc2LjI4MiBMMTIwLjM0Niw5Ny45MDkgTDkzLjAyNSwxMTMuNjgzIEw5My4wMjUsNjIuODEzIEwxNjguNTQzLDE5LjIxMyIgaWQ9IkZpbGwtMTUiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTMuMDI1LDExMy44IEM5My4wMDUsMTEzLjggOTIuOTg0LDExMy43OTUgOTIuOTY2LDExMy43ODUgQzkyLjkzMSwxMTMuNzY0IDkyLjkwOCwxMTMuNzI1IDkyLjkwOCwxMTMuNjg0IEw5Mi45MDgsNjIuODEzIEM5Mi45MDgsNjIuNzcxIDkyLjkzMSw2Mi43MzMgOTIuOTY2LDYyLjcxMiBMMTY4LjQ4NCwxOS4xMTIgQzE2OC41MiwxOS4wOSAxNjguNTY1LDE5LjA5IDE2OC42MDEsMTkuMTEyIEMxNjguNjM3LDE5LjEzMiAxNjguNjYsMTkuMTcxIDE2OC42NiwxOS4yMTIgTDE2OC42Niw3MC4wODMgQzE2OC42Niw3MC4xMjUgMTY4LjYzNyw3MC4xNjQgMTY4LjYwMSw3MC4xODQgTDE0MS4yOCw4NS45NTggQzE0MS4yNTEsODUuOTc1IDE0MS4yMTcsODUuOTc5IDE0MS4xODYsODUuOTY4IEMxNDEuMTU0LDg1Ljk1OCAxNDEuMTI5LDg1LjkzNiAxNDEuMTE1LDg1LjkwNiBMMTM0LjY1NSw3MS43MzggQzEzNC4yOCw3MC45MTUgMTMzLjU5Myw3MC40NjMgMTMyLjcyLDcwLjQ2MyBDMTMxLjYzMiw3MC40NjMgMTMwLjM1Nyw3MS4xNDggMTI5LjIyMSw3Mi4zNDQgQzEyOC4xODYsNzMuNDMzIDEyNy4zNDcsNzQuODgxIDEyNi45MTksNzYuMzE1IEwxMjAuNDU4LDk3Ljk0MyBDMTIwLjQ1LDk3Ljk3MiAxMjAuNDMxLDk3Ljk5NiAxMjAuNDA1LDk4LjAxIEw5My4wODMsMTEzLjc4NSBDOTMuMDY1LDExMy43OTUgOTMuMDQ1LDExMy44IDkzLjAyNSwxMTMuOCBMOTMuMDI1LDExMy44IFogTTkzLjE0Miw2Mi44ODEgTDkzLjE0MiwxMTMuNDgxIEwxMjAuMjQ4LDk3LjgzMiBMMTI2LjY5NSw3Ni4yNDggQzEyNy4xNCw3NC43NTggMTI3Ljk3Nyw3My4zMTUgMTI5LjA1Miw3Mi4xODMgQzEzMC4yMzEsNzAuOTQyIDEzMS41NjgsNzAuMjI5IDEzMi43Miw3MC4yMjkgQzEzMy42ODksNzAuMjI5IDEzNC40NTIsNzAuNzMxIDEzNC44NjcsNzEuNjQxIEwxNDEuMjc0LDg1LjY5MiBMMTY4LjQyNiw3MC4wMTYgTDE2OC40MjYsMTkuNDE1IEw5My4xNDIsNjIuODgxIEw5My4xNDIsNjIuODgxIFoiIGlkPSJGaWxsLTE2IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS44LDcwLjA4MyBMMTQyLjQ3OCw4NS44NTcgTDEzNi4wMTgsNzEuNjg5IEMxMzUuMTA4LDY5LjY5NCAxMzIuNTksNjkuOTUxIDEzMC4zOTMsNzIuMjYzIEMxMjkuMzM5LDczLjM3NCAxMjguNSw3NC44MTkgMTI4LjA2NCw3Ni4yODIgTDEyMS42MDMsOTcuOTA5IEw5NC4yODIsMTEzLjY4MyBMOTQuMjgyLDYyLjgxMyBMMTY5LjgsMTkuMjEzIEwxNjkuOCw3MC4wODMgWiIgaWQ9IkZpbGwtMTciIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTQuMjgyLDExMy45MTcgQzk0LjI0MSwxMTMuOTE3IDk0LjIwMSwxMTMuOTA3IDk0LjE2NSwxMTMuODg2IEM5NC4wOTMsMTEzLjg0NSA5NC4wNDgsMTEzLjc2NyA5NC4wNDgsMTEzLjY4NCBMOTQuMDQ4LDYyLjgxMyBDOTQuMDQ4LDYyLjczIDk0LjA5Myw2Mi42NTIgOTQuMTY1LDYyLjYxMSBMMTY5LjY4MywxOS4wMSBDMTY5Ljc1NSwxOC45NjkgMTY5Ljg0NCwxOC45NjkgMTY5LjkxNywxOS4wMSBDMTY5Ljk4OSwxOS4wNTIgMTcwLjAzMywxOS4xMjkgMTcwLjAzMywxOS4yMTIgTDE3MC4wMzMsNzAuMDgzIEMxNzAuMDMzLDcwLjE2NiAxNjkuOTg5LDcwLjI0NCAxNjkuOTE3LDcwLjI4NSBMMTQyLjU5NSw4Ni4wNiBDMTQyLjUzOCw4Ni4wOTIgMTQyLjQ2OSw4Ni4xIDE0Mi40MDcsODYuMDggQzE0Mi4zNDQsODYuMDYgMTQyLjI5Myw4Ni4wMTQgMTQyLjI2Niw4NS45NTQgTDEzNS44MDUsNzEuNzg2IEMxMzUuNDQ1LDcwLjk5NyAxMzQuODEzLDcwLjU4IDEzMy45NzcsNzAuNTggQzEzMi45MjEsNzAuNTggMTMxLjY3Niw3MS4yNTIgMTMwLjU2Miw3Mi40MjQgQzEyOS41NCw3My41MDEgMTI4LjcxMSw3NC45MzEgMTI4LjI4Nyw3Ni4zNDggTDEyMS44MjcsOTcuOTc2IEMxMjEuODEsOTguMDM0IDEyMS43NzEsOTguMDgyIDEyMS43Miw5OC4xMTIgTDk0LjM5OCwxMTMuODg2IEM5NC4zNjIsMTEzLjkwNyA5NC4zMjIsMTEzLjkxNyA5NC4yODIsMTEzLjkxNyBMOTQuMjgyLDExMy45MTcgWiBNOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDExMy4yNzkgTDEyMS40MDYsOTcuNzU0IEwxMjcuODQsNzYuMjE1IEMxMjguMjksNzQuNzA4IDEyOS4xMzcsNzMuMjQ3IDEzMC4yMjQsNzIuMTAzIEMxMzEuNDI1LDcwLjgzOCAxMzIuNzkzLDcwLjExMiAxMzMuOTc3LDcwLjExMiBDMTM0Ljk5NSw3MC4xMTIgMTM1Ljc5NSw3MC42MzggMTM2LjIzLDcxLjU5MiBMMTQyLjU4NCw4NS41MjYgTDE2OS41NjYsNjkuOTQ4IEwxNjkuNTY2LDE5LjYxNyBMOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDYyLjk0OCBaIiBpZD0iRmlsbC0xOCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMDkuODk0LDkyLjk0MyBMMTA5Ljg5NCw5Mi45NDMgQzEwOC4xMiw5Mi45NDMgMTA2LjY1Myw5Mi4yMTggMTA1LjY1LDkwLjgyMyBDMTA1LjU4Myw5MC43MzEgMTA1LjU5Myw5MC42MSAxMDUuNjczLDkwLjUyOSBDMTA1Ljc1Myw5MC40NDggMTA1Ljg4LDkwLjQ0IDEwNS45NzQsOTAuNTA2IEMxMDYuNzU0LDkxLjA1MyAxMDcuNjc5LDkxLjMzMyAxMDguNzI0LDkxLjMzMyBDMTEwLjA0Nyw5MS4zMzMgMTExLjQ3OCw5MC44OTQgMTEyLjk4LDkwLjAyNyBDMTE4LjI5MSw4Ni45NiAxMjIuNjExLDc5LjUwOSAxMjIuNjExLDczLjQxNiBDMTIyLjYxMSw3MS40ODkgMTIyLjE2OSw2OS44NTYgMTIxLjMzMyw2OC42OTIgQzEyMS4yNjYsNjguNiAxMjEuMjc2LDY4LjQ3MyAxMjEuMzU2LDY4LjM5MiBDMTIxLjQzNiw2OC4zMTEgMTIxLjU2Myw2OC4yOTkgMTIxLjY1Niw2OC4zNjUgQzEyMy4zMjcsNjkuNTM3IDEyNC4yNDcsNzEuNzQ2IDEyNC4yNDcsNzQuNTg0IEMxMjQuMjQ3LDgwLjgyNiAxMTkuODIxLDg4LjQ0NyAxMTQuMzgyLDkxLjU4NyBDMTEyLjgwOCw5Mi40OTUgMTExLjI5OCw5Mi45NDMgMTA5Ljg5NCw5Mi45NDMgTDEwOS44OTQsOTIuOTQzIFogTTEwNi45MjUsOTEuNDAxIEMxMDcuNzM4LDkyLjA1MiAxMDguNzQ1LDkyLjI3OCAxMDkuODkzLDkyLjI3OCBMMTA5Ljg5NCw5Mi4yNzggQzExMS4yMTUsOTIuMjc4IDExMi42NDcsOTEuOTUxIDExNC4xNDgsOTEuMDg0IEMxMTkuNDU5LDg4LjAxNyAxMjMuNzgsODAuNjIxIDEyMy43OCw3NC41MjggQzEyMy43OCw3Mi41NDkgMTIzLjMxNyw3MC45MjkgMTIyLjQ1NCw2OS43NjcgQzEyMi44NjUsNzAuODAyIDEyMy4wNzksNzIuMDQyIDEyMy4wNzksNzMuNDAyIEMxMjMuMDc5LDc5LjY0NSAxMTguNjUzLDg3LjI4NSAxMTMuMjE0LDkwLjQyNSBDMTExLjY0LDkxLjMzNCAxMTAuMTMsOTEuNzQyIDEwOC43MjQsOTEuNzQyIEMxMDguMDgzLDkxLjc0MiAxMDcuNDgxLDkxLjU5MyAxMDYuOTI1LDkxLjQwMSBMMTA2LjkyNSw5MS40MDEgWiIgaWQ9IkZpbGwtMTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjA5Nyw5MC4yMyBDMTE4LjQ4MSw4Ny4xMjIgMTIyLjg0NSw3OS41OTQgMTIyLjg0NSw3My40MTYgQzEyMi44NDUsNzEuMzY1IDEyMi4zNjIsNjkuNzI0IDEyMS41MjIsNjguNTU2IEMxMTkuNzM4LDY3LjMwNCAxMTcuMTQ4LDY3LjM2MiAxMTQuMjY1LDY5LjAyNiBDMTA4Ljg4MSw3Mi4xMzQgMTA0LjUxNyw3OS42NjIgMTA0LjUxNyw4NS44NCBDMTA0LjUxNyw4Ny44OTEgMTA1LDg5LjUzMiAxMDUuODQsOTAuNyBDMTA3LjYyNCw5MS45NTIgMTEwLjIxNCw5MS44OTQgMTEzLjA5Nyw5MC4yMyIgaWQ9IkZpbGwtMjAiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTA4LjcyNCw5MS42MTQgTDEwOC43MjQsOTEuNjE0IEMxMDcuNTgyLDkxLjYxNCAxMDYuNTY2LDkxLjQwMSAxMDUuNzA1LDkwLjc5NyBDMTA1LjY4NCw5MC43ODMgMTA1LjY2NSw5MC44MTEgMTA1LjY1LDkwLjc5IEMxMDQuNzU2LDg5LjU0NiAxMDQuMjgzLDg3Ljg0MiAxMDQuMjgzLDg1LjgxNyBDMTA0LjI4Myw3OS41NzUgMTA4LjcwOSw3MS45NTMgMTE0LjE0OCw2OC44MTIgQzExNS43MjIsNjcuOTA0IDExNy4yMzIsNjcuNDQ5IDExOC42MzgsNjcuNDQ5IEMxMTkuNzgsNjcuNDQ5IDEyMC43OTYsNjcuNzU4IDEyMS42NTYsNjguMzYyIEMxMjEuNjc4LDY4LjM3NyAxMjEuNjk3LDY4LjM5NyAxMjEuNzEyLDY4LjQxOCBDMTIyLjYwNiw2OS42NjIgMTIzLjA3OSw3MS4zOSAxMjMuMDc5LDczLjQxNSBDMTIzLjA3OSw3OS42NTggMTE4LjY1Myw4Ny4xOTggMTEzLjIxNCw5MC4zMzggQzExMS42NCw5MS4yNDcgMTEwLjEzLDkxLjYxNCAxMDguNzI0LDkxLjYxNCBMMTA4LjcyNCw5MS42MTQgWiBNMTA2LjAwNiw5MC41MDUgQzEwNi43OCw5MS4wMzcgMTA3LjY5NCw5MS4yODEgMTA4LjcyNCw5MS4yODEgQzExMC4wNDcsOTEuMjgxIDExMS40NzgsOTAuODY4IDExMi45OCw5MC4wMDEgQzExOC4yOTEsODYuOTM1IDEyMi42MTEsNzkuNDk2IDEyMi42MTEsNzMuNDAzIEMxMjIuNjExLDcxLjQ5NCAxMjIuMTc3LDY5Ljg4IDEyMS4zNTYsNjguNzE4IEMxMjAuNTgyLDY4LjE4NSAxMTkuNjY4LDY3LjkxOSAxMTguNjM4LDY3LjkxOSBDMTE3LjMxNSw2Ny45MTkgMTE1Ljg4Myw2OC4zNiAxMTQuMzgyLDY5LjIyNyBDMTA5LjA3MSw3Mi4yOTMgMTA0Ljc1MSw3OS43MzMgMTA0Ljc1MSw4NS44MjYgQzEwNC43NTEsODcuNzM1IDEwNS4xODUsODkuMzQzIDEwNi4wMDYsOTAuNTA1IEwxMDYuMDA2LDkwLjUwNSBaIiBpZD0iRmlsbC0yMSIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDkuMzE4LDcuMjYyIEwxMzkuMzM0LDE2LjE0IEwxNTUuMjI3LDI3LjE3MSBMMTYwLjgxNiwyMS4wNTkgTDE0OS4zMTgsNy4yNjIiIGlkPSJGaWxsLTIyIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS42NzYsMTMuODQgTDE1OS45MjgsMTkuNDY3IEMxNTYuMjg2LDIxLjU3IDE1MC40LDIxLjU4IDE0Ni43ODEsMTkuNDkxIEMxNDMuMTYxLDE3LjQwMiAxNDMuMTgsMTQuMDAzIDE0Ni44MjIsMTEuOSBMMTU2LjMxNyw2LjI5MiBMMTQ5LjU4OCwyLjQwNyBMNjcuNzUyLDQ5LjQ3OCBMMTEzLjY3NSw3NS45OTIgTDExNi43NTYsNzQuMjEzIEMxMTcuMzg3LDczLjg0OCAxMTcuNjI1LDczLjMxNSAxMTcuMzc0LDcyLjgyMyBDMTE1LjAxNyw2OC4xOTEgMTE0Ljc4MSw2My4yNzcgMTE2LjY5MSw1OC41NjEgQzEyMi4zMjksNDQuNjQxIDE0MS4yLDMzLjc0NiAxNjUuMzA5LDMwLjQ5MSBDMTczLjQ3OCwyOS4zODggMTgxLjk4OSwyOS41MjQgMTkwLjAxMywzMC44ODUgQzE5MC44NjUsMzEuMDMgMTkxLjc4OSwzMC44OTMgMTkyLjQyLDMwLjUyOCBMMTk1LjUwMSwyOC43NSBMMTY5LjY3NiwxMy44NCIgaWQ9IkZpbGwtMjMiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3Ni40NTkgQzExMy41OTQsNzYuNDU5IDExMy41MTQsNzYuNDM4IDExMy40NDIsNzYuMzk3IEw2Ny41MTgsNDkuODgyIEM2Ny4zNzQsNDkuNzk5IDY3LjI4NCw0OS42NDUgNjcuMjg1LDQ5LjQ3OCBDNjcuMjg1LDQ5LjMxMSA2Ny4zNzQsNDkuMTU3IDY3LjUxOSw0OS4wNzMgTDE0OS4zNTUsMi4wMDIgQzE0OS40OTksMS45MTkgMTQ5LjY3NywxLjkxOSAxNDkuODIxLDIuMDAyIEwxNTYuNTUsNS44ODcgQzE1Ni43NzQsNi4wMTcgMTU2Ljg1LDYuMzAyIDE1Ni43MjIsNi41MjYgQzE1Ni41OTIsNi43NDkgMTU2LjMwNyw2LjgyNiAxNTYuMDgzLDYuNjk2IEwxNDkuNTg3LDIuOTQ2IEw2OC42ODcsNDkuNDc5IEwxMTMuNjc1LDc1LjQ1MiBMMTE2LjUyMyw3My44MDggQzExNi43MTUsNzMuNjk3IDExNy4xNDMsNzMuMzk5IDExNi45NTgsNzMuMDM1IEMxMTQuNTQyLDY4LjI4NyAxMTQuMyw2My4yMjEgMTE2LjI1OCw1OC4zODUgQzExOS4wNjQsNTEuNDU4IDEyNS4xNDMsNDUuMTQzIDEzMy44NCw0MC4xMjIgQzE0Mi40OTcsMzUuMTI0IDE1My4zNTgsMzEuNjMzIDE2NS4yNDcsMzAuMDI4IEMxNzMuNDQ1LDI4LjkyMSAxODIuMDM3LDI5LjA1OCAxOTAuMDkxLDMwLjQyNSBDMTkwLjgzLDMwLjU1IDE5MS42NTIsMzAuNDMyIDE5Mi4xODYsMzAuMTI0IEwxOTQuNTY3LDI4Ljc1IEwxNjkuNDQyLDE0LjI0NCBDMTY5LjIxOSwxNC4xMTUgMTY5LjE0MiwxMy44MjkgMTY5LjI3MSwxMy42MDYgQzE2OS40LDEzLjM4MiAxNjkuNjg1LDEzLjMwNiAxNjkuOTA5LDEzLjQzNSBMMTk1LjczNCwyOC4zNDUgQzE5NS44NzksMjguNDI4IDE5NS45NjgsMjguNTgzIDE5NS45NjgsMjguNzUgQzE5NS45NjgsMjguOTE2IDE5NS44NzksMjkuMDcxIDE5NS43MzQsMjkuMTU0IEwxOTIuNjUzLDMwLjkzMyBDMTkxLjkzMiwzMS4zNSAxOTAuODksMzEuNTA4IDE4OS45MzUsMzEuMzQ2IEMxODEuOTcyLDI5Ljk5NSAxNzMuNDc4LDI5Ljg2IDE2NS4zNzIsMzAuOTU0IEMxNTMuNjAyLDMyLjU0MyAxNDIuODYsMzUuOTkzIDEzNC4zMDcsNDAuOTMxIEMxMjUuNzkzLDQ1Ljg0NyAxMTkuODUxLDUyLjAwNCAxMTcuMTI0LDU4LjczNiBDMTE1LjI3LDYzLjMxNCAxMTUuNTAxLDY4LjExMiAxMTcuNzksNzIuNjExIEMxMTguMTYsNzMuMzM2IDExNy44NDUsNzQuMTI0IDExNi45OSw3NC42MTcgTDExMy45MDksNzYuMzk3IEMxMTMuODM2LDc2LjQzOCAxMTMuNzU2LDc2LjQ1OSAxMTMuNjc1LDc2LjQ1OSIgaWQ9IkZpbGwtMjQiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUzLjMxNiwyMS4yNzkgQzE1MC45MDMsMjEuMjc5IDE0OC40OTUsMjAuNzUxIDE0Ni42NjQsMTkuNjkzIEMxNDQuODQ2LDE4LjY0NCAxNDMuODQ0LDE3LjIzMiAxNDMuODQ0LDE1LjcxOCBDMTQzLjg0NCwxNC4xOTEgMTQ0Ljg2LDEyLjc2MyAxNDYuNzA1LDExLjY5OCBMMTU2LjE5OCw2LjA5MSBDMTU2LjMwOSw2LjAyNSAxNTYuNDUyLDYuMDYyIDE1Ni41MTgsNi4xNzMgQzE1Ni41ODMsNi4yODQgMTU2LjU0Nyw2LjQyNyAxNTYuNDM2LDYuNDkzIEwxNDYuOTQsMTIuMTAyIEMxNDUuMjQ0LDEzLjA4MSAxNDQuMzEyLDE0LjM2NSAxNDQuMzEyLDE1LjcxOCBDMTQ0LjMxMiwxNy4wNTggMTQ1LjIzLDE4LjMyNiAxNDYuODk3LDE5LjI4OSBDMTUwLjQ0NiwyMS4zMzggMTU2LjI0LDIxLjMyNyAxNTkuODExLDE5LjI2NSBMMTY5LjU1OSwxMy42MzcgQzE2OS42NywxMy41NzMgMTY5LjgxMywxMy42MTEgMTY5Ljg3OCwxMy43MjMgQzE2OS45NDMsMTMuODM0IDE2OS45MDQsMTMuOTc3IDE2OS43OTMsMTQuMDQyIEwxNjAuMDQ1LDE5LjY3IEMxNTguMTg3LDIwLjc0MiAxNTUuNzQ5LDIxLjI3OSAxNTMuMzE2LDIxLjI3OSIgaWQ9IkZpbGwtMjUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3NS45OTIgTDY3Ljc2Miw0OS40ODQiIGlkPSJGaWxsLTI2IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMy42NzUsNzYuMzQyIEMxMTMuNjE1LDc2LjM0MiAxMTMuNTU1LDc2LjMyNyAxMTMuNSw3Ni4yOTUgTDY3LjU4Nyw0OS43ODcgQzY3LjQxOSw0OS42OSA2Ny4zNjIsNDkuNDc2IDY3LjQ1OSw0OS4zMDkgQzY3LjU1Niw0OS4xNDEgNjcuNzcsNDkuMDgzIDY3LjkzNyw0OS4xOCBMMTEzLjg1LDc1LjY4OCBDMTE0LjAxOCw3NS43ODUgMTE0LjA3NSw3NiAxMTMuOTc4LDc2LjE2NyBDMTEzLjkxNCw3Ni4yNzkgMTEzLjc5Niw3Ni4zNDIgMTEzLjY3NSw3Ni4zNDIiIGlkPSJGaWxsLTI3IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY3Ljc2Miw0OS40ODQgTDY3Ljc2MiwxMDMuNDg1IEM2Ny43NjIsMTA0LjU3NSA2OC41MzIsMTA1LjkwMyA2OS40ODIsMTA2LjQ1MiBMMTExLjk1NSwxMzAuOTczIEMxMTIuOTA1LDEzMS41MjIgMTEzLjY3NSwxMzEuMDgzIDExMy42NzUsMTI5Ljk5MyBMMTEzLjY3NSw3NS45OTIiIGlkPSJGaWxsLTI4IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMi43MjcsMTMxLjU2MSBDMTEyLjQzLDEzMS41NjEgMTEyLjEwNywxMzEuNDY2IDExMS43OCwxMzEuMjc2IEw2OS4zMDcsMTA2Ljc1NSBDNjguMjQ0LDEwNi4xNDIgNjcuNDEyLDEwNC43MDUgNjcuNDEyLDEwMy40ODUgTDY3LjQxMiw0OS40ODQgQzY3LjQxMiw0OS4yOSA2Ny41NjksNDkuMTM0IDY3Ljc2Miw0OS4xMzQgQzY3Ljk1Niw0OS4xMzQgNjguMTEzLDQ5LjI5IDY4LjExMyw0OS40ODQgTDY4LjExMywxMDMuNDg1IEM2OC4xMTMsMTA0LjQ0NSA2OC44MiwxMDUuNjY1IDY5LjY1NywxMDYuMTQ4IEwxMTIuMTMsMTMwLjY3IEMxMTIuNDc0LDEzMC44NjggMTEyLjc5MSwxMzAuOTEzIDExMywxMzAuNzkyIEMxMTMuMjA2LDEzMC42NzMgMTEzLjMyNSwxMzAuMzgxIDExMy4zMjUsMTI5Ljk5MyBMMTEzLjMyNSw3NS45OTIgQzExMy4zMjUsNzUuNzk4IDExMy40ODIsNzUuNjQxIDExMy42NzUsNzUuNjQxIEMxMTMuODY5LDc1LjY0MSAxMTQuMDI1LDc1Ljc5OCAxMTQuMDI1LDc1Ljk5MiBMMTE0LjAyNSwxMjkuOTkzIEMxMTQuMDI1LDEzMC42NDggMTEzLjc4NiwxMzEuMTQ3IDExMy4zNSwxMzEuMzk5IEMxMTMuMTYyLDEzMS41MDcgMTEyLjk1MiwxMzEuNTYxIDExMi43MjcsMTMxLjU2MSIgaWQ9IkZpbGwtMjkiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEyLjg2LDQwLjUxMiBDMTEyLjg2LDQwLjUxMiAxMTIuODYsNDAuNTEyIDExMi44NTksNDAuNTEyIEMxMTAuNTQxLDQwLjUxMiAxMDguMzYsMzkuOTkgMTA2LjcxNywzOS4wNDEgQzEwNS4wMTIsMzguMDU3IDEwNC4wNzQsMzYuNzI2IDEwNC4wNzQsMzUuMjkyIEMxMDQuMDc0LDMzLjg0NyAxMDUuMDI2LDMyLjUwMSAxMDYuNzU0LDMxLjUwNCBMMTE4Ljc5NSwyNC41NTEgQzEyMC40NjMsMjMuNTg5IDEyMi42NjksMjMuMDU4IDEyNS4wMDcsMjMuMDU4IEMxMjcuMzI1LDIzLjA1OCAxMjkuNTA2LDIzLjU4MSAxMzEuMTUsMjQuNTMgQzEzMi44NTQsMjUuNTE0IDEzMy43OTMsMjYuODQ1IDEzMy43OTMsMjguMjc4IEMxMzMuNzkzLDI5LjcyNCAxMzIuODQxLDMxLjA2OSAxMzEuMTEzLDMyLjA2NyBMMTE5LjA3MSwzOS4wMTkgQzExNy40MDMsMzkuOTgyIDExNS4xOTcsNDAuNTEyIDExMi44Niw0MC41MTIgTDExMi44Niw0MC41MTIgWiBNMTI1LjAwNywyMy43NTkgQzEyMi43OSwyMy43NTkgMTIwLjcwOSwyNC4yNTYgMTE5LjE0NiwyNS4xNTggTDEwNy4xMDQsMzIuMTEgQzEwNS42MDIsMzIuOTc4IDEwNC43NzQsMzQuMTA4IDEwNC43NzQsMzUuMjkyIEMxMDQuNzc0LDM2LjQ2NSAxMDUuNTg5LDM3LjU4MSAxMDcuMDY3LDM4LjQzNCBDMTA4LjYwNSwzOS4zMjMgMTEwLjY2MywzOS44MTIgMTEyLjg1OSwzOS44MTIgTDExMi44NiwzOS44MTIgQzExNS4wNzYsMzkuODEyIDExNy4xNTgsMzkuMzE1IDExOC43MjEsMzguNDEzIEwxMzAuNzYyLDMxLjQ2IEMxMzIuMjY0LDMwLjU5MyAxMzMuMDkyLDI5LjQ2MyAxMzMuMDkyLDI4LjI3OCBDMTMzLjA5MiwyNy4xMDYgMTMyLjI3OCwyNS45OSAxMzAuOCwyNS4xMzYgQzEyOS4yNjEsMjQuMjQ4IDEyNy4yMDQsMjMuNzU5IDEyNS4wMDcsMjMuNzU5IEwxMjUuMDA3LDIzLjc1OSBaIiBpZD0iRmlsbC0zMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNjUuNjMsMTYuMjE5IEwxNTkuODk2LDE5LjUzIEMxNTYuNzI5LDIxLjM1OCAxNTEuNjEsMjEuMzY3IDE0OC40NjMsMTkuNTUgQzE0NS4zMTYsMTcuNzMzIDE0NS4zMzIsMTQuNzc4IDE0OC40OTksMTIuOTQ5IEwxNTQuMjMzLDkuNjM5IEwxNjUuNjMsMTYuMjE5IiBpZD0iRmlsbC0zMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNTQuMjMzLDEwLjQ0OCBMMTY0LjIyOCwxNi4yMTkgTDE1OS41NDYsMTguOTIzIEMxNTguMTEyLDE5Ljc1IDE1Ni4xOTQsMjAuMjA2IDE1NC4xNDcsMjAuMjA2IEMxNTIuMTE4LDIwLjIwNiAxNTAuMjI0LDE5Ljc1NyAxNDguODE0LDE4Ljk0MyBDMTQ3LjUyNCwxOC4xOTkgMTQ2LjgxNCwxNy4yNDkgMTQ2LjgxNCwxNi4yNjkgQzE0Ni44MTQsMTUuMjc4IDE0Ny41MzcsMTQuMzE0IDE0OC44NSwxMy41NTYgTDE1NC4yMzMsMTAuNDQ4IE0xNTQuMjMzLDkuNjM5IEwxNDguNDk5LDEyLjk0OSBDMTQ1LjMzMiwxNC43NzggMTQ1LjMxNiwxNy43MzMgMTQ4LjQ2MywxOS41NSBDMTUwLjAzMSwyMC40NTUgMTUyLjA4NiwyMC45MDcgMTU0LjE0NywyMC45MDcgQzE1Ni4yMjQsMjAuOTA3IDE1OC4zMDYsMjAuNDQ3IDE1OS44OTYsMTkuNTMgTDE2NS42MywxNi4yMTkgTDE1NC4yMzMsOS42MzkiIGlkPSJGaWxsLTMyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NS40NDUsNzIuNjY3IEwxNDUuNDQ1LDcyLjY2NyBDMTQzLjY3Miw3Mi42NjcgMTQyLjIwNCw3MS44MTcgMTQxLjIwMiw3MC40MjIgQzE0MS4xMzUsNzAuMzMgMTQxLjE0NSw3MC4xNDcgMTQxLjIyNSw3MC4wNjYgQzE0MS4zMDUsNjkuOTg1IDE0MS40MzIsNjkuOTQ2IDE0MS41MjUsNzAuMDExIEMxNDIuMzA2LDcwLjU1OSAxNDMuMjMxLDcwLjgyMyAxNDQuMjc2LDcwLjgyMiBDMTQ1LjU5OCw3MC44MjIgMTQ3LjAzLDcwLjM3NiAxNDguNTMyLDY5LjUwOSBDMTUzLjg0Miw2Ni40NDMgMTU4LjE2Myw1OC45ODcgMTU4LjE2Myw1Mi44OTQgQzE1OC4xNjMsNTAuOTY3IDE1Ny43MjEsNDkuMzMyIDE1Ni44ODQsNDguMTY4IEMxNTYuODE4LDQ4LjA3NiAxNTYuODI4LDQ3Ljk0OCAxNTYuOTA4LDQ3Ljg2NyBDMTU2Ljk4OCw0Ny43ODYgMTU3LjExNCw0Ny43NzQgMTU3LjIwOCw0Ny44NCBDMTU4Ljg3OCw0OS4wMTIgMTU5Ljc5OCw1MS4yMiAxNTkuNzk4LDU0LjA1OSBDMTU5Ljc5OCw2MC4zMDEgMTU1LjM3Myw2OC4wNDYgMTQ5LjkzMyw3MS4xODYgQzE0OC4zNiw3Mi4wOTQgMTQ2Ljg1LDcyLjY2NyAxNDUuNDQ1LDcyLjY2NyBMMTQ1LjQ0NSw3Mi42NjcgWiBNMTQyLjQ3Niw3MSBDMTQzLjI5LDcxLjY1MSAxNDQuMjk2LDcyLjAwMiAxNDUuNDQ1LDcyLjAwMiBDMTQ2Ljc2Nyw3Mi4wMDIgMTQ4LjE5OCw3MS41NSAxNDkuNyw3MC42ODIgQzE1NS4wMSw2Ny42MTcgMTU5LjMzMSw2MC4xNTkgMTU5LjMzMSw1NC4wNjUgQzE1OS4zMzEsNTIuMDg1IDE1OC44NjgsNTAuNDM1IDE1OC4wMDYsNDkuMjcyIEMxNTguNDE3LDUwLjMwNyAxNTguNjMsNTEuNTMyIDE1OC42Myw1Mi44OTIgQzE1OC42Myw1OS4xMzQgMTU0LjIwNSw2Ni43NjcgMTQ4Ljc2NSw2OS45MDcgQzE0Ny4xOTIsNzAuODE2IDE0NS42ODEsNzEuMjgzIDE0NC4yNzYsNzEuMjgzIEMxNDMuNjM0LDcxLjI4MyAxNDMuMDMzLDcxLjE5MiAxNDIuNDc2LDcxIEwxNDIuNDc2LDcxIFoiIGlkPSJGaWxsLTMzIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0OC42NDgsNjkuNzA0IEMxNTQuMDMyLDY2LjU5NiAxNTguMzk2LDU5LjA2OCAxNTguMzk2LDUyLjg5MSBDMTU4LjM5Niw1MC44MzkgMTU3LjkxMyw0OS4xOTggMTU3LjA3NCw0OC4wMyBDMTU1LjI4OSw0Ni43NzggMTUyLjY5OSw0Ni44MzYgMTQ5LjgxNiw0OC41MDEgQzE0NC40MzMsNTEuNjA5IDE0MC4wNjgsNTkuMTM3IDE0MC4wNjgsNjUuMzE0IEMxNDAuMDY4LDY3LjM2NSAxNDAuNTUyLDY5LjAwNiAxNDEuMzkxLDcwLjE3NCBDMTQzLjE3Niw3MS40MjcgMTQ1Ljc2NSw3MS4zNjkgMTQ4LjY0OCw2OS43MDQiIGlkPSJGaWxsLTM0IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NC4yNzYsNzEuMjc2IEwxNDQuMjc2LDcxLjI3NiBDMTQzLjEzMyw3MS4yNzYgMTQyLjExOCw3MC45NjkgMTQxLjI1Nyw3MC4zNjUgQzE0MS4yMzYsNzAuMzUxIDE0MS4yMTcsNzAuMzMyIDE0MS4yMDIsNzAuMzExIEMxNDAuMzA3LDY5LjA2NyAxMzkuODM1LDY3LjMzOSAxMzkuODM1LDY1LjMxNCBDMTM5LjgzNSw1OS4wNzMgMTQ0LjI2LDUxLjQzOSAxNDkuNyw0OC4yOTggQzE1MS4yNzMsNDcuMzkgMTUyLjc4NCw0Ni45MjkgMTU0LjE4OSw0Ni45MjkgQzE1NS4zMzIsNDYuOTI5IDE1Ni4zNDcsNDcuMjM2IDE1Ny4yMDgsNDcuODM5IEMxNTcuMjI5LDQ3Ljg1NCAxNTcuMjQ4LDQ3Ljg3MyAxNTcuMjYzLDQ3Ljg5NCBDMTU4LjE1Nyw0OS4xMzggMTU4LjYzLDUwLjg2NSAxNTguNjMsNTIuODkxIEMxNTguNjMsNTkuMTMyIDE1NC4yMDUsNjYuNzY2IDE0OC43NjUsNjkuOTA3IEMxNDcuMTkyLDcwLjgxNSAxNDUuNjgxLDcxLjI3NiAxNDQuMjc2LDcxLjI3NiBMMTQ0LjI3Niw3MS4yNzYgWiBNMTQxLjU1OCw3MC4xMDQgQzE0Mi4zMzEsNzAuNjM3IDE0My4yNDUsNzEuMDA1IDE0NC4yNzYsNzEuMDA1IEMxNDUuNTk4LDcxLjAwNSAxNDcuMDMsNzAuNDY3IDE0OC41MzIsNjkuNiBDMTUzLjg0Miw2Ni41MzQgMTU4LjE2Myw1OS4wMzMgMTU4LjE2Myw1Mi45MzkgQzE1OC4xNjMsNTEuMDMxIDE1Ny43MjksNDkuMzg1IDE1Ni45MDcsNDguMjIzIEMxNTYuMTMzLDQ3LjY5MSAxNTUuMjE5LDQ3LjQwOSAxNTQuMTg5LDQ3LjQwOSBDMTUyLjg2Nyw0Ny40MDkgMTUxLjQzNSw0Ny44NDIgMTQ5LjkzMyw0OC43MDkgQzE0NC42MjMsNTEuNzc1IDE0MC4zMDIsNTkuMjczIDE0MC4zMDIsNjUuMzY2IEMxNDAuMzAyLDY3LjI3NiAxNDAuNzM2LDY4Ljk0MiAxNDEuNTU4LDcwLjEwNCBMMTQxLjU1OCw3MC4xMDQgWiIgaWQ9IkZpbGwtMzUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUwLjcyLDY1LjM2MSBMMTUwLjM1Nyw2NS4wNjYgQzE1MS4xNDcsNjQuMDkyIDE1MS44NjksNjMuMDQgMTUyLjUwNSw2MS45MzggQzE1My4zMTMsNjAuNTM5IDE1My45NzgsNTkuMDY3IDE1NC40ODIsNTcuNTYzIEwxNTQuOTI1LDU3LjcxMiBDMTU0LjQxMiw1OS4yNDUgMTUzLjczMyw2MC43NDUgMTUyLjkxLDYyLjE3MiBDMTUyLjI2Miw2My4yOTUgMTUxLjUyNSw2NC4zNjggMTUwLjcyLDY1LjM2MSIgaWQ9IkZpbGwtMzYiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE1LjkxNyw4NC41MTQgTDExNS41NTQsODQuMjIgQzExNi4zNDQsODMuMjQ1IDExNy4wNjYsODIuMTk0IDExNy43MDIsODEuMDkyIEMxMTguNTEsNzkuNjkyIDExOS4xNzUsNzguMjIgMTE5LjY3OCw3Ni43MTcgTDEyMC4xMjEsNzYuODY1IEMxMTkuNjA4LDc4LjM5OCAxMTguOTMsNzkuODk5IDExOC4xMDYsODEuMzI2IEMxMTcuNDU4LDgyLjQ0OCAxMTYuNzIyLDgzLjUyMSAxMTUuOTE3LDg0LjUxNCIgaWQ9IkZpbGwtMzciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE0LDEzMC40NzYgTDExNCwxMzAuMDA4IEwxMTQsNzYuMDUyIEwxMTQsNzUuNTg0IEwxMTQsNzYuMDUyIEwxMTQsMTMwLjAwOCBMMTE0LDEzMC40NzYiIGlkPSJGaWxsLTM4IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDYyLjAwMDAwMCwgMC4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTkuODIyLDM3LjQ3NCBDMTkuODM5LDM3LjMzOSAxOS43NDcsMzcuMTk0IDE5LjU1NSwzNy4wODIgQzE5LjIyOCwzNi44OTQgMTguNzI5LDM2Ljg3MiAxOC40NDYsMzcuMDM3IEwxMi40MzQsNDAuNTA4IEMxMi4zMDMsNDAuNTg0IDEyLjI0LDQwLjY4NiAxMi4yNDMsNDAuNzkzIEMxMi4yNDUsNDAuOTI1IDEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQxLjM3MSBMMTIuMjQ1LDQxLjQxNCBMMTIuMjM4LDQxLjU0MiBDOC4xNDgsNDMuODg3IDUuNjQ3LDQ1LjMyMSA1LjY0Nyw0NS4zMjEgQzUuNjQ2LDQ1LjMyMSAzLjU3LDQ2LjM2NyAyLjg2LDUwLjUxMyBDMi44Niw1MC41MTMgMS45NDgsNTcuNDc0IDEuOTYyLDcwLjI1OCBDMS45NzcsODIuODI4IDIuNTY4LDg3LjMyOCAzLjEyOSw5MS42MDkgQzMuMzQ5LDkzLjI5MyA2LjEzLDkzLjczNCA2LjEzLDkzLjczNCBDNi40NjEsOTMuNzc0IDYuODI4LDkzLjcwNyA3LjIxLDkzLjQ4NiBMODIuNDgzLDQ5LjkzNSBDODQuMjkxLDQ4Ljg2NiA4NS4xNSw0Ni4yMTYgODUuNTM5LDQzLjY1MSBDODYuNzUyLDM1LjY2MSA4Ny4yMTQsMTAuNjczIDg1LjI2NCwzLjc3MyBDODUuMDY4LDMuMDggODQuNzU0LDIuNjkgODQuMzk2LDIuNDkxIEw4Mi4zMSwxLjcwMSBDODEuNTgzLDEuNzI5IDgwLjg5NCwyLjE2OCA4MC43NzYsMi4yMzYgQzgwLjYzNiwyLjMxNyA0MS44MDcsMjQuNTg1IDIwLjAzMiwzNy4wNzIgTDE5LjgyMiwzNy40NzQiIGlkPSJGaWxsLTEiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNODIuMzExLDEuNzAxIEw4NC4zOTYsMi40OTEgQzg0Ljc1NCwyLjY5IDg1LjA2OCwzLjA4IDg1LjI2NCwzLjc3MyBDODcuMjEzLDEwLjY3MyA4Ni43NTEsMzUuNjYgODUuNTM5LDQzLjY1MSBDODUuMTQ5LDQ2LjIxNiA4NC4yOSw0OC44NjYgODIuNDgzLDQ5LjkzNSBMNy4yMSw5My40ODYgQzYuODk3LDkzLjY2NyA2LjU5NSw5My43NDQgNi4zMTQsOTMuNzQ0IEw2LjEzMSw5My43MzMgQzYuMTMxLDkzLjczNCAzLjM0OSw5My4yOTMgMy4xMjgsOTEuNjA5IEMyLjU2OCw4Ny4zMjcgMS45NzcsODIuODI4IDEuOTYzLDcwLjI1OCBDMS45NDgsNTcuNDc0IDIuODYsNTAuNTEzIDIuODYsNTAuNTEzIEMzLjU3LDQ2LjM2NyA1LjY0Nyw0NS4zMjEgNS42NDcsNDUuMzIxIEM1LjY0Nyw0NS4zMjEgOC4xNDgsNDMuODg3IDEyLjIzOCw0MS41NDIgTDEyLjI0NSw0MS40MTQgTDEyLjI0NSw0MS4zNzEgQzEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQwLjkyNSAxMi4yNDMsNDAuNzkzIEMxMi4yNCw0MC42ODYgMTIuMzAyLDQwLjU4MyAxMi40MzQsNDAuNTA4IEwxOC40NDYsMzcuMDM2IEMxOC41NzQsMzYuOTYyIDE4Ljc0NiwzNi45MjYgMTguOTI3LDM2LjkyNiBDMTkuMTQ1LDM2LjkyNiAxOS4zNzYsMzYuOTc5IDE5LjU1NCwzNy4wODIgQzE5Ljc0NywzNy4xOTQgMTkuODM5LDM3LjM0IDE5LjgyMiwzNy40NzQgTDIwLjAzMywzNy4wNzIgQzQxLjgwNiwyNC41ODUgODAuNjM2LDIuMzE4IDgwLjc3NywyLjIzNiBDODAuODk0LDIuMTY4IDgxLjU4MywxLjcyOSA4Mi4zMTEsMS43MDEgTTgyLjMxMSwwLjcwNCBMODIuMjcyLDAuNzA1IEM4MS42NTQsMC43MjggODAuOTg5LDAuOTQ5IDgwLjI5OCwxLjM2MSBMODAuMjc3LDEuMzczIEM4MC4xMjksMS40NTggNTkuNzY4LDEzLjEzNSAxOS43NTgsMzYuMDc5IEMxOS41LDM1Ljk4MSAxOS4yMTQsMzUuOTI5IDE4LjkyNywzNS45MjkgQzE4LjU2MiwzNS45MjkgMTguMjIzLDM2LjAxMyAxNy45NDcsMzYuMTczIEwxMS45MzUsMzkuNjQ0IEMxMS40OTMsMzkuODk5IDExLjIzNiw0MC4zMzQgMTEuMjQ2LDQwLjgxIEwxMS4yNDcsNDAuOTYgTDUuMTY3LDQ0LjQ0NyBDNC43OTQsNDQuNjQ2IDIuNjI1LDQ1Ljk3OCAxLjg3Nyw1MC4zNDUgTDEuODcxLDUwLjM4NCBDMS44NjIsNTAuNDU0IDAuOTUxLDU3LjU1NyAwLjk2NSw3MC4yNTkgQzAuOTc5LDgyLjg3OSAxLjU2OCw4Ny4zNzUgMi4xMzcsOTEuNzI0IEwyLjEzOSw5MS43MzkgQzIuNDQ3LDk0LjA5NCA1LjYxNCw5NC42NjIgNS45NzUsOTQuNzE5IEw2LjAwOSw5NC43MjMgQzYuMTEsOTQuNzM2IDYuMjEzLDk0Ljc0MiA2LjMxNCw5NC43NDIgQzYuNzksOTQuNzQyIDcuMjYsOTQuNjEgNy43MSw5NC4zNSBMODIuOTgzLDUwLjc5OCBDODQuNzk0LDQ5LjcyNyA4NS45ODIsNDcuMzc1IDg2LjUyNSw0My44MDEgQzg3LjcxMSwzNS45ODcgODguMjU5LDEwLjcwNSA4Ni4yMjQsMy41MDIgQzg1Ljk3MSwyLjYwOSA4NS41MiwxLjk3NSA4NC44ODEsMS42MiBMODQuNzQ5LDEuNTU4IEw4Mi42NjQsMC43NjkgQzgyLjU1MSwwLjcyNSA4Mi40MzEsMC43MDQgODIuMzExLDAuNzA0IiBpZD0iRmlsbC0yIiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY2LjI2NywxMS41NjUgTDY3Ljc2MiwxMS45OTkgTDExLjQyMyw0NC4zMjUiIGlkPSJGaWxsLTMiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMjAyLDkwLjU0NSBDMTIuMDI5LDkwLjU0NSAxMS44NjIsOTAuNDU1IDExLjc2OSw5MC4yOTUgQzExLjYzMiw5MC4wNTcgMTEuNzEzLDg5Ljc1MiAxMS45NTIsODkuNjE0IEwzMC4zODksNzguOTY5IEMzMC42MjgsNzguODMxIDMwLjkzMyw3OC45MTMgMzEuMDcxLDc5LjE1MiBDMzEuMjA4LDc5LjM5IDMxLjEyNyw3OS42OTYgMzAuODg4LDc5LjgzMyBMMTIuNDUxLDkwLjQ3OCBMMTIuMjAyLDkwLjU0NSIgaWQ9IkZpbGwtNCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMy43NjQsNDIuNjU0IEwxMy42NTYsNDIuNTkyIEwxMy43MDIsNDIuNDIxIEwxOC44MzcsMzkuNDU3IEwxOS4wMDcsMzkuNTAyIEwxOC45NjIsMzkuNjczIEwxMy44MjcsNDIuNjM3IEwxMy43NjQsNDIuNjU0IiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTguNTIsOTAuMzc1IEw4LjUyLDQ2LjQyMSBMOC41ODMsNDYuMzg1IEw3NS44NCw3LjU1NCBMNzUuODQsNTEuNTA4IEw3NS43NzgsNTEuNTQ0IEw4LjUyLDkwLjM3NSBMOC41Miw5MC4zNzUgWiBNOC43Nyw0Ni41NjQgTDguNzcsODkuOTQ0IEw3NS41OTEsNTEuMzY1IEw3NS41OTEsNy45ODUgTDguNzcsNDYuNTY0IEw4Ljc3LDQ2LjU2NCBaIiBpZD0iRmlsbC02IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTI0Ljk4Niw4My4xODIgQzI0Ljc1Niw4My4zMzEgMjQuMzc0LDgzLjU2NiAyNC4xMzcsODMuNzA1IEwxMi42MzIsOTAuNDA2IEMxMi4zOTUsOTAuNTQ1IDEyLjQyNiw5MC42NTggMTIuNyw5MC42NTggTDEzLjI2NSw5MC42NTggQzEzLjU0LDkwLjY1OCAxMy45NTgsOTAuNTQ1IDE0LjE5NSw5MC40MDYgTDI1LjcsODMuNzA1IEMyNS45MzcsODMuNTY2IDI2LjEyOCw4My40NTIgMjYuMTI1LDgzLjQ0OSBDMjYuMTIyLDgzLjQ0NyAyNi4xMTksODMuMjIgMjYuMTE5LDgyLjk0NiBDMjYuMTE5LDgyLjY3MiAyNS45MzEsODIuNTY5IDI1LjcwMSw4Mi43MTkgTDI0Ljk4Niw4My4xODIiIGlkPSJGaWxsLTciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTMuMjY2LDkwLjc4MiBMMTIuNyw5MC43ODIgQzEyLjUsOTAuNzgyIDEyLjM4NCw5MC43MjYgMTIuMzU0LDkwLjYxNiBDMTIuMzI0LDkwLjUwNiAxMi4zOTcsOTAuMzk5IDEyLjU2OSw5MC4yOTkgTDI0LjA3NCw4My41OTcgQzI0LjMxLDgzLjQ1OSAyNC42ODksODMuMjI2IDI0LjkxOCw4My4wNzggTDI1LjYzMyw4Mi42MTQgQzI1LjcyMyw4Mi41NTUgMjUuODEzLDgyLjUyNSAyNS44OTksODIuNTI1IEMyNi4wNzEsODIuNTI1IDI2LjI0NCw4Mi42NTUgMjYuMjQ0LDgyLjk0NiBDMjYuMjQ0LDgzLjE2IDI2LjI0NSw4My4zMDkgMjYuMjQ3LDgzLjM4MyBMMjYuMjUzLDgzLjM4NyBMMjYuMjQ5LDgzLjQ1NiBDMjYuMjQ2LDgzLjUzMSAyNi4yNDYsODMuNTMxIDI1Ljc2Myw4My44MTIgTDE0LjI1OCw5MC41MTQgQzE0LDkwLjY2NSAxMy41NjQsOTAuNzgyIDEzLjI2Niw5MC43ODIgTDEzLjI2Niw5MC43ODIgWiBNMTIuNjY2LDkwLjUzMiBMMTIuNyw5MC41MzMgTDEzLjI2Niw5MC41MzMgQzEzLjUxOCw5MC41MzMgMTMuOTE1LDkwLjQyNSAxNC4xMzIsOTAuMjk5IEwyNS42MzcsODMuNTk3IEMyNS44MDUsODMuNDk5IDI1LjkzMSw4My40MjQgMjUuOTk4LDgzLjM4MyBDMjUuOTk0LDgzLjI5OSAyNS45OTQsODMuMTY1IDI1Ljk5NCw4Mi45NDYgTDI1Ljg5OSw4Mi43NzUgTDI1Ljc2OCw4Mi44MjQgTDI1LjA1NCw4My4yODcgQzI0LjgyMiw4My40MzcgMjQuNDM4LDgzLjY3MyAyNC4yLDgzLjgxMiBMMTIuNjk1LDkwLjUxNCBMMTIuNjY2LDkwLjUzMiBMMTIuNjY2LDkwLjUzMiBaIiBpZD0iRmlsbC04IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEzLjI2Niw4OS44NzEgTDEyLjcsODkuODcxIEMxMi41LDg5Ljg3MSAxMi4zODQsODkuODE1IDEyLjM1NCw4OS43MDUgQzEyLjMyNCw4OS41OTUgMTIuMzk3LDg5LjQ4OCAxMi41NjksODkuMzg4IEwyNC4wNzQsODIuNjg2IEMyNC4zMzIsODIuNTM1IDI0Ljc2OCw4Mi40MTggMjUuMDY3LDgyLjQxOCBMMjUuNjMyLDgyLjQxOCBDMjUuODMyLDgyLjQxOCAyNS45NDgsODIuNDc0IDI1Ljk3OCw4Mi41ODQgQzI2LjAwOCw4Mi42OTQgMjUuOTM1LDgyLjgwMSAyNS43NjMsODIuOTAxIEwxNC4yNTgsODkuNjAzIEMxNCw4OS43NTQgMTMuNTY0LDg5Ljg3MSAxMy4yNjYsODkuODcxIEwxMy4yNjYsODkuODcxIFogTTEyLjY2Niw4OS42MjEgTDEyLjcsODkuNjIyIEwxMy4yNjYsODkuNjIyIEMxMy41MTgsODkuNjIyIDEzLjkxNSw4OS41MTUgMTQuMTMyLDg5LjM4OCBMMjUuNjM3LDgyLjY4NiBMMjUuNjY3LDgyLjY2OCBMMjUuNjMyLDgyLjY2NyBMMjUuMDY3LDgyLjY2NyBDMjQuODE1LDgyLjY2NyAyNC40MTgsODIuNzc1IDI0LjIsODIuOTAxIEwxMi42OTUsODkuNjAzIEwxMi42NjYsODkuNjIxIEwxMi42NjYsODkuNjIxIFoiIGlkPSJGaWxsLTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMzcsOTAuODAxIEwxMi4zNyw4OS41NTQgTDEyLjM3LDkwLjgwMSIgaWQ9IkZpbGwtMTAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNi4xMyw5My45MDEgQzUuMzc5LDkzLjgwOCA0LjgxNiw5My4xNjQgNC42OTEsOTIuNTI1IEMzLjg2LDg4LjI4NyAzLjU0LDgzLjc0MyAzLjUyNiw3MS4xNzMgQzMuNTExLDU4LjM4OSA0LjQyMyw1MS40MjggNC40MjMsNTEuNDI4IEM1LjEzNCw0Ny4yODIgNy4yMSw0Ni4yMzYgNy4yMSw0Ni4yMzYgQzcuMjEsNDYuMjM2IDgxLjY2NywzLjI1IDgyLjA2OSwzLjAxNyBDODIuMjkyLDIuODg4IDg0LjU1NiwxLjQzMyA4NS4yNjQsMy45NCBDODcuMjE0LDEwLjg0IDg2Ljc1MiwzNS44MjcgODUuNTM5LDQzLjgxOCBDODUuMTUsNDYuMzgzIDg0LjI5MSw0OS4wMzMgODIuNDgzLDUwLjEwMSBMNy4yMSw5My42NTMgQzYuODI4LDkzLjg3NCA2LjQ2MSw5My45NDEgNi4xMyw5My45MDEgQzYuMTMsOTMuOTAxIDMuMzQ5LDkzLjQ2IDMuMTI5LDkxLjc3NiBDMi41NjgsODcuNDk1IDEuOTc3LDgyLjk5NSAxLjk2Miw3MC40MjUgQzEuOTQ4LDU3LjY0MSAyLjg2LDUwLjY4IDIuODYsNTAuNjggQzMuNTcsNDYuNTM0IDUuNjQ3LDQ1LjQ4OSA1LjY0Nyw0NS40ODkgQzUuNjQ2LDQ1LjQ4OSA4LjA2NSw0NC4wOTIgMTIuMjQ1LDQxLjY3OSBMMTMuMTE2LDQxLjU2IEwxOS43MTUsMzcuNzMgTDE5Ljc2MSwzNy4yNjkgTDYuMTMsOTMuOTAxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjMxNyw5NC4xNjEgTDYuMTAyLDk0LjE0OCBMNi4xMDEsOTQuMTQ4IEw1Ljg1Nyw5NC4xMDEgQzUuMTM4LDkzLjk0NSAzLjA4NSw5My4zNjUgMi44ODEsOTEuODA5IEMyLjMxMyw4Ny40NjkgMS43MjcsODIuOTk2IDEuNzEzLDcwLjQyNSBDMS42OTksNTcuNzcxIDIuNjA0LDUwLjcxOCAyLjYxMyw1MC42NDggQzMuMzM4LDQ2LjQxNyA1LjQ0NSw0NS4zMSA1LjUzNSw0NS4yNjYgTDEyLjE2Myw0MS40MzkgTDEzLjAzMyw0MS4zMiBMMTkuNDc5LDM3LjU3OCBMMTkuNTEzLDM3LjI0NCBDMTkuNTI2LDM3LjEwNyAxOS42NDcsMzcuMDA4IDE5Ljc4NiwzNy4wMjEgQzE5LjkyMiwzNy4wMzQgMjAuMDIzLDM3LjE1NiAyMC4wMDksMzcuMjkzIEwxOS45NSwzNy44ODIgTDEzLjE5OCw0MS44MDEgTDEyLjMyOCw0MS45MTkgTDUuNzcyLDQ1LjcwNCBDNS43NDEsNDUuNzIgMy43ODIsNDYuNzcyIDMuMTA2LDUwLjcyMiBDMy4wOTksNTAuNzgyIDIuMTk4LDU3LjgwOCAyLjIxMiw3MC40MjQgQzIuMjI2LDgyLjk2MyAyLjgwOSw4Ny40MiAzLjM3Myw5MS43MjkgQzMuNDY0LDkyLjQyIDQuMDYyLDkyLjg4MyA0LjY4Miw5My4xODEgQzQuNTY2LDkyLjk4NCA0LjQ4Niw5Mi43NzYgNC40NDYsOTIuNTcyIEMzLjY2NSw4OC41ODggMy4yOTEsODQuMzcgMy4yNzYsNzEuMTczIEMzLjI2Miw1OC41MiA0LjE2Nyw1MS40NjYgNC4xNzYsNTEuMzk2IEM0LjkwMSw0Ny4xNjUgNy4wMDgsNDYuMDU5IDcuMDk4LDQ2LjAxNCBDNy4wOTQsNDYuMDE1IDgxLjU0MiwzLjAzNCA4MS45NDQsMi44MDIgTDgxLjk3MiwyLjc4NSBDODIuODc2LDIuMjQ3IDgzLjY5MiwyLjA5NyA4NC4zMzIsMi4zNTIgQzg0Ljg4NywyLjU3MyA4NS4yODEsMy4wODUgODUuNTA0LDMuODcyIEM4Ny41MTgsMTEgODYuOTY0LDM2LjA5MSA4NS43ODUsNDMuODU1IEM4NS4yNzgsNDcuMTk2IDg0LjIxLDQ5LjM3IDgyLjYxLDUwLjMxNyBMNy4zMzUsOTMuODY5IEM2Ljk5OSw5NC4wNjMgNi42NTgsOTQuMTYxIDYuMzE3LDk0LjE2MSBMNi4zMTcsOTQuMTYxIFogTTYuMTcsOTMuNjU0IEM2LjQ2Myw5My42OSA2Ljc3NCw5My42MTcgNy4wODUsOTMuNDM3IEw4Mi4zNTgsNDkuODg2IEM4NC4xODEsNDguODA4IDg0Ljk2LDQ1Ljk3MSA4NS4yOTIsNDMuNzggQzg2LjQ2NiwzNi4wNDkgODcuMDIzLDExLjA4NSA4NS4wMjQsNC4wMDggQzg0Ljg0NiwzLjM3NyA4NC41NTEsMi45NzYgODQuMTQ4LDIuODE2IEM4My42NjQsMi42MjMgODIuOTgyLDIuNzY0IDgyLjIyNywzLjIxMyBMODIuMTkzLDMuMjM0IEM4MS43OTEsMy40NjYgNy4zMzUsNDYuNDUyIDcuMzM1LDQ2LjQ1MiBDNy4zMDQsNDYuNDY5IDUuMzQ2LDQ3LjUyMSA0LjY2OSw1MS40NzEgQzQuNjYyLDUxLjUzIDMuNzYxLDU4LjU1NiAzLjc3NSw3MS4xNzMgQzMuNzksODQuMzI4IDQuMTYxLDg4LjUyNCA0LjkzNiw5Mi40NzYgQzUuMDI2LDkyLjkzNyA1LjQxMiw5My40NTkgNS45NzMsOTMuNjE1IEM2LjA4Nyw5My42NCA2LjE1OCw5My42NTIgNi4xNjksOTMuNjU0IEw2LjE3LDkzLjY1NCBMNi4xNyw5My42NTQgWiIgaWQ9IkZpbGwtMTIiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4zMTcsNjguOTgyIEM3LjgwNiw2OC43MDEgOC4yMDIsNjguOTI2IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNi44MjksNzEuMjk0IDYuNDMzLDcxLjA2OSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIiBpZD0iRmlsbC0xMyIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjkyLDcxLjEzMyBDNi42MzEsNzEuMTMzIDYuNDMzLDcwLjkwNSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIEM3LjQ2LDY4LjkgNy41OTUsNjguODYxIDcuNzE0LDY4Ljg2MSBDOC4wMDMsNjguODYxIDguMjAyLDY5LjA5IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNy4xNzQsNzEuMDk0IDcuMDM5LDcxLjEzMyA2LjkyLDcxLjEzMyBNNy43MTQsNjguNjc0IEM3LjU1Nyw2OC42NzQgNy4zOTIsNjguNzIzIDcuMjI0LDY4LjgyMSBDNi42NzYsNjkuMTM4IDYuMjQ2LDY5Ljg3OSA2LjI0Niw3MC41MDggQzYuMjQ2LDcwLjk5NCA2LjUxNyw3MS4zMiA2LjkyLDcxLjMyIEM3LjA3OCw3MS4zMiA3LjI0Myw3MS4yNzEgNy40MTEsNzEuMTc0IEM3Ljk1OSw3MC44NTcgOC4zODksNzAuMTE3IDguMzg5LDY5LjQ4NyBDOC4zODksNjkuMDAxIDguMTE3LDY4LjY3NCA3LjcxNCw2OC42NzQiIGlkPSJGaWxsLTE0IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYuOTIsNzAuOTQ3IEM2LjY0OSw3MC45NDcgNi42MjEsNzAuNjQgNi42MjEsNzAuNTA4IEM2LjYyMSw3MC4wMTcgNi45ODIsNjkuMzkyIDcuNDExLDY5LjE0NSBDNy41MjEsNjkuMDgyIDcuNjI1LDY5LjA0OSA3LjcxNCw2OS4wNDkgQzcuOTg2LDY5LjA0OSA4LjAxNSw2OS4zNTUgOC4wMTUsNjkuNDg3IEM4LjAxNSw2OS45NzggNy42NTIsNzAuNjAzIDcuMjI0LDcwLjg1MSBDNy4xMTUsNzAuOTE0IDcuMDEsNzAuOTQ3IDYuOTIsNzAuOTQ3IE03LjcxNCw2OC44NjEgQzcuNTk1LDY4Ljg2MSA3LjQ2LDY4LjkgNy4zMTcsNjguOTgyIEM2LjgyOSw2OS4yNjUgNi40MzMsNjkuOTQ4IDYuNDMzLDcwLjUwOCBDNi40MzMsNzAuOTA1IDYuNjMxLDcxLjEzMyA2LjkyLDcxLjEzMyBDNy4wMzksNzEuMTMzIDcuMTc0LDcxLjA5NCA3LjMxNyw3MS4wMTIgQzcuODA2LDcwLjczIDguMjAyLDcwLjA0NyA4LjIwMiw2OS40ODcgQzguMjAyLDY5LjA5IDguMDAzLDY4Ljg2MSA3LjcxNCw2OC44NjEiIGlkPSJGaWxsLTE1IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTcuNDQ0LDg1LjM1IEM3LjcwOCw4NS4xOTggNy45MjEsODUuMzE5IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuOTI1IDcuNzA4LDg2LjI5MiA3LjQ0NCw4Ni40NDQgQzcuMTgxLDg2LjU5NyA2Ljk2Nyw4Ni40NzUgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IiBpZD0iRmlsbC0xNiIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik03LjIzLDg2LjUxIEM3LjA3NCw4Ni41MSA2Ljk2Nyw4Ni4zODcgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IEM3LjUyMSw4NS4zMDUgNy41OTQsODUuMjg0IDcuNjU4LDg1LjI4NCBDNy44MTQsODUuMjg0IDcuOTIxLDg1LjQwOCA3LjkyMSw4NS42MjIgQzcuOTIxLDg1LjkyNSA3LjcwOCw4Ni4yOTIgNy40NDQsODYuNDQ0IEM3LjM2Nyw4Ni40ODkgNy4yOTQsODYuNTEgNy4yMyw4Ni41MSBNNy42NTgsODUuMDk4IEM3LjU1OCw4NS4wOTggNy40NTUsODUuMTI3IDcuMzUxLDg1LjE4OCBDNy4wMzEsODUuMzczIDYuNzgxLDg1LjgwNiA2Ljc4MSw4Ni4xNzMgQzYuNzgxLDg2LjQ4MiA2Ljk2Niw4Ni42OTcgNy4yMyw4Ni42OTcgQzcuMzMsODYuNjk3IDcuNDMzLDg2LjY2NiA3LjUzOCw4Ni42MDcgQzcuODU4LDg2LjQyMiA4LjEwOCw4NS45ODkgOC4xMDgsODUuNjIyIEM4LjEwOCw4NS4zMTMgNy45MjMsODUuMDk4IDcuNjU4LDg1LjA5OCIgaWQ9IkZpbGwtMTciIGZpbGw9IiM4MDk3QTIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4yMyw4Ni4zMjIgTDcuMTU0LDg2LjE3MyBDNy4xNTQsODUuOTM4IDcuMzMzLDg1LjYyOSA3LjUzOCw4NS41MTIgTDcuNjU4LDg1LjQ3MSBMNy43MzQsODUuNjIyIEM3LjczNCw4NS44NTYgNy41NTUsODYuMTY0IDcuMzUxLDg2LjI4MiBMNy4yMyw4Ni4zMjIgTTcuNjU4LDg1LjI4NCBDNy41OTQsODUuMjg0IDcuNTIxLDg1LjMwNSA3LjQ0NCw4NS4zNSBDNy4xODEsODUuNTAyIDYuOTY3LDg1Ljg3MSA2Ljk2Nyw4Ni4xNzMgQzYuOTY3LDg2LjM4NyA3LjA3NCw4Ni41MSA3LjIzLDg2LjUxIEM3LjI5NCw4Ni41MSA3LjM2Nyw4Ni40ODkgNy40NDQsODYuNDQ0IEM3LjcwOCw4Ni4yOTIgNy45MjEsODUuOTI1IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuNDA4IDcuODE0LDg1LjI4NCA3LjY1OCw4NS4yODQiIGlkPSJGaWxsLTE4IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTc3LjI3OCw3Ljc2OSBMNzcuMjc4LDUxLjQzNiBMMTAuMjA4LDkwLjE2IEwxMC4yMDgsNDYuNDkzIEw3Ny4yNzgsNy43NjkiIGlkPSJGaWxsLTE5IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEwLjA4Myw5MC4zNzUgTDEwLjA4Myw0Ni40MjEgTDEwLjE0Niw0Ni4zODUgTDc3LjQwMyw3LjU1NCBMNzcuNDAzLDUxLjUwOCBMNzcuMzQxLDUxLjU0NCBMMTAuMDgzLDkwLjM3NSBMMTAuMDgzLDkwLjM3NSBaIE0xMC4zMzMsNDYuNTY0IEwxMC4zMzMsODkuOTQ0IEw3Ny4xNTQsNTEuMzY1IEw3Ny4xNTQsNy45ODUgTDEwLjMzMyw0Ni41NjQgTDEwLjMzMyw0Ni41NjQgWiIgaWQ9IkZpbGwtMjAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMjUuNzM3LDg4LjY0NyBMMTE4LjA5OCw5MS45ODEgTDExOC4wOTgsODQgTDEwNi42MzksODguNzEzIEwxMDYuNjM5LDk2Ljk4MiBMOTksMTAwLjMxNSBMMTEyLjM2OSwxMDMuOTYxIEwxMjUuNzM3LDg4LjY0NyIgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTIiIGZpbGw9IiM0NTVBNjQiIHNrZXRjaDp0eXBlPSJNU1NoYXBlR3JvdXAiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+';
+var rotateInstructionsAsset = "<svg width='198' height='240' viewBox='0 0 198 240' xmlns='http://www.w3.org/2000/svg'><g fill='none' fill-rule='evenodd'><path d='M149.625 109.527l6.737 3.891v.886c0 .177.013.36.038.549.01.081.02.162.027.242.14 1.415.974 2.998 2.105 3.999l5.72 5.062.081-.09s4.382-2.53 5.235-3.024l25.97 14.993v54.001c0 .771-.386 1.217-.948 1.217-.233 0-.495-.076-.772-.236l-23.967-13.838-.014.024-27.322 15.775-.85-1.323c-4.731-1.529-9.748-2.74-14.951-3.61a.27.27 0 0 0-.007.024l-5.067 16.961-7.891 4.556-.037-.063v27.59c0 .772-.386 1.217-.948 1.217-.232 0-.495-.076-.772-.236l-42.473-24.522c-.95-.549-1.72-1.877-1.72-2.967v-1.035l-.021.047a5.111 5.111 0 0 0-1.816-.399 5.682 5.682 0 0 0-.546.001 13.724 13.724 0 0 1-1.918-.041c-1.655-.153-3.2-.6-4.404-1.296l-46.576-26.89.005.012-10.278-18.75c-1.001-1.827-.241-4.216 1.698-5.336l56.011-32.345a4.194 4.194 0 0 1 2.099-.572c1.326 0 2.572.659 3.227 1.853l.005-.003.227.413-.006.004a9.63 9.63 0 0 0 1.477 2.018l.277.27c1.914 1.85 4.468 2.801 7.113 2.801 1.949 0 3.948-.517 5.775-1.572.013 0 7.319-4.219 7.319-4.219a4.194 4.194 0 0 1 2.099-.572c1.326 0 2.572.658 3.226 1.853l3.25 5.928.022-.018 6.785 3.917-.105-.182 46.881-26.965m0-1.635c-.282 0-.563.073-.815.218l-46.169 26.556-5.41-3.124-3.005-5.481c-.913-1.667-2.699-2.702-4.66-2.703-1.011 0-2.02.274-2.917.792a3825 3825 0 0 1-7.275 4.195l-.044.024a9.937 9.937 0 0 1-4.957 1.353c-2.292 0-4.414-.832-5.976-2.342l-.252-.245a7.992 7.992 0 0 1-1.139-1.534 1.379 1.379 0 0 0-.06-.122l-.227-.414a1.718 1.718 0 0 0-.095-.154c-.938-1.574-2.673-2.545-4.571-2.545-1.011 0-2.02.274-2.917.792L3.125 155.502c-2.699 1.559-3.738 4.94-2.314 7.538l10.278 18.75c.177.323.448.563.761.704l46.426 26.804c1.403.81 3.157 1.332 5.072 1.508a15.661 15.661 0 0 0 2.146.046 4.766 4.766 0 0 1 .396 0c.096.004.19.011.283.022.109 1.593 1.159 3.323 2.529 4.114l42.472 24.522c.524.302 1.058.455 1.59.455 1.497 0 2.583-1.2 2.583-2.852v-26.562l7.111-4.105a1.64 1.64 0 0 0 .749-.948l4.658-15.593c4.414.797 8.692 1.848 12.742 3.128l.533.829a1.634 1.634 0 0 0 2.193.531l26.532-15.317L193 192.433c.523.302 1.058.455 1.59.455 1.497 0 2.583-1.199 2.583-2.852v-54.001c0-.584-.312-1.124-.818-1.416l-25.97-14.993a1.633 1.633 0 0 0-1.636.001c-.606.351-2.993 1.73-4.325 2.498l-4.809-4.255c-.819-.725-1.461-1.933-1.561-2.936a7.776 7.776 0 0 0-.033-.294 2.487 2.487 0 0 1-.023-.336v-.886c0-.584-.312-1.123-.817-1.416l-6.739-3.891a1.633 1.633 0 0 0-.817-.219' fill='#455A64'/><path d='M96.027 132.636l46.576 26.891c1.204.695 1.979 1.587 2.242 2.541l-.01.007-81.374 46.982h-.001c-1.654-.152-3.199-.6-4.403-1.295l-46.576-26.891 83.546-48.235' fill='#FAFAFA'/><path d='M63.461 209.174c-.008 0-.015 0-.022-.002-1.693-.156-3.228-.609-4.441-1.309l-46.576-26.89a.118.118 0 0 1 0-.203l83.546-48.235a.117.117 0 0 1 .117 0l46.576 26.891c1.227.708 2.021 1.612 2.296 2.611a.116.116 0 0 1-.042.124l-.021.016-81.375 46.981a.11.11 0 0 1-.058.016zm-50.747-28.303l46.401 26.79c1.178.68 2.671 1.121 4.32 1.276l81.272-46.922c-.279-.907-1.025-1.73-2.163-2.387l-46.517-26.857-83.313 48.1z' fill='#607D8B'/><path d='M148.327 165.471a5.85 5.85 0 0 1-.546.001c-1.894-.083-3.302-1.038-3.145-2.132a2.693 2.693 0 0 0-.072-1.105l-81.103 46.822c.628.058 1.272.073 1.918.042.182-.009.364-.009.546-.001 1.894.083 3.302 1.038 3.145 2.132l79.257-45.759' fill='#FFF'/><path d='M69.07 211.347a.118.118 0 0 1-.115-.134c.045-.317-.057-.637-.297-.925-.505-.61-1.555-1.022-2.738-1.074a5.966 5.966 0 0 0-.535.001 14.03 14.03 0 0 1-1.935-.041.117.117 0 0 1-.103-.092.116.116 0 0 1 .055-.126l81.104-46.822a.117.117 0 0 1 .171.07c.104.381.129.768.074 1.153-.045.316.057.637.296.925.506.61 1.555 1.021 2.739 1.073.178.008.357.008.535-.001a.117.117 0 0 1 .064.218l-79.256 45.759a.114.114 0 0 1-.059.016zm-3.405-2.372c.089 0 .177.002.265.006 1.266.056 2.353.488 2.908 1.158.227.274.35.575.36.882l78.685-45.429c-.036 0-.072-.001-.107-.003-1.267-.056-2.354-.489-2.909-1.158-.282-.34-.402-.724-.347-1.107a2.604 2.604 0 0 0-.032-.91L63.846 208.97a13.91 13.91 0 0 0 1.528.012c.097-.005.194-.007.291-.007z' fill='#607D8B'/><path d='M2.208 162.134c-1.001-1.827-.241-4.217 1.698-5.337l56.011-32.344c1.939-1.12 4.324-.546 5.326 1.281l.232.41a9.344 9.344 0 0 0 1.47 2.021l.278.27c3.325 3.214 8.583 3.716 12.888 1.23l7.319-4.22c1.94-1.119 4.324-.546 5.325 1.282l3.25 5.928-83.519 48.229-10.278-18.75z' fill='#FAFAFA'/><path d='M12.486 181.001a.112.112 0 0 1-.031-.005.114.114 0 0 1-.071-.056L2.106 162.19c-1.031-1.88-.249-4.345 1.742-5.494l56.01-32.344a4.328 4.328 0 0 1 2.158-.588c1.415 0 2.65.702 3.311 1.882.01.008.018.017.024.028l.227.414a.122.122 0 0 1 .013.038 9.508 9.508 0 0 0 1.439 1.959l.275.266c1.846 1.786 4.344 2.769 7.031 2.769 1.977 0 3.954-.538 5.717-1.557a.148.148 0 0 1 .035-.013l7.284-4.206a4.321 4.321 0 0 1 2.157-.588c1.427 0 2.672.716 3.329 1.914l3.249 5.929a.116.116 0 0 1-.044.157l-83.518 48.229a.116.116 0 0 1-.059.016zm49.53-57.004c-.704 0-1.41.193-2.041.557l-56.01 32.345c-1.882 1.086-2.624 3.409-1.655 5.179l10.221 18.645 83.317-48.112-3.195-5.829c-.615-1.122-1.783-1.792-3.124-1.792a4.08 4.08 0 0 0-2.04.557l-7.317 4.225a.148.148 0 0 1-.035.013 11.7 11.7 0 0 1-5.801 1.569c-2.748 0-5.303-1.007-7.194-2.835l-.278-.27a9.716 9.716 0 0 1-1.497-2.046.096.096 0 0 1-.013-.037l-.191-.347a.11.11 0 0 1-.023-.029c-.615-1.123-1.783-1.793-3.124-1.793z' fill='#607D8B'/><path d='M42.434 155.808c-2.51-.001-4.697-1.258-5.852-3.365-1.811-3.304-.438-7.634 3.059-9.654l12.291-7.098a7.599 7.599 0 0 1 3.789-1.033c2.51 0 4.697 1.258 5.852 3.365 1.811 3.304.439 7.634-3.059 9.654l-12.291 7.098a7.606 7.606 0 0 1-3.789 1.033zm13.287-20.683a7.128 7.128 0 0 0-3.555.971l-12.291 7.098c-3.279 1.893-4.573 5.942-2.883 9.024 1.071 1.955 3.106 3.122 5.442 3.122a7.13 7.13 0 0 0 3.556-.97l12.291-7.098c3.279-1.893 4.572-5.942 2.883-9.024-1.072-1.955-3.106-3.123-5.443-3.123z' fill='#607D8B'/><path d='M149.588 109.407l6.737 3.89v.887c0 .176.013.36.037.549.011.081.02.161.028.242.14 1.415.973 2.998 2.105 3.999l7.396 6.545c.177.156.358.295.541.415 1.579 1.04 2.95.466 3.062-1.282.049-.784.057-1.595.023-2.429l-.003-.16v-1.151l25.987 15.003v54c0 1.09-.77 1.53-1.72.982l-42.473-24.523c-.95-.548-1.72-1.877-1.72-2.966v-34.033' fill='#FAFAFA'/><path d='M194.553 191.25c-.257 0-.54-.085-.831-.253l-42.472-24.521c-.981-.567-1.779-1.943-1.779-3.068v-34.033h.234v34.033c0 1.051.745 2.336 1.661 2.866l42.473 24.521c.424.245.816.288 1.103.122.285-.164.442-.52.442-1.002v-53.933l-25.753-14.868.003 1.106c.034.832.026 1.654-.024 2.439-.054.844-.396 1.464-.963 1.746-.619.309-1.45.173-2.28-.373a5.023 5.023 0 0 1-.553-.426l-7.397-6.544c-1.158-1.026-1.999-2.625-2.143-4.076a9.624 9.624 0 0 0-.027-.238 4.241 4.241 0 0 1-.038-.564v-.82l-6.68-3.856.117-.202 6.738 3.89.058.034v.954c0 .171.012.351.036.533.011.083.021.165.029.246.138 1.395.948 2.935 2.065 3.923l7.397 6.545c.173.153.35.289.527.406.758.499 1.504.63 2.047.359.49-.243.786-.795.834-1.551.05-.778.057-1.591.024-2.417l-.004-.163v-1.355l.175.1 25.987 15.004.059.033v54.068c0 .569-.198.996-.559 1.204a1.002 1.002 0 0 1-.506.131' fill='#607D8B'/><path d='M145.685 163.161l24.115 13.922-25.978 14.998-1.462-.307c-6.534-2.17-13.628-3.728-21.019-4.616-4.365-.524-8.663 1.096-9.598 3.62a2.746 2.746 0 0 0-.011 1.928c1.538 4.267 4.236 8.363 7.995 12.135l.532.845-25.977 14.997-24.115-13.922 75.518-43.6' fill='#FFF'/><path d='M94.282 220.818l-.059-.033-24.29-14.024.175-.101 75.577-43.634.058.033 24.29 14.024-26.191 15.122-.045-.01-1.461-.307c-6.549-2.174-13.613-3.725-21.009-4.614a13.744 13.744 0 0 0-1.638-.097c-3.758 0-7.054 1.531-7.837 3.642a2.62 2.62 0 0 0-.01 1.848c1.535 4.258 4.216 8.326 7.968 12.091l.016.021.526.835.006.01.064.102-.105.061-25.977 14.998-.058.033zm-23.881-14.057l23.881 13.788 24.802-14.32c.546-.315.846-.489 1.017-.575l-.466-.74c-3.771-3.787-6.467-7.881-8.013-12.168a2.851 2.851 0 0 1 .011-2.008c.815-2.199 4.203-3.795 8.056-3.795.557 0 1.117.033 1.666.099 7.412.891 14.491 2.445 21.041 4.621.836.175 1.215.254 1.39.304l25.78-14.884-23.881-13.788-75.284 43.466z' fill='#607D8B'/><path d='M167.23 125.979v50.871l-27.321 15.773-6.461-14.167c-.91-1.996-3.428-1.738-5.624.574a10.238 10.238 0 0 0-2.33 4.018l-6.46 21.628-27.322 15.774v-50.871l75.518-43.6' fill='#FFF'/><path d='M91.712 220.567a.127.127 0 0 1-.059-.016.118.118 0 0 1-.058-.101v-50.871c0-.042.023-.08.058-.101l75.519-43.6a.117.117 0 0 1 .175.101v50.871c0 .041-.023.08-.059.1l-27.321 15.775a.118.118 0 0 1-.094.01.12.12 0 0 1-.071-.063l-6.46-14.168c-.375-.822-1.062-1.275-1.934-1.275-1.089 0-2.364.686-3.5 1.881a10.206 10.206 0 0 0-2.302 3.972l-6.46 21.627a.118.118 0 0 1-.054.068L91.77 220.551a.12.12 0 0 1-.058.016zm.117-50.92v50.601l27.106-15.65 6.447-21.583a10.286 10.286 0 0 1 2.357-4.065c1.18-1.242 2.517-1.954 3.669-1.954.969 0 1.731.501 2.146 1.411l6.407 14.051 27.152-15.676v-50.601l-75.284 43.466z' fill='#607D8B'/><path d='M168.543 126.213v50.87l-27.322 15.774-6.46-14.168c-.91-1.995-3.428-1.738-5.624.574a10.248 10.248 0 0 0-2.33 4.019l-6.461 21.627-27.321 15.774v-50.87l75.518-43.6' fill='#FFF'/><path d='M93.025 220.8a.123.123 0 0 1-.059-.015.12.12 0 0 1-.058-.101v-50.871c0-.042.023-.08.058-.101l75.518-43.6a.112.112 0 0 1 .117 0c.036.02.059.059.059.1v50.871a.116.116 0 0 1-.059.101l-27.321 15.774a.111.111 0 0 1-.094.01.115.115 0 0 1-.071-.062l-6.46-14.168c-.375-.823-1.062-1.275-1.935-1.275-1.088 0-2.363.685-3.499 1.881a10.19 10.19 0 0 0-2.302 3.971l-6.461 21.628a.108.108 0 0 1-.053.067l-27.322 15.775a.12.12 0 0 1-.058.015zm.117-50.919v50.6l27.106-15.649 6.447-21.584a10.293 10.293 0 0 1 2.357-4.065c1.179-1.241 2.516-1.954 3.668-1.954.969 0 1.732.502 2.147 1.412l6.407 14.051 27.152-15.676v-50.601l-75.284 43.466z' fill='#607D8B'/><path d='M169.8 177.083l-27.322 15.774-6.46-14.168c-.91-1.995-3.428-1.738-5.625.574a10.246 10.246 0 0 0-2.329 4.019l-6.461 21.627-27.321 15.774v-50.87l75.518-43.6v50.87z' fill='#FAFAFA'/><path d='M94.282 220.917a.234.234 0 0 1-.234-.233v-50.871c0-.083.045-.161.117-.202l75.518-43.601a.234.234 0 1 1 .35.202v50.871a.233.233 0 0 1-.116.202l-27.322 15.775a.232.232 0 0 1-.329-.106l-6.461-14.168c-.36-.789-.992-1.206-1.828-1.206-1.056 0-2.301.672-3.415 1.844a10.099 10.099 0 0 0-2.275 3.924l-6.46 21.628a.235.235 0 0 1-.107.136l-27.322 15.774a.23.23 0 0 1-.116.031zm.233-50.969v50.331l26.891-15.525 6.434-21.539a10.41 10.41 0 0 1 2.384-4.112c1.201-1.265 2.569-1.991 3.753-1.991 1.018 0 1.818.526 2.253 1.48l6.354 13.934 26.982-15.578v-50.331l-75.051 43.331z' fill='#607D8B'/><path d='M109.894 199.943c-1.774 0-3.241-.725-4.244-2.12a.224.224 0 0 1 .023-.294.233.233 0 0 1 .301-.023c.78.547 1.705.827 2.75.827 1.323 0 2.754-.439 4.256-1.306 5.311-3.067 9.631-10.518 9.631-16.611 0-1.927-.442-3.56-1.278-4.724a.232.232 0 0 1 .323-.327c1.671 1.172 2.591 3.381 2.591 6.219 0 6.242-4.426 13.863-9.865 17.003-1.574.908-3.084 1.356-4.488 1.356zm-2.969-1.542c.813.651 1.82.877 2.968.877h.001c1.321 0 2.753-.327 4.254-1.194 5.311-3.067 9.632-10.463 9.632-16.556 0-1.979-.463-3.599-1.326-4.761.411 1.035.625 2.275.625 3.635 0 6.243-4.426 13.883-9.865 17.023-1.574.909-3.084 1.317-4.49 1.317-.641 0-1.243-.149-1.799-.341z' fill='#607D8B'/><path d='M113.097 197.23c5.384-3.108 9.748-10.636 9.748-16.814 0-2.051-.483-3.692-1.323-4.86-1.784-1.252-4.374-1.194-7.257.47-5.384 3.108-9.748 10.636-9.748 16.814 0 2.051.483 3.692 1.323 4.86 1.784 1.252 4.374 1.194 7.257-.47' fill='#FAFAFA'/><path d='M108.724 198.614c-1.142 0-2.158-.213-3.019-.817-.021-.014-.04.014-.055-.007-.894-1.244-1.367-2.948-1.367-4.973 0-6.242 4.426-13.864 9.865-17.005 1.574-.908 3.084-1.363 4.49-1.363 1.142 0 2.158.309 3.018.913a.23.23 0 0 1 .056.056c.894 1.244 1.367 2.972 1.367 4.997 0 6.243-4.426 13.783-9.865 16.923-1.574.909-3.084 1.276-4.49 1.276zm-2.718-1.109c.774.532 1.688.776 2.718.776 1.323 0 2.754-.413 4.256-1.28 5.311-3.066 9.631-10.505 9.631-16.598 0-1.909-.434-3.523-1.255-4.685-.774-.533-1.688-.799-2.718-.799-1.323 0-2.755.441-4.256 1.308-5.311 3.066-9.631 10.506-9.631 16.599 0 1.909.434 3.517 1.255 4.679z' fill='#607D8B'/><path d='M149.318 114.262l-9.984 8.878 15.893 11.031 5.589-6.112-11.498-13.797' fill='#FAFAFA'/><path d='M169.676 120.84l-9.748 5.627c-3.642 2.103-9.528 2.113-13.147.024-3.62-2.089-3.601-5.488.041-7.591l9.495-5.608-6.729-3.885-81.836 47.071 45.923 26.514 3.081-1.779c.631-.365.869-.898.618-1.39-2.357-4.632-2.593-9.546-.683-14.262 5.638-13.92 24.509-24.815 48.618-28.07 8.169-1.103 16.68-.967 24.704.394.852.145 1.776.008 2.407-.357l3.081-1.778-25.825-14.91' fill='#FAFAFA'/><path d='M113.675 183.459a.47.47 0 0 1-.233-.062l-45.924-26.515a.468.468 0 0 1 .001-.809l81.836-47.071a.467.467 0 0 1 .466 0l6.729 3.885a.467.467 0 0 1-.467.809l-6.496-3.75-80.9 46.533 44.988 25.973 2.848-1.644c.192-.111.62-.409.435-.773-2.416-4.748-2.658-9.814-.7-14.65 2.806-6.927 8.885-13.242 17.582-18.263 8.657-4.998 19.518-8.489 31.407-10.094 8.198-1.107 16.79-.97 24.844.397.739.125 1.561.007 2.095-.301l2.381-1.374-25.125-14.506a.467.467 0 0 1 .467-.809l25.825 14.91a.467.467 0 0 1 0 .809l-3.081 1.779c-.721.417-1.763.575-2.718.413-7.963-1.351-16.457-1.486-24.563-.392-11.77 1.589-22.512 5.039-31.065 9.977-8.514 4.916-14.456 11.073-17.183 17.805-1.854 4.578-1.623 9.376.666 13.875.37.725.055 1.513-.8 2.006l-3.081 1.78a.476.476 0 0 1-.234.062' fill='#455A64'/><path d='M153.316 128.279c-2.413 0-4.821-.528-6.652-1.586-1.818-1.049-2.82-2.461-2.82-3.975 0-1.527 1.016-2.955 2.861-4.02l9.493-5.607a.233.233 0 1 1 .238.402l-9.496 5.609c-1.696.979-2.628 2.263-2.628 3.616 0 1.34.918 2.608 2.585 3.571 3.549 2.049 9.343 2.038 12.914-.024l9.748-5.628a.234.234 0 0 1 .234.405l-9.748 5.628c-1.858 1.072-4.296 1.609-6.729 1.609' fill='#607D8B'/><path d='M113.675 182.992l-45.913-26.508M113.675 183.342a.346.346 0 0 1-.175-.047l-45.913-26.508a.35.35 0 1 1 .35-.607l45.913 26.508a.35.35 0 0 1-.175.654' fill='#455A64'/><path d='M67.762 156.484v54.001c0 1.09.77 2.418 1.72 2.967l42.473 24.521c.95.549 1.72.11 1.72-.98v-54.001' fill='#FAFAFA'/><path d='M112.727 238.561c-.297 0-.62-.095-.947-.285l-42.473-24.521c-1.063-.613-1.895-2.05-1.895-3.27v-54.001a.35.35 0 1 1 .701 0v54.001c0 .96.707 2.18 1.544 2.663l42.473 24.522c.344.198.661.243.87.122.206-.119.325-.411.325-.799v-54.001a.35.35 0 1 1 .7 0v54.001c0 .655-.239 1.154-.675 1.406a1.235 1.235 0 0 1-.623.162' fill='#455A64'/><path d='M112.86 147.512h-.001c-2.318 0-4.499-.522-6.142-1.471-1.705-.984-2.643-2.315-2.643-3.749 0-1.445.952-2.791 2.68-3.788l12.041-6.953c1.668-.962 3.874-1.493 6.212-1.493 2.318 0 4.499.523 6.143 1.472 1.704.984 2.643 2.315 2.643 3.748 0 1.446-.952 2.791-2.68 3.789l-12.042 6.952c-1.668.963-3.874 1.493-6.211 1.493zm12.147-16.753c-2.217 0-4.298.497-5.861 1.399l-12.042 6.952c-1.502.868-2.33 1.998-2.33 3.182 0 1.173.815 2.289 2.293 3.142 1.538.889 3.596 1.378 5.792 1.378h.001c2.216 0 4.298-.497 5.861-1.399l12.041-6.953c1.502-.867 2.33-1.997 2.33-3.182 0-1.172-.814-2.288-2.292-3.142-1.539-.888-3.596-1.377-5.793-1.377z' fill='#607D8B'/><path d='M165.63 123.219l-5.734 3.311c-3.167 1.828-8.286 1.837-11.433.02-3.147-1.817-3.131-4.772.036-6.601l5.734-3.31 11.397 6.58' fill='#FAFAFA'/><path d='M154.233 117.448l9.995 5.771-4.682 2.704c-1.434.827-3.352 1.283-5.399 1.283-2.029 0-3.923-.449-5.333-1.263-1.29-.744-2-1.694-2-2.674 0-.991.723-1.955 2.036-2.713l5.383-3.108m0-.809l-5.734 3.31c-3.167 1.829-3.183 4.784-.036 6.601 1.568.905 3.623 1.357 5.684 1.357 2.077 0 4.159-.46 5.749-1.377l5.734-3.311-11.397-6.58M145.445 179.667c-1.773 0-3.241-.85-4.243-2.245-.067-.092-.057-.275.023-.356.08-.081.207-.12.3-.055.781.548 1.706.812 2.751.811 1.322 0 2.754-.446 4.256-1.313 5.31-3.066 9.631-10.522 9.631-16.615 0-1.927-.442-3.562-1.279-4.726a.235.235 0 0 1 .024-.301.232.232 0 0 1 .3-.027c1.67 1.172 2.59 3.38 2.59 6.219 0 6.242-4.425 13.987-9.865 17.127-1.573.908-3.083 1.481-4.488 1.481zM142.476 178c.814.651 1.82 1.002 2.969 1.002 1.322 0 2.753-.452 4.255-1.32 5.31-3.065 9.631-10.523 9.631-16.617 0-1.98-.463-3.63-1.325-4.793.411 1.035.624 2.26.624 3.62 0 6.242-4.425 13.875-9.865 17.015-1.573.909-3.084 1.376-4.489 1.376a5.49 5.49 0 0 1-1.8-.283z' fill='#607D8B'/><path d='M148.648 176.704c5.384-3.108 9.748-10.636 9.748-16.813 0-2.052-.483-3.693-1.322-4.861-1.785-1.252-4.375-1.194-7.258.471-5.383 3.108-9.748 10.636-9.748 16.813 0 2.051.484 3.692 1.323 4.86 1.785 1.253 4.374 1.195 7.257-.47' fill='#FAFAFA'/><path d='M144.276 178.276c-1.143 0-2.158-.307-3.019-.911a.217.217 0 0 1-.055-.054c-.895-1.244-1.367-2.972-1.367-4.997 0-6.241 4.425-13.875 9.865-17.016 1.573-.908 3.084-1.369 4.489-1.369 1.143 0 2.158.307 3.019.91a.24.24 0 0 1 .055.055c.894 1.244 1.367 2.971 1.367 4.997 0 6.241-4.425 13.875-9.865 17.016-1.573.908-3.084 1.369-4.489 1.369zm-2.718-1.172c.773.533 1.687.901 2.718.901 1.322 0 2.754-.538 4.256-1.405 5.31-3.066 9.631-10.567 9.631-16.661 0-1.908-.434-3.554-1.256-4.716-.774-.532-1.688-.814-2.718-.814-1.322 0-2.754.433-4.256 1.3-5.31 3.066-9.631 10.564-9.631 16.657 0 1.91.434 3.576 1.256 4.738z' fill='#607D8B'/><path d='M150.72 172.361l-.363-.295a24.105 24.105 0 0 0 2.148-3.128 24.05 24.05 0 0 0 1.977-4.375l.443.149a24.54 24.54 0 0 1-2.015 4.46 24.61 24.61 0 0 1-2.19 3.189M115.917 191.514l-.363-.294a24.174 24.174 0 0 0 2.148-3.128 24.038 24.038 0 0 0 1.976-4.375l.443.148a24.48 24.48 0 0 1-2.015 4.461 24.662 24.662 0 0 1-2.189 3.188M114 237.476V182.584 237.476' fill='#607D8B'/><g><path d='M81.822 37.474c.017-.135-.075-.28-.267-.392-.327-.188-.826-.21-1.109-.045l-6.012 3.471c-.131.076-.194.178-.191.285.002.132.002.461.002.578v.043l-.007.128-6.591 3.779c-.001 0-2.077 1.046-2.787 5.192 0 0-.912 6.961-.898 19.745.015 12.57.606 17.07 1.167 21.351.22 1.684 3.001 2.125 3.001 2.125.331.04.698-.027 1.08-.248l75.273-43.551c1.808-1.069 2.667-3.719 3.056-6.284 1.213-7.99 1.675-32.978-.275-39.878-.196-.693-.51-1.083-.868-1.282l-2.086-.79c-.727.028-1.416.467-1.534.535L82.032 37.072l-.21.402' fill='#FFF'/><path d='M144.311 1.701l2.085.79c.358.199.672.589.868 1.282 1.949 6.9 1.487 31.887.275 39.878-.39 2.565-1.249 5.215-3.056 6.284L69.21 93.486a1.78 1.78 0 0 1-.896.258l-.183-.011c0 .001-2.782-.44-3.003-2.124-.56-4.282-1.151-8.781-1.165-21.351-.015-12.784.897-19.745.897-19.745.71-4.146 2.787-5.192 2.787-5.192l6.591-3.779.007-.128v-.043c0-.117 0-.446-.002-.578-.003-.107.059-.21.191-.285l6.012-3.472a.98.98 0 0 1 .481-.11c.218 0 .449.053.627.156.193.112.285.258.268.392l.211-.402 60.744-34.836c.117-.068.806-.507 1.534-.535m0-.997l-.039.001c-.618.023-1.283.244-1.974.656l-.021.012-60.519 34.706a2.358 2.358 0 0 0-.831-.15c-.365 0-.704.084-.98.244l-6.012 3.471c-.442.255-.699.69-.689 1.166l.001.15-6.08 3.487c-.373.199-2.542 1.531-3.29 5.898l-.006.039c-.009.07-.92 7.173-.906 19.875.014 12.62.603 17.116 1.172 21.465l.002.015c.308 2.355 3.475 2.923 3.836 2.98l.034.004c.101.013.204.019.305.019a2.77 2.77 0 0 0 1.396-.392l75.273-43.552c1.811-1.071 2.999-3.423 3.542-6.997 1.186-7.814 1.734-33.096-.301-40.299-.253-.893-.704-1.527-1.343-1.882l-.132-.062-2.085-.789a.973.973 0 0 0-.353-.065' fill='#455A64'/><path d='M128.267 11.565l1.495.434-56.339 32.326' fill='#FFF'/><path d='M74.202 90.545a.5.5 0 0 1-.25-.931l18.437-10.645a.499.499 0 1 1 .499.864L74.451 90.478l-.249.067M75.764 42.654l-.108-.062.046-.171 5.135-2.964.17.045-.045.171-5.135 2.964-.063.017M70.52 90.375V46.421l.063-.036L137.84 7.554v43.954l-.062.036L70.52 90.375zm.25-43.811v43.38l66.821-38.579V7.985L70.77 46.564z' fill='#607D8B'/><path d='M86.986 83.182c-.23.149-.612.384-.849.523l-11.505 6.701c-.237.139-.206.252.068.252h.565c.275 0 .693-.113.93-.252L87.7 83.705c.237-.139.428-.253.425-.256a11.29 11.29 0 0 1-.006-.503c0-.274-.188-.377-.418-.227l-.715.463' fill='#607D8B'/><path d='M75.266 90.782H74.7c-.2 0-.316-.056-.346-.166-.03-.11.043-.217.215-.317l11.505-6.702c.236-.138.615-.371.844-.519l.715-.464a.488.488 0 0 1 .266-.089c.172 0 .345.13.345.421 0 .214.001.363.003.437l.006.004-.004.069c-.003.075-.003.075-.486.356l-11.505 6.702a2.282 2.282 0 0 1-.992.268zm-.6-.25l.034.001h.566c.252 0 .649-.108.866-.234l11.505-6.702c.168-.098.294-.173.361-.214-.004-.084-.004-.218-.004-.437l-.095-.171-.131.049-.714.463c-.232.15-.616.386-.854.525l-11.505 6.702-.029.018z' fill='#607D8B'/><path d='M75.266 89.871H74.7c-.2 0-.316-.056-.346-.166-.03-.11.043-.217.215-.317l11.505-6.702c.258-.151.694-.268.993-.268h.565c.2 0 .316.056.346.166.03.11-.043.217-.215.317l-11.505 6.702a2.282 2.282 0 0 1-.992.268zm-.6-.25l.034.001h.566c.252 0 .649-.107.866-.234l11.505-6.702.03-.018-.035-.001h-.565c-.252 0-.649.108-.867.234l-11.505 6.702-.029.018zM74.37 90.801v-1.247 1.247' fill='#607D8B'/><path d='M68.13 93.901c-.751-.093-1.314-.737-1.439-1.376-.831-4.238-1.151-8.782-1.165-21.352-.015-12.784.897-19.745.897-19.745.711-4.146 2.787-5.192 2.787-5.192l74.859-43.219c.223-.129 2.487-1.584 3.195.923 1.95 6.9 1.488 31.887.275 39.878-.389 2.565-1.248 5.215-3.056 6.283L69.21 93.653c-.382.221-.749.288-1.08.248 0 0-2.781-.441-3.001-2.125-.561-4.281-1.152-8.781-1.167-21.351-.014-12.784.898-19.745.898-19.745.71-4.146 2.787-5.191 2.787-5.191l6.598-3.81.871-.119 6.599-3.83.046-.461L68.13 93.901' fill='#FAFAFA'/><path d='M68.317 94.161l-.215-.013h-.001l-.244-.047c-.719-.156-2.772-.736-2.976-2.292-.568-4.34-1.154-8.813-1.168-21.384-.014-12.654.891-19.707.9-19.777.725-4.231 2.832-5.338 2.922-5.382l6.628-3.827.87-.119 6.446-3.742.034-.334a.248.248 0 0 1 .273-.223.248.248 0 0 1 .223.272l-.059.589-6.752 3.919-.87.118-6.556 3.785c-.031.016-1.99 1.068-2.666 5.018-.007.06-.908 7.086-.894 19.702.014 12.539.597 16.996 1.161 21.305.091.691.689 1.154 1.309 1.452a1.95 1.95 0 0 1-.236-.609c-.781-3.984-1.155-8.202-1.17-21.399-.014-12.653.891-19.707.9-19.777.725-4.231 2.832-5.337 2.922-5.382-.004.001 74.444-42.98 74.846-43.212l.028-.017c.904-.538 1.72-.688 2.36-.433.555.221.949.733 1.172 1.52 2.014 7.128 1.46 32.219.281 39.983-.507 3.341-1.575 5.515-3.175 6.462L69.335 93.869a2.023 2.023 0 0 1-1.018.292zm-.147-.507c.293.036.604-.037.915-.217l75.273-43.551c1.823-1.078 2.602-3.915 2.934-6.106 1.174-7.731 1.731-32.695-.268-39.772-.178-.631-.473-1.032-.876-1.192-.484-.193-1.166-.052-1.921.397l-.034.021-74.858 43.218c-.031.017-1.989 1.069-2.666 5.019-.007.059-.908 7.085-.894 19.702.015 13.155.386 17.351 1.161 21.303.09.461.476.983 1.037 1.139.114.025.185.037.196.039h.001z' fill='#455A64'/><path d='M69.317 68.982c.489-.281.885-.056.885.505 0 .56-.396 1.243-.885 1.525-.488.282-.884.057-.884-.504 0-.56.396-1.243.884-1.526' fill='#FFF'/><path d='M68.92 71.133c-.289 0-.487-.228-.487-.625 0-.56.396-1.243.884-1.526a.812.812 0 0 1 .397-.121c.289 0 .488.229.488.626 0 .56-.396 1.243-.885 1.525a.812.812 0 0 1-.397.121m.794-2.459a.976.976 0 0 0-.49.147c-.548.317-.978 1.058-.978 1.687 0 .486.271.812.674.812a.985.985 0 0 0 .491-.146c.548-.317.978-1.057.978-1.687 0-.486-.272-.813-.675-.813' fill='#8097A2'/><path d='M68.92 70.947c-.271 0-.299-.307-.299-.439 0-.491.361-1.116.79-1.363a.632.632 0 0 1 .303-.096c.272 0 .301.306.301.438 0 .491-.363 1.116-.791 1.364a.629.629 0 0 1-.304.096m.794-2.086a.812.812 0 0 0-.397.121c-.488.283-.884.966-.884 1.526 0 .397.198.625.487.625a.812.812 0 0 0 .397-.121c.489-.282.885-.965.885-1.525 0-.397-.199-.626-.488-.626' fill='#8097A2'/><path d='M69.444 85.35c.264-.152.477-.031.477.272 0 .303-.213.67-.477.822-.263.153-.477.031-.477-.271 0-.302.214-.671.477-.823' fill='#FFF'/><path d='M69.23 86.51c-.156 0-.263-.123-.263-.337 0-.302.214-.671.477-.823a.431.431 0 0 1 .214-.066c.156 0 .263.124.263.338 0 .303-.213.67-.477.822a.431.431 0 0 1-.214.066m.428-1.412c-.1 0-.203.029-.307.09-.32.185-.57.618-.57.985 0 .309.185.524.449.524a.63.63 0 0 0 .308-.09c.32-.185.57-.618.57-.985 0-.309-.185-.524-.45-.524' fill='#8097A2'/><path d='M69.23 86.322l-.076-.149c0-.235.179-.544.384-.661l.12-.041.076.151c0 .234-.179.542-.383.66l-.121.04m.428-1.038a.431.431 0 0 0-.214.066c-.263.152-.477.521-.477.823 0 .214.107.337.263.337a.431.431 0 0 0 .214-.066c.264-.152.477-.519.477-.822 0-.214-.107-.338-.263-.338' fill='#8097A2'/><path d='M139.278 7.769v43.667L72.208 90.16V46.493l67.07-38.724' fill='#455A64'/><path d='M72.083 90.375V46.421l.063-.036 67.257-38.831v43.954l-.062.036-67.258 38.831zm.25-43.811v43.38l66.821-38.579V7.985L72.333 46.564z' fill='#607D8B'/></g><path d='M125.737 88.647l-7.639 3.334V84l-11.459 4.713v8.269L99 100.315l13.369 3.646 13.368-15.314' fill='#455A64'/></g></svg>";
function RotateInstructions() {
this.loadIcon_();
var overlay = document.createElement('div');
@@ -4030,7 +4428,7 @@ RotateInstructions.prototype.update = function () {
}
};
RotateInstructions.prototype.loadIcon_ = function () {
- this.icon = base64('image/svg+xml', rotateInstructionsAsset);
+ this.icon = dataUri('image/svg+xml', rotateInstructionsAsset);
};
var DEFAULT_VIEWER = 'CardboardV1';
var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';
@@ -4175,7 +4573,7 @@ ViewerSelector.prototype.createButton_ = function (label, onclick) {
};
var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
function unwrapExports$$1 (x) {
- return x && x.__esModule ? x['default'] : x;
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function createCommonjsModule$$1(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
@@ -4878,493 +5276,143 @@ return CardboardVRDisplay;
});
var CardboardVRDisplay = unwrapExports(cardboardVrDisplay);
-var PolyfilledXRDevice = function (_EventTarget) {
- inherits(PolyfilledXRDevice, _EventTarget);
- function PolyfilledXRDevice(global) {
- classCallCheck(this, PolyfilledXRDevice);
- var _this = possibleConstructorReturn(this, (PolyfilledXRDevice.__proto__ || Object.getPrototypeOf(PolyfilledXRDevice)).call(this));
- _this.global = global;
- _this.onWindowResize = _this.onWindowResize.bind(_this);
- _this.global.window.addEventListener('resize', _this.onWindowResize);
- _this.environmentBlendMode = 'opaque';
- return _this;
- }
- createClass(PolyfilledXRDevice, [{
- key: 'onBaseLayerSet',
- value: function onBaseLayerSet(sessionId, layer) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'supportsSession',
- value: function supportsSession() {
- throw new Error('Not implemented');
- }
- }, {
- key: 'requestSession',
- value: function requestSession() {
- return new Promise(function ($return, $error) {
- return $error(new Error('Not implemented'));
- }.bind(this));
- }
- }, {
- key: 'requestAnimationFrame',
- value: function requestAnimationFrame(callback) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'onFrameStart',
- value: function onFrameStart(sessionId) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'onFrameEnd',
- value: function onFrameEnd(sessionId) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'requestStageBounds',
- value: function requestStageBounds() {
- throw new Error('Not implemented');
- }
- }, {
- key: 'requestFrameOfReferenceTransform',
- value: function requestFrameOfReferenceTransform(type, options) {
- return new Promise(function ($return, $error) {
- return $return(undefined);
- }.bind(this));
- }
- }, {
- key: 'cancelAnimationFrame',
- value: function cancelAnimationFrame(handle) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'endSession',
- value: function endSession(sessionId) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'getViewport',
- value: function getViewport(sessionId, eye, layer, target) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'getProjectionMatrix',
- value: function getProjectionMatrix(eye) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'getBasePoseMatrix',
- value: function getBasePoseMatrix() {
- throw new Error('Not implemented');
- }
- }, {
- key: 'getBaseViewMatrix',
- value: function getBaseViewMatrix(eye) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'getInputSources',
- value: function getInputSources() {
- throw new Error('Not implemented');
- }
- }, {
- key: 'getInputPose',
- value: function getInputPose(inputSource, coordinateSystem) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'onWindowResize',
- value: function onWindowResize() {
- this.onWindowResize();
- }
- }, {
- key: 'depthNear',
- get: function get$$1() {
- throw new Error('Not implemented');
- }
- ,
- set: function set$$1(val) {
- throw new Error('Not implemented');
- }
- }, {
- key: 'depthFar',
- get: function get$$1() {
- throw new Error('Not implemented');
- }
- ,
- set: function set$$1(val) {
- throw new Error('Not implemented');
- }
- }]);
- return PolyfilledXRDevice;
-}(EventTarget);
-
-function create$2() {
- var out = new ARRAY_TYPE(9);
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- out[4] = 1;
- out[5] = 0;
- out[6] = 0;
- out[7] = 0;
- out[8] = 1;
- return out;
-}
-
-function create$3() {
- var out = new ARRAY_TYPE(4);
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
- return out;
-}
-function clone$3(a) {
- var out = new ARRAY_TYPE(4);
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
- out[3] = a[3];
- 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) {
- var x = a[0];
- var y = a[1];
- var z = a[2];
- var w = a[3];
- var 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;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-var forEach$1 = function () {
- var vec = create$3();
- return function (a, stride, offset, count, fn, arg) {
- var i = void 0,
- l = void 0;
- 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() {
- var out = new ARRAY_TYPE(4);
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- out[3] = 1;
- return out;
-}
-
-function setAxisAngle(out, axis, rad) {
- rad = rad * 0.5;
- var 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) {
- var ax = a[0],
- ay = a[1],
- az = a[2],
- aw = a[3];
- var 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) {
- var ax = a[0],
- ay = a[1],
- az = a[2],
- aw = a[3];
- var bx = b[0],
- by = b[1],
- bz = b[2],
- bw = b[3];
- var omega = void 0,
- cosom = void 0,
- sinom = void 0,
- scale0 = void 0,
- scale1 = void 0;
- 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 > 0.000001) {
- 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) {
- var a0 = a[0],
- a1 = a[1],
- a2 = a[2],
- a3 = a[3];
- var dot$$1 = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
- var 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) {
- var fTrace = m[0] + m[4] + m[8];
- var fRoot = void 0;
- 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 {
- var i = 0;
- if (m[4] > m[0]) i = 1;
- if (m[8] > m[i * 3 + i]) i = 2;
- var j = (i + 1) % 3;
- var 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;
+class XRDevice extends EventTarget {
+ constructor(global) {
+ super();
+ this.global = global;
+ this.onWindowResize = this.onWindowResize.bind(this);
+ this.global.window.addEventListener('resize', this.onWindowResize);
+ this.environmentBlendMode = 'opaque';
+ }
+ get depthNear() { throw new Error('Not implemented'); }
+ set depthNear(val) { throw new Error('Not implemented'); }
+ get depthFar() { throw new Error('Not implemented'); }
+ set depthFar(val) { throw new Error('Not implemented'); }
+ onBaseLayerSet(sessionId, layer) { throw new Error('Not implemented'); }
+ onInlineVerticalFieldOfViewSet(sessionId, value) { throw new Error('Not implemented'); }
+ supportsSession(mode) { throw new Error('Not implemented'); }
+ async requestSession(mode) { throw new Error('Not implemented'); }
+ requestAnimationFrame(callback) { throw new Error('Not implemented'); }
+ onFrameStart(sessionId) { throw new Error('Not implemented'); }
+ onFrameEnd(sessionId) { throw new Error('Not implemented'); }
+ requestStageBounds() { throw new Error('Not implemented'); }
+ async requestFrameOfReferenceTransform(type, options) {
+ return undefined;
+ }
+ cancelAnimationFrame(handle) { throw new Error('Not implemented'); }
+ endSession(sessionId) { throw new Error('Not implemented'); }
+ getViewport(sessionId, eye, layer, target) { throw new Error('Not implemented'); }
+ getProjectionMatrix(eye) { throw new Error('Not implemented'); }
+ getBasePoseMatrix() { throw new Error('Not implemented'); }
+ getBaseViewMatrix(eye) { throw new Error('Not implemented'); }
+ getInputSources() { throw new Error('Not implemented'); }
+ getInputPose(inputSource, coordinateSystem, poseType) { throw new Error('Not implemented'); }
+ onWindowResize() {
+ this.onWindowResize();
}
- return out;
}
-function fromEuler(out, x, y, z) {
- var halfToRad = 0.5 * Math.PI / 180.0;
- x *= halfToRad;
- y *= halfToRad;
- z *= halfToRad;
- var sx = Math.sin(x);
- var cx = Math.cos(x);
- var sy = Math.sin(y);
- var cy = Math.cos(y);
- var sz = Math.sin(z);
- var 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;
-}
-
-var clone$4 = clone$3;
-
-var copy$4 = copy$3;
-
-
-
-
-
-
-
-
-
-var normalize$2 = normalize$1;
-
-
-var rotationTo = function () {
- var tmpvec3 = create$1();
- var xUnitVec3 = fromValues$1(1, 0, 0);
- var yUnitVec3 = fromValues$1(0, 1, 0);
- return function (out, a, b) {
- var 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);
+let oculusTouch = {
+ mapping: 'xr-standard',
+ id: 'oculus-touch',
+ buttons: {
+ length: 6,
+ 0: 1,
+ 1: 0,
+ 2: 2,
+ 3: null,
+ 4: 3,
+ 5: 4
+ },
+ gripTransform: {
+ position: [0, -0.02, 0.04, 1],
+ orientation: [Math.PI * 0.11, 0, 0, 1]
+ }
+};
+let windowsMixedReality = {
+ mapping: 'xr-standard',
+ id: 'windows-mixed-reality',
+ buttons: {
+ length: 4,
+ 0: 1,
+ 1: 0,
+ 2: 2,
+ 3: 4,
+ },
+ gripTransform: {
+ position: [0, -0.02, 0.04, 1],
+ orientation: [Math.PI * 0.11, 0, 0, 1]
+ }
+};
+let GamepadMappings = {
+ "Oculus Touch (Right)": oculusTouch,
+ "Oculus Touch (Left)": oculusTouch,
+ "Oculus Go Controller": {
+ mapping: 'xr-standard',
+ id: 'oculus-go',
+ buttons: {
+ 0: 1,
+ 1: 0,
+ },
+ gripTransform: {
+ orientation: [Math.PI * 0.11, 0, 0, 1]
}
- };
-}();
-var sqlerp = function () {
- var temp1 = create$4();
- var 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;
- };
-}();
-var setAxes = function () {
- var 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));
- };
-}();
-
-var HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15);
-var HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15);
-var ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25);
-var WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05);
-var ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08);
-var ELBOW_BEND_RATIO = 0.4;
-var EXTENSION_RATIO_WEIGHT = 0.4;
-var MIN_ANGULAR_SPEED = 0.61;
-var MIN_ANGLE_DELTA = 0.175;
-var MIN_EXTENSION_COS = 0.12;
-var MAX_EXTENSION_COS = 0.87;
-var RAD_TO_DEG = 180 / Math.PI;
+ },
+ "Windows Mixed Reality (Right)": windowsMixedReality,
+ "Windows Mixed Reality (Left)": windowsMixedReality,
+};
+
+const HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15);
+const HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15);
+const ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25);
+const WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05);
+const ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08);
+const ELBOW_BEND_RATIO = 0.4;
+const EXTENSION_RATIO_WEIGHT = 0.4;
+const MIN_ANGULAR_SPEED = 0.61;
+const MIN_ANGLE_DELTA = 0.175;
+const MIN_EXTENSION_COS = 0.12;
+const MAX_EXTENSION_COS = 0.87;
+const RAD_TO_DEG = 180 / Math.PI;
function eulerFromQuaternion(out, q, order) {
function clamp(value, min$$1, max$$1) {
- return value < min$$1 ? min$$1 : value > max$$1 ? max$$1 : value;
+ return (value < min$$1 ? min$$1 : (value > max$$1 ? max$$1 : value));
}
var sqx = q[0] * q[0];
var sqy = q[1] * q[1];
var sqz = q[2] * q[2];
var sqw = q[3] * q[3];
- if (order === 'XYZ') {
- out[0] = Math.atan2(2 * (q[0] * q[3] - q[1] * q[2]), sqw - sqx - sqy + sqz);
- out[1] = Math.asin(clamp(2 * (q[0] * q[2] + q[1] * q[3]), -1, 1));
- out[2] = Math.atan2(2 * (q[2] * q[3] - q[0] * q[1]), sqw + sqx - sqy - sqz);
- } else if (order === 'YXZ') {
- out[0] = Math.asin(clamp(2 * (q[0] * q[3] - q[1] * q[2]), -1, 1));
- out[1] = Math.atan2(2 * (q[0] * q[2] + q[1] * q[3]), sqw - sqx - sqy + sqz);
- out[2] = Math.atan2(2 * (q[0] * q[1] + q[2] * q[3]), sqw - sqx + sqy - sqz);
- } else if (order === 'ZXY') {
- out[0] = Math.asin(clamp(2 * (q[0] * q[3] + q[1] * q[2]), -1, 1));
- out[1] = Math.atan2(2 * (q[1] * q[3] - q[2] * q[0]), sqw - sqx - sqy + sqz);
- out[2] = Math.atan2(2 * (q[2] * q[3] - q[0] * q[1]), sqw - sqx + sqy - sqz);
- } else if (order === 'ZYX') {
- out[0] = Math.atan2(2 * (q[0] * q[3] + q[2] * q[1]), sqw - sqx - sqy + sqz);
- out[1] = Math.asin(clamp(2 * (q[1] * q[3] - q[0] * q[2]), -1, 1));
- out[2] = Math.atan2(2 * (q[0] * q[1] + q[2] * q[3]), sqw + sqx - sqy - sqz);
- } else if (order === 'YZX') {
- out[0] = Math.atan2(2 * (q[0] * q[3] - q[2] * q[1]), sqw - sqx + sqy - sqz);
- out[1] = Math.atan2(2 * (q[1] * q[3] - q[0] * q[2]), sqw + sqx - sqy - sqz);
- out[2] = Math.asin(clamp(2 * (q[0] * q[1] + q[2] * q[3]), -1, 1));
- } else if (order === 'XZY') {
- out[0] = Math.atan2(2 * (q[0] * q[3] + q[1] * q[2]), sqw - sqx + sqy - sqz);
- out[1] = Math.atan2(2 * (q[0] * q[2] + q[1] * q[3]), sqw + sqx - sqy - sqz);
- out[2] = Math.asin(clamp(2 * (q[2] * q[3] - q[0] * q[1]), -1, 1));
+ if ( order === 'XYZ' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[1] * q[2] ), ( sqw - sqx - sqy + sqz ) );
+ out[1] = Math.asin( clamp( 2 * ( q[0] * q[2] + q[1] * q[3] ), -1, 1 ) );
+ out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw + sqx - sqy - sqz ) );
+ } else if ( order === 'YXZ' ) {
+ out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] - q[1] * q[2] ), -1, 1 ) );
+ out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw - sqx - sqy + sqz ) );
+ out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw - sqx + sqy - sqz ) );
+ } else if ( order === 'ZXY' ) {
+ out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] + q[1] * q[2] ), -1, 1 ) );
+ out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[2] * q[0] ), ( sqw - sqx - sqy + sqz ) );
+ out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw - sqx + sqy - sqz ) );
+ } else if ( order === 'ZYX' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[2] * q[1] ), ( sqw - sqx - sqy + sqz ) );
+ out[1] = Math.asin( clamp( 2 * ( q[1] * q[3] - q[0] * q[2] ), -1, 1 ) );
+ out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw + sqx - sqy - sqz ) );
+ } else if ( order === 'YZX' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[2] * q[1] ), ( sqw - sqx + sqy - sqz ) );
+ out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[0] * q[2] ), ( sqw + sqx - sqy - sqz ) );
+ out[2] = Math.asin( clamp( 2 * ( q[0] * q[1] + q[2] * q[3] ), -1, 1 ) );
+ } else if ( order === 'XZY' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[1] * q[2] ), ( sqw - sqx + sqy - sqz ) );
+ out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw + sqx - sqy - sqz ) );
+ out[2] = Math.asin( clamp( 2 * ( q[2] * q[3] - q[0] * q[1] ), -1, 1 ) );
} else {
console.log('No order given for quaternion to euler conversion.');
return;
}
}
-var OrientationArmModel = function () {
- function OrientationArmModel() {
- classCallCheck(this, OrientationArmModel);
+class OrientationArmModel {
+ constructor() {
this.hand = 'right';
this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED;
this.controllerQ = create$4();
@@ -5378,115 +5426,196 @@ var OrientationArmModel = function () {
this.rootQ = create$4();
this.position = create$1();
}
- createClass(OrientationArmModel, [{
- key: 'setHandedness',
- value: function setHandedness(hand) {
- if (this.hand != hand) {
- this.hand = hand;
- if (this.hand == 'left') {
- this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED;
- } else {
- this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED;
- }
- }
- }
- }, {
- key: 'update',
- value: function update(controllerOrientation, headPoseMatrix) {
- this.time = now$1();
- if (controllerOrientation) {
- copy$4(this.lastControllerQ, this.controllerQ);
- copy$4(this.controllerQ, controllerOrientation);
- }
- if (headPoseMatrix) {
- getTranslation(this.headPos, headPoseMatrix);
- getRotation(this.headQ, headPoseMatrix);
- }
- var headYawQ = this.getHeadYawOrientation_();
- var angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ);
- var timeDelta = (this.time - this.lastTime) / 1000;
- var controllerAngularSpeed = angleDelta / timeDelta;
- if (controllerAngularSpeed > MIN_ANGULAR_SPEED) {
- slerp(this.rootQ, this.rootQ, headYawQ, Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0));
+ setHandedness(hand) {
+ if (this.hand != hand) {
+ this.hand = hand;
+ if (this.hand == 'left') {
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED;
} else {
- copy$4(this.rootQ, headYawQ);
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED;
}
- var controllerForward = fromValues$1(0, 0, -1.0);
- transformQuat(controllerForward, controllerForward, this.controllerQ);
- var controllerDotY = dot(controllerForward, [0, 1, 0]);
- var extensionRatio = this.clamp_((controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0);
- var controllerCameraQ = clone$4(this.rootQ);
- invert$2(controllerCameraQ, controllerCameraQ);
- multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ);
- var elbowPos = this.elbowPos;
- copy$1(elbowPos, this.headPos);
- add$1(elbowPos, elbowPos, this.headElbowOffset);
- var elbowOffset = clone$1(ARM_EXTENSION_OFFSET);
- scale$1(elbowOffset, elbowOffset, extensionRatio);
- add$1(elbowPos, elbowPos, elbowOffset);
- var totalAngle = this.quatAngle_(controllerCameraQ, create$4());
- var totalAngleDeg = totalAngle * RAD_TO_DEG;
- var lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);var elbowRatio = ELBOW_BEND_RATIO;
- var wristRatio = 1 - ELBOW_BEND_RATIO;
- var lerpValue = lerpSuppression * (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT);
- var wristQ = create$4();
- slerp(wristQ, wristQ, controllerCameraQ, lerpValue);
- var invWristQ = invert$2(create$4(), wristQ);
- var elbowQ = clone$4(controllerCameraQ);
- multiply$4(elbowQ, elbowQ, invWristQ);
- var wristPos = this.wristPos;
- copy$1(wristPos, WRIST_CONTROLLER_OFFSET);
- transformQuat(wristPos, wristPos, wristQ);
- add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET);
- transformQuat(wristPos, wristPos, elbowQ);
- add$1(wristPos, wristPos, elbowPos);
- var offset = clone$1(ARM_EXTENSION_OFFSET);
- scale$1(offset, offset, extensionRatio);
- add$1(this.position, this.wristPos, offset);
- transformQuat(this.position, this.position, this.rootQ);
- this.lastTime = this.time;
}
- }, {
- key: 'getPosition',
- value: function getPosition() {
- return this.position;
+ }
+ update(controllerOrientation, headPoseMatrix) {
+ this.time = now$1();
+ if (controllerOrientation) {
+ copy$4(this.lastControllerQ, this.controllerQ);
+ copy$4(this.controllerQ, controllerOrientation);
}
- }, {
- key: 'getHeadYawOrientation_',
- value: function getHeadYawOrientation_() {
- var headEuler = create$1();
- eulerFromQuaternion(headEuler, this.headQ, 'YXZ');
- var destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0);
- return destinationQ;
+ if (headPoseMatrix) {
+ getTranslation(this.headPos, headPoseMatrix);
+ getRotation(this.headQ, headPoseMatrix);
}
- }, {
- key: 'clamp_',
- value: function clamp_(value, min$$1, max$$1) {
- return Math.min(Math.max(value, min$$1), max$$1);
+ let headYawQ = this.getHeadYawOrientation_();
+ let angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ);
+ let timeDelta = (this.time - this.lastTime) / 1000;
+ let controllerAngularSpeed = angleDelta / timeDelta;
+ if (controllerAngularSpeed > MIN_ANGULAR_SPEED) {
+ slerp(this.rootQ, this.rootQ, headYawQ,
+ Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0));
+ } else {
+ copy$4(this.rootQ, headYawQ);
+ }
+ let controllerForward = fromValues$1(0, 0, -1.0);
+ transformQuat(controllerForward, controllerForward, this.controllerQ);
+ let controllerDotY = dot(controllerForward, [0, 1, 0]);
+ let extensionRatio = this.clamp_(
+ (controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0);
+ let controllerCameraQ = clone$4(this.rootQ);
+ invert$2(controllerCameraQ, controllerCameraQ);
+ multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ);
+ let elbowPos = this.elbowPos;
+ copy$1(elbowPos, this.headPos);
+ add$1(elbowPos, elbowPos, this.headElbowOffset);
+ let elbowOffset = clone$1(ARM_EXTENSION_OFFSET);
+ scale$1(elbowOffset, elbowOffset, extensionRatio);
+ add$1(elbowPos, elbowPos, elbowOffset);
+ let totalAngle = this.quatAngle_(controllerCameraQ, create$4());
+ let totalAngleDeg = totalAngle * RAD_TO_DEG;
+ let lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);let elbowRatio = ELBOW_BEND_RATIO;
+ let wristRatio = 1 - ELBOW_BEND_RATIO;
+ let lerpValue = lerpSuppression *
+ (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT);
+ let wristQ = create$4();
+ slerp(wristQ, wristQ, controllerCameraQ, lerpValue);
+ let invWristQ = invert$2(create$4(), wristQ);
+ let elbowQ = clone$4(controllerCameraQ);
+ multiply$4(elbowQ, elbowQ, invWristQ);
+ let wristPos = this.wristPos;
+ copy$1(wristPos, WRIST_CONTROLLER_OFFSET);
+ transformQuat(wristPos, wristPos, wristQ);
+ add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET);
+ transformQuat(wristPos, wristPos, elbowQ);
+ add$1(wristPos, wristPos, elbowPos);
+ let offset = clone$1(ARM_EXTENSION_OFFSET);
+ scale$1(offset, offset, extensionRatio);
+ add$1(this.position, this.wristPos, offset);
+ transformQuat(this.position, this.position, this.rootQ);
+ this.lastTime = this.time;
+ }
+ getPosition() {
+ return this.position;
+ }
+ getHeadYawOrientation_() {
+ let headEuler = create$1();
+ eulerFromQuaternion(headEuler, this.headQ, 'YXZ');
+ let destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0);
+ return destinationQ;
+ }
+ clamp_(value, min$$1, max$$1) {
+ return Math.min(Math.max(value, min$$1), max$$1);
+ }
+ quatAngle_(q1, q2) {
+ let vec1 = [0, 0, -1];
+ let vec2 = [0, 0, -1];
+ transformQuat(vec1, vec1, q1);
+ transformQuat(vec2, vec2, q2);
+ return angle(vec1, vec2);
+ }
+}
+
+const PRIVATE$16 = Symbol('@@webxr-polyfill/XRRemappedGamepad');
+const PLACEHOLDER_BUTTON = { pressed: false, touched: false, value: 0.0 };
+Object.freeze(PLACEHOLDER_BUTTON);
+class XRRemappedGamepad {
+ constructor(gamepad, map) {
+ if (!map) {
+ map = {};
+ }
+ let axes = new Array(map.axes ? map.axes.length : gamepad.axes.length);
+ let buttons = new Array(map.buttons ? map.buttons.length : gamepad.buttons.length);
+ let gripTransform = null;
+ if (map.gripTransform) {
+ let orientation = map.gripTransform.orientation || [0, 0, 0, 1];
+ gripTransform = create();
+ fromRotationTranslation(
+ gripTransform,
+ normalize$2(orientation, orientation),
+ map.gripTransform.position || [0, 0, 0]
+ );
+ }
+ let targetRayTransform = null;
+ if (map.targetRayTransform) {
+ let orientation = map.targetRayTransform.orientation || [0, 0, 0, 1];
+ targetRayTransform = create();
+ fromRotationTranslation(
+ targetRayTransform,
+ normalize$2(orientation, orientation),
+ map.targetRayTransform.position || [0, 0, 0]
+ );
+ }
+ this[PRIVATE$16] = {
+ gamepad,
+ map,
+ id: map.id || gamepad.id,
+ mapping: map.mapping || gamepad.mapping,
+ axes,
+ buttons,
+ gripTransform,
+ targetRayTransform,
+ };
+ this._update();
+ }
+ _update() {
+ let gamepad = this[PRIVATE$16].gamepad;
+ let map = this[PRIVATE$16].map;
+ let axes = this[PRIVATE$16].axes;
+ for (let i = 0; i < axes.length; ++i) {
+ if (map.axes && i in map.axes) {
+ if (map.axes[i] === null) {
+ axes[i] = 0;
+ } else {
+ axes[i] = gamepad.axes[map.axes[i]];
+ }
+ } else {
+ axes[i] = gamepad.axes[i];
+ }
}
- }, {
- key: 'quatAngle_',
- value: function quatAngle_(q1, q2) {
- var vec1 = [0, 0, -1];
- var vec2 = [0, 0, -1];
- transformQuat(vec1, vec1, q1);
- transformQuat(vec2, vec2, q2);
- return angle(vec1, vec2);
+ let buttons = this[PRIVATE$16].buttons;
+ for (let i = 0; i < buttons.length; ++i) {
+ if (map.buttons && i in map.buttons) {
+ if (map.buttons[i] === null) {
+ buttons[i] = PLACEHOLDER_BUTTON;
+ } else {
+ buttons[i] = gamepad.buttons[map.buttons[i]];
+ }
+ } else {
+ buttons[i] = gamepad.buttons[i];
+ }
}
- }]);
- return OrientationArmModel;
-}();
-
-var GamepadXRInputSource = function () {
- function GamepadXRInputSource(polyfill) {
- var primaryButtonIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
- classCallCheck(this, GamepadXRInputSource);
+ }
+ get id() {
+ return this[PRIVATE$16].id;
+ }
+ get index() {
+ return 0;
+ }
+ get connected() {
+ return this[PRIVATE$16].gamepad.connected;
+ }
+ get timestamp() {
+ return this[PRIVATE$16].gamepad.timestamp;
+ }
+ get mapping() {
+ return this[PRIVATE$16].mapping;
+ }
+ get axes() {
+ return this[PRIVATE$16].axes;
+ }
+ get buttons() {
+ return this[PRIVATE$16].buttons;
+ }
+}
+class GamepadXRInputSource {
+ constructor(polyfill, primaryButtonIndex = 0) {
this.polyfill = polyfill;
+ this.nativeGamepad = null;
this.gamepad = null;
this.inputSource = new XRInputSource(this);
this.lastPosition = create$1();
this.emulatedPosition = false;
this.basePoseMatrix = create();
+ this.outputMatrix = create();
this.inputPoses = new WeakMap();
this.primaryButtonIndex = primaryButtonIndex;
this.primaryActionPressed = false;
@@ -5494,675 +5623,514 @@ var GamepadXRInputSource = function () {
this.targetRayMode = 'gaze';
this.armModel = null;
}
- createClass(GamepadXRInputSource, [{
- key: 'updateFromGamepad',
- value: function updateFromGamepad(gamepad) {
- this.gamepad = gamepad;
- this.handedness = gamepad.hand;
- if (gamepad.pose) {
- this.targetRayMode = 'tracked-pointer';
- this.emulatedPosition = !gamepad.pose.hasPosition;
- } else if (gamepad.hand === '') {
- this.targetRayMode = 'gaze';
- this.emulatedPosition = false;
+ updateFromGamepad(gamepad) {
+ if (this.nativeGamepad !== gamepad) {
+ this.nativeGamepad = gamepad;
+ if (gamepad) {
+ this.gamepad = new XRRemappedGamepad(gamepad, GamepadMappings[gamepad.id]);
+ } else {
+ this.gamepad = null;
}
}
- }, {
- key: 'updateBasePoseMatrix',
- value: function updateBasePoseMatrix() {
- if (this.gamepad && this.gamepad.pose) {
- var pose = this.gamepad.pose;
- var position = pose.position;
- var orientation = pose.orientation;
- if (!position && !orientation) {
- return;
- }
- if (!position) {
- if (!pose.hasPosition) {
- if (!this.armModel) {
- this.armModel = new OrientationArmModel();
- }
- this.armModel.setHandedness(this.gamepad.hand);
- this.armModel.update(orientation, this.polyfill.getBasePoseMatrix());
- position = this.armModel.getPosition();
- } else {
- position = this.lastPosition;
+ this.handedness = gamepad.hand;
+ if (this.gamepad) {
+ this.gamepad._update();
+ }
+ if (gamepad.pose) {
+ this.targetRayMode = 'tracked-pointer';
+ this.emulatedPosition = !gamepad.pose.hasPosition;
+ } else if (gamepad.hand === '') {
+ this.targetRayMode = 'gaze';
+ this.emulatedPosition = false;
+ }
+ }
+ updateBasePoseMatrix() {
+ if (this.nativeGamepad && this.nativeGamepad.pose) {
+ let pose = this.nativeGamepad.pose;
+ let position = pose.position;
+ let orientation = pose.orientation;
+ if (!position && !orientation) {
+ return;
+ }
+ if (!position) {
+ if (!pose.hasPosition) {
+ if (!this.armModel) {
+ this.armModel = new OrientationArmModel();
}
+ this.armModel.setHandedness(this.nativeGamepad.hand);
+ this.armModel.update(orientation, this.polyfill.getBasePoseMatrix());
+ position = this.armModel.getPosition();
} else {
- this.lastPosition[0] = position[0];
- this.lastPosition[1] = position[1];
- this.lastPosition[2] = position[2];
+ position = this.lastPosition;
}
- fromRotationTranslation(this.basePoseMatrix, orientation, position);
} else {
- copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix());
+ this.lastPosition[0] = position[0];
+ this.lastPosition[1] = position[1];
+ this.lastPosition[2] = position[2];
}
- return this.basePoseMatrix;
+ fromRotationTranslation(this.basePoseMatrix, orientation, position);
+ } else {
+ copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix());
}
- }, {
- key: 'getXRInputPose',
- value: function getXRInputPose(coordinateSystem) {
- this.updateBasePoseMatrix();
- var inputPose = this.inputPoses.get(coordinateSystem);
- if (!inputPose) {
- inputPose = new XRInputPose(this, this.gamepad && this.gamepad.pose);
- this.inputPoses.set(coordinateSystem, inputPose);
- }
- var rayTransformMatrix = new Float32Array(16);
- coordinateSystem.transformBasePoseMatrix(rayTransformMatrix, this.basePoseMatrix);
- inputPose.targetRay = poseMatrixToXRRay(rayTransformMatrix);
- if (inputPose.gripMatrix) {
- coordinateSystem.transformBasePoseMatrix(inputPose.gripMatrix, this.basePoseMatrix);
- }
- return inputPose;
+ return this.basePoseMatrix;
+ }
+ getXRPose(coordinateSystem, poseType) {
+ this.updateBasePoseMatrix();
+ switch(poseType) {
+ case "target-ray":
+ coordinateSystem.transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix);
+ if (this.gamepad && this.gamepad[PRIVATE$16].targetRayTransform) {
+ multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$16].targetRayTransform);
+ }
+ break;
+ case "grip":
+ if (!this.nativeGamepad || !this.nativeGamepad.pose) {
+ return null;
+ }
+ coordinateSystem.transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix);
+ if (this.gamepad && this.gamepad[PRIVATE$16].gripTransform) {
+ multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$16].gripTransform);
+ }
+ break;
+ default:
+ return null;
}
- }]);
- return GamepadXRInputSource;
-}();
+ coordinateSystem._adjustForOriginOffset(this.outputMatrix);
+ return new XRPose(new XRRigidTransform(this.outputMatrix), this.emulatedPosition);
+ }
+}
-var EXTRA_PRESENTATION_ATTRIBUTES = {
- highRefreshRate: true
+const TEST_ENV = "production" === 'test';
+const EXTRA_PRESENTATION_ATTRIBUTES = {
+ highRefreshRate: true,
};
-var PRIMARY_BUTTON_MAP = {
+const PRIMARY_BUTTON_MAP = {
oculus: 1,
- openvr: 1
-};
-var CAN_USE_GAMEPAD = _global.navigator && 'getGamepads' in _global.navigator;
-var SESSION_ID = 0;
-var Session = function Session(sessionOptions) {
- classCallCheck(this, Session);
- this.outputContext = sessionOptions.outputContext;
- this.immersive = sessionOptions.immersive;
- this.ended = null;
- this.baseLayer = null;
- this.id = ++SESSION_ID;
- this.modifiedCanvasLayer = false;
-};
-
-var WebVRDevice = function (_PolyfilledXRDevice) {
- inherits(WebVRDevice, _PolyfilledXRDevice);
- function WebVRDevice(global, display) {
- classCallCheck(this, WebVRDevice);
- var canPresent = display.capabilities.canPresent;
- var _this = possibleConstructorReturn(this, (WebVRDevice.__proto__ || Object.getPrototypeOf(WebVRDevice)).call(this, global));
- _this.display = display;
- _this.frame = new global.VRFrameData();
- _this.sessions = new Map();
- _this.immersiveSession = null;
- _this.canPresent = canPresent;
- _this.baseModelMatrix = create();
- _this.gamepadInputSources = {};
- _this.tempVec3 = new Float32Array(3);
- _this.onVRDisplayPresentChange = _this.onVRDisplayPresentChange.bind(_this);
- global.window.addEventListener('vrdisplaypresentchange', _this.onVRDisplayPresentChange);
- return _this;
- }
- createClass(WebVRDevice, [{
- key: 'onBaseLayerSet',
- value: function onBaseLayerSet(sessionId, layer) {
- var _this2 = this;
- var session = this.sessions.get(sessionId);
- var canvas = layer.context.canvas;
- if (session.immersive) {
- var left = this.display.getEyeParameters('left');
- var right = this.display.getEyeParameters('right');
- canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2;
- canvas.height = Math.max(left.renderHeight, right.renderHeight);
- this.display.requestPresent([{
+ openvr: 1,
+ 'spatial controller (spatial interaction source)': 1
+};
+let SESSION_ID = 0;
+class Session {
+ constructor(mode, polyfillOptions={}) {
+ this.mode = mode;
+ this.outputContext = null;
+ this.immersive = mode == 'immersive-vr' || mode == 'immersive-ar';
+ this.ended = null;
+ this.baseLayer = null;
+ this.inlineVerticalFieldOfView = Math.PI * 0.5;
+ this.id = ++SESSION_ID;
+ this.modifiedCanvasLayer = false;
+ if (this.outputContext && !TEST_ENV) {
+ const renderContextType = polyfillOptions.renderContextType || '2d';
+ this.renderContext = this.outputContext.canvas.getContext(renderContextType);
+ }
+ }
+}
+class WebVRDevice extends XRDevice {
+ constructor(global, display) {
+ const { canPresent } = display.capabilities;
+ super(global);
+ this.display = display;
+ this.frame = new global.VRFrameData();
+ this.sessions = new Map();
+ this.immersiveSession = null;
+ this.canPresent = canPresent;
+ this.baseModelMatrix = create();
+ this.gamepadInputSources = {};
+ this.tempVec3 = new Float32Array(3);
+ this.onVRDisplayPresentChange = this.onVRDisplayPresentChange.bind(this);
+ global.window.addEventListener('vrdisplaypresentchange', this.onVRDisplayPresentChange);
+ this.CAN_USE_GAMEPAD = global.navigator && ('getGamepads' in global.navigator);
+ this.HAS_BITMAP_SUPPORT = isImageBitmapSupported(global);
+ }
+ get depthNear() { return this.display.depthNear; }
+ set depthNear(val) { this.display.depthNear = val; }
+ get depthFar() { return this.display.depthFar; }
+ set depthFar(val) { this.display.depthFar = val; }
+ onBaseLayerSet(sessionId, layer) {
+ const session = this.sessions.get(sessionId);
+ const canvas = layer.context.canvas;
+ if (session.immersive) {
+ const left = this.display.getEyeParameters('left');
+ const right = this.display.getEyeParameters('right');
+ canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2;
+ canvas.height = Math.max(left.renderHeight, right.renderHeight);
+ this.display.requestPresent([{
source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES
- }]).then(function () {
- if ("production" !== 'test' && !_this2.global.document.body.contains(canvas)) {
- session.modifiedCanvasLayer = true;
- _this2.global.document.body.appendChild(canvas);
- applyCanvasStylesForMinimalRendering(canvas);
- }
- session.baseLayer = layer;
- });
- }
- else if (session.outputContext) {
- session.baseLayer = layer;
+ }]).then(() => {
+ if (!TEST_ENV && !this.global.document.body.contains(canvas)) {
+ session.modifiedCanvasLayer = true;
+ this.global.document.body.appendChild(canvas);
+ applyCanvasStylesForMinimalRendering(canvas);
}
+ session.baseLayer = layer;
+ });
}
- }, {
- key: 'supportsSession',
- value: function supportsSession() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- if (options.immersive === true && this.canPresent === false) {
- return false;
- }
- return true;
+ else {
+ session.baseLayer = layer;
}
- }, {
- key: 'requestSession',
- value: function requestSession() {
- var $args = arguments;return new Promise(function ($return, $error) {
- var options, canvas, ctx, session;
- options = $args.length > 0 && $args[0] !== undefined ? $args[0] : {};
- if (!this.supportsSession(options)) {
- return $return(Promise.reject());
- }
- if (options.immersive) {
- canvas = this.global.document.createElement('canvas');
- {
- ctx = canvas.getContext('webgl');
- }
- return Promise.resolve(this.display.requestPresent([{
- source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }])).then(function ($await_2) {
- try {
- return $If_1.call(this);
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this), $error);
- }
- function $If_1() {
- session = new Session(options);
- this.sessions.set(session.id, session);
- if (options.immersive) {
- this.immersiveSession = session;
- this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id);
- }
- return $return(Promise.resolve(session.id));
- }
- return $If_1.call(this);
- }.bind(this));
+ }
+ onInlineVerticalFieldOfViewSet(sessionId, value) {
+ const session = this.sessions.get(sessionId);
+ session.inlineVerticalFieldOfView = value;
+ }
+ supportsSession(mode) {
+ if (XRSessionModes.indexOf(mode) == -1) {
+ throw new TypeError(
+ `The provided value '${mode}' is not a valid enum value of type XRSessionMode`);
}
- }, {
- key: 'requestAnimationFrame',
- value: function requestAnimationFrame(callback) {
- return this.display.requestAnimationFrame(callback);
+ if (mode == 'immersive-ar') {
+ return false;
}
- }, {
- key: 'getPrimaryButtonIndex',
- value: function getPrimaryButtonIndex(gamepad) {
- var primaryButton = 0;
- var name = gamepad.id.toLowerCase();
- for (var key in PRIMARY_BUTTON_MAP) {
- if (name.includes(key)) {
- primaryButton = PRIMARY_BUTTON_MAP[key];
- break;
- }
+ if (mode == 'immersive-vr' && this.canPresent === false) {
+ return false;
+ }
+ return true;
+ }
+ async requestSession(mode) {
+ if (!this.supportsSession(mode)) {
+ return Promise.reject();
+ }
+ let immersive = mode == 'immersive-vr';
+ if (immersive) {
+ const canvas = this.global.document.createElement('canvas');
+ if (!TEST_ENV) {
+ const ctx = canvas.getContext('webgl');
}
- return Math.min(primaryButton, gamepad.buttons.length - 1);
+ await this.display.requestPresent([{
+ source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }]);
}
- }, {
- key: 'onFrameStart',
- value: function onFrameStart(sessionId) {
- this.display.getFrameData(this.frame);
- var session = this.sessions.get(sessionId);
- if (session.immersive && CAN_USE_GAMEPAD) {
- var prevInputSources = this.gamepadInputSources;
- this.gamepadInputSources = {};
- var gamepads = _global.navigator.getGamepads();
- for (var i = 0; i < gamepads.length; ++i) {
- var gamepad = gamepads[i];
- if (gamepad && gamepad.displayId === this.display.displayId) {
- var inputSourceImpl = prevInputSources[i];
- if (!inputSourceImpl) {
- inputSourceImpl = new GamepadXRInputSource(this, this.getPrimaryButtonIndex(gamepad));
- }
- inputSourceImpl.updateFromGamepad(gamepad);
- this.gamepadInputSources[i] = inputSourceImpl;
- if (inputSourceImpl.primaryButtonIndex != -1) {
- var primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed;
- if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) {
- this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
- } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) {
- this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
- }
- inputSourceImpl.primaryActionPressed = primaryActionPressed;
- }
- }
- }
+ const session = new Session(mode, {
+ renderContextType: this.HAS_BITMAP_SUPPORT ? 'bitmaprenderer' : '2d'
+ });
+ this.sessions.set(session.id, session);
+ if (immersive) {
+ this.immersiveSession = session;
+ this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id);
+ }
+ return Promise.resolve(session.id);
+ }
+ requestAnimationFrame(callback) {
+ return this.display.requestAnimationFrame(callback);
+ }
+ getPrimaryButtonIndex(gamepad) {
+ let primaryButton = 0;
+ let name = gamepad.id.toLowerCase();
+ for (let key in PRIMARY_BUTTON_MAP) {
+ if (name.includes(key)) {
+ primaryButton = PRIMARY_BUTTON_MAP[key];
+ break;
}
- if (session.outputContext && !session.immersive) {
- var outputCanvas = session.outputContext.canvas;
- var oWidth = outputCanvas.offsetWidth;
- var oHeight = outputCanvas.offsetHeight;
- if (outputCanvas.width != oWidth) {
- outputCanvas.width = oWidth;
- }
- if (outputCanvas.height != oHeight) {
- outputCanvas.height = oHeight;
- }
- var canvas = session.baseLayer.context.canvas;
- if (!this.immersiveSession || canvas !== this.immersiveSession.baseLayer.context.canvas) {
- if (canvas.width != oWidth) {
- canvas.width = oWidth;
+ }
+ return Math.min(primaryButton, gamepad.buttons.length - 1);
+ }
+ onFrameStart(sessionId) {
+ this.display.getFrameData(this.frame);
+ const session = this.sessions.get(sessionId);
+ if (session.immersive && this.CAN_USE_GAMEPAD) {
+ let prevInputSources = this.gamepadInputSources;
+ this.gamepadInputSources = {};
+ let gamepads = this.global.navigator.getGamepads();
+ for (let i = 0; i < gamepads.length; ++i) {
+ let gamepad = gamepads[i];
+ if (gamepad && gamepad.displayId > 0) {
+ let inputSourceImpl = prevInputSources[i];
+ if (!inputSourceImpl) {
+ inputSourceImpl = new GamepadXRInputSource(this, this.getPrimaryButtonIndex(gamepad));
}
- if (canvas.height != oHeight) {
- canvas.height = oHeight;
+ inputSourceImpl.updateFromGamepad(gamepad);
+ this.gamepadInputSources[i] = inputSourceImpl;
+ if (inputSourceImpl.primaryButtonIndex != -1) {
+ let primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed;
+ if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) {
+ this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
+ } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) {
+ this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
+ }
+ inputSourceImpl.primaryActionPressed = primaryActionPressed;
}
- perspective(this.frame.leftProjectionMatrix, Math.PI * 0.4, oWidth / oHeight, this.depthNear, this.depthFar);
}
}
}
- }, {
- key: 'onFrameEnd',
- value: function onFrameEnd(sessionId) {
- var session = this.sessions.get(sessionId);
- if (session.ended || !session.baseLayer) {
- return;
- }
- if (session.outputContext && !(session.immersive && !this.display.capabilities.hasExternalDisplay)) {
- var mirroring = session.immersive && this.display.capabilities.hasExternalDisplay;
- var canvas = session.baseLayer.context.canvas;
- var iWidth = mirroring ? canvas.width / 2 : canvas.width;
- var iHeight = canvas.height;
- {
- var outputCanvas = session.outputContext.canvas;
- var outputContext = outputCanvas.getContext('2d');
- var oWidth = outputCanvas.width;
- var oHeight = outputCanvas.height;
- outputContext.drawImage(canvas, 0, 0, iWidth, iHeight, 0, 0, oWidth, oHeight);
- }
- }
- if (session.immersive && session.baseLayer) {
- this.display.submitFrame();
- }
+ if (TEST_ENV) {
+ return;
}
- }, {
- key: 'cancelAnimationFrame',
- value: function cancelAnimationFrame(handle) {
- this.display.cancelAnimationFrame(handle);
+ if (!session.immersive && session.baseLayer) {
+ const canvas = session.baseLayer.context.canvas;
+ perspective(this.frame.leftProjectionMatrix, session.inlineVerticalFieldOfView,
+ canvas.width/canvas.height, this.depthNear, this.depthFar);
}
- }, {
- key: 'endSession',
- value: function endSession(sessionId) {
- return new Promise(function ($return, $error) {
- var session = this.sessions.get(sessionId);
- if (session.ended) {
- return $return();
- }
- if (session.immersive) {
- return $return(this.display.exitPresent());
+ }
+ onFrameEnd(sessionId) {
+ const session = this.sessions.get(sessionId);
+ if (session.ended || !session.baseLayer) {
+ return;
+ }
+ if (session.outputContext &&
+ !(session.immersive && !this.display.capabilities.hasExternalDisplay)) {
+ const mirroring =
+ session.immersive && this.display.capabilities.hasExternalDisplay;
+ const iCanvas = session.baseLayer.context.canvas;
+ const iWidth = mirroring ? iCanvas.width / 2 : iCanvas.width;
+ const iHeight = iCanvas.height;
+ if (!TEST_ENV) {
+ const oCanvas = session.outputContext.canvas;
+ const oWidth = oCanvas.width;
+ const oHeight = oCanvas.height;
+ const renderContext = session.renderContext;
+ if (this.HAS_BITMAP_SUPPORT) {
+ if (iCanvas.transferToImageBitmap) {
+ renderContext.transferFromImageBitmap(iCanvas.transferToImageBitmap());
+ }
+ else {
+ this.global.createImageBitmap(iCanvas, 0, 0, iWidth, iHeight, {
+ resizeWidth: oWidth,
+ resizeHeight: oHeight,
+ }).then(bitmap => renderContext.transferFromImageBitmap(bitmap));
+ }
} else {
- session.ended = true;
+ renderContext.drawImage(iCanvas, 0, 0, iWidth, iHeight,
+ 0, 0, oWidth, oHeight);
}
- return $return();
- }.bind(this));
- }
- }, {
- key: 'requestStageBounds',
- value: function requestStageBounds() {
- if (this.display.stageParameters) {
- var width = this.display.stageParameters.sizeX;
- var depth = this.display.stageParameters.sizeZ;
- var data = [];
- data.push(-width / 2);
- data.push(-depth / 2);
- data.push(width / 2);
- data.push(-depth / 2);
- data.push(width / 2);
- data.push(depth / 2);
- data.push(-width / 2);
- data.push(depth / 2);
- return data;
}
- return null;
}
- }, {
- key: 'requestFrameOfReferenceTransform',
- value: function requestFrameOfReferenceTransform(type, options) {
- return new Promise(function ($return, $error) {
- if (type === 'stage' && this.display.stageParameters && this.display.stageParameters.sittingToStandingTransform) {
- return $return(this.display.stageParameters.sittingToStandingTransform);
- }
- return $return();
- }.bind(this));
+ if (session.immersive && session.baseLayer) {
+ this.display.submitFrame();
}
- }, {
- key: 'getProjectionMatrix',
- value: function getProjectionMatrix(eye) {
- if (eye === 'left') {
- return this.frame.leftProjectionMatrix;
- } else if (eye === 'right') {
- return this.frame.rightProjectionMatrix;
- } else {
- throw new Error('eye must be of type \'left\' or \'right\'');
- }
+ }
+ cancelAnimationFrame(handle) {
+ this.display.cancelAnimationFrame(handle);
+ }
+ async endSession(sessionId) {
+ const session = this.sessions.get(sessionId);
+ if (session.ended) {
+ return;
}
- }, {
- key: 'getViewport',
- value: function getViewport(sessionId, eye, layer, target) {
- var session = this.sessions.get(sessionId);
- var _layer$context$canvas = layer.context.canvas,
- width = _layer$context$canvas.width,
- height = _layer$context$canvas.height;
- if (!session.immersive) {
- target.x = target.y = 0;
- target.width = width;
- target.height = height;
- return true;
- }
- if (eye === 'left') {
- target.x = 0;
- } else if (eye === 'right') {
- target.x = width / 2;
- } else {
- return false;
- }
- target.y = 0;
- target.width = width / 2;
+ if (session.immersive) {
+ return this.display.exitPresent();
+ } else {
+ session.ended = true;
+ }
+ }
+ requestStageBounds() {
+ if (this.display.stageParameters) {
+ const width = this.display.stageParameters.sizeX;
+ const depth = this.display.stageParameters.sizeZ;
+ const data = [];
+ data.push(-width / 2);
+ data.push(-depth / 2);
+ data.push(width / 2);
+ data.push(-depth / 2);
+ data.push(width / 2);
+ data.push(depth / 2);
+ data.push(-width / 2);
+ data.push(depth / 2);
+ return data;
+ }
+ return null;
+ }
+ async requestFrameOfReferenceTransform(type, options) {
+ if (type === 'stage' && this.display.stageParameters &&
+ this.display.stageParameters.sittingToStandingTransform) {
+ return this.display.stageParameters.sittingToStandingTransform;
+ }
+ }
+ getProjectionMatrix(eye) {
+ if (eye === 'left') {
+ return this.frame.leftProjectionMatrix;
+ } else if (eye === 'right') {
+ return this.frame.rightProjectionMatrix;
+ } else if (eye === 'none') {
+ return this.frame.leftProjectionMatrix;
+ } else {
+ throw new Error(`eye must be of type 'left' or 'right'`);
+ }
+ }
+ getViewport(sessionId, eye, layer, target) {
+ const session = this.sessions.get(sessionId);
+ const { width, height } = layer.context.canvas;
+ if (!session.immersive) {
+ target.x = target.y = 0;
+ target.width = width;
target.height = height;
return true;
}
- }, {
- key: 'getBasePoseMatrix',
- value: function getBasePoseMatrix() {
- var _frame$pose = this.frame.pose,
- position = _frame$pose.position,
- orientation = _frame$pose.orientation;
- if (!position && !orientation) {
- return this.baseModelMatrix;
- }
- if (!position) {
- position = this.tempVec3;
- position[0] = position[1] = position[2] = 0;
- }
- fromRotationTranslation(this.baseModelMatrix, orientation, position);
+ if (eye === 'left') {
+ target.x = 0;
+ } else if (eye === 'right') {
+ target.x = width / 2;
+ } else {
+ return false;
+ }
+ target.y = 0;
+ target.width = width / 2;
+ target.height = height;
+ return true;
+ }
+ getBasePoseMatrix() {
+ let { position, orientation } = this.frame.pose;
+ if (!position && !orientation) {
return this.baseModelMatrix;
}
- }, {
- key: 'getBaseViewMatrix',
- value: function getBaseViewMatrix(eye) {
- if (eye === 'left') {
- return this.frame.leftViewMatrix;
- } else if (eye === 'right') {
- return this.frame.rightViewMatrix;
- } else {
- throw new Error('eye must be of type \'left\' or \'right\'');
- }
+ if (!position) {
+ position = this.tempVec3;
+ position[0] = position[1] = position[2] = 0;
}
- }, {
- key: 'getInputSources',
- value: function getInputSources() {
- var inputSources = [];
- for (var i in this.gamepadInputSources) {
- inputSources.push(this.gamepadInputSources[i].inputSource);
- }
- return inputSources;
+ fromRotationTranslation(this.baseModelMatrix, orientation, position);
+ return this.baseModelMatrix;
+ }
+ getBaseViewMatrix(eye) {
+ if (eye === 'left') {
+ return this.frame.leftViewMatrix;
+ } else if (eye === 'right') {
+ return this.frame.rightViewMatrix;
+ } else {
+ throw new Error(`eye must be of type 'left' or 'right'`);
}
- }, {
- key: 'getInputPose',
- value: function getInputPose(inputSource, coordinateSystem) {
- if (!coordinateSystem) {
- return null;
- }
- for (var i in this.gamepadInputSources) {
- var inputSourceImpl = this.gamepadInputSources[i];
- if (inputSourceImpl.inputSource === inputSource) {
- return inputSourceImpl.getXRInputPose(coordinateSystem);
- }
- }
+ }
+ getInputSources() {
+ let inputSources = [];
+ for (let i in this.gamepadInputSources) {
+ inputSources.push(this.gamepadInputSources[i].inputSource);
+ }
+ return inputSources;
+ }
+ getInputPose(inputSource, coordinateSystem, poseType) {
+ if (!coordinateSystem) {
return null;
}
- }, {
- key: 'onWindowResize',
- value: function onWindowResize() {}
- }, {
- key: 'onVRDisplayPresentChange',
- value: function onVRDisplayPresentChange(e) {
- var _this3 = this;
- if (!this.display.isPresenting) {
- this.sessions.forEach(function (session) {
- if (session.immersive && !session.ended) {
- if (session.modifiedCanvasLayer) {
- var canvas = session.baseLayer.context.canvas;
- document.body.removeChild(canvas);
- canvas.setAttribute('style', '');
- }
- if (_this3.immersiveSession === session) {
- _this3.immersiveSession = null;
- }
- _this3.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id);
- }
- });
+ for (let i in this.gamepadInputSources) {
+ let inputSourceImpl = this.gamepadInputSources[i];
+ if (inputSourceImpl.inputSource === inputSource) {
+ return inputSourceImpl.getXRPose(coordinateSystem, poseType);
}
}
- }, {
- key: 'depthNear',
- get: function get$$1() {
- return this.display.depthNear;
- }
- ,
- set: function set$$1(val) {
- this.display.depthNear = val;
- }
- }, {
- key: 'depthFar',
- get: function get$$1() {
- return this.display.depthFar;
- }
- ,
- set: function set$$1(val) {
- this.display.depthFar = val;
+ return null;
+ }
+ onWindowResize() {
+ }
+ onVRDisplayPresentChange(e) {
+ if (!this.display.isPresenting) {
+ this.sessions.forEach(session => {
+ if (session.immersive && !session.ended) {
+ if (session.modifiedCanvasLayer) {
+ const canvas = session.baseLayer.context.canvas;
+ document.body.removeChild(canvas);
+ canvas.setAttribute('style', '');
+ }
+ if (this.immersiveSession === session) {
+ this.immersiveSession = null;
+ }
+ this.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id);
+ }
+ });
}
- }]);
- return WebVRDevice;
-}(PolyfilledXRDevice);
-
-var CardboardXRDevice = function (_WebVRDevice) {
- inherits(CardboardXRDevice, _WebVRDevice);
- function CardboardXRDevice(global) {
- classCallCheck(this, CardboardXRDevice);
- var display = new CardboardVRDisplay();
- var _this = possibleConstructorReturn(this, (CardboardXRDevice.__proto__ || Object.getPrototypeOf(CardboardXRDevice)).call(this, global, display));
- _this.display = display;
- _this.frame = {
+ }
+}
+
+class CardboardXRDevice extends WebVRDevice {
+ constructor(global, cardboardConfig) {
+ const display = new CardboardVRDisplay(cardboardConfig || {});
+ super(global, display);
+ this.display = display;
+ this.frame = {
rightViewMatrix: new Float32Array(16),
leftViewMatrix: new Float32Array(16),
rightProjectionMatrix: new Float32Array(16),
leftProjectionMatrix: new Float32Array(16),
pose: null,
- timestamp: null
+ timestamp: null,
};
- return _this;
- }
- return CardboardXRDevice;
-}(WebVRDevice);
-
-var getXRDevice = function getXRDevice(global) {
- return new Promise(function ($return, $error) {
- var device;
- device = null;
- if ('xr' in global.navigator) {
- var $Try_1_Post = function () {
- try {
- return $If_3.call(this);
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this);var $Try_1_Catch = function (e) {
- try {
- return $Try_1_Post();
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this);
- try {
- return Promise.resolve(global.navigator.xr.requestDevice()).then(function ($await_6) {
- try {
- device = $await_6;
- return $Try_1_Post();
- } catch ($boundEx) {
- return $Try_1_Catch($boundEx);
- }
- }.bind(this), $Try_1_Catch);
- } catch (e) {
- $Try_1_Catch(e);
- }
- }
- function $If_3() {
- return $return(device);
- }
- return $If_3.call(this);
- }.bind(this));
-};
-var getVRDisplay = function getVRDisplay(global) {
- return new Promise(function ($return, $error) {
- var device, displays;
- device = null;
- if ('getVRDisplays' in global.navigator) {
- var $Try_2_Post = function () {
- try {
- return $If_4.call(this);
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this);var $Try_2_Catch = function (e) {
- try {
- return $Try_2_Post();
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this);
- try {
- return Promise.resolve(global.navigator.getVRDisplays()).then(function ($await_7) {
- try {
- displays = $await_7;
- if (displays && displays.length) {
- device = new WebVRDevice(global, displays[0]);
- }
- return $Try_2_Post();
- } catch ($boundEx) {
- return $Try_2_Catch($boundEx);
- }
- }.bind(this), $Try_2_Catch);
- } catch (e) {
- $Try_2_Catch(e);
+ }
+}
+
+const getWebVRDevice = async function (global) {
+ let device = null;
+ if ('getVRDisplays' in global.navigator) {
+ try {
+ const displays = await global.navigator.getVRDisplays();
+ if (displays && displays.length) {
+ device = new WebVRDevice(global, displays[0]);
}
- }
- function $If_4() {
- return $return(device);
- }
- return $If_4.call(this);
- }.bind(this));
+ } catch (e) {}
+ }
+ return device;
};
-var requestDevice = function requestDevice(global, config) {
- return new Promise(function ($return, $error) {
- var device;
- return Promise.resolve(getXRDevice(global)).then(function ($await_8) {
- try {
- device = $await_8;
- if (device) {
- return $return(device);
- }
- if (config.webvr) {
- return Promise.resolve(getVRDisplay(global)).then(function ($await_9) {
- try {
- device = $await_9;
- if (device) {
- return $return(new XRDevice(device));
- }
- return $If_5.call(this);
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this), $error);
- }
- function $If_5() {
- if (config.cardboard && isMobile(global)) {
- if (!global.VRFrameData) {
- global.VRFrameData = function () {
- this.rightViewMatrix = new Float32Array(16);
- this.leftViewMatrix = new Float32Array(16);
- this.rightProjectionMatrix = new Float32Array(16);
- this.leftProjectionMatrix = new Float32Array(16);
- this.pose = null;
- };
- }
- return $return(new XRDevice(new CardboardXRDevice(global)));
- }
- return $return(null);
- }
- return $If_5.call(this);
- } catch ($boundEx) {
- return $error($boundEx);
- }
- }.bind(this), $error);
- }.bind(this));
+const requestXRDevice = async function (global, config) {
+ if (config.webvr) {
+ let xr = await getWebVRDevice(global);
+ if (xr) {
+ return xr;
+ }
+ }
+ if (!global.VRFrameData) {
+ global.VRFrameData = function () {
+ this.rightViewMatrix = new Float32Array(16);
+ this.leftViewMatrix = new Float32Array(16);
+ this.rightProjectionMatrix = new Float32Array(16);
+ this.leftProjectionMatrix = new Float32Array(16);
+ this.pose = null;
+ };
+ }
+ return new CardboardXRDevice(global, config.cardboardConfig);
};
-var CONFIG_DEFAULTS = {
+const CONFIG_DEFAULTS = {
+ global: _global,
webvr: true,
- cardboard: true
-};
-var partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext'];
-var WebXRPolyfill = function () {
- function WebXRPolyfill(global) {
- var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- classCallCheck(this, WebXRPolyfill);
- this.global = global || _global;
+ cardboard: true,
+ cardboardConfig: null,
+ allowCardboardOnDesktop: false,
+};
+const partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext'];
+class WebXRPolyfill {
+ constructor(config={}) {
this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config));
+ this.global = this.config.global;
this.nativeWebXR = 'xr' in this.global.navigator;
this.injected = false;
if (!this.nativeWebXR) {
this._injectPolyfill(this.global);
}
else if (this.config.cardboard && isMobile(this.global)) {
- this._patchRequestDevice();
- }
+ this._patchNavigatorXR();
+ }
}
- createClass(WebXRPolyfill, [{
- key: '_injectPolyfill',
- value: function _injectPolyfill(global) {
- if (!partials.every(function (iface) {
- return !!global[iface];
- })) {
- throw new Error('Global must have the following attributes : ' + partials);
+ _injectPolyfill(global) {
+ if (!partials.every(iface => !!global[iface])) {
+ throw new Error(`Global must have the following attributes : ${partials}`);
+ }
+ for (const className of Object.keys(API)) {
+ if (global[className] !== undefined) {
+ console.warn(`${className} already defined on global.`);
+ } else {
+ global[className] = API[className];
}
- var _iteratorNormalCompletion = true;
- var _didIteratorError = false;
- var _iteratorError = undefined;
- try {
- for (var _iterator = Object.keys(API)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
- var className = _step.value;
- if (global[className] !== undefined) {
- console.warn(className + ' already defined on global.');
- } else {
- global[className] = API[className];
- }
- }
- } catch (err) {
- _didIteratorError = true;
- _iteratorError = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion && _iterator.return) {
- _iterator.return();
- }
- } finally {
- if (_didIteratorError) {
- throw _iteratorError;
- }
+ }
+ {
+ const polyfilledCtx = polyfillMakeXRCompatible(global.WebGLRenderingContext);
+ if (polyfilledCtx) {
+ polyfillGetContext(global.HTMLCanvasElement);
+ if (global.OffscreenCanvas) {
+ polyfillGetContext(global.OffscreenCanvas);
}
- }
- {
- var polyfilledCtx = extendContextCompatibleXRDevice(global.WebGLRenderingContext);
- if (polyfilledCtx) {
- extendGetContext(global.HTMLCanvasElement);
- if (global.WebGL2RenderingContext) {
- extendContextCompatibleXRDevice(global.WebGL2RenderingContext);
- }
+ if (global.WebGL2RenderingContext){
+ polyfillMakeXRCompatible(global.WebGL2RenderingContext);
}
}
- this.injected = true;
- this._patchRequestDevice();
}
- }, {
- key: '_patchRequestDevice',
- value: function _patchRequestDevice() {
- var device = requestDevice(this.global, this.config);
- this.xr = new XR(device);
- Object.defineProperty(this.global.navigator, 'xr', {
- value: this.xr,
- configurable: true
- });
- }
- }]);
- return WebXRPolyfill;
-}();
+ this.injected = true;
+ this._patchNavigatorXR();
+ }
+ _patchNavigatorXR() {
+ let devicePromise = requestXRDevice(this.global, this.config);
+ this.xr = new XR(devicePromise);
+ Object.defineProperty(this.global.navigator, 'xr', {
+ value: this.xr,
+ configurable: true,
+ });
+ }
+}
return WebXRPolyfill;
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.min.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.min.js
new file mode 100644
index 00000000000..bb39d85599b
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.min.js
@@ -0,0 +1,95 @@
+/**
+ * @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(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.WebXRPolyfill=t()}(this,function(){"use strict";const e="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},t=Symbol("@@webxr-polyfill/EventTarget");class i{constructor(){this[t]={listeners:new Map}}addEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];r.push(i),this[t].listeners.set(e,r)}removeEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];for(let e=r.length;e>=0;e--)r[e]===i&&r.pop()}dispatchEvent(e,i){const r=this[t].listeners.get(e)||[],n=[];for(let e=0;e<r.length;e++)n[e]=r[e];for(let e of n)e(i);"function"==typeof this[`on${e}`]&&this[`on${e}`](i)}}const r=Symbol("@@webxr-polyfill/XR"),n=["inline","immersive-vr","immersive-ar"],s="Polyfill Error: Must call navigator.xr.supportsSession() with any XRSessionMode\nor navigator.xr.requestSession('inline') prior to requesting an immersive\nsession. This is a limitation specific to the WebXR Polyfill and does not apply\nto native implementations of the API.";let a;if("performance"in e==!1){let e=Date.now();a=(()=>Date.now()-e)}else a=(()=>performance.now());var o=a;const l=Symbol("@@webxr-polyfill/XRPose");class A{constructor(e,t){this[l]={transform:e,emulatedPosition:t}}get transform(){return this[l].transform}get emulatedPosition(){return this[l].emulatedPosition}_setTransform(e){this[l].transform=e}}const h=1e-6;let c="undefined"!=typeof Float32Array?Float32Array:Array;Math.PI;function d(){let e=new c(16);return c!=Float32Array&&(e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0),e[0]=1,e[5]=1,e[10]=1,e[15]=1,e}function u(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e[9]=t[9],e[10]=t[10],e[11]=t[11],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15],e}function p(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e}function f(e,t){let i=t[0],r=t[1],n=t[2],s=t[3],a=t[4],o=t[5],l=t[6],A=t[7],h=t[8],c=t[9],d=t[10],u=t[11],p=t[12],f=t[13],m=t[14],g=t[15],w=i*o-r*a,v=i*l-n*a,y=i*A-s*a,b=r*l-n*o,E=r*A-s*o,M=n*A-s*l,_=h*f-c*p,x=h*m-d*p,F=h*g-u*p,S=c*m-d*f,R=c*g-u*f,T=d*g-u*m,B=w*T-v*R+y*S+b*F-E*x+M*_;return B?(B=1/B,e[0]=(o*T-l*R+A*S)*B,e[1]=(n*R-r*T-s*S)*B,e[2]=(f*M-m*E+g*b)*B,e[3]=(d*E-c*M-u*b)*B,e[4]=(l*F-a*T-A*x)*B,e[5]=(i*T-n*F+s*x)*B,e[6]=(m*y-p*M-g*v)*B,e[7]=(h*M-d*y+u*v)*B,e[8]=(a*R-o*F+A*_)*B,e[9]=(r*F-i*R-s*_)*B,e[10]=(p*E-f*y+g*w)*B,e[11]=(c*y-h*E-u*w)*B,e[12]=(o*x-a*S-l*_)*B,e[13]=(i*S-r*x+n*_)*B,e[14]=(f*v-p*b-m*w)*B,e[15]=(h*b-c*v+d*w)*B,e):null}function m(e,t,i){let r=t[0],n=t[1],s=t[2],a=t[3],o=t[4],l=t[5],A=t[6],h=t[7],c=t[8],d=t[9],u=t[10],p=t[11],f=t[12],m=t[13],g=t[14],w=t[15],v=i[0],y=i[1],b=i[2],E=i[3];return e[0]=v*r+y*o+b*c+E*f,e[1]=v*n+y*l+b*d+E*m,e[2]=v*s+y*A+b*u+E*g,e[3]=v*a+y*h+b*p+E*w,v=i[4],y=i[5],b=i[6],E=i[7],e[4]=v*r+y*o+b*c+E*f,e[5]=v*n+y*l+b*d+E*m,e[6]=v*s+y*A+b*u+E*g,e[7]=v*a+y*h+b*p+E*w,v=i[8],y=i[9],b=i[10],E=i[11],e[8]=v*r+y*o+b*c+E*f,e[9]=v*n+y*l+b*d+E*m,e[10]=v*s+y*A+b*u+E*g,e[11]=v*a+y*h+b*p+E*w,v=i[12],y=i[13],b=i[14],E=i[15],e[12]=v*r+y*o+b*c+E*f,e[13]=v*n+y*l+b*d+E*m,e[14]=v*s+y*A+b*u+E*g,e[15]=v*a+y*h+b*p+E*w,e}function g(e,t,i){let r=t[0],n=t[1],s=t[2],a=t[3],o=r+r,l=n+n,A=s+s,h=r*o,c=r*l,d=r*A,u=n*l,p=n*A,f=s*A,m=a*o,g=a*l,w=a*A;return e[0]=1-(u+f),e[1]=c+w,e[2]=d-g,e[3]=0,e[4]=c-w,e[5]=1-(h+f),e[6]=p+m,e[7]=0,e[8]=d+g,e[9]=p-m,e[10]=1-(h+u),e[11]=0,e[12]=i[0],e[13]=i[1],e[14]=i[2],e[15]=1,e}function w(e,t){return e[0]=t[12],e[1]=t[13],e[2]=t[14],e}function v(e,t){let i=t[0]+t[5]+t[10],r=0;return i>0?(r=2*Math.sqrt(i+1),e[3]=.25*r,e[0]=(t[6]-t[9])/r,e[1]=(t[8]-t[2])/r,e[2]=(t[1]-t[4])/r):t[0]>t[5]&&t[0]>t[10]?(r=2*Math.sqrt(1+t[0]-t[5]-t[10]),e[3]=(t[6]-t[9])/r,e[0]=.25*r,e[1]=(t[1]+t[4])/r,e[2]=(t[8]+t[2])/r):t[5]>t[10]?(r=2*Math.sqrt(1+t[5]-t[0]-t[10]),e[3]=(t[8]-t[2])/r,e[0]=(t[1]+t[4])/r,e[1]=.25*r,e[2]=(t[6]+t[9])/r):(r=2*Math.sqrt(1+t[10]-t[0]-t[5]),e[3]=(t[1]-t[4])/r,e[0]=(t[8]+t[2])/r,e[1]=(t[6]+t[9])/r,e[2]=.25*r),e}function y(){let e=new c(3);return c!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e}function b(e){var t=new c(3);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function E(e,t,i){let r=new c(3);return r[0]=e,r[1]=t,r[2]=i,r}function M(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function _(e,t,i){return e[0]=t[0]+i[0],e[1]=t[1]+i[1],e[2]=t[2]+i[2],e}function x(e,t,i){return e[0]=t[0]*i,e[1]=t[1]*i,e[2]=t[2]*i,e}function F(e,t){let i=t[0],r=t[1],n=t[2],s=i*i+r*r+n*n;return s>0&&(s=1/Math.sqrt(s),e[0]=t[0]*s,e[1]=t[1]*s,e[2]=t[2]*s),e}function S(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function R(e,t,i){let r=t[0],n=t[1],s=t[2],a=i[0],o=i[1],l=i[2];return e[0]=n*l-s*o,e[1]=s*a-r*l,e[2]=r*o-n*a,e}function T(e,t,i){let r=i[0],n=i[1],s=i[2],a=i[3],o=t[0],l=t[1],A=t[2],h=n*A-s*l,c=s*o-r*A,d=r*l-n*o,u=n*d-s*c,p=s*h-r*d,f=r*c-n*h,m=2*a;return h*=m,c*=m,d*=m,u*=2,p*=2,f*=2,e[0]=o+h+u,e[1]=l+c+p,e[2]=A+d+f,e}const B=function(e){let t=e[0],i=e[1],r=e[2];return Math.sqrt(t*t+i*i+r*r)};!function(){let e=y()}();!function(){let e=function(){let e=new c(4);return c!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0,e[3]=0),e}()}();function C(){let e=new c(4);return c!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e[3]=1,e}function P(e,t,i){let r=t[0],n=t[1],s=t[2],a=t[3],o=i[0],l=i[1],A=i[2],h=i[3];return e[0]=r*h+a*o+n*A-s*l,e[1]=n*h+a*l+s*o-r*A,e[2]=s*h+a*A+r*l-n*o,e[3]=a*h-r*o-n*l-s*A,e}function D(e,t,i,r){let n,s,a,o,l,A=t[0],c=t[1],d=t[2],u=t[3],p=i[0],f=i[1],m=i[2],g=i[3];return(s=A*p+c*f+d*m+u*g)<0&&(s=-s,p=-p,f=-f,m=-m,g=-g),1-s>h?(n=Math.acos(s),a=Math.sin(n),o=Math.sin((1-r)*n)/a,l=Math.sin(r*n)/a):(o=1-r,l=r),e[0]=o*A+l*p,e[1]=o*c+l*f,e[2]=o*d+l*m,e[3]=o*u+l*g,e}function I(e,t){let i=t[0],r=t[1],n=t[2],s=t[3],a=i*i+r*r+n*n+s*s,o=a?1/a:0;return e[0]=-i*o,e[1]=-r*o,e[2]=-n*o,e[3]=s*o,e}const L=function(e){let t=new c(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},O=function(e,t,i,r){let n=new c(4);return n[0]=e,n[1]=t,n[2]=i,n[3]=r,n},Q=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},N=function(e,t){let i=t[0],r=t[1],n=t[2],s=t[3],a=i*i+r*r+n*n+s*s;return a>0&&(a=1/Math.sqrt(a),e[0]=i*a,e[1]=r*a,e[2]=n*a,e[3]=s*a),e},G=(function(){let e=y(),t=E(1,0,0),i=E(0,1,0)}(),function(){let e=C(),t=C()}(),function(){let e=function(){let e=new c(9);return c!=Float32Array&&(e[1]=0,e[2]=0,e[3]=0,e[5]=0,e[6]=0,e[7]=0),e[0]=1,e[4]=1,e[8]=1,e}()}(),Symbol("@@webxr-polyfill/XRRigidTransform"));class k{constructor(){if(this[G]={matrix:null,position:null,orientation:null,inverse:null},0===arguments.length)this[G].matrix=p(new Float32Array(16));else if(1===arguments.length)arguments[0]instanceof Float32Array?this[G].matrix=arguments[0]:(this[G].position=this._getPoint(arguments[0]),this[G].orientation=DOMPointReadOnly.fromPoint({x:0,y:0,z:0,w:1}));else{if(2!==arguments.length)throw new Error("Too many arguments!");this[G].position=this._getPoint(arguments[0]),this[G].orientation=this._getPoint(arguments[1])}if(this[G].matrix){let e=y();w(e,this[G].matrix),this[G].position=DOMPointReadOnly.fromPoint({x:e[0],y:e[1],z:e[2]});let t=C();v(t,this[G].matrix),this[G].orientation=DOMPointReadOnly.fromPoint({x:t[0],y:t[1],z:t[2],w:t[3]})}else this[G].matrix=p(new Float32Array(16)),g(this[G].matrix,O(this[G].orientation.x,this[G].orientation.y,this[G].orientation.z,this[G].orientation.w),E(this[G].position.x,this[G].position.y,this[G].position.z))}_getPoint(e){return e instanceof DOMPointReadOnly?e:DOMPointReadOnly.fromPoint(e)}get matrix(){return this[G].matrix}get position(){return this[G].position}get orientation(){return this[G].orientation}get inverse(){if(null===this[G].inverse){let e=p(new Float32Array(16));f(e,this[G].matrix),this[G].inverse=new k(e),this[G].inverse[G].inverse=this}return this[G].inverse}}const V=Symbol("@@webxr-polyfill/XRViewerPose");class z extends A{constructor(e){super(new k,!1),this[V]={device:e,leftViewMatrix:p(new Float32Array(16)),rightViewMatrix:p(new Float32Array(16)),poseModelMatrix:p(new Float32Array(16))}}get poseModelMatrix(){return this[V].poseModelMatrix}getViewMatrix(e){switch(e.eye){case"left":return this[V].leftViewMatrix;case"right":return this[V].rightViewMatrix}throw new Error("view is not a valid XREye")}get views(){return this[V].views}set views(e){this[V].views=e}updateFromReferenceSpace(e){const t=this[V].device.getBasePoseMatrix(),i=this[V].device.getBaseViewMatrix("left"),r=this[V].device.getBaseViewMatrix("right");t&&(e.transformBasePoseMatrix(this[V].poseModelMatrix,t),e._adjustForOriginOffset(this[V].poseModelMatrix),super._setTransform(new k(this[V].poseModelMatrix))),i&&r&&(e.transformBaseViewMatrix(this[V].leftViewMatrix,i,this[V].poseModelMatrix),e.transformBaseViewMatrix(this[V].rightViewMatrix,r,this[V].poseModelMatrix),m(this[V].leftViewMatrix,this[V].leftViewMatrix,e._originOffsetMatrix()),m(this[V].rightViewMatrix,this[V].rightViewMatrix,e._originOffsetMatrix()));for(let e of this[V].views)"left"==e.eye?e._updateViewMatrix(this[V].leftViewMatrix):"right"==e.eye&&e._updateViewMatrix(this[V].rightViewMatrix)}}const U=Symbol("@@webxr-polyfill/XRViewport");class H{constructor(e){this[U]={target:e}}get x(){return this[U].target.x}get y(){return this[U].target.y}get width(){return this[U].target.width}get height(){return this[U].target.height}}const X=["left","right"],W=Symbol("@@webxr-polyfill/XRView");class j{constructor(e,t,i){if(!X.includes(t))throw new Error(`XREye must be one of: ${X}`);const r=Object.create(null),n=new H(r);this[W]={device:e,eye:t,viewport:n,temp:r,sessionId:i,transform:null}}get eye(){return this[W].eye}get projectionMatrix(){return this[W].device.getProjectionMatrix(this.eye)}get transform(){return this[W].transform}_updateViewMatrix(e){let t=p(new Float32Array(16));f(t,e),this[W].transform=new k(t)}_getViewport(e){this[W].viewport;if(this[W].device.getViewport(this[W].sessionId,this.eye,e,this[W].temp))return this[W].viewport}}var Y=1e-6,Z="undefined"!=typeof Float32Array?Float32Array:Array;Math.PI;function q(){var e=new Z(3);return Z!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e}function J(e,t,i){var r=new Z(3);return r[0]=e,r[1]=t,r[2]=i,r}function K(e,t,i){var r=t[0],n=t[1],s=t[2],a=i[0],o=i[1],l=i[2];return e[0]=n*l-s*o,e[1]=s*a-r*l,e[2]=r*o-n*a,e}var $,ee=function(e){var t=e[0],i=e[1],r=e[2];return Math.sqrt(t*t+i*i+r*r)};$=q();!function(){var e,t=(e=new Z(4),Z!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0,e[3]=0),e)}();function te(){var e=new Z(4);return Z!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e[3]=1,e}function ie(e,t,i,r){var n=t[0],s=t[1],a=t[2],o=t[3],l=i[0],A=i[1],h=i[2],c=i[3],d=void 0,u=void 0,p=void 0,f=void 0,m=void 0;return(u=n*l+s*A+a*h+o*c)<0&&(u=-u,l=-l,A=-A,h=-h,c=-c),1-u>Y?(d=Math.acos(u),p=Math.sin(d),f=Math.sin((1-r)*d)/p,m=Math.sin(r*d)/p):(f=1-r,m=r),e[0]=f*n+m*l,e[1]=f*s+m*A,e[2]=f*a+m*h,e[3]=f*o+m*c,e}var re,ne,se,ae,oe,le,Ae,he=function(e,t){var i=t[0],r=t[1],n=t[2],s=t[3],a=i*i+r*r+n*n+s*s;return a>0&&(a=1/Math.sqrt(a),e[0]=i*a,e[1]=r*a,e[2]=n*a,e[3]=s*a),e};re=q(),ne=J(1,0,0),se=J(0,1,0),ae=te(),oe=te(),le=new Z(9),Z!=Float32Array&&(le[1]=0,le[2]=0,le[3]=0,le[5]=0,le[6]=0,le[7]=0),le[0]=1,le[4]=1,le[8]=1,Ae=le;!function(){var e,t=(e=new Z(2),Z!=Float32Array&&(e[0]=0,e[1]=0),e)}();const ce=Symbol("@@webxr-polyfill/XRFrame");class de{constructor(e,t,i){const r=new z(e),n=[new j(e,"left",i)];t.immersive&&n.push(new j(e,"right",i)),r.views=n,this[ce]={device:e,viewerPose:r,views:n,session:t}}get session(){return this[ce].session}get views(){return this[ce].views}getViewerPose(e){return this[ce].viewerPose.updateFromReferenceSpace(e),this[ce].viewerPose}getPose(e,t){if("viewer"===e._specialType){let e=this.getViewerPose(t);return new XRPose(new XRRigidTransform(e.poseModelMatrix),e.emulatedPosition)}return"target-ray"===e._specialType||"grip"===e._specialType?this[ce].device.getInputPose(e._inputSource,t,e._specialType):null}}const ue=Symbol("@@webxr-polyfill/XRStageBoundsPoint");class pe{constructor(e,t){this[ue]={x:e,z:t}}get x(){return this[ue].x}get z(){return this[ue].z}}const fe=Symbol("@@webxr-polyfill/XRStageBounds");class me{constructor(e){const t=[];for(let i=0;i<e.length;i+=2)t.push(new pe(e[i],e[i+1]));this[fe]={geometry:t}}get geometry(){return this[fe].geometry}}const ge=Symbol("@@webxr-polyfill/XRSpace");class we{constructor(e=null,t=null){this[ge]={specialType:e,inputSource:t}}get _specialType(){return this[ge].specialType}get _inputSource(){return this[ge].inputSource}}const ve=1.6,ye=Symbol("@@webxr-polyfill/XRReferenceSpace"),be=["viewer","local","local-floor","bounded-floor","unbounded"],Ee=Object.freeze({disableStageEmulation:!1,stageEmulationHeight:0});class Me extends we{constructor(e,t,i,r,n){if(i=Object.assign({},Ee,i),!be.includes(t))throw new Error(`XRReferenceSpaceType must be one of ${be}`);if(super("viewer"===t?"viewer":null),this._isFloor(t)&&i.disableStageEmulation&&!r)throw new Error("XRReferenceSpace cannot use 'bounded-floor' type, if disabling emulation and platform does not provide");const{disableStageEmulation:s,stageEmulationHeight:a}=i;let o=0;this._isFloor(t)&&!r&&(o=0!==a?a:ve),this._isFloor(t)&&!r&&((r=p(new Float32Array(16)))[13]=o),r||(r=p(new Float32Array(16))),this[ye]={disableStageEmulation:s,stageEmulationHeight:a,emulatedHeight:o,type:t,transform:r,device:e,bounds:n,options:i,originOffset:p(new Float32Array(16))},this.onboundschange=void 0}_isFloor(e){return"bounded-floor"===e||"local-floor"===e}get bounds(){return this[ye].bounds}get emulatedHeight(){return this[ye].emulatedHeight}get type(){return this[ye].type}transformBasePoseMatrix(e,t){if(this[ye].transform)m(e,this[ye].transform,t);else switch(this.type){case"local":return void(e!==t&&u(e,t))}}transformBaseViewMatrix(e,t){let i=this[ye].transform;return i?(f(e,i),m(e,t,e)):u(e,t),e}_inverseOriginOffsetMatrix(){let e=p(new Float32Array(16));return f(e,this[ye].originOffset),e}_originOffsetMatrix(){return this[ye].originOffset}_adjustForOriginOffset(e){m(e,this._inverseOriginOffsetMatrix(),e)}getOffsetReferenceSpace(e){let t=new Me(this[ye].device,this[ye].type,this[ye].options,this[ye].transform,this[ye].bounds);return m(t[ye].originOffset,this[ye].originOffset,e.matrix),t}}const _e=Symbol("@@webxr-polyfill/polyfilled-xr-compatible"),xe=Symbol("@@webxr-polyfill/xr-compatible"),Fe=Symbol("@@webxr-polyfill/XRWebGLLayer"),Se=Object.freeze({antialias:!0,depth:!1,stencil:!1,alpha:!0,multiview:!1,ignoreDepthValues:!1,framebufferScaleFactor:1});const Re=Symbol("@@webxr-polyfill/XRSession");class Te extends i{constructor(e,t,i){super();let r="inline"!=t;this[Re]={device:e,mode:t,immersive:r,outputContext:null,ended:!1,suspended:!1,suspendedCallback:null,id:i,activeRenderState:null,pendingRenderState:null};const n=new de(e,this,this[Re].id);this[Re].frame=n,this[Re].onPresentationEnd=(t=>{if(t!==this[Re].id){this[Re].suspended=!1,this.dispatchEvent("focus",{session:this});const e=this[Re].suspendedCallback;return this[Re].suspendedCallback=null,void(e&&this.requestAnimationFrame(e))}this[Re].ended=!0,e.removeEventListener("@webvr-polyfill/vr-present-end",this[Re].onPresentationEnd),e.removeEventListener("@webvr-polyfill/vr-present-start",this[Re].onPresentationStart),e.removeEventListener("@@webvr-polyfill/input-select-start",this[Re].onSelectStart),e.removeEventListener("@@webvr-polyfill/input-select-end",this[Re].onSelectEnd),this.dispatchEvent("end",{session:this})}),e.addEventListener("@@webxr-polyfill/vr-present-end",this[Re].onPresentationEnd),this[Re].onPresentationStart=(e=>{e!==this[Re].id&&(this[Re].suspended=!0,this.dispatchEvent("blur",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-start",this[Re].onPresentationStart),this[Re].onSelectStart=(e=>{e.sessionId===this[Re].id&&this.dispatchEvent("selectstart",{frame:this[Re].frame,inputSource:e.inputSource})}),e.addEventListener("@@webxr-polyfill/input-select-start",this[Re].onSelectStart),this[Re].onSelectEnd=(e=>{e.sessionId===this[Re].id&&(this.dispatchEvent("selectend",{frame:this[Re].frame,inputSource:e.inputSource}),this.dispatchEvent("select",{frame:this[Re].frame,inputSource:e.inputSource}))}),e.addEventListener("@@webxr-polyfill/input-select-end",this[Re].onSelectEnd),this.onblur=void 0,this.onfocus=void 0,this.onresetpose=void 0,this.onend=void 0,this.onselect=void 0,this.onselectstart=void 0,this.onselectend=void 0}get renderState(){return this[Re].activeRenderState}get immersive(){return this[Re].immersive}get outputContext(){return this[Re].outputContext}get depthNear(){return this[Re].device.depthNear}set depthNear(e){this[Re].device.depthNear=e}get depthFar(){return this[Re].device.depthFar}set depthFar(e){this[Re].device.depthFar=e}get environmentBlendMode(){return this[Re].device.environmentBlendMode||"opaque"}get baseLayer(){return this[Re].baseLayer}set baseLayer(e){this[Re].ended||(this[Re].baseLayer=e,this[Re].device.onBaseLayerSet(this[Re].id,e))}async requestReferenceSpace(e,t={}){if(this[Re].ended)return;if(t=Object.assign({},Ee,t),!be.includes(e))throw new TypeError(`XRReferenceSpaceType must be one of ${be}`);let i=null,r=null;try{i=await this[Re].device.requestFrameOfReferenceTransform(e,t)}catch(i){if("stage"!==e||t.disableStageEmulation)throw i}return"stage"===e&&i&&(r=this[Re].device.requestStageBounds())&&(r=new me(r)),new Me(this[Re].device,e,t,i,r)}requestAnimationFrame(e){if(!(this[Re].ended||this[Re].suspended&&this[Re].suspendedCallback))return this[Re].suspended&&!this[Re].suspendedCallback&&(this[Re].suspendedCallback=e),this[Re].device.requestAnimationFrame(()=>{null!==this[Re].pendingRenderState&&(this[Re].activeRenderState=this[Re].pendingRenderState,this[Re].pendingRenderState=null,this[Re].activeRenderState.baseLayer&&this[Re].device.onBaseLayerSet(this[Re].id,this[Re].activeRenderState.baseLayer),this[Re].activeRenderState.inlineVerticalFieldOfView&&this[Re].device.onInlineVerticalFieldOfViewSet(this[Re].id,this[Re].activeRenderState.inlineVerticalFieldOfView)),this[Re].device.onFrameStart(this[Re].id),e(o(),this[Re].frame),this[Re].device.onFrameEnd(this[Re].id)})}cancelAnimationFrame(e){this[Re].ended||this[Re].device.cancelAnimationFrame(e)}get inputSources(){return this[Re].device.getInputSources()}async end(){if(!this[Re].ended)return this.immersive||(this[Re].ended=!0,this[Re].device.removeEventListener("@@webvr-polyfill/vr-present-start",this[Re].onPresentationStart),this[Re].device.removeEventListener("@@webvr-polyfill/vr-present-end",this[Re].onPresentationEnd),this[Re].device.removeEventListener("@@webvr-polyfill/input-select-start",this[Re].onSelectStart),this[Re].device.removeEventListener("@@webvr-polyfill/input-select-end",this[Re].onSelectEnd),this.dispatchEvent("end",{session:this})),this[Re].device.endSession(this[Re].id)}updateRenderState(e){if(this[Re].ended){throw new Error("Can't call updateRenderState on an XRSession that has already ended.")}if(e.baseLayer&&e.baseLayer._session!==this){throw new Error("Called updateRenderState with a base layer that was created by a different session.")}if(null!==e.inlineVerticalFieldOfView&&void 0!==e.inlineVerticalFieldOfView){if(this[Re].immersive){throw new Error("inlineVerticalFieldOfView must not be set for an XRRenderState passed to updateRenderState for an immersive session.")}e.inlineVerticalFieldOfView=Math.min(3.13,Math.max(.01,e.inlineVerticalFieldOfView))}null===this[Re].pendingRenderState&&(this[Re].pendingRenderState=Object.assign({},this[Re].activeRenderState,e))}}const Be=Symbol("@@webxr-polyfill/XRInputSource");class Ce{constructor(e){this[Be]={impl:e,gripSpace:new we("grip",this),targetRaySpace:new we("target-ray",this)}}get handedness(){return this[Be].impl.handedness}get targetRayMode(){return this[Be].impl.targetRayMode}get gripSpace(){let e=this[Be].impl.targetRayMode;return"gaze"===e||"screen"===e?null:this[Be].gripSpace}get targetRaySpace(){return this[Be].targetRaySpace}get gamepad(){return this[Be].impl.gamepad}}const Pe=Symbol("@@webxr-polyfill/XRRenderState"),De=Object.freeze({depthNear:.1,depthFar:1e3,inlineVerticalFieldOfView:null,baseLayer:null});var Ie={XR:class extends i{constructor(e){super(),this[r]={device:null,devicePromise:e,immersiveSession:null,inlineSessions:new Set},e.then(e=>{this[r].device=e})}async supportsSession(e){return this[r].device||await this[r].devicePromise,"inline"==e||this[r].device.supportsSession(e)?Promise.resolve(null):Promise.reject(null)}async requestSession(e){if(!this[r].device){if("inline"!=e)throw new Error(s);await this[r].devicePromise}const t=await this[r].device.requestSession(e),i=new XRSession(this[r].device,e,t);"inline"==e?this[r].inlineSessions.add(i):this[r].immersiveSession=i;const n=()=>{"inline"==e?this[r].inlineSessions.delete(i):this[r].immersiveSession=null,i.removeEventListener("end",n)};return i.addEventListener("end",n),i}},XRSession:Te,XRFrame:de,XRView:j,XRViewport:H,XRViewerPose:z,XRWebGLLayer:class{constructor(e,t,i={}){const r=Object.assign({},Se,i);if(!(e instanceof Te))throw new Error("session must be a XRSession");if(e.ended)throw new Error("InvalidStateError");if(t[_e]&&!0!==t[xe])throw new Error("InvalidStateError");const n=t.getParameter(t.FRAMEBUFFER_BINDING);this[Fe]={context:t,config:r,framebuffer:n,session:e}}get context(){return this[Fe].context}get antialias(){return this[Fe].config.antialias}get ignoreDepthValues(){return!0}get framebuffer(){return this[Fe].framebuffer}get framebufferWidth(){return this[Fe].context.drawingBufferWidth}get framebufferHeight(){return this[Fe].context.drawingBufferHeight}get _session(){return this[Fe].session}getViewport(e){return e._getViewport(this)}},XRSpace:we,XRReferenceSpace:Me,XRStageBounds:me,XRStageBoundsPoint:pe,XRInputSource:Ce,XRRenderState:class{constructor(e={}){const t=Object.assign({},De,e);this[Pe]={config:t}}get depthNear(){return this[Pe].depthNear}get depthFar(){return this[Pe].depthFar}get inlineVerticalFieldOfView(){return this[Pe].inlineVerticalFieldOfView}get baseLayer(){return this[Pe].baseLayer}},XRRigidTransform:k,XRPose:A};const Le=e=>"function"!=typeof e.prototype.makeXRCompatible&&(e.prototype.makeXRCompatible=function(){return this[xe]=!0,Promise.resolve()},!0),Oe=e=>{const t=e.prototype.getContext;e.prototype.getContext=function(e,i){const r=t.call(this,e,i);return r[_e]=!0,i&&"xrCompatible"in i&&(r[xe]=i.xrCompatible),r}},Qe=e=>!(!e.ImageBitmapRenderingContext||!e.createImageBitmap),Ne=e=>{var t=!1;return Ge=e.navigator.userAgent||e.navigator.vendor||e.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(Ge)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(Ge.substr(0,4)))&&(t=!0),t};var Ge;const ke=e=>{e.style.display="block",e.style.position="absolute",e.style.width=e.style.height="1px",e.style.top=e.style.left="0px"};var Ve="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var ze,Ue,He=(function(e,t){e.exports=function(){var e,t,i,r=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var i=0;i<t.length;i++){var r=t[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,i,r){return i&&e(t.prototype,i),r&&e(t,r),t}}(),s=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var i=[],r=!0,n=!1,s=void 0;try{for(var a,o=e[Symbol.iterator]();!(r=(a=o.next()).done)&&(i.push(a.value),!t||i.length!==t);r=!0);}catch(e){n=!0,s=e}finally{try{!r&&o.return&&o.return()}finally{if(n)throw s}}return i}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},a=function(e,t,i){return e+(t-e)*i},o=function(){var e=/iPad|iPhone|iPod/.test(navigator.platform);return function(){return e}}(),l=function(){var e=-1!==navigator.userAgent.indexOf("Version")&&-1!==navigator.userAgent.indexOf("Android")&&-1!==navigator.userAgent.indexOf("Chrome");return function(){return e}}(),A=(/^((?!chrome|android).)*safari/i.test(navigator.userAgent),function(){var e=-1!==navigator.userAgent.indexOf("Firefox")&&-1!==navigator.userAgent.indexOf("Android");return function(){return e}}()),h=(t=navigator.userAgent.match(/.*Chrome\/([0-9]+)/),i=t?parseInt(t[1],10):null,function(){return i}),c=function(){var e=!1;if(65===h()){var t=navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/);if(t){var i=t[1].split("."),r=s(i,4),n=(r[0],r[1],r[2]),a=r[3];e=3325===parseInt(n,10)&&parseInt(a,10)<148}}return function(){return e}}(),d=function(){var e=-1!==navigator.userAgent.indexOf("R7 Build");return function(){return e}}(),u=function(){var e=90==window.orientation||-90==window.orientation;return d()?!e:e},p=function(){return Math.max(window.screen.width,window.screen.height)*window.devicePixelRatio},f=function(){return Math.min(window.screen.width,window.screen.height)*window.devicePixelRatio},m=function(){if(document.exitFullscreen)document.exitFullscreen();else if(document.webkitExitFullscreen)document.webkitExitFullscreen();else if(document.mozCancelFullScreen)document.mozCancelFullScreen();else{if(!document.msExitFullscreen)return!1;document.msExitFullscreen()}return!0},g=function(e,t,i,r){var n=e.createShader(e.VERTEX_SHADER);e.shaderSource(n,t),e.compileShader(n);var s=e.createShader(e.FRAGMENT_SHADER);e.shaderSource(s,i),e.compileShader(s);var a=e.createProgram();for(var o in e.attachShader(a,n),e.attachShader(a,s),r)e.bindAttribLocation(a,r[o],o);return e.linkProgram(a),e.deleteShader(n),e.deleteShader(s),a},w=function(e,t){for(var i={},r=e.getProgramParameter(t,e.ACTIVE_UNIFORMS),n="",s=0;s<r;s++){var a=e.getActiveUniform(t,s);n=a.name.replace("[0]",""),i[n]=e.getUniformLocation(t,n)}return i},v=function(){var e,t=!1;return e=navigator.userAgent||navigator.vendor||window.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(e)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(e.substr(0,4)))&&(t=!0),t},y=function(e,t){for(var i in t)t.hasOwnProperty(i)&&(e[i]=t[i]);return e},b=function(e){if(o()){var t=e.style.width,i=e.style.height;e.style.width=parseInt(t)+1+"px",e.style.height=parseInt(i)+"px",setTimeout(function(){e.style.width=t,e.style.height=i},100)}window.canvas=e},E=function(){var e=Math.PI/180,t=.25*Math.PI,i=new Float32Array([0,0,0,1]),r=new Float32Array([0,0,0]);function n(n,s,a,o,l,A){!function(i,r,n,s){var a=Math.tan(r?r.upDegrees*e:t),o=Math.tan(r?r.downDegrees*e:t),l=Math.tan(r?r.leftDegrees*e:t),A=Math.tan(r?r.rightDegrees*e:t),h=2/(l+A),c=2/(a+o);i[0]=h,i[1]=0,i[2]=0,i[3]=0,i[4]=0,i[5]=c,i[6]=0,i[7]=0,i[8]=-(l-A)*h*.5,i[9]=(a-o)*c*.5,i[10]=s/(n-s),i[11]=-1,i[12]=0,i[13]=0,i[14]=s*n/(n-s),i[15]=0}(n,o||null,A.depthNear,A.depthFar);var h,c,d,u,p,f,m,g,w,v,y,b,E,M,_,x,F,S,R,T=a.orientation||i,B=a.position||r;h=s,d=B,u=(c=T)[0],p=c[1],f=c[2],m=c[3],y=u*(g=u+u),b=u*(w=p+p),E=u*(v=f+f),M=p*w,_=p*v,x=f*v,F=m*g,S=m*w,R=m*v,h[0]=1-(M+x),h[1]=b+R,h[2]=E-S,h[3]=0,h[4]=b-R,h[5]=1-(y+x),h[6]=_+F,h[7]=0,h[8]=E+S,h[9]=_-F,h[10]=1-(y+M),h[11]=0,h[12]=d[0],h[13]=d[1],h[14]=d[2],h[15]=1,l&&function(e,t,i){var r,n,s,a,o,l,A,h,c,d,u,p,f=i[0],m=i[1],g=i[2];t===e?(e[12]=t[0]*f+t[4]*m+t[8]*g+t[12],e[13]=t[1]*f+t[5]*m+t[9]*g+t[13],e[14]=t[2]*f+t[6]*m+t[10]*g+t[14],e[15]=t[3]*f+t[7]*m+t[11]*g+t[15]):(r=t[0],n=t[1],s=t[2],a=t[3],o=t[4],l=t[5],A=t[6],h=t[7],c=t[8],d=t[9],u=t[10],p=t[11],e[0]=r,e[1]=n,e[2]=s,e[3]=a,e[4]=o,e[5]=l,e[6]=A,e[7]=h,e[8]=c,e[9]=d,e[10]=u,e[11]=p,e[12]=r*f+o*m+c*g+t[12],e[13]=n*f+l*m+d*g+t[13],e[14]=s*f+A*m+u*g+t[14],e[15]=a*f+h*m+p*g+t[15])}(s,s,l),function(e,t){var i=t[0],r=t[1],n=t[2],s=t[3],a=t[4],o=t[5],l=t[6],A=t[7],h=t[8],c=t[9],d=t[10],u=t[11],p=t[12],f=t[13],m=t[14],g=t[15],w=i*o-r*a,v=i*l-n*a,y=i*A-s*a,b=r*l-n*o,E=r*A-s*o,M=n*A-s*l,_=h*f-c*p,x=h*m-d*p,F=h*g-u*p,S=c*m-d*f,R=c*g-u*f,T=d*g-u*m,B=w*T-v*R+y*S+b*F-E*x+M*_;if(!B)return null;B=1/B,e[0]=(o*T-l*R+A*S)*B,e[1]=(n*R-r*T-s*S)*B,e[2]=(f*M-m*E+g*b)*B,e[3]=(d*E-c*M-u*b)*B,e[4]=(l*F-a*T-A*x)*B,e[5]=(i*T-n*F+s*x)*B,e[6]=(m*y-p*M-g*v)*B,e[7]=(h*M-d*y+u*v)*B,e[8]=(a*R-o*F+A*_)*B,e[9]=(r*F-i*R-s*_)*B,e[10]=(p*E-f*y+g*w)*B,e[11]=(c*y-h*E-u*w)*B,e[12]=(o*x-a*S-l*_)*B,e[13]=(i*S-r*x+n*_)*B,e[14]=(f*v-p*b-m*w)*B,e[15]=(h*b-c*v+d*w)*B}(s,s)}return function(e,t,i){return!(!e||!t||(e.pose=t,e.timestamp=t.timestamp,n(e.leftProjectionMatrix,e.leftViewMatrix,t,i._getFieldOfView("left"),i._getEyeOffset("left"),i),n(e.rightProjectionMatrix,e.rightViewMatrix,t,i._getFieldOfView("right"),i._getEyeOffset("right"),i),0))}}(),M=function(e){var t,i=e.indexOf("://");t=-1!==i?i+3:0;var r=e.indexOf("/",t);return-1===r&&(r=e.length),e.substring(0,r)},_=(e={},function(t,i){void 0===e[t]&&(console.warn("webvr-polyfill: "+i),e[t]=!0)}),x=function(e,t){var i=t?"Please use "+t+" instead.":"";_(e,e+" has been deprecated. This may not work on native WebVR displays. "+i)},F=function(e,t,i){if(t){for(var r=[],n=null,s=0;s<t.length;++s){var a=t[s];switch(a){case e.TEXTURE_BINDING_2D:case e.TEXTURE_BINDING_CUBE_MAP:var o=t[++s];if(o<e.TEXTURE0||o>e.TEXTURE31){console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"),r.push(null,null);break}n||(n=e.getParameter(e.ACTIVE_TEXTURE)),e.activeTexture(o),r.push(e.getParameter(a),null);break;case e.ACTIVE_TEXTURE:n=e.getParameter(e.ACTIVE_TEXTURE),r.push(null);break;default:r.push(e.getParameter(a))}}i(e);for(var s=0;s<t.length;++s){var a=t[s],l=r[s];switch(a){case e.ACTIVE_TEXTURE:break;case e.ARRAY_BUFFER_BINDING:e.bindBuffer(e.ARRAY_BUFFER,l);break;case e.COLOR_CLEAR_VALUE:e.clearColor(l[0],l[1],l[2],l[3]);break;case e.COLOR_WRITEMASK:e.colorMask(l[0],l[1],l[2],l[3]);break;case e.CURRENT_PROGRAM:e.useProgram(l);break;case e.ELEMENT_ARRAY_BUFFER_BINDING:e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,l);break;case e.FRAMEBUFFER_BINDING:e.bindFramebuffer(e.FRAMEBUFFER,l);break;case e.RENDERBUFFER_BINDING:e.bindRenderbuffer(e.RENDERBUFFER,l);break;case e.TEXTURE_BINDING_2D:var o=t[++s];if(o<e.TEXTURE0||o>e.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_2D,l);break;case e.TEXTURE_BINDING_CUBE_MAP:var o=t[++s];if(o<e.TEXTURE0||o>e.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_CUBE_MAP,l);break;case e.VIEWPORT:e.viewport(l[0],l[1],l[2],l[3]);break;case e.BLEND:case e.CULL_FACE:case e.DEPTH_TEST:case e.SCISSOR_TEST:case e.STENCIL_TEST:l?e.enable(a):e.disable(a);break;default:console.log("No GL restore behavior for 0x"+a.toString(16))}n&&e.activeTexture(n)}}else i(e)},S=["attribute vec2 position;","attribute vec3 texCoord;","varying vec2 vTexCoord;","uniform vec4 viewportOffsetScale[2];","void main() {"," vec4 viewport = viewportOffsetScale[int(texCoord.z)];"," vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;"," gl_Position = vec4( position, 1.0, 1.0 );","}"].join("\n"),R=["precision mediump float;","uniform sampler2D diffuse;","varying vec2 vTexCoord;","void main() {"," gl_FragColor = texture2D(diffuse, vTexCoord);","}"].join("\n");function T(e,t,i,r){this.gl=e,this.cardboardUI=t,this.bufferScale=i,this.dirtySubmitFrameBindings=r,this.ctxAttribs=e.getContextAttributes(),this.meshWidth=20,this.meshHeight=20,this.bufferWidth=e.drawingBufferWidth,this.bufferHeight=e.drawingBufferHeight,this.realBindFramebuffer=e.bindFramebuffer,this.realEnable=e.enable,this.realDisable=e.disable,this.realColorMask=e.colorMask,this.realClearColor=e.clearColor,this.realViewport=e.viewport,o()||(this.realCanvasWidth=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"width"),this.realCanvasHeight=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"height")),this.isPatched=!1,this.lastBoundFramebuffer=null,this.cullFace=!1,this.depthTest=!1,this.blend=!1,this.scissorTest=!1,this.stencilTest=!1,this.viewport=[0,0,0,0],this.colorMask=[!0,!0,!0,!0],this.clearColor=[0,0,0,0],this.attribs={position:0,texCoord:1},this.program=g(e,S,R,this.attribs),this.uniforms=w(e,this.program),this.viewportOffsetScale=new Float32Array(8),this.setTextureBounds(),this.vertexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),this.indexCount=0,this.renderTarget=e.createTexture(),this.framebuffer=e.createFramebuffer(),this.depthStencilBuffer=null,this.depthBuffer=null,this.stencilBuffer=null,this.ctxAttribs.depth&&this.ctxAttribs.stencil?this.depthStencilBuffer=e.createRenderbuffer():this.ctxAttribs.depth?this.depthBuffer=e.createRenderbuffer():this.ctxAttribs.stencil&&(this.stencilBuffer=e.createRenderbuffer()),this.patch(),this.onResize()}T.prototype.destroy=function(){var e=this.gl;this.unpatch(),e.deleteProgram(this.program),e.deleteBuffer(this.vertexBuffer),e.deleteBuffer(this.indexBuffer),e.deleteTexture(this.renderTarget),e.deleteFramebuffer(this.framebuffer),this.depthStencilBuffer&&e.deleteRenderbuffer(this.depthStencilBuffer),this.depthBuffer&&e.deleteRenderbuffer(this.depthBuffer),this.stencilBuffer&&e.deleteRenderbuffer(this.stencilBuffer),this.cardboardUI&&this.cardboardUI.destroy()},T.prototype.onResize=function(){var e=this.gl,t=this,i=[e.RENDERBUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0];F(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.framebuffer),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.texImage2D(e.TEXTURE_2D,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,t.bufferWidth,t.bufferHeight,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t.renderTarget,0),t.ctxAttribs.depth&&t.ctxAttribs.stencil?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthStencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_STENCIL,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.RENDERBUFFER,t.depthStencilBuffer)):t.ctxAttribs.depth?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_COMPONENT16,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.RENDERBUFFER,t.depthBuffer)):t.ctxAttribs.stencil&&(e.bindRenderbuffer(e.RENDERBUFFER,t.stencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.STENCIL_INDEX8,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.STENCIL_ATTACHMENT,e.RENDERBUFFER,t.stencilBuffer)),!e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer incomplete!"),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),t.realClearColor.apply(e,t.clearColor)}),this.cardboardUI&&this.cardboardUI.onResize()},T.prototype.patch=function(){if(!this.isPatched){var e=this,t=this.gl.canvas,i=this.gl;o()||(t.width=p()*this.bufferScale,t.height=f()*this.bufferScale,Object.defineProperty(t,"width",{configurable:!0,enumerable:!0,get:function(){return e.bufferWidth},set:function(i){e.bufferWidth=i,e.realCanvasWidth.set.call(t,i),e.onResize()}}),Object.defineProperty(t,"height",{configurable:!0,enumerable:!0,get:function(){return e.bufferHeight},set:function(i){e.bufferHeight=i,e.realCanvasHeight.set.call(t,i),e.onResize()}})),this.lastBoundFramebuffer=i.getParameter(i.FRAMEBUFFER_BINDING),null==this.lastBoundFramebuffer&&(this.lastBoundFramebuffer=this.framebuffer,this.gl.bindFramebuffer(i.FRAMEBUFFER,this.framebuffer)),this.gl.bindFramebuffer=function(t,r){e.lastBoundFramebuffer=r||e.framebuffer,e.realBindFramebuffer.call(i,t,e.lastBoundFramebuffer)},this.cullFace=i.getParameter(i.CULL_FACE),this.depthTest=i.getParameter(i.DEPTH_TEST),this.blend=i.getParameter(i.BLEND),this.scissorTest=i.getParameter(i.SCISSOR_TEST),this.stencilTest=i.getParameter(i.STENCIL_TEST),i.enable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!0;break;case i.DEPTH_TEST:e.depthTest=!0;break;case i.BLEND:e.blend=!0;break;case i.SCISSOR_TEST:e.scissorTest=!0;break;case i.STENCIL_TEST:e.stencilTest=!0}e.realEnable.call(i,t)},i.disable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!1;break;case i.DEPTH_TEST:e.depthTest=!1;break;case i.BLEND:e.blend=!1;break;case i.SCISSOR_TEST:e.scissorTest=!1;break;case i.STENCIL_TEST:e.stencilTest=!1}e.realDisable.call(i,t)},this.colorMask=i.getParameter(i.COLOR_WRITEMASK),i.colorMask=function(t,r,n,s){e.colorMask[0]=t,e.colorMask[1]=r,e.colorMask[2]=n,e.colorMask[3]=s,e.realColorMask.call(i,t,r,n,s)},this.clearColor=i.getParameter(i.COLOR_CLEAR_VALUE),i.clearColor=function(t,r,n,s){e.clearColor[0]=t,e.clearColor[1]=r,e.clearColor[2]=n,e.clearColor[3]=s,e.realClearColor.call(i,t,r,n,s)},this.viewport=i.getParameter(i.VIEWPORT),i.viewport=function(t,r,n,s){e.viewport[0]=t,e.viewport[1]=r,e.viewport[2]=n,e.viewport[3]=s,e.realViewport.call(i,t,r,n,s)},this.isPatched=!0,b(t)}},T.prototype.unpatch=function(){if(this.isPatched){var e=this.gl,t=this.gl.canvas;o()||(Object.defineProperty(t,"width",this.realCanvasWidth),Object.defineProperty(t,"height",this.realCanvasHeight)),t.width=this.bufferWidth,t.height=this.bufferHeight,e.bindFramebuffer=this.realBindFramebuffer,e.enable=this.realEnable,e.disable=this.realDisable,e.colorMask=this.realColorMask,e.clearColor=this.realClearColor,e.viewport=this.realViewport,this.lastBoundFramebuffer==this.framebuffer&&e.bindFramebuffer(e.FRAMEBUFFER,null),this.isPatched=!1,setTimeout(function(){b(t)},1)}},T.prototype.setTextureBounds=function(e,t){e||(e=[0,0,.5,1]),t||(t=[.5,0,.5,1]),this.viewportOffsetScale[0]=e[0],this.viewportOffsetScale[1]=e[1],this.viewportOffsetScale[2]=e[2],this.viewportOffsetScale[3]=e[3],this.viewportOffsetScale[4]=t[0],this.viewportOffsetScale[5]=t[1],this.viewportOffsetScale[6]=t[2],this.viewportOffsetScale[7]=t[3]},T.prototype.submitFrame=function(){var e=this.gl,t=this,i=[];if(this.dirtySubmitFrameBindings||i.push(e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING,e.ELEMENT_ARRAY_BUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0),F(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.cullFace&&t.realDisable.call(e,e.CULL_FACE),t.depthTest&&t.realDisable.call(e,e.DEPTH_TEST),t.blend&&t.realDisable.call(e,e.BLEND),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realDisable.call(e,e.STENCIL_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),(t.ctxAttribs.alpha||o())&&(t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT)),e.useProgram(t.program),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,t.indexBuffer),e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.enableVertexAttribArray(t.attribs.position),e.enableVertexAttribArray(t.attribs.texCoord),e.vertexAttribPointer(t.attribs.position,2,e.FLOAT,!1,20,0),e.vertexAttribPointer(t.attribs.texCoord,3,e.FLOAT,!1,20,8),e.activeTexture(e.TEXTURE0),e.uniform1i(t.uniforms.diffuse,0),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.uniform4fv(t.uniforms.viewportOffsetScale,t.viewportOffsetScale),e.drawElements(e.TRIANGLES,t.indexCount,e.UNSIGNED_SHORT,0),t.cardboardUI&&t.cardboardUI.renderNoState(),t.realBindFramebuffer.call(t.gl,e.FRAMEBUFFER,t.framebuffer),t.ctxAttribs.preserveDrawingBuffer||(t.realClearColor.call(e,0,0,0,0),e.clear(e.COLOR_BUFFER_BIT)),t.dirtySubmitFrameBindings||t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.cullFace&&t.realEnable.call(e,e.CULL_FACE),t.depthTest&&t.realEnable.call(e,e.DEPTH_TEST),t.blend&&t.realEnable.call(e,e.BLEND),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realEnable.call(e,e.STENCIL_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),!t.ctxAttribs.alpha&&t.ctxAttribs.preserveDrawingBuffer||t.realClearColor.apply(e,t.clearColor)}),o()){var r=e.canvas;r.width==t.bufferWidth&&r.height==t.bufferHeight||(t.bufferWidth=r.width,t.bufferHeight=r.height,t.onResize())}},T.prototype.updateDeviceInfo=function(e){var t=this.gl,i=this,r=[t.ARRAY_BUFFER_BINDING,t.ELEMENT_ARRAY_BUFFER_BINDING];F(t,r,function(t){var r=i.computeMeshVertices_(i.meshWidth,i.meshHeight,e);if(t.bindBuffer(t.ARRAY_BUFFER,i.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,r,t.STATIC_DRAW),!i.indexCount){var n=i.computeMeshIndices_(i.meshWidth,i.meshHeight);t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,i.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,n,t.STATIC_DRAW),i.indexCount=n.length}})},T.prototype.computeMeshVertices_=function(e,t,i){for(var r=new Float32Array(2*e*t*5),n=i.getLeftEyeVisibleTanAngles(),s=i.getLeftEyeNoLensTanAngles(),o=i.getLeftEyeVisibleScreenRect(s),l=0,A=0;A<2;A++){for(var h=0;h<t;h++)for(var c=0;c<e;c++,l++){var d=c/(e-1),u=h/(t-1),p=d,f=u,m=a(n[0],n[2],d),g=a(n[3],n[1],u),w=Math.sqrt(m*m+g*g),v=i.distortion.distortInverse(w),y=m*v/w,b=g*v/w;d=(y-s[0])/(s[2]-s[0]),u=(b-s[3])/(s[1]-s[3]),d=2*(o.x+d*o.width-.5),u=2*(o.y+u*o.height-.5),r[5*l+0]=d,r[5*l+1]=u,r[5*l+2]=p,r[5*l+3]=f,r[5*l+4]=A}var E=n[2]-n[0];n[0]=-(E+n[0]),n[2]=E-n[2],E=s[2]-s[0],s[0]=-(E+s[0]),s[2]=E-s[2],o.x=1-(o.x+o.width)}return r},T.prototype.computeMeshIndices_=function(e,t){for(var i=new Uint16Array(2*(e-1)*(t-1)*6),r=e/2,n=t/2,s=0,a=0,o=0;o<2;o++)for(var l=0;l<t;l++)for(var A=0;A<e;A++,s++)0!=A&&0!=l&&(A<=r==l<=n?(i[a++]=s,i[a++]=s-e-1,i[a++]=s-e,i[a++]=s-e-1,i[a++]=s,i[a++]=s-1):(i[a++]=s-1,i[a++]=s-e,i[a++]=s,i[a++]=s-e,i[a++]=s-1,i[a++]=s-e-1));return i},T.prototype.getOwnPropertyDescriptor_=function(e,t){var i=Object.getOwnPropertyDescriptor(e,t);return void 0!==i.get&&void 0!==i.set||(i.configurable=!0,i.enumerable=!0,i.get=function(){return this.getAttribute(t)},i.set=function(e){this.setAttribute(t,e)}),i};var B=["attribute vec2 position;","uniform mat4 projectionMat;","void main() {"," gl_Position = projectionMat * vec4( position, -1.0, 1.0 );","}"].join("\n"),C=["precision mediump float;","uniform vec4 color;","void main() {"," gl_FragColor = color;","}"].join("\n"),P=Math.PI/180,D=.3125;function I(e){this.gl=e,this.attribs={position:0},this.program=g(e,B,C,this.attribs),this.uniforms=w(e,this.program),this.vertexBuffer=e.createBuffer(),this.gearOffset=0,this.gearVertexCount=0,this.arrowOffset=0,this.arrowVertexCount=0,this.projMat=new Float32Array(16),this.listener=null,this.onResize()}function L(e){this.coefficients=e}I.prototype.destroy=function(){var e=this.gl;this.listener&&e.canvas.removeEventListener("click",this.listener,!1),e.deleteProgram(this.program),e.deleteBuffer(this.vertexBuffer)},I.prototype.listen=function(e,t){var i=this.gl.canvas;this.listener=function(r){var n=i.clientWidth/2;r.clientX>n-42&&r.clientX<n+42&&r.clientY>i.clientHeight-42?e(r):r.clientX<42&&r.clientY<42&&t(r)},i.addEventListener("click",this.listener,!1)},I.prototype.onResize=function(){var e=this.gl,t=this,i=[e.ARRAY_BUFFER_BINDING];F(e,i,function(e){var i=[],r=e.drawingBufferWidth/2,n=Math.max(screen.width,screen.height)*window.devicePixelRatio,s=e.drawingBufferWidth/n,a=s*window.devicePixelRatio,o=4*a/2,l=42*a,A=28*a/2,h=14*a;function c(e,t){var n=(90-e)*P,s=Math.cos(n),a=Math.sin(n);i.push(D*s*A+r,D*a*A+A),i.push(t*s*A+r,t*a*A+A)}i.push(r-o,l),i.push(r-o,e.drawingBufferHeight),i.push(r+o,l),i.push(r+o,e.drawingBufferHeight),t.gearOffset=i.length/2;for(var d=0;d<=6;d++){var u=60*d;c(u,1),c(u+12,1),c(u+20,.75),c(u+40,.75),c(u+48,1)}function p(t,r){i.push(h+t,e.drawingBufferHeight-h-r)}t.gearVertexCount=i.length/2-t.gearOffset,t.arrowOffset=i.length/2;var f=o/Math.sin(45*P);p(0,A),p(A,0),p(A+f,f),p(f,A+f),p(f,A-f),p(0,A),p(A,2*A),p(A+f,2*A-f),p(f,A-f),p(0,A),p(f,A-o),p(28*a,A-o),p(f,A+o),p(28*a,A+o),t.arrowVertexCount=i.length/2-t.arrowOffset,e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,new Float32Array(i),e.STATIC_DRAW)})},I.prototype.render=function(){var e=this.gl,t=this,i=[e.CULL_FACE,e.DEPTH_TEST,e.BLEND,e.SCISSOR_TEST,e.STENCIL_TEST,e.COLOR_WRITEMASK,e.VIEWPORT,e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING];F(e,i,function(e){e.disable(e.CULL_FACE),e.disable(e.DEPTH_TEST),e.disable(e.BLEND),e.disable(e.SCISSOR_TEST),e.disable(e.STENCIL_TEST),e.colorMask(!0,!0,!0,!0),e.viewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.renderNoState()})},I.prototype.renderNoState=function(){var e,t,i,r,n,s,a,o,l,A,h=this.gl;h.useProgram(this.program),h.bindBuffer(h.ARRAY_BUFFER,this.vertexBuffer),h.enableVertexAttribArray(this.attribs.position),h.vertexAttribPointer(this.attribs.position,2,h.FLOAT,!1,8,0),h.uniform4f(this.uniforms.color,1,1,1,1),e=this.projMat,t=0,i=h.drawingBufferWidth,r=0,n=h.drawingBufferHeight,o=1/(t-i),l=1/(r-n),A=1/((s=.1)-(a=1024)),e[0]=-2*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*l,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*A,e[11]=0,e[12]=(t+i)*o,e[13]=(n+r)*l,e[14]=(a+s)*A,e[15]=1,h.uniformMatrix4fv(this.uniforms.projectionMat,!1,this.projMat),h.drawArrays(h.TRIANGLE_STRIP,0,4),h.drawArrays(h.TRIANGLE_STRIP,this.gearOffset,this.gearVertexCount),h.drawArrays(h.TRIANGLE_STRIP,this.arrowOffset,this.arrowVertexCount)},L.prototype.distortInverse=function(e){for(var t=0,i=1,r=e-this.distort(t);Math.abs(i-t)>1e-4;){var n=e-this.distort(i),s=i-n*((i-t)/(n-r));t=i,i=s,r=n}return i},L.prototype.distort=function(e){for(var t=e*e,i=0,r=0;r<this.coefficients.length;r++)i=t*(i+this.coefficients[r]);return(i+1)*e};var O=Math.PI/180,Q=180/Math.PI,N=function(e,t,i){this.x=e||0,this.y=t||0,this.z=i||0};N.prototype={constructor:N,set:function(e,t,i){return this.x=e,this.y=t,this.z=i,this},copy:function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},normalize:function(){var e=this.length();if(0!==e){var t=1/e;this.multiplyScalar(t)}else this.x=0,this.y=0,this.z=0;return this},multiplyScalar:function(e){this.x*=e,this.y*=e,this.z*=e},applyQuaternion:function(e){var t=this.x,i=this.y,r=this.z,n=e.x,s=e.y,a=e.z,o=e.w,l=o*t+s*r-a*i,A=o*i+a*t-n*r,h=o*r+n*i-s*t,c=-n*t-s*i-a*r;return this.x=l*o+c*-n+A*-a-h*-s,this.y=A*o+c*-s+h*-n-l*-a,this.z=h*o+c*-a+l*-s-A*-n,this},dot:function(e){return this.x*e.x+this.y*e.y+this.z*e.z},crossVectors:function(e,t){var i=e.x,r=e.y,n=e.z,s=t.x,a=t.y,o=t.z;return this.x=r*o-n*a,this.y=n*s-i*o,this.z=i*a-r*s,this}};var G,k,V=function(e,t,i,r){this.x=e||0,this.y=t||0,this.z=i||0,this.w=void 0!==r?r:1};function z(e){this.width=e.width||p(),this.height=e.height||f(),this.widthMeters=e.widthMeters,this.heightMeters=e.heightMeters,this.bevelMeters=e.bevelMeters}V.prototype={constructor:V,set:function(e,t,i,r){return this.x=e,this.y=t,this.z=i,this.w=r,this},copy:function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w,this},setFromEulerXYZ:function(e,t,i){var r=Math.cos(e/2),n=Math.cos(t/2),s=Math.cos(i/2),a=Math.sin(e/2),o=Math.sin(t/2),l=Math.sin(i/2);return this.x=a*n*s+r*o*l,this.y=r*o*s-a*n*l,this.z=r*n*l+a*o*s,this.w=r*n*s-a*o*l,this},setFromEulerYXZ:function(e,t,i){var r=Math.cos(e/2),n=Math.cos(t/2),s=Math.cos(i/2),a=Math.sin(e/2),o=Math.sin(t/2),l=Math.sin(i/2);return this.x=a*n*s+r*o*l,this.y=r*o*s-a*n*l,this.z=r*n*l-a*o*s,this.w=r*n*s+a*o*l,this},setFromAxisAngle:function(e,t){var i=t/2,r=Math.sin(i);return this.x=e.x*r,this.y=e.y*r,this.z=e.z*r,this.w=Math.cos(i),this},multiply:function(e){return this.multiplyQuaternions(this,e)},multiplyQuaternions:function(e,t){var i=e.x,r=e.y,n=e.z,s=e.w,a=t.x,o=t.y,l=t.z,A=t.w;return this.x=i*A+s*a+r*l-n*o,this.y=r*A+s*o+n*a-i*l,this.z=n*A+s*l+i*o-r*a,this.w=s*A-i*a-r*o-n*l,this},inverse:function(){return this.x*=-1,this.y*=-1,this.z*=-1,this.normalize(),this},normalize:function(){var e=Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);return 0===e?(this.x=0,this.y=0,this.z=0,this.w=1):(e=1/e,this.x=this.x*e,this.y=this.y*e,this.z=this.z*e,this.w=this.w*e),this},slerp:function(e,t){if(0===t)return this;if(1===t)return this.copy(e);var i=this.x,r=this.y,n=this.z,s=this.w,a=s*e.w+i*e.x+r*e.y+n*e.z;if(a<0?(this.w=-e.w,this.x=-e.x,this.y=-e.y,this.z=-e.z,a=-a):this.copy(e),a>=1)return this.w=s,this.x=i,this.y=r,this.z=n,this;var o=Math.acos(a),l=Math.sqrt(1-a*a);if(Math.abs(l)<.001)return this.w=.5*(s+this.w),this.x=.5*(i+this.x),this.y=.5*(r+this.y),this.z=.5*(n+this.z),this;var A=Math.sin((1-t)*o)/l,h=Math.sin(t*o)/l;return this.w=s*A+this.w*h,this.x=i*A+this.x*h,this.y=r*A+this.y*h,this.z=n*A+this.z*h,this},setFromUnitVectors:function(e,t){return void 0===G&&(G=new N),(k=e.dot(t)+1)<1e-6?(k=0,Math.abs(e.x)>Math.abs(e.z)?G.set(-e.y,e.x,0):G.set(0,-e.z,e.y)):G.crossVectors(e,t),this.x=G.x,this.y=G.y,this.z=G.z,this.w=k,this.normalize(),this}};var U=new z({widthMeters:.11,heightMeters:.062,bevelMeters:.004}),H=new z({widthMeters:.1038,heightMeters:.0584,bevelMeters:.004}),X={CardboardV1:new j({id:"CardboardV1",label:"Cardboard I/O 2014",fov:40,interLensDistance:.06,baselineLensDistance:.035,screenLensDistance:.042,distortionCoefficients:[.441,.156],inverseCoefficients:[-.4410035,.42756155,-.4804439,.5460139,-.58821183,.5733938,-.48303202,.33299083,-.17573841,.0651772,-.01488963,.001559834]}),CardboardV2:new j({id:"CardboardV2",label:"Cardboard I/O 2015",fov:60,interLensDistance:.064,baselineLensDistance:.035,screenLensDistance:.039,distortionCoefficients:[.34,.55],inverseCoefficients:[-.33836704,-.18162185,.862655,-1.2462051,1.0560602,-.58208317,.21609078,-.05444823,.009177956,-.0009904169,6183535e-11,-16981803e-13]})};function W(e,t){this.viewer=X.CardboardV2,this.updateDeviceParams(e),this.distortion=new L(this.viewer.distortionCoefficients);for(var i=0;i<t.length;i++){var r=t[i];X[r.id]=new j(r)}}function j(e){this.id=e.id,this.label=e.label,this.fov=e.fov,this.interLensDistance=e.interLensDistance,this.baselineLensDistance=e.baselineLensDistance,this.screenLensDistance=e.screenLensDistance,this.distortionCoefficients=e.distortionCoefficients,this.inverseCoefficients=e.inverseCoefficients}W.prototype.updateDeviceParams=function(e){this.device=this.determineDevice_(e)||this.device},W.prototype.getDevice=function(){return this.device},W.prototype.setViewer=function(e){this.viewer=e,this.distortion=new L(this.viewer.distortionCoefficients)},W.prototype.determineDevice_=function(e){if(!e)return o()?(console.warn("Using fallback iOS device measurements."),H):(console.warn("Using fallback Android device measurements."),U);var t=.0254/e.xdpi,i=.0254/e.ydpi,r=p(),n=f();return new z({widthMeters:t*r,heightMeters:i*n,bevelMeters:.001*e.bevelMm})},W.prototype.getDistortedFieldOfViewLeftEye=function(){var e=this.viewer,t=this.device,i=this.distortion,r=e.screenLensDistance,n=(t.widthMeters-e.interLensDistance)/2,s=e.interLensDistance/2,a=e.baselineLensDistance-t.bevelMeters,o=t.heightMeters-a,l=Q*Math.atan(i.distort(n/r)),A=Q*Math.atan(i.distort(s/r)),h=Q*Math.atan(i.distort(a/r)),c=Q*Math.atan(i.distort(o/r));return{leftDegrees:Math.min(l,e.fov),rightDegrees:Math.min(A,e.fov),downDegrees:Math.min(h,e.fov),upDegrees:Math.min(c,e.fov)}},W.prototype.getLeftEyeVisibleTanAngles=function(){var e=this.viewer,t=this.device,i=this.distortion,r=Math.tan(-O*e.fov),n=Math.tan(O*e.fov),s=Math.tan(O*e.fov),a=Math.tan(-O*e.fov),o=t.widthMeters/4,l=t.heightMeters/2,A=e.baselineLensDistance-t.bevelMeters-l,h=e.interLensDistance/2-o,c=-A,d=e.screenLensDistance,u=i.distort((h-o)/d),p=i.distort((c+l)/d),f=i.distort((h+o)/d),m=i.distort((c-l)/d),g=new Float32Array(4);return g[0]=Math.max(r,u),g[1]=Math.min(n,p),g[2]=Math.min(s,f),g[3]=Math.max(a,m),g},W.prototype.getLeftEyeNoLensTanAngles=function(){var e=this.viewer,t=this.device,i=this.distortion,r=new Float32Array(4),n=i.distortInverse(Math.tan(-O*e.fov)),s=i.distortInverse(Math.tan(O*e.fov)),a=i.distortInverse(Math.tan(O*e.fov)),o=i.distortInverse(Math.tan(-O*e.fov)),l=t.widthMeters/4,A=t.heightMeters/2,h=e.baselineLensDistance-t.bevelMeters-A,c=e.interLensDistance/2-l,d=-h,u=e.screenLensDistance,p=(c-l)/u,f=(d+A)/u,m=(c+l)/u,g=(d-A)/u;return r[0]=Math.max(n,p),r[1]=Math.min(s,f),r[2]=Math.min(a,m),r[3]=Math.max(o,g),r},W.prototype.getLeftEyeVisibleScreenRect=function(e){var t=this.viewer,i=this.device,r=t.screenLensDistance,n=(i.widthMeters-t.interLensDistance)/2,s=t.baselineLensDistance-i.bevelMeters,a=(e[0]*r+n)/i.widthMeters,o=(e[1]*r+s)/i.heightMeters,l=(e[2]*r+n)/i.widthMeters,A=(e[3]*r+s)/i.heightMeters;return{x:a,y:A,width:l-a,height:o-A}},W.prototype.getFieldOfViewLeftEye=function(e){return e?this.getUndistortedFieldOfViewLeftEye():this.getDistortedFieldOfViewLeftEye()},W.prototype.getFieldOfViewRightEye=function(e){var t=this.getFieldOfViewLeftEye(e);return{leftDegrees:t.rightDegrees,rightDegrees:t.leftDegrees,upDegrees:t.upDegrees,downDegrees:t.downDegrees}},W.prototype.getUndistortedFieldOfViewLeftEye=function(){var e=this.getUndistortedParams_();return{leftDegrees:Q*Math.atan(e.outerDist),rightDegrees:Q*Math.atan(e.innerDist),downDegrees:Q*Math.atan(e.bottomDist),upDegrees:Q*Math.atan(e.topDist)}},W.prototype.getUndistortedViewportLeftEye=function(){var e=this.getUndistortedParams_(),t=this.viewer,i=this.device,r=t.screenLensDistance,n=i.widthMeters/r,s=i.heightMeters/r,a=i.width/n,o=i.height/s,l=Math.round((e.eyePosX-e.outerDist)*a),A=Math.round((e.eyePosY-e.bottomDist)*o);return{x:l,y:A,width:Math.round((e.eyePosX+e.innerDist)*a)-l,height:Math.round((e.eyePosY+e.topDist)*o)-A}},W.prototype.getUndistortedParams_=function(){var e=this.viewer,t=this.device,i=this.distortion,r=e.screenLensDistance,n=e.interLensDistance/2/r,s=t.widthMeters/r,a=t.heightMeters/r,o=s/2-n,l=(e.baselineLensDistance-t.bevelMeters)/r,A=e.fov,h=i.distortInverse(Math.tan(O*A)),c=Math.min(o,h),d=Math.min(n,h),u=Math.min(l,h),p=Math.min(a-l,h);return{outerDist:c,innerDist:d,topDist:p,bottomDist:u,eyePosX:o,eyePosY:l}},W.Viewers=X;var Y={format:1,last_updated:"2018-12-10T17:01:42Z",devices:[{type:"android",rules:[{mdmh:"asus/*/Nexus 7/*"},{ua:"Nexus 7"}],dpi:[320.8,323],bw:3,ac:500},{type:"android",rules:[{mdmh:"asus/*/ASUS_Z00AD/*"},{ua:"ASUS_Z00AD"}],dpi:[403,404.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Google/*/Pixel 2 XL/*"},{ua:"Pixel 2 XL"}],dpi:537.9,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Google/*/Pixel 3 XL/*"},{ua:"Pixel 3 XL"}],dpi:[558.5,553.8],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Google/*/Pixel XL/*"},{ua:"Pixel XL"}],dpi:[537.9,533],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Google/*/Pixel 3/*"},{ua:"Pixel 3"}],dpi:442.4,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Google/*/Pixel 2/*"},{ua:"Pixel 2"}],dpi:441,bw:3,ac:500},{type:"android",rules:[{mdmh:"Google/*/Pixel/*"},{ua:"Pixel"}],dpi:[432.6,436.7],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"HTC/*/HTC6435LVW/*"},{ua:"HTC6435LVW"}],dpi:[449.7,443.3],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"HTC/*/HTC One XL/*"},{ua:"HTC One XL"}],dpi:[315.3,314.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"htc/*/Nexus 9/*"},{ua:"Nexus 9"}],dpi:289,bw:3,ac:500},{type:"android",rules:[{mdmh:"HTC/*/HTC One M9/*"},{ua:"HTC One M9"}],dpi:[442.5,443.3],bw:3,ac:500},{type:"android",rules:[{mdmh:"HTC/*/HTC One_M8/*"},{ua:"HTC One_M8"}],dpi:[449.7,447.4],bw:3,ac:500},{type:"android",rules:[{mdmh:"HTC/*/HTC One/*"},{ua:"HTC One"}],dpi:472.8,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Huawei/*/Nexus 6P/*"},{ua:"Nexus 6P"}],dpi:[515.1,518],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Huawei/*/BLN-L24/*"},{ua:"HONORBLN-L24"}],dpi:480,bw:4,ac:500},{type:"android",rules:[{mdmh:"Huawei/*/BKL-L09/*"},{ua:"BKL-L09"}],dpi:403,bw:3.47,ac:500},{type:"android",rules:[{mdmh:"LENOVO/*/Lenovo PB2-690Y/*"},{ua:"Lenovo PB2-690Y"}],dpi:[457.2,454.713],bw:3,ac:500},{type:"android",rules:[{mdmh:"LGE/*/Nexus 5X/*"},{ua:"Nexus 5X"}],dpi:[422,419.9],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"LGE/*/LGMS345/*"},{ua:"LGMS345"}],dpi:[221.7,219.1],bw:3,ac:500},{type:"android",rules:[{mdmh:"LGE/*/LG-D800/*"},{ua:"LG-D800"}],dpi:[422,424.1],bw:3,ac:500},{type:"android",rules:[{mdmh:"LGE/*/LG-D850/*"},{ua:"LG-D850"}],dpi:[537.9,541.9],bw:3,ac:500},{type:"android",rules:[{mdmh:"LGE/*/VS985 4G/*"},{ua:"VS985 4G"}],dpi:[537.9,535.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"LGE/*/Nexus 5/*"},{ua:"Nexus 5 B"}],dpi:[442.4,444.8],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"LGE/*/Nexus 4/*"},{ua:"Nexus 4"}],dpi:[319.8,318.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"LGE/*/LG-P769/*"},{ua:"LG-P769"}],dpi:[240.6,247.5],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"LGE/*/LGMS323/*"},{ua:"LGMS323"}],dpi:[206.6,204.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"LGE/*/LGLS996/*"},{ua:"LGLS996"}],dpi:[403.4,401.5],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Micromax/*/4560MMX/*"},{ua:"4560MMX"}],dpi:[240,219.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Micromax/*/A250/*"},{ua:"Micromax A250"}],dpi:[480,446.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Micromax/*/Micromax AQ4501/*"},{ua:"Micromax AQ4501"}],dpi:240,bw:3,ac:500},{type:"android",rules:[{mdmh:"motorola/*/G5/*"},{ua:"Moto G (5) Plus"}],dpi:[403.4,403],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/DROID RAZR/*"},{ua:"DROID RAZR"}],dpi:[368.1,256.7],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/XT830C/*"},{ua:"XT830C"}],dpi:[254,255.9],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/XT1021/*"},{ua:"XT1021"}],dpi:[254,256.7],bw:3,ac:500},{type:"android",rules:[{mdmh:"motorola/*/XT1023/*"},{ua:"XT1023"}],dpi:[254,256.7],bw:3,ac:500},{type:"android",rules:[{mdmh:"motorola/*/XT1028/*"},{ua:"XT1028"}],dpi:[326.6,327.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/XT1034/*"},{ua:"XT1034"}],dpi:[326.6,328.4],bw:3,ac:500},{type:"android",rules:[{mdmh:"motorola/*/XT1053/*"},{ua:"XT1053"}],dpi:[315.3,316.1],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/XT1562/*"},{ua:"XT1562"}],dpi:[403.4,402.7],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/Nexus 6/*"},{ua:"Nexus 6 B"}],dpi:[494.3,489.7],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/XT1063/*"},{ua:"XT1063"}],dpi:[295,296.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/XT1064/*"},{ua:"XT1064"}],dpi:[295,295.6],bw:3,ac:500},{type:"android",rules:[{mdmh:"motorola/*/XT1092/*"},{ua:"XT1092"}],dpi:[422,424.1],bw:3,ac:500},{type:"android",rules:[{mdmh:"motorola/*/XT1095/*"},{ua:"XT1095"}],dpi:[422,423.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"motorola/*/G4/*"},{ua:"Moto G (4)"}],dpi:401,bw:4,ac:1e3},{type:"android",rules:[{mdmh:"OnePlus/*/A0001/*"},{ua:"A0001"}],dpi:[403.4,401],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"OnePlus/*/ONE E1005/*"},{ua:"ONE E1005"}],dpi:[442.4,441.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"OnePlus/*/ONE A2005/*"},{ua:"ONE A2005"}],dpi:[391.9,405.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"OnePlus/*/ONEPLUS A5000/*"},{ua:"ONEPLUS A5000 "}],dpi:[403.411,399.737],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"OnePlus/*/ONE A5010/*"},{ua:"ONEPLUS A5010"}],dpi:[403,400],bw:2,ac:1e3},{type:"android",rules:[{mdmh:"OPPO/*/X909/*"},{ua:"X909"}],dpi:[442.4,444.1],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/GT-I9082/*"},{ua:"GT-I9082"}],dpi:[184.7,185.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G360P/*"},{ua:"SM-G360P"}],dpi:[196.7,205.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/Nexus S/*"},{ua:"Nexus S"}],dpi:[234.5,229.8],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/GT-I9300/*"},{ua:"GT-I9300"}],dpi:[304.8,303.9],bw:5,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-T230NU/*"},{ua:"SM-T230NU"}],dpi:216,bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SGH-T399/*"},{ua:"SGH-T399"}],dpi:[217.7,231.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SGH-M919/*"},{ua:"SGH-M919"}],dpi:[440.8,437.7],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-N9005/*"},{ua:"SM-N9005"}],dpi:[386.4,387],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SAMSUNG-SM-N900A/*"},{ua:"SAMSUNG-SM-N900A"}],dpi:[386.4,387.7],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/GT-I9500/*"},{ua:"GT-I9500"}],dpi:[442.5,443.3],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/GT-I9505/*"},{ua:"GT-I9505"}],dpi:439.4,bw:4,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G900F/*"},{ua:"SM-G900F"}],dpi:[415.6,431.6],bw:5,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G900M/*"},{ua:"SM-G900M"}],dpi:[415.6,431.6],bw:5,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G800F/*"},{ua:"SM-G800F"}],dpi:326.8,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G906S/*"},{ua:"SM-G906S"}],dpi:[562.7,572.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/GT-I9300/*"},{ua:"GT-I9300"}],dpi:[306.7,304.8],bw:5,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-T535/*"},{ua:"SM-T535"}],dpi:[142.6,136.4],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-N920C/*"},{ua:"SM-N920C"}],dpi:[515.1,518.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-N920P/*"},{ua:"SM-N920P"}],dpi:[386.3655,390.144],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-N920W8/*"},{ua:"SM-N920W8"}],dpi:[515.1,518.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/GT-I9300I/*"},{ua:"GT-I9300I"}],dpi:[304.8,305.8],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/GT-I9195/*"},{ua:"GT-I9195"}],dpi:[249.4,256.7],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SPH-L520/*"},{ua:"SPH-L520"}],dpi:[249.4,255.9],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SAMSUNG-SGH-I717/*"},{ua:"SAMSUNG-SGH-I717"}],dpi:285.8,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SPH-D710/*"},{ua:"SPH-D710"}],dpi:[217.7,204.2],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/GT-N7100/*"},{ua:"GT-N7100"}],dpi:265.1,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SCH-I605/*"},{ua:"SCH-I605"}],dpi:265.1,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/Galaxy Nexus/*"},{ua:"Galaxy Nexus"}],dpi:[315.3,314.2],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-N910H/*"},{ua:"SM-N910H"}],dpi:[515.1,518],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-N910C/*"},{ua:"SM-N910C"}],dpi:[515.2,520.2],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-G130M/*"},{ua:"SM-G130M"}],dpi:[165.9,164.8],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-G928I/*"},{ua:"SM-G928I"}],dpi:[515.1,518.4],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G920F/*"},{ua:"SM-G920F"}],dpi:580.6,bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-G920P/*"},{ua:"SM-G920P"}],dpi:[522.5,577],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G925F/*"},{ua:"SM-G925F"}],dpi:580.6,bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-G925V/*"},{ua:"SM-G925V"}],dpi:[522.5,576.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G930F/*"},{ua:"SM-G930F"}],dpi:576.6,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"samsung/*/SM-G935F/*"},{ua:"SM-G935F"}],dpi:533,bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-G950F/*"},{ua:"SM-G950F"}],dpi:[562.707,565.293],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-G955U/*"},{ua:"SM-G955U"}],dpi:[522.514,525.762],bw:3,ac:500},{type:"android",rules:[{mdmh:"samsung/*/SM-G955F/*"},{ua:"SM-G955F"}],dpi:[522.514,525.762],bw:3,ac:500},{type:"android",rules:[{mdmh:"Sony/*/C6903/*"},{ua:"C6903"}],dpi:[442.5,443.3],bw:3,ac:500},{type:"android",rules:[{mdmh:"Sony/*/D6653/*"},{ua:"D6653"}],dpi:[428.6,427.6],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Sony/*/E6653/*"},{ua:"E6653"}],dpi:[428.6,425.7],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Sony/*/E6853/*"},{ua:"E6853"}],dpi:[403.4,401.9],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Sony/*/SGP321/*"},{ua:"SGP321"}],dpi:[224.7,224.1],bw:3,ac:500},{type:"android",rules:[{mdmh:"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{ua:"ALCATEL ONE TOUCH Fierce"}],dpi:[240,247.5],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"THL/*/thl 5000/*"},{ua:"thl 5000"}],dpi:[480,443.3],bw:3,ac:1e3},{type:"android",rules:[{mdmh:"Fly/*/IQ4412/*"},{ua:"IQ4412"}],dpi:307.9,bw:3,ac:1e3},{type:"android",rules:[{mdmh:"ZTE/*/ZTE Blade L2/*"},{ua:"ZTE Blade L2"}],dpi:240,bw:3,ac:500},{type:"android",rules:[{mdmh:"BENEVE/*/VR518/*"},{ua:"VR518"}],dpi:480,bw:3,ac:500},{type:"ios",rules:[{res:[640,960]}],dpi:[325.1,328.4],bw:4,ac:1e3},{type:"ios",rules:[{res:[640,1136]}],dpi:[317.1,320.2],bw:3,ac:1e3},{type:"ios",rules:[{res:[750,1334]}],dpi:326.4,bw:4,ac:1e3},{type:"ios",rules:[{res:[1242,2208]}],dpi:[453.6,458.4],bw:4,ac:1e3},{type:"ios",rules:[{res:[1125,2001]}],dpi:[410.9,415.4],bw:4,ac:1e3},{type:"ios",rules:[{res:[1125,2436]}],dpi:458,bw:4,ac:1e3}]};function Z(e,t){if(this.dpdb=Y,this.recalculateDeviceParams_(),e){this.onDeviceParamsUpdated=t;var i=new XMLHttpRequest,r=this;i.open("GET",e,!0),i.addEventListener("load",function(){r.loading=!1,i.status>=200&&i.status<=299?(r.dpdb=JSON.parse(i.response),r.recalculateDeviceParams_()):console.error("Error loading online DPDB!")}),i.send()}}function q(e){this.xdpi=e.xdpi,this.ydpi=e.ydpi,this.bevelMm=e.bevelMm}function J(e,t){this.set(e,t)}function K(e,t){this.kFilter=e,this.isDebug=t,this.currentAccelMeasurement=new J,this.currentGyroMeasurement=new J,this.previousGyroMeasurement=new J,o()?this.filterQ=new V(-1,0,0,1):this.filterQ=new V(1,0,0,1),this.previousFilterQ=new V,this.previousFilterQ.copy(this.filterQ),this.accelQ=new V,this.isOrientationInitialized=!1,this.estimatedGravity=new N,this.measuredGravity=new N,this.gyroIntegralQ=new V}function $(e,t){this.predictionTimeS=e,this.isDebug=t,this.previousQ=new V,this.previousTimestampS=null,this.deltaQ=new V,this.outQ=new V}function ee(e,t,i,r){this.yawOnly=i,this.accelerometer=new N,this.gyroscope=new N,this.filter=new K(e,r),this.posePredictor=new $(t,r),this.isFirefoxAndroid=A(),this.isIOS=o();var n=h();this.isDeviceMotionInRadians=!this.isIOS&&n&&n<66,this.isWithoutDeviceMotion=c(),this.filterToWorldQ=new V,o()?this.filterToWorldQ.setFromAxisAngle(new N(1,0,0),Math.PI/2):this.filterToWorldQ.setFromAxisAngle(new N(1,0,0),-Math.PI/2),this.inverseWorldToScreenQ=new V,this.worldToScreenQ=new V,this.originalPoseAdjustQ=new V,this.originalPoseAdjustQ.setFromAxisAngle(new N(0,0,1),-window.orientation*Math.PI/180),this.setScreenTransform_(),u()&&this.filterToWorldQ.multiply(this.inverseWorldToScreenQ),this.resetQ=new V,this.orientationOut_=new Float32Array(4),this.start()}Z.prototype.getDeviceParams=function(){return this.deviceParams},Z.prototype.recalculateDeviceParams_=function(){var e=this.calcDeviceParams_();e?(this.deviceParams=e,this.onDeviceParamsUpdated&&this.onDeviceParamsUpdated(this.deviceParams)):console.error("Failed to recalculate device parameters.")},Z.prototype.calcDeviceParams_=function(){var e=this.dpdb;if(!e)return console.error("DPDB not available."),null;if(1!=e.format)return console.error("DPDB has unexpected format version."),null;if(!e.devices||!e.devices.length)return console.error("DPDB does not have a devices section."),null;var t=navigator.userAgent||navigator.vendor||window.opera,i=p(),r=f();if(!e.devices)return console.error("DPDB has no devices section."),null;for(var n=0;n<e.devices.length;n++){var s=e.devices[n];if(s.rules)if("ios"==s.type||"android"==s.type){if(o()==("ios"==s.type)){for(var a=!1,l=0;l<s.rules.length;l++){var A=s.rules[l];if(this.ruleMatches_(A,t,i,r)){a=!0;break}}if(a){var h=s.dpi[0]||s.dpi,c=s.dpi[1]||s.dpi;return new q({xdpi:h,ydpi:c,bevelMm:s.bw})}}}else console.warn("Device["+n+"] has invalid type.");else console.warn("Device["+n+"] has no rules section.")}return console.warn("No DPDB device match."),null},Z.prototype.ruleMatches_=function(e,t,i,r){if(!e.ua&&!e.res)return!1;if(e.ua&&"SM"===e.ua.substring(0,2)&&(e.ua=e.ua.substring(0,7)),e.ua&&t.indexOf(e.ua)<0)return!1;if(e.res){if(!e.res[0]||!e.res[1])return!1;var n=e.res[0],s=e.res[1];if(Math.min(i,r)!=Math.min(n,s)||Math.max(i,r)!=Math.max(n,s))return!1}return!0},J.prototype.set=function(e,t){this.sample=e,this.timestampS=t},J.prototype.copy=function(e){this.set(e.sample,e.timestampS)},K.prototype.addAccelMeasurement=function(e,t){this.currentAccelMeasurement.set(e,t)},K.prototype.addGyroMeasurement=function(e,t){this.currentGyroMeasurement.set(e,t);var i,r=t-this.previousGyroMeasurement.timestampS;i=r,!(isNaN(i)||i<=.001||i>1)&&this.run_(),this.previousGyroMeasurement.copy(this.currentGyroMeasurement)},K.prototype.run_=function(){if(!this.isOrientationInitialized)return this.accelQ=this.accelToQuaternion_(this.currentAccelMeasurement.sample),this.previousFilterQ.copy(this.accelQ),void(this.isOrientationInitialized=!0);var e=this.currentGyroMeasurement.timestampS-this.previousGyroMeasurement.timestampS,t=this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample,e);this.gyroIntegralQ.multiply(t),this.filterQ.copy(this.previousFilterQ),this.filterQ.multiply(t);var i=new V;i.copy(this.filterQ),i.inverse(),this.estimatedGravity.set(0,0,-1),this.estimatedGravity.applyQuaternion(i),this.estimatedGravity.normalize(),this.measuredGravity.copy(this.currentAccelMeasurement.sample),this.measuredGravity.normalize();var r,n=new V;n.setFromUnitVectors(this.estimatedGravity,this.measuredGravity),n.inverse(),this.isDebug&&console.log("Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)",Q*((r=n).w>1?(console.warn("getQuaternionAngle: w > 1"),0):2*Math.acos(r.w)),this.estimatedGravity.x.toFixed(1),this.estimatedGravity.y.toFixed(1),this.estimatedGravity.z.toFixed(1),this.measuredGravity.x.toFixed(1),this.measuredGravity.y.toFixed(1),this.measuredGravity.z.toFixed(1));var s=new V;s.copy(this.filterQ),s.multiply(n),this.filterQ.slerp(s,1-this.kFilter),this.previousFilterQ.copy(this.filterQ)},K.prototype.getOrientation=function(){return this.filterQ},K.prototype.accelToQuaternion_=function(e){var t=new N;t.copy(e),t.normalize();var i=new V;return i.setFromUnitVectors(new N(0,0,-1),t),i.inverse(),i},K.prototype.gyroToQuaternionDelta_=function(e,t){var i=new V,r=new N;return r.copy(e),r.normalize(),i.setFromAxisAngle(r,e.length()*t),i},$.prototype.getPrediction=function(e,t,i){if(!this.previousTimestampS)return this.previousQ.copy(e),this.previousTimestampS=i,e;var r=new N;r.copy(t),r.normalize();var n=t.length();if(n<20*O)return this.isDebug&&console.log("Moving slowly, at %s deg/s: no prediction",(Q*n).toFixed(1)),this.outQ.copy(e),this.previousQ.copy(e),this.outQ;var s=n*this.predictionTimeS;return this.deltaQ.setFromAxisAngle(r,s),this.outQ.copy(this.previousQ),this.outQ.multiply(this.deltaQ),this.previousQ.copy(e),this.previousTimestampS=i,this.outQ},ee.prototype.getPosition=function(){return null},ee.prototype.getOrientation=function(){var e=void 0;if(this.isWithoutDeviceMotion&&this._deviceOrientationQ){this.deviceOrientationFixQ=this.deviceOrientationFixQ||(r=(new V).setFromAxisAngle(new N(0,0,-1),0),n=new V,-90===window.orientation?n.setFromAxisAngle(new N(0,1,0),Math.PI/-2):n.setFromAxisAngle(new N(0,1,0),Math.PI/2),r.multiply(n)),this.deviceOrientationFilterToWorldQ=this.deviceOrientationFilterToWorldQ||((i=new V).setFromAxisAngle(new N(1,0,0),-Math.PI/2),i),e=this._deviceOrientationQ;var t=new V;return t.copy(e),t.multiply(this.deviceOrientationFilterToWorldQ),t.multiply(this.resetQ),t.multiply(this.worldToScreenQ),t.multiplyQuaternions(this.deviceOrientationFixQ,t),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_}var i,r,n,s=this.filter.getOrientation();e=this.posePredictor.getPrediction(s,this.gyroscope,this.previousTimestampS);var t=new V;return t.copy(this.filterToWorldQ),t.multiply(this.resetQ),t.multiply(e),t.multiply(this.worldToScreenQ),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_},ee.prototype.resetPose=function(){this.resetQ.copy(this.filter.getOrientation()),this.resetQ.x=0,this.resetQ.y=0,this.resetQ.z*=-1,this.resetQ.normalize(),u()&&this.resetQ.multiply(this.inverseWorldToScreenQ),this.resetQ.multiply(this.originalPoseAdjustQ)},ee.prototype.onDeviceOrientation_=function(e){this._deviceOrientationQ=this._deviceOrientationQ||new V;var t=e.alpha,i=e.beta,r=e.gamma;t=(t||0)*Math.PI/180,i=(i||0)*Math.PI/180,r=(r||0)*Math.PI/180,this._deviceOrientationQ.setFromEulerYXZ(i,t,-r)},ee.prototype.onDeviceMotion_=function(e){this.updateDeviceMotion_(e)},ee.prototype.updateDeviceMotion_=function(e){var t=e.accelerationIncludingGravity,i=e.rotationRate,r=e.timeStamp/1e3,n=r-this.previousTimestampS;return n<0?(_("fusion-pose-sensor:invalid:non-monotonic","Invalid timestamps detected: non-monotonic timestamp from devicemotion"),void(this.previousTimestampS=r)):n<=.001||n>1?(_("fusion-pose-sensor:invalid:outside-threshold","Invalid timestamps detected: Timestamp from devicemotion outside expected range."),void(this.previousTimestampS=r)):(this.accelerometer.set(-t.x,-t.y,-t.z),d()?this.gyroscope.set(-i.beta,i.alpha,i.gamma):this.gyroscope.set(i.alpha,i.beta,i.gamma),this.isDeviceMotionInRadians||this.gyroscope.multiplyScalar(Math.PI/180),this.filter.addAccelMeasurement(this.accelerometer,r),this.filter.addGyroMeasurement(this.gyroscope,r),void(this.previousTimestampS=r))},ee.prototype.onOrientationChange_=function(e){this.setScreenTransform_()},ee.prototype.onMessage_=function(e){var t=e.data;if(t&&t.type){var i=t.type.toLowerCase();"devicemotion"===i&&this.updateDeviceMotion_(t.deviceMotionEvent)}},ee.prototype.setScreenTransform_=function(){switch(this.worldToScreenQ.set(0,0,0,1),window.orientation){case 0:break;case 90:this.worldToScreenQ.setFromAxisAngle(new N(0,0,1),-Math.PI/2);break;case-90:this.worldToScreenQ.setFromAxisAngle(new N(0,0,1),Math.PI/2)}this.inverseWorldToScreenQ.copy(this.worldToScreenQ),this.inverseWorldToScreenQ.inverse()},ee.prototype.start=function(){var e,t,i;this.onDeviceMotionCallback_=this.onDeviceMotion_.bind(this),this.onOrientationChangeCallback_=this.onOrientationChange_.bind(this),this.onMessageCallback_=this.onMessage_.bind(this),this.onDeviceOrientationCallback_=this.onDeviceOrientation_.bind(this),o()&&(e=window.self!==window.top,t=M(document.referrer),i=M(window.location.href),e&&t!==i)&&window.addEventListener("message",this.onMessageCallback_),window.addEventListener("orientationchange",this.onOrientationChangeCallback_),this.isWithoutDeviceMotion?window.addEventListener("deviceorientation",this.onDeviceOrientationCallback_):window.addEventListener("devicemotion",this.onDeviceMotionCallback_)},ee.prototype.stop=function(){window.removeEventListener("devicemotion",this.onDeviceMotionCallback_),window.removeEventListener("deviceorientation",this.onDeviceOrientationCallback_),window.removeEventListener("orientationchange",this.onOrientationChangeCallback_),window.removeEventListener("message",this.onMessageCallback_)};var te=new N(1,0,0),ie=new N(0,0,1),re=new V;re.setFromAxisAngle(te,-Math.PI/2),re.multiply((new V).setFromAxisAngle(ie,Math.PI/2));var ne=function(){function e(t){r(this,e),this.config=t,this.sensor=null,this.fusionSensor=null,this._out=new Float32Array(4),this.api=null,this.errors=[],this._sensorQ=new V,this._outQ=new V,this._onSensorRead=this._onSensorRead.bind(this),this._onSensorError=this._onSensorError.bind(this),this.init()}return n(e,[{key:"init",value:function(){var e=null;try{(e=new RelativeOrientationSensor({frequency:60,referenceFrame:"screen"})).addEventListener("error",this._onSensorError)}catch(e){this.errors.push(e),"SecurityError"===e.name?(console.error("Cannot construct sensors due to the Feature Policy"),console.warn('Attempting to fall back using "devicemotion"; however this will fail in the future without correct permissions.'),this.useDeviceMotion()):"ReferenceError"===e.name?this.useDeviceMotion():console.error(e)}e&&(this.api="sensor",this.sensor=e,this.sensor.addEventListener("reading",this._onSensorRead),this.sensor.start())}},{key:"useDeviceMotion",value:function(){this.api="devicemotion",this.fusionSensor=new ee(this.config.K_FILTER,this.config.PREDICTION_TIME_S,this.config.YAW_ONLY,this.config.DEBUG),this.sensor&&(this.sensor.removeEventListener("reading",this._onSensorRead),this.sensor.removeEventListener("error",this._onSensorError),this.sensor=null)}},{key:"getOrientation",value:function(){if(this.fusionSensor)return this.fusionSensor.getOrientation();if(!this.sensor||!this.sensor.quaternion)return this._out[0]=this._out[1]=this._out[2]=0,this._out[3]=1,this._out;var e=this.sensor.quaternion;this._sensorQ.set(e[0],e[1],e[2],e[3]);var t=this._outQ;return t.copy(re),t.multiply(this._sensorQ),this.config.YAW_ONLY&&(t.x=t.z=0,t.normalize()),this._out[0]=t.x,this._out[1]=t.y,this._out[2]=t.z,this._out[3]=t.w,this._out}},{key:"_onSensorError",value:function(e){this.errors.push(e.error),"NotAllowedError"===e.error.name?console.error("Permission to access sensor was denied"):"NotReadableError"===e.error.name?console.error("Sensor could not be read"):console.error(e.error),this.useDeviceMotion()}},{key:"_onSensorRead",value:function(){}}]),e}();function se(){this.loadIcon_();var e=document.createElement("div"),t=e.style;t.position="fixed",t.top=0,t.right=0,t.bottom=0,t.left=0,t.backgroundColor="gray",t.fontFamily="sans-serif",t.zIndex=1e6;var i=document.createElement("img");i.src=this.icon;var t=i.style;t.marginLeft="25%",t.marginTop="25%",t.width="50%",e.appendChild(i);var r=document.createElement("div"),t=r.style;t.textAlign="center",t.fontSize="16px",t.lineHeight="24px",t.margin="24px 25%",t.width="50%",r.innerHTML="Place your phone into your Cardboard viewer.",e.appendChild(r);var n=document.createElement("div"),t=n.style;t.backgroundColor="#CFD8DC",t.position="fixed",t.bottom=0,t.width="100%",t.height="48px",t.padding="14px 24px",t.boxSizing="border-box",t.color="#656A6B",e.appendChild(n);var s=document.createElement("div");s.style.float="left",s.innerHTML="No Cardboard viewer?";var a=document.createElement("a");a.href="https://www.google.com/get/cardboard/get-cardboard/",a.innerHTML="get one",a.target="_blank";var t=a.style;t.float="right",t.fontWeight=600,t.textTransform="uppercase",t.borderLeft="1px solid gray",t.paddingLeft="24px",t.textDecoration="none",t.color="#656A6B",n.appendChild(s),n.appendChild(a),this.overlay=e,this.text=r,this.hide()}se.prototype.show=function(e){e||this.overlay.parentElement?e&&(this.overlay.parentElement&&this.overlay.parentElement!=e&&this.overlay.parentElement.removeChild(this.overlay),e.appendChild(this.overlay)):document.body.appendChild(this.overlay),this.overlay.style.display="block";var t=this.overlay.querySelector("img"),i=t.style;u()?(i.width="20%",i.marginLeft="40%",i.marginTop="3%"):(i.width="50%",i.marginLeft="25%",i.marginTop="25%")},se.prototype.hide=function(){this.overlay.style.display="none"},se.prototype.showTemporarily=function(e,t){this.show(t),this.timer=setTimeout(this.hide.bind(this),e)},se.prototype.disableShowTemporarily=function(){clearTimeout(this.timer)},se.prototype.update=function(){this.disableShowTemporarily(),!u()&&v()?this.show():this.hide()},se.prototype.loadIcon_=function(){this.icon="data:image/svg+xml,"+encodeURIComponent("<svg width='198' height='240' viewBox='0 0 198 240' xmlns='http://www.w3.org/2000/svg'><g fill='none' fill-rule='evenodd'><path d='M149.625 109.527l6.737 3.891v.886c0 .177.013.36.038.549.01.081.02.162.027.242.14 1.415.974 2.998 2.105 3.999l5.72 5.062.081-.09s4.382-2.53 5.235-3.024l25.97 14.993v54.001c0 .771-.386 1.217-.948 1.217-.233 0-.495-.076-.772-.236l-23.967-13.838-.014.024-27.322 15.775-.85-1.323c-4.731-1.529-9.748-2.74-14.951-3.61a.27.27 0 0 0-.007.024l-5.067 16.961-7.891 4.556-.037-.063v27.59c0 .772-.386 1.217-.948 1.217-.232 0-.495-.076-.772-.236l-42.473-24.522c-.95-.549-1.72-1.877-1.72-2.967v-1.035l-.021.047a5.111 5.111 0 0 0-1.816-.399 5.682 5.682 0 0 0-.546.001 13.724 13.724 0 0 1-1.918-.041c-1.655-.153-3.2-.6-4.404-1.296l-46.576-26.89.005.012-10.278-18.75c-1.001-1.827-.241-4.216 1.698-5.336l56.011-32.345a4.194 4.194 0 0 1 2.099-.572c1.326 0 2.572.659 3.227 1.853l.005-.003.227.413-.006.004a9.63 9.63 0 0 0 1.477 2.018l.277.27c1.914 1.85 4.468 2.801 7.113 2.801 1.949 0 3.948-.517 5.775-1.572.013 0 7.319-4.219 7.319-4.219a4.194 4.194 0 0 1 2.099-.572c1.326 0 2.572.658 3.226 1.853l3.25 5.928.022-.018 6.785 3.917-.105-.182 46.881-26.965m0-1.635c-.282 0-.563.073-.815.218l-46.169 26.556-5.41-3.124-3.005-5.481c-.913-1.667-2.699-2.702-4.66-2.703-1.011 0-2.02.274-2.917.792a3825 3825 0 0 1-7.275 4.195l-.044.024a9.937 9.937 0 0 1-4.957 1.353c-2.292 0-4.414-.832-5.976-2.342l-.252-.245a7.992 7.992 0 0 1-1.139-1.534 1.379 1.379 0 0 0-.06-.122l-.227-.414a1.718 1.718 0 0 0-.095-.154c-.938-1.574-2.673-2.545-4.571-2.545-1.011 0-2.02.274-2.917.792L3.125 155.502c-2.699 1.559-3.738 4.94-2.314 7.538l10.278 18.75c.177.323.448.563.761.704l46.426 26.804c1.403.81 3.157 1.332 5.072 1.508a15.661 15.661 0 0 0 2.146.046 4.766 4.766 0 0 1 .396 0c.096.004.19.011.283.022.109 1.593 1.159 3.323 2.529 4.114l42.472 24.522c.524.302 1.058.455 1.59.455 1.497 0 2.583-1.2 2.583-2.852v-26.562l7.111-4.105a1.64 1.64 0 0 0 .749-.948l4.658-15.593c4.414.797 8.692 1.848 12.742 3.128l.533.829a1.634 1.634 0 0 0 2.193.531l26.532-15.317L193 192.433c.523.302 1.058.455 1.59.455 1.497 0 2.583-1.199 2.583-2.852v-54.001c0-.584-.312-1.124-.818-1.416l-25.97-14.993a1.633 1.633 0 0 0-1.636.001c-.606.351-2.993 1.73-4.325 2.498l-4.809-4.255c-.819-.725-1.461-1.933-1.561-2.936a7.776 7.776 0 0 0-.033-.294 2.487 2.487 0 0 1-.023-.336v-.886c0-.584-.312-1.123-.817-1.416l-6.739-3.891a1.633 1.633 0 0 0-.817-.219' fill='#455A64'/><path d='M96.027 132.636l46.576 26.891c1.204.695 1.979 1.587 2.242 2.541l-.01.007-81.374 46.982h-.001c-1.654-.152-3.199-.6-4.403-1.295l-46.576-26.891 83.546-48.235' fill='#FAFAFA'/><path d='M63.461 209.174c-.008 0-.015 0-.022-.002-1.693-.156-3.228-.609-4.441-1.309l-46.576-26.89a.118.118 0 0 1 0-.203l83.546-48.235a.117.117 0 0 1 .117 0l46.576 26.891c1.227.708 2.021 1.612 2.296 2.611a.116.116 0 0 1-.042.124l-.021.016-81.375 46.981a.11.11 0 0 1-.058.016zm-50.747-28.303l46.401 26.79c1.178.68 2.671 1.121 4.32 1.276l81.272-46.922c-.279-.907-1.025-1.73-2.163-2.387l-46.517-26.857-83.313 48.1z' fill='#607D8B'/><path d='M148.327 165.471a5.85 5.85 0 0 1-.546.001c-1.894-.083-3.302-1.038-3.145-2.132a2.693 2.693 0 0 0-.072-1.105l-81.103 46.822c.628.058 1.272.073 1.918.042.182-.009.364-.009.546-.001 1.894.083 3.302 1.038 3.145 2.132l79.257-45.759' fill='#FFF'/><path d='M69.07 211.347a.118.118 0 0 1-.115-.134c.045-.317-.057-.637-.297-.925-.505-.61-1.555-1.022-2.738-1.074a5.966 5.966 0 0 0-.535.001 14.03 14.03 0 0 1-1.935-.041.117.117 0 0 1-.103-.092.116.116 0 0 1 .055-.126l81.104-46.822a.117.117 0 0 1 .171.07c.104.381.129.768.074 1.153-.045.316.057.637.296.925.506.61 1.555 1.021 2.739 1.073.178.008.357.008.535-.001a.117.117 0 0 1 .064.218l-79.256 45.759a.114.114 0 0 1-.059.016zm-3.405-2.372c.089 0 .177.002.265.006 1.266.056 2.353.488 2.908 1.158.227.274.35.575.36.882l78.685-45.429c-.036 0-.072-.001-.107-.003-1.267-.056-2.354-.489-2.909-1.158-.282-.34-.402-.724-.347-1.107a2.604 2.604 0 0 0-.032-.91L63.846 208.97a13.91 13.91 0 0 0 1.528.012c.097-.005.194-.007.291-.007z' fill='#607D8B'/><path d='M2.208 162.134c-1.001-1.827-.241-4.217 1.698-5.337l56.011-32.344c1.939-1.12 4.324-.546 5.326 1.281l.232.41a9.344 9.344 0 0 0 1.47 2.021l.278.27c3.325 3.214 8.583 3.716 12.888 1.23l7.319-4.22c1.94-1.119 4.324-.546 5.325 1.282l3.25 5.928-83.519 48.229-10.278-18.75z' fill='#FAFAFA'/><path d='M12.486 181.001a.112.112 0 0 1-.031-.005.114.114 0 0 1-.071-.056L2.106 162.19c-1.031-1.88-.249-4.345 1.742-5.494l56.01-32.344a4.328 4.328 0 0 1 2.158-.588c1.415 0 2.65.702 3.311 1.882.01.008.018.017.024.028l.227.414a.122.122 0 0 1 .013.038 9.508 9.508 0 0 0 1.439 1.959l.275.266c1.846 1.786 4.344 2.769 7.031 2.769 1.977 0 3.954-.538 5.717-1.557a.148.148 0 0 1 .035-.013l7.284-4.206a4.321 4.321 0 0 1 2.157-.588c1.427 0 2.672.716 3.329 1.914l3.249 5.929a.116.116 0 0 1-.044.157l-83.518 48.229a.116.116 0 0 1-.059.016zm49.53-57.004c-.704 0-1.41.193-2.041.557l-56.01 32.345c-1.882 1.086-2.624 3.409-1.655 5.179l10.221 18.645 83.317-48.112-3.195-5.829c-.615-1.122-1.783-1.792-3.124-1.792a4.08 4.08 0 0 0-2.04.557l-7.317 4.225a.148.148 0 0 1-.035.013 11.7 11.7 0 0 1-5.801 1.569c-2.748 0-5.303-1.007-7.194-2.835l-.278-.27a9.716 9.716 0 0 1-1.497-2.046.096.096 0 0 1-.013-.037l-.191-.347a.11.11 0 0 1-.023-.029c-.615-1.123-1.783-1.793-3.124-1.793z' fill='#607D8B'/><path d='M42.434 155.808c-2.51-.001-4.697-1.258-5.852-3.365-1.811-3.304-.438-7.634 3.059-9.654l12.291-7.098a7.599 7.599 0 0 1 3.789-1.033c2.51 0 4.697 1.258 5.852 3.365 1.811 3.304.439 7.634-3.059 9.654l-12.291 7.098a7.606 7.606 0 0 1-3.789 1.033zm13.287-20.683a7.128 7.128 0 0 0-3.555.971l-12.291 7.098c-3.279 1.893-4.573 5.942-2.883 9.024 1.071 1.955 3.106 3.122 5.442 3.122a7.13 7.13 0 0 0 3.556-.97l12.291-7.098c3.279-1.893 4.572-5.942 2.883-9.024-1.072-1.955-3.106-3.123-5.443-3.123z' fill='#607D8B'/><path d='M149.588 109.407l6.737 3.89v.887c0 .176.013.36.037.549.011.081.02.161.028.242.14 1.415.973 2.998 2.105 3.999l7.396 6.545c.177.156.358.295.541.415 1.579 1.04 2.95.466 3.062-1.282.049-.784.057-1.595.023-2.429l-.003-.16v-1.151l25.987 15.003v54c0 1.09-.77 1.53-1.72.982l-42.473-24.523c-.95-.548-1.72-1.877-1.72-2.966v-34.033' fill='#FAFAFA'/><path d='M194.553 191.25c-.257 0-.54-.085-.831-.253l-42.472-24.521c-.981-.567-1.779-1.943-1.779-3.068v-34.033h.234v34.033c0 1.051.745 2.336 1.661 2.866l42.473 24.521c.424.245.816.288 1.103.122.285-.164.442-.52.442-1.002v-53.933l-25.753-14.868.003 1.106c.034.832.026 1.654-.024 2.439-.054.844-.396 1.464-.963 1.746-.619.309-1.45.173-2.28-.373a5.023 5.023 0 0 1-.553-.426l-7.397-6.544c-1.158-1.026-1.999-2.625-2.143-4.076a9.624 9.624 0 0 0-.027-.238 4.241 4.241 0 0 1-.038-.564v-.82l-6.68-3.856.117-.202 6.738 3.89.058.034v.954c0 .171.012.351.036.533.011.083.021.165.029.246.138 1.395.948 2.935 2.065 3.923l7.397 6.545c.173.153.35.289.527.406.758.499 1.504.63 2.047.359.49-.243.786-.795.834-1.551.05-.778.057-1.591.024-2.417l-.004-.163v-1.355l.175.1 25.987 15.004.059.033v54.068c0 .569-.198.996-.559 1.204a1.002 1.002 0 0 1-.506.131' fill='#607D8B'/><path d='M145.685 163.161l24.115 13.922-25.978 14.998-1.462-.307c-6.534-2.17-13.628-3.728-21.019-4.616-4.365-.524-8.663 1.096-9.598 3.62a2.746 2.746 0 0 0-.011 1.928c1.538 4.267 4.236 8.363 7.995 12.135l.532.845-25.977 14.997-24.115-13.922 75.518-43.6' fill='#FFF'/><path d='M94.282 220.818l-.059-.033-24.29-14.024.175-.101 75.577-43.634.058.033 24.29 14.024-26.191 15.122-.045-.01-1.461-.307c-6.549-2.174-13.613-3.725-21.009-4.614a13.744 13.744 0 0 0-1.638-.097c-3.758 0-7.054 1.531-7.837 3.642a2.62 2.62 0 0 0-.01 1.848c1.535 4.258 4.216 8.326 7.968 12.091l.016.021.526.835.006.01.064.102-.105.061-25.977 14.998-.058.033zm-23.881-14.057l23.881 13.788 24.802-14.32c.546-.315.846-.489 1.017-.575l-.466-.74c-3.771-3.787-6.467-7.881-8.013-12.168a2.851 2.851 0 0 1 .011-2.008c.815-2.199 4.203-3.795 8.056-3.795.557 0 1.117.033 1.666.099 7.412.891 14.491 2.445 21.041 4.621.836.175 1.215.254 1.39.304l25.78-14.884-23.881-13.788-75.284 43.466z' fill='#607D8B'/><path d='M167.23 125.979v50.871l-27.321 15.773-6.461-14.167c-.91-1.996-3.428-1.738-5.624.574a10.238 10.238 0 0 0-2.33 4.018l-6.46 21.628-27.322 15.774v-50.871l75.518-43.6' fill='#FFF'/><path d='M91.712 220.567a.127.127 0 0 1-.059-.016.118.118 0 0 1-.058-.101v-50.871c0-.042.023-.08.058-.101l75.519-43.6a.117.117 0 0 1 .175.101v50.871c0 .041-.023.08-.059.1l-27.321 15.775a.118.118 0 0 1-.094.01.12.12 0 0 1-.071-.063l-6.46-14.168c-.375-.822-1.062-1.275-1.934-1.275-1.089 0-2.364.686-3.5 1.881a10.206 10.206 0 0 0-2.302 3.972l-6.46 21.627a.118.118 0 0 1-.054.068L91.77 220.551a.12.12 0 0 1-.058.016zm.117-50.92v50.601l27.106-15.65 6.447-21.583a10.286 10.286 0 0 1 2.357-4.065c1.18-1.242 2.517-1.954 3.669-1.954.969 0 1.731.501 2.146 1.411l6.407 14.051 27.152-15.676v-50.601l-75.284 43.466z' fill='#607D8B'/><path d='M168.543 126.213v50.87l-27.322 15.774-6.46-14.168c-.91-1.995-3.428-1.738-5.624.574a10.248 10.248 0 0 0-2.33 4.019l-6.461 21.627-27.321 15.774v-50.87l75.518-43.6' fill='#FFF'/><path d='M93.025 220.8a.123.123 0 0 1-.059-.015.12.12 0 0 1-.058-.101v-50.871c0-.042.023-.08.058-.101l75.518-43.6a.112.112 0 0 1 .117 0c.036.02.059.059.059.1v50.871a.116.116 0 0 1-.059.101l-27.321 15.774a.111.111 0 0 1-.094.01.115.115 0 0 1-.071-.062l-6.46-14.168c-.375-.823-1.062-1.275-1.935-1.275-1.088 0-2.363.685-3.499 1.881a10.19 10.19 0 0 0-2.302 3.971l-6.461 21.628a.108.108 0 0 1-.053.067l-27.322 15.775a.12.12 0 0 1-.058.015zm.117-50.919v50.6l27.106-15.649 6.447-21.584a10.293 10.293 0 0 1 2.357-4.065c1.179-1.241 2.516-1.954 3.668-1.954.969 0 1.732.502 2.147 1.412l6.407 14.051 27.152-15.676v-50.601l-75.284 43.466z' fill='#607D8B'/><path d='M169.8 177.083l-27.322 15.774-6.46-14.168c-.91-1.995-3.428-1.738-5.625.574a10.246 10.246 0 0 0-2.329 4.019l-6.461 21.627-27.321 15.774v-50.87l75.518-43.6v50.87z' fill='#FAFAFA'/><path d='M94.282 220.917a.234.234 0 0 1-.234-.233v-50.871c0-.083.045-.161.117-.202l75.518-43.601a.234.234 0 1 1 .35.202v50.871a.233.233 0 0 1-.116.202l-27.322 15.775a.232.232 0 0 1-.329-.106l-6.461-14.168c-.36-.789-.992-1.206-1.828-1.206-1.056 0-2.301.672-3.415 1.844a10.099 10.099 0 0 0-2.275 3.924l-6.46 21.628a.235.235 0 0 1-.107.136l-27.322 15.774a.23.23 0 0 1-.116.031zm.233-50.969v50.331l26.891-15.525 6.434-21.539a10.41 10.41 0 0 1 2.384-4.112c1.201-1.265 2.569-1.991 3.753-1.991 1.018 0 1.818.526 2.253 1.48l6.354 13.934 26.982-15.578v-50.331l-75.051 43.331z' fill='#607D8B'/><path d='M109.894 199.943c-1.774 0-3.241-.725-4.244-2.12a.224.224 0 0 1 .023-.294.233.233 0 0 1 .301-.023c.78.547 1.705.827 2.75.827 1.323 0 2.754-.439 4.256-1.306 5.311-3.067 9.631-10.518 9.631-16.611 0-1.927-.442-3.56-1.278-4.724a.232.232 0 0 1 .323-.327c1.671 1.172 2.591 3.381 2.591 6.219 0 6.242-4.426 13.863-9.865 17.003-1.574.908-3.084 1.356-4.488 1.356zm-2.969-1.542c.813.651 1.82.877 2.968.877h.001c1.321 0 2.753-.327 4.254-1.194 5.311-3.067 9.632-10.463 9.632-16.556 0-1.979-.463-3.599-1.326-4.761.411 1.035.625 2.275.625 3.635 0 6.243-4.426 13.883-9.865 17.023-1.574.909-3.084 1.317-4.49 1.317-.641 0-1.243-.149-1.799-.341z' fill='#607D8B'/><path d='M113.097 197.23c5.384-3.108 9.748-10.636 9.748-16.814 0-2.051-.483-3.692-1.323-4.86-1.784-1.252-4.374-1.194-7.257.47-5.384 3.108-9.748 10.636-9.748 16.814 0 2.051.483 3.692 1.323 4.86 1.784 1.252 4.374 1.194 7.257-.47' fill='#FAFAFA'/><path d='M108.724 198.614c-1.142 0-2.158-.213-3.019-.817-.021-.014-.04.014-.055-.007-.894-1.244-1.367-2.948-1.367-4.973 0-6.242 4.426-13.864 9.865-17.005 1.574-.908 3.084-1.363 4.49-1.363 1.142 0 2.158.309 3.018.913a.23.23 0 0 1 .056.056c.894 1.244 1.367 2.972 1.367 4.997 0 6.243-4.426 13.783-9.865 16.923-1.574.909-3.084 1.276-4.49 1.276zm-2.718-1.109c.774.532 1.688.776 2.718.776 1.323 0 2.754-.413 4.256-1.28 5.311-3.066 9.631-10.505 9.631-16.598 0-1.909-.434-3.523-1.255-4.685-.774-.533-1.688-.799-2.718-.799-1.323 0-2.755.441-4.256 1.308-5.311 3.066-9.631 10.506-9.631 16.599 0 1.909.434 3.517 1.255 4.679z' fill='#607D8B'/><path d='M149.318 114.262l-9.984 8.878 15.893 11.031 5.589-6.112-11.498-13.797' fill='#FAFAFA'/><path d='M169.676 120.84l-9.748 5.627c-3.642 2.103-9.528 2.113-13.147.024-3.62-2.089-3.601-5.488.041-7.591l9.495-5.608-6.729-3.885-81.836 47.071 45.923 26.514 3.081-1.779c.631-.365.869-.898.618-1.39-2.357-4.632-2.593-9.546-.683-14.262 5.638-13.92 24.509-24.815 48.618-28.07 8.169-1.103 16.68-.967 24.704.394.852.145 1.776.008 2.407-.357l3.081-1.778-25.825-14.91' fill='#FAFAFA'/><path d='M113.675 183.459a.47.47 0 0 1-.233-.062l-45.924-26.515a.468.468 0 0 1 .001-.809l81.836-47.071a.467.467 0 0 1 .466 0l6.729 3.885a.467.467 0 0 1-.467.809l-6.496-3.75-80.9 46.533 44.988 25.973 2.848-1.644c.192-.111.62-.409.435-.773-2.416-4.748-2.658-9.814-.7-14.65 2.806-6.927 8.885-13.242 17.582-18.263 8.657-4.998 19.518-8.489 31.407-10.094 8.198-1.107 16.79-.97 24.844.397.739.125 1.561.007 2.095-.301l2.381-1.374-25.125-14.506a.467.467 0 0 1 .467-.809l25.825 14.91a.467.467 0 0 1 0 .809l-3.081 1.779c-.721.417-1.763.575-2.718.413-7.963-1.351-16.457-1.486-24.563-.392-11.77 1.589-22.512 5.039-31.065 9.977-8.514 4.916-14.456 11.073-17.183 17.805-1.854 4.578-1.623 9.376.666 13.875.37.725.055 1.513-.8 2.006l-3.081 1.78a.476.476 0 0 1-.234.062' fill='#455A64'/><path d='M153.316 128.279c-2.413 0-4.821-.528-6.652-1.586-1.818-1.049-2.82-2.461-2.82-3.975 0-1.527 1.016-2.955 2.861-4.02l9.493-5.607a.233.233 0 1 1 .238.402l-9.496 5.609c-1.696.979-2.628 2.263-2.628 3.616 0 1.34.918 2.608 2.585 3.571 3.549 2.049 9.343 2.038 12.914-.024l9.748-5.628a.234.234 0 0 1 .234.405l-9.748 5.628c-1.858 1.072-4.296 1.609-6.729 1.609' fill='#607D8B'/><path d='M113.675 182.992l-45.913-26.508M113.675 183.342a.346.346 0 0 1-.175-.047l-45.913-26.508a.35.35 0 1 1 .35-.607l45.913 26.508a.35.35 0 0 1-.175.654' fill='#455A64'/><path d='M67.762 156.484v54.001c0 1.09.77 2.418 1.72 2.967l42.473 24.521c.95.549 1.72.11 1.72-.98v-54.001' fill='#FAFAFA'/><path d='M112.727 238.561c-.297 0-.62-.095-.947-.285l-42.473-24.521c-1.063-.613-1.895-2.05-1.895-3.27v-54.001a.35.35 0 1 1 .701 0v54.001c0 .96.707 2.18 1.544 2.663l42.473 24.522c.344.198.661.243.87.122.206-.119.325-.411.325-.799v-54.001a.35.35 0 1 1 .7 0v54.001c0 .655-.239 1.154-.675 1.406a1.235 1.235 0 0 1-.623.162' fill='#455A64'/><path d='M112.86 147.512h-.001c-2.318 0-4.499-.522-6.142-1.471-1.705-.984-2.643-2.315-2.643-3.749 0-1.445.952-2.791 2.68-3.788l12.041-6.953c1.668-.962 3.874-1.493 6.212-1.493 2.318 0 4.499.523 6.143 1.472 1.704.984 2.643 2.315 2.643 3.748 0 1.446-.952 2.791-2.68 3.789l-12.042 6.952c-1.668.963-3.874 1.493-6.211 1.493zm12.147-16.753c-2.217 0-4.298.497-5.861 1.399l-12.042 6.952c-1.502.868-2.33 1.998-2.33 3.182 0 1.173.815 2.289 2.293 3.142 1.538.889 3.596 1.378 5.792 1.378h.001c2.216 0 4.298-.497 5.861-1.399l12.041-6.953c1.502-.867 2.33-1.997 2.33-3.182 0-1.172-.814-2.288-2.292-3.142-1.539-.888-3.596-1.377-5.793-1.377z' fill='#607D8B'/><path d='M165.63 123.219l-5.734 3.311c-3.167 1.828-8.286 1.837-11.433.02-3.147-1.817-3.131-4.772.036-6.601l5.734-3.31 11.397 6.58' fill='#FAFAFA'/><path d='M154.233 117.448l9.995 5.771-4.682 2.704c-1.434.827-3.352 1.283-5.399 1.283-2.029 0-3.923-.449-5.333-1.263-1.29-.744-2-1.694-2-2.674 0-.991.723-1.955 2.036-2.713l5.383-3.108m0-.809l-5.734 3.31c-3.167 1.829-3.183 4.784-.036 6.601 1.568.905 3.623 1.357 5.684 1.357 2.077 0 4.159-.46 5.749-1.377l5.734-3.311-11.397-6.58M145.445 179.667c-1.773 0-3.241-.85-4.243-2.245-.067-.092-.057-.275.023-.356.08-.081.207-.12.3-.055.781.548 1.706.812 2.751.811 1.322 0 2.754-.446 4.256-1.313 5.31-3.066 9.631-10.522 9.631-16.615 0-1.927-.442-3.562-1.279-4.726a.235.235 0 0 1 .024-.301.232.232 0 0 1 .3-.027c1.67 1.172 2.59 3.38 2.59 6.219 0 6.242-4.425 13.987-9.865 17.127-1.573.908-3.083 1.481-4.488 1.481zM142.476 178c.814.651 1.82 1.002 2.969 1.002 1.322 0 2.753-.452 4.255-1.32 5.31-3.065 9.631-10.523 9.631-16.617 0-1.98-.463-3.63-1.325-4.793.411 1.035.624 2.26.624 3.62 0 6.242-4.425 13.875-9.865 17.015-1.573.909-3.084 1.376-4.489 1.376a5.49 5.49 0 0 1-1.8-.283z' fill='#607D8B'/><path d='M148.648 176.704c5.384-3.108 9.748-10.636 9.748-16.813 0-2.052-.483-3.693-1.322-4.861-1.785-1.252-4.375-1.194-7.258.471-5.383 3.108-9.748 10.636-9.748 16.813 0 2.051.484 3.692 1.323 4.86 1.785 1.253 4.374 1.195 7.257-.47' fill='#FAFAFA'/><path d='M144.276 178.276c-1.143 0-2.158-.307-3.019-.911a.217.217 0 0 1-.055-.054c-.895-1.244-1.367-2.972-1.367-4.997 0-6.241 4.425-13.875 9.865-17.016 1.573-.908 3.084-1.369 4.489-1.369 1.143 0 2.158.307 3.019.91a.24.24 0 0 1 .055.055c.894 1.244 1.367 2.971 1.367 4.997 0 6.241-4.425 13.875-9.865 17.016-1.573.908-3.084 1.369-4.489 1.369zm-2.718-1.172c.773.533 1.687.901 2.718.901 1.322 0 2.754-.538 4.256-1.405 5.31-3.066 9.631-10.567 9.631-16.661 0-1.908-.434-3.554-1.256-4.716-.774-.532-1.688-.814-2.718-.814-1.322 0-2.754.433-4.256 1.3-5.31 3.066-9.631 10.564-9.631 16.657 0 1.91.434 3.576 1.256 4.738z' fill='#607D8B'/><path d='M150.72 172.361l-.363-.295a24.105 24.105 0 0 0 2.148-3.128 24.05 24.05 0 0 0 1.977-4.375l.443.149a24.54 24.54 0 0 1-2.015 4.46 24.61 24.61 0 0 1-2.19 3.189M115.917 191.514l-.363-.294a24.174 24.174 0 0 0 2.148-3.128 24.038 24.038 0 0 0 1.976-4.375l.443.148a24.48 24.48 0 0 1-2.015 4.461 24.662 24.662 0 0 1-2.189 3.188M114 237.476V182.584 237.476' fill='#607D8B'/><g><path d='M81.822 37.474c.017-.135-.075-.28-.267-.392-.327-.188-.826-.21-1.109-.045l-6.012 3.471c-.131.076-.194.178-.191.285.002.132.002.461.002.578v.043l-.007.128-6.591 3.779c-.001 0-2.077 1.046-2.787 5.192 0 0-.912 6.961-.898 19.745.015 12.57.606 17.07 1.167 21.351.22 1.684 3.001 2.125 3.001 2.125.331.04.698-.027 1.08-.248l75.273-43.551c1.808-1.069 2.667-3.719 3.056-6.284 1.213-7.99 1.675-32.978-.275-39.878-.196-.693-.51-1.083-.868-1.282l-2.086-.79c-.727.028-1.416.467-1.534.535L82.032 37.072l-.21.402' fill='#FFF'/><path d='M144.311 1.701l2.085.79c.358.199.672.589.868 1.282 1.949 6.9 1.487 31.887.275 39.878-.39 2.565-1.249 5.215-3.056 6.284L69.21 93.486a1.78 1.78 0 0 1-.896.258l-.183-.011c0 .001-2.782-.44-3.003-2.124-.56-4.282-1.151-8.781-1.165-21.351-.015-12.784.897-19.745.897-19.745.71-4.146 2.787-5.192 2.787-5.192l6.591-3.779.007-.128v-.043c0-.117 0-.446-.002-.578-.003-.107.059-.21.191-.285l6.012-3.472a.98.98 0 0 1 .481-.11c.218 0 .449.053.627.156.193.112.285.258.268.392l.211-.402 60.744-34.836c.117-.068.806-.507 1.534-.535m0-.997l-.039.001c-.618.023-1.283.244-1.974.656l-.021.012-60.519 34.706a2.358 2.358 0 0 0-.831-.15c-.365 0-.704.084-.98.244l-6.012 3.471c-.442.255-.699.69-.689 1.166l.001.15-6.08 3.487c-.373.199-2.542 1.531-3.29 5.898l-.006.039c-.009.07-.92 7.173-.906 19.875.014 12.62.603 17.116 1.172 21.465l.002.015c.308 2.355 3.475 2.923 3.836 2.98l.034.004c.101.013.204.019.305.019a2.77 2.77 0 0 0 1.396-.392l75.273-43.552c1.811-1.071 2.999-3.423 3.542-6.997 1.186-7.814 1.734-33.096-.301-40.299-.253-.893-.704-1.527-1.343-1.882l-.132-.062-2.085-.789a.973.973 0 0 0-.353-.065' fill='#455A64'/><path d='M128.267 11.565l1.495.434-56.339 32.326' fill='#FFF'/><path d='M74.202 90.545a.5.5 0 0 1-.25-.931l18.437-10.645a.499.499 0 1 1 .499.864L74.451 90.478l-.249.067M75.764 42.654l-.108-.062.046-.171 5.135-2.964.17.045-.045.171-5.135 2.964-.063.017M70.52 90.375V46.421l.063-.036L137.84 7.554v43.954l-.062.036L70.52 90.375zm.25-43.811v43.38l66.821-38.579V7.985L70.77 46.564z' fill='#607D8B'/><path d='M86.986 83.182c-.23.149-.612.384-.849.523l-11.505 6.701c-.237.139-.206.252.068.252h.565c.275 0 .693-.113.93-.252L87.7 83.705c.237-.139.428-.253.425-.256a11.29 11.29 0 0 1-.006-.503c0-.274-.188-.377-.418-.227l-.715.463' fill='#607D8B'/><path d='M75.266 90.782H74.7c-.2 0-.316-.056-.346-.166-.03-.11.043-.217.215-.317l11.505-6.702c.236-.138.615-.371.844-.519l.715-.464a.488.488 0 0 1 .266-.089c.172 0 .345.13.345.421 0 .214.001.363.003.437l.006.004-.004.069c-.003.075-.003.075-.486.356l-11.505 6.702a2.282 2.282 0 0 1-.992.268zm-.6-.25l.034.001h.566c.252 0 .649-.108.866-.234l11.505-6.702c.168-.098.294-.173.361-.214-.004-.084-.004-.218-.004-.437l-.095-.171-.131.049-.714.463c-.232.15-.616.386-.854.525l-11.505 6.702-.029.018z' fill='#607D8B'/><path d='M75.266 89.871H74.7c-.2 0-.316-.056-.346-.166-.03-.11.043-.217.215-.317l11.505-6.702c.258-.151.694-.268.993-.268h.565c.2 0 .316.056.346.166.03.11-.043.217-.215.317l-11.505 6.702a2.282 2.282 0 0 1-.992.268zm-.6-.25l.034.001h.566c.252 0 .649-.107.866-.234l11.505-6.702.03-.018-.035-.001h-.565c-.252 0-.649.108-.867.234l-11.505 6.702-.029.018zM74.37 90.801v-1.247 1.247' fill='#607D8B'/><path d='M68.13 93.901c-.751-.093-1.314-.737-1.439-1.376-.831-4.238-1.151-8.782-1.165-21.352-.015-12.784.897-19.745.897-19.745.711-4.146 2.787-5.192 2.787-5.192l74.859-43.219c.223-.129 2.487-1.584 3.195.923 1.95 6.9 1.488 31.887.275 39.878-.389 2.565-1.248 5.215-3.056 6.283L69.21 93.653c-.382.221-.749.288-1.08.248 0 0-2.781-.441-3.001-2.125-.561-4.281-1.152-8.781-1.167-21.351-.014-12.784.898-19.745.898-19.745.71-4.146 2.787-5.191 2.787-5.191l6.598-3.81.871-.119 6.599-3.83.046-.461L68.13 93.901' fill='#FAFAFA'/><path d='M68.317 94.161l-.215-.013h-.001l-.244-.047c-.719-.156-2.772-.736-2.976-2.292-.568-4.34-1.154-8.813-1.168-21.384-.014-12.654.891-19.707.9-19.777.725-4.231 2.832-5.338 2.922-5.382l6.628-3.827.87-.119 6.446-3.742.034-.334a.248.248 0 0 1 .273-.223.248.248 0 0 1 .223.272l-.059.589-6.752 3.919-.87.118-6.556 3.785c-.031.016-1.99 1.068-2.666 5.018-.007.06-.908 7.086-.894 19.702.014 12.539.597 16.996 1.161 21.305.091.691.689 1.154 1.309 1.452a1.95 1.95 0 0 1-.236-.609c-.781-3.984-1.155-8.202-1.17-21.399-.014-12.653.891-19.707.9-19.777.725-4.231 2.832-5.337 2.922-5.382-.004.001 74.444-42.98 74.846-43.212l.028-.017c.904-.538 1.72-.688 2.36-.433.555.221.949.733 1.172 1.52 2.014 7.128 1.46 32.219.281 39.983-.507 3.341-1.575 5.515-3.175 6.462L69.335 93.869a2.023 2.023 0 0 1-1.018.292zm-.147-.507c.293.036.604-.037.915-.217l75.273-43.551c1.823-1.078 2.602-3.915 2.934-6.106 1.174-7.731 1.731-32.695-.268-39.772-.178-.631-.473-1.032-.876-1.192-.484-.193-1.166-.052-1.921.397l-.034.021-74.858 43.218c-.031.017-1.989 1.069-2.666 5.019-.007.059-.908 7.085-.894 19.702.015 13.155.386 17.351 1.161 21.303.09.461.476.983 1.037 1.139.114.025.185.037.196.039h.001z' fill='#455A64'/><path d='M69.317 68.982c.489-.281.885-.056.885.505 0 .56-.396 1.243-.885 1.525-.488.282-.884.057-.884-.504 0-.56.396-1.243.884-1.526' fill='#FFF'/><path d='M68.92 71.133c-.289 0-.487-.228-.487-.625 0-.56.396-1.243.884-1.526a.812.812 0 0 1 .397-.121c.289 0 .488.229.488.626 0 .56-.396 1.243-.885 1.525a.812.812 0 0 1-.397.121m.794-2.459a.976.976 0 0 0-.49.147c-.548.317-.978 1.058-.978 1.687 0 .486.271.812.674.812a.985.985 0 0 0 .491-.146c.548-.317.978-1.057.978-1.687 0-.486-.272-.813-.675-.813' fill='#8097A2'/><path d='M68.92 70.947c-.271 0-.299-.307-.299-.439 0-.491.361-1.116.79-1.363a.632.632 0 0 1 .303-.096c.272 0 .301.306.301.438 0 .491-.363 1.116-.791 1.364a.629.629 0 0 1-.304.096m.794-2.086a.812.812 0 0 0-.397.121c-.488.283-.884.966-.884 1.526 0 .397.198.625.487.625a.812.812 0 0 0 .397-.121c.489-.282.885-.965.885-1.525 0-.397-.199-.626-.488-.626' fill='#8097A2'/><path d='M69.444 85.35c.264-.152.477-.031.477.272 0 .303-.213.67-.477.822-.263.153-.477.031-.477-.271 0-.302.214-.671.477-.823' fill='#FFF'/><path d='M69.23 86.51c-.156 0-.263-.123-.263-.337 0-.302.214-.671.477-.823a.431.431 0 0 1 .214-.066c.156 0 .263.124.263.338 0 .303-.213.67-.477.822a.431.431 0 0 1-.214.066m.428-1.412c-.1 0-.203.029-.307.09-.32.185-.57.618-.57.985 0 .309.185.524.449.524a.63.63 0 0 0 .308-.09c.32-.185.57-.618.57-.985 0-.309-.185-.524-.45-.524' fill='#8097A2'/><path d='M69.23 86.322l-.076-.149c0-.235.179-.544.384-.661l.12-.041.076.151c0 .234-.179.542-.383.66l-.121.04m.428-1.038a.431.431 0 0 0-.214.066c-.263.152-.477.521-.477.823 0 .214.107.337.263.337a.431.431 0 0 0 .214-.066c.264-.152.477-.519.477-.822 0-.214-.107-.338-.263-.338' fill='#8097A2'/><path d='M139.278 7.769v43.667L72.208 90.16V46.493l67.07-38.724' fill='#455A64'/><path d='M72.083 90.375V46.421l.063-.036 67.257-38.831v43.954l-.062.036-67.258 38.831zm.25-43.811v43.38l66.821-38.579V7.985L72.333 46.564z' fill='#607D8B'/></g><path d='M125.737 88.647l-7.639 3.334V84l-11.459 4.713v8.269L99 100.315l13.369 3.646 13.368-15.314' fill='#455A64'/></g></svg>")};var ae="CardboardV1",oe="WEBVR_CARDBOARD_VIEWER";function le(e){try{this.selectedKey=localStorage.getItem(oe)}catch(e){console.error("Failed to load viewer profile: %s",e)}this.selectedKey||(this.selectedKey=e||ae),this.dialog=this.createDialog_(W.Viewers),this.root=null,this.onChangeCallbacks_=[]}le.prototype.show=function(e){this.root=e,e.appendChild(this.dialog);var t=this.dialog.querySelector("#"+this.selectedKey);t.checked=!0,this.dialog.style.display="block"},le.prototype.hide=function(){this.root&&this.root.contains(this.dialog)&&this.root.removeChild(this.dialog),this.dialog.style.display="none"},le.prototype.getCurrentViewer=function(){return W.Viewers[this.selectedKey]},le.prototype.getSelectedKey_=function(){var e=this.dialog.querySelector("input[name=field]:checked");return e?e.id:null},le.prototype.onChange=function(e){this.onChangeCallbacks_.push(e)},le.prototype.fireOnChange_=function(e){for(var t=0;t<this.onChangeCallbacks_.length;t++)this.onChangeCallbacks_[t](e)},le.prototype.onSave_=function(){if(this.selectedKey=this.getSelectedKey_(),this.selectedKey&&W.Viewers[this.selectedKey]){this.fireOnChange_(W.Viewers[this.selectedKey]);try{localStorage.setItem(oe,this.selectedKey)}catch(e){console.error("Failed to save viewer profile: %s",e)}this.hide()}else console.error("ViewerSelector.onSave_: this should never happen!")},le.prototype.createDialog_=function(e){var t=document.createElement("div");t.classList.add("webvr-polyfill-viewer-selector"),t.style.display="none";var i=document.createElement("div"),r=i.style;r.position="fixed",r.left=0,r.top=0,r.width="100%",r.height="100%",r.background="rgba(0, 0, 0, 0.3)",i.addEventListener("click",this.hide.bind(this));var n=document.createElement("div"),r=n.style;for(var s in r.boxSizing="border-box",r.position="fixed",r.top="24px",r.left="50%",r.marginLeft="-140px",r.width="280px",r.padding="24px",r.overflow="hidden",r.background="#fafafa",r.fontFamily="'Roboto', sans-serif",r.boxShadow="0px 5px 20px #666",n.appendChild(this.createH1_("Select your viewer")),e)n.appendChild(this.createChoice_(s,e[s].label));return n.appendChild(this.createButton_("Save",this.onSave_.bind(this))),t.appendChild(i),t.appendChild(n),t},le.prototype.createH1_=function(e){var t=document.createElement("h1"),i=t.style;return i.color="black",i.fontSize="20px",i.fontWeight="bold",i.marginTop=0,i.marginBottom="24px",t.innerHTML=e,t},le.prototype.createChoice_=function(e,t){var i=document.createElement("div");i.style.marginTop="8px",i.style.color="black";var r=document.createElement("input");r.style.fontSize="30px",r.setAttribute("id",e),r.setAttribute("type","radio"),r.setAttribute("value",e),r.setAttribute("name","field");var n=document.createElement("label");return n.style.marginLeft="4px",n.setAttribute("for",e),n.innerHTML=t,i.appendChild(r),i.appendChild(n),i},le.prototype.createButton_=function(e,t){var i=document.createElement("button");i.innerHTML=e;var r=i.style;return r.float="right",r.textTransform="uppercase",r.color="#1094f7",r.fontSize="14px",r.letterSpacing=0,r.border=0,r.background="none",r.marginTop="16px",i.addEventListener("click",t),i},"undefined"!=typeof window?window:void 0!==Ve||"undefined"!=typeof self&&self;var Ae,he,ce=(function(e,t){var i;i=function(){return function(e){var t={};function i(r){if(t[r])return t[r].exports;var n=t[r]={i:r,l:!1,exports:{}};return e[r].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){var r=function(){function e(e,t){for(var i=0;i<t.length;i++){var r=t[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,i,r){return i&&e(t.prototype,i),r&&e(t,r),t}}(),n=i(1),s="undefined"!=typeof navigator&&parseFloat((""+(/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))<10&&!window.MSStream,a=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),s?this.noSleepTimer=null:(this.noSleepVideo=document.createElement("video"),this.noSleepVideo.setAttribute("playsinline",""),this.noSleepVideo.setAttribute("src",n),this.noSleepVideo.addEventListener("timeupdate",function(e){this.noSleepVideo.currentTime>.5&&(this.noSleepVideo.currentTime=Math.random())}.bind(this)))}return r(e,[{key:"enable",value:function(){s?(this.disable(),this.noSleepTimer=window.setInterval(function(){window.location.href="/",window.setTimeout(window.stop,0)},15e3)):this.noSleepVideo.play()}},{key:"disable",value:function(){s?this.noSleepTimer&&(window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause()}}]),e}();e.exports=a},function(e,t,i){e.exports="data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA="}])},e.exports=i()}(he={exports:{}},he.exports),(Ae=he.exports)&&Ae.__esModule&&Object.prototype.hasOwnProperty.call(Ae,"default")?Ae.default:Ae),de=1e3,ue=[0,0,.5,1],pe=[.5,0,.5,1],fe=window.requestAnimationFrame,me=window.cancelAnimationFrame;function ge(e){Object.defineProperties(this,{hasPosition:{writable:!1,enumerable:!0,value:e.hasPosition},hasExternalDisplay:{writable:!1,enumerable:!0,value:e.hasExternalDisplay},canPresent:{writable:!1,enumerable:!0,value:e.canPresent},maxLayers:{writable:!1,enumerable:!0,value:e.maxLayers},hasOrientation:{enumerable:!0,get:function(){return x("VRDisplayCapabilities.prototype.hasOrientation","VRDisplay.prototype.getFrameData"),e.hasOrientation}}})}function we(e){var t=!("wakelock"in(e=e||{}))||e.wakelock;this.isPolyfilled=!0,this.displayId=de++,this.displayName="",this.depthNear=.01,this.depthFar=1e4,this.isPresenting=!1,Object.defineProperty(this,"isConnected",{get:function(){return x("VRDisplay.prototype.isConnected","VRDisplayCapabilities.prototype.hasExternalDisplay"),!1}}),this.capabilities=new ge({hasPosition:!1,hasOrientation:!1,hasExternalDisplay:!1,canPresent:!1,maxLayers:1}),this.stageParameters=null,this.waitingForPresent_=!1,this.layer_=null,this.originalParent_=null,this.fullscreenElement_=null,this.fullscreenWrapper_=null,this.fullscreenElementCachedStyle_=null,this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null,t&&v()&&(this.wakelock_=new ce)}we.prototype.getFrameData=function(e){return E(e,this._getPose(),this)},we.prototype.getPose=function(){return x("VRDisplay.prototype.getPose","VRDisplay.prototype.getFrameData"),this._getPose()},we.prototype.resetPose=function(){return x("VRDisplay.prototype.resetPose"),this._resetPose()},we.prototype.getImmediatePose=function(){return x("VRDisplay.prototype.getImmediatePose","VRDisplay.prototype.getFrameData"),this._getPose()},we.prototype.requestAnimationFrame=function(e){return fe(e)},we.prototype.cancelAnimationFrame=function(e){return me(e)},we.prototype.wrapForFullscreen=function(e){if(o())return e;if(!this.fullscreenWrapper_){this.fullscreenWrapper_=document.createElement("div");var t=["height: "+Math.min(screen.height,screen.width)+"px !important","top: 0 !important","left: 0 !important","right: 0 !important","border: 0","margin: 0","padding: 0","z-index: 999999 !important","position: fixed"];this.fullscreenWrapper_.setAttribute("style",t.join("; ")+";"),this.fullscreenWrapper_.classList.add("webvr-polyfill-fullscreen-wrapper")}if(this.fullscreenElement_==e)return this.fullscreenWrapper_;if(this.fullscreenElement_&&(this.originalParent_?this.originalParent_.appendChild(this.fullscreenElement_):this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_)),this.fullscreenElement_=e,this.originalParent_=e.parentElement,this.originalParent_||document.body.appendChild(e),!this.fullscreenWrapper_.parentElement){var i=this.fullscreenElement_.parentElement;i.insertBefore(this.fullscreenWrapper_,this.fullscreenElement_),i.removeChild(this.fullscreenElement_)}this.fullscreenWrapper_.insertBefore(this.fullscreenElement_,this.fullscreenWrapper_.firstChild),this.fullscreenElementCachedStyle_=this.fullscreenElement_.getAttribute("style");var r=this;return function(){if(r.fullscreenElement_){var e=["position: absolute","top: 0","left: 0","width: "+Math.max(screen.width,screen.height)+"px","height: "+Math.min(screen.height,screen.width)+"px","border: 0","margin: 0","padding: 0"];r.fullscreenElement_.setAttribute("style",e.join("; ")+";")}}(),this.fullscreenWrapper_},we.prototype.removeFullscreenWrapper=function(){if(this.fullscreenElement_){var e=this.fullscreenElement_;this.fullscreenElementCachedStyle_?e.setAttribute("style",this.fullscreenElementCachedStyle_):e.removeAttribute("style"),this.fullscreenElement_=null,this.fullscreenElementCachedStyle_=null;var t=this.fullscreenWrapper_.parentElement;return this.fullscreenWrapper_.removeChild(e),this.originalParent_===t?t.insertBefore(e,this.fullscreenWrapper_):this.originalParent_&&this.originalParent_.appendChild(e),t.removeChild(this.fullscreenWrapper_),e}},we.prototype.requestPresent=function(e){var t=this.isPresenting,i=this;return e instanceof Array||(x("VRDisplay.prototype.requestPresent with non-array argument","an array of VRLayers as the first argument"),e=[e]),new Promise(function(r,n){if(i.capabilities.canPresent)if(0==e.length||e.length>i.capabilities.maxLayers)n(new Error("Invalid number of layers."));else{var s=e[0];if(s.source){var a=s.leftBounds||ue,A=s.rightBounds||pe;if(t){var h=i.layer_;h.source!==s.source&&(h.source=s.source);for(var c=0;c<4;c++)h.leftBounds[c]=a[c],h.rightBounds[c]=A[c];return i.wrapForFullscreen(i.layer_.source),i.updatePresent_(),void r()}if(i.layer_={predistorted:s.predistorted,source:s.source,leftBounds:a.slice(0),rightBounds:A.slice(0)},i.waitingForPresent_=!1,i.layer_&&i.layer_.source){var d=i.wrapForFullscreen(i.layer_.source);i.addFullscreenListeners_(d,function(){var e=document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement;i.isPresenting=d===e,i.isPresenting?(screen.orientation&&screen.orientation.lock&&screen.orientation.lock("landscape-primary").catch(function(e){console.error("screen.orientation.lock() failed due to",e.message)}),i.waitingForPresent_=!1,i.beginPresent_(),r()):(screen.orientation&&screen.orientation.unlock&&screen.orientation.unlock(),i.removeFullscreenWrapper(),i.disableWakeLock(),i.endPresent_(),i.removeFullscreenListeners_()),i.fireVRDisplayPresentChange_()},function(){i.waitingForPresent_&&(i.removeFullscreenWrapper(),i.removeFullscreenListeners_(),i.disableWakeLock(),i.waitingForPresent_=!1,i.isPresenting=!1,n(new Error("Unable to present.")))}),function(e){if(l())return!1;if(e.requestFullscreen)e.requestFullscreen();else if(e.webkitRequestFullscreen)e.webkitRequestFullscreen();else if(e.mozRequestFullScreen)e.mozRequestFullScreen();else{if(!e.msRequestFullscreen)return!1;e.msRequestFullscreen()}return!0}(d)?(i.enableWakeLock(),i.waitingForPresent_=!0):(o()||l())&&(i.enableWakeLock(),i.isPresenting=!0,i.beginPresent_(),i.fireVRDisplayPresentChange_(),r())}i.waitingForPresent_||o()||(m(),n(new Error("Unable to present.")))}else r()}else n(new Error("VRDisplay is not capable of presenting."))})},we.prototype.exitPresent=function(){var e=this.isPresenting,t=this;return this.isPresenting=!1,this.layer_=null,this.disableWakeLock(),new Promise(function(i,r){e?(!m()&&o()&&(t.endPresent_(),t.fireVRDisplayPresentChange_()),l()&&(t.removeFullscreenWrapper(),t.removeFullscreenListeners_(),t.endPresent_(),t.fireVRDisplayPresentChange_()),i()):r(new Error("Was not presenting to VRDisplay."))})},we.prototype.getLayers=function(){return this.layer_?[this.layer_]:[]},we.prototype.fireVRDisplayPresentChange_=function(){var e=new CustomEvent("vrdisplaypresentchange",{detail:{display:this}});window.dispatchEvent(e)},we.prototype.fireVRDisplayConnect_=function(){var e=new CustomEvent("vrdisplayconnect",{detail:{display:this}});window.dispatchEvent(e)},we.prototype.addFullscreenListeners_=function(e,t,i){this.removeFullscreenListeners_(),this.fullscreenEventTarget_=e,this.fullscreenChangeHandler_=t,this.fullscreenErrorHandler_=i,t&&(document.fullscreenEnabled?e.addEventListener("fullscreenchange",t,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenchange",t,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenchange",t,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenchange",t,!1)),i&&(document.fullscreenEnabled?e.addEventListener("fullscreenerror",i,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenerror",i,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenerror",i,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenerror",i,!1))},we.prototype.removeFullscreenListeners_=function(){if(this.fullscreenEventTarget_){var e=this.fullscreenEventTarget_;if(this.fullscreenChangeHandler_){var t=this.fullscreenChangeHandler_;e.removeEventListener("fullscreenchange",t,!1),e.removeEventListener("webkitfullscreenchange",t,!1),document.removeEventListener("mozfullscreenchange",t,!1),e.removeEventListener("msfullscreenchange",t,!1)}if(this.fullscreenErrorHandler_){var i=this.fullscreenErrorHandler_;e.removeEventListener("fullscreenerror",i,!1),e.removeEventListener("webkitfullscreenerror",i,!1),document.removeEventListener("mozfullscreenerror",i,!1),e.removeEventListener("msfullscreenerror",i,!1)}this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null}},we.prototype.enableWakeLock=function(){this.wakelock_&&this.wakelock_.enable()},we.prototype.disableWakeLock=function(){this.wakelock_&&this.wakelock_.disable()},we.prototype.beginPresent_=function(){},we.prototype.endPresent_=function(){},we.prototype.submitFrame=function(e){},we.prototype.getEyeParameters=function(e){return null};var ve={ADDITIONAL_VIEWERS:[],DEFAULT_VIEWER:"",MOBILE_WAKE_LOCK:!0,DEBUG:!1,DPDB_URL:"https://dpdb.webvr.rocks/dpdb.json",K_FILTER:.98,PREDICTION_TIME_S:.04,CARDBOARD_UI_DISABLED:!1,ROTATE_INSTRUCTIONS_DISABLED:!1,YAW_ONLY:!1,BUFFER_SCALE:.5,DIRTY_SUBMIT_FRAME_BINDINGS:!1},ye={LEFT:"left",RIGHT:"right"};function be(e){var t=y({},ve);e=y(t,e||{}),we.call(this,{wakelock:e.MOBILE_WAKE_LOCK}),this.config=e,this.displayName="Cardboard VRDisplay",this.capabilities=new ge({hasPosition:!1,hasOrientation:!0,hasExternalDisplay:!1,canPresent:!0,maxLayers:1}),this.stageParameters=null,this.bufferScale_=this.config.BUFFER_SCALE,this.poseSensor_=new ne(this.config),this.distorter_=null,this.cardboardUI_=null,this.dpdb_=new Z(this.config.DPDB_URL,this.onDeviceParamsUpdated_.bind(this)),this.deviceInfo_=new W(this.dpdb_.getDeviceParams(),e.ADDITIONAL_VIEWERS),this.viewerSelector_=new le(e.DEFAULT_VIEWER),this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)),this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()),this.config.ROTATE_INSTRUCTIONS_DISABLED||(this.rotateInstructions_=new se),o()&&window.addEventListener("resize",this.onResize_.bind(this))}return be.prototype=Object.create(we.prototype),be.prototype._getPose=function(){return{position:null,orientation:this.poseSensor_.getOrientation(),linearVelocity:null,linearAcceleration:null,angularVelocity:null,angularAcceleration:null}},be.prototype._resetPose=function(){this.poseSensor_.resetPose&&this.poseSensor_.resetPose()},be.prototype._getFieldOfView=function(e){var t;if(e==ye.LEFT)t=this.deviceInfo_.getFieldOfViewLeftEye();else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=this.deviceInfo_.getFieldOfViewRightEye()}return t},be.prototype._getEyeOffset=function(e){var t;if(e==ye.LEFT)t=[.5*-this.deviceInfo_.viewer.interLensDistance,0,0];else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=[.5*this.deviceInfo_.viewer.interLensDistance,0,0]}return t},be.prototype.getEyeParameters=function(e){var t=this._getEyeOffset(e),i=this._getFieldOfView(e),r={offset:t,renderWidth:.5*this.deviceInfo_.device.width*this.bufferScale_,renderHeight:this.deviceInfo_.device.height*this.bufferScale_};return Object.defineProperty(r,"fieldOfView",{enumerable:!0,get:function(){return x("VRFieldOfView","VRFrameData's projection matrices"),i}}),r},be.prototype.onDeviceParamsUpdated_=function(e){this.config.DEBUG&&console.log("DPDB reported that device params were updated."),this.deviceInfo_.updateDeviceParams(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_)},be.prototype.updateBounds_=function(){this.layer_&&this.distorter_&&(this.layer_.leftBounds||this.layer_.rightBounds)&&this.distorter_.setTextureBounds(this.layer_.leftBounds,this.layer_.rightBounds)},be.prototype.beginPresent_=function(){var e=this.layer_.source.getContext("webgl");e||(e=this.layer_.source.getContext("experimental-webgl")),e||(e=this.layer_.source.getContext("webgl2")),e&&(this.layer_.predistorted?this.config.CARDBOARD_UI_DISABLED||(e.canvas.width=p()*this.bufferScale_,e.canvas.height=f()*this.bufferScale_,this.cardboardUI_=new I(e)):(this.config.CARDBOARD_UI_DISABLED||(this.cardboardUI_=new I(e)),this.distorter_=new T(e,this.cardboardUI_,this.config.BUFFER_SCALE,this.config.DIRTY_SUBMIT_FRAME_BINDINGS),this.distorter_.updateDeviceInfo(this.deviceInfo_)),this.cardboardUI_&&this.cardboardUI_.listen(function(e){this.viewerSelector_.show(this.layer_.source.parentElement),e.stopPropagation(),e.preventDefault()}.bind(this),function(e){this.exitPresent(),e.stopPropagation(),e.preventDefault()}.bind(this)),this.rotateInstructions_&&(u()&&v()?this.rotateInstructions_.showTemporarily(3e3,this.layer_.source.parentElement):this.rotateInstructions_.update()),this.orientationHandler=this.onOrientationChange_.bind(this),window.addEventListener("orientationchange",this.orientationHandler),this.vrdisplaypresentchangeHandler=this.updateBounds_.bind(this),window.addEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler),this.fireVRDisplayDeviceParamsChange_())},be.prototype.endPresent_=function(){this.distorter_&&(this.distorter_.destroy(),this.distorter_=null),this.cardboardUI_&&(this.cardboardUI_.destroy(),this.cardboardUI_=null),this.rotateInstructions_&&this.rotateInstructions_.hide(),this.viewerSelector_.hide(),window.removeEventListener("orientationchange",this.orientationHandler),window.removeEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler)},be.prototype.updatePresent_=function(){this.endPresent_(),this.beginPresent_()},be.prototype.submitFrame=function(e){if(this.distorter_)this.updateBounds_(),this.distorter_.submitFrame();else if(this.cardboardUI_&&this.layer_){var t=this.layer_.source.getContext("webgl").canvas;t.width==this.lastWidth&&t.height==this.lastHeight||this.cardboardUI_.onResize(),this.lastWidth=t.width,this.lastHeight=t.height,this.cardboardUI_.render()}},be.prototype.onOrientationChange_=function(e){this.viewerSelector_.hide(),this.rotateInstructions_&&this.rotateInstructions_.update(),this.onResize_()},be.prototype.onResize_=function(e){if(this.layer_){var t=this.layer_.source.getContext("webgl");t.canvas.setAttribute("style",["position: absolute","top: 0","left: 0","width: 100vw","height: 100vh","border: 0","margin: 0","padding: 0px","box-sizing: content-box"].join("; ")+";"),b(t.canvas)}},be.prototype.onViewerChanged_=function(e){this.deviceInfo_.setViewer(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_),this.fireVRDisplayDeviceParamsChange_()},be.prototype.fireVRDisplayDeviceParamsChange_=function(){var e=new CustomEvent("vrdisplaydeviceparamschange",{detail:{vrdisplay:this,deviceInfo:this.deviceInfo_}});window.dispatchEvent(e)},be.VRFrameData=function(){this.leftProjectionMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.rightViewMatrix=new Float32Array(16),this.pose=null},be.VRDisplay=we,be}()}(ze={exports:{}},ze.exports),ze.exports),Xe=(Ue=He)&&Ue.__esModule&&Object.prototype.hasOwnProperty.call(Ue,"default")?Ue.default:Ue;class We extends i{constructor(e){super(),this.global=e,this.onWindowResize=this.onWindowResize.bind(this),this.global.window.addEventListener("resize",this.onWindowResize),this.environmentBlendMode="opaque"}get depthNear(){throw new Error("Not implemented")}set depthNear(e){throw new Error("Not implemented")}get depthFar(){throw new Error("Not implemented")}set depthFar(e){throw new Error("Not implemented")}onBaseLayerSet(e,t){throw new Error("Not implemented")}onInlineVerticalFieldOfViewSet(e,t){throw new Error("Not implemented")}supportsSession(e){throw new Error("Not implemented")}async requestSession(e){throw new Error("Not implemented")}requestAnimationFrame(e){throw new Error("Not implemented")}onFrameStart(e){throw new Error("Not implemented")}onFrameEnd(e){throw new Error("Not implemented")}requestStageBounds(){throw new Error("Not implemented")}async requestFrameOfReferenceTransform(e,t){}cancelAnimationFrame(e){throw new Error("Not implemented")}endSession(e){throw new Error("Not implemented")}getViewport(e,t,i,r){throw new Error("Not implemented")}getProjectionMatrix(e){throw new Error("Not implemented")}getBasePoseMatrix(){throw new Error("Not implemented")}getBaseViewMatrix(e){throw new Error("Not implemented")}getInputSources(){throw new Error("Not implemented")}getInputPose(e,t,i){throw new Error("Not implemented")}onWindowResize(){this.onWindowResize()}}let je={mapping:"xr-standard",id:"oculus-touch",buttons:{length:6,0:1,1:0,2:2,3:null,4:3,5:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ye={mapping:"xr-standard",id:"windows-mixed-reality",buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ze={"Oculus Touch (Right)":je,"Oculus Touch (Left)":je,"Oculus Go Controller":{mapping:"xr-standard",id:"oculus-go",buttons:{0:1,1:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},"Windows Mixed Reality (Right)":Ye,"Windows Mixed Reality (Left)":Ye};const qe=E(.155,-.465,-.15),Je=E(-.155,-.465,-.15),Ke=E(0,0,-.25),$e=E(0,0,.05),et=E(-.08,.14,.08),tt=.4,it=.4,rt=.61,nt=.175,st=.12,at=.87,ot=180/Math.PI;class lt{constructor(){this.hand="right",this.headElbowOffset=qe,this.controllerQ=C(),this.lastControllerQ=C(),this.headQ=C(),this.headPos=y(),this.elbowPos=y(),this.wristPos=y(),this.time=null,this.lastTime=null,this.rootQ=C(),this.position=y()}setHandedness(e){this.hand!=e&&(this.hand=e,"left"==this.hand?this.headElbowOffset=Je:this.headElbowOffset=qe)}update(e,t){this.time=o(),e&&(Q(this.lastControllerQ,this.controllerQ),Q(this.controllerQ,e)),t&&(w(this.headPos,t),v(this.headQ,t));let i=this.getHeadYawOrientation_(),r=this.quatAngle_(this.lastControllerQ,this.controllerQ);r/((this.time-this.lastTime)/1e3)>rt?D(this.rootQ,this.rootQ,i,Math.min(r/nt,1)):Q(this.rootQ,i);let n=E(0,0,-1);T(n,n,this.controllerQ);let s=S(n,[0,1,0]),a=this.clamp_((s-st)/at,0,1),l=L(this.rootQ);I(l,l),P(l,l,this.controllerQ);let A=this.elbowPos;M(A,this.headPos),_(A,A,this.headElbowOffset);let h=b(et);x(h,h,a),_(A,A,h);let c=this.quatAngle_(l,C())*ot,d=(1-Math.pow(c/180,4))*(tt+(1-tt)*a*it),u=C();D(u,u,l,d);let p=I(C(),u),f=L(l);P(f,f,p);let m=this.wristPos;M(m,$e),T(m,m,u),_(m,m,Ke),T(m,m,f),_(m,m,A);let g=b(et);x(g,g,a),_(this.position,this.wristPos,g),T(this.position,this.position,this.rootQ),this.lastTime=this.time}getPosition(){return this.position}getHeadYawOrientation_(){let e=y();return function(e,t,i){function r(e,t,i){return e<t?t:e>i?i:e}var n=t[0]*t[0],s=t[1]*t[1],a=t[2]*t[2],o=t[3]*t[3];if("XYZ"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[1]*t[2]),o-n-s+a),e[1]=Math.asin(r(2*(t[0]*t[2]+t[1]*t[3]),-1,1)),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o+n-s-a);else if("YXZ"===i)e[0]=Math.asin(r(2*(t[0]*t[3]-t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o-n-s+a),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o-n+s-a);else if("ZXY"===i)e[0]=Math.asin(r(2*(t[0]*t[3]+t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[1]*t[3]-t[2]*t[0]),o-n-s+a),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o-n+s-a);else if("ZYX"===i)e[0]=Math.atan2(2*(t[0]*t[3]+t[2]*t[1]),o-n-s+a),e[1]=Math.asin(r(2*(t[1]*t[3]-t[0]*t[2]),-1,1)),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o+n-s-a);else if("YZX"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[2]*t[1]),o-n+s-a),e[1]=Math.atan2(2*(t[1]*t[3]-t[0]*t[2]),o+n-s-a),e[2]=Math.asin(r(2*(t[0]*t[1]+t[2]*t[3]),-1,1));else{if("XZY"!==i)return void console.log("No order given for quaternion to euler conversion.");e[0]=Math.atan2(2*(t[0]*t[3]+t[1]*t[2]),o-n+s-a),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o+n-s-a),e[2]=Math.asin(r(2*(t[2]*t[3]-t[0]*t[1]),-1,1))}}(e,this.headQ,"YXZ"),function(e,t,i,r){let n=.5*Math.PI/180;t*=n,i*=n,r*=n;let s=Math.sin(t),a=Math.cos(t),o=Math.sin(i),l=Math.cos(i),A=Math.sin(r),h=Math.cos(r);return e[0]=s*l*h-a*o*A,e[1]=a*o*h+s*l*A,e[2]=a*l*A-s*o*h,e[3]=a*l*h+s*o*A,e}(C(),0,e[1]*ot,0)}clamp_(e,t,i){return Math.min(Math.max(e,t),i)}quatAngle_(e,t){let i=[0,0,-1],r=[0,0,-1];return T(i,i,e),T(r,r,t),function(e,t){let i=E(e[0],e[1],e[2]),r=E(t[0],t[1],t[2]);F(i,i),F(r,r);let n=S(i,r);return n>1?0:n<-1?Math.PI:Math.acos(n)}(i,r)}}const At=Symbol("@@webxr-polyfill/XRRemappedGamepad"),ht={pressed:!1,touched:!1,value:0};Object.freeze(ht);class ct{constructor(e,t){t||(t={});let i=new Array(t.axes?t.axes.length:e.axes.length),r=new Array(t.buttons?t.buttons.length:e.buttons.length),n=null;if(t.gripTransform){let e=t.gripTransform.orientation||[0,0,0,1];g(n=d(),N(e,e),t.gripTransform.position||[0,0,0])}let s=null;if(t.targetRayTransform){let e=t.targetRayTransform.orientation||[0,0,0,1];g(s=d(),N(e,e),t.targetRayTransform.position||[0,0,0])}this[At]={gamepad:e,map:t,id:t.id||e.id,mapping:t.mapping||e.mapping,axes:i,buttons:r,gripTransform:n,targetRayTransform:s},this._update()}_update(){let e=this[At].gamepad,t=this[At].map,i=this[At].axes;for(let r=0;r<i.length;++r)t.axes&&r in t.axes?null===t.axes[r]?i[r]=0:i[r]=e.axes[t.axes[r]]:i[r]=e.axes[r];let r=this[At].buttons;for(let i=0;i<r.length;++i)t.buttons&&i in t.buttons?null===t.buttons[i]?r[i]=ht:r[i]=e.buttons[t.buttons[i]]:r[i]=e.buttons[i]}get id(){return this[At].id}get index(){return 0}get connected(){return this[At].gamepad.connected}get timestamp(){return this[At].gamepad.timestamp}get mapping(){return this[At].mapping}get axes(){return this[At].axes}get buttons(){return this[At].buttons}}class dt{constructor(e,t=0){this.polyfill=e,this.nativeGamepad=null,this.gamepad=null,this.inputSource=new Ce(this),this.lastPosition=y(),this.emulatedPosition=!1,this.basePoseMatrix=d(),this.outputMatrix=d(),this.inputPoses=new WeakMap,this.primaryButtonIndex=t,this.primaryActionPressed=!1,this.handedness="",this.targetRayMode="gaze",this.armModel=null}updateFromGamepad(e){this.nativeGamepad!==e&&(this.nativeGamepad=e,this.gamepad=e?new ct(e,Ze[e.id]):null),this.handedness=e.hand,this.gamepad&&this.gamepad._update(),e.pose?(this.targetRayMode="tracked-pointer",this.emulatedPosition=!e.pose.hasPosition):""===e.hand&&(this.targetRayMode="gaze",this.emulatedPosition=!1)}updateBasePoseMatrix(){if(this.nativeGamepad&&this.nativeGamepad.pose){let e=this.nativeGamepad.pose,t=e.position,i=e.orientation;if(!t&&!i)return;t?(this.lastPosition[0]=t[0],this.lastPosition[1]=t[1],this.lastPosition[2]=t[2]):e.hasPosition?t=this.lastPosition:(this.armModel||(this.armModel=new lt),this.armModel.setHandedness(this.nativeGamepad.hand),this.armModel.update(i,this.polyfill.getBasePoseMatrix()),t=this.armModel.getPosition()),g(this.basePoseMatrix,i,t)}else u(this.basePoseMatrix,this.polyfill.getBasePoseMatrix());return this.basePoseMatrix}getXRPose(e,t){switch(this.updateBasePoseMatrix(),t){case"target-ray":e.transformBasePoseMatrix(this.outputMatrix,this.basePoseMatrix),this.gamepad&&this.gamepad[At].targetRayTransform&&m(this.outputMatrix,this.outputMatrix,this.gamepad[At].targetRayTransform);break;case"grip":if(!this.nativeGamepad||!this.nativeGamepad.pose)return null;e.transformBasePoseMatrix(this.outputMatrix,this.basePoseMatrix),this.gamepad&&this.gamepad[At].gripTransform&&m(this.outputMatrix,this.outputMatrix,this.gamepad[At].gripTransform);break;default:return null}return e._adjustForOriginOffset(this.outputMatrix),new XRPose(new XRRigidTransform(this.outputMatrix),this.emulatedPosition)}}const ut=!1,pt={highRefreshRate:!0},ft={oculus:1,openvr:1,"spatial controller (spatial interaction source)":1};let mt=0;class gt{constructor(e,t={}){if(this.mode=e,this.outputContext=null,this.immersive="immersive-vr"==e||"immersive-ar"==e,this.ended=null,this.baseLayer=null,this.inlineVerticalFieldOfView=.5*Math.PI,this.id=++mt,this.modifiedCanvasLayer=!1,this.outputContext&&!ut){const e=t.renderContextType||"2d";this.renderContext=this.outputContext.canvas.getContext(e)}}}class wt extends We{constructor(e,t){const{canPresent:i}=t.capabilities;super(e),this.display=t,this.frame=new e.VRFrameData,this.sessions=new Map,this.immersiveSession=null,this.canPresent=i,this.baseModelMatrix=d(),this.gamepadInputSources={},this.tempVec3=new Float32Array(3),this.onVRDisplayPresentChange=this.onVRDisplayPresentChange.bind(this),e.window.addEventListener("vrdisplaypresentchange",this.onVRDisplayPresentChange),this.CAN_USE_GAMEPAD=e.navigator&&"getGamepads"in e.navigator,this.HAS_BITMAP_SUPPORT=Qe(e)}get depthNear(){return this.display.depthNear}set depthNear(e){this.display.depthNear=e}get depthFar(){return this.display.depthFar}set depthFar(e){this.display.depthFar=e}onBaseLayerSet(e,t){const i=this.sessions.get(e),r=t.context.canvas;if(i.immersive){const e=this.display.getEyeParameters("left"),n=this.display.getEyeParameters("right");r.width=2*Math.max(e.renderWidth,n.renderWidth),r.height=Math.max(e.renderHeight,n.renderHeight),this.display.requestPresent([{source:r,attributes:pt}]).then(()=>{ut||this.global.document.body.contains(r)||(i.modifiedCanvasLayer=!0,this.global.document.body.appendChild(r),ke(r)),i.baseLayer=t})}else i.baseLayer=t}onInlineVerticalFieldOfViewSet(e,t){this.sessions.get(e).inlineVerticalFieldOfView=t}supportsSession(e){if(-1==n.indexOf(e))throw new TypeError(`The provided value '${e}' is not a valid enum value of type XRSessionMode`);return"immersive-ar"!=e&&("immersive-vr"!=e||!1!==this.canPresent)}async requestSession(e){if(!this.supportsSession(e))return Promise.reject();let t="immersive-vr"==e;if(t){const e=this.global.document.createElement("canvas");if(!ut){e.getContext("webgl")}await this.display.requestPresent([{source:e,attributes:pt}])}const i=new gt(e,{renderContextType:this.HAS_BITMAP_SUPPORT?"bitmaprenderer":"2d"});return this.sessions.set(i.id,i),t&&(this.immersiveSession=i,this.dispatchEvent("@@webxr-polyfill/vr-present-start",i.id)),Promise.resolve(i.id)}requestAnimationFrame(e){return this.display.requestAnimationFrame(e)}getPrimaryButtonIndex(e){let t=0,i=e.id.toLowerCase();for(let e in ft)if(i.includes(e)){t=ft[e];break}return Math.min(t,e.buttons.length-1)}onFrameStart(e){this.display.getFrameData(this.frame);const t=this.sessions.get(e);if(t.immersive&&this.CAN_USE_GAMEPAD){let e=this.gamepadInputSources;this.gamepadInputSources={};let i=this.global.navigator.getGamepads();for(let r=0;r<i.length;++r){let n=i[r];if(n&&n.displayId>0){let i=e[r];if(i||(i=new dt(this,this.getPrimaryButtonIndex(n))),i.updateFromGamepad(n),this.gamepadInputSources[r]=i,-1!=i.primaryButtonIndex){let e=n.buttons[i.primaryButtonIndex].pressed;e&&!i.primaryActionPressed?this.dispatchEvent("@@webxr-polyfill/input-select-start",{sessionId:t.id,inputSource:i.inputSource}):!e&&i.primaryActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-select-end",{sessionId:t.id,inputSource:i.inputSource}),i.primaryActionPressed=e}}}}if(!ut&&!t.immersive&&t.baseLayer){const e=t.baseLayer.context.canvas;!function(e,t,i,r,n){let s,a=1/Math.tan(t/2);e[0]=a/i,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=a,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[11]=-1,e[12]=0,e[13]=0,e[15]=0,null!=n&&n!==1/0?(s=1/(r-n),e[10]=(n+r)*s,e[14]=2*n*r*s):(e[10]=-1,e[14]=-2*r)}(this.frame.leftProjectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,this.depthNear,this.depthFar)}}onFrameEnd(e){const t=this.sessions.get(e);if(!t.ended&&t.baseLayer){if(t.outputContext&&(!t.immersive||this.display.capabilities.hasExternalDisplay)){const e=t.immersive&&this.display.capabilities.hasExternalDisplay,i=t.baseLayer.context.canvas,r=e?i.width/2:i.width,n=i.height;if(!ut){const e=t.outputContext.canvas,s=e.width,a=e.height,o=t.renderContext;this.HAS_BITMAP_SUPPORT?i.transferToImageBitmap?o.transferFromImageBitmap(i.transferToImageBitmap()):this.global.createImageBitmap(i,0,0,r,n,{resizeWidth:s,resizeHeight:a}).then(e=>o.transferFromImageBitmap(e)):o.drawImage(i,0,0,r,n,0,0,s,a)}}t.immersive&&t.baseLayer&&this.display.submitFrame()}}cancelAnimationFrame(e){this.display.cancelAnimationFrame(e)}async endSession(e){const t=this.sessions.get(e);if(!t.ended)return t.immersive?this.display.exitPresent():void(t.ended=!0)}requestStageBounds(){if(this.display.stageParameters){const e=this.display.stageParameters.sizeX,t=this.display.stageParameters.sizeZ,i=[];return i.push(-e/2),i.push(-t/2),i.push(e/2),i.push(-t/2),i.push(e/2),i.push(t/2),i.push(-e/2),i.push(t/2),i}return null}async requestFrameOfReferenceTransform(e,t){if("stage"===e&&this.display.stageParameters&&this.display.stageParameters.sittingToStandingTransform)return this.display.stageParameters.sittingToStandingTransform}getProjectionMatrix(e){if("left"===e)return this.frame.leftProjectionMatrix;if("right"===e)return this.frame.rightProjectionMatrix;if("none"===e)return this.frame.leftProjectionMatrix;throw new Error("eye must be of type 'left' or 'right'")}getViewport(e,t,i,r){const n=this.sessions.get(e),{width:s,height:a}=i.context.canvas;if(!n.immersive)return r.x=r.y=0,r.width=s,r.height=a,!0;if("left"===t)r.x=0;else{if("right"!==t)return!1;r.x=s/2}return r.y=0,r.width=s/2,r.height=a,!0}getBasePoseMatrix(){let{position:e,orientation:t}=this.frame.pose;return e||t?(e||((e=this.tempVec3)[0]=e[1]=e[2]=0),g(this.baseModelMatrix,t,e),this.baseModelMatrix):this.baseModelMatrix}getBaseViewMatrix(e){if("left"===e)return this.frame.leftViewMatrix;if("right"===e)return this.frame.rightViewMatrix;throw new Error("eye must be of type 'left' or 'right'")}getInputSources(){let e=[];for(let t in this.gamepadInputSources)e.push(this.gamepadInputSources[t].inputSource);return e}getInputPose(e,t,i){if(!t)return null;for(let r in this.gamepadInputSources){let n=this.gamepadInputSources[r];if(n.inputSource===e)return n.getXRPose(t,i)}return null}onWindowResize(){}onVRDisplayPresentChange(e){this.display.isPresenting||this.sessions.forEach(e=>{if(e.immersive&&!e.ended){if(e.modifiedCanvasLayer){const t=e.baseLayer.context.canvas;document.body.removeChild(t),t.setAttribute("style","")}this.immersiveSession===e&&(this.immersiveSession=null),this.dispatchEvent("@@webxr-polyfill/vr-present-end",e.id)}})}}const vt=async function(e,t){if(t.webvr){let t=await async function(e){let t=null;if("getVRDisplays"in e.navigator)try{const i=await e.navigator.getVRDisplays();i&&i.length&&(t=new wt(e,i[0]))}catch(e){}return t}(e);if(t)return t}return e.VRFrameData||(e.VRFrameData=function(){this.rightViewMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.leftProjectionMatrix=new Float32Array(16),this.pose=null}),new class extends wt{constructor(e,t){const i=new Xe(t||{});super(e,i),this.display=i,this.frame={rightViewMatrix:new Float32Array(16),leftViewMatrix:new Float32Array(16),rightProjectionMatrix:new Float32Array(16),leftProjectionMatrix:new Float32Array(16),pose:null,timestamp:null}}}(e,t.cardboardConfig)},yt={global:e,webvr:!0,cardboard:!0,cardboardConfig:null,allowCardboardOnDesktop:!1},bt=["navigator","HTMLCanvasElement","WebGLRenderingContext"];return class{constructor(e={}){this.config=Object.freeze(Object.assign({},yt,e)),this.global=this.config.global,this.nativeWebXR="xr"in this.global.navigator,this.injected=!1,this.nativeWebXR?this.config.cardboard&&Ne(this.global)&&this._patchNavigatorXR():this._injectPolyfill(this.global)}_injectPolyfill(e){if(!bt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${bt}`);for(const t of Object.keys(Ie))void 0!==e[t]?console.warn(`${t} already defined on global.`):e[t]=Ie[t];Le(e.WebGLRenderingContext)&&(Oe(e.HTMLCanvasElement),e.OffscreenCanvas&&Oe(e.OffscreenCanvas),e.WebGL2RenderingContext&&Le(e.WebGL2RenderingContext)),this.injected=!0,this._patchNavigatorXR()}_patchNavigatorXR(){let e=vt(this.global,this.config);this.xr=new XR(e),Object.defineProperty(this.global.navigator,"xr",{value:this.xr,configurable:!0})}}});
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.module.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.module.js
new file mode 100644
index 00000000000..5afcfbc137f
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.module.js
@@ -0,0 +1,6129 @@
+/**
+ * @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.
+ */
+
+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 PRIVATE$1 = Symbol('@@webxr-polyfill/XR');
+const XRSessionModes = ['inline', 'immersive-vr', 'immersive-ar'];
+const POLYFILL_REQUEST_SESSION_ERROR =
+`Polyfill Error: Must call navigator.xr.supportsSession() 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 XR$1 extends EventTarget {
+ constructor(devicePromise) {
+ super();
+ this[PRIVATE$1] = {
+ device: null,
+ devicePromise,
+ immersiveSession: null,
+ inlineSessions: new Set(),
+ };
+ devicePromise.then((device) => { this[PRIVATE$1].device = device; });
+ }
+ async supportsSession(mode) {
+ if (!this[PRIVATE$1].device) {
+ await this[PRIVATE$1].devicePromise;
+ }
+ if (mode != 'inline') {
+ if (!this[PRIVATE$1].device.supportsSession(mode)) {
+ return Promise.reject(null);
+ }
+ }
+ return Promise.resolve(null);
+ }
+ async requestSession(mode) {
+ if (!this[PRIVATE$1].device) {
+ if (mode != 'inline') {
+ throw new Error(POLYFILL_REQUEST_SESSION_ERROR);
+ } else {
+ await this[PRIVATE$1].devicePromise;
+ }
+ }
+ const sessionId = await this[PRIVATE$1].device.requestSession(mode);
+ const session = new XRSession(this[PRIVATE$1].device, mode, sessionId);
+ if (mode == 'inline') {
+ this[PRIVATE$1].inlineSessions.add(session);
+ } else {
+ this[PRIVATE$1].immersiveSession = session;
+ }
+ const onSessionEnd = () => {
+ if (mode == 'inline') {
+ this[PRIVATE$1].inlineSessions.delete(session);
+ } else {
+ this[PRIVATE$1].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$2 = Symbol('@@webxr-polyfill/XRPose');
+class XRPose$1 {
+ constructor(transform, emulatedPosition) {
+ this[PRIVATE$2] = {
+ transform,
+ emulatedPosition,
+ };
+ }
+ get transform() { return this[PRIVATE$2].transform; }
+ get emulatedPosition() { return this[PRIVATE$2].emulatedPosition; }
+ _setTransform(transform) { this[PRIVATE$2].transform = transform; }
+}
+
+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$3 = Symbol('@@webxr-polyfill/XRRigidTransform');
+class XRRigidTransform$1 {
+ constructor() {
+ this[PRIVATE$3] = {
+ matrix: null,
+ position: null,
+ orientation: null,
+ inverse: null,
+ };
+ if (arguments.length === 0) {
+ this[PRIVATE$3].matrix = identity(new Float32Array(16));
+ } else if (arguments.length === 1) {
+ if (arguments[0] instanceof Float32Array) {
+ this[PRIVATE$3].matrix = arguments[0];
+ } else {
+ this[PRIVATE$3].position = this._getPoint(arguments[0]);
+ this[PRIVATE$3].orientation = DOMPointReadOnly.fromPoint({
+ x: 0, y: 0, z: 0, w: 1
+ });
+ }
+ } else if (arguments.length === 2) {
+ this[PRIVATE$3].position = this._getPoint(arguments[0]);
+ this[PRIVATE$3].orientation = this._getPoint(arguments[1]);
+ } else {
+ throw new Error("Too many arguments!");
+ }
+ if (this[PRIVATE$3].matrix) {
+ let position = create$1();
+ getTranslation(position, this[PRIVATE$3].matrix);
+ this[PRIVATE$3].position = DOMPointReadOnly.fromPoint({
+ x: position[0],
+ y: position[1],
+ z: position[2]
+ });
+ let orientation = create$4();
+ getRotation(orientation, this[PRIVATE$3].matrix);
+ this[PRIVATE$3].orientation = DOMPointReadOnly.fromPoint({
+ x: orientation[0],
+ y: orientation[1],
+ z: orientation[2],
+ w: orientation[3]
+ });
+ } else {
+ this[PRIVATE$3].matrix = identity(new Float32Array(16));
+ fromRotationTranslation(
+ this[PRIVATE$3].matrix,
+ fromValues$4(
+ this[PRIVATE$3].orientation.x,
+ this[PRIVATE$3].orientation.y,
+ this[PRIVATE$3].orientation.z,
+ this[PRIVATE$3].orientation.w),
+ fromValues$1(
+ this[PRIVATE$3].position.x,
+ this[PRIVATE$3].position.y,
+ this[PRIVATE$3].position.z)
+ );
+ }
+ }
+ _getPoint(arg) {
+ if (arg instanceof DOMPointReadOnly) {
+ return arg;
+ }
+ return DOMPointReadOnly.fromPoint(arg);
+ }
+ get matrix() { return this[PRIVATE$3].matrix; }
+ get position() { return this[PRIVATE$3].position; }
+ get orientation() { return this[PRIVATE$3].orientation; }
+ get inverse() {
+ if (this[PRIVATE$3].inverse === null) {
+ let invMatrix = identity(new Float32Array(16));
+ invert(invMatrix, this[PRIVATE$3].matrix);
+ this[PRIVATE$3].inverse = new XRRigidTransform$1(invMatrix);
+ this[PRIVATE$3].inverse[PRIVATE$3].inverse = this;
+ }
+ return this[PRIVATE$3].inverse;
+ }
+}
+
+const PRIVATE$4 = Symbol('@@webxr-polyfill/XRViewerPose');
+class XRViewerPose extends XRPose$1 {
+ constructor(device) {
+ super(new XRRigidTransform$1(), false);
+ this[PRIVATE$4] = {
+ device,
+ leftViewMatrix: identity(new Float32Array(16)),
+ rightViewMatrix: identity(new Float32Array(16)),
+ poseModelMatrix: identity(new Float32Array(16)),
+ };
+ }
+ get poseModelMatrix() { return this[PRIVATE$4].poseModelMatrix; }
+ getViewMatrix(view) {
+ switch (view.eye) {
+ case 'left': return this[PRIVATE$4].leftViewMatrix;
+ case 'right': return this[PRIVATE$4].rightViewMatrix;
+ }
+ throw new Error(`view is not a valid XREye`);
+ }
+ get views() {
+ return this[PRIVATE$4].views;
+ }
+ set views(value) {
+ this[PRIVATE$4].views = value;
+ }
+ updateFromReferenceSpace(refSpace) {
+ const pose = this[PRIVATE$4].device.getBasePoseMatrix();
+ const leftViewMatrix = this[PRIVATE$4].device.getBaseViewMatrix('left');
+ const rightViewMatrix = this[PRIVATE$4].device.getBaseViewMatrix('right');
+ if (pose) {
+ refSpace.transformBasePoseMatrix(this[PRIVATE$4].poseModelMatrix, pose);
+ refSpace._adjustForOriginOffset(this[PRIVATE$4].poseModelMatrix);
+ super._setTransform(new XRRigidTransform$1(this[PRIVATE$4].poseModelMatrix));
+ }
+ if (leftViewMatrix && rightViewMatrix) {
+ refSpace.transformBaseViewMatrix(this[PRIVATE$4].leftViewMatrix,
+ leftViewMatrix,
+ this[PRIVATE$4].poseModelMatrix);
+ refSpace.transformBaseViewMatrix(this[PRIVATE$4].rightViewMatrix,
+ rightViewMatrix,
+ this[PRIVATE$4].poseModelMatrix);
+ multiply(this[PRIVATE$4].leftViewMatrix, this[PRIVATE$4].leftViewMatrix, refSpace._originOffsetMatrix());
+ multiply(this[PRIVATE$4].rightViewMatrix, this[PRIVATE$4].rightViewMatrix, refSpace._originOffsetMatrix());
+ }
+ for (let view of this[PRIVATE$4].views) {
+ if (view.eye == "left") {
+ view._updateViewMatrix(this[PRIVATE$4].leftViewMatrix);
+ } else if (view.eye == "right") {
+ view._updateViewMatrix(this[PRIVATE$4].rightViewMatrix);
+ }
+ }
+ }
+}
+
+const PRIVATE$5 = Symbol('@@webxr-polyfill/XRViewport');
+class XRViewport {
+ constructor(target) {
+ this[PRIVATE$5] = { target };
+ }
+ get x() { return this[PRIVATE$5].target.x; }
+ get y() { return this[PRIVATE$5].target.y; }
+ get width() { return this[PRIVATE$5].target.width; }
+ get height() { return this[PRIVATE$5].target.height; }
+}
+
+const XREyes = ['left', 'right'];
+const PRIVATE$6 = Symbol('@@webxr-polyfill/XRView');
+class XRView {
+ constructor(device, 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$6] = {
+ device,
+ eye,
+ viewport,
+ temp,
+ sessionId,
+ transform: null,
+ };
+ }
+ get eye() { return this[PRIVATE$6].eye; }
+ get projectionMatrix() { return this[PRIVATE$6].device.getProjectionMatrix(this.eye); }
+ get transform() { return this[PRIVATE$6].transform; }
+ _updateViewMatrix(viewMatrix) {
+ let invMatrix = identity(new Float32Array(16));
+ invert(invMatrix, viewMatrix);
+ this[PRIVATE$6].transform = new XRRigidTransform$1(invMatrix);
+ }
+ _getViewport(layer) {
+ const viewport = this[PRIVATE$6].viewport;
+ if (this[PRIVATE$6].device.getViewport(this[PRIVATE$6].sessionId,
+ this.eye,
+ layer,
+ this[PRIVATE$6].temp)) {
+ return this[PRIVATE$6].viewport;
+ }
+ return undefined;
+ }
+}
+
+var EPSILON$1 = 0.000001;
+var ARRAY_TYPE$1 = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+
+
+var degree$1 = Math.PI / 180;
+
+function create$7() {
+ var out = new ARRAY_TYPE$1(9);
+ if (ARRAY_TYPE$1 != 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$9() {
+ var out = new ARRAY_TYPE$1(3);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ }
+ return out;
+}
+
+function length$3(a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ return Math.sqrt(x * x + y * y + z * z);
+}
+function fromValues$9(x, y, z) {
+ var out = new ARRAY_TYPE$1(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function normalize$3(out, a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ var 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$3(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+function cross$1(out, a, b) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ var 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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var len$3 = length$3;
+
+var forEach$2 = function () {
+ var vec = create$9();
+ return function (a, stride, offset, count, fn, arg) {
+ var i = void 0,
+ l = void 0;
+ 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$10() {
+ var out = new ARRAY_TYPE$1(4);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ }
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function normalize$4(out, a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ var w = a[3];
+ var 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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var forEach$3 = function () {
+ var vec = create$10();
+ return function (a, stride, offset, count, fn, arg) {
+ var i = void 0,
+ l = void 0;
+ 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$11() {
+ var out = new ARRAY_TYPE$1(4);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ }
+ out[3] = 1;
+ return out;
+}
+
+function setAxisAngle$1(out, axis, rad) {
+ rad = rad * 0.5;
+ var 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 slerp$1(out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ var bx = b[0],
+ by = b[1],
+ bz = b[2],
+ bw = b[3];
+ var omega = void 0,
+ cosom = void 0,
+ sinom = void 0,
+ scale0 = void 0,
+ scale1 = void 0;
+ 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$1) {
+ 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 fromMat3$1(out, m) {
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot = void 0;
+ 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 {
+ var i = 0;
+ if (m[4] > m[0]) i = 1;
+ if (m[8] > m[i * 3 + i]) i = 2;
+ var j = (i + 1) % 3;
+ var 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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var normalize$5 = normalize$4;
+
+
+var rotationTo$1 = function () {
+ var tmpvec3 = create$9();
+ var xUnitVec3 = fromValues$9(1, 0, 0);
+ var yUnitVec3 = fromValues$9(0, 1, 0);
+ return function (out, a, b) {
+ var dot = dot$3(a, b);
+ if (dot < -0.999999) {
+ cross$1(tmpvec3, xUnitVec3, a);
+ if (len$3(tmpvec3) < 0.000001) cross$1(tmpvec3, yUnitVec3, a);
+ normalize$3(tmpvec3, tmpvec3);
+ setAxisAngle$1(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ cross$1(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return normalize$5(out, out);
+ }
+ };
+}();
+var sqlerp$1 = function () {
+ var temp1 = create$11();
+ var temp2 = create$11();
+ return function (out, a, b, c, d, t) {
+ slerp$1(temp1, a, d, t);
+ slerp$1(temp2, b, c, t);
+ slerp$1(out, temp1, temp2, 2 * t * (1 - t));
+ return out;
+ };
+}();
+var setAxes$1 = function () {
+ var matr = create$7();
+ 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$5(out, fromMat3$1(out, matr));
+ };
+}();
+
+function create$13() {
+ var out = new ARRAY_TYPE$1(2);
+ if (ARRAY_TYPE$1 != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ }
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var forEach$4 = function () {
+ var vec = create$13();
+ return function (a, stride, offset, count, fn, arg) {
+ var i = void 0,
+ l = void 0;
+ if (!stride) {
+ stride = 2;
+ }
+ 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];
+ fn(vec, vec, arg);
+ a[i] = vec[0];a[i + 1] = vec[1];
+ }
+ return a;
+ };
+}();
+
+const PRIVATE$7 = Symbol('@@webxr-polyfill/XRFrame');
+class XRFrame {
+ constructor(device, session, sessionId) {
+ const viewerPose = new XRViewerPose(device);
+ const views = [
+ new XRView(device, 'left', sessionId),
+ ];
+ if (session.immersive) {
+ views.push(new XRView(device, 'right', sessionId));
+ }
+ viewerPose.views = views;
+ this[PRIVATE$7] = {
+ device,
+ viewerPose,
+ views,
+ session,
+ };
+ }
+ get session() { return this[PRIVATE$7].session; }
+ get views() { return this[PRIVATE$7].views; }
+ getViewerPose(space) {
+ this[PRIVATE$7].viewerPose.updateFromReferenceSpace(space);
+ return this[PRIVATE$7].viewerPose;
+ }
+ getPose(space, baseSpace) {
+ if (space._specialType === "viewer") {
+ let viewerPose = this.getViewerPose(baseSpace);
+ return new XRPose(
+ new XRRigidTransform(viewerPose.poseModelMatrix),
+ viewerPose.emulatedPosition);
+ }
+ if (space._specialType === "target-ray" || space._specialType === "grip") {
+ return this[PRIVATE$7].device.getInputPose(
+ space._inputSource, baseSpace, space._specialType);
+ }
+ return null;
+ }
+}
+
+const PRIVATE$8 = Symbol('@@webxr-polyfill/XRStageBoundsPoint');
+class XRStageBoundsPoint {
+ constructor(x, z) {
+ this[PRIVATE$8] = { x, z };
+ }
+ get x() { return this[PRIVATE$8].x; }
+ get z() { return this[PRIVATE$8].z; }
+}
+
+const PRIVATE$9 = Symbol('@@webxr-polyfill/XRStageBounds');
+class XRStageBounds {
+ constructor(boundsData) {
+ const geometry = [];
+ for (let i = 0; i < boundsData.length; i += 2) {
+ geometry.push(new XRStageBoundsPoint(boundsData[i], boundsData[i + 1]));
+ }
+ this[PRIVATE$9] = { geometry };
+ }
+ get geometry() { return this[PRIVATE$9].geometry; }
+}
+
+const PRIVATE$10 = Symbol('@@webxr-polyfill/XRSpace');
+class XRSpace {
+ constructor(specialType = null, inputSource = null) {
+ this[PRIVATE$10] = {
+ specialType,
+ inputSource,
+ };
+ }
+ get _specialType() {
+ return this[PRIVATE$10].specialType;
+ }
+ get _inputSource() {
+ return this[PRIVATE$10].inputSource;
+ }
+}
+
+const DEFAULT_EMULATION_HEIGHT = 1.6;
+const PRIVATE$11 = Symbol('@@webxr-polyfill/XRReferenceSpace');
+const XRReferenceSpaceTypes = [
+ 'viewer',
+ 'local',
+ 'local-floor',
+ 'bounded-floor',
+ 'unbounded'
+];
+const XRReferenceSpaceOptions = Object.freeze({
+ disableStageEmulation: false,
+ stageEmulationHeight: 0,
+});
+class XRReferenceSpace extends XRSpace {
+ constructor(device, type, options, transform, bounds) {
+ options = Object.assign({}, XRReferenceSpaceOptions, options);
+ if (!XRReferenceSpaceTypes.includes(type)) {
+ throw new Error(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`);
+ }
+ super((type === 'viewer') ? 'viewer' : null);
+ if (this._isFloor(type) && options.disableStageEmulation && !transform) {
+ throw new Error(`XRReferenceSpace cannot use 'bounded-floor' type, if disabling emulation and platform does not provide`);
+ }
+ const { disableStageEmulation, stageEmulationHeight } = options;
+ let emulatedHeight = 0;
+ if (this._isFloor(type) && !transform) {
+ emulatedHeight = stageEmulationHeight !== 0 ? stageEmulationHeight : DEFAULT_EMULATION_HEIGHT;
+ }
+ if (this._isFloor(type) && !transform) {
+ transform = identity(new Float32Array(16));
+ transform[13] = emulatedHeight;
+ }
+ if (!transform) {
+ transform = identity(new Float32Array(16));
+ }
+ this[PRIVATE$11] = {
+ disableStageEmulation,
+ stageEmulationHeight,
+ emulatedHeight,
+ type,
+ transform,
+ device,
+ bounds,
+ options,
+ originOffset : identity(new Float32Array(16)),
+ };
+ this.onboundschange = undefined;
+ }
+ _isFloor(type) {
+ return type === 'bounded-floor' || type === 'local-floor';
+ }
+ get bounds() { return this[PRIVATE$11].bounds; }
+ get emulatedHeight() { return this[PRIVATE$11].emulatedHeight; }
+ get type() { return this[PRIVATE$11].type; }
+ transformBasePoseMatrix(out, pose) {
+ if (this[PRIVATE$11].transform) {
+ multiply(out, this[PRIVATE$11].transform, pose);
+ return;
+ }
+ switch (this.type) {
+ case 'local':
+ if (out !== pose) {
+ copy(out, pose);
+ }
+ return;
+ }
+ }
+ transformBaseViewMatrix(out, view) {
+ let frameOfRef = this[PRIVATE$11].transform;
+ if (frameOfRef) {
+ invert(out, frameOfRef);
+ multiply(out, view, out);
+ }
+ else {
+ copy(out, view);
+ }
+ return out;
+ }
+ _inverseOriginOffsetMatrix() {
+ let result = identity(new Float32Array(16));
+ invert(result, this[PRIVATE$11].originOffset);
+ return result;
+ }
+ _originOffsetMatrix() {
+ return this[PRIVATE$11].originOffset;
+ }
+ _adjustForOriginOffset(transformMatrix) {
+ multiply(transformMatrix, this._inverseOriginOffsetMatrix(), transformMatrix);
+ }
+ getOffsetReferenceSpace(additionalOffset) {
+ let newSpace = new XRReferenceSpace(
+ this[PRIVATE$11].device,
+ this[PRIVATE$11].type,
+ this[PRIVATE$11].options,
+ this[PRIVATE$11].transform,
+ this[PRIVATE$11].bounds);
+ multiply(newSpace[PRIVATE$11].originOffset, this[PRIVATE$11].originOffset, additionalOffset.matrix);
+ return newSpace;
+ }
+}
+
+const POLYFILLED_XR_COMPATIBLE = Symbol('@@webxr-polyfill/polyfilled-xr-compatible');
+const XR_COMPATIBLE = Symbol('@@webxr-polyfill/xr-compatible');
+
+const PRIVATE$12 = 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$12] = {
+ context,
+ config,
+ framebuffer,
+ session,
+ };
+ }
+ get context() { return this[PRIVATE$12].context; }
+ get antialias() { return this[PRIVATE$12].config.antialias; }
+ get ignoreDepthValues() { return true; }
+ get framebuffer() { return this[PRIVATE$12].framebuffer; }
+ get framebufferWidth() { return this[PRIVATE$12].context.drawingBufferWidth; }
+ get framebufferHeight() { return this[PRIVATE$12].context.drawingBufferHeight; }
+ get _session() { return this[PRIVATE$12].session; }
+ getViewport(view) {
+ return view._getViewport(this);
+ }
+}
+
+const PRIVATE$13 = Symbol('@@webxr-polyfill/XRSession');
+class XRSession$1 extends EventTarget {
+ constructor(device, mode, id) {
+ super();
+ let immersive = mode != 'inline';
+ let outputContext = null;
+ this[PRIVATE$13] = {
+ device,
+ mode,
+ immersive,
+ outputContext,
+ ended: false,
+ suspended: false,
+ suspendedCallback: null,
+ id,
+ activeRenderState: null,
+ pendingRenderState: null,
+ };
+ const frame = new XRFrame(device, this, this[PRIVATE$13].id);
+ this[PRIVATE$13].frame = frame;
+ this[PRIVATE$13].onPresentationEnd = sessionId => {
+ if (sessionId !== this[PRIVATE$13].id) {
+ this[PRIVATE$13].suspended = false;
+ this.dispatchEvent('focus', { session: this });
+ const suspendedCallback = this[PRIVATE$13].suspendedCallback;
+ this[PRIVATE$13].suspendedCallback = null;
+ if (suspendedCallback) {
+ this.requestAnimationFrame(suspendedCallback);
+ }
+ return;
+ }
+ this[PRIVATE$13].ended = true;
+ device.removeEventListener('@webvr-polyfill/vr-present-end', this[PRIVATE$13].onPresentationEnd);
+ device.removeEventListener('@webvr-polyfill/vr-present-start', this[PRIVATE$13].onPresentationStart);
+ device.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$13].onSelectStart);
+ device.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$13].onSelectEnd);
+ this.dispatchEvent('end', { session: this });
+ };
+ device.addEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$13].onPresentationEnd);
+ this[PRIVATE$13].onPresentationStart = sessionId => {
+ if (sessionId === this[PRIVATE$13].id) {
+ return;
+ }
+ this[PRIVATE$13].suspended = true;
+ this.dispatchEvent('blur', { session: this });
+ };
+ device.addEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$13].onPresentationStart);
+ this[PRIVATE$13].onSelectStart = evt => {
+ if (evt.sessionId !== this[PRIVATE$13].id) {
+ return;
+ }
+ this.dispatchEvent('selectstart', {
+ frame: this[PRIVATE$13].frame,
+ inputSource: evt.inputSource
+ });
+ };
+ device.addEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$13].onSelectStart);
+ this[PRIVATE$13].onSelectEnd = evt => {
+ if (evt.sessionId !== this[PRIVATE$13].id) {
+ return;
+ }
+ this.dispatchEvent('selectend', {
+ frame: this[PRIVATE$13].frame,
+ inputSource: evt.inputSource
+ });
+ this.dispatchEvent('select', {
+ frame: this[PRIVATE$13].frame,
+ inputSource: evt.inputSource
+ });
+ };
+ device.addEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$13].onSelectEnd);
+ 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$13].activeRenderState; }
+ get immersive() { return this[PRIVATE$13].immersive; }
+ get outputContext() { return this[PRIVATE$13].outputContext; }
+ get depthNear() { return this[PRIVATE$13].device.depthNear; }
+ set depthNear(value) { this[PRIVATE$13].device.depthNear = value; }
+ get depthFar() { return this[PRIVATE$13].device.depthFar; }
+ set depthFar(value) { this[PRIVATE$13].device.depthFar = value; }
+ get environmentBlendMode() {
+ return this[PRIVATE$13].device.environmentBlendMode || 'opaque';
+ }
+ get baseLayer() { return this[PRIVATE$13].baseLayer; }
+ set baseLayer(value) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ this[PRIVATE$13].baseLayer = value;
+ this[PRIVATE$13].device.onBaseLayerSet(this[PRIVATE$13].id, value);
+ }
+ async requestReferenceSpace(type, options={}) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ options = Object.assign({}, XRReferenceSpaceOptions, options);
+ if (!XRReferenceSpaceTypes.includes(type)) {
+ throw new TypeError(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`);
+ }
+ let transform = null;
+ let bounds = null;
+ try {
+ transform = await this[PRIVATE$13].device.requestFrameOfReferenceTransform(type, options);
+ } catch (e) {
+ if (type !== 'stage' || options.disableStageEmulation) {
+ throw e;
+ }
+ }
+ if (type === 'stage' && transform) {
+ bounds = this[PRIVATE$13].device.requestStageBounds();
+ if (bounds) {
+ bounds = new XRStageBounds(bounds);
+ }
+ }
+ return new XRReferenceSpace(this[PRIVATE$13].device, type, options, transform, bounds);
+ }
+ requestAnimationFrame(callback) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ if (this[PRIVATE$13].suspended && this[PRIVATE$13].suspendedCallback) {
+ return;
+ }
+ if (this[PRIVATE$13].suspended && !this[PRIVATE$13].suspendedCallback) {
+ this[PRIVATE$13].suspendedCallback = callback;
+ }
+ return this[PRIVATE$13].device.requestAnimationFrame(() => {
+ if (this[PRIVATE$13].pendingRenderState !== null) {
+ this[PRIVATE$13].activeRenderState = this[PRIVATE$13].pendingRenderState;
+ this[PRIVATE$13].pendingRenderState = null;
+ if (this[PRIVATE$13].activeRenderState.baseLayer) {
+ this[PRIVATE$13].device.onBaseLayerSet(
+ this[PRIVATE$13].id,
+ this[PRIVATE$13].activeRenderState.baseLayer);
+ }
+ if (this[PRIVATE$13].activeRenderState.inlineVerticalFieldOfView) {
+ this[PRIVATE$13].device.onInlineVerticalFieldOfViewSet(
+ this[PRIVATE$13].id,
+ this[PRIVATE$13].activeRenderState.inlineVerticalFieldOfView);
+ }
+ }
+ this[PRIVATE$13].device.onFrameStart(this[PRIVATE$13].id);
+ callback(now$1(), this[PRIVATE$13].frame);
+ this[PRIVATE$13].device.onFrameEnd(this[PRIVATE$13].id);
+ });
+ }
+ cancelAnimationFrame(handle) {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ this[PRIVATE$13].device.cancelAnimationFrame(handle);
+ }
+ get inputSources() {
+ return this[PRIVATE$13].device.getInputSources();
+ }
+ async end() {
+ if (this[PRIVATE$13].ended) {
+ return;
+ }
+ if (!this.immersive) {
+ this[PRIVATE$13].ended = true;
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/vr-present-start',
+ this[PRIVATE$13].onPresentationStart);
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/vr-present-end',
+ this[PRIVATE$13].onPresentationEnd);
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/input-select-start',
+ this[PRIVATE$13].onSelectStart);
+ this[PRIVATE$13].device.removeEventListener('@@webvr-polyfill/input-select-end',
+ this[PRIVATE$13].onSelectEnd);
+ this.dispatchEvent('end', { session: this });
+ }
+ return this[PRIVATE$13].device.endSession(this[PRIVATE$13].id);
+ }
+ updateRenderState(newState) {
+ if (this[PRIVATE$13].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$13].immersive) {
+ const message = "inlineVerticalFieldOfView must not be set for an " +
+ "XRRenderState passed to updateRenderState for an " +
+ "immersive session.";
+ throw new Error(message);
+ } else {
+ newState.inlineVerticalFieldOfView = Math.min(
+ 3.13, Math.max(0.01, newState.inlineVerticalFieldOfView));
+ }
+ }
+ if (this[PRIVATE$13].pendingRenderState === null) {
+ this[PRIVATE$13].pendingRenderState = Object.assign(
+ {}, this[PRIVATE$13].activeRenderState, newState);
+ }
+ }
+}
+
+const PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSource');
+class XRInputSource {
+ constructor(impl) {
+ this[PRIVATE$14] = {
+ impl,
+ gripSpace: new XRSpace("grip", this),
+ targetRaySpace: new XRSpace("target-ray", this)
+ };
+ }
+ get handedness() { return this[PRIVATE$14].impl.handedness; }
+ get targetRayMode() { return this[PRIVATE$14].impl.targetRayMode; }
+ get gripSpace() {
+ let mode = this[PRIVATE$14].impl.targetRayMode;
+ if (mode === "gaze" || mode === "screen") {
+ return null;
+ }
+ return this[PRIVATE$14].gripSpace;
+ }
+ get targetRaySpace() { return this[PRIVATE$14].targetRaySpace; }
+ get gamepad() { return this[PRIVATE$14].impl.gamepad; }
+}
+
+const PRIVATE$15 = 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$15] = { config };
+ }
+ get depthNear() { return this[PRIVATE$15].depthNear; }
+ get depthFar() { return this[PRIVATE$15].depthFar; }
+ get inlineVerticalFieldOfView() { return this[PRIVATE$15].inlineVerticalFieldOfView; }
+ get baseLayer() { return this[PRIVATE$15].baseLayer; }
+}
+
+var API = {
+ XR: XR$1,
+ XRSession: XRSession$1,
+ XRFrame,
+ XRView,
+ XRViewport,
+ XRViewerPose,
+ XRWebGLLayer,
+ XRSpace,
+ XRReferenceSpace,
+ XRStageBounds,
+ XRStageBoundsPoint,
+ XRInputSource,
+ XRRenderState,
+ XRRigidTransform: XRRigidTransform$1,
+ XRPose: XRPose$1,
+};
+
+const polyfillMakeXRCompatible = Context => {
+ if (typeof Context.prototype.makeXRCompatible === 'function') {
+ return false;
+ }
+ Context.prototype.makeXRCompatible = function () {
+ this[XR_COMPATIBLE] = true;
+ return Promise.resolve();
+ };
+ return true;
+};
+const polyfillGetContext = (Canvas) => {
+ const getContext = Canvas.prototype.getContext;
+ Canvas.prototype.getContext = function (contextType, glAttribs) {
+ const ctx = getContext.call(this, contextType, glAttribs);
+ ctx[POLYFILLED_XR_COMPATIBLE] = true;
+ if (glAttribs && ('xrCompatible' in glAttribs)) {
+ ctx[XR_COMPATIBLE] = glAttribs.xrCompatible;
+ }
+ return ctx;
+ };
+};
+
+const isImageBitmapSupported = global =>
+ !!(global.ImageBitmapRenderingContext &&
+ global.createImageBitmap);
+const isMobile = global => {
+ var check = false;
+ (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(global.navigator.userAgent||global.navigator.vendor||global.opera);
+ return check;
+};
+const applyCanvasStylesForMinimalRendering = canvas => {
+ canvas.style.display = 'block';
+ canvas.style.position = 'absolute';
+ canvas.style.width = canvas.style.height = '1px';
+ canvas.style.top = canvas.style.left = '0px';
+};
+
+var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+
+
+function unwrapExports (x) {
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
+}
+
+function createCommonjsModule(fn, module) {
+ return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
+
+var cardboardVrDisplay = createCommonjsModule(function (module, exports) {
+(function (global, factory) {
+ module.exports = factory();
+}(commonjsGlobal, (function () { var classCallCheck = function (instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+};
+var createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+}();
+var slicedToArray = function () {
+ function sliceIterator(arr, i) {
+ var _arr = [];
+ var _n = true;
+ var _d = false;
+ var _e = undefined;
+ try {
+ for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
+ _arr.push(_s.value);
+ if (i && _arr.length === i) break;
+ }
+ } catch (err) {
+ _d = true;
+ _e = err;
+ } finally {
+ try {
+ if (!_n && _i["return"]) _i["return"]();
+ } finally {
+ if (_d) throw _e;
+ }
+ }
+ return _arr;
+ }
+ return function (arr, i) {
+ if (Array.isArray(arr)) {
+ return arr;
+ } else if (Symbol.iterator in Object(arr)) {
+ return sliceIterator(arr, i);
+ } else {
+ throw new TypeError("Invalid attempt to destructure non-iterable instance");
+ }
+ };
+}();
+var MIN_TIMESTEP = 0.001;
+var MAX_TIMESTEP = 1;
+var dataUri = function dataUri(mimeType, svg) {
+ return 'data:' + mimeType + ',' + encodeURIComponent(svg);
+};
+var lerp = function lerp(a, b, t) {
+ return a + (b - a) * t;
+};
+var isIOS = function () {
+ var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);
+ return function () {
+ return isIOS;
+ };
+}();
+var isWebViewAndroid = function () {
+ var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1;
+ return function () {
+ return isWebViewAndroid;
+ };
+}();
+var isSafari = function () {
+ var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+ return function () {
+ return isSafari;
+ };
+}();
+var isFirefoxAndroid = function () {
+ var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1;
+ return function () {
+ return isFirefoxAndroid;
+ };
+}();
+var getChromeVersion = function () {
+ var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/);
+ var value = match ? parseInt(match[1], 10) : null;
+ return function () {
+ return value;
+ };
+}();
+var isChromeWithoutDeviceMotion = function () {
+ var value = false;
+ if (getChromeVersion() === 65) {
+ var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/);
+ if (match) {
+ var _match$1$split = match[1].split('.'),
+ _match$1$split2 = slicedToArray(_match$1$split, 4),
+ major = _match$1$split2[0],
+ minor = _match$1$split2[1],
+ branch = _match$1$split2[2],
+ build = _match$1$split2[3];
+ value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148;
+ }
+ }
+ return function () {
+ return value;
+ };
+}();
+var isR7 = function () {
+ var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1;
+ return function () {
+ return isR7;
+ };
+}();
+var isLandscapeMode = function isLandscapeMode() {
+ var rtn = window.orientation == 90 || window.orientation == -90;
+ return isR7() ? !rtn : rtn;
+};
+var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) {
+ if (isNaN(timestampDeltaS)) {
+ return false;
+ }
+ if (timestampDeltaS <= MIN_TIMESTEP) {
+ return false;
+ }
+ if (timestampDeltaS > MAX_TIMESTEP) {
+ return false;
+ }
+ return true;
+};
+var getScreenWidth = function getScreenWidth() {
+ return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio;
+};
+var getScreenHeight = function getScreenHeight() {
+ return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio;
+};
+var requestFullscreen = function requestFullscreen(element) {
+ if (isWebViewAndroid()) {
+ return false;
+ }
+ if (element.requestFullscreen) {
+ element.requestFullscreen();
+ } else if (element.webkitRequestFullscreen) {
+ element.webkitRequestFullscreen();
+ } else if (element.mozRequestFullScreen) {
+ element.mozRequestFullScreen();
+ } else if (element.msRequestFullscreen) {
+ element.msRequestFullscreen();
+ } else {
+ return false;
+ }
+ return true;
+};
+var exitFullscreen = function exitFullscreen() {
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen();
+ } else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen();
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen();
+ } else {
+ return false;
+ }
+ return true;
+};
+var getFullscreenElement = function getFullscreenElement() {
+ return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
+};
+var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) {
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, vertexSource);
+ gl.compileShader(vertexShader);
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, fragmentSource);
+ gl.compileShader(fragmentShader);
+ var program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ for (var attribName in attribLocationMap) {
+ gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);
+ }gl.linkProgram(program);
+ gl.deleteShader(vertexShader);
+ gl.deleteShader(fragmentShader);
+ return program;
+};
+var getProgramUniforms = function getProgramUniforms(gl, program) {
+ var uniforms = {};
+ var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
+ var uniformName = '';
+ for (var i = 0; i < uniformCount; i++) {
+ var uniformInfo = gl.getActiveUniform(program, i);
+ uniformName = uniformInfo.name.replace('[0]', '');
+ uniforms[uniformName] = gl.getUniformLocation(program, uniformName);
+ }
+ return uniforms;
+};
+var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+var isMobile = function isMobile() {
+ var check = false;
+ (function (a) {
+ if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
+ })(navigator.userAgent || navigator.vendor || window.opera);
+ return check;
+};
+var extend = function extend(dest, src) {
+ for (var key in src) {
+ if (src.hasOwnProperty(key)) {
+ dest[key] = src[key];
+ }
+ }
+ return dest;
+};
+var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) {
+ if (isIOS()) {
+ var width = canvas.style.width;
+ var height = canvas.style.height;
+ canvas.style.width = parseInt(width) + 1 + 'px';
+ canvas.style.height = parseInt(height) + 'px';
+ setTimeout(function () {
+ canvas.style.width = width;
+ canvas.style.height = height;
+ }, 100);
+ }
+ window.canvas = canvas;
+};
+var frameDataFromPose = function () {
+ var piOver180 = Math.PI / 180.0;
+ var rad45 = Math.PI * 0.25;
+ function mat4_perspectiveFromFieldOfView(out, fov, near, far) {
+ var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45),
+ downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45),
+ leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45),
+ rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45),
+ xScale = 2.0 / (leftTan + rightTan),
+ yScale = 2.0 / (upTan + downTan);
+ out[0] = xScale;
+ out[1] = 0.0;
+ out[2] = 0.0;
+ out[3] = 0.0;
+ out[4] = 0.0;
+ out[5] = yScale;
+ out[6] = 0.0;
+ out[7] = 0.0;
+ out[8] = -((leftTan - rightTan) * xScale * 0.5);
+ out[9] = (upTan - downTan) * yScale * 0.5;
+ out[10] = far / (near - far);
+ out[11] = -1.0;
+ out[12] = 0.0;
+ out[13] = 0.0;
+ out[14] = far * near / (near - far);
+ out[15] = 0.0;
+ return out;
+ }
+ function mat4_fromRotationTranslation(out, q, v) {
+ var x = q[0],
+ y = q[1],
+ z = q[2],
+ w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ 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 mat4_translate(out, a, v) {
+ var x = v[0],
+ y = v[1],
+ z = v[2],
+ a00,
+ a01,
+ a02,
+ a03,
+ a10,
+ a11,
+ a12,
+ a13,
+ a20,
+ a21,
+ a22,
+ a23;
+ if (a === out) {
+ out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+ out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+ out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+ out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+ } else {
+ a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
+ a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
+ a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
+ out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
+ out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
+ out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
+ out[12] = a00 * x + a10 * y + a20 * z + a[12];
+ out[13] = a01 * x + a11 * y + a21 * z + a[13];
+ out[14] = a02 * x + a12 * y + a22 * z + a[14];
+ out[15] = a03 * x + a13 * y + a23 * z + a[15];
+ }
+ return out;
+ }
+ function mat4_invert(out, a) {
+ var a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11],
+ a30 = a[12],
+ a31 = a[13],
+ a32 = a[14],
+ a33 = a[15],
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+ 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;
+ }
+ var defaultOrientation = new Float32Array([0, 0, 0, 1]);
+ var defaultPosition = new Float32Array([0, 0, 0]);
+ function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) {
+ mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar);
+ var orientation = pose.orientation || defaultOrientation;
+ var position = pose.position || defaultPosition;
+ mat4_fromRotationTranslation(view, orientation, position);
+ if (offset) mat4_translate(view, view, offset);
+ mat4_invert(view, view);
+ }
+ return function (frameData, pose, vrDisplay) {
+ if (!frameData || !pose) return false;
+ frameData.pose = pose;
+ frameData.timestamp = pose.timestamp;
+ updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay);
+ updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay);
+ return true;
+ };
+}();
+var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() {
+ var isFramed = window.self !== window.top;
+ var refOrigin = getOriginFromUrl(document.referrer);
+ var thisOrigin = getOriginFromUrl(window.location.href);
+ return isFramed && refOrigin !== thisOrigin;
+};
+var getOriginFromUrl = function getOriginFromUrl(url) {
+ var domainIdx;
+ var protoSepIdx = url.indexOf("://");
+ if (protoSepIdx !== -1) {
+ domainIdx = protoSepIdx + 3;
+ } else {
+ domainIdx = 0;
+ }
+ var domainEndIdx = url.indexOf('/', domainIdx);
+ if (domainEndIdx === -1) {
+ domainEndIdx = url.length;
+ }
+ return url.substring(0, domainEndIdx);
+};
+var getQuaternionAngle = function getQuaternionAngle(quat) {
+ if (quat.w > 1) {
+ console.warn('getQuaternionAngle: w > 1');
+ return 0;
+ }
+ var angle = 2 * Math.acos(quat.w);
+ return angle;
+};
+var warnOnce = function () {
+ var observedWarnings = {};
+ return function (key, message) {
+ if (observedWarnings[key] === undefined) {
+ console.warn('webvr-polyfill: ' + message);
+ observedWarnings[key] = true;
+ }
+ };
+}();
+var deprecateWarning = function deprecateWarning(deprecated, suggested) {
+ var alternative = suggested ? 'Please use ' + suggested + ' instead.' : '';
+ warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative);
+};
+function WGLUPreserveGLState(gl, bindings, callback) {
+ if (!bindings) {
+ callback(gl);
+ return;
+ }
+ var boundValues = [];
+ var activeTexture = null;
+ for (var i = 0; i < bindings.length; ++i) {
+ var binding = bindings[i];
+ switch (binding) {
+ case gl.TEXTURE_BINDING_2D:
+ case gl.TEXTURE_BINDING_CUBE_MAP:
+ var textureUnit = bindings[++i];
+ if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {
+ console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit");
+ boundValues.push(null, null);
+ break;
+ }
+ if (!activeTexture) {
+ activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
+ }
+ gl.activeTexture(textureUnit);
+ boundValues.push(gl.getParameter(binding), null);
+ break;
+ case gl.ACTIVE_TEXTURE:
+ activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
+ boundValues.push(null);
+ break;
+ default:
+ boundValues.push(gl.getParameter(binding));
+ break;
+ }
+ }
+ callback(gl);
+ for (var i = 0; i < bindings.length; ++i) {
+ var binding = bindings[i];
+ var boundValue = boundValues[i];
+ switch (binding) {
+ case gl.ACTIVE_TEXTURE:
+ break;
+ case gl.ARRAY_BUFFER_BINDING:
+ gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);
+ break;
+ case gl.COLOR_CLEAR_VALUE:
+ gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
+ break;
+ case gl.COLOR_WRITEMASK:
+ gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
+ break;
+ case gl.CURRENT_PROGRAM:
+ gl.useProgram(boundValue);
+ break;
+ case gl.ELEMENT_ARRAY_BUFFER_BINDING:
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);
+ break;
+ case gl.FRAMEBUFFER_BINDING:
+ gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);
+ break;
+ case gl.RENDERBUFFER_BINDING:
+ gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);
+ break;
+ case gl.TEXTURE_BINDING_2D:
+ var textureUnit = bindings[++i];
+ if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
+ break;
+ gl.activeTexture(textureUnit);
+ gl.bindTexture(gl.TEXTURE_2D, boundValue);
+ break;
+ case gl.TEXTURE_BINDING_CUBE_MAP:
+ var textureUnit = bindings[++i];
+ if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
+ break;
+ gl.activeTexture(textureUnit);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);
+ break;
+ case gl.VIEWPORT:
+ gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
+ break;
+ case gl.BLEND:
+ case gl.CULL_FACE:
+ case gl.DEPTH_TEST:
+ case gl.SCISSOR_TEST:
+ case gl.STENCIL_TEST:
+ if (boundValue) {
+ gl.enable(binding);
+ } else {
+ gl.disable(binding);
+ }
+ break;
+ default:
+ console.log("No GL restore behavior for 0x" + binding.toString(16));
+ break;
+ }
+ if (activeTexture) {
+ gl.activeTexture(activeTexture);
+ }
+ }
+}
+var glPreserveState = WGLUPreserveGLState;
+var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n');
+var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n');
+function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) {
+ this.gl = gl;
+ this.cardboardUI = cardboardUI;
+ this.bufferScale = bufferScale;
+ this.dirtySubmitFrameBindings = dirtySubmitFrameBindings;
+ this.ctxAttribs = gl.getContextAttributes();
+ this.meshWidth = 20;
+ this.meshHeight = 20;
+ this.bufferWidth = gl.drawingBufferWidth;
+ this.bufferHeight = gl.drawingBufferHeight;
+ this.realBindFramebuffer = gl.bindFramebuffer;
+ this.realEnable = gl.enable;
+ this.realDisable = gl.disable;
+ this.realColorMask = gl.colorMask;
+ this.realClearColor = gl.clearColor;
+ this.realViewport = gl.viewport;
+ if (!isIOS()) {
+ this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');
+ this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');
+ }
+ this.isPatched = false;
+ this.lastBoundFramebuffer = null;
+ this.cullFace = false;
+ this.depthTest = false;
+ this.blend = false;
+ this.scissorTest = false;
+ this.stencilTest = false;
+ this.viewport = [0, 0, 0, 0];
+ this.colorMask = [true, true, true, true];
+ this.clearColor = [0, 0, 0, 0];
+ this.attribs = {
+ position: 0,
+ texCoord: 1
+ };
+ this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs);
+ this.uniforms = getProgramUniforms(gl, this.program);
+ this.viewportOffsetScale = new Float32Array(8);
+ this.setTextureBounds();
+ this.vertexBuffer = gl.createBuffer();
+ this.indexBuffer = gl.createBuffer();
+ this.indexCount = 0;
+ this.renderTarget = gl.createTexture();
+ this.framebuffer = gl.createFramebuffer();
+ this.depthStencilBuffer = null;
+ this.depthBuffer = null;
+ this.stencilBuffer = null;
+ if (this.ctxAttribs.depth && this.ctxAttribs.stencil) {
+ this.depthStencilBuffer = gl.createRenderbuffer();
+ } else if (this.ctxAttribs.depth) {
+ this.depthBuffer = gl.createRenderbuffer();
+ } else if (this.ctxAttribs.stencil) {
+ this.stencilBuffer = gl.createRenderbuffer();
+ }
+ this.patch();
+ this.onResize();
+}
+CardboardDistorter.prototype.destroy = function () {
+ var gl = this.gl;
+ this.unpatch();
+ gl.deleteProgram(this.program);
+ gl.deleteBuffer(this.vertexBuffer);
+ gl.deleteBuffer(this.indexBuffer);
+ gl.deleteTexture(this.renderTarget);
+ gl.deleteFramebuffer(this.framebuffer);
+ if (this.depthStencilBuffer) {
+ gl.deleteRenderbuffer(this.depthStencilBuffer);
+ }
+ if (this.depthBuffer) {
+ gl.deleteRenderbuffer(this.depthBuffer);
+ }
+ if (this.stencilBuffer) {
+ gl.deleteRenderbuffer(this.stencilBuffer);
+ }
+ if (this.cardboardUI) {
+ this.cardboardUI.destroy();
+ }
+};
+CardboardDistorter.prototype.onResize = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0];
+ glPreserveState(gl, glState, function (gl) {
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
+ if (self.scissorTest) {
+ self.realDisable.call(gl, gl.SCISSOR_TEST);
+ }
+ self.realColorMask.call(gl, true, true, true, true);
+ self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ self.realClearColor.call(gl, 0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer);
+ gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
+ gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0);
+ if (self.ctxAttribs.depth && self.ctxAttribs.stencil) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer);
+ } else if (self.ctxAttribs.depth) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer);
+ } else if (self.ctxAttribs.stencil) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer);
+ }
+ if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
+ console.error('Framebuffer incomplete!');
+ }
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
+ if (self.scissorTest) {
+ self.realEnable.call(gl, gl.SCISSOR_TEST);
+ }
+ self.realColorMask.apply(gl, self.colorMask);
+ self.realViewport.apply(gl, self.viewport);
+ self.realClearColor.apply(gl, self.clearColor);
+ });
+ if (this.cardboardUI) {
+ this.cardboardUI.onResize();
+ }
+};
+CardboardDistorter.prototype.patch = function () {
+ if (this.isPatched) {
+ return;
+ }
+ var self = this;
+ var canvas = this.gl.canvas;
+ var gl = this.gl;
+ if (!isIOS()) {
+ canvas.width = getScreenWidth() * this.bufferScale;
+ canvas.height = getScreenHeight() * this.bufferScale;
+ Object.defineProperty(canvas, 'width', {
+ configurable: true,
+ enumerable: true,
+ get: function get() {
+ return self.bufferWidth;
+ },
+ set: function set(value) {
+ self.bufferWidth = value;
+ self.realCanvasWidth.set.call(canvas, value);
+ self.onResize();
+ }
+ });
+ Object.defineProperty(canvas, 'height', {
+ configurable: true,
+ enumerable: true,
+ get: function get() {
+ return self.bufferHeight;
+ },
+ set: function set(value) {
+ self.bufferHeight = value;
+ self.realCanvasHeight.set.call(canvas, value);
+ self.onResize();
+ }
+ });
+ }
+ this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
+ if (this.lastBoundFramebuffer == null) {
+ this.lastBoundFramebuffer = this.framebuffer;
+ this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
+ }
+ this.gl.bindFramebuffer = function (target, framebuffer) {
+ self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer;
+ self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer);
+ };
+ this.cullFace = gl.getParameter(gl.CULL_FACE);
+ this.depthTest = gl.getParameter(gl.DEPTH_TEST);
+ this.blend = gl.getParameter(gl.BLEND);
+ this.scissorTest = gl.getParameter(gl.SCISSOR_TEST);
+ this.stencilTest = gl.getParameter(gl.STENCIL_TEST);
+ gl.enable = function (pname) {
+ switch (pname) {
+ case gl.CULL_FACE:
+ self.cullFace = true;break;
+ case gl.DEPTH_TEST:
+ self.depthTest = true;break;
+ case gl.BLEND:
+ self.blend = true;break;
+ case gl.SCISSOR_TEST:
+ self.scissorTest = true;break;
+ case gl.STENCIL_TEST:
+ self.stencilTest = true;break;
+ }
+ self.realEnable.call(gl, pname);
+ };
+ gl.disable = function (pname) {
+ switch (pname) {
+ case gl.CULL_FACE:
+ self.cullFace = false;break;
+ case gl.DEPTH_TEST:
+ self.depthTest = false;break;
+ case gl.BLEND:
+ self.blend = false;break;
+ case gl.SCISSOR_TEST:
+ self.scissorTest = false;break;
+ case gl.STENCIL_TEST:
+ self.stencilTest = false;break;
+ }
+ self.realDisable.call(gl, pname);
+ };
+ this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK);
+ gl.colorMask = function (r, g, b, a) {
+ self.colorMask[0] = r;
+ self.colorMask[1] = g;
+ self.colorMask[2] = b;
+ self.colorMask[3] = a;
+ self.realColorMask.call(gl, r, g, b, a);
+ };
+ this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
+ gl.clearColor = function (r, g, b, a) {
+ self.clearColor[0] = r;
+ self.clearColor[1] = g;
+ self.clearColor[2] = b;
+ self.clearColor[3] = a;
+ self.realClearColor.call(gl, r, g, b, a);
+ };
+ this.viewport = gl.getParameter(gl.VIEWPORT);
+ gl.viewport = function (x, y, w, h) {
+ self.viewport[0] = x;
+ self.viewport[1] = y;
+ self.viewport[2] = w;
+ self.viewport[3] = h;
+ self.realViewport.call(gl, x, y, w, h);
+ };
+ this.isPatched = true;
+ safariCssSizeWorkaround(canvas);
+};
+CardboardDistorter.prototype.unpatch = function () {
+ if (!this.isPatched) {
+ return;
+ }
+ var gl = this.gl;
+ var canvas = this.gl.canvas;
+ if (!isIOS()) {
+ Object.defineProperty(canvas, 'width', this.realCanvasWidth);
+ Object.defineProperty(canvas, 'height', this.realCanvasHeight);
+ }
+ canvas.width = this.bufferWidth;
+ canvas.height = this.bufferHeight;
+ gl.bindFramebuffer = this.realBindFramebuffer;
+ gl.enable = this.realEnable;
+ gl.disable = this.realDisable;
+ gl.colorMask = this.realColorMask;
+ gl.clearColor = this.realClearColor;
+ gl.viewport = this.realViewport;
+ if (this.lastBoundFramebuffer == this.framebuffer) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ }
+ this.isPatched = false;
+ setTimeout(function () {
+ safariCssSizeWorkaround(canvas);
+ }, 1);
+};
+CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) {
+ if (!leftBounds) {
+ leftBounds = [0, 0, 0.5, 1];
+ }
+ if (!rightBounds) {
+ rightBounds = [0.5, 0, 0.5, 1];
+ }
+ this.viewportOffsetScale[0] = leftBounds[0];
+ this.viewportOffsetScale[1] = leftBounds[1];
+ this.viewportOffsetScale[2] = leftBounds[2];
+ this.viewportOffsetScale[3] = leftBounds[3];
+ this.viewportOffsetScale[4] = rightBounds[0];
+ this.viewportOffsetScale[5] = rightBounds[1];
+ this.viewportOffsetScale[6] = rightBounds[2];
+ this.viewportOffsetScale[7] = rightBounds[3];
+};
+CardboardDistorter.prototype.submitFrame = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [];
+ if (!this.dirtySubmitFrameBindings) {
+ glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0);
+ }
+ glPreserveState(gl, glState, function (gl) {
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
+ if (self.cullFace) {
+ self.realDisable.call(gl, gl.CULL_FACE);
+ }
+ if (self.depthTest) {
+ self.realDisable.call(gl, gl.DEPTH_TEST);
+ }
+ if (self.blend) {
+ self.realDisable.call(gl, gl.BLEND);
+ }
+ if (self.scissorTest) {
+ self.realDisable.call(gl, gl.SCISSOR_TEST);
+ }
+ if (self.stencilTest) {
+ self.realDisable.call(gl, gl.STENCIL_TEST);
+ }
+ self.realColorMask.call(gl, true, true, true, true);
+ self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ if (self.ctxAttribs.alpha || isIOS()) {
+ self.realClearColor.call(gl, 0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+ gl.useProgram(self.program);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
+ gl.enableVertexAttribArray(self.attribs.position);
+ gl.enableVertexAttribArray(self.attribs.texCoord);
+ gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8);
+ gl.activeTexture(gl.TEXTURE0);
+ gl.uniform1i(self.uniforms.diffuse, 0);
+ gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
+ gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale);
+ gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);
+ if (self.cardboardUI) {
+ self.cardboardUI.renderNoState();
+ }
+ self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);
+ if (!self.ctxAttribs.preserveDrawingBuffer) {
+ self.realClearColor.call(gl, 0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+ if (!self.dirtySubmitFrameBindings) {
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
+ }
+ if (self.cullFace) {
+ self.realEnable.call(gl, gl.CULL_FACE);
+ }
+ if (self.depthTest) {
+ self.realEnable.call(gl, gl.DEPTH_TEST);
+ }
+ if (self.blend) {
+ self.realEnable.call(gl, gl.BLEND);
+ }
+ if (self.scissorTest) {
+ self.realEnable.call(gl, gl.SCISSOR_TEST);
+ }
+ if (self.stencilTest) {
+ self.realEnable.call(gl, gl.STENCIL_TEST);
+ }
+ self.realColorMask.apply(gl, self.colorMask);
+ self.realViewport.apply(gl, self.viewport);
+ if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) {
+ self.realClearColor.apply(gl, self.clearColor);
+ }
+ });
+ if (isIOS()) {
+ var canvas = gl.canvas;
+ if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) {
+ self.bufferWidth = canvas.width;
+ self.bufferHeight = canvas.height;
+ self.onResize();
+ }
+ }
+};
+CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];
+ glPreserveState(gl, glState, function (gl) {
+ var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo);
+ gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ if (!self.indexCount) {
+ var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+ self.indexCount = indices.length;
+ }
+ });
+};
+CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) {
+ var vertices = new Float32Array(2 * width * height * 5);
+ var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();
+ var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();
+ var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);
+ var vidx = 0;
+ for (var e = 0; e < 2; e++) {
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++, vidx++) {
+ var u = i / (width - 1);
+ var v = j / (height - 1);
+ var s = u;
+ var t = v;
+ var x = lerp(lensFrustum[0], lensFrustum[2], u);
+ var y = lerp(lensFrustum[3], lensFrustum[1], v);
+ var d = Math.sqrt(x * x + y * y);
+ var r = deviceInfo.distortion.distortInverse(d);
+ var p = x * r / d;
+ var q = y * r / d;
+ u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]);
+ v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]);
+ u = (viewport.x + u * viewport.width - 0.5) * 2.0;
+ v = (viewport.y + v * viewport.height - 0.5) * 2.0;
+ vertices[vidx * 5 + 0] = u;
+ vertices[vidx * 5 + 1] = v;
+ vertices[vidx * 5 + 2] = s;
+ vertices[vidx * 5 + 3] = t;
+ vertices[vidx * 5 + 4] = e;
+ }
+ }
+ var w = lensFrustum[2] - lensFrustum[0];
+ lensFrustum[0] = -(w + lensFrustum[0]);
+ lensFrustum[2] = w - lensFrustum[2];
+ w = noLensFrustum[2] - noLensFrustum[0];
+ noLensFrustum[0] = -(w + noLensFrustum[0]);
+ noLensFrustum[2] = w - noLensFrustum[2];
+ viewport.x = 1 - (viewport.x + viewport.width);
+ }
+ return vertices;
+};
+CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) {
+ var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6);
+ var halfwidth = width / 2;
+ var halfheight = height / 2;
+ var vidx = 0;
+ var iidx = 0;
+ for (var e = 0; e < 2; e++) {
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++, vidx++) {
+ if (i == 0 || j == 0) continue;
+ if (i <= halfwidth == j <= halfheight) {
+ indices[iidx++] = vidx;
+ indices[iidx++] = vidx - width - 1;
+ indices[iidx++] = vidx - width;
+ indices[iidx++] = vidx - width - 1;
+ indices[iidx++] = vidx;
+ indices[iidx++] = vidx - 1;
+ } else {
+ indices[iidx++] = vidx - 1;
+ indices[iidx++] = vidx - width;
+ indices[iidx++] = vidx;
+ indices[iidx++] = vidx - width;
+ indices[iidx++] = vidx - 1;
+ indices[iidx++] = vidx - width - 1;
+ }
+ }
+ }
+ }
+ return indices;
+};
+CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) {
+ var descriptor = Object.getOwnPropertyDescriptor(proto, attrName);
+ if (descriptor.get === undefined || descriptor.set === undefined) {
+ descriptor.configurable = true;
+ descriptor.enumerable = true;
+ descriptor.get = function () {
+ return this.getAttribute(attrName);
+ };
+ descriptor.set = function (val) {
+ this.setAttribute(attrName, val);
+ };
+ }
+ return descriptor;
+};
+var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n');
+var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n');
+var DEG2RAD = Math.PI / 180.0;
+var kAnglePerGearSection = 60;
+var kOuterRimEndAngle = 12;
+var kInnerRimBeginAngle = 20;
+var kOuterRadius = 1;
+var kMiddleRadius = 0.75;
+var kInnerRadius = 0.3125;
+var kCenterLineThicknessDp = 4;
+var kButtonWidthDp = 28;
+var kTouchSlopFactor = 1.5;
+function CardboardUI(gl) {
+ this.gl = gl;
+ this.attribs = {
+ position: 0
+ };
+ this.program = linkProgram(gl, uiVS, uiFS, this.attribs);
+ this.uniforms = getProgramUniforms(gl, this.program);
+ this.vertexBuffer = gl.createBuffer();
+ this.gearOffset = 0;
+ this.gearVertexCount = 0;
+ this.arrowOffset = 0;
+ this.arrowVertexCount = 0;
+ this.projMat = new Float32Array(16);
+ this.listener = null;
+ this.onResize();
+}
+CardboardUI.prototype.destroy = function () {
+ var gl = this.gl;
+ if (this.listener) {
+ gl.canvas.removeEventListener('click', this.listener, false);
+ }
+ gl.deleteProgram(this.program);
+ gl.deleteBuffer(this.vertexBuffer);
+};
+CardboardUI.prototype.listen = function (optionsCallback, backCallback) {
+ var canvas = this.gl.canvas;
+ this.listener = function (event) {
+ var midline = canvas.clientWidth / 2;
+ var buttonSize = kButtonWidthDp * kTouchSlopFactor;
+ if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) {
+ optionsCallback(event);
+ }
+ else if (event.clientX < buttonSize && event.clientY < buttonSize) {
+ backCallback(event);
+ }
+ };
+ canvas.addEventListener('click', this.listener, false);
+};
+CardboardUI.prototype.onResize = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.ARRAY_BUFFER_BINDING];
+ glPreserveState(gl, glState, function (gl) {
+ var vertices = [];
+ var midline = gl.drawingBufferWidth / 2;
+ var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;
+ var scalingRatio = gl.drawingBufferWidth / physicalPixels;
+ var dps = scalingRatio * window.devicePixelRatio;
+ var lineWidth = kCenterLineThicknessDp * dps / 2;
+ var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps;
+ var buttonScale = kButtonWidthDp * dps / 2;
+ var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps;
+ vertices.push(midline - lineWidth, buttonSize);
+ vertices.push(midline - lineWidth, gl.drawingBufferHeight);
+ vertices.push(midline + lineWidth, buttonSize);
+ vertices.push(midline + lineWidth, gl.drawingBufferHeight);
+ self.gearOffset = vertices.length / 2;
+ function addGearSegment(theta, r) {
+ var angle = (90 - theta) * DEG2RAD;
+ var x = Math.cos(angle);
+ var y = Math.sin(angle);
+ vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale);
+ vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale);
+ }
+ for (var i = 0; i <= 6; i++) {
+ var segmentTheta = i * kAnglePerGearSection;
+ addGearSegment(segmentTheta, kOuterRadius);
+ addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius);
+ addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius);
+ addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius);
+ addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius);
+ }
+ self.gearVertexCount = vertices.length / 2 - self.gearOffset;
+ self.arrowOffset = vertices.length / 2;
+ function addArrowVertex(x, y) {
+ vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);
+ }
+ var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);
+ addArrowVertex(0, buttonScale);
+ addArrowVertex(buttonScale, 0);
+ addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);
+ addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);
+ addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
+ addArrowVertex(0, buttonScale);
+ addArrowVertex(buttonScale, buttonScale * 2);
+ addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth);
+ addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
+ addArrowVertex(0, buttonScale);
+ addArrowVertex(angledLineWidth, buttonScale - lineWidth);
+ addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);
+ addArrowVertex(angledLineWidth, buttonScale + lineWidth);
+ addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);
+ self.arrowVertexCount = vertices.length / 2 - self.arrowOffset;
+ gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+ });
+};
+CardboardUI.prototype.render = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING];
+ glPreserveState(gl, glState, function (gl) {
+ gl.disable(gl.CULL_FACE);
+ gl.disable(gl.DEPTH_TEST);
+ gl.disable(gl.BLEND);
+ gl.disable(gl.SCISSOR_TEST);
+ gl.disable(gl.STENCIL_TEST);
+ gl.colorMask(true, true, true, true);
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ self.renderNoState();
+ });
+};
+CardboardUI.prototype.renderNoState = function () {
+ var gl = this.gl;
+ gl.useProgram(this.program);
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
+ gl.enableVertexAttribArray(this.attribs.position);
+ gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0);
+ gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);
+ orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);
+ gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount);
+ gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount);
+};
+function Distortion(coefficients) {
+ this.coefficients = coefficients;
+}
+Distortion.prototype.distortInverse = function (radius) {
+ var r0 = 0;
+ var r1 = 1;
+ var dr0 = radius - this.distort(r0);
+ while (Math.abs(r1 - r0) > 0.0001 ) {
+ var dr1 = radius - this.distort(r1);
+ var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));
+ r0 = r1;
+ r1 = r2;
+ dr0 = dr1;
+ }
+ return r1;
+};
+Distortion.prototype.distort = function (radius) {
+ var r2 = radius * radius;
+ var ret = 0;
+ for (var i = 0; i < this.coefficients.length; i++) {
+ ret = r2 * (ret + this.coefficients[i]);
+ }
+ return (ret + 1) * radius;
+};
+var degToRad = Math.PI / 180;
+var radToDeg = 180 / Math.PI;
+var Vector3 = function Vector3(x, y, z) {
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+};
+Vector3.prototype = {
+ constructor: Vector3,
+ set: function set(x, y, z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ },
+ copy: function copy(v) {
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+ return this;
+ },
+ length: function length() {
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
+ },
+ normalize: function normalize() {
+ var scalar = this.length();
+ if (scalar !== 0) {
+ var invScalar = 1 / scalar;
+ this.multiplyScalar(invScalar);
+ } else {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ }
+ return this;
+ },
+ multiplyScalar: function multiplyScalar(scalar) {
+ this.x *= scalar;
+ this.y *= scalar;
+ this.z *= scalar;
+ },
+ applyQuaternion: function applyQuaternion(q) {
+ var x = this.x;
+ var y = this.y;
+ var z = this.z;
+ var qx = q.x;
+ var qy = q.y;
+ var qz = q.z;
+ var qw = q.w;
+ var ix = qw * x + qy * z - qz * y;
+ var iy = qw * y + qz * x - qx * z;
+ var iz = qw * z + qx * y - qy * x;
+ var iw = -qx * x - qy * y - qz * z;
+ this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return this;
+ },
+ dot: function dot(v) {
+ return this.x * v.x + this.y * v.y + this.z * v.z;
+ },
+ crossVectors: function crossVectors(a, b) {
+ var ax = a.x,
+ ay = a.y,
+ az = a.z;
+ var bx = b.x,
+ by = b.y,
+ bz = b.z;
+ this.x = ay * bz - az * by;
+ this.y = az * bx - ax * bz;
+ this.z = ax * by - ay * bx;
+ return this;
+ }
+};
+var Quaternion = function Quaternion(x, y, z, w) {
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+ this.w = w !== undefined ? w : 1;
+};
+Quaternion.prototype = {
+ constructor: Quaternion,
+ set: function set(x, y, z, w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ },
+ copy: function copy(quaternion) {
+ this.x = quaternion.x;
+ this.y = quaternion.y;
+ this.z = quaternion.z;
+ this.w = quaternion.w;
+ return this;
+ },
+ setFromEulerXYZ: function setFromEulerXYZ(x, y, z) {
+ var c1 = Math.cos(x / 2);
+ var c2 = Math.cos(y / 2);
+ var c3 = Math.cos(z / 2);
+ var s1 = Math.sin(x / 2);
+ var s2 = Math.sin(y / 2);
+ var s3 = Math.sin(z / 2);
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
+ return this;
+ },
+ setFromEulerYXZ: function setFromEulerYXZ(x, y, z) {
+ var c1 = Math.cos(x / 2);
+ var c2 = Math.cos(y / 2);
+ var c3 = Math.cos(z / 2);
+ var s1 = Math.sin(x / 2);
+ var s2 = Math.sin(y / 2);
+ var s3 = Math.sin(z / 2);
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
+ return this;
+ },
+ setFromAxisAngle: function setFromAxisAngle(axis, angle) {
+ var halfAngle = angle / 2,
+ s = Math.sin(halfAngle);
+ this.x = axis.x * s;
+ this.y = axis.y * s;
+ this.z = axis.z * s;
+ this.w = Math.cos(halfAngle);
+ return this;
+ },
+ multiply: function multiply(q) {
+ return this.multiplyQuaternions(this, q);
+ },
+ multiplyQuaternions: function multiplyQuaternions(a, b) {
+ var qax = a.x,
+ qay = a.y,
+ qaz = a.z,
+ qaw = a.w;
+ var qbx = b.x,
+ qby = b.y,
+ qbz = b.z,
+ qbw = b.w;
+ this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
+ this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
+ this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
+ this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
+ return this;
+ },
+ inverse: function inverse() {
+ this.x *= -1;
+ this.y *= -1;
+ this.z *= -1;
+ this.normalize();
+ return this;
+ },
+ normalize: function normalize() {
+ var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
+ if (l === 0) {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 1;
+ } else {
+ l = 1 / l;
+ this.x = this.x * l;
+ this.y = this.y * l;
+ this.z = this.z * l;
+ this.w = this.w * l;
+ }
+ return this;
+ },
+ slerp: function slerp(qb, t) {
+ if (t === 0) return this;
+ if (t === 1) return this.copy(qb);
+ var x = this.x,
+ y = this.y,
+ z = this.z,
+ w = this.w;
+ var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
+ if (cosHalfTheta < 0) {
+ this.w = -qb.w;
+ this.x = -qb.x;
+ this.y = -qb.y;
+ this.z = -qb.z;
+ cosHalfTheta = -cosHalfTheta;
+ } else {
+ this.copy(qb);
+ }
+ if (cosHalfTheta >= 1.0) {
+ this.w = w;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+ var halfTheta = Math.acos(cosHalfTheta);
+ var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
+ if (Math.abs(sinHalfTheta) < 0.001) {
+ this.w = 0.5 * (w + this.w);
+ this.x = 0.5 * (x + this.x);
+ this.y = 0.5 * (y + this.y);
+ this.z = 0.5 * (z + this.z);
+ return this;
+ }
+ var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
+ ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
+ this.w = w * ratioA + this.w * ratioB;
+ this.x = x * ratioA + this.x * ratioB;
+ this.y = y * ratioA + this.y * ratioB;
+ this.z = z * ratioA + this.z * ratioB;
+ return this;
+ },
+ setFromUnitVectors: function () {
+ var v1, r;
+ var EPS = 0.000001;
+ return function (vFrom, vTo) {
+ if (v1 === undefined) v1 = new Vector3();
+ r = vFrom.dot(vTo) + 1;
+ if (r < EPS) {
+ r = 0;
+ if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
+ v1.set(-vFrom.y, vFrom.x, 0);
+ } else {
+ v1.set(0, -vFrom.z, vFrom.y);
+ }
+ } else {
+ v1.crossVectors(vFrom, vTo);
+ }
+ this.x = v1.x;
+ this.y = v1.y;
+ this.z = v1.z;
+ this.w = r;
+ this.normalize();
+ return this;
+ };
+ }()
+};
+function Device(params) {
+ this.width = params.width || getScreenWidth();
+ this.height = params.height || getScreenHeight();
+ this.widthMeters = params.widthMeters;
+ this.heightMeters = params.heightMeters;
+ this.bevelMeters = params.bevelMeters;
+}
+var DEFAULT_ANDROID = new Device({
+ widthMeters: 0.110,
+ heightMeters: 0.062,
+ bevelMeters: 0.004
+});
+var DEFAULT_IOS = new Device({
+ widthMeters: 0.1038,
+ heightMeters: 0.0584,
+ bevelMeters: 0.004
+});
+var Viewers = {
+ CardboardV1: new CardboardViewer({
+ id: 'CardboardV1',
+ label: 'Cardboard I/O 2014',
+ fov: 40,
+ interLensDistance: 0.060,
+ baselineLensDistance: 0.035,
+ screenLensDistance: 0.042,
+ distortionCoefficients: [0.441, 0.156],
+ inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834]
+ }),
+ CardboardV2: new CardboardViewer({
+ id: 'CardboardV2',
+ label: 'Cardboard I/O 2015',
+ fov: 60,
+ interLensDistance: 0.064,
+ baselineLensDistance: 0.035,
+ screenLensDistance: 0.039,
+ distortionCoefficients: [0.34, 0.55],
+ inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6]
+ })
+};
+function DeviceInfo(deviceParams, additionalViewers) {
+ this.viewer = Viewers.CardboardV2;
+ this.updateDeviceParams(deviceParams);
+ this.distortion = new Distortion(this.viewer.distortionCoefficients);
+ for (var i = 0; i < additionalViewers.length; i++) {
+ var viewer = additionalViewers[i];
+ Viewers[viewer.id] = new CardboardViewer(viewer);
+ }
+}
+DeviceInfo.prototype.updateDeviceParams = function (deviceParams) {
+ this.device = this.determineDevice_(deviceParams) || this.device;
+};
+DeviceInfo.prototype.getDevice = function () {
+ return this.device;
+};
+DeviceInfo.prototype.setViewer = function (viewer) {
+ this.viewer = viewer;
+ this.distortion = new Distortion(this.viewer.distortionCoefficients);
+};
+DeviceInfo.prototype.determineDevice_ = function (deviceParams) {
+ if (!deviceParams) {
+ if (isIOS()) {
+ console.warn('Using fallback iOS device measurements.');
+ return DEFAULT_IOS;
+ } else {
+ console.warn('Using fallback Android device measurements.');
+ return DEFAULT_ANDROID;
+ }
+ }
+ var METERS_PER_INCH = 0.0254;
+ var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi;
+ var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi;
+ var width = getScreenWidth();
+ var height = getScreenHeight();
+ return new Device({
+ widthMeters: metersPerPixelX * width,
+ heightMeters: metersPerPixelY * height,
+ bevelMeters: deviceParams.bevelMm * 0.001
+ });
+};
+DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var eyeToScreenDistance = viewer.screenLensDistance;
+ var outerDist = (device.widthMeters - viewer.interLensDistance) / 2;
+ var innerDist = viewer.interLensDistance / 2;
+ var bottomDist = viewer.baselineLensDistance - device.bevelMeters;
+ var topDist = device.heightMeters - bottomDist;
+ var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance));
+ var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance));
+ var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance));
+ var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance));
+ return {
+ leftDegrees: Math.min(outerAngle, viewer.fov),
+ rightDegrees: Math.min(innerAngle, viewer.fov),
+ downDegrees: Math.min(bottomAngle, viewer.fov),
+ upDegrees: Math.min(topAngle, viewer.fov)
+ };
+};
+DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var fovLeft = Math.tan(-degToRad * viewer.fov);
+ var fovTop = Math.tan(degToRad * viewer.fov);
+ var fovRight = Math.tan(degToRad * viewer.fov);
+ var fovBottom = Math.tan(-degToRad * viewer.fov);
+ var halfWidth = device.widthMeters / 4;
+ var halfHeight = device.heightMeters / 2;
+ var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
+ var centerX = viewer.interLensDistance / 2 - halfWidth;
+ var centerY = -verticalLensOffset;
+ var centerZ = viewer.screenLensDistance;
+ var screenLeft = distortion.distort((centerX - halfWidth) / centerZ);
+ var screenTop = distortion.distort((centerY + halfHeight) / centerZ);
+ var screenRight = distortion.distort((centerX + halfWidth) / centerZ);
+ var screenBottom = distortion.distort((centerY - halfHeight) / centerZ);
+ var result = new Float32Array(4);
+ result[0] = Math.max(fovLeft, screenLeft);
+ result[1] = Math.min(fovTop, screenTop);
+ result[2] = Math.min(fovRight, screenRight);
+ result[3] = Math.max(fovBottom, screenBottom);
+ return result;
+};
+DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var result = new Float32Array(4);
+ var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
+ var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
+ var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
+ var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
+ var halfWidth = device.widthMeters / 4;
+ var halfHeight = device.heightMeters / 2;
+ var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
+ var centerX = viewer.interLensDistance / 2 - halfWidth;
+ var centerY = -verticalLensOffset;
+ var centerZ = viewer.screenLensDistance;
+ var screenLeft = (centerX - halfWidth) / centerZ;
+ var screenTop = (centerY + halfHeight) / centerZ;
+ var screenRight = (centerX + halfWidth) / centerZ;
+ var screenBottom = (centerY - halfHeight) / centerZ;
+ result[0] = Math.max(fovLeft, screenLeft);
+ result[1] = Math.min(fovTop, screenTop);
+ result[2] = Math.min(fovRight, screenRight);
+ result[3] = Math.max(fovBottom, screenBottom);
+ return result;
+};
+DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) {
+ var viewer = this.viewer;
+ var device = this.device;
+ var dist = viewer.screenLensDistance;
+ var eyeX = (device.widthMeters - viewer.interLensDistance) / 2;
+ var eyeY = viewer.baselineLensDistance - device.bevelMeters;
+ var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters;
+ var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters;
+ var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters;
+ var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters;
+ return {
+ x: left,
+ y: bottom,
+ width: right - left,
+ height: top - bottom
+ };
+};
+DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) {
+ return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye();
+};
+DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) {
+ var fov = this.getFieldOfViewLeftEye(opt_isUndistorted);
+ return {
+ leftDegrees: fov.rightDegrees,
+ rightDegrees: fov.leftDegrees,
+ upDegrees: fov.upDegrees,
+ downDegrees: fov.downDegrees
+ };
+};
+DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () {
+ var p = this.getUndistortedParams_();
+ return {
+ leftDegrees: radToDeg * Math.atan(p.outerDist),
+ rightDegrees: radToDeg * Math.atan(p.innerDist),
+ downDegrees: radToDeg * Math.atan(p.bottomDist),
+ upDegrees: radToDeg * Math.atan(p.topDist)
+ };
+};
+DeviceInfo.prototype.getUndistortedViewportLeftEye = function () {
+ var p = this.getUndistortedParams_();
+ var viewer = this.viewer;
+ var device = this.device;
+ var eyeToScreenDistance = viewer.screenLensDistance;
+ var screenWidth = device.widthMeters / eyeToScreenDistance;
+ var screenHeight = device.heightMeters / eyeToScreenDistance;
+ var xPxPerTanAngle = device.width / screenWidth;
+ var yPxPerTanAngle = device.height / screenHeight;
+ var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle);
+ var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle);
+ return {
+ x: x,
+ y: y,
+ width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x,
+ height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y
+ };
+};
+DeviceInfo.prototype.getUndistortedParams_ = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var eyeToScreenDistance = viewer.screenLensDistance;
+ var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance;
+ var screenWidth = device.widthMeters / eyeToScreenDistance;
+ var screenHeight = device.heightMeters / eyeToScreenDistance;
+ var eyePosX = screenWidth / 2 - halfLensDistance;
+ var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance;
+ var maxFov = viewer.fov;
+ var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov));
+ var outerDist = Math.min(eyePosX, viewerMax);
+ var innerDist = Math.min(halfLensDistance, viewerMax);
+ var bottomDist = Math.min(eyePosY, viewerMax);
+ var topDist = Math.min(screenHeight - eyePosY, viewerMax);
+ return {
+ outerDist: outerDist,
+ innerDist: innerDist,
+ topDist: topDist,
+ bottomDist: bottomDist,
+ eyePosX: eyePosX,
+ eyePosY: eyePosY
+ };
+};
+function CardboardViewer(params) {
+ this.id = params.id;
+ this.label = params.label;
+ this.fov = params.fov;
+ this.interLensDistance = params.interLensDistance;
+ this.baselineLensDistance = params.baselineLensDistance;
+ this.screenLensDistance = params.screenLensDistance;
+ this.distortionCoefficients = params.distortionCoefficients;
+ this.inverseCoefficients = params.inverseCoefficients;
+}
+DeviceInfo.Viewers = Viewers;
+var format = 1;
+var last_updated = "2018-12-10T17:01:42Z";
+var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}];
+var DPDB_CACHE = {
+ format: format,
+ last_updated: last_updated,
+ devices: devices
+};
+function Dpdb(url, onDeviceParamsUpdated) {
+ this.dpdb = DPDB_CACHE;
+ this.recalculateDeviceParams_();
+ if (url) {
+ this.onDeviceParamsUpdated = onDeviceParamsUpdated;
+ var xhr = new XMLHttpRequest();
+ var obj = this;
+ xhr.open('GET', url, true);
+ xhr.addEventListener('load', function () {
+ obj.loading = false;
+ if (xhr.status >= 200 && xhr.status <= 299) {
+ obj.dpdb = JSON.parse(xhr.response);
+ obj.recalculateDeviceParams_();
+ } else {
+ console.error('Error loading online DPDB!');
+ }
+ });
+ xhr.send();
+ }
+}
+Dpdb.prototype.getDeviceParams = function () {
+ return this.deviceParams;
+};
+Dpdb.prototype.recalculateDeviceParams_ = function () {
+ var newDeviceParams = this.calcDeviceParams_();
+ if (newDeviceParams) {
+ this.deviceParams = newDeviceParams;
+ if (this.onDeviceParamsUpdated) {
+ this.onDeviceParamsUpdated(this.deviceParams);
+ }
+ } else {
+ console.error('Failed to recalculate device parameters.');
+ }
+};
+Dpdb.prototype.calcDeviceParams_ = function () {
+ var db = this.dpdb;
+ if (!db) {
+ console.error('DPDB not available.');
+ return null;
+ }
+ if (db.format != 1) {
+ console.error('DPDB has unexpected format version.');
+ return null;
+ }
+ if (!db.devices || !db.devices.length) {
+ console.error('DPDB does not have a devices section.');
+ return null;
+ }
+ var userAgent = navigator.userAgent || navigator.vendor || window.opera;
+ var width = getScreenWidth();
+ var height = getScreenHeight();
+ if (!db.devices) {
+ console.error('DPDB has no devices section.');
+ return null;
+ }
+ for (var i = 0; i < db.devices.length; i++) {
+ var device = db.devices[i];
+ if (!device.rules) {
+ console.warn('Device[' + i + '] has no rules section.');
+ continue;
+ }
+ if (device.type != 'ios' && device.type != 'android') {
+ console.warn('Device[' + i + '] has invalid type.');
+ continue;
+ }
+ if (isIOS() != (device.type == 'ios')) continue;
+ var matched = false;
+ for (var j = 0; j < device.rules.length; j++) {
+ var rule = device.rules[j];
+ if (this.ruleMatches_(rule, userAgent, width, height)) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) continue;
+ var xdpi = device.dpi[0] || device.dpi;
+ var ydpi = device.dpi[1] || device.dpi;
+ return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw });
+ }
+ console.warn('No DPDB device match.');
+ return null;
+};
+Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) {
+ if (!rule.ua && !rule.res) return false;
+ if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7);
+ if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
+ if (rule.res) {
+ if (!rule.res[0] || !rule.res[1]) return false;
+ var resX = rule.res[0];
+ var resY = rule.res[1];
+ if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) {
+ return false;
+ }
+ }
+ return true;
+};
+function DeviceParams(params) {
+ this.xdpi = params.xdpi;
+ this.ydpi = params.ydpi;
+ this.bevelMm = params.bevelMm;
+}
+function SensorSample(sample, timestampS) {
+ this.set(sample, timestampS);
+}
+SensorSample.prototype.set = function (sample, timestampS) {
+ this.sample = sample;
+ this.timestampS = timestampS;
+};
+SensorSample.prototype.copy = function (sensorSample) {
+ this.set(sensorSample.sample, sensorSample.timestampS);
+};
+function ComplementaryFilter(kFilter, isDebug) {
+ this.kFilter = kFilter;
+ this.isDebug = isDebug;
+ this.currentAccelMeasurement = new SensorSample();
+ this.currentGyroMeasurement = new SensorSample();
+ this.previousGyroMeasurement = new SensorSample();
+ if (isIOS()) {
+ this.filterQ = new Quaternion(-1, 0, 0, 1);
+ } else {
+ this.filterQ = new Quaternion(1, 0, 0, 1);
+ }
+ this.previousFilterQ = new Quaternion();
+ this.previousFilterQ.copy(this.filterQ);
+ this.accelQ = new Quaternion();
+ this.isOrientationInitialized = false;
+ this.estimatedGravity = new Vector3();
+ this.measuredGravity = new Vector3();
+ this.gyroIntegralQ = new Quaternion();
+}
+ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) {
+ this.currentAccelMeasurement.set(vector, timestampS);
+};
+ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) {
+ this.currentGyroMeasurement.set(vector, timestampS);
+ var deltaT = timestampS - this.previousGyroMeasurement.timestampS;
+ if (isTimestampDeltaValid(deltaT)) {
+ this.run_();
+ }
+ this.previousGyroMeasurement.copy(this.currentGyroMeasurement);
+};
+ComplementaryFilter.prototype.run_ = function () {
+ if (!this.isOrientationInitialized) {
+ this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample);
+ this.previousFilterQ.copy(this.accelQ);
+ this.isOrientationInitialized = true;
+ return;
+ }
+ var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS;
+ var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);
+ this.gyroIntegralQ.multiply(gyroDeltaQ);
+ this.filterQ.copy(this.previousFilterQ);
+ this.filterQ.multiply(gyroDeltaQ);
+ var invFilterQ = new Quaternion();
+ invFilterQ.copy(this.filterQ);
+ invFilterQ.inverse();
+ this.estimatedGravity.set(0, 0, -1);
+ this.estimatedGravity.applyQuaternion(invFilterQ);
+ this.estimatedGravity.normalize();
+ this.measuredGravity.copy(this.currentAccelMeasurement.sample);
+ this.measuredGravity.normalize();
+ var deltaQ = new Quaternion();
+ deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);
+ deltaQ.inverse();
+ if (this.isDebug) {
+ console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1));
+ }
+ var targetQ = new Quaternion();
+ targetQ.copy(this.filterQ);
+ targetQ.multiply(deltaQ);
+ this.filterQ.slerp(targetQ, 1 - this.kFilter);
+ this.previousFilterQ.copy(this.filterQ);
+};
+ComplementaryFilter.prototype.getOrientation = function () {
+ return this.filterQ;
+};
+ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) {
+ var normAccel = new Vector3();
+ normAccel.copy(accel);
+ normAccel.normalize();
+ var quat = new Quaternion();
+ quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel);
+ quat.inverse();
+ return quat;
+};
+ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) {
+ var quat = new Quaternion();
+ var axis = new Vector3();
+ axis.copy(gyro);
+ axis.normalize();
+ quat.setFromAxisAngle(axis, gyro.length() * dt);
+ return quat;
+};
+function PosePredictor(predictionTimeS, isDebug) {
+ this.predictionTimeS = predictionTimeS;
+ this.isDebug = isDebug;
+ this.previousQ = new Quaternion();
+ this.previousTimestampS = null;
+ this.deltaQ = new Quaternion();
+ this.outQ = new Quaternion();
+}
+PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) {
+ if (!this.previousTimestampS) {
+ this.previousQ.copy(currentQ);
+ this.previousTimestampS = timestampS;
+ return currentQ;
+ }
+ var axis = new Vector3();
+ axis.copy(gyro);
+ axis.normalize();
+ var angularSpeed = gyro.length();
+ if (angularSpeed < degToRad * 20) {
+ if (this.isDebug) {
+ console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1));
+ }
+ this.outQ.copy(currentQ);
+ this.previousQ.copy(currentQ);
+ return this.outQ;
+ }
+ var predictAngle = angularSpeed * this.predictionTimeS;
+ this.deltaQ.setFromAxisAngle(axis, predictAngle);
+ this.outQ.copy(this.previousQ);
+ this.outQ.multiply(this.deltaQ);
+ this.previousQ.copy(currentQ);
+ this.previousTimestampS = timestampS;
+ return this.outQ;
+};
+function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) {
+ this.yawOnly = yawOnly;
+ this.accelerometer = new Vector3();
+ this.gyroscope = new Vector3();
+ this.filter = new ComplementaryFilter(kFilter, isDebug);
+ this.posePredictor = new PosePredictor(predictionTime, isDebug);
+ this.isFirefoxAndroid = isFirefoxAndroid();
+ this.isIOS = isIOS();
+ var chromeVersion = getChromeVersion();
+ this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66;
+ this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion();
+ this.filterToWorldQ = new Quaternion();
+ if (isIOS()) {
+ this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);
+ } else {
+ this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
+ }
+ this.inverseWorldToScreenQ = new Quaternion();
+ this.worldToScreenQ = new Quaternion();
+ this.originalPoseAdjustQ = new Quaternion();
+ this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180);
+ this.setScreenTransform_();
+ if (isLandscapeMode()) {
+ this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);
+ }
+ this.resetQ = new Quaternion();
+ this.orientationOut_ = new Float32Array(4);
+ this.start();
+}
+FusionPoseSensor.prototype.getPosition = function () {
+ return null;
+};
+FusionPoseSensor.prototype.getOrientation = function () {
+ var orientation = void 0;
+ if (this.isWithoutDeviceMotion && this._deviceOrientationQ) {
+ this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () {
+ var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0);
+ var y = new Quaternion();
+ if (window.orientation === -90) {
+ y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2);
+ } else {
+ y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2);
+ }
+ return z.multiply(y);
+ }();
+ this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () {
+ var q = new Quaternion();
+ q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
+ return q;
+ }();
+ orientation = this._deviceOrientationQ;
+ var out = new Quaternion();
+ out.copy(orientation);
+ out.multiply(this.deviceOrientationFilterToWorldQ);
+ out.multiply(this.resetQ);
+ out.multiply(this.worldToScreenQ);
+ out.multiplyQuaternions(this.deviceOrientationFixQ, out);
+ if (this.yawOnly) {
+ out.x = 0;
+ out.z = 0;
+ out.normalize();
+ }
+ this.orientationOut_[0] = out.x;
+ this.orientationOut_[1] = out.y;
+ this.orientationOut_[2] = out.z;
+ this.orientationOut_[3] = out.w;
+ return this.orientationOut_;
+ } else {
+ var filterOrientation = this.filter.getOrientation();
+ orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS);
+ }
+ var out = new Quaternion();
+ out.copy(this.filterToWorldQ);
+ out.multiply(this.resetQ);
+ out.multiply(orientation);
+ out.multiply(this.worldToScreenQ);
+ if (this.yawOnly) {
+ out.x = 0;
+ out.z = 0;
+ out.normalize();
+ }
+ this.orientationOut_[0] = out.x;
+ this.orientationOut_[1] = out.y;
+ this.orientationOut_[2] = out.z;
+ this.orientationOut_[3] = out.w;
+ return this.orientationOut_;
+};
+FusionPoseSensor.prototype.resetPose = function () {
+ this.resetQ.copy(this.filter.getOrientation());
+ this.resetQ.x = 0;
+ this.resetQ.y = 0;
+ this.resetQ.z *= -1;
+ this.resetQ.normalize();
+ if (isLandscapeMode()) {
+ this.resetQ.multiply(this.inverseWorldToScreenQ);
+ }
+ this.resetQ.multiply(this.originalPoseAdjustQ);
+};
+FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) {
+ this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion();
+ var alpha = e.alpha,
+ beta = e.beta,
+ gamma = e.gamma;
+ alpha = (alpha || 0) * Math.PI / 180;
+ beta = (beta || 0) * Math.PI / 180;
+ gamma = (gamma || 0) * Math.PI / 180;
+ this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma);
+};
+FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) {
+ this.updateDeviceMotion_(deviceMotion);
+};
+FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) {
+ var accGravity = deviceMotion.accelerationIncludingGravity;
+ var rotRate = deviceMotion.rotationRate;
+ var timestampS = deviceMotion.timeStamp / 1000;
+ var deltaS = timestampS - this.previousTimestampS;
+ if (deltaS < 0) {
+ warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion');
+ this.previousTimestampS = timestampS;
+ return;
+ } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) {
+ warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.');
+ this.previousTimestampS = timestampS;
+ return;
+ }
+ this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
+ if (isR7()) {
+ this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma);
+ } else {
+ this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);
+ }
+ if (!this.isDeviceMotionInRadians) {
+ this.gyroscope.multiplyScalar(Math.PI / 180);
+ }
+ this.filter.addAccelMeasurement(this.accelerometer, timestampS);
+ this.filter.addGyroMeasurement(this.gyroscope, timestampS);
+ this.previousTimestampS = timestampS;
+};
+FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) {
+ this.setScreenTransform_();
+};
+FusionPoseSensor.prototype.onMessage_ = function (event) {
+ var message = event.data;
+ if (!message || !message.type) {
+ return;
+ }
+ var type = message.type.toLowerCase();
+ if (type !== 'devicemotion') {
+ return;
+ }
+ this.updateDeviceMotion_(message.deviceMotionEvent);
+};
+FusionPoseSensor.prototype.setScreenTransform_ = function () {
+ this.worldToScreenQ.set(0, 0, 0, 1);
+ switch (window.orientation) {
+ case 0:
+ break;
+ case 90:
+ this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2);
+ break;
+ case -90:
+ this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2);
+ break;
+ case 180:
+ break;
+ }
+ this.inverseWorldToScreenQ.copy(this.worldToScreenQ);
+ this.inverseWorldToScreenQ.inverse();
+};
+FusionPoseSensor.prototype.start = function () {
+ this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this);
+ this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this);
+ this.onMessageCallback_ = this.onMessage_.bind(this);
+ this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this);
+ if (isIOS() && isInsideCrossOriginIFrame()) {
+ window.addEventListener('message', this.onMessageCallback_);
+ }
+ window.addEventListener('orientationchange', this.onOrientationChangeCallback_);
+ if (this.isWithoutDeviceMotion) {
+ window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_);
+ } else {
+ window.addEventListener('devicemotion', this.onDeviceMotionCallback_);
+ }
+};
+FusionPoseSensor.prototype.stop = function () {
+ window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);
+ window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_);
+ window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);
+ window.removeEventListener('message', this.onMessageCallback_);
+};
+var SENSOR_FREQUENCY = 60;
+var X_AXIS = new Vector3(1, 0, 0);
+var Z_AXIS = new Vector3(0, 0, 1);
+var SENSOR_TO_VR = new Quaternion();
+SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2);
+SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2));
+var PoseSensor = function () {
+ function PoseSensor(config) {
+ classCallCheck(this, PoseSensor);
+ this.config = config;
+ this.sensor = null;
+ this.fusionSensor = null;
+ this._out = new Float32Array(4);
+ this.api = null;
+ this.errors = [];
+ this._sensorQ = new Quaternion();
+ this._outQ = new Quaternion();
+ this._onSensorRead = this._onSensorRead.bind(this);
+ this._onSensorError = this._onSensorError.bind(this);
+ this.init();
+ }
+ createClass(PoseSensor, [{
+ key: 'init',
+ value: function init() {
+ var sensor = null;
+ try {
+ sensor = new RelativeOrientationSensor({
+ frequency: SENSOR_FREQUENCY,
+ referenceFrame: 'screen'
+ });
+ sensor.addEventListener('error', this._onSensorError);
+ } catch (error) {
+ this.errors.push(error);
+ if (error.name === 'SecurityError') {
+ console.error('Cannot construct sensors due to the Feature Policy');
+ console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.');
+ this.useDeviceMotion();
+ } else if (error.name === 'ReferenceError') {
+ this.useDeviceMotion();
+ } else {
+ console.error(error);
+ }
+ }
+ if (sensor) {
+ this.api = 'sensor';
+ this.sensor = sensor;
+ this.sensor.addEventListener('reading', this._onSensorRead);
+ this.sensor.start();
+ }
+ }
+ }, {
+ key: 'useDeviceMotion',
+ value: function useDeviceMotion() {
+ this.api = 'devicemotion';
+ this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG);
+ if (this.sensor) {
+ this.sensor.removeEventListener('reading', this._onSensorRead);
+ this.sensor.removeEventListener('error', this._onSensorError);
+ this.sensor = null;
+ }
+ }
+ }, {
+ key: 'getOrientation',
+ value: function getOrientation() {
+ if (this.fusionSensor) {
+ return this.fusionSensor.getOrientation();
+ }
+ if (!this.sensor || !this.sensor.quaternion) {
+ this._out[0] = this._out[1] = this._out[2] = 0;
+ this._out[3] = 1;
+ return this._out;
+ }
+ var q = this.sensor.quaternion;
+ this._sensorQ.set(q[0], q[1], q[2], q[3]);
+ var out = this._outQ;
+ out.copy(SENSOR_TO_VR);
+ out.multiply(this._sensorQ);
+ if (this.config.YAW_ONLY) {
+ out.x = out.z = 0;
+ out.normalize();
+ }
+ this._out[0] = out.x;
+ this._out[1] = out.y;
+ this._out[2] = out.z;
+ this._out[3] = out.w;
+ return this._out;
+ }
+ }, {
+ key: '_onSensorError',
+ value: function _onSensorError(event) {
+ this.errors.push(event.error);
+ if (event.error.name === 'NotAllowedError') {
+ console.error('Permission to access sensor was denied');
+ } else if (event.error.name === 'NotReadableError') {
+ console.error('Sensor could not be read');
+ } else {
+ console.error(event.error);
+ }
+ this.useDeviceMotion();
+ }
+ }, {
+ key: '_onSensorRead',
+ value: function _onSensorRead() {}
+ }]);
+ return PoseSensor;
+}();
+var rotateInstructionsAsset = "<svg width='198' height='240' viewBox='0 0 198 240' xmlns='http://www.w3.org/2000/svg'><g fill='none' fill-rule='evenodd'><path d='M149.625 109.527l6.737 3.891v.886c0 .177.013.36.038.549.01.081.02.162.027.242.14 1.415.974 2.998 2.105 3.999l5.72 5.062.081-.09s4.382-2.53 5.235-3.024l25.97 14.993v54.001c0 .771-.386 1.217-.948 1.217-.233 0-.495-.076-.772-.236l-23.967-13.838-.014.024-27.322 15.775-.85-1.323c-4.731-1.529-9.748-2.74-14.951-3.61a.27.27 0 0 0-.007.024l-5.067 16.961-7.891 4.556-.037-.063v27.59c0 .772-.386 1.217-.948 1.217-.232 0-.495-.076-.772-.236l-42.473-24.522c-.95-.549-1.72-1.877-1.72-2.967v-1.035l-.021.047a5.111 5.111 0 0 0-1.816-.399 5.682 5.682 0 0 0-.546.001 13.724 13.724 0 0 1-1.918-.041c-1.655-.153-3.2-.6-4.404-1.296l-46.576-26.89.005.012-10.278-18.75c-1.001-1.827-.241-4.216 1.698-5.336l56.011-32.345a4.194 4.194 0 0 1 2.099-.572c1.326 0 2.572.659 3.227 1.853l.005-.003.227.413-.006.004a9.63 9.63 0 0 0 1.477 2.018l.277.27c1.914 1.85 4.468 2.801 7.113 2.801 1.949 0 3.948-.517 5.775-1.572.013 0 7.319-4.219 7.319-4.219a4.194 4.194 0 0 1 2.099-.572c1.326 0 2.572.658 3.226 1.853l3.25 5.928.022-.018 6.785 3.917-.105-.182 46.881-26.965m0-1.635c-.282 0-.563.073-.815.218l-46.169 26.556-5.41-3.124-3.005-5.481c-.913-1.667-2.699-2.702-4.66-2.703-1.011 0-2.02.274-2.917.792a3825 3825 0 0 1-7.275 4.195l-.044.024a9.937 9.937 0 0 1-4.957 1.353c-2.292 0-4.414-.832-5.976-2.342l-.252-.245a7.992 7.992 0 0 1-1.139-1.534 1.379 1.379 0 0 0-.06-.122l-.227-.414a1.718 1.718 0 0 0-.095-.154c-.938-1.574-2.673-2.545-4.571-2.545-1.011 0-2.02.274-2.917.792L3.125 155.502c-2.699 1.559-3.738 4.94-2.314 7.538l10.278 18.75c.177.323.448.563.761.704l46.426 26.804c1.403.81 3.157 1.332 5.072 1.508a15.661 15.661 0 0 0 2.146.046 4.766 4.766 0 0 1 .396 0c.096.004.19.011.283.022.109 1.593 1.159 3.323 2.529 4.114l42.472 24.522c.524.302 1.058.455 1.59.455 1.497 0 2.583-1.2 2.583-2.852v-26.562l7.111-4.105a1.64 1.64 0 0 0 .749-.948l4.658-15.593c4.414.797 8.692 1.848 12.742 3.128l.533.829a1.634 1.634 0 0 0 2.193.531l26.532-15.317L193 192.433c.523.302 1.058.455 1.59.455 1.497 0 2.583-1.199 2.583-2.852v-54.001c0-.584-.312-1.124-.818-1.416l-25.97-14.993a1.633 1.633 0 0 0-1.636.001c-.606.351-2.993 1.73-4.325 2.498l-4.809-4.255c-.819-.725-1.461-1.933-1.561-2.936a7.776 7.776 0 0 0-.033-.294 2.487 2.487 0 0 1-.023-.336v-.886c0-.584-.312-1.123-.817-1.416l-6.739-3.891a1.633 1.633 0 0 0-.817-.219' fill='#455A64'/><path d='M96.027 132.636l46.576 26.891c1.204.695 1.979 1.587 2.242 2.541l-.01.007-81.374 46.982h-.001c-1.654-.152-3.199-.6-4.403-1.295l-46.576-26.891 83.546-48.235' fill='#FAFAFA'/><path d='M63.461 209.174c-.008 0-.015 0-.022-.002-1.693-.156-3.228-.609-4.441-1.309l-46.576-26.89a.118.118 0 0 1 0-.203l83.546-48.235a.117.117 0 0 1 .117 0l46.576 26.891c1.227.708 2.021 1.612 2.296 2.611a.116.116 0 0 1-.042.124l-.021.016-81.375 46.981a.11.11 0 0 1-.058.016zm-50.747-28.303l46.401 26.79c1.178.68 2.671 1.121 4.32 1.276l81.272-46.922c-.279-.907-1.025-1.73-2.163-2.387l-46.517-26.857-83.313 48.1z' fill='#607D8B'/><path d='M148.327 165.471a5.85 5.85 0 0 1-.546.001c-1.894-.083-3.302-1.038-3.145-2.132a2.693 2.693 0 0 0-.072-1.105l-81.103 46.822c.628.058 1.272.073 1.918.042.182-.009.364-.009.546-.001 1.894.083 3.302 1.038 3.145 2.132l79.257-45.759' fill='#FFF'/><path d='M69.07 211.347a.118.118 0 0 1-.115-.134c.045-.317-.057-.637-.297-.925-.505-.61-1.555-1.022-2.738-1.074a5.966 5.966 0 0 0-.535.001 14.03 14.03 0 0 1-1.935-.041.117.117 0 0 1-.103-.092.116.116 0 0 1 .055-.126l81.104-46.822a.117.117 0 0 1 .171.07c.104.381.129.768.074 1.153-.045.316.057.637.296.925.506.61 1.555 1.021 2.739 1.073.178.008.357.008.535-.001a.117.117 0 0 1 .064.218l-79.256 45.759a.114.114 0 0 1-.059.016zm-3.405-2.372c.089 0 .177.002.265.006 1.266.056 2.353.488 2.908 1.158.227.274.35.575.36.882l78.685-45.429c-.036 0-.072-.001-.107-.003-1.267-.056-2.354-.489-2.909-1.158-.282-.34-.402-.724-.347-1.107a2.604 2.604 0 0 0-.032-.91L63.846 208.97a13.91 13.91 0 0 0 1.528.012c.097-.005.194-.007.291-.007z' fill='#607D8B'/><path d='M2.208 162.134c-1.001-1.827-.241-4.217 1.698-5.337l56.011-32.344c1.939-1.12 4.324-.546 5.326 1.281l.232.41a9.344 9.344 0 0 0 1.47 2.021l.278.27c3.325 3.214 8.583 3.716 12.888 1.23l7.319-4.22c1.94-1.119 4.324-.546 5.325 1.282l3.25 5.928-83.519 48.229-10.278-18.75z' fill='#FAFAFA'/><path d='M12.486 181.001a.112.112 0 0 1-.031-.005.114.114 0 0 1-.071-.056L2.106 162.19c-1.031-1.88-.249-4.345 1.742-5.494l56.01-32.344a4.328 4.328 0 0 1 2.158-.588c1.415 0 2.65.702 3.311 1.882.01.008.018.017.024.028l.227.414a.122.122 0 0 1 .013.038 9.508 9.508 0 0 0 1.439 1.959l.275.266c1.846 1.786 4.344 2.769 7.031 2.769 1.977 0 3.954-.538 5.717-1.557a.148.148 0 0 1 .035-.013l7.284-4.206a4.321 4.321 0 0 1 2.157-.588c1.427 0 2.672.716 3.329 1.914l3.249 5.929a.116.116 0 0 1-.044.157l-83.518 48.229a.116.116 0 0 1-.059.016zm49.53-57.004c-.704 0-1.41.193-2.041.557l-56.01 32.345c-1.882 1.086-2.624 3.409-1.655 5.179l10.221 18.645 83.317-48.112-3.195-5.829c-.615-1.122-1.783-1.792-3.124-1.792a4.08 4.08 0 0 0-2.04.557l-7.317 4.225a.148.148 0 0 1-.035.013 11.7 11.7 0 0 1-5.801 1.569c-2.748 0-5.303-1.007-7.194-2.835l-.278-.27a9.716 9.716 0 0 1-1.497-2.046.096.096 0 0 1-.013-.037l-.191-.347a.11.11 0 0 1-.023-.029c-.615-1.123-1.783-1.793-3.124-1.793z' fill='#607D8B'/><path d='M42.434 155.808c-2.51-.001-4.697-1.258-5.852-3.365-1.811-3.304-.438-7.634 3.059-9.654l12.291-7.098a7.599 7.599 0 0 1 3.789-1.033c2.51 0 4.697 1.258 5.852 3.365 1.811 3.304.439 7.634-3.059 9.654l-12.291 7.098a7.606 7.606 0 0 1-3.789 1.033zm13.287-20.683a7.128 7.128 0 0 0-3.555.971l-12.291 7.098c-3.279 1.893-4.573 5.942-2.883 9.024 1.071 1.955 3.106 3.122 5.442 3.122a7.13 7.13 0 0 0 3.556-.97l12.291-7.098c3.279-1.893 4.572-5.942 2.883-9.024-1.072-1.955-3.106-3.123-5.443-3.123z' fill='#607D8B'/><path d='M149.588 109.407l6.737 3.89v.887c0 .176.013.36.037.549.011.081.02.161.028.242.14 1.415.973 2.998 2.105 3.999l7.396 6.545c.177.156.358.295.541.415 1.579 1.04 2.95.466 3.062-1.282.049-.784.057-1.595.023-2.429l-.003-.16v-1.151l25.987 15.003v54c0 1.09-.77 1.53-1.72.982l-42.473-24.523c-.95-.548-1.72-1.877-1.72-2.966v-34.033' fill='#FAFAFA'/><path d='M194.553 191.25c-.257 0-.54-.085-.831-.253l-42.472-24.521c-.981-.567-1.779-1.943-1.779-3.068v-34.033h.234v34.033c0 1.051.745 2.336 1.661 2.866l42.473 24.521c.424.245.816.288 1.103.122.285-.164.442-.52.442-1.002v-53.933l-25.753-14.868.003 1.106c.034.832.026 1.654-.024 2.439-.054.844-.396 1.464-.963 1.746-.619.309-1.45.173-2.28-.373a5.023 5.023 0 0 1-.553-.426l-7.397-6.544c-1.158-1.026-1.999-2.625-2.143-4.076a9.624 9.624 0 0 0-.027-.238 4.241 4.241 0 0 1-.038-.564v-.82l-6.68-3.856.117-.202 6.738 3.89.058.034v.954c0 .171.012.351.036.533.011.083.021.165.029.246.138 1.395.948 2.935 2.065 3.923l7.397 6.545c.173.153.35.289.527.406.758.499 1.504.63 2.047.359.49-.243.786-.795.834-1.551.05-.778.057-1.591.024-2.417l-.004-.163v-1.355l.175.1 25.987 15.004.059.033v54.068c0 .569-.198.996-.559 1.204a1.002 1.002 0 0 1-.506.131' fill='#607D8B'/><path d='M145.685 163.161l24.115 13.922-25.978 14.998-1.462-.307c-6.534-2.17-13.628-3.728-21.019-4.616-4.365-.524-8.663 1.096-9.598 3.62a2.746 2.746 0 0 0-.011 1.928c1.538 4.267 4.236 8.363 7.995 12.135l.532.845-25.977 14.997-24.115-13.922 75.518-43.6' fill='#FFF'/><path d='M94.282 220.818l-.059-.033-24.29-14.024.175-.101 75.577-43.634.058.033 24.29 14.024-26.191 15.122-.045-.01-1.461-.307c-6.549-2.174-13.613-3.725-21.009-4.614a13.744 13.744 0 0 0-1.638-.097c-3.758 0-7.054 1.531-7.837 3.642a2.62 2.62 0 0 0-.01 1.848c1.535 4.258 4.216 8.326 7.968 12.091l.016.021.526.835.006.01.064.102-.105.061-25.977 14.998-.058.033zm-23.881-14.057l23.881 13.788 24.802-14.32c.546-.315.846-.489 1.017-.575l-.466-.74c-3.771-3.787-6.467-7.881-8.013-12.168a2.851 2.851 0 0 1 .011-2.008c.815-2.199 4.203-3.795 8.056-3.795.557 0 1.117.033 1.666.099 7.412.891 14.491 2.445 21.041 4.621.836.175 1.215.254 1.39.304l25.78-14.884-23.881-13.788-75.284 43.466z' fill='#607D8B'/><path d='M167.23 125.979v50.871l-27.321 15.773-6.461-14.167c-.91-1.996-3.428-1.738-5.624.574a10.238 10.238 0 0 0-2.33 4.018l-6.46 21.628-27.322 15.774v-50.871l75.518-43.6' fill='#FFF'/><path d='M91.712 220.567a.127.127 0 0 1-.059-.016.118.118 0 0 1-.058-.101v-50.871c0-.042.023-.08.058-.101l75.519-43.6a.117.117 0 0 1 .175.101v50.871c0 .041-.023.08-.059.1l-27.321 15.775a.118.118 0 0 1-.094.01.12.12 0 0 1-.071-.063l-6.46-14.168c-.375-.822-1.062-1.275-1.934-1.275-1.089 0-2.364.686-3.5 1.881a10.206 10.206 0 0 0-2.302 3.972l-6.46 21.627a.118.118 0 0 1-.054.068L91.77 220.551a.12.12 0 0 1-.058.016zm.117-50.92v50.601l27.106-15.65 6.447-21.583a10.286 10.286 0 0 1 2.357-4.065c1.18-1.242 2.517-1.954 3.669-1.954.969 0 1.731.501 2.146 1.411l6.407 14.051 27.152-15.676v-50.601l-75.284 43.466z' fill='#607D8B'/><path d='M168.543 126.213v50.87l-27.322 15.774-6.46-14.168c-.91-1.995-3.428-1.738-5.624.574a10.248 10.248 0 0 0-2.33 4.019l-6.461 21.627-27.321 15.774v-50.87l75.518-43.6' fill='#FFF'/><path d='M93.025 220.8a.123.123 0 0 1-.059-.015.12.12 0 0 1-.058-.101v-50.871c0-.042.023-.08.058-.101l75.518-43.6a.112.112 0 0 1 .117 0c.036.02.059.059.059.1v50.871a.116.116 0 0 1-.059.101l-27.321 15.774a.111.111 0 0 1-.094.01.115.115 0 0 1-.071-.062l-6.46-14.168c-.375-.823-1.062-1.275-1.935-1.275-1.088 0-2.363.685-3.499 1.881a10.19 10.19 0 0 0-2.302 3.971l-6.461 21.628a.108.108 0 0 1-.053.067l-27.322 15.775a.12.12 0 0 1-.058.015zm.117-50.919v50.6l27.106-15.649 6.447-21.584a10.293 10.293 0 0 1 2.357-4.065c1.179-1.241 2.516-1.954 3.668-1.954.969 0 1.732.502 2.147 1.412l6.407 14.051 27.152-15.676v-50.601l-75.284 43.466z' fill='#607D8B'/><path d='M169.8 177.083l-27.322 15.774-6.46-14.168c-.91-1.995-3.428-1.738-5.625.574a10.246 10.246 0 0 0-2.329 4.019l-6.461 21.627-27.321 15.774v-50.87l75.518-43.6v50.87z' fill='#FAFAFA'/><path d='M94.282 220.917a.234.234 0 0 1-.234-.233v-50.871c0-.083.045-.161.117-.202l75.518-43.601a.234.234 0 1 1 .35.202v50.871a.233.233 0 0 1-.116.202l-27.322 15.775a.232.232 0 0 1-.329-.106l-6.461-14.168c-.36-.789-.992-1.206-1.828-1.206-1.056 0-2.301.672-3.415 1.844a10.099 10.099 0 0 0-2.275 3.924l-6.46 21.628a.235.235 0 0 1-.107.136l-27.322 15.774a.23.23 0 0 1-.116.031zm.233-50.969v50.331l26.891-15.525 6.434-21.539a10.41 10.41 0 0 1 2.384-4.112c1.201-1.265 2.569-1.991 3.753-1.991 1.018 0 1.818.526 2.253 1.48l6.354 13.934 26.982-15.578v-50.331l-75.051 43.331z' fill='#607D8B'/><path d='M109.894 199.943c-1.774 0-3.241-.725-4.244-2.12a.224.224 0 0 1 .023-.294.233.233 0 0 1 .301-.023c.78.547 1.705.827 2.75.827 1.323 0 2.754-.439 4.256-1.306 5.311-3.067 9.631-10.518 9.631-16.611 0-1.927-.442-3.56-1.278-4.724a.232.232 0 0 1 .323-.327c1.671 1.172 2.591 3.381 2.591 6.219 0 6.242-4.426 13.863-9.865 17.003-1.574.908-3.084 1.356-4.488 1.356zm-2.969-1.542c.813.651 1.82.877 2.968.877h.001c1.321 0 2.753-.327 4.254-1.194 5.311-3.067 9.632-10.463 9.632-16.556 0-1.979-.463-3.599-1.326-4.761.411 1.035.625 2.275.625 3.635 0 6.243-4.426 13.883-9.865 17.023-1.574.909-3.084 1.317-4.49 1.317-.641 0-1.243-.149-1.799-.341z' fill='#607D8B'/><path d='M113.097 197.23c5.384-3.108 9.748-10.636 9.748-16.814 0-2.051-.483-3.692-1.323-4.86-1.784-1.252-4.374-1.194-7.257.47-5.384 3.108-9.748 10.636-9.748 16.814 0 2.051.483 3.692 1.323 4.86 1.784 1.252 4.374 1.194 7.257-.47' fill='#FAFAFA'/><path d='M108.724 198.614c-1.142 0-2.158-.213-3.019-.817-.021-.014-.04.014-.055-.007-.894-1.244-1.367-2.948-1.367-4.973 0-6.242 4.426-13.864 9.865-17.005 1.574-.908 3.084-1.363 4.49-1.363 1.142 0 2.158.309 3.018.913a.23.23 0 0 1 .056.056c.894 1.244 1.367 2.972 1.367 4.997 0 6.243-4.426 13.783-9.865 16.923-1.574.909-3.084 1.276-4.49 1.276zm-2.718-1.109c.774.532 1.688.776 2.718.776 1.323 0 2.754-.413 4.256-1.28 5.311-3.066 9.631-10.505 9.631-16.598 0-1.909-.434-3.523-1.255-4.685-.774-.533-1.688-.799-2.718-.799-1.323 0-2.755.441-4.256 1.308-5.311 3.066-9.631 10.506-9.631 16.599 0 1.909.434 3.517 1.255 4.679z' fill='#607D8B'/><path d='M149.318 114.262l-9.984 8.878 15.893 11.031 5.589-6.112-11.498-13.797' fill='#FAFAFA'/><path d='M169.676 120.84l-9.748 5.627c-3.642 2.103-9.528 2.113-13.147.024-3.62-2.089-3.601-5.488.041-7.591l9.495-5.608-6.729-3.885-81.836 47.071 45.923 26.514 3.081-1.779c.631-.365.869-.898.618-1.39-2.357-4.632-2.593-9.546-.683-14.262 5.638-13.92 24.509-24.815 48.618-28.07 8.169-1.103 16.68-.967 24.704.394.852.145 1.776.008 2.407-.357l3.081-1.778-25.825-14.91' fill='#FAFAFA'/><path d='M113.675 183.459a.47.47 0 0 1-.233-.062l-45.924-26.515a.468.468 0 0 1 .001-.809l81.836-47.071a.467.467 0 0 1 .466 0l6.729 3.885a.467.467 0 0 1-.467.809l-6.496-3.75-80.9 46.533 44.988 25.973 2.848-1.644c.192-.111.62-.409.435-.773-2.416-4.748-2.658-9.814-.7-14.65 2.806-6.927 8.885-13.242 17.582-18.263 8.657-4.998 19.518-8.489 31.407-10.094 8.198-1.107 16.79-.97 24.844.397.739.125 1.561.007 2.095-.301l2.381-1.374-25.125-14.506a.467.467 0 0 1 .467-.809l25.825 14.91a.467.467 0 0 1 0 .809l-3.081 1.779c-.721.417-1.763.575-2.718.413-7.963-1.351-16.457-1.486-24.563-.392-11.77 1.589-22.512 5.039-31.065 9.977-8.514 4.916-14.456 11.073-17.183 17.805-1.854 4.578-1.623 9.376.666 13.875.37.725.055 1.513-.8 2.006l-3.081 1.78a.476.476 0 0 1-.234.062' fill='#455A64'/><path d='M153.316 128.279c-2.413 0-4.821-.528-6.652-1.586-1.818-1.049-2.82-2.461-2.82-3.975 0-1.527 1.016-2.955 2.861-4.02l9.493-5.607a.233.233 0 1 1 .238.402l-9.496 5.609c-1.696.979-2.628 2.263-2.628 3.616 0 1.34.918 2.608 2.585 3.571 3.549 2.049 9.343 2.038 12.914-.024l9.748-5.628a.234.234 0 0 1 .234.405l-9.748 5.628c-1.858 1.072-4.296 1.609-6.729 1.609' fill='#607D8B'/><path d='M113.675 182.992l-45.913-26.508M113.675 183.342a.346.346 0 0 1-.175-.047l-45.913-26.508a.35.35 0 1 1 .35-.607l45.913 26.508a.35.35 0 0 1-.175.654' fill='#455A64'/><path d='M67.762 156.484v54.001c0 1.09.77 2.418 1.72 2.967l42.473 24.521c.95.549 1.72.11 1.72-.98v-54.001' fill='#FAFAFA'/><path d='M112.727 238.561c-.297 0-.62-.095-.947-.285l-42.473-24.521c-1.063-.613-1.895-2.05-1.895-3.27v-54.001a.35.35 0 1 1 .701 0v54.001c0 .96.707 2.18 1.544 2.663l42.473 24.522c.344.198.661.243.87.122.206-.119.325-.411.325-.799v-54.001a.35.35 0 1 1 .7 0v54.001c0 .655-.239 1.154-.675 1.406a1.235 1.235 0 0 1-.623.162' fill='#455A64'/><path d='M112.86 147.512h-.001c-2.318 0-4.499-.522-6.142-1.471-1.705-.984-2.643-2.315-2.643-3.749 0-1.445.952-2.791 2.68-3.788l12.041-6.953c1.668-.962 3.874-1.493 6.212-1.493 2.318 0 4.499.523 6.143 1.472 1.704.984 2.643 2.315 2.643 3.748 0 1.446-.952 2.791-2.68 3.789l-12.042 6.952c-1.668.963-3.874 1.493-6.211 1.493zm12.147-16.753c-2.217 0-4.298.497-5.861 1.399l-12.042 6.952c-1.502.868-2.33 1.998-2.33 3.182 0 1.173.815 2.289 2.293 3.142 1.538.889 3.596 1.378 5.792 1.378h.001c2.216 0 4.298-.497 5.861-1.399l12.041-6.953c1.502-.867 2.33-1.997 2.33-3.182 0-1.172-.814-2.288-2.292-3.142-1.539-.888-3.596-1.377-5.793-1.377z' fill='#607D8B'/><path d='M165.63 123.219l-5.734 3.311c-3.167 1.828-8.286 1.837-11.433.02-3.147-1.817-3.131-4.772.036-6.601l5.734-3.31 11.397 6.58' fill='#FAFAFA'/><path d='M154.233 117.448l9.995 5.771-4.682 2.704c-1.434.827-3.352 1.283-5.399 1.283-2.029 0-3.923-.449-5.333-1.263-1.29-.744-2-1.694-2-2.674 0-.991.723-1.955 2.036-2.713l5.383-3.108m0-.809l-5.734 3.31c-3.167 1.829-3.183 4.784-.036 6.601 1.568.905 3.623 1.357 5.684 1.357 2.077 0 4.159-.46 5.749-1.377l5.734-3.311-11.397-6.58M145.445 179.667c-1.773 0-3.241-.85-4.243-2.245-.067-.092-.057-.275.023-.356.08-.081.207-.12.3-.055.781.548 1.706.812 2.751.811 1.322 0 2.754-.446 4.256-1.313 5.31-3.066 9.631-10.522 9.631-16.615 0-1.927-.442-3.562-1.279-4.726a.235.235 0 0 1 .024-.301.232.232 0 0 1 .3-.027c1.67 1.172 2.59 3.38 2.59 6.219 0 6.242-4.425 13.987-9.865 17.127-1.573.908-3.083 1.481-4.488 1.481zM142.476 178c.814.651 1.82 1.002 2.969 1.002 1.322 0 2.753-.452 4.255-1.32 5.31-3.065 9.631-10.523 9.631-16.617 0-1.98-.463-3.63-1.325-4.793.411 1.035.624 2.26.624 3.62 0 6.242-4.425 13.875-9.865 17.015-1.573.909-3.084 1.376-4.489 1.376a5.49 5.49 0 0 1-1.8-.283z' fill='#607D8B'/><path d='M148.648 176.704c5.384-3.108 9.748-10.636 9.748-16.813 0-2.052-.483-3.693-1.322-4.861-1.785-1.252-4.375-1.194-7.258.471-5.383 3.108-9.748 10.636-9.748 16.813 0 2.051.484 3.692 1.323 4.86 1.785 1.253 4.374 1.195 7.257-.47' fill='#FAFAFA'/><path d='M144.276 178.276c-1.143 0-2.158-.307-3.019-.911a.217.217 0 0 1-.055-.054c-.895-1.244-1.367-2.972-1.367-4.997 0-6.241 4.425-13.875 9.865-17.016 1.573-.908 3.084-1.369 4.489-1.369 1.143 0 2.158.307 3.019.91a.24.24 0 0 1 .055.055c.894 1.244 1.367 2.971 1.367 4.997 0 6.241-4.425 13.875-9.865 17.016-1.573.908-3.084 1.369-4.489 1.369zm-2.718-1.172c.773.533 1.687.901 2.718.901 1.322 0 2.754-.538 4.256-1.405 5.31-3.066 9.631-10.567 9.631-16.661 0-1.908-.434-3.554-1.256-4.716-.774-.532-1.688-.814-2.718-.814-1.322 0-2.754.433-4.256 1.3-5.31 3.066-9.631 10.564-9.631 16.657 0 1.91.434 3.576 1.256 4.738z' fill='#607D8B'/><path d='M150.72 172.361l-.363-.295a24.105 24.105 0 0 0 2.148-3.128 24.05 24.05 0 0 0 1.977-4.375l.443.149a24.54 24.54 0 0 1-2.015 4.46 24.61 24.61 0 0 1-2.19 3.189M115.917 191.514l-.363-.294a24.174 24.174 0 0 0 2.148-3.128 24.038 24.038 0 0 0 1.976-4.375l.443.148a24.48 24.48 0 0 1-2.015 4.461 24.662 24.662 0 0 1-2.189 3.188M114 237.476V182.584 237.476' fill='#607D8B'/><g><path d='M81.822 37.474c.017-.135-.075-.28-.267-.392-.327-.188-.826-.21-1.109-.045l-6.012 3.471c-.131.076-.194.178-.191.285.002.132.002.461.002.578v.043l-.007.128-6.591 3.779c-.001 0-2.077 1.046-2.787 5.192 0 0-.912 6.961-.898 19.745.015 12.57.606 17.07 1.167 21.351.22 1.684 3.001 2.125 3.001 2.125.331.04.698-.027 1.08-.248l75.273-43.551c1.808-1.069 2.667-3.719 3.056-6.284 1.213-7.99 1.675-32.978-.275-39.878-.196-.693-.51-1.083-.868-1.282l-2.086-.79c-.727.028-1.416.467-1.534.535L82.032 37.072l-.21.402' fill='#FFF'/><path d='M144.311 1.701l2.085.79c.358.199.672.589.868 1.282 1.949 6.9 1.487 31.887.275 39.878-.39 2.565-1.249 5.215-3.056 6.284L69.21 93.486a1.78 1.78 0 0 1-.896.258l-.183-.011c0 .001-2.782-.44-3.003-2.124-.56-4.282-1.151-8.781-1.165-21.351-.015-12.784.897-19.745.897-19.745.71-4.146 2.787-5.192 2.787-5.192l6.591-3.779.007-.128v-.043c0-.117 0-.446-.002-.578-.003-.107.059-.21.191-.285l6.012-3.472a.98.98 0 0 1 .481-.11c.218 0 .449.053.627.156.193.112.285.258.268.392l.211-.402 60.744-34.836c.117-.068.806-.507 1.534-.535m0-.997l-.039.001c-.618.023-1.283.244-1.974.656l-.021.012-60.519 34.706a2.358 2.358 0 0 0-.831-.15c-.365 0-.704.084-.98.244l-6.012 3.471c-.442.255-.699.69-.689 1.166l.001.15-6.08 3.487c-.373.199-2.542 1.531-3.29 5.898l-.006.039c-.009.07-.92 7.173-.906 19.875.014 12.62.603 17.116 1.172 21.465l.002.015c.308 2.355 3.475 2.923 3.836 2.98l.034.004c.101.013.204.019.305.019a2.77 2.77 0 0 0 1.396-.392l75.273-43.552c1.811-1.071 2.999-3.423 3.542-6.997 1.186-7.814 1.734-33.096-.301-40.299-.253-.893-.704-1.527-1.343-1.882l-.132-.062-2.085-.789a.973.973 0 0 0-.353-.065' fill='#455A64'/><path d='M128.267 11.565l1.495.434-56.339 32.326' fill='#FFF'/><path d='M74.202 90.545a.5.5 0 0 1-.25-.931l18.437-10.645a.499.499 0 1 1 .499.864L74.451 90.478l-.249.067M75.764 42.654l-.108-.062.046-.171 5.135-2.964.17.045-.045.171-5.135 2.964-.063.017M70.52 90.375V46.421l.063-.036L137.84 7.554v43.954l-.062.036L70.52 90.375zm.25-43.811v43.38l66.821-38.579V7.985L70.77 46.564z' fill='#607D8B'/><path d='M86.986 83.182c-.23.149-.612.384-.849.523l-11.505 6.701c-.237.139-.206.252.068.252h.565c.275 0 .693-.113.93-.252L87.7 83.705c.237-.139.428-.253.425-.256a11.29 11.29 0 0 1-.006-.503c0-.274-.188-.377-.418-.227l-.715.463' fill='#607D8B'/><path d='M75.266 90.782H74.7c-.2 0-.316-.056-.346-.166-.03-.11.043-.217.215-.317l11.505-6.702c.236-.138.615-.371.844-.519l.715-.464a.488.488 0 0 1 .266-.089c.172 0 .345.13.345.421 0 .214.001.363.003.437l.006.004-.004.069c-.003.075-.003.075-.486.356l-11.505 6.702a2.282 2.282 0 0 1-.992.268zm-.6-.25l.034.001h.566c.252 0 .649-.108.866-.234l11.505-6.702c.168-.098.294-.173.361-.214-.004-.084-.004-.218-.004-.437l-.095-.171-.131.049-.714.463c-.232.15-.616.386-.854.525l-11.505 6.702-.029.018z' fill='#607D8B'/><path d='M75.266 89.871H74.7c-.2 0-.316-.056-.346-.166-.03-.11.043-.217.215-.317l11.505-6.702c.258-.151.694-.268.993-.268h.565c.2 0 .316.056.346.166.03.11-.043.217-.215.317l-11.505 6.702a2.282 2.282 0 0 1-.992.268zm-.6-.25l.034.001h.566c.252 0 .649-.107.866-.234l11.505-6.702.03-.018-.035-.001h-.565c-.252 0-.649.108-.867.234l-11.505 6.702-.029.018zM74.37 90.801v-1.247 1.247' fill='#607D8B'/><path d='M68.13 93.901c-.751-.093-1.314-.737-1.439-1.376-.831-4.238-1.151-8.782-1.165-21.352-.015-12.784.897-19.745.897-19.745.711-4.146 2.787-5.192 2.787-5.192l74.859-43.219c.223-.129 2.487-1.584 3.195.923 1.95 6.9 1.488 31.887.275 39.878-.389 2.565-1.248 5.215-3.056 6.283L69.21 93.653c-.382.221-.749.288-1.08.248 0 0-2.781-.441-3.001-2.125-.561-4.281-1.152-8.781-1.167-21.351-.014-12.784.898-19.745.898-19.745.71-4.146 2.787-5.191 2.787-5.191l6.598-3.81.871-.119 6.599-3.83.046-.461L68.13 93.901' fill='#FAFAFA'/><path d='M68.317 94.161l-.215-.013h-.001l-.244-.047c-.719-.156-2.772-.736-2.976-2.292-.568-4.34-1.154-8.813-1.168-21.384-.014-12.654.891-19.707.9-19.777.725-4.231 2.832-5.338 2.922-5.382l6.628-3.827.87-.119 6.446-3.742.034-.334a.248.248 0 0 1 .273-.223.248.248 0 0 1 .223.272l-.059.589-6.752 3.919-.87.118-6.556 3.785c-.031.016-1.99 1.068-2.666 5.018-.007.06-.908 7.086-.894 19.702.014 12.539.597 16.996 1.161 21.305.091.691.689 1.154 1.309 1.452a1.95 1.95 0 0 1-.236-.609c-.781-3.984-1.155-8.202-1.17-21.399-.014-12.653.891-19.707.9-19.777.725-4.231 2.832-5.337 2.922-5.382-.004.001 74.444-42.98 74.846-43.212l.028-.017c.904-.538 1.72-.688 2.36-.433.555.221.949.733 1.172 1.52 2.014 7.128 1.46 32.219.281 39.983-.507 3.341-1.575 5.515-3.175 6.462L69.335 93.869a2.023 2.023 0 0 1-1.018.292zm-.147-.507c.293.036.604-.037.915-.217l75.273-43.551c1.823-1.078 2.602-3.915 2.934-6.106 1.174-7.731 1.731-32.695-.268-39.772-.178-.631-.473-1.032-.876-1.192-.484-.193-1.166-.052-1.921.397l-.034.021-74.858 43.218c-.031.017-1.989 1.069-2.666 5.019-.007.059-.908 7.085-.894 19.702.015 13.155.386 17.351 1.161 21.303.09.461.476.983 1.037 1.139.114.025.185.037.196.039h.001z' fill='#455A64'/><path d='M69.317 68.982c.489-.281.885-.056.885.505 0 .56-.396 1.243-.885 1.525-.488.282-.884.057-.884-.504 0-.56.396-1.243.884-1.526' fill='#FFF'/><path d='M68.92 71.133c-.289 0-.487-.228-.487-.625 0-.56.396-1.243.884-1.526a.812.812 0 0 1 .397-.121c.289 0 .488.229.488.626 0 .56-.396 1.243-.885 1.525a.812.812 0 0 1-.397.121m.794-2.459a.976.976 0 0 0-.49.147c-.548.317-.978 1.058-.978 1.687 0 .486.271.812.674.812a.985.985 0 0 0 .491-.146c.548-.317.978-1.057.978-1.687 0-.486-.272-.813-.675-.813' fill='#8097A2'/><path d='M68.92 70.947c-.271 0-.299-.307-.299-.439 0-.491.361-1.116.79-1.363a.632.632 0 0 1 .303-.096c.272 0 .301.306.301.438 0 .491-.363 1.116-.791 1.364a.629.629 0 0 1-.304.096m.794-2.086a.812.812 0 0 0-.397.121c-.488.283-.884.966-.884 1.526 0 .397.198.625.487.625a.812.812 0 0 0 .397-.121c.489-.282.885-.965.885-1.525 0-.397-.199-.626-.488-.626' fill='#8097A2'/><path d='M69.444 85.35c.264-.152.477-.031.477.272 0 .303-.213.67-.477.822-.263.153-.477.031-.477-.271 0-.302.214-.671.477-.823' fill='#FFF'/><path d='M69.23 86.51c-.156 0-.263-.123-.263-.337 0-.302.214-.671.477-.823a.431.431 0 0 1 .214-.066c.156 0 .263.124.263.338 0 .303-.213.67-.477.822a.431.431 0 0 1-.214.066m.428-1.412c-.1 0-.203.029-.307.09-.32.185-.57.618-.57.985 0 .309.185.524.449.524a.63.63 0 0 0 .308-.09c.32-.185.57-.618.57-.985 0-.309-.185-.524-.45-.524' fill='#8097A2'/><path d='M69.23 86.322l-.076-.149c0-.235.179-.544.384-.661l.12-.041.076.151c0 .234-.179.542-.383.66l-.121.04m.428-1.038a.431.431 0 0 0-.214.066c-.263.152-.477.521-.477.823 0 .214.107.337.263.337a.431.431 0 0 0 .214-.066c.264-.152.477-.519.477-.822 0-.214-.107-.338-.263-.338' fill='#8097A2'/><path d='M139.278 7.769v43.667L72.208 90.16V46.493l67.07-38.724' fill='#455A64'/><path d='M72.083 90.375V46.421l.063-.036 67.257-38.831v43.954l-.062.036-67.258 38.831zm.25-43.811v43.38l66.821-38.579V7.985L72.333 46.564z' fill='#607D8B'/></g><path d='M125.737 88.647l-7.639 3.334V84l-11.459 4.713v8.269L99 100.315l13.369 3.646 13.368-15.314' fill='#455A64'/></g></svg>";
+function RotateInstructions() {
+ this.loadIcon_();
+ var overlay = document.createElement('div');
+ var s = overlay.style;
+ s.position = 'fixed';
+ s.top = 0;
+ s.right = 0;
+ s.bottom = 0;
+ s.left = 0;
+ s.backgroundColor = 'gray';
+ s.fontFamily = 'sans-serif';
+ s.zIndex = 1000000;
+ var img = document.createElement('img');
+ img.src = this.icon;
+ var s = img.style;
+ s.marginLeft = '25%';
+ s.marginTop = '25%';
+ s.width = '50%';
+ overlay.appendChild(img);
+ var text = document.createElement('div');
+ var s = text.style;
+ s.textAlign = 'center';
+ s.fontSize = '16px';
+ s.lineHeight = '24px';
+ s.margin = '24px 25%';
+ s.width = '50%';
+ text.innerHTML = 'Place your phone into your Cardboard viewer.';
+ overlay.appendChild(text);
+ var snackbar = document.createElement('div');
+ var s = snackbar.style;
+ s.backgroundColor = '#CFD8DC';
+ s.position = 'fixed';
+ s.bottom = 0;
+ s.width = '100%';
+ s.height = '48px';
+ s.padding = '14px 24px';
+ s.boxSizing = 'border-box';
+ s.color = '#656A6B';
+ overlay.appendChild(snackbar);
+ var snackbarText = document.createElement('div');
+ snackbarText.style.float = 'left';
+ snackbarText.innerHTML = 'No Cardboard viewer?';
+ var snackbarButton = document.createElement('a');
+ snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/';
+ snackbarButton.innerHTML = 'get one';
+ snackbarButton.target = '_blank';
+ var s = snackbarButton.style;
+ s.float = 'right';
+ s.fontWeight = 600;
+ s.textTransform = 'uppercase';
+ s.borderLeft = '1px solid gray';
+ s.paddingLeft = '24px';
+ s.textDecoration = 'none';
+ s.color = '#656A6B';
+ snackbar.appendChild(snackbarText);
+ snackbar.appendChild(snackbarButton);
+ this.overlay = overlay;
+ this.text = text;
+ this.hide();
+}
+RotateInstructions.prototype.show = function (parent) {
+ if (!parent && !this.overlay.parentElement) {
+ document.body.appendChild(this.overlay);
+ } else if (parent) {
+ if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay);
+ parent.appendChild(this.overlay);
+ }
+ this.overlay.style.display = 'block';
+ var img = this.overlay.querySelector('img');
+ var s = img.style;
+ if (isLandscapeMode()) {
+ s.width = '20%';
+ s.marginLeft = '40%';
+ s.marginTop = '3%';
+ } else {
+ s.width = '50%';
+ s.marginLeft = '25%';
+ s.marginTop = '25%';
+ }
+};
+RotateInstructions.prototype.hide = function () {
+ this.overlay.style.display = 'none';
+};
+RotateInstructions.prototype.showTemporarily = function (ms, parent) {
+ this.show(parent);
+ this.timer = setTimeout(this.hide.bind(this), ms);
+};
+RotateInstructions.prototype.disableShowTemporarily = function () {
+ clearTimeout(this.timer);
+};
+RotateInstructions.prototype.update = function () {
+ this.disableShowTemporarily();
+ if (!isLandscapeMode() && isMobile()) {
+ this.show();
+ } else {
+ this.hide();
+ }
+};
+RotateInstructions.prototype.loadIcon_ = function () {
+ this.icon = dataUri('image/svg+xml', rotateInstructionsAsset);
+};
+var DEFAULT_VIEWER = 'CardboardV1';
+var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';
+var CLASS_NAME = 'webvr-polyfill-viewer-selector';
+function ViewerSelector(defaultViewer) {
+ try {
+ this.selectedKey = localStorage.getItem(VIEWER_KEY);
+ } catch (error) {
+ console.error('Failed to load viewer profile: %s', error);
+ }
+ if (!this.selectedKey) {
+ this.selectedKey = defaultViewer || DEFAULT_VIEWER;
+ }
+ this.dialog = this.createDialog_(DeviceInfo.Viewers);
+ this.root = null;
+ this.onChangeCallbacks_ = [];
+}
+ViewerSelector.prototype.show = function (root) {
+ this.root = root;
+ root.appendChild(this.dialog);
+ var selected = this.dialog.querySelector('#' + this.selectedKey);
+ selected.checked = true;
+ this.dialog.style.display = 'block';
+};
+ViewerSelector.prototype.hide = function () {
+ if (this.root && this.root.contains(this.dialog)) {
+ this.root.removeChild(this.dialog);
+ }
+ this.dialog.style.display = 'none';
+};
+ViewerSelector.prototype.getCurrentViewer = function () {
+ return DeviceInfo.Viewers[this.selectedKey];
+};
+ViewerSelector.prototype.getSelectedKey_ = function () {
+ var input = this.dialog.querySelector('input[name=field]:checked');
+ if (input) {
+ return input.id;
+ }
+ return null;
+};
+ViewerSelector.prototype.onChange = function (cb) {
+ this.onChangeCallbacks_.push(cb);
+};
+ViewerSelector.prototype.fireOnChange_ = function (viewer) {
+ for (var i = 0; i < this.onChangeCallbacks_.length; i++) {
+ this.onChangeCallbacks_[i](viewer);
+ }
+};
+ViewerSelector.prototype.onSave_ = function () {
+ this.selectedKey = this.getSelectedKey_();
+ if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) {
+ console.error('ViewerSelector.onSave_: this should never happen!');
+ return;
+ }
+ this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]);
+ try {
+ localStorage.setItem(VIEWER_KEY, this.selectedKey);
+ } catch (error) {
+ console.error('Failed to save viewer profile: %s', error);
+ }
+ this.hide();
+};
+ViewerSelector.prototype.createDialog_ = function (options) {
+ var container = document.createElement('div');
+ container.classList.add(CLASS_NAME);
+ container.style.display = 'none';
+ var overlay = document.createElement('div');
+ var s = overlay.style;
+ s.position = 'fixed';
+ s.left = 0;
+ s.top = 0;
+ s.width = '100%';
+ s.height = '100%';
+ s.background = 'rgba(0, 0, 0, 0.3)';
+ overlay.addEventListener('click', this.hide.bind(this));
+ var width = 280;
+ var dialog = document.createElement('div');
+ var s = dialog.style;
+ s.boxSizing = 'border-box';
+ s.position = 'fixed';
+ s.top = '24px';
+ s.left = '50%';
+ s.marginLeft = -width / 2 + 'px';
+ s.width = width + 'px';
+ s.padding = '24px';
+ s.overflow = 'hidden';
+ s.background = '#fafafa';
+ s.fontFamily = "'Roboto', sans-serif";
+ s.boxShadow = '0px 5px 20px #666';
+ dialog.appendChild(this.createH1_('Select your viewer'));
+ for (var id in options) {
+ dialog.appendChild(this.createChoice_(id, options[id].label));
+ }
+ dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this)));
+ container.appendChild(overlay);
+ container.appendChild(dialog);
+ return container;
+};
+ViewerSelector.prototype.createH1_ = function (name) {
+ var h1 = document.createElement('h1');
+ var s = h1.style;
+ s.color = 'black';
+ s.fontSize = '20px';
+ s.fontWeight = 'bold';
+ s.marginTop = 0;
+ s.marginBottom = '24px';
+ h1.innerHTML = name;
+ return h1;
+};
+ViewerSelector.prototype.createChoice_ = function (id, name) {
+ var div = document.createElement('div');
+ div.style.marginTop = '8px';
+ div.style.color = 'black';
+ var input = document.createElement('input');
+ input.style.fontSize = '30px';
+ input.setAttribute('id', id);
+ input.setAttribute('type', 'radio');
+ input.setAttribute('value', id);
+ input.setAttribute('name', 'field');
+ var label = document.createElement('label');
+ label.style.marginLeft = '4px';
+ label.setAttribute('for', id);
+ label.innerHTML = name;
+ div.appendChild(input);
+ div.appendChild(label);
+ return div;
+};
+ViewerSelector.prototype.createButton_ = function (label, onclick) {
+ var button = document.createElement('button');
+ button.innerHTML = label;
+ var s = button.style;
+ s.float = 'right';
+ s.textTransform = 'uppercase';
+ s.color = '#1094f7';
+ s.fontSize = '14px';
+ s.letterSpacing = 0;
+ s.border = 0;
+ s.background = 'none';
+ s.marginTop = '16px';
+ button.addEventListener('click', onclick);
+ return button;
+};
+var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
+function unwrapExports$$1 (x) {
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
+}
+function createCommonjsModule$$1(fn, module) {
+ return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
+var NoSleep = createCommonjsModule$$1(function (module, exports) {
+(function webpackUniversalModuleDefinition(root, factory) {
+ module.exports = factory();
+})(commonjsGlobal$$1, function() {
+return (function(modules) {
+ var installedModules = {};
+ function __webpack_require__(moduleId) {
+ if(installedModules[moduleId]) {
+ return installedModules[moduleId].exports;
+ }
+ var module = installedModules[moduleId] = {
+ i: moduleId,
+ l: false,
+ exports: {}
+ };
+ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+ module.l = true;
+ return module.exports;
+ }
+ __webpack_require__.m = modules;
+ __webpack_require__.c = installedModules;
+ __webpack_require__.d = function(exports, name, getter) {
+ if(!__webpack_require__.o(exports, name)) {
+ Object.defineProperty(exports, name, {
+ configurable: false,
+ enumerable: true,
+ get: getter
+ });
+ }
+ };
+ __webpack_require__.n = function(module) {
+ var getter = module && module.__esModule ?
+ function getDefault() { return module['default']; } :
+ function getModuleExports() { return module; };
+ __webpack_require__.d(getter, 'a', getter);
+ return getter;
+ };
+ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+ __webpack_require__.p = "";
+ return __webpack_require__(__webpack_require__.s = 0);
+ })
+ ([
+ (function(module, exports, __webpack_require__) {
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+var mediaFile = __webpack_require__(1);
+var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream;
+var NoSleep = function () {
+ function NoSleep() {
+ _classCallCheck(this, NoSleep);
+ if (oldIOS) {
+ this.noSleepTimer = null;
+ } else {
+ this.noSleepVideo = document.createElement('video');
+ this.noSleepVideo.setAttribute('playsinline', '');
+ this.noSleepVideo.setAttribute('src', mediaFile);
+ this.noSleepVideo.addEventListener('timeupdate', function (e) {
+ if (this.noSleepVideo.currentTime > 0.5) {
+ this.noSleepVideo.currentTime = Math.random();
+ }
+ }.bind(this));
+ }
+ }
+ _createClass(NoSleep, [{
+ key: 'enable',
+ value: function enable() {
+ if (oldIOS) {
+ this.disable();
+ this.noSleepTimer = window.setInterval(function () {
+ window.location.href = '/';
+ window.setTimeout(window.stop, 0);
+ }, 15000);
+ } else {
+ this.noSleepVideo.play();
+ }
+ }
+ }, {
+ key: 'disable',
+ value: function disable() {
+ if (oldIOS) {
+ if (this.noSleepTimer) {
+ window.clearInterval(this.noSleepTimer);
+ this.noSleepTimer = null;
+ }
+ } else {
+ this.noSleepVideo.pause();
+ }
+ }
+ }]);
+ return NoSleep;
+}();
+module.exports = NoSleep;
+ }),
+ (function(module, exports, __webpack_require__) {
+module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=';
+ })
+ ]);
+});
+});
+var NoSleep$1 = unwrapExports$$1(NoSleep);
+var nextDisplayId = 1000;
+var defaultLeftBounds = [0, 0, 0.5, 1];
+var defaultRightBounds = [0.5, 0, 0.5, 1];
+var raf = window.requestAnimationFrame;
+var caf = window.cancelAnimationFrame;
+function VRFrameData() {
+ this.leftProjectionMatrix = new Float32Array(16);
+ this.leftViewMatrix = new Float32Array(16);
+ this.rightProjectionMatrix = new Float32Array(16);
+ this.rightViewMatrix = new Float32Array(16);
+ this.pose = null;
+}
+function VRDisplayCapabilities(config) {
+ Object.defineProperties(this, {
+ hasPosition: {
+ writable: false, enumerable: true, value: config.hasPosition
+ },
+ hasExternalDisplay: {
+ writable: false, enumerable: true, value: config.hasExternalDisplay
+ },
+ canPresent: {
+ writable: false, enumerable: true, value: config.canPresent
+ },
+ maxLayers: {
+ writable: false, enumerable: true, value: config.maxLayers
+ },
+ hasOrientation: {
+ enumerable: true, get: function get() {
+ deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData');
+ return config.hasOrientation;
+ }
+ }
+ });
+}
+function VRDisplay(config) {
+ config = config || {};
+ var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true;
+ this.isPolyfilled = true;
+ this.displayId = nextDisplayId++;
+ this.displayName = '';
+ this.depthNear = 0.01;
+ this.depthFar = 10000.0;
+ this.isPresenting = false;
+ Object.defineProperty(this, 'isConnected', {
+ get: function get() {
+ deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay');
+ return false;
+ }
+ });
+ this.capabilities = new VRDisplayCapabilities({
+ hasPosition: false,
+ hasOrientation: false,
+ hasExternalDisplay: false,
+ canPresent: false,
+ maxLayers: 1
+ });
+ this.stageParameters = null;
+ this.waitingForPresent_ = false;
+ this.layer_ = null;
+ this.originalParent_ = null;
+ this.fullscreenElement_ = null;
+ this.fullscreenWrapper_ = null;
+ this.fullscreenElementCachedStyle_ = null;
+ this.fullscreenEventTarget_ = null;
+ this.fullscreenChangeHandler_ = null;
+ this.fullscreenErrorHandler_ = null;
+ if (USE_WAKELOCK && isMobile()) {
+ this.wakelock_ = new NoSleep$1();
+ }
+}
+VRDisplay.prototype.getFrameData = function (frameData) {
+ return frameDataFromPose(frameData, this._getPose(), this);
+};
+VRDisplay.prototype.getPose = function () {
+ deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData');
+ return this._getPose();
+};
+VRDisplay.prototype.resetPose = function () {
+ deprecateWarning('VRDisplay.prototype.resetPose');
+ return this._resetPose();
+};
+VRDisplay.prototype.getImmediatePose = function () {
+ deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData');
+ return this._getPose();
+};
+VRDisplay.prototype.requestAnimationFrame = function (callback) {
+ return raf(callback);
+};
+VRDisplay.prototype.cancelAnimationFrame = function (id) {
+ return caf(id);
+};
+VRDisplay.prototype.wrapForFullscreen = function (element) {
+ if (isIOS()) {
+ return element;
+ }
+ if (!this.fullscreenWrapper_) {
+ this.fullscreenWrapper_ = document.createElement('div');
+ var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed'];
+ this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');
+ this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');
+ }
+ if (this.fullscreenElement_ == element) {
+ return this.fullscreenWrapper_;
+ }
+ if (this.fullscreenElement_) {
+ if (this.originalParent_) {
+ this.originalParent_.appendChild(this.fullscreenElement_);
+ } else {
+ this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_);
+ }
+ }
+ this.fullscreenElement_ = element;
+ this.originalParent_ = element.parentElement;
+ if (!this.originalParent_) {
+ document.body.appendChild(element);
+ }
+ if (!this.fullscreenWrapper_.parentElement) {
+ var parent = this.fullscreenElement_.parentElement;
+ parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);
+ parent.removeChild(this.fullscreenElement_);
+ }
+ this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);
+ this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');
+ var self = this;
+ function applyFullscreenElementStyle() {
+ if (!self.fullscreenElement_) {
+ return;
+ }
+ var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0'];
+ self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');
+ }
+ applyFullscreenElementStyle();
+ return this.fullscreenWrapper_;
+};
+VRDisplay.prototype.removeFullscreenWrapper = function () {
+ if (!this.fullscreenElement_) {
+ return;
+ }
+ var element = this.fullscreenElement_;
+ if (this.fullscreenElementCachedStyle_) {
+ element.setAttribute('style', this.fullscreenElementCachedStyle_);
+ } else {
+ element.removeAttribute('style');
+ }
+ this.fullscreenElement_ = null;
+ this.fullscreenElementCachedStyle_ = null;
+ var parent = this.fullscreenWrapper_.parentElement;
+ this.fullscreenWrapper_.removeChild(element);
+ if (this.originalParent_ === parent) {
+ parent.insertBefore(element, this.fullscreenWrapper_);
+ }
+ else if (this.originalParent_) {
+ this.originalParent_.appendChild(element);
+ }
+ parent.removeChild(this.fullscreenWrapper_);
+ return element;
+};
+VRDisplay.prototype.requestPresent = function (layers) {
+ var wasPresenting = this.isPresenting;
+ var self = this;
+ if (!(layers instanceof Array)) {
+ deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument');
+ layers = [layers];
+ }
+ return new Promise(function (resolve, reject) {
+ if (!self.capabilities.canPresent) {
+ reject(new Error('VRDisplay is not capable of presenting.'));
+ return;
+ }
+ if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {
+ reject(new Error('Invalid number of layers.'));
+ return;
+ }
+ var incomingLayer = layers[0];
+ if (!incomingLayer.source) {
+ resolve();
+ return;
+ }
+ var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
+ var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
+ if (wasPresenting) {
+ var layer = self.layer_;
+ if (layer.source !== incomingLayer.source) {
+ layer.source = incomingLayer.source;
+ }
+ for (var i = 0; i < 4; i++) {
+ layer.leftBounds[i] = leftBounds[i];
+ layer.rightBounds[i] = rightBounds[i];
+ }
+ self.wrapForFullscreen(self.layer_.source);
+ self.updatePresent_();
+ resolve();
+ return;
+ }
+ self.layer_ = {
+ predistorted: incomingLayer.predistorted,
+ source: incomingLayer.source,
+ leftBounds: leftBounds.slice(0),
+ rightBounds: rightBounds.slice(0)
+ };
+ self.waitingForPresent_ = false;
+ if (self.layer_ && self.layer_.source) {
+ var fullscreenElement = self.wrapForFullscreen(self.layer_.source);
+ var onFullscreenChange = function onFullscreenChange() {
+ var actualFullscreenElement = getFullscreenElement();
+ self.isPresenting = fullscreenElement === actualFullscreenElement;
+ if (self.isPresenting) {
+ if (screen.orientation && screen.orientation.lock) {
+ screen.orientation.lock('landscape-primary').catch(function (error) {
+ console.error('screen.orientation.lock() failed due to', error.message);
+ });
+ }
+ self.waitingForPresent_ = false;
+ self.beginPresent_();
+ resolve();
+ } else {
+ if (screen.orientation && screen.orientation.unlock) {
+ screen.orientation.unlock();
+ }
+ self.removeFullscreenWrapper();
+ self.disableWakeLock();
+ self.endPresent_();
+ self.removeFullscreenListeners_();
+ }
+ self.fireVRDisplayPresentChange_();
+ };
+ var onFullscreenError = function onFullscreenError() {
+ if (!self.waitingForPresent_) {
+ return;
+ }
+ self.removeFullscreenWrapper();
+ self.removeFullscreenListeners_();
+ self.disableWakeLock();
+ self.waitingForPresent_ = false;
+ self.isPresenting = false;
+ reject(new Error('Unable to present.'));
+ };
+ self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError);
+ if (requestFullscreen(fullscreenElement)) {
+ self.enableWakeLock();
+ self.waitingForPresent_ = true;
+ } else if (isIOS() || isWebViewAndroid()) {
+ self.enableWakeLock();
+ self.isPresenting = true;
+ self.beginPresent_();
+ self.fireVRDisplayPresentChange_();
+ resolve();
+ }
+ }
+ if (!self.waitingForPresent_ && !isIOS()) {
+ exitFullscreen();
+ reject(new Error('Unable to present.'));
+ }
+ });
+};
+VRDisplay.prototype.exitPresent = function () {
+ var wasPresenting = this.isPresenting;
+ var self = this;
+ this.isPresenting = false;
+ this.layer_ = null;
+ this.disableWakeLock();
+ return new Promise(function (resolve, reject) {
+ if (wasPresenting) {
+ if (!exitFullscreen() && isIOS()) {
+ self.endPresent_();
+ self.fireVRDisplayPresentChange_();
+ }
+ if (isWebViewAndroid()) {
+ self.removeFullscreenWrapper();
+ self.removeFullscreenListeners_();
+ self.endPresent_();
+ self.fireVRDisplayPresentChange_();
+ }
+ resolve();
+ } else {
+ reject(new Error('Was not presenting to VRDisplay.'));
+ }
+ });
+};
+VRDisplay.prototype.getLayers = function () {
+ if (this.layer_) {
+ return [this.layer_];
+ }
+ return [];
+};
+VRDisplay.prototype.fireVRDisplayPresentChange_ = function () {
+ var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } });
+ window.dispatchEvent(event);
+};
+VRDisplay.prototype.fireVRDisplayConnect_ = function () {
+ var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } });
+ window.dispatchEvent(event);
+};
+VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) {
+ this.removeFullscreenListeners_();
+ this.fullscreenEventTarget_ = element;
+ this.fullscreenChangeHandler_ = changeHandler;
+ this.fullscreenErrorHandler_ = errorHandler;
+ if (changeHandler) {
+ if (document.fullscreenEnabled) {
+ element.addEventListener('fullscreenchange', changeHandler, false);
+ } else if (document.webkitFullscreenEnabled) {
+ element.addEventListener('webkitfullscreenchange', changeHandler, false);
+ } else if (document.mozFullScreenEnabled) {
+ document.addEventListener('mozfullscreenchange', changeHandler, false);
+ } else if (document.msFullscreenEnabled) {
+ element.addEventListener('msfullscreenchange', changeHandler, false);
+ }
+ }
+ if (errorHandler) {
+ if (document.fullscreenEnabled) {
+ element.addEventListener('fullscreenerror', errorHandler, false);
+ } else if (document.webkitFullscreenEnabled) {
+ element.addEventListener('webkitfullscreenerror', errorHandler, false);
+ } else if (document.mozFullScreenEnabled) {
+ document.addEventListener('mozfullscreenerror', errorHandler, false);
+ } else if (document.msFullscreenEnabled) {
+ element.addEventListener('msfullscreenerror', errorHandler, false);
+ }
+ }
+};
+VRDisplay.prototype.removeFullscreenListeners_ = function () {
+ if (!this.fullscreenEventTarget_) return;
+ var element = this.fullscreenEventTarget_;
+ if (this.fullscreenChangeHandler_) {
+ var changeHandler = this.fullscreenChangeHandler_;
+ element.removeEventListener('fullscreenchange', changeHandler, false);
+ element.removeEventListener('webkitfullscreenchange', changeHandler, false);
+ document.removeEventListener('mozfullscreenchange', changeHandler, false);
+ element.removeEventListener('msfullscreenchange', changeHandler, false);
+ }
+ if (this.fullscreenErrorHandler_) {
+ var errorHandler = this.fullscreenErrorHandler_;
+ element.removeEventListener('fullscreenerror', errorHandler, false);
+ element.removeEventListener('webkitfullscreenerror', errorHandler, false);
+ document.removeEventListener('mozfullscreenerror', errorHandler, false);
+ element.removeEventListener('msfullscreenerror', errorHandler, false);
+ }
+ this.fullscreenEventTarget_ = null;
+ this.fullscreenChangeHandler_ = null;
+ this.fullscreenErrorHandler_ = null;
+};
+VRDisplay.prototype.enableWakeLock = function () {
+ if (this.wakelock_) {
+ this.wakelock_.enable();
+ }
+};
+VRDisplay.prototype.disableWakeLock = function () {
+ if (this.wakelock_) {
+ this.wakelock_.disable();
+ }
+};
+VRDisplay.prototype.beginPresent_ = function () {
+};
+VRDisplay.prototype.endPresent_ = function () {
+};
+VRDisplay.prototype.submitFrame = function (pose) {
+};
+VRDisplay.prototype.getEyeParameters = function (whichEye) {
+ return null;
+};
+var config = {
+ ADDITIONAL_VIEWERS: [],
+ DEFAULT_VIEWER: '',
+ MOBILE_WAKE_LOCK: true,
+ DEBUG: false,
+ DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
+ K_FILTER: 0.98,
+ PREDICTION_TIME_S: 0.040,
+ CARDBOARD_UI_DISABLED: false,
+ ROTATE_INSTRUCTIONS_DISABLED: false,
+ YAW_ONLY: false,
+ BUFFER_SCALE: 0.5,
+ DIRTY_SUBMIT_FRAME_BINDINGS: false
+};
+var Eye = {
+ LEFT: 'left',
+ RIGHT: 'right'
+};
+function CardboardVRDisplay(config$$1) {
+ var defaults = extend({}, config);
+ config$$1 = extend(defaults, config$$1 || {});
+ VRDisplay.call(this, {
+ wakelock: config$$1.MOBILE_WAKE_LOCK
+ });
+ this.config = config$$1;
+ this.displayName = 'Cardboard VRDisplay';
+ this.capabilities = new VRDisplayCapabilities({
+ hasPosition: false,
+ hasOrientation: true,
+ hasExternalDisplay: false,
+ canPresent: true,
+ maxLayers: 1
+ });
+ this.stageParameters = null;
+ this.bufferScale_ = this.config.BUFFER_SCALE;
+ this.poseSensor_ = new PoseSensor(this.config);
+ this.distorter_ = null;
+ this.cardboardUI_ = null;
+ this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this));
+ this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS);
+ this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER);
+ this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));
+ this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());
+ if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) {
+ this.rotateInstructions_ = new RotateInstructions();
+ }
+ if (isIOS()) {
+ window.addEventListener('resize', this.onResize_.bind(this));
+ }
+}
+CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype);
+CardboardVRDisplay.prototype._getPose = function () {
+ return {
+ position: null,
+ orientation: this.poseSensor_.getOrientation(),
+ linearVelocity: null,
+ linearAcceleration: null,
+ angularVelocity: null,
+ angularAcceleration: null
+ };
+};
+CardboardVRDisplay.prototype._resetPose = function () {
+ if (this.poseSensor_.resetPose) {
+ this.poseSensor_.resetPose();
+ }
+};
+CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) {
+ var fieldOfView;
+ if (whichEye == Eye.LEFT) {
+ fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye();
+ } else if (whichEye == Eye.RIGHT) {
+ fieldOfView = this.deviceInfo_.getFieldOfViewRightEye();
+ } else {
+ console.error('Invalid eye provided: %s', whichEye);
+ return null;
+ }
+ return fieldOfView;
+};
+CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) {
+ var offset;
+ if (whichEye == Eye.LEFT) {
+ offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
+ } else if (whichEye == Eye.RIGHT) {
+ offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
+ } else {
+ console.error('Invalid eye provided: %s', whichEye);
+ return null;
+ }
+ return offset;
+};
+CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) {
+ var offset = this._getEyeOffset(whichEye);
+ var fieldOfView = this._getFieldOfView(whichEye);
+ var eyeParams = {
+ offset: offset,
+ renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,
+ renderHeight: this.deviceInfo_.device.height * this.bufferScale_
+ };
+ Object.defineProperty(eyeParams, 'fieldOfView', {
+ enumerable: true,
+ get: function get() {
+ deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices');
+ return fieldOfView;
+ }
+ });
+ return eyeParams;
+};
+CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) {
+ if (this.config.DEBUG) {
+ console.log('DPDB reported that device params were updated.');
+ }
+ this.deviceInfo_.updateDeviceParams(newParams);
+ if (this.distorter_) {
+ this.distorter_.updateDeviceInfo(this.deviceInfo_);
+ }
+};
+CardboardVRDisplay.prototype.updateBounds_ = function () {
+ if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) {
+ this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds);
+ }
+};
+CardboardVRDisplay.prototype.beginPresent_ = function () {
+ var gl = this.layer_.source.getContext('webgl');
+ if (!gl) gl = this.layer_.source.getContext('experimental-webgl');
+ if (!gl) gl = this.layer_.source.getContext('webgl2');
+ if (!gl) return;
+ if (this.layer_.predistorted) {
+ if (!this.config.CARDBOARD_UI_DISABLED) {
+ gl.canvas.width = getScreenWidth() * this.bufferScale_;
+ gl.canvas.height = getScreenHeight() * this.bufferScale_;
+ this.cardboardUI_ = new CardboardUI(gl);
+ }
+ } else {
+ if (!this.config.CARDBOARD_UI_DISABLED) {
+ this.cardboardUI_ = new CardboardUI(gl);
+ }
+ this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS);
+ this.distorter_.updateDeviceInfo(this.deviceInfo_);
+ }
+ if (this.cardboardUI_) {
+ this.cardboardUI_.listen(function (e) {
+ this.viewerSelector_.show(this.layer_.source.parentElement);
+ e.stopPropagation();
+ e.preventDefault();
+ }.bind(this), function (e) {
+ this.exitPresent();
+ e.stopPropagation();
+ e.preventDefault();
+ }.bind(this));
+ }
+ if (this.rotateInstructions_) {
+ if (isLandscapeMode() && isMobile()) {
+ this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);
+ } else {
+ this.rotateInstructions_.update();
+ }
+ }
+ this.orientationHandler = this.onOrientationChange_.bind(this);
+ window.addEventListener('orientationchange', this.orientationHandler);
+ this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);
+ window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
+ this.fireVRDisplayDeviceParamsChange_();
+};
+CardboardVRDisplay.prototype.endPresent_ = function () {
+ if (this.distorter_) {
+ this.distorter_.destroy();
+ this.distorter_ = null;
+ }
+ if (this.cardboardUI_) {
+ this.cardboardUI_.destroy();
+ this.cardboardUI_ = null;
+ }
+ if (this.rotateInstructions_) {
+ this.rotateInstructions_.hide();
+ }
+ this.viewerSelector_.hide();
+ window.removeEventListener('orientationchange', this.orientationHandler);
+ window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
+};
+CardboardVRDisplay.prototype.updatePresent_ = function () {
+ this.endPresent_();
+ this.beginPresent_();
+};
+CardboardVRDisplay.prototype.submitFrame = function (pose) {
+ if (this.distorter_) {
+ this.updateBounds_();
+ this.distorter_.submitFrame();
+ } else if (this.cardboardUI_ && this.layer_) {
+ var canvas = this.layer_.source.getContext('webgl').canvas;
+ if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) {
+ this.cardboardUI_.onResize();
+ }
+ this.lastWidth = canvas.width;
+ this.lastHeight = canvas.height;
+ this.cardboardUI_.render();
+ }
+};
+CardboardVRDisplay.prototype.onOrientationChange_ = function (e) {
+ this.viewerSelector_.hide();
+ if (this.rotateInstructions_) {
+ this.rotateInstructions_.update();
+ }
+ this.onResize_();
+};
+CardboardVRDisplay.prototype.onResize_ = function (e) {
+ if (this.layer_) {
+ var gl = this.layer_.source.getContext('webgl');
+ var cssProperties = ['position: absolute', 'top: 0', 'left: 0',
+ 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0',
+ 'padding: 0px', 'box-sizing: content-box'];
+ gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');
+ safariCssSizeWorkaround(gl.canvas);
+ }
+};
+CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) {
+ this.deviceInfo_.setViewer(viewer);
+ if (this.distorter_) {
+ this.distorter_.updateDeviceInfo(this.deviceInfo_);
+ }
+ this.fireVRDisplayDeviceParamsChange_();
+};
+CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () {
+ var event = new CustomEvent('vrdisplaydeviceparamschange', {
+ detail: {
+ vrdisplay: this,
+ deviceInfo: this.deviceInfo_
+ }
+ });
+ window.dispatchEvent(event);
+};
+CardboardVRDisplay.VRFrameData = VRFrameData;
+CardboardVRDisplay.VRDisplay = VRDisplay;
+return CardboardVRDisplay;
+})));
+});
+var CardboardVRDisplay = unwrapExports(cardboardVrDisplay);
+
+class XRDevice extends EventTarget {
+ constructor(global) {
+ super();
+ this.global = global;
+ this.onWindowResize = this.onWindowResize.bind(this);
+ this.global.window.addEventListener('resize', this.onWindowResize);
+ this.environmentBlendMode = 'opaque';
+ }
+ get depthNear() { throw new Error('Not implemented'); }
+ set depthNear(val) { throw new Error('Not implemented'); }
+ get depthFar() { throw new Error('Not implemented'); }
+ set depthFar(val) { throw new Error('Not implemented'); }
+ onBaseLayerSet(sessionId, layer) { throw new Error('Not implemented'); }
+ onInlineVerticalFieldOfViewSet(sessionId, value) { throw new Error('Not implemented'); }
+ supportsSession(mode) { throw new Error('Not implemented'); }
+ async requestSession(mode) { throw new Error('Not implemented'); }
+ requestAnimationFrame(callback) { throw new Error('Not implemented'); }
+ onFrameStart(sessionId) { throw new Error('Not implemented'); }
+ onFrameEnd(sessionId) { throw new Error('Not implemented'); }
+ requestStageBounds() { throw new Error('Not implemented'); }
+ async requestFrameOfReferenceTransform(type, options) {
+ return undefined;
+ }
+ cancelAnimationFrame(handle) { throw new Error('Not implemented'); }
+ endSession(sessionId) { throw new Error('Not implemented'); }
+ getViewport(sessionId, eye, layer, target) { throw new Error('Not implemented'); }
+ getProjectionMatrix(eye) { throw new Error('Not implemented'); }
+ getBasePoseMatrix() { throw new Error('Not implemented'); }
+ getBaseViewMatrix(eye) { throw new Error('Not implemented'); }
+ getInputSources() { throw new Error('Not implemented'); }
+ getInputPose(inputSource, coordinateSystem, poseType) { throw new Error('Not implemented'); }
+ onWindowResize() {
+ this.onWindowResize();
+ }
+}
+
+let oculusTouch = {
+ mapping: 'xr-standard',
+ id: 'oculus-touch',
+ buttons: {
+ length: 6,
+ 0: 1,
+ 1: 0,
+ 2: 2,
+ 3: null,
+ 4: 3,
+ 5: 4
+ },
+ gripTransform: {
+ position: [0, -0.02, 0.04, 1],
+ orientation: [Math.PI * 0.11, 0, 0, 1]
+ }
+};
+let windowsMixedReality = {
+ mapping: 'xr-standard',
+ id: 'windows-mixed-reality',
+ buttons: {
+ length: 4,
+ 0: 1,
+ 1: 0,
+ 2: 2,
+ 3: 4,
+ },
+ gripTransform: {
+ position: [0, -0.02, 0.04, 1],
+ orientation: [Math.PI * 0.11, 0, 0, 1]
+ }
+};
+let GamepadMappings = {
+ "Oculus Touch (Right)": oculusTouch,
+ "Oculus Touch (Left)": oculusTouch,
+ "Oculus Go Controller": {
+ mapping: 'xr-standard',
+ id: 'oculus-go',
+ buttons: {
+ 0: 1,
+ 1: 0,
+ },
+ gripTransform: {
+ orientation: [Math.PI * 0.11, 0, 0, 1]
+ }
+ },
+ "Windows Mixed Reality (Right)": windowsMixedReality,
+ "Windows Mixed Reality (Left)": windowsMixedReality,
+};
+
+const HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15);
+const HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15);
+const ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25);
+const WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05);
+const ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08);
+const ELBOW_BEND_RATIO = 0.4;
+const EXTENSION_RATIO_WEIGHT = 0.4;
+const MIN_ANGULAR_SPEED = 0.61;
+const MIN_ANGLE_DELTA = 0.175;
+const MIN_EXTENSION_COS = 0.12;
+const MAX_EXTENSION_COS = 0.87;
+const RAD_TO_DEG = 180 / Math.PI;
+function eulerFromQuaternion(out, q, order) {
+ function clamp(value, min$$1, max$$1) {
+ return (value < min$$1 ? min$$1 : (value > max$$1 ? max$$1 : value));
+ }
+ var sqx = q[0] * q[0];
+ var sqy = q[1] * q[1];
+ var sqz = q[2] * q[2];
+ var sqw = q[3] * q[3];
+ if ( order === 'XYZ' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[1] * q[2] ), ( sqw - sqx - sqy + sqz ) );
+ out[1] = Math.asin( clamp( 2 * ( q[0] * q[2] + q[1] * q[3] ), -1, 1 ) );
+ out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw + sqx - sqy - sqz ) );
+ } else if ( order === 'YXZ' ) {
+ out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] - q[1] * q[2] ), -1, 1 ) );
+ out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw - sqx - sqy + sqz ) );
+ out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw - sqx + sqy - sqz ) );
+ } else if ( order === 'ZXY' ) {
+ out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] + q[1] * q[2] ), -1, 1 ) );
+ out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[2] * q[0] ), ( sqw - sqx - sqy + sqz ) );
+ out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw - sqx + sqy - sqz ) );
+ } else if ( order === 'ZYX' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[2] * q[1] ), ( sqw - sqx - sqy + sqz ) );
+ out[1] = Math.asin( clamp( 2 * ( q[1] * q[3] - q[0] * q[2] ), -1, 1 ) );
+ out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw + sqx - sqy - sqz ) );
+ } else if ( order === 'YZX' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[2] * q[1] ), ( sqw - sqx + sqy - sqz ) );
+ out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[0] * q[2] ), ( sqw + sqx - sqy - sqz ) );
+ out[2] = Math.asin( clamp( 2 * ( q[0] * q[1] + q[2] * q[3] ), -1, 1 ) );
+ } else if ( order === 'XZY' ) {
+ out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[1] * q[2] ), ( sqw - sqx + sqy - sqz ) );
+ out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw + sqx - sqy - sqz ) );
+ out[2] = Math.asin( clamp( 2 * ( q[2] * q[3] - q[0] * q[1] ), -1, 1 ) );
+ } else {
+ console.log('No order given for quaternion to euler conversion.');
+ return;
+ }
+}
+class OrientationArmModel {
+ constructor() {
+ this.hand = 'right';
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED;
+ this.controllerQ = create$4();
+ this.lastControllerQ = create$4();
+ this.headQ = create$4();
+ this.headPos = create$1();
+ this.elbowPos = create$1();
+ this.wristPos = create$1();
+ this.time = null;
+ this.lastTime = null;
+ this.rootQ = create$4();
+ this.position = create$1();
+ }
+ setHandedness(hand) {
+ if (this.hand != hand) {
+ this.hand = hand;
+ if (this.hand == 'left') {
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED;
+ } else {
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED;
+ }
+ }
+ }
+ update(controllerOrientation, headPoseMatrix) {
+ this.time = now$1();
+ if (controllerOrientation) {
+ copy$4(this.lastControllerQ, this.controllerQ);
+ copy$4(this.controllerQ, controllerOrientation);
+ }
+ if (headPoseMatrix) {
+ getTranslation(this.headPos, headPoseMatrix);
+ getRotation(this.headQ, headPoseMatrix);
+ }
+ let headYawQ = this.getHeadYawOrientation_();
+ let angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ);
+ let timeDelta = (this.time - this.lastTime) / 1000;
+ let controllerAngularSpeed = angleDelta / timeDelta;
+ if (controllerAngularSpeed > MIN_ANGULAR_SPEED) {
+ slerp(this.rootQ, this.rootQ, headYawQ,
+ Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0));
+ } else {
+ copy$4(this.rootQ, headYawQ);
+ }
+ let controllerForward = fromValues$1(0, 0, -1.0);
+ transformQuat(controllerForward, controllerForward, this.controllerQ);
+ let controllerDotY = dot(controllerForward, [0, 1, 0]);
+ let extensionRatio = this.clamp_(
+ (controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0);
+ let controllerCameraQ = clone$4(this.rootQ);
+ invert$2(controllerCameraQ, controllerCameraQ);
+ multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ);
+ let elbowPos = this.elbowPos;
+ copy$1(elbowPos, this.headPos);
+ add$1(elbowPos, elbowPos, this.headElbowOffset);
+ let elbowOffset = clone$1(ARM_EXTENSION_OFFSET);
+ scale$1(elbowOffset, elbowOffset, extensionRatio);
+ add$1(elbowPos, elbowPos, elbowOffset);
+ let totalAngle = this.quatAngle_(controllerCameraQ, create$4());
+ let totalAngleDeg = totalAngle * RAD_TO_DEG;
+ let lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);let elbowRatio = ELBOW_BEND_RATIO;
+ let wristRatio = 1 - ELBOW_BEND_RATIO;
+ let lerpValue = lerpSuppression *
+ (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT);
+ let wristQ = create$4();
+ slerp(wristQ, wristQ, controllerCameraQ, lerpValue);
+ let invWristQ = invert$2(create$4(), wristQ);
+ let elbowQ = clone$4(controllerCameraQ);
+ multiply$4(elbowQ, elbowQ, invWristQ);
+ let wristPos = this.wristPos;
+ copy$1(wristPos, WRIST_CONTROLLER_OFFSET);
+ transformQuat(wristPos, wristPos, wristQ);
+ add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET);
+ transformQuat(wristPos, wristPos, elbowQ);
+ add$1(wristPos, wristPos, elbowPos);
+ let offset = clone$1(ARM_EXTENSION_OFFSET);
+ scale$1(offset, offset, extensionRatio);
+ add$1(this.position, this.wristPos, offset);
+ transformQuat(this.position, this.position, this.rootQ);
+ this.lastTime = this.time;
+ }
+ getPosition() {
+ return this.position;
+ }
+ getHeadYawOrientation_() {
+ let headEuler = create$1();
+ eulerFromQuaternion(headEuler, this.headQ, 'YXZ');
+ let destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0);
+ return destinationQ;
+ }
+ clamp_(value, min$$1, max$$1) {
+ return Math.min(Math.max(value, min$$1), max$$1);
+ }
+ quatAngle_(q1, q2) {
+ let vec1 = [0, 0, -1];
+ let vec2 = [0, 0, -1];
+ transformQuat(vec1, vec1, q1);
+ transformQuat(vec2, vec2, q2);
+ return angle(vec1, vec2);
+ }
+}
+
+const PRIVATE$16 = Symbol('@@webxr-polyfill/XRRemappedGamepad');
+const PLACEHOLDER_BUTTON = { pressed: false, touched: false, value: 0.0 };
+Object.freeze(PLACEHOLDER_BUTTON);
+class XRRemappedGamepad {
+ constructor(gamepad, map) {
+ if (!map) {
+ map = {};
+ }
+ let axes = new Array(map.axes ? map.axes.length : gamepad.axes.length);
+ let buttons = new Array(map.buttons ? map.buttons.length : gamepad.buttons.length);
+ let gripTransform = null;
+ if (map.gripTransform) {
+ let orientation = map.gripTransform.orientation || [0, 0, 0, 1];
+ gripTransform = create();
+ fromRotationTranslation(
+ gripTransform,
+ normalize$2(orientation, orientation),
+ map.gripTransform.position || [0, 0, 0]
+ );
+ }
+ let targetRayTransform = null;
+ if (map.targetRayTransform) {
+ let orientation = map.targetRayTransform.orientation || [0, 0, 0, 1];
+ targetRayTransform = create();
+ fromRotationTranslation(
+ targetRayTransform,
+ normalize$2(orientation, orientation),
+ map.targetRayTransform.position || [0, 0, 0]
+ );
+ }
+ this[PRIVATE$16] = {
+ gamepad,
+ map,
+ id: map.id || gamepad.id,
+ mapping: map.mapping || gamepad.mapping,
+ axes,
+ buttons,
+ gripTransform,
+ targetRayTransform,
+ };
+ this._update();
+ }
+ _update() {
+ let gamepad = this[PRIVATE$16].gamepad;
+ let map = this[PRIVATE$16].map;
+ let axes = this[PRIVATE$16].axes;
+ for (let i = 0; i < axes.length; ++i) {
+ if (map.axes && i in map.axes) {
+ if (map.axes[i] === null) {
+ axes[i] = 0;
+ } else {
+ axes[i] = gamepad.axes[map.axes[i]];
+ }
+ } else {
+ axes[i] = gamepad.axes[i];
+ }
+ }
+ let buttons = this[PRIVATE$16].buttons;
+ for (let i = 0; i < buttons.length; ++i) {
+ if (map.buttons && i in map.buttons) {
+ if (map.buttons[i] === null) {
+ buttons[i] = PLACEHOLDER_BUTTON;
+ } else {
+ buttons[i] = gamepad.buttons[map.buttons[i]];
+ }
+ } else {
+ buttons[i] = gamepad.buttons[i];
+ }
+ }
+ }
+ get id() {
+ return this[PRIVATE$16].id;
+ }
+ get index() {
+ return 0;
+ }
+ get connected() {
+ return this[PRIVATE$16].gamepad.connected;
+ }
+ get timestamp() {
+ return this[PRIVATE$16].gamepad.timestamp;
+ }
+ get mapping() {
+ return this[PRIVATE$16].mapping;
+ }
+ get axes() {
+ return this[PRIVATE$16].axes;
+ }
+ get buttons() {
+ return this[PRIVATE$16].buttons;
+ }
+}
+class GamepadXRInputSource {
+ constructor(polyfill, primaryButtonIndex = 0) {
+ this.polyfill = polyfill;
+ this.nativeGamepad = null;
+ this.gamepad = null;
+ this.inputSource = new XRInputSource(this);
+ this.lastPosition = create$1();
+ this.emulatedPosition = false;
+ this.basePoseMatrix = create();
+ this.outputMatrix = create();
+ this.inputPoses = new WeakMap();
+ this.primaryButtonIndex = primaryButtonIndex;
+ this.primaryActionPressed = false;
+ this.handedness = '';
+ this.targetRayMode = 'gaze';
+ this.armModel = null;
+ }
+ updateFromGamepad(gamepad) {
+ if (this.nativeGamepad !== gamepad) {
+ this.nativeGamepad = gamepad;
+ if (gamepad) {
+ this.gamepad = new XRRemappedGamepad(gamepad, GamepadMappings[gamepad.id]);
+ } else {
+ this.gamepad = null;
+ }
+ }
+ this.handedness = gamepad.hand;
+ if (this.gamepad) {
+ this.gamepad._update();
+ }
+ if (gamepad.pose) {
+ this.targetRayMode = 'tracked-pointer';
+ this.emulatedPosition = !gamepad.pose.hasPosition;
+ } else if (gamepad.hand === '') {
+ this.targetRayMode = 'gaze';
+ this.emulatedPosition = false;
+ }
+ }
+ updateBasePoseMatrix() {
+ if (this.nativeGamepad && this.nativeGamepad.pose) {
+ let pose = this.nativeGamepad.pose;
+ let position = pose.position;
+ let orientation = pose.orientation;
+ if (!position && !orientation) {
+ return;
+ }
+ if (!position) {
+ if (!pose.hasPosition) {
+ if (!this.armModel) {
+ this.armModel = new OrientationArmModel();
+ }
+ this.armModel.setHandedness(this.nativeGamepad.hand);
+ this.armModel.update(orientation, this.polyfill.getBasePoseMatrix());
+ position = this.armModel.getPosition();
+ } else {
+ position = this.lastPosition;
+ }
+ } else {
+ this.lastPosition[0] = position[0];
+ this.lastPosition[1] = position[1];
+ this.lastPosition[2] = position[2];
+ }
+ fromRotationTranslation(this.basePoseMatrix, orientation, position);
+ } else {
+ copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix());
+ }
+ return this.basePoseMatrix;
+ }
+ getXRPose(coordinateSystem, poseType) {
+ this.updateBasePoseMatrix();
+ switch(poseType) {
+ case "target-ray":
+ coordinateSystem.transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix);
+ if (this.gamepad && this.gamepad[PRIVATE$16].targetRayTransform) {
+ multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$16].targetRayTransform);
+ }
+ break;
+ case "grip":
+ if (!this.nativeGamepad || !this.nativeGamepad.pose) {
+ return null;
+ }
+ coordinateSystem.transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix);
+ if (this.gamepad && this.gamepad[PRIVATE$16].gripTransform) {
+ multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$16].gripTransform);
+ }
+ break;
+ default:
+ return null;
+ }
+ coordinateSystem._adjustForOriginOffset(this.outputMatrix);
+ return new XRPose(new XRRigidTransform(this.outputMatrix), this.emulatedPosition);
+ }
+}
+
+const TEST_ENV = "production" === 'test';
+const EXTRA_PRESENTATION_ATTRIBUTES = {
+ highRefreshRate: true,
+};
+const PRIMARY_BUTTON_MAP = {
+ oculus: 1,
+ openvr: 1,
+ 'spatial controller (spatial interaction source)': 1
+};
+let SESSION_ID = 0;
+class Session {
+ constructor(mode, polyfillOptions={}) {
+ this.mode = mode;
+ this.outputContext = null;
+ this.immersive = mode == 'immersive-vr' || mode == 'immersive-ar';
+ this.ended = null;
+ this.baseLayer = null;
+ this.inlineVerticalFieldOfView = Math.PI * 0.5;
+ this.id = ++SESSION_ID;
+ this.modifiedCanvasLayer = false;
+ if (this.outputContext && !TEST_ENV) {
+ const renderContextType = polyfillOptions.renderContextType || '2d';
+ this.renderContext = this.outputContext.canvas.getContext(renderContextType);
+ }
+ }
+}
+class WebVRDevice extends XRDevice {
+ constructor(global, display) {
+ const { canPresent } = display.capabilities;
+ super(global);
+ this.display = display;
+ this.frame = new global.VRFrameData();
+ this.sessions = new Map();
+ this.immersiveSession = null;
+ this.canPresent = canPresent;
+ this.baseModelMatrix = create();
+ this.gamepadInputSources = {};
+ this.tempVec3 = new Float32Array(3);
+ this.onVRDisplayPresentChange = this.onVRDisplayPresentChange.bind(this);
+ global.window.addEventListener('vrdisplaypresentchange', this.onVRDisplayPresentChange);
+ this.CAN_USE_GAMEPAD = global.navigator && ('getGamepads' in global.navigator);
+ this.HAS_BITMAP_SUPPORT = isImageBitmapSupported(global);
+ }
+ get depthNear() { return this.display.depthNear; }
+ set depthNear(val) { this.display.depthNear = val; }
+ get depthFar() { return this.display.depthFar; }
+ set depthFar(val) { this.display.depthFar = val; }
+ onBaseLayerSet(sessionId, layer) {
+ const session = this.sessions.get(sessionId);
+ const canvas = layer.context.canvas;
+ if (session.immersive) {
+ const left = this.display.getEyeParameters('left');
+ const right = this.display.getEyeParameters('right');
+ canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2;
+ canvas.height = Math.max(left.renderHeight, right.renderHeight);
+ this.display.requestPresent([{
+ source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES
+ }]).then(() => {
+ if (!TEST_ENV && !this.global.document.body.contains(canvas)) {
+ session.modifiedCanvasLayer = true;
+ this.global.document.body.appendChild(canvas);
+ applyCanvasStylesForMinimalRendering(canvas);
+ }
+ session.baseLayer = layer;
+ });
+ }
+ else {
+ session.baseLayer = layer;
+ }
+ }
+ onInlineVerticalFieldOfViewSet(sessionId, value) {
+ const session = this.sessions.get(sessionId);
+ session.inlineVerticalFieldOfView = value;
+ }
+ supportsSession(mode) {
+ if (XRSessionModes.indexOf(mode) == -1) {
+ throw new TypeError(
+ `The provided value '${mode}' is not a valid enum value of type XRSessionMode`);
+ }
+ if (mode == 'immersive-ar') {
+ return false;
+ }
+ if (mode == 'immersive-vr' && this.canPresent === false) {
+ return false;
+ }
+ return true;
+ }
+ async requestSession(mode) {
+ if (!this.supportsSession(mode)) {
+ return Promise.reject();
+ }
+ let immersive = mode == 'immersive-vr';
+ if (immersive) {
+ const canvas = this.global.document.createElement('canvas');
+ if (!TEST_ENV) {
+ const ctx = canvas.getContext('webgl');
+ }
+ await this.display.requestPresent([{
+ source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }]);
+ }
+ const session = new Session(mode, {
+ renderContextType: this.HAS_BITMAP_SUPPORT ? 'bitmaprenderer' : '2d'
+ });
+ this.sessions.set(session.id, session);
+ if (immersive) {
+ this.immersiveSession = session;
+ this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id);
+ }
+ return Promise.resolve(session.id);
+ }
+ requestAnimationFrame(callback) {
+ return this.display.requestAnimationFrame(callback);
+ }
+ getPrimaryButtonIndex(gamepad) {
+ let primaryButton = 0;
+ let name = gamepad.id.toLowerCase();
+ for (let key in PRIMARY_BUTTON_MAP) {
+ if (name.includes(key)) {
+ primaryButton = PRIMARY_BUTTON_MAP[key];
+ break;
+ }
+ }
+ return Math.min(primaryButton, gamepad.buttons.length - 1);
+ }
+ onFrameStart(sessionId) {
+ this.display.getFrameData(this.frame);
+ const session = this.sessions.get(sessionId);
+ if (session.immersive && this.CAN_USE_GAMEPAD) {
+ let prevInputSources = this.gamepadInputSources;
+ this.gamepadInputSources = {};
+ let gamepads = this.global.navigator.getGamepads();
+ for (let i = 0; i < gamepads.length; ++i) {
+ let gamepad = gamepads[i];
+ if (gamepad && gamepad.displayId > 0) {
+ let inputSourceImpl = prevInputSources[i];
+ if (!inputSourceImpl) {
+ inputSourceImpl = new GamepadXRInputSource(this, this.getPrimaryButtonIndex(gamepad));
+ }
+ inputSourceImpl.updateFromGamepad(gamepad);
+ this.gamepadInputSources[i] = inputSourceImpl;
+ if (inputSourceImpl.primaryButtonIndex != -1) {
+ let primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed;
+ if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) {
+ this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
+ } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) {
+ this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
+ }
+ inputSourceImpl.primaryActionPressed = primaryActionPressed;
+ }
+ }
+ }
+ }
+ if (TEST_ENV) {
+ return;
+ }
+ if (!session.immersive && session.baseLayer) {
+ const canvas = session.baseLayer.context.canvas;
+ perspective(this.frame.leftProjectionMatrix, session.inlineVerticalFieldOfView,
+ canvas.width/canvas.height, this.depthNear, this.depthFar);
+ }
+ }
+ onFrameEnd(sessionId) {
+ const session = this.sessions.get(sessionId);
+ if (session.ended || !session.baseLayer) {
+ return;
+ }
+ if (session.outputContext &&
+ !(session.immersive && !this.display.capabilities.hasExternalDisplay)) {
+ const mirroring =
+ session.immersive && this.display.capabilities.hasExternalDisplay;
+ const iCanvas = session.baseLayer.context.canvas;
+ const iWidth = mirroring ? iCanvas.width / 2 : iCanvas.width;
+ const iHeight = iCanvas.height;
+ if (!TEST_ENV) {
+ const oCanvas = session.outputContext.canvas;
+ const oWidth = oCanvas.width;
+ const oHeight = oCanvas.height;
+ const renderContext = session.renderContext;
+ if (this.HAS_BITMAP_SUPPORT) {
+ if (iCanvas.transferToImageBitmap) {
+ renderContext.transferFromImageBitmap(iCanvas.transferToImageBitmap());
+ }
+ else {
+ this.global.createImageBitmap(iCanvas, 0, 0, iWidth, iHeight, {
+ resizeWidth: oWidth,
+ resizeHeight: oHeight,
+ }).then(bitmap => renderContext.transferFromImageBitmap(bitmap));
+ }
+ } else {
+ renderContext.drawImage(iCanvas, 0, 0, iWidth, iHeight,
+ 0, 0, oWidth, oHeight);
+ }
+ }
+ }
+ if (session.immersive && session.baseLayer) {
+ this.display.submitFrame();
+ }
+ }
+ cancelAnimationFrame(handle) {
+ this.display.cancelAnimationFrame(handle);
+ }
+ async endSession(sessionId) {
+ const session = this.sessions.get(sessionId);
+ if (session.ended) {
+ return;
+ }
+ if (session.immersive) {
+ return this.display.exitPresent();
+ } else {
+ session.ended = true;
+ }
+ }
+ requestStageBounds() {
+ if (this.display.stageParameters) {
+ const width = this.display.stageParameters.sizeX;
+ const depth = this.display.stageParameters.sizeZ;
+ const data = [];
+ data.push(-width / 2);
+ data.push(-depth / 2);
+ data.push(width / 2);
+ data.push(-depth / 2);
+ data.push(width / 2);
+ data.push(depth / 2);
+ data.push(-width / 2);
+ data.push(depth / 2);
+ return data;
+ }
+ return null;
+ }
+ async requestFrameOfReferenceTransform(type, options) {
+ if (type === 'stage' && this.display.stageParameters &&
+ this.display.stageParameters.sittingToStandingTransform) {
+ return this.display.stageParameters.sittingToStandingTransform;
+ }
+ }
+ getProjectionMatrix(eye) {
+ if (eye === 'left') {
+ return this.frame.leftProjectionMatrix;
+ } else if (eye === 'right') {
+ return this.frame.rightProjectionMatrix;
+ } else if (eye === 'none') {
+ return this.frame.leftProjectionMatrix;
+ } else {
+ throw new Error(`eye must be of type 'left' or 'right'`);
+ }
+ }
+ getViewport(sessionId, eye, layer, target) {
+ const session = this.sessions.get(sessionId);
+ const { width, height } = layer.context.canvas;
+ if (!session.immersive) {
+ target.x = target.y = 0;
+ target.width = width;
+ target.height = height;
+ return true;
+ }
+ if (eye === 'left') {
+ target.x = 0;
+ } else if (eye === 'right') {
+ target.x = width / 2;
+ } else {
+ return false;
+ }
+ target.y = 0;
+ target.width = width / 2;
+ target.height = height;
+ return true;
+ }
+ getBasePoseMatrix() {
+ let { position, orientation } = this.frame.pose;
+ if (!position && !orientation) {
+ return this.baseModelMatrix;
+ }
+ if (!position) {
+ position = this.tempVec3;
+ position[0] = position[1] = position[2] = 0;
+ }
+ fromRotationTranslation(this.baseModelMatrix, orientation, position);
+ return this.baseModelMatrix;
+ }
+ getBaseViewMatrix(eye) {
+ if (eye === 'left') {
+ return this.frame.leftViewMatrix;
+ } else if (eye === 'right') {
+ return this.frame.rightViewMatrix;
+ } else {
+ throw new Error(`eye must be of type 'left' or 'right'`);
+ }
+ }
+ getInputSources() {
+ let inputSources = [];
+ for (let i in this.gamepadInputSources) {
+ inputSources.push(this.gamepadInputSources[i].inputSource);
+ }
+ return inputSources;
+ }
+ getInputPose(inputSource, coordinateSystem, poseType) {
+ if (!coordinateSystem) {
+ return null;
+ }
+ for (let i in this.gamepadInputSources) {
+ let inputSourceImpl = this.gamepadInputSources[i];
+ if (inputSourceImpl.inputSource === inputSource) {
+ return inputSourceImpl.getXRPose(coordinateSystem, poseType);
+ }
+ }
+ return null;
+ }
+ onWindowResize() {
+ }
+ onVRDisplayPresentChange(e) {
+ if (!this.display.isPresenting) {
+ this.sessions.forEach(session => {
+ if (session.immersive && !session.ended) {
+ if (session.modifiedCanvasLayer) {
+ const canvas = session.baseLayer.context.canvas;
+ document.body.removeChild(canvas);
+ canvas.setAttribute('style', '');
+ }
+ if (this.immersiveSession === session) {
+ this.immersiveSession = null;
+ }
+ this.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id);
+ }
+ });
+ }
+ }
+}
+
+class CardboardXRDevice extends WebVRDevice {
+ constructor(global, cardboardConfig) {
+ const display = new CardboardVRDisplay(cardboardConfig || {});
+ super(global, display);
+ this.display = display;
+ this.frame = {
+ rightViewMatrix: new Float32Array(16),
+ leftViewMatrix: new Float32Array(16),
+ rightProjectionMatrix: new Float32Array(16),
+ leftProjectionMatrix: new Float32Array(16),
+ pose: null,
+ timestamp: null,
+ };
+ }
+}
+
+const getWebVRDevice = async function (global) {
+ let device = null;
+ if ('getVRDisplays' in global.navigator) {
+ try {
+ const displays = await global.navigator.getVRDisplays();
+ if (displays && displays.length) {
+ device = new WebVRDevice(global, displays[0]);
+ }
+ } catch (e) {}
+ }
+ return device;
+};
+const requestXRDevice = async function (global, config) {
+ if (config.webvr) {
+ let xr = await getWebVRDevice(global);
+ if (xr) {
+ return xr;
+ }
+ }
+ if (!global.VRFrameData) {
+ global.VRFrameData = function () {
+ this.rightViewMatrix = new Float32Array(16);
+ this.leftViewMatrix = new Float32Array(16);
+ this.rightProjectionMatrix = new Float32Array(16);
+ this.leftProjectionMatrix = new Float32Array(16);
+ this.pose = null;
+ };
+ }
+ return new CardboardXRDevice(global, config.cardboardConfig);
+};
+
+const CONFIG_DEFAULTS = {
+ global: _global,
+ webvr: true,
+ cardboard: true,
+ cardboardConfig: null,
+ allowCardboardOnDesktop: false,
+};
+const partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext'];
+class WebXRPolyfill {
+ constructor(config={}) {
+ this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config));
+ this.global = this.config.global;
+ this.nativeWebXR = 'xr' in this.global.navigator;
+ this.injected = false;
+ if (!this.nativeWebXR) {
+ this._injectPolyfill(this.global);
+ }
+ else if (this.config.cardboard && isMobile(this.global)) {
+ this._patchNavigatorXR();
+ }
+ }
+ _injectPolyfill(global) {
+ if (!partials.every(iface => !!global[iface])) {
+ throw new Error(`Global must have the following attributes : ${partials}`);
+ }
+ for (const className of Object.keys(API)) {
+ if (global[className] !== undefined) {
+ console.warn(`${className} already defined on global.`);
+ } else {
+ global[className] = API[className];
+ }
+ }
+ {
+ const polyfilledCtx = polyfillMakeXRCompatible(global.WebGLRenderingContext);
+ if (polyfilledCtx) {
+ polyfillGetContext(global.HTMLCanvasElement);
+ if (global.OffscreenCanvas) {
+ polyfillGetContext(global.OffscreenCanvas);
+ }
+ if (global.WebGL2RenderingContext){
+ polyfillMakeXRCompatible(global.WebGL2RenderingContext);
+ }
+ }
+ }
+ this.injected = true;
+ this._patchNavigatorXR();
+ }
+ _patchNavigatorXR() {
+ let devicePromise = requestXRDevice(this.global, this.config);
+ this.xr = new XR(devicePromise);
+ Object.defineProperty(this.global.navigator, 'xr', {
+ value: this.xr,
+ configurable: true,
+ });
+ }
+}
+
+export default WebXRPolyfill;
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js
index 218967ea506..71f30efdcc8 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js
@@ -21,12 +21,12 @@
// |matrix| - Float32Array representing 4x4 matrix (column major)
// |point| - DOMPointReadOnly
const transformByMatrix = function(matrix, point){
- return new DOMPointReadOnly({
- x : matrix[0] * point.x + matrix[4] * point.y + matrix[8] * point.z + matrix[12] * point.w,
- y : matrix[1] * point.x + matrix[5] * point.y + matrix[9] * point.z + matrix[13] * point.w,
- z : matrix[2] * point.x + matrix[6] * point.y + matrix[10] * point.z + matrix[14] * point.w,
- w : matrix[3] * point.x + matrix[7] * point.y + matrix[11] * point.z + matrix[15] * point.w,
- });
+ return new DOMPointReadOnly(
+ matrix[0] * point.x + matrix[4] * point.y + matrix[8] * point.z + matrix[12] * point.w,
+ matrix[1] * point.x + matrix[5] * point.y + matrix[9] * point.z + matrix[13] * point.w,
+ matrix[2] * point.x + matrix[6] * point.y + matrix[10] * point.z + matrix[14] * point.w,
+ matrix[3] * point.x + matrix[7] * point.y + matrix[11] * point.z + matrix[15] * point.w,
+ );
};
// |lhs|, |rhs| - Float32Arrays representing 4x4 matrices (column major)
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/magic-window.html b/chromium/third_party/webxr_test_pages/webxr-samples/magic-window.html
index 08fbc202c81..2bf545e6209 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/magic-window.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/magic-window.html
@@ -26,8 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<meta name='mobile-web-app-capable' content='yes'>
<meta name='apple-mobile-web-app-capable' content='yes'>
- <!-- Origin Trial Token, feature = WebXR Device API, origin = https://immersive-web.github.io, expires = 2018-08-28 -->
-<meta http-equiv="origin-trial" data-feature="WebXR Device API" data-expires="2018-08-28" content="AnNpu7ceXvLew05ccD8Zr1OZsdZiB2hLQKK82kTTMDwF7oRKtP3QEJ4RzkeHrmB8Sq0vSV6ZNmszpBCZ0I8p9gAAAABceyJvcmlnaW4iOiJodHRwczovL2ltbWVyc2l2ZS13ZWIuZ2l0aHViLmlvOjQ0MyIsImZlYXR1cmUiOiJXZWJYUkRldmljZSIsImV4cGlyeSI6MTUzNTQxNDQwMH0=">
+ <!-- Origin Trial Token, feature = WebXR Device API (For Chrome M76+), origin = storage.googleapis.com, expires = 2019-07-24 -->
+ <meta http-equiv="origin-trial" data-feature="WebXR Device API (For Chrome M76+)" data-expires="2019-07-24" content="Ap6io/uhkGK7vXCD+golNnQfj8wJ4so790EzZoqb8YOljMXIBTvBEQFPTHYIz5d/BgtuwZTKOLrmHAOt30f38g8AAABxeyJvcmlnaW4iOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb206NDQzIiwiZmVhdHVyZSI6IldlYlhSRGV2aWNlTTc2IiwiZXhwaXJ5IjoxNTY0MDA5MzU2LCJpc1N1YmRvbWFpbiI6dHJ1ZX0=">
<title>Magic Window</title>
@@ -57,7 +57,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<p>
This sample demonstrates use of a non-immersive XRSession to present
'Magic Window' content prior to entering XR presentation with an
- immersive session.
+ immersive session. The viewer pose can be adjusted by clicking and
+ dragging with mouse or touch.
</p>
<p>
<a class="back" href="./index.html">Back</a>
@@ -80,6 +81,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import {Gltf2Node} from './js/cottontail/src/nodes/gltf2.js';
import {QueryArgs} from './js/cottontail/src/util/query-args.js';
import {SkyboxNode} from './js/cottontail/src/nodes/skybox.js';
+ import {mat4, vec3, quat} from './js/cottontail/src/math/gl-matrix.js';
// If requested, initialize the WebXR polyfill
if (QueryArgs.getBool('allowPolyfill', false)) {
@@ -91,8 +93,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// XR globals.
let xrButton = null;
- let xrImmersiveRefSpace = null;
- let xrNonImmersiveRefSpace = null;
+ let xrRefSpaces = {};
// WebGL scene globals.
let gl = null;
@@ -113,7 +114,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
onEndSession: onEndSession,
supportedSessionTypes: ['immersive-vr']
});
- document.querySelector('header').appendChild(xrButton.domElement);
+ xrButton.addToHeader();
if (navigator.xr) {
// Pick an arbitrary device for the magic window content and start
@@ -124,6 +125,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
function onRequestSession() {
navigator.xr.requestSession('immersive-vr').then((session) => {
+ // Keep track of the session mode so that we use the correct reference
+ // space later.
session.mode = 'immersive-vr';
xrButton.setSession(session);
onSessionStarted(session);
@@ -154,6 +157,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
renderer = new Renderer(gl);
scene.setRenderer(renderer);
+
+ // Make the canvas listen for touch events so that we can adjust the
+ // viewer pose accordingly in inline sessions.
+ gl.canvas.addEventListener("touchstart", onTouchStart);
+ gl.canvas.addEventListener("touchend", onTouchEnd);
+ gl.canvas.addEventListener("touchcancel", onTouchCancel);
+ gl.canvas.addEventListener("touchmove", onTouchMove);
}
// In order for an inline session to be used we must set the GL layer's
@@ -173,7 +183,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}, (e) => {
if (!session.mode.startsWith('immersive')) {
// If we're in inline mode, our underlying platform may not support
- // the stationary reference space, but an identity space is guaranteed.
+ // the stationary reference space, but a viewer space is guaranteed.
return session.requestReferenceSpace('viewer');
} else {
throw e;
@@ -181,11 +191,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}).then((refSpace) => {
// Since we're dealing with multple sessions now we need to track
// which XRReferenceSpace is associated with which XRSession.
- if (session.mode.startsWith('immersive')) {
- xrImmersiveRefSpace = refSpace;
- } else {
- xrNonImmersiveRefSpace = refSpace;
- }
+ xrRefSpaces[session.mode] = refSpace;
session.requestAnimationFrame(onXRFrame);
});
}
@@ -201,37 +207,176 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
}
+ // Allow the user to click and drag the mouse (or touch and drag the
+ // screen on handheld devices) to adjust the viewer pose for inline
+ // sessions.
+ let lookYaw = 0;
+ let lookPitch = 0;
+ const lookSpeed = 0.0025;
+
+ function processMoveEvent(dx, dy) {
+ lookYaw += dx * lookSpeed;
+ lookPitch += dy * lookSpeed;
+ if (lookPitch < -Math.PI*0.5)
+ lookPitch = -Math.PI*0.5;
+ if (lookPitch > Math.PI*0.5)
+ lookPitch = Math.PI*0.5;
+ }
+
+
+ window.addEventListener('mousemove', (ev) => {
+ // Only rotate when the left button is pressed
+ if (ev.buttons && 1) {
+ processMoveEvent(ev.movementX, ev.movementY);
+ }
+ });
+
+ // Keep track of touch-related state so that users can touch and drag on
+ // the canvas to adjust the viewer pose in an inline session.
+ let primaryTouch = undefined;
+ let prevTouchX = undefined;
+ let prevTouchY = undefined;
+ let currentTouches = new Set();
+
+ // Keep track of all active touches, but only use the first touch to
+ // adjust the viewer pose.
+ function onTouchStart(event) {
+ let touches = event.changedTouches;
+ for (let i = 0; i < touches.length; ++i) {
+ let touch = touches[i];
+ let id = touch.identifier;
+ if (primaryTouch == undefined) {
+ primaryTouch = id;
+ prevTouchX = touch.pageX;
+ prevTouchY = touch.pageY;
+ }
+ currentTouches.add(id);
+ }
+ }
+
+ // Update the set of active touches now that one or more touches finished.
+ // If the primary touch just finished, update the viewer pose based on the
+ // final touch movement.
+ function onTouchEnd(event) {
+ let touches = event.changedTouches;
+ for (let i = 0; i < touches.length; ++i) {
+ let touch = touches[i];
+ let id = touch.identifier;
+ if (id == primaryTouch) {
+ let dx = touch.pageX - prevTouchX;
+ let dy = touch.pageY - prevTouchY;
+ processMoveEvent(dx, dy);
+ primaryTouch = undefined;
+ }
+ currentTouches.delete(id);
+ }
+ }
+
+ // Update the set of active touches now that one or more touches was
+ // cancelled. Don't update the viewer pose when the primary touch was
+ // cancelled.
+ function onTouchCancel(event) {
+ let touches = event.changedTouches;
+ for (let i = 0; i < touches.length; ++i) {
+ let touch = touches[i];
+ let id = touch.identifier;
+ if (id == primaryTouch) {
+ primaryTouch = undefined;
+ }
+ currentTouches.delete(id);
+ }
+ }
+
+ // Only use the delta between the most recent and previous events for the
+ // primary touch. Ignore the other touches.
+ function onTouchMove(event) {
+ let touches = event.changedTouches;
+ for (let i = 0; i < touches.length; ++i) {
+ let touch = touches[i];
+ let id = touch.identifier;
+ if (id == primaryTouch) {
+ let dx = touch.pageX - prevTouchX;
+ let dy = touch.pageY - prevTouchY;
+ processMoveEvent(dx, dy);
+ prevTouchX = touch.pageX;
+ prevTouchY = touch.pageY;
+ }
+ }
+ }
+
+ // XRReferenceSpace offset is immutable, so return a new reference space
+ // that has an updated orientation.
+ function getAdjustedRefSpace(refSpace) {
+ // Represent the rotational component of the reference space as a
+ // quaternion.
+ let invOrientation = quat.create();
+ quat.rotateX(invOrientation, invOrientation, -lookPitch);
+ quat.rotateY(invOrientation, invOrientation, -lookYaw);
+ let xform = new XRRigidTransform(
+ {x: 0, y: 0, z: 0},
+ {x: invOrientation[0], y: invOrientation[1], z: invOrientation[2], w: invOrientation[3]});
+ return refSpace.getOffsetReferenceSpace(xform);
+ }
+
// Called every time a XRSession requests that a new frame be drawn.
function onXRFrame(t, frame) {
let session = frame.session;
- // Ensure that we're using the right frame of reference for the session.
- let refSpace = session.mode.startsWith('immersive') ?
- xrImmersiveRefSpace :
- xrNonImmersiveRefSpace;
- let pose = frame.getViewerPose(refSpace);
+ // Per-frame scene setup. Nothing WebXR specific here.
scene.startFrame();
+ // Inform the session that we're ready for the next frame.
session.requestAnimationFrame(onXRFrame);
+ // Ensure that we're using the right reference space for the session.
+ let refSpace = xrRefSpaces[session.mode];
+
+ // Account for the click-and-drag mouse movement or touch movement when
+ // calculating the viewer pose for inline sessions.
+ if (session.mode == 'inline') {
+ refSpace = getAdjustedRefSpace(refSpace);
+ }
+
+ let pose = frame.getViewerPose(refSpace);
+
+ // In most other samples, these rendering details will be handeld by
+ // cottontail by calling scene.drawXRFrame.
if (pose) {
gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer);
if (!arMode) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
+ // Loop through each of the views reported by the frame and draw them
+ // into the corresponding viewport.
for (let view of pose.views) {
- // TODO(crbug.com/966077): This appears to be returning null for inline.
- if (session.mode.startsWith('immersive')) {
- let viewport = session.renderState.baseLayer.getViewport(view);
- gl.viewport(viewport.x, viewport.y,
- viewport.width, viewport.height);
- }
-
+ let viewport = session.renderState.baseLayer.getViewport(view);
+ gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+ // Draw this view of the scene. What happens in this function really
+ // isn't all that important. What is important is that it renders
+ // into the XRWebGLLayer's framebuffer, using the viewport into that
+ // framebuffer reported by the current view, and using the
+ // projection and view matricies from the current view and pose.
+ // We bound the framebuffer and viewport up above, and are passing
+ // in the appropriate matrices here to be used when rendering.
scene.draw(view.projectionMatrix, view.transform.inverse.matrix);
}
+ } else {
+ // There's several options for handling cases where no pose is given.
+ // The simplest, which these samples opt for, is to simply not draw
+ // anything. That way the device will continue to show the last frame
+ // drawn, possibly even with reprojection. Alternately you could
+ // re-draw the scene again with the last known good pose (which is now
+ // likely to be wrong), clear to black, or draw a head-locked message
+ // for the user indicating that they should try to get back to an area
+ // with better tracking. In all cases it's possible that the device
+ // may override what is drawn here to show the user it's own error
+ // message, so it should not be anything critical to the application's
+ // use.
}
+ // Per-frame scene teardown. Nothing WebXR specific here.
scene.endFrame();
}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/positional-audio.html b/chromium/third_party/webxr_test_pages/webxr-samples/positional-audio.html
index 5fec78d28f1..f80212be580 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/positional-audio.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/positional-audio.html
@@ -70,7 +70,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var polyfill = new WebXRPolyfill();
}
- // Temporary
+ // If requested, don't display the frame rate info.
let hideStats = QueryArgs.getBool('hideStats', false);
const DEFAULT_HEIGHT = 1.5;
@@ -297,6 +297,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if (audioContext.state == 'running') {
pauseAudio();
} else {
+ if("userActivation" in navigator) {
+ console.debug(navigator.userActivation);
+ }
playAudio();
}
});
@@ -373,8 +376,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}, (e) => {
if (!session.mode.startsWith('immersive')) {
// If we're in inline mode, our underlying platform may not support
- // the stationary reference space, but an identity space is guaranteed.
- return session.requestReferenceSpace('viewer');
+ // the local-floor reference space, but a viewer space is guaranteed.
+ return session.requestReferenceSpace('viewer').then((viewerRefSpace) => {
+ // Adjust the viewer space for an estimated user height. Otherwise,
+ // the poses queried with this space will originate from the floor.
+ let xform = new XRRigidTransform({x: 0, y: -1.5, z: 0});
+ return viewerRefSpace.getOffsetReferenceSpace(xform);
+ });
} else {
throw e;
}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/proposals/index.html b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/index.html
index d1df4fccef3..2f9d0af8563 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/proposals/index.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/index.html
@@ -110,9 +110,9 @@
path: 'phone-ar-hit-test.html',
description: 'Demonstrates using the Hit Test API to place virtual objects on real-world surfaces.' },
- { title: 'AR Plane Detection & Hit-Test', category: 'Phone AR',
+ { title: 'AR Plane Detection', category: 'Phone AR',
path: 'phone-ar-plane-detection.html',
- description: 'Demonstrates using the Plane Detection feature, including implementation of' +
+ description: 'Demonstrates using the Plane Detection feature, including implementation of ' +
'synchronous hit test in JavaScript leveraging obtained plane data.' },
];
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection.html b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection.html
index 59b0e43f5e7..122b27b7632 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection.html
@@ -29,7 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<!-- Origin Trial Token, feature = WebXR Device API, origin = https://immersive-web.github.io, expires = 2018-08-28 -->
<meta http-equiv="origin-trial" data-feature="WebXR Device API" data-expires="2018-08-28" content="AnNpu7ceXvLew05ccD8Zr1OZsdZiB2hLQKK82kTTMDwF7oRKtP3QEJ4RzkeHrmB8Sq0vSV6ZNmszpBCZ0I8p9gAAAABceyJvcmlnaW4iOiJodHRwczovL2ltbWVyc2l2ZS13ZWIuZ2l0aHViLmlvOjQ0MyIsImZlYXR1cmUiOiJXZWJYUkRldmljZSIsImV4cGlyeSI6MTUzNTQxNDQwMH0=">
- <title>AR Hit Test</title>
+ <title>AR Plane Detection</title>
<link href='../css/common.css' rel='stylesheet'></link>
@@ -44,7 +44,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<body>
<header>
<details open>
- <summary>AR Synchronous Hit Test</summary>
+ <summary>AR Plane Detection</summary>
+ This sample demonstrates using the Plane Detection feature,
+ including implementation of synchronous hit test in JavaScript
+ leveraging obtained plane data.
<p>
<input id="useReticle" type="checkbox" checked>
<label for="useReticle">Use reticle for placement</label><br/>
@@ -344,7 +347,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
}
- function addPlaneToScene(plane) {
+ function addPlaneToScene(frame, plane, timestamp) {
if(typeof XRPlane.counter == 'undefined') {
XRPlane.counter = 1;
XRPlane.colors = [
@@ -386,7 +389,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
plane_node.addNode(planeFrameOfReference);
plane.scene_node = plane_node;
- plane.scene_node.matrix = plane.getPose(xrRefSpace).transform.matrix;
+ plane.scene_node.matrix = frame.getPose(plane.planeSpace, xrRefSpace).transform.matrix;
plane.extended_polygon = extendPolygon(plane.polygon);
plane.extended_polygon_node = new PlaneNode({
@@ -399,17 +402,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
scene.addNode(plane.scene_node);
}
- else
+ else if(plane.lastChangedTime == timestamp)
{
- // old plane
+ // old plane that was updated in current frame
plane.scene_node.onPlaneChanged(plane.polygon);
- plane.scene_node.matrix = plane.getPose(xrRefSpace).transform.matrix;
+ plane.scene_node.matrix = frame.getPose(plane.planeSpace, xrRefSpace).transform.matrix;
plane.extended_polygon = extendPolygon(plane.polygon);
plane.extended_polygon_node.onPlaneChanged(plane.extended_polygon);
}
}
- let all_planes = new Set();
+ // Set with all planes detected in a previous frame.
+ let all_previous_planes = new Set();
// Called every time a XRSession requests that a new frame be drawn.
async function onXRFrame(t, frame) {
@@ -417,32 +421,37 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let session = frame.session;
let pose = frame.getViewerPose(xrRefSpace);
- let previous_planes = new Set(all_planes);
let detected_planes = frame.worldInformation.detectedPlanes;
- detected_planes.forEach(plane => {
- addPlaneToScene(plane);
- if(previous_planes.has(plane)) {
- previous_planes.delete(plane);
- }
- });
- previous_planes.forEach(plane => {
- console.log("Removing plane, id:", plane.id);
+ // Check if any of the old planes is no longer present in detected planes set.
+ // If it's no longer present, it was removed - clean up after.
+ all_previous_planes.forEach(plane => {
+ if(!detected_planes.has(plane)) {
+ console.log("Removing plane, id:", plane.id);
- let index = all_plane_origins.findIndex(element => element === plane.scene_node.origins);
- if(index != -1){
- all_plane_origins.splice(index, 1);
- }
+ let index = all_plane_origins.findIndex(
+ element => element === plane.scene_node.origins);
+ if(index != -1){
+ all_plane_origins.splice(index, 1);
+ }
- index = all_extended_planes.findIndex(element => element === plane.extended_polygon_node);
- if(index != -1){
- all_extended_planes.splice(index, 1);
- }
+ index = all_extended_planes.findIndex(
+ element => element === plane.extended_polygon_node);
+ if(index != -1){
+ all_extended_planes.splice(index, 1);
+ }
- scene.removeNode(plane.scene_node);
+ scene.removeNode(plane.scene_node);
+ }
});
- all_planes = new Set(detected_planes);
+ // Store currently detected planes to check against them in subsequent frame.
+ all_previous_planes = detected_planes;
+
+ // Process all currently detected planes.
+ detected_planes.forEach(plane => {
+ addPlaneToScene(frame, plane, t);
+ });
// If requested, use the pose to cast a reticle into the scene using a
// continuous hit test. For the moment we're just using the flower
@@ -460,7 +469,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
rayObject.matrix = ray.matrix.slice();
rayObject.visible = true;
- const hitTestResults = hitTest(ray, frame.worldInformation.detectedPlanes, xrRefSpace);
+ const hitTestResults = hitTest(frame, ray, xrRefSpace);
const hitTestFiltered = filterHitTestResults(hitTestResults,
extendPlanesEnabled.checked,
false,
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
index 096c27ffc66..7aacf65c680 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
@@ -98,12 +98,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Requests an inline (non-immersive) session with environment integration
// to get AR via video passthrough.
+ // Test the new XRSessionInit dictionary by asking for a nonexistent
+ // optional feature. This should be silently ignored.
+ let options = {optionalFeatures: ['unicorns-and-rainbows']};
+
// Even though this is a non-immersive session, the fact that it's
// using environment integration means it must be requested in a user
// activation event so that appropriate permissions can be granted.
// This will likely prompt the user to allow camera use, so the promise
// may remain outstanding for a while.
- navigator.xr.requestSession('immersive-ar').then((session) => {
+ navigator.xr.requestSession('immersive-ar', options).then((session) => {
session.mode = 'immersive-ar';
xrButton.setSession(session);
onSessionStarted(session);
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/room-scale.html b/chromium/third_party/webxr_test_pages/webxr-samples/room-scale.html
index f06dae7499c..b44e3655ab5 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/room-scale.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/room-scale.html
@@ -69,8 +69,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// XR globals.
let xrButton = null;
- let xrImmersiveRefSpace = null;
- let xrNonImmersiveRefSpace = null;
+ let refSpaces = {};
// WebGL scene globals.
let gl = null;
@@ -127,13 +126,22 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
onResize();
renderer = new Renderer(gl);
-
scene.setRenderer(renderer);
}
+ function updateBoundsRenderer(refSpace) {
+ if (!boundsRenderer) {
+ boundsRenderer = new BoundsRenderer(refSpace);
+ scene.addNode(boundsRenderer);
+ } else {
+ boundsRenderer.boundedRefSpace = refSpace;
+ }
+ }
+
function onSessionStarted(session) {
if (!session.mode)
session.mode = 'inline';
+ session.ended = false;
session.addEventListener('end', onSessionEnded);
initGL();
@@ -147,13 +155,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Attempt to get a 'bounded' reference space, which will align the
// user's physical floor with Y=0 and provide boundaries that indicate
// where the user can safely walk.
- session.requestReferenceSpace({ type: 'bounded' }).then((refSpace) => {
- if (!boundsRenderer) {
- boundsRenderer = new BoundsRenderer(refSpace);
- scene.addNode(boundsRenderer);
- } else {
- boundsRenderer.boundedRefSpace = refSpace;
- }
+ session.requestReferenceSpace('bounded-floor').then((refSpace) => {
+ updateBoundsRenderer(refSpace);
return refSpace;
}).catch(() => {
// If a bounded reference space isn't supported, fall back to a
@@ -185,16 +188,31 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
});
}).then((refSpace) => {
- if (session.mode.startsWith('immersive')) {
- xrImmersiveRefSpace = refSpace;
- } else {
- xrNonImmersiveRefSpace = refSpace;
- }
-
+ refSpaces[session.mode] = refSpace;
session.requestAnimationFrame(onXRFrame);
+ if (session.mode.startsWith('immersive') && !boundsRenderer) {
+ pollBounds(session);
+ }
});
}
+ function sleep(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+
+ function pollBounds(session) {
+ if (session.mode.startsWith('immersive') && !session.ended) {
+ session.requestReferenceSpace('bounded-floor').then((space) => {
+ updateBoundsRenderer(space);
+ refSpaces[session.mode] = space;
+ console.log(space.boundsGeometry);
+ }).catch(() => {
+ console.log("Failed to get bounded reference space. Trying again in 1 second.");
+ sleep(1000).then(() => pollBounds(session));
+ });
+ }
+ }
+
function onEndSession(session) {
session.end();
}
@@ -203,14 +221,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if (event.session.mode.startsWith('immersive')) {
xrButton.setSession(null);
}
+ event.session.ended = true;
}
function onXRFrame(t, frame) {
let session = frame.session;
- let refSpace = session.mode.startsWith('immersive') ?
- xrImmersiveRefSpace :
- xrNonImmersiveRefSpace;
- let pose = frame.getViewerPose(refSpace);
+ let pose = frame.getViewerPose(refSpaces[session.mode]);
scene.startFrame();
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html b/chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html
index 3f83e99af44..5ee97cad760 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html
@@ -155,10 +155,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
spectatorButton.innerHTML = 'Enable spectator mode';
spectatorButton.addEventListener('click', onEnableSpectatorMode);
mainElement.appendChild(spectatorButton);
-
- // Hide the inline session's canvas so that we can see
- // the button.
- gl.canvas.style.display = 'none';
});
}
@@ -167,7 +163,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
initGL();
- session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
+ // In order for an inline session to be used we must set the GL layer's
+ // compositionDisabled option to "true", which indicates that WebGL
+ // commands will draw to the canvas like normal.
+ session.updateRenderState({
+ baseLayer: new XRWebGLLayer(session, gl, {
+ compositionDisabled: session.mode == 'inline'
+ })
+ });
session.requestReferenceSpace('local-floor').then((refSpace) => {
return refSpace;
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/input-selection.html b/chromium/third_party/webxr_test_pages/webxr-samples/teleportation.html
index 5f70d7ff245..bf056d5c5f9 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/input-selection.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/teleportation.html
@@ -26,14 +26,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<meta name='mobile-web-app-capable' content='yes'>
<meta name='apple-mobile-web-app-capable' content='yes'>
- <!-- Origin Trial Token, feature = WebXR Device API, origin = https://immersive-web.github.io, expires = 2018-08-28 -->
-<meta http-equiv="origin-trial" data-feature="WebXR Device API" data-expires="2018-08-28" content="AnNpu7ceXvLew05ccD8Zr1OZsdZiB2hLQKK82kTTMDwF7oRKtP3QEJ4RzkeHrmB8Sq0vSV6ZNmszpBCZ0I8p9gAAAABceyJvcmlnaW4iOiJodHRwczovL2ltbWVyc2l2ZS13ZWIuZ2l0aHViLmlvOjQ0MyIsImZlYXR1cmUiOiJXZWJYUkRldmljZSIsImV4cGlyeSI6MTUzNTQxNDQwMH0=">
+ <!-- Origin Trial Token, feature = WebXR Device API (For Chrome M76+), origin = storage.googleapis.com, expires = 2019-07-24 -->
+ <meta http-equiv="origin-trial" data-feature="WebXR Device API (For Chrome M76+)" data-expires="2019-07-24" content="Ap6io/uhkGK7vXCD+golNnQfj8wJ4so790EzZoqb8YOljMXIBTvBEQFPTHYIz5d/BgtuwZTKOLrmHAOt30f38g8AAABxeyJvcmlnaW4iOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb206NDQzIiwiZmVhdHVyZSI6IldlYlhSRGV2aWNlTTc2IiwiZXhwaXJ5IjoxNTY0MDA5MzU2LCJpc1N1YmRvbWFpbiI6dHJ1ZX0=">
- <title>Input Selection</title>
+ <title>Teleportation</title>
<link href='css/common.css' rel='stylesheet'></link>
-
<!--The polyfill is not needed for browser that have native API support,
but is linked by these samples for wider compatibility.-->
<!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script-->
@@ -45,32 +44,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<body>
<header>
<details open>
- <summary>Input Selection</summary>
+ <summary>Teleportation</summary>
<p>
- This sample demonstrates handling 'select' events generated by
- XRInputSources to create clickable objects in the scene.
+ This sample demonstrates teleporting the viewer by updating the
+ XRSession reference space. Select a point on the floor with a
+ controller to teleport to it. Select the leftmost box to rotate to the
+ left by 30 degrees. Selecting the rightmost box rotates the viewer by
+ 30 degress to the right. Select the middle box to reset the
+ viewer orientation.
<a class="back" href="./index.html">Back</a>
</p>
</details>
</header>
- <header>
- <details id="gamepad-details-hand-none">
- <summary>None-hand Gamepad</summary>
- <p>Real-time info for gamepad not associated with a particular hand.</p>
- </details>
- </header>
- <header>
- <details id="gamepad-details-hand-left">
- <summary>Left-hand Gamepad</summary>
- <p>Real-time info for gamepad associated with left hand.</p>
- </details>
- </header>
- <header>
- <details id="gamepad-details-hand-right">
- <summary>Right-hand Gamepad</summary>
- <p>Real-time info for gamepad associated with right hand.</p>
- </details>
- </header>
<script type="module">
import {Scene} from './js/cottontail/src/scenes/scene.js';
import {Renderer, createWebGLContext} from './js/cottontail/src/core/renderer.js';
@@ -88,16 +73,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var polyfill = new WebXRPolyfill();
}
- // Temporary
+ // If requested, don't display the frame rate info.
let hideStats = QueryArgs.getBool('hideStats', false);
- // XR globals.
+ // XR globals. Several additional reference spaces are required because of
+ // how the teleportation mechanic in onSelect works.
let xrButton = null;
let xrImmersiveRefSpaceBase = null;
let xrImmersiveRefSpaceOffset = null;
let xrNonImmersiveRefSpaceBase = null;
let xrNonImmersiveRefSpaceOffset = null;
- let xrViewerSpace = null;
+ let xrViewerSpaces = {};
+
+ let trackingSpaceOriginInWorldSpace = vec3.create();
+ let trackingSpaceHeadingDegrees = 0; // around +Y axis, positive angles rotate left
+ let floorSize = 10;
+ let floorPosition = [0, -floorSize / 2 + 0.01, 0];
+ let floorNode = null;
// WebGL scene globals.
let gl = null;
@@ -112,299 +104,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let boxes = [];
- let trackingSpaceOriginInWorldSpace = vec3.create();
- let trackingSpaceHeadingDegrees = 0; // around +Y axis, positive angles rotate left
- let floorSize = 10;
- let floorPosition = [0, -floorSize / 2 + 0.01, 0];
- let floorNode = null;
-
- let controllerTable = {};
- let boxTable = {};
- let movableBoxes = {};
- let loggedGamepadInfo = {};
-
- let frame_number = 0;
- let axes_tables = {};
- let info_tables = {};
- let button_tables = {};
-
- class XRControllerState {
- constructor(button_count) {
- this.buttons = [];
- for (let i = 0; i < button_count; ++i) {
- this.buttons.push(false);
- }
- }
-
- // returns array of buttons to fire events for
- update(gamepad) {
- let result = [];
- for (let i = 0; i < this.buttons.length; ++i) {
- let old_state = this.buttons[i];
- let new_state = gamepad.buttons[i].pressed;
- if (old_state && !new_state) {
- // Button which was previously pressed is not pressed anymore.
- result.push(i);
- }
- this.buttons[i] = new_state;
- }
- return result;
- }
- }
-
- class GamepadBoxSet {
- constructor(button_count, x, z) {
- this.box_list = [];
- this.box_state = [];
- for (let y = 1; y <= button_count; ++y) {
- addBox(x, y, z, 1, 0, 0, this.box_list);
- this.box_state.push(true);
- }
- }
-
- toggle(box_index) {
- let box = this.box_list[box_index];
- let uniforms = box.renderPrimitive.uniforms;
- if (this.box_state[box_index]) {
- uniforms.baseColorFactor.value = [0, 1, 0, 1];
- } else {
- uniforms.baseColorFactor.value = [1, 0, 0, 1];
- }
- this.box_state[box_index] = !this.box_state[box_index];
- }
- }
-
- class MovableBox {
- constructor(x, y, z, inv_speed) {
- this.box_list = [];
- addBox(x, y, z, 0, 0, 1, this.box_list);
- this.inv_speed = inv_speed;
- }
-
- update(dx, dz) {
- vec3.add(this.box_list[0].position, this.box_list[0].position, [dx / this.inv_speed, 0, dz / this.inv_speed]);
- }
- }
-
- class GamepadTable {
- constructor(title, cols, hand) {
- this.table = document.createElement("table");
- this.table.setAttribute("border", 1);
- this.body = document.createElement("tbody");
- this.AddHeader(title, cols);
- this.table.appendChild(this.body);
- document.getElementById("gamepad-details-hand-" + hand).appendChild(this.table);
- }
-
- AddHeader(title, cols) {
- let row = document.createElement("tr");
- let th = document.createElement("th");
- th.setAttribute("colspan", cols);
- th.appendChild(document.createTextNode(title));
- row.appendChild(th);
- this.body.appendChild(row);
- }
-
- AddCell(row, text) {
- let cell = document.createElement("td");
- cell.appendChild(document.createTextNode(text));
- row.appendChild(cell);
- return cell;
- }
-
- AddRow(values) {
- let cells = [];
- let row = document.createElement("tr");
- for (let i = 0; i < values.length; ++i) {
- cells.push(this.AddCell(row, values[i]));
- }
- this.body.appendChild(row);
- return cells;
- }
- }
-
- class ButtonTable extends GamepadTable {
- constructor(buttons, hand) {
- super("button data", 3, hand);
-
- this.AddRow(["pressed", "touched", "value"]);
-
- this.pressed_cells = [];
- this.touched_cells = [];
- this.value_cells = [];
-
- this.pressed = [];
- this.touched = [];
- this.values = [];
-
- for (let i = 0; i < buttons.length; ++i) {
- this.pressed.push(buttons[i].pressed);
- this.touched.push(buttons[i].touched);
- this.values.push(buttons[i].value);
- let cells = this.AddRow([buttons[i].pressed, buttons[i].touched, buttons[i].value.toFixed(3)]);
- this.pressed_cells.push(cells[0]);
- this.touched_cells.push(cells[1]);
- this.value_cells.push(cells[2]);
- }
- }
-
- update(buttons) {
- for (let i = 0; i < buttons.length; ++i) {
- const is_pressed = buttons[i].pressed;
- if (this.pressed[i] != is_pressed) {
- this.pressed_cells[i].innerHTML = is_pressed;
- this.pressed[i] = is_pressed;
- }
- const is_touched = buttons[i].touched;
- if (this.touched[i] != is_touched) {
- this.touched_cells[i].innerHTML = is_touched;
- this.touched[i] = is_touched;
- }
- const value = buttons[i].value;
- if (this.values[i] != value) {
- this.value_cells[i].innerHTML = value.toFixed(3);
- this.values[i] = value;
- }
- }
- }
- }
-
- class AxesTable extends GamepadTable {
- constructor(axes, hand) {
- super("axis values", 1, hand);
-
- this.values = [];
- for (let i = 0; i < axes.length; ++i) {
- this.values.push(axes[i]);
- }
-
- this.cells = [];
- for (let i = 0; i < axes.length; ++i) {
- let temp_cells = this.AddRow([axes[i].toFixed(3)]);
- this.cells.push(temp_cells[0]);
- }
- }
-
- update(axes) {
- // assumes length is still the same
- for (let i = 0; i < axes.length; ++i) {
- if (this.values[i] != axes[i]) {
- this.cells[i].innerHTML = axes[i].toFixed(3);
- this.values[i] = axes[i];
- }
- }
- }
- }
-
- class InfoTable extends GamepadTable {
- constructor(gamepad, hand) {
- super("Gamepad", 2, hand);
-
- this.hand = hand;
- this.id = gamepad.id;
- this.mapping = gamepad.mapping;
-
- this.hand_cell = this.AddRow(["hand", hand])[1];
- this.id_cell = this.AddRow(["id", gamepad.id])[1];
- this.mapping_cell = this.AddRow(["mapping", gamepad.mapping])[1];
- }
-
- update(gamepad, hand) {
- if (this.hand != hand) {
- this.hand_cell.innerHTML = hand;
- this.hand = hand;
- }
- if (this.id != gamepad.id) {
- this.id_cell.innerHTML = gamepad.id;
- this.id = gamepad.id;
- }
- if (this.mapping != gamepad.mapping) {
- this.mapping_cell.innerHTML = gamepad.mapping;
- this.mapping = gamepad.mapping;
- }
- }
- }
-
- function ProcessGamepad(gamepad, input_source) {
- let hand = input_source.handedness;
- if (!(hand in loggedGamepadInfo)) {
- loggedGamepadInfo[hand] = true;
- console.log(gamepad);
- }
- if (!(hand in movableBoxes)) {
- let x = 2;
- let z = 2;
- if (hand == "right") {
- x = -2;
- z = -2;
- }
- movableBoxes[hand] = new MovableBox(x, 2, z, 100);
- }
- if (!(hand in boxTable)) {
- let x = 1;
- let z = 1;
- if (hand == "right") {
- x = -1;
- z = -1;
- }
- boxTable[hand] = new GamepadBoxSet(gamepad.buttons.length, x, z);
- }
- if (!(hand in controllerTable)) {
- controllerTable[hand] = new XRControllerState(gamepad.buttons.length);
- }
- let buttons_fired = controllerTable[hand].update(gamepad);
- for (let button_index of buttons_fired) {
- let message = "controller for " + hand + " hand fired button " + button_index.toString();
- console.log(message);
- boxTable[hand].toggle(button_index);
- }
- for (let i = 0; i < gamepad.axes.length; i += 2) {
- let dx = gamepad.axes[i];
- let dy = gamepad.axes[i + 1];
- if (dx != 0 || dy != 0) {
- // Invert the y axis because gamepads follow the convention that -1
- // is up/forwards, but we want to have a forward joystick/touchpad
- // input result in forward motion for the box.
- // TODO(https://crbug.com/966060): Revisit this if the convention changes.
- movableBoxes[hand].update(dx, -dy);
- }
- }
-
- // Only update the gamepad tables once every 10 frames for perf reasons.
- // Only update the tables if the relevant section is expanded on the page.
- let details_elem = document.getElementById("gamepad-details-hand-" + hand);
- if (details_elem.hasAttribute("open")) {
- // Construct the tables if necessary. Must check this every frame
- // because otherwise, the table doesn't get created until the gamepad
- // has an input change on a frame that's a multiple of 10.
- if (!(hand in info_tables)) {
- info_tables[hand] = new InfoTable(gamepad, hand);
- }
-
- if (!(hand in axes_tables)) {
- axes_tables[hand] = new AxesTable(gamepad.axes, hand);
- }
-
- if (!(hand in button_tables)) {
- button_tables[hand] = new ButtonTable(gamepad.buttons, hand);
- }
-
- if ((frame_number % 10) == 0) {
- info_tables[hand].update(gamepad, hand);
- axes_tables[hand].update(gamepad.axes);
- button_tables[hand].update(gamepad.buttons);
- }
- }
- frame_number++;
- }
-
function initXR() {
xrButton = new XRDeviceButton({
onRequestSession: onRequestSession,
onEndSession: onEndSession,
supportedSessionTypes: ['immersive-vr']
});
- document.querySelector('header').appendChild(xrButton.domElement);
+ xrButton.addToHeader();
if (navigator.xr) {
const mode = 'inline';
@@ -413,6 +119,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
onSessionStarted(session);
});
} else {
+ // Still render the initial scene if WebXR is not available.
initFallback();
}
}
@@ -442,6 +149,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
scene.addNode(boxNode);
}
+ function addFloorBox() {
+ let boxBuilder = new BoxBuilder();
+ boxBuilder.pushCube([0, 0, 0], floorSize);
+ let boxPrimitive = boxBuilder.finishPrimitive(renderer);
+
+ let boxMaterial = new PbrMaterial();
+ boxMaterial.baseColorFactor.value = [0.3, 0.3, 0.3, 1.0];
+ let boxRenderPrimitive = renderer.createRenderPrimitive(boxPrimitive, boxMaterial);
+
+ floorNode = new Node();
+ floorNode.addRenderPrimitive(boxRenderPrimitive);
+ floorNode.selectable = true;
+ scene.addNode(floorNode);
+ mat4.identity(floorNode.matrix);
+ mat4.translate(floorNode.matrix, floorNode.matrix, floorPosition);
+ }
+
function initGL() {
if (gl)
return;
@@ -468,26 +192,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
addBox(0.0, 1.7, -1.5, 0.0, 1.0, 0.0, boxes);
addBox(1.0, 1.6, -1.3, 0.0, 0.0, 1.0, boxes);
+ // Represent the floor as a box so that we can perform a hit test
+ // against it onSelect so that we can teleport the user to that
+ // particular location.
addFloorBox();
}
- function addFloorBox() {
- let boxBuilder = new BoxBuilder();
- boxBuilder.pushCube([0, 0, 0], floorSize);
- let boxPrimitive = boxBuilder.finishPrimitive(renderer);
-
- let boxMaterial = new PbrMaterial();
- boxMaterial.baseColorFactor.value = [0.3, 0.3, 0.3, 1.0];
- let boxRenderPrimitive = renderer.createRenderPrimitive(boxPrimitive, boxMaterial);
-
- floorNode = new Node();
- floorNode.addRenderPrimitive(boxRenderPrimitive);
- floorNode.selectable = true;
- scene.addNode(floorNode);
- mat4.identity(floorNode.matrix);
- mat4.translate(floorNode.matrix, floorNode.matrix, floorPosition);
- }
-
function onRequestSession() {
const mode = 'immersive-vr';
navigator.xr.requestSession(mode).then((session) => {
@@ -516,48 +226,73 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
})
});
- // Same logic for establishing a reference space as in room-scale.html
session.requestReferenceSpace('local-floor').then((refSpace) => {
+ console.log("created local-floor reference space for " + session.mode + " session");
return refSpace;
}, (e) => {
if (!session.mode.startsWith('immersive')) {
// If we're in inline mode, our underlying platform may not support
- // the stationary reference space, but an identity space is guaranteed.
- console.log("falling back to identity reference space");
- return session.requestReferenceSpace('viewer');
+ // the local-floor reference space, but a viewer space is guaranteed.
+ console.log("falling back to viewer reference space for " + session.mode + "session");
+ return session.requestReferenceSpace('viewer').then((viewerRefSpace) => {
+ // Adjust the viewer space for an estimated user height. Otherwise,
+ // the poses queried with this space will originate from the floor.
+ let xform = new XRRigidTransform({x: 0, y: -1.5, z: 0});
+ return viewerRefSpace.getOffsetReferenceSpace(xform);
+ });
} else {
throw e;
}
}).then((refSpace) => {
- // Save the session-specific reference space, and apply the
- // current player orientation/position as originOffset.
+ // Save the session-specific base reference space, and apply the current
+ // player orientation/position as originOffset. This reference space
+ // won't change for the duration of the session and is used when
+ // updating the player position and/or orientation in onSelect.
setRefSpace(session, refSpace, false);
updateOriginOffset(session);
+
session.requestReferenceSpace('viewer').then(function(viewerSpace){
- xrViewerSpace = viewerSpace;
+ // Save a separate reference space that represents the tracking space
+ // origin, which does not change for the duration of the session.
+ // This is used when updating the player position and/or orientation
+ // in onSelect.
+ xrViewerSpaces[session.mode] = viewerSpace;
session.requestAnimationFrame(onXRFrame);
});
});
}
+ // Used for updating the origin offset.
let playerInWorldSpaceOld = vec3.create();
let playerInWorldSpaceNew = vec3.create();
let playerOffsetInWorldSpaceOld = vec3.create();
let playerOffsetInWorldSpaceNew = vec3.create();
let rotationDeltaQuat = quat.create();
+ let invPosition = vec3.create();
+ let invOrientation = quat.create();
+ // If the user selected a point on the floor, teleport them to that
+ // position while keeping their orientation the same.
+ // Otherwise, check if one of the boxes was selected and update the
+ // user's orientation accordingly:
+ // left box: turn left by 30 degress
+ // center box: reset orientation
+ // right box: turn right by 30 degrees
function onSelect(ev) {
let session = ev.frame.session;
let refSpace = getRefSpace(session, true);
- let headPose = ev.frame.getPose(xrViewerSpace, refSpace);
+ let headPose = ev.frame.getPose(xrViewerSpaces[session.mode], refSpace);
if (!headPose) return;
// Get the position offset in world space from the tracking space origin
// to the player's feet. The headPose position is the head position in world space.
// Subtract the tracking space origin position in world space to get a relative world space vector.
vec3.set(playerInWorldSpaceOld, headPose.transform.position.x, 0, headPose.transform.position.z);
- vec3.sub(playerOffsetInWorldSpaceOld, playerInWorldSpaceOld, trackingSpaceOriginInWorldSpace);
+ vec3.sub(
+ playerOffsetInWorldSpaceOld,
+ playerInWorldSpaceOld,
+ trackingSpaceOriginInWorldSpace);
// based on https://github.com/immersive-web/webxr/blob/master/input-explainer.md#targeting-ray-pose
let inputSourcePose = ev.frame.getPose(ev.inputSource.targetRaySpace, refSpace);
@@ -618,7 +353,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
trackingSpaceHeadingDegrees += rotationDelta;
// Update tracking space origin so that origin + playerOffset == player location in world space
- vec3.sub(trackingSpaceOriginInWorldSpace, playerInWorldSpaceNew, playerOffsetInWorldSpaceNew);
+ vec3.sub(
+ trackingSpaceOriginInWorldSpace,
+ playerInWorldSpaceNew,
+ playerOffsetInWorldSpaceNew);
updateOriginOffset(session);
}
@@ -633,7 +371,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{x: invPosition[0], y: invPosition[1], z: invPosition[2]},
{x: invOrientation[0], y: invOrientation[1], z: invOrientation[2], w: invOrientation[3]});
- // Update offset reference to use a new originOffset with the teleported player position and orientation.
+ // Update offset reference to use a new originOffset with the teleported
+ // player position and orientation.
// This new offset needs to be applied to the base ref space.
let refSpace = getRefSpace(session, false).getOffsetReferenceSpace(xform);
setRefSpace(session, refSpace, true);
@@ -651,9 +390,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
}
- let invPosition = vec3.create();
- let invOrientation = quat.create();
-
function getRefSpace(session, isOffset) {
return session.mode.startsWith('immersive') ?
(isOffset ? xrImmersiveRefSpaceOffset : xrImmersiveRefSpaceBase) :
@@ -684,38 +420,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
scene.startFrame();
session.requestAnimationFrame(onXRFrame);
- function updateBoxes(box_list, rotate) {
- // Update the matrix for each box
- for (let box of box_list) {
- let node = box.node;
- mat4.identity(node.matrix);
- mat4.translate(node.matrix, node.matrix, box.position);
- if (rotate) {
- mat4.rotateX(node.matrix, node.matrix, time/1000);
- mat4.rotateY(node.matrix, node.matrix, time/1500);
- }
- }
- }
-
- for (let source of session.inputSources) {
- let gamepad = source.gamepad;
- if (gamepad) {
- ProcessGamepad(gamepad, source);
- }
- }
-
- updateBoxes(boxes, true);
- for (let hand in boxTable) {
- updateBoxes(boxTable[hand].box_list, false);
- }
- for (let hand in movableBoxes) {
- updateBoxes(movableBoxes[hand].box_list, false);
+ // Update the matrix for each box
+ for (let box of boxes) {
+ let node = box.node;
+ mat4.identity(node.matrix);
+ mat4.translate(node.matrix, node.matrix, box.position);
+ mat4.rotateX(node.matrix, node.matrix, time/1000);
+ mat4.rotateY(node.matrix, node.matrix, time/1500);
}
- // In this sample and most samples after it we'll use a helper function
- // to automatically add the right meshes for the session's input sources
- // each frame. This also does simple hit detection to position the
- // cursors correctly on the surface of selectable nodes.
scene.updateInputSources(frame, refSpace);
scene.drawXRFrame(frame, pose);
scene.endFrame();
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html b/chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
index bb9e5e1a09c..dbc2e219e3c 100644
--- a/chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
@@ -26,13 +26,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<meta name='mobile-web-app-capable' content='yes'>
<meta name='apple-mobile-web-app-capable' content='yes'>
- <!-- Origin Trial Token, feature = WebXR Device API, origin = https://immersive-web.github.io, expires = 2018-08-28 -->
-<meta http-equiv="origin-trial" data-feature="WebXR Device API" data-expires="2018-08-28" content="AnNpu7ceXvLew05ccD8Zr1OZsdZiB2hLQKK82kTTMDwF7oRKtP3QEJ4RzkeHrmB8Sq0vSV6ZNmszpBCZ0I8p9gAAAABceyJvcmlnaW4iOiJodHRwczovL2ltbWVyc2l2ZS13ZWIuZ2l0aHViLmlvOjQ0MyIsImZlYXR1cmUiOiJXZWJYUkRldmljZSIsImV4cGlyeSI6MTUzNTQxNDQwMH0=">
+ <!-- Origin Trial Token, feature = WebXR Device API (For Chrome M76+), origin = storage.googleapis.com, expires = 2019-07-24 -->
+ <meta http-equiv="origin-trial" data-feature="WebXR Device API (For Chrome M76+)" data-expires="2019-07-24" content="Ap6io/uhkGK7vXCD+golNnQfj8wJ4so790EzZoqb8YOljMXIBTvBEQFPTHYIz5d/BgtuwZTKOLrmHAOt30f38g8AAABxeyJvcmlnaW4iOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb206NDQzIiwiZmVhdHVyZSI6IldlYlhSRGV2aWNlTTc2IiwiZXhwaXJ5IjoxNTY0MDA5MzU2LCJpc1N1YmRvbWFpbiI6dHJ1ZX0=">
<title>Barebones WebXR</title>
-
<link href='css/common.css' rel='stylesheet'></link>
-
</head>
<body>
<header>
@@ -44,6 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
headset's display to a slowly changing color to prove it's working.
<a class="back" href="./index.html">Back</a>
</p>
+ <div id="warning-zone"></div>
<button id="xr-button" disabled>XR not found</button>
</details>
</header>
@@ -60,32 +59,44 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let gl = null;
function checkSupportedState() {
- // If the device allows creation of exclusive sessions enable the
- // button. If the supportsSession request is rejected, then
- // disable the button because it means that XR is not supported.
- navigator.xr.supportsSession('immersive-vr').then(() => {
- // Updates the button to start an XR session when clicked.
- xrButton.innerHTML = 'Enter XR';
- xrButton.disabled = false;
- }, () => {
- xrButton.innerHTML = 'XR not found';
- xrButton.disabled = true;
- });
+ // If the device allows creation of immersive VR sessions, enable the
+ // button. If the supportsSession request is rejected, then
+ // disable the button because it means that the desired session mode is
+ // not supported.
+ navigator.xr.supportsSession('immersive-vr').then(() => {
+ // Updates the button to start an XR session when clicked.
+ xrButton.innerHTML = 'Enter XR';
+ xrButton.disabled = false;
+ }, () => {
+ xrButton.innerHTML = 'XR not found';
+ xrButton.disabled = true;
+ });
}
- // Checks to see if WebXR is available and, if so, requests an XRDevice
- // that is connected to the system and tests it to ensure it supports the
- // desired session options.
+ // Checks to see if WebXR is available. If it is, checks if the desired
+ // session options are supported both right now and whenever a device is
+ // added or removed.
function initXR() {
- // Is WebXR available on this UA?
+ // WebXR API is only available for secure contexts. If the page is using
+ // an insecure context, add a warning message about this above the
+ // button.
+ if (!window.isSecureContext) {
+ let message = "WebXR unavailable due to insecure context";
+ document.getElementById("warning-zone").innerText = message;
+ }
+
+ // If WebXR is available on this UA, check if any devices are connected
+ // that would support an immersive VR session.
if (navigator.xr) {
- // Register our click handler
+ // Register our click handler.
+ // In the other WebXR samples, most of the button details are handled
+ // by XRDeviceButton from js/webxr-button.js.
xrButton.addEventListener('click', onButtonClicked);
- // Register for device change events, this indicates that a device has
- // been added or removed and that whether or not XR is supported has
- // likely changed.
- navigator.xr.addEventListener('devicechange',checkSupportedState);
+ // Register for device change events. This indicates that a device has
+ // been added or removed, which means that whether or not XR is
+ // supported has likely changed.
+ navigator.xr.addEventListener('devicechange', checkSupportedState);
// Just in case the devicechange event has already fired, call it now
// as well.
@@ -97,7 +108,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// session already we'll request one, and if we do we'll end it.
function onButtonClicked() {
if (!xrSession) {
- navigator.xr.requestSession('immersive-vr').then(onSessionStarted);
+ navigator.xr.requestSession('immersive-vr').then(
+ onSessionStarted,
+ onRequestSessionError);
} else {
xrSession.end();
}
@@ -106,7 +119,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Called when we've successfully acquired a XRSession. In response we
// will set up the necessary session state and kick off the frame loop.
function onSessionStarted(session) {
- session.mode = 'immersive-vr';
xrSession = session;
xrButton.innerHTML = 'Exit XR';
@@ -123,12 +135,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Use the new WebGL context to create a XRWebGLLayer and set it as the
// sessions baseLayer. This allows any content rendered to the layer to
- // be displayed on the XRDevice.
+ // be displayed on the XR Device.
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
- // Get a frame of reference, which is required for querying poses. In
- // this case an 'eye-level' frame of reference means that all poses will
- // be relative to the location where the XRDevice was first detected.
+ // Get a reference space, which is required for querying poses. In
+ // this case a 'local' reference space means that all poses will be
+ // relative to the location of the user's head at the time this
+ // reference space is first created.
session.requestReferenceSpace('local').then((refSpace) => {
xrRefSpace = refSpace;
@@ -137,6 +150,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
});
}
+ // Called when the requestSession promise was rejected with an exception.
+ function onRequestSessionError(ex) {
+ alert("Failed to start immersive VR session.");
+ console.error(ex.message);
+ }
+
// Called when the user clicks the 'Exit XR' button. In response we end
// the session.
function onEndSession(session) {
@@ -160,22 +179,26 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
function onXRFrame(t, frame) {
let session = frame.session;
- // Inform the session that we're ready for the next frame.
+ // There are a few advantages to requesting the next frame immediately
+ // instead of at the end of this function.
+ // 1) It's less likely to forget to call requestAnimationFrame in cases
+ // when onXRFrame has more complicated control flow.
+ // 2) If an exception is thrown later in this function, the render loop
+ // will still continue.
session.requestAnimationFrame(onXRFrame);
- // Get the XRDevice pose relative to the Frame of Reference we created
+ // Get the viewer pose relative to the reference space we created
// earlier.
let pose = frame.getViewerPose(xrRefSpace);
// Getting the pose may fail if, for example, tracking is lost. So we
// have to check to make sure that we got a valid pose before attempting
- // to render with it. If not in this case we'll just leave the
+ // to render with it. If not, in this case we'll just leave the
// framebuffer cleared, so tracking loss means the scene will simply
- // dissapear.
+ // disappear.
if (pose) {
-
// If we do have a valid pose, bind the WebGL layer's framebuffer,
- // which is where any content to be displayed on the XRDevice must be
+ // which is where any content to be displayed on the XR Device must be
// rendered.
gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer);
@@ -195,7 +218,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let viewport = session.renderState.baseLayer.getViewport(view);
gl.viewport(viewport.x, viewport.y,
viewport.width, viewport.height);
-
// Draw something.
}*/
}