summaryrefslogtreecommitdiff
path: root/chromium/third_party/webxr_test_pages/webxr-samples
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 16:23:34 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:37:21 +0000
commit38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch)
treec4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/third_party/webxr_test_pages/webxr-samples
parente684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff)
downloadqtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/webxr_test_pages/webxr-samples')
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/360-photos.html227
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/LICENSE.md18
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/css/common.css64
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/css/pygment_trac.css69
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/css/stylesheet.css297
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/explainer.html70
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html257
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/favicon-32x32.pngbin0 -> 1270 bytes
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/favicon-96x96.pngbin0 -> 2011 bytes
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/favicon.icobin0 -> 1150 bytes
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html206
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/index.html235
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/input-selection.html275
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html258
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/.eslintrc.json20
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/LICENSE.md18
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/README.md47
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/TODOs.md15
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js15198
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map1
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js22
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json30
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/material.js278
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/node.js450
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/primitive.js57
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/program.js114
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/renderer.js939
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/texture.js213
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/cottontail.js43
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/box-builder.js110
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/cone-builder.js78
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/primitive-stream.js239
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/loaders/gltf2.js427
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/materials/pbr.js281
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/gl-matrix.js43
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/ray.js122
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js118
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/button.js242
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/cube-sea.js263
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/drop-shadow.js119
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/gltf2.js77
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/input-renderer.js457
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/seven-segment-text.js210
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/skybox.js162
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/stats-viewer.js268
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/video.js145
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js304
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/fallback-helper.js144
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/query-args.js87
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.debug.js54
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.js53
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/third-party/dat.gui.min.js13
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js488
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js6196
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js220
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/magic-window.html216
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/mirroring.html198
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/module-tester.html301
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/positional-audio.html484
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/proposals/index.html172
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html272
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html188
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/reduced-bind-rendering.html267
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/room-scale.html212
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html315
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/stereo-video.html259
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/viewport-scaling.html230
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html206
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/xr-presentation.html244
69 files changed, 33905 insertions, 0 deletions
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/360-photos.html b/chromium/third_party/webxr_test_pages/webxr-samples/360-photos.html
new file mode 100644
index 00000000000..54158223f1c
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/360-photos.html
@@ -0,0 +1,227 @@
+<!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, 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>360 Photos</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>360 Photos</summary>
+ <p>
+ This sample demonstrates displaying a 360 degree equirectangular stereo
+ photo. It intentionally suppresses view position to ensure that the user
+ cannot move out of the photo sphere.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new SkyboxNode({
+ url: 'media/textures/chess-pano-4k.jpg',
+ displayMode: 'stereoTopBottom'
+ }));
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ // When rendering 360 photos/videos you want to ensure that the user's
+ // head is always at the center of the rendered media. Otherwise users
+ // with 6DoF hardware could walk towards the edges and see a very skewed
+ // or outright broken view of the image. To prevent that, we request a
+ // 'head-model' frame of reference, which suppresses any positional
+ // information from the headset in favor of a head and neck model based
+ // solely on the device orientation. (As an added bonus this mode may
+ // be more power efficent on some hardware!)
+ session.requestFrameOfReference('head-model').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ if (pose) {
+ let views = [];
+ for (let view of frame.views) {
+ let renderView = new WebXRView();
+ renderView.projectionMatrix = view.projectionMatrix;
+ renderView.viewMatrix = pose.getViewMatrix(view);
+ renderView.viewport = session.baseLayer.getViewport(view);
+
+ // It's important to take into account which eye the view is
+ // associated with in cases like this, since it informs which half
+ // of the stereo image should be used when rendering the view.
+ renderView.eye = view.eye
+ views.push(renderView);
+ }
+
+ scene.updateInputSources(frame, frameOfRef);
+
+ scene.drawViewArray(views);
+ }
+
+ scene.endFrame();
+ }
+
+ // Start the XR application.
+ initXR();
+ })();
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/LICENSE.md b/chromium/third_party/webxr_test_pages/webxr-samples/LICENSE.md
new file mode 100644
index 00000000000..3180b1bce3b
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/LICENSE.md
@@ -0,0 +1,18 @@
+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.
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/css/common.css b/chromium/third_party/webxr_test_pages/webxr-samples/css/common.css
new file mode 100644
index 00000000000..e161575532a
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/css/common.css
@@ -0,0 +1,64 @@
+body {
+ background-color: #F0F0F0;
+ font: 1rem/1.4 -apple-system, BlinkMacSystemFont,
+ Segoe UI, Roboto, Oxygen,
+ Ubuntu, Cantarell, Fira Sans,
+ Droid Sans, Helvetica Neue, sans-serif;
+}
+
+header {
+ position: relative;
+ z-index: 2;
+ left: 0px;
+ text-align: left;
+ max-width: 420px;
+ padding: 0.5em;
+ background-color: rgba(255, 255, 255, 0.90);
+ margin-bottom: 0.5em;
+ border-radius: 2px;
+}
+
+details summary {
+ font-size: 1.0em;
+ font-weight: bold;
+}
+
+details[open] summary {
+ font-size: 1.4em;
+ font-weight: bold;
+}
+
+header h1 {
+ margin-top: 0px;
+}
+
+canvas {
+ position: absolute;
+ z-index: 0;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ margin: 0;
+ touch-action: none;
+}
+
+.back {
+ float: right;
+ text-decoration: none;
+}
+
+.back:hover {
+ text-decoration: underline;
+}
+
+.back::before {
+ display: inline-block;
+ content: attr(data-index) '<';
+ font-weight: bold;
+ white-space: nowrap;
+ margin-right: 0.2em;
+ margin-left: 0.2em;
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/css/pygment_trac.css b/chromium/third_party/webxr_test_pages/webxr-samples/css/pygment_trac.css
new file mode 100644
index 00000000000..c6a6452d249
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/css/pygment_trac.css
@@ -0,0 +1,69 @@
+.highlight { background: #ffffff; }
+.highlight .c { color: #999988; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { font-weight: bold } /* Keyword */
+.highlight .o { font-weight: bold } /* Operator */
+.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
+.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #999999 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { font-weight: bold } /* Keyword.Constant */
+.highlight .kd { font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #009999 } /* Literal.Number */
+.highlight .s { color: #d14 } /* Literal.String */
+.highlight .na { color: #008080 } /* Name.Attribute */
+.highlight .nb { color: #0086B3 } /* Name.Builtin */
+.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
+.highlight .no { color: #008080 } /* Name.Constant */
+.highlight .ni { color: #800080 } /* Name.Entity */
+.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
+.highlight .nn { color: #555555 } /* Name.Namespace */
+.highlight .nt { color: #000080 } /* Name.Tag */
+.highlight .nv { color: #008080 } /* Name.Variable */
+.highlight .ow { font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #009999 } /* Literal.Number.Float */
+.highlight .mh { color: #009999 } /* Literal.Number.Hex */
+.highlight .mi { color: #009999 } /* Literal.Number.Integer */
+.highlight .mo { color: #009999 } /* Literal.Number.Oct */
+.highlight .sb { color: #d14 } /* Literal.String.Backtick */
+.highlight .sc { color: #d14 } /* Literal.String.Char */
+.highlight .sd { color: #d14 } /* Literal.String.Doc */
+.highlight .s2 { color: #d14 } /* Literal.String.Double */
+.highlight .se { color: #d14 } /* Literal.String.Escape */
+.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
+.highlight .si { color: #d14 } /* Literal.String.Interpol */
+.highlight .sx { color: #d14 } /* Literal.String.Other */
+.highlight .sr { color: #009926 } /* Literal.String.Regex */
+.highlight .s1 { color: #d14 } /* Literal.String.Single */
+.highlight .ss { color: #990073 } /* Literal.String.Symbol */
+.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #008080 } /* Name.Variable.Class */
+.highlight .vg { color: #008080 } /* Name.Variable.Global */
+.highlight .vi { color: #008080 } /* Name.Variable.Instance */
+.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
+
+.type-csharp .highlight .k { color: #0000FF }
+.type-csharp .highlight .kt { color: #0000FF }
+.type-csharp .highlight .nf { color: #000000; font-weight: normal }
+.type-csharp .highlight .nc { color: #2B91AF }
+.type-csharp .highlight .nn { color: #000000 }
+.type-csharp .highlight .s { color: #A31515 }
+.type-csharp .highlight .sc { color: #A31515 }
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
new file mode 100644
index 00000000000..d63a1194948
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/css/stylesheet.css
@@ -0,0 +1,297 @@
+* {
+ -moz-sizing: border-box;
+ -webkit-sizing: border-box;
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+html,
+body {
+ height: 100%;
+ width: 100%;
+}
+
+html {
+ font-size: 16px;
+}
+
+body {
+ background-color: #f1f1f1;
+ color: #333;
+ font: 1rem/1.4 -apple-system, BlinkMacSystemFont,
+ Segoe UI, Roboto, Oxygen,
+ Ubuntu, Cantarell, Fira Sans,
+ Droid Sans, Helvetica Neue, sans-serif;
+}
+
+a {
+ color: #369;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #036;
+ text-decoration: underline;
+}
+
+.link-important {
+ font-weight: bold;
+}
+
+.header {
+ padding-bottom: 2rem;
+ text-align: center;
+}
+
+#nav {
+ position: absolute;
+ top: 0;
+}
+
+#nav a {
+ display: inline-block;
+ margin-right:20px;
+ font-size: 15px;
+ opacity: 0.4;
+ padding-top: 14px;
+ color:black;
+}
+
+#nav a.selected{
+ border-top: 2px solid black;
+ opacity: 1.0;
+}
+
+.wordmark {
+ color: inherit;
+ display: block;
+}
+
+.wordmark > span {
+ background: #2ea;
+ 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-weight: 300;
+ margin-bottom: 15px;
+ max-width: 100%;
+ padding: 15px 30px;
+ transition: .25s box-shadow ease-in-out, .5s width ease-in-out;
+}
+
+.wordmark:hover {
+ text-decoration: none;
+}
+
+.wordmark:hover > span {
+ background: #2ea;
+ box-shadow: 3px 3px 0 0 rgba(0,0,0,.25);
+}
+
+.tagline {
+ color: #999;
+ font-size: 1rem;
+ font-weight: normal;
+}
+
+.device-box {
+ border-bottom: 1px solid #D8D8D8;
+ overflow: hidden;
+ max-height: 60px;
+ position: relative;
+ padding-left:72px;
+ font-size: 14px;
+ padding-bottom:20px;
+
+ -moz-transition: max-height 0.25s ease-in-out;
+ -ms-transition: max-height 0.25s ease-in-out;
+ -o-transition: max-height 0.25s ease-in-out;
+ -webkit-transition: max-height 0.25s ease-in-out;
+ transition: max-height 0.25s ease-in-out;
+}
+
+.device-box.open {
+ max-height:250px;
+}
+
+.device-box > span {
+ margin: 0.5rem 0;
+ display: block;
+}
+
+.device-box > img {
+ width: 48px;
+ /*float:left;*/
+ /*margin: 6px 8px;*/
+ position: absolute;
+ left: 11px;
+ top: 8px;
+}
+
+.device-box-header {
+ display: block;
+ padding: 23px 0 6px;
+}
+
+.carrot {
+ background-size: cover;
+ background-image: url('../images/carrot.svg');
+ display: block;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ right:20px;
+ top: 22px;
+ opacity: 0.4;
+}
+
+.device-box:hover {
+ cursor: pointer;
+}
+
+.device-box:hover > .carrot {
+ opacity: 0.8;
+}
+
+.device-box.open > .carrot {
+ -moz-transform: scaleY(-1);
+ -o-transform: scaleY(-1);
+ -webkit-transform: scaleY(-1);
+ transform: scaleY(-1);
+ filter: FlipV;
+ -ms-filter: "FlipV";
+}
+
+.devices {
+ overflow: auto;
+}
+
+@media screen and (min-width: 650px) {
+ .device-col {
+ width: 48%;
+ float: left;
+ }
+ .device-col:last-of-type{
+ margin-left: 4%;
+ }
+}
+
+.no-headset > img {
+ float:left;
+ display: inline-block;
+ width: 82px;
+ margin: 5px 20px 0px 10px;
+}
+
+
+@media screen and (max-width: 650px) {
+ .no-headset > img {
+ float: initial;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom:20px;
+ margin-top:35px;
+ }
+}
+
+
+code,
+pre {
+ font-family: Consolas, Andale Mono, Monaco,
+ Lucida Console, Liberation Mono, DejaVu Sans Mono,
+ Bitstream Vera Sans Mono, Courier New, monospace;
+}
+
+hr {
+ background-color: rgba(0,0,0,.15);
+ height: 1px;
+ padding-bottom: 2px;
+}
+
+.container {
+ max-width: 740px;
+ margin: 0 auto;
+ min-width: 300px;
+ padding: 2rem;
+ padding-top: 4rem;
+ width: 100%;
+}
+
+h3,
+h4,
+ul,
+ol,
+dl,
+p,
+blockquote {
+ margin: 1.5rem 0;
+}
+
+ul,
+ol,
+dl {
+ margin-left: 2.75rem;
+}
+
+ul {
+ list-style: none;
+}
+
+ul li:before {
+ content: "•";
+ color: #999;
+ display: inline-block;
+ margin-left: -1em;
+ width: 1em;
+}
+
+li + li {
+ margin-top: .25rem;
+}
+
+h3 {
+ border-bottom: 1px solid #ddd;
+ color: #111;
+ line-height: 1.4;
+ padding-bottom: .35rem;
+}
+
+h3 + p {
+ margin-top: 1rem;
+}
+
+p {
+ font-weight: normal;
+}
+
+iframe {
+ border: 0;
+ height: 100%;
+ width: 100%;
+}
+
+.iframe-wrap {
+ height: 600px;
+}
+
+.iframe-wrap--chrome {
+ height: 400px;
+}
+
+.iframe--chrome {
+ min-width: 400px;
+ margin-left: -15px;
+ width: 100%;
+ width: calc(100% + 35px);
+}
+
+@media only screen and (max-width: 449px) {
+ .wordmark > span {
+ display: block;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/explainer.html b/chromium/third_party/webxr_test_pages/webxr-samples/explainer.html
new file mode 100644
index 00000000000..df122075f2a
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/explainer.html
@@ -0,0 +1,70 @@
+<!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='twitter:card' content='summary'>
+ <meta name='twitter:title' content='WebXR Samples Explainer'>
+ <meta name='twitter:description' content='Overview of how the WebXR samples are designed'>
+
+ <link rel='stylesheet' href='css/stylesheet.css'>
+ <link rel='stylesheet' href='css/pygment_trac.css'>
+
+ <style>
+ h3 {
+ font-size: 1.0em;
+ margin-top: 2em;
+ }
+
+ .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 Explainer</title>
+ </head>
+ <body>
+
+ <div class='container' id='container'>
+ <header class='header'>
+ <div id='nav'>
+ <a href='./' class='selected'>Samples</a>
+ </div>
+
+ <h1><a href='' class='wordmark'><span>WebXR</span></a></h1>
+ <h2 class='tagline'>Samples Explainer</h2>
+ </header>
+
+ <main class='main' id='main'>
+ <h3>What are these?</h3>
+ <p>These samples have been created to give developers a set of simple, fun, readable apps that demonstrate various aspects of using the WebXR API. They are designed to focus on API use rather than the details of how the WebGL rendering is done.</p>
+
+ <h3>Who are they for?</h3>
+ <p>The samples will be most useful as a reference for developers that want to use the WebXR API directly in their own project or add XR functionality to their libraries. They are also handy for testing the functionality of WebXR implementations.</p>
+
+ <p>If you are using a graphics framework in your project you should check it's documentation first, as they may already have WebXR support built in! In that case, you should refer to the library documentation for details on how to use XR features.</p>
+
+ <h3>How are they formatted</h3>
+ <p>The samples are provided as web pages with heavily commented javscript code. Each page covers a single, targeted topic relating to API use. Code that has already been well commented in a previous sample will typically not be commented in subsequent samples in order to make it easier to focus on the newly introduced concepts, so if you see an uncommented code block that you don't understand check the previous samples and you will probably find the explanation that you're looking for.</p>
+
+ <h3>What's the deal with WebGL?</h3>
+ <p>Today the primary way of drawing XR content is via the <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL API</a>. WebGL provides an efficient way of rendering 3D graphics in the browser, which is great for XR applications that require high performance.</p>
+
+ <p>Unfortunately WebGL is fairly verbose and can be hard to follow for developers who aren't already familiar with it. Because of this, these samples generally avoid spending much time on the details of how the WebGL rendering is done. Otherwise they would quickly turn into WebGL tutorials with a little bit of XR on the side. Instead the focus is on how to get the necessary values from the WebXR API to feed into WebGL to ensure that the rendering is done correctly.</p>
+
+ <h3>To Framework or not to Framework?</h3>
+ <p>Most usage of WebGL today happens via frameworks that significantly simplify the creation of 3D scenes compared to using raw WebGL. Some of the more popular examples are <a href="https://threejs.org/">three.js</a>, <a href="https://www.babylonjs.com/">babylon.js</a>, and <a href="https://playcanvas.com/">PlayCanvas</a>. There's also frameworks that are specifically designed to create XR content on the web, such as <a href="https://aframe.io/">A-Frame</a> and <a href="https://facebook.github.io/react-vr/">ReactVR</a>. These are all <i>fantastic</i> libraries with their own strengths and focuses, and in general it's recommended that you find tools that suit your needs and rely on them rather than trying to build your own rendering systems from scratch.</p>
+
+ <p>However, most frameworks will also hide away the details of interacting with the WebXR API. That's generally great for users, but not terribly useful when the entire point of your code is to demonstrate how to use the API! At the same time, we don't want the WebXR logic to be obscured by hundreds of lines of WebGL calls. As a result, these samples make use of their own <a href="https://github.com/immersive-web/webxr-samples/tree/master/js/cottontail">minimalistic rendering library</a> that is specifically designed to highlight use of the WebXR API and de-emphasize the WebGL rendering logic. It is <b>not</b> recommended that you use this library in your own projects, as you will almost certainly be better served by one of the more popular, better established frameworks.</p>
+ </main>
+
+ <footer class='footer'>
+ </footer>
+ </div>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html b/chromium/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html
new file mode 100644
index 00000000000..7faceea4b94
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html
@@ -0,0 +1,257 @@
+<!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, 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>Fallback Rendering</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Fallback Rendering</summary>
+ <p>
+ This sample demonstrates a way to fallback to rendering the scene when
+ WebXR isn't available.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new Gltf2Node({url: 'media/gltf/space/space.gltf'}));
+ scene.addNode(new SkyboxNode({url: 'media/textures/milky-way-4k.png'}));
+
+ let projectionMatrix = mat4.create();
+ let viewMatrix = mat4.create();
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ // If navigator.xr is found but it doesn't have any devices, we'll
+ // need to use the fallback rendering path.
+ initFallback();
+ });
+ } else {
+ // If navigator.xr isn't present in the browser then we need to use
+ // the fallback rendering path.
+ initFallback();
+ }
+ }
+
+ // When we hit the fallback path, we'll need to initialize a few extra
+ // variables in order to render correctly.
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+
+ // Using a simple identity matrix for the view.
+ mat4.identity(viewMatrix);
+
+ // We need to track the canvas size in order to resize the WebGL
+ // backbuffer width and height, as well as update the projection matrix
+ // and adjust the viewport.
+ function onResize() {
+ gl.canvas.width = gl.canvas.offsetWidth * window.devicePixelRatio;
+ gl.canvas.height = gl.canvas.offsetHeight * window.devicePixelRatio;
+ mat4.perspective(projectionMatrix, Math.PI*0.4,
+ gl.canvas.width/gl.canvas.height,
+ 0.1, 1000.0);
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ }
+ window.addEventListener('resize', onResize);
+ onResize();
+
+ // We'll kick off the render loop using the window's
+ // requestAnimationFrame function.
+ window.requestAnimationFrame(onWindowFrame);
+ }
+
+ // Since both the XR and fallback paths need to do the same WebGL
+ // initialization code, we've moved that code out to it's own function.
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ }
+
+ function onRequestSession(device) {
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ session.requestAnimationFrame(onXRFrame);
+
+ scene.startFrame();
+
+ if (pose) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ for (let view of frame.views) {
+ let viewport = session.baseLayer.getViewport(view);
+ gl.viewport(viewport.x, viewport.y,
+ viewport.width, viewport.height);
+
+ scene.draw(view.projectionMatrix, pose.getViewMatrix(view));
+ }
+ }
+
+ scene.endFrame();
+ }
+
+ // This is the bulk of the fallback rendering loop. Notice that it looks
+ // a lot like a simplified version of the XR frame loop. Samples after
+ // this one will do some work to hide this for code readability purposes.
+ function onWindowFrame(t) {
+ window.requestAnimationFrame(onWindowFrame);
+
+ scene.startFrame();
+
+ // We can skip setting the framebuffer and viewport every frame, because
+ // it won't change from frame to frame and we're updating the viewport
+ // only when we resize for efficency.
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // We're drawing with our own projection and view matrix now, and we
+ // don't have a list of view to loop through, but otherwise all of the
+ // WebGL drawing logic is exactly the same.
+ scene.draw(projectionMatrix, viewMatrix);
+
+ scene.endFrame();
+ }
+
+ // Start the XR application.
+ initXR();
+ })();
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/favicon-32x32.png b/chromium/third_party/webxr_test_pages/webxr-samples/favicon-32x32.png
new file mode 100644
index 00000000000..2c6895444de
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/favicon-32x32.png
Binary files differ
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/favicon-96x96.png b/chromium/third_party/webxr_test_pages/webxr-samples/favicon-96x96.png
new file mode 100644
index 00000000000..1f538066d4e
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/favicon-96x96.png
Binary files differ
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/favicon.ico b/chromium/third_party/webxr_test_pages/webxr-samples/favicon.ico
new file mode 100644
index 00000000000..6f5f7be098a
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/favicon.ico
Binary files differ
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html b/chromium/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html
new file mode 100644
index 00000000000..12fa781b4d0
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html
@@ -0,0 +1,206 @@
+<!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, 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>Framebuffer Scaling</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='js/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Framebuffer Scaling</summary>
+ <p>
+ This sample demonstrates scaling the framebuffer used for a WebXR layer
+ at creation time to control the memory and fillrate required and improve
+ performance or quality as needed. (The system may clamp the actual
+ buffer sizes)
+
+ Framebuffer scaling should be used to make a performance/memory/quality
+ tradeoff for the lifetime of the session.
+ <a class="back" href="./">Back</a>
+ <br/>
+ <hr/>
+ <input id='framebufferScaleSelect' value='1.0' min='0.25' max='2.0' step='0.125' type='range'/><br/>
+ <span id='framebufferScaleLabel'></span>
+ </p>
+ </details>
+ </header>
+ <main style='text-align: center;'>
+ <p>Click 'Enter XR' to see content</p>
+ </main>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ let scaleSelect = document.getElementById('framebufferScaleSelect');
+ let scaleLabel = document.getElementById('framebufferScaleLabel');
+
+ function updateLabel() {
+ let value = parseFloat(scaleSelect.value);
+ let label = `Framebuffer scale: ${scaleSelect.value}`;
+ switch (value) {
+ case 0.5: label += ' - 50% recommended res'; break;
+ case 1.0: label += ' - Default, system recommendation'; break;
+ case 1.5: label += ' - 150% recommended res'; break;
+ case 2.0: label += ' - 200% recommended res'; break;
+ }
+ scaleLabel.innerHTML = label;
+ }
+
+ scaleSelect.addEventListener('change', updateLabel);
+ updateLabel();
+
+ // XR globals.
+ let xrButton = null;
+ let xrFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new CubeSeaNode());
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+ });
+ }
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then(onSessionStarted);
+ }
+
+ function onSessionStarted(session) {
+ xrButton.setSession(session);
+
+ session.addEventListener('end', onSessionEnded);
+
+ if (!gl) {
+ gl = createWebGLContext({
+ compatibleXRDevice: session.device
+ });
+
+ // Set up a non-black clear color so that we can see if something renders wrong.
+ gl.clearColor(0.1, 0.2, 0.3, 1.0);
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+ }
+
+ // This is the only meaningful change in this sample from xr-presentation.js.
+ // It sets a requested scale to be applied to the framebuffer created
+ // for the layer. The UA is allowed to ignore the request or adjust it
+ // as needed. The scale of the framebuffer cannot be changed after the
+ // layer is created, though the UA is allowed to resize the framebuffer
+ // at any time.
+ let scale = parseFloat(scaleSelect.value);
+ session.baseLayer = new XRWebGLLayer(session, gl, {
+ framebufferScaleFactor: scale
+ });
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ xrFrameOfRef = frameOfRef;
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+
+ gl = null;
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let pose = frame.getDevicePose(xrFrameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ scene.updateInputSources(frame, xrFrameOfRef);
+
+ 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
new file mode 100644
index 00000000000..46cdb33b65c
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/index.html
@@ -0,0 +1,235 @@
+<!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'>
+ <header class='header'>
+ <div id='nav'>
+ <a href='./' class='selected'>Samples</a>
+ <a href='proposals/'>Proposals</a>
+ <a href='tests/'>Test Pages</a>
+ </div>
+
+ <h1><a href='' class='wordmark'><span>WebXR</span></a></h1>
+ <h2 class='tagline'>Sample Pages</h2>
+ </header>
+
+ <main class='main' id='main'>
+ <p>Sample pages demonstrating how to use various aspects of the WebXR API.<br/>
+ <a href="explainer.html">Learn More</a></p>
+
+ <script>
+ let pages = [
+ { title: 'XR Presentation', category: 'Basics',
+ path: 'xr-presentation.html',
+ description: 'Demonstrates how to present a simple WebGL scene to a XRDevice.' },
+
+ { title: 'Mirroring', category: 'Basics',
+ path: 'mirroring.html',
+ description: 'Demonstrates how to mirroring exclusive session content to a canvas.' },
+
+ { title: 'Magic Window', category: 'Basics',
+ path: 'magic-window.html',
+ description: 'Demonstrates use of a non-exclusive XRSession to present "Magic Window" content.' },
+
+ { title: 'Fallback Rendering', category: 'Basics',
+ path: 'fallback-rendering.html',
+ description: 'Demonstrates a way to fallback to rendering the scene when WebXR isn\'t available..' },
+
+ { tag: 'hr' },
+ { tag: 'br' },
+
+ { title: 'Reduced-Bind Rendering', category: 'Performance',
+ path: 'reduced-bind-rendering.html',
+ description: 'Demonstrates a technique to reduce the number of state changes made while rendering.' },
+
+ { title: 'Room Scale', category: 'Basics',
+ path: 'room-scale.html',
+ description: 'Demonstrates using a "stage" frame of reference to provide room scale tracking.' },
+
+ { title: 'Input Tracking', category: 'Input',
+ 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: 'Framebuffer Scaling', category: 'Performance',
+ path: 'framebuffer-scaling.html',
+ description: 'Demonstrates scaling a layer\'s framebuffer to statically control performance or quality.' },
+
+ { title: 'Viewport Scaling', category: 'Performance',
+ path: 'viewport-scaling.html',
+ description: 'Demonstrates scaling a layer\'s viewports to dynamically control performance or quality.' },
+
+ { title: '360 Stereo Photos', category: 'Content',
+ path: '360-photos.html',
+ description: 'Demonstrates displaying a 360 degree equirectangular stereo photo.' },
+
+ { title: 'Stereo Video', category: 'Content',
+ path: 'stereo-video.html',
+ description: 'Demonstrates playing stereo videos.' },
+
+ { title: 'Positional Audio', category: 'Content',
+ path: 'positional-audio.html',
+ description: 'Demonstrates playing audio that sounds as if it originates at a specific point in the space.' },
+
+ { 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.
+ for (var i = 0; i < pages.length; ++i) {
+ var page = pages[i];
+
+ if (page.tag) {
+ mainElement.appendChild(document.createElement(page.tag));
+ continue;
+ }
+
+ let article = document.createElement('article');
+
+ let title = document.createElement('h3');
+ title.setAttribute('data-index', i + 1);
+
+ 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);
+
+ let sourceLink = document.createElement('a');
+ sourceLink.href = 'https://github.com/immersive-web/webxr-samples/blob/master/' + page.path;
+ sourceLink.innerHTML = 'Source';
+ links.appendChild(sourceLink);
+
+ 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 a 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 under the <a href="https://github.com/immersive-web/webxr-samples/tree/master/media/gltf">media/gltf</a> folders for this repository.</p>
+
+ <h3><a class='github-link' href='https://github.com/immersive-web/webxr-samples'>View samples source on GitHub</a></h3>
+
+ <footer class='footer'>
+ </footer>
+ </div>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/input-selection.html b/chromium/third_party/webxr_test_pages/webxr-samples/input-selection.html
new file mode 100644
index 00000000000..f9b815f872f
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/input-selection.html
@@ -0,0 +1,275 @@
+<!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, 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>Input Selection</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Input Selection</summary>
+ <p>
+ This sample demonstrates handling 'select' events generated by
+ XRInputSources to create clickable objects in the scene.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // Temporary
+ let hideStats = QueryArgs.getBool('hideStats', false);
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = 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 boxes = [];
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ fallbackHelper.emulateStage = true;
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+
+ // Create several boxes to use for hit testing.
+ let boxBuilder = new BoxBuilder();
+ boxBuilder.pushCube([0, 0, 0], 0.4);
+ let boxPrimitive = boxBuilder.finishPrimitive(renderer);
+
+ function addBox(x, y, z, r, g, b) {
+ let boxMaterial = new PbrMaterial();
+ boxMaterial.baseColorFactor.value = [r, g, b, 1.0];
+ let boxRenderPrimitive = renderer.createRenderPrimitive(boxPrimitive, boxMaterial);
+ let boxNode = new Node();
+ boxNode.addRenderPrimitive(boxRenderPrimitive);
+ // Marks the node as one that needs to be checked when hit testing.
+ boxNode.selectable = true;
+ boxes.push({
+ node: boxNode,
+ renderPrimitive: boxRenderPrimitive,
+ position: [x, y, z]
+ });
+ scene.addNode(boxNode);
+ }
+
+ addBox(-1.0, 1.6, -1.3, 1.0, 0.0, 0.0);
+ addBox(0.0, 1.7, -1.5, 0.0, 1.0, 0.0);
+ addBox(1.0, 1.6, -1.3, 0.0, 0.0, 1.0);
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ // By listening for the 'select' event we can find out when the user has
+ // performed some sort of primary input action and respond to it.
+ session.addEventListener('select', onSelect);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('stage').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onSelect(ev) {
+ let frameOfRef = ev.frame.session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+
+ let inputPose = ev.frame.getInputPose(ev.inputSource, frameOfRef);
+ if (!inputPose) {
+ return;
+ }
+
+ if (inputPose.targetRay) {
+ let hitResult = scene.hitTest(inputPose.targetRay)
+ if (hitResult) {
+ // Check to see if the hit result was one of our boxes.
+ for (let box of boxes) {
+ if (hitResult.node == box.node) {
+ // Change the box color to something random.
+ let uniforms = box.renderPrimitive.uniforms;
+ uniforms.baseColorFactor.value = [Math.random(), Math.random(), Math.random(), 1.0];
+ }
+ }
+ }
+ }
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function onXRFrame(time, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ // 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, frameOfRef);
+
+ 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/input-tracking.html b/chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html
new file mode 100644
index 00000000000..487289c9062
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/input-tracking.html
@@ -0,0 +1,258 @@
+<!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, 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>Input Tracking</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Input Tracking</summary>
+ <p>
+ This sample demonstrates basic tracking and rendering of
+ XRInputSources. It does not respond to button presses or other
+ controller interactions.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new Gltf2Node({url: 'media/gltf/cave/cave.gltf'}));
+ scene.addNode(new SkyboxNode({url: 'media/textures/eilenriede-park-2k.png'}));
+ scene.standingStats(true);
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ // Note: If you don't want dragging on the canvas to do things like
+ // scroll or pull-to-refresh, you'll want to set touch-action: none;
+ // on the canvas' CSS style, which this page does in common.css
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ fallbackHelper.emulateStage = true;
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+
+ // Loads a generic controller mesh.
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('stage').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function updateInputSources(session, frame, frameOfRef) {
+ let inputSources = session.getInputSources();
+
+ for (let inputSource of inputSources) {
+ let inputPose = frame.getInputPose(inputSource, frameOfRef);
+
+ // We may not get a pose back in cases where the input source has lost
+ // tracking or does not know where it is relative to the given frame
+ // of reference.
+ if (!inputPose) {
+ continue;
+ }
+
+ if (inputPose.gripMatrix) {
+ // If we have a grip matrix use it to render a mesh showing the
+ // position of the controller.
+ scene.inputRenderer.addController(inputPose.gripMatrix);
+ }
+
+ if (inputPose.targetRay) {
+ if (inputSource.targetRayMode == 'tracked-pointer') {
+ // If we have a pointer matrix and the pointer origin is the users
+ // hand (as opposed to their head or the screen) use it to render
+ // a ray coming out of the input device to indicate the pointer
+ // direction.
+ scene.inputRenderer.addLaserPointer(inputPose.targetRay);
+ }
+
+ // If we have a pointer matrix we can also use it to render a cursor
+ // for both handheld and gaze-based input sources.
+
+ // Statically render the cursor 2 meters down the ray since we're
+ // not calculating any intersections in this sample.
+ let cursorDistance = 2.0;
+ let cursorPos = vec3.fromValues(
+ inputPose.targetRay.origin.x,
+ inputPose.targetRay.origin.y,
+ inputPose.targetRay.origin.z
+ );
+ vec3.add(cursorPos, cursorPos, [
+ inputPose.targetRay.direction.x * cursorDistance,
+ inputPose.targetRay.direction.y * cursorDistance,
+ inputPose.targetRay.direction.z * cursorDistance,
+ ]);
+ // vec3.transformMat4(cursorPos, cursorPos, inputPose.targetRay.transformMatrix);
+
+ scene.inputRenderer.addCursor(cursorPos);
+ }
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ updateInputSources(session, frame, frameOfRef);
+
+ 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/js/cottontail/.eslintrc.json b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/.eslintrc.json
new file mode 100644
index 00000000000..d6719c99d62
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/.eslintrc.json
@@ -0,0 +1,20 @@
+{
+ "extends": ["eslint:recommended","google"],
+ "parserOptions": {
+ "sourceType": "module"
+ },
+ "env": {
+ "browser": true,
+ "es6": true
+ },
+ "globals": {
+ "XRWebGLLayer": true
+ },
+ "rules": {
+ "max-len": [2,120],
+ "valid-jsdoc": [0, {}],
+ "require-jsdoc": [0, {}],
+ "no-console": 0,
+ "guard-for-in": 0
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/LICENSE.md b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/LICENSE.md
new file mode 100644
index 00000000000..3180b1bce3b
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/LICENSE.md
@@ -0,0 +1,18 @@
+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.
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/README.md b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/README.md
new file mode 100644
index 00000000000..54bb914d235
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/README.md
@@ -0,0 +1,47 @@
+Cottontail
+==========================================
+A simple WebGL renderering framework optimised for demonstrating WebXR concepts.
+
+Cottontail does two things well and not much else:
+
+1) Loading and Rendering GLTF 2.0 files.
+2) Optimising for WebXR-style rendering.
+
+However it explicitly goes out of it's way to NOT wrap much, if any, WebXR
+functionality. This is because arguably it's sole purpose in life is to enable
+the WebXR samples, who's sole purpose in life is to provide easy-to-follow code
+snippets demonstrating the API use and thus anything this code did to hide the
+WebXR API's direct use is counter productive.
+
+Using Cottontail for your own projects is very much not recommended, as you will
+almost certainly be better served by one of the other more popular frameworks
+out there.
+
+**About the name:** I wanted something that evoked XR imagery without being too
+heavy handed about it. The "White Rabbit" is prominent symbol in multiple peices
+of media about virtual worlds, such as the movie _The Matrix_ and the novel
+_Rainbows End_, which has a particularly heavy focus on AR/MR. So I liked the
+idea of riffing off of that. It's also nice (though unintended) bonus that the
+Daydream logo looks a bit like a stylized rabbit tail. Finally, it's based on
+some code that I started on Easter day, 2017.
+
+The real world may rest on the back of a giant tortise, but I propose
+that the virtual one is bunnies all the way down. ;)
+
+Building
+--------
+Cottontail can be used directly by any browser with good JavaScript modules
+support, but to ensure widest compatibility (and shorter download times) using
+a version compiled into a single file is recommended. To build first install the
+[node.js](https://nodejs.org/en/) dependencies with:
+
+ `npm install`
+
+Then build with:
+
+ `npm run build-all`
+
+For faster development iteration you can also have the project rebuild with any
+code changes automatically by running:
+
+ `npm run watch`
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/TODOs.md b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/TODOs.md
new file mode 100644
index 00000000000..102aac3c315
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/TODOs.md
@@ -0,0 +1,15 @@
+Cottontail TODOs
+================
+
+ - Make texture upload use of `ImageBitmaps` when available
+ - Generally reduce use of GL enums at user level
+ - Clean up `Scene` logic, maybe rename to `WebXRSampleScene`?
+ - Node cloning has issues, doesn't handle renderer changes.
+
+Nice to haves
+-------------
+
+ - Support GLTF skeletal animations
+ - Support Draco compression
+ - "Floaties"
+ - HTML-to-texture for captions. (SVG?) \ No newline at end of file
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js
new file mode 100644
index 00000000000..40deaa60b25
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js
@@ -0,0 +1,15198 @@
+/*!
+ * 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.
+ *
+ */
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory();
+ else if(typeof define === 'function' && define.amd)
+ define([], factory);
+ else {
+ var a = factory();
+ for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
+ }
+})(window, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId]) {
+/******/ return installedModules[moduleId].exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ i: moduleId,
+/******/ l: false,
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.l = true;
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+/******/
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+/******/
+/******/ // define getter function for harmony exports
+/******/ __webpack_require__.d = function(exports, name, getter) {
+/******/ if(!__webpack_require__.o(exports, name)) {
+/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
+/******/ }
+/******/ };
+/******/
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = function(exports) {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/
+/******/ // create a fake namespace object
+/******/ // mode & 1: value is a module id, require it
+/******/ // mode & 2: merge all properties of value into the ns
+/******/ // mode & 4: return value when already ns object
+/******/ // mode & 8|1: behave like require
+/******/ __webpack_require__.t = function(value, mode) {
+/******/ if(mode & 1) value = __webpack_require__(value);
+/******/ if(mode & 8) return value;
+/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
+/******/ var ns = Object.create(null);
+/******/ __webpack_require__.r(ns);
+/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
+/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
+/******/ return ns;
+/******/ };
+/******/
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __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;
+/******/ };
+/******/
+/******/ // Object.prototype.hasOwnProperty.call
+/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+/******/
+/******/
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(__webpack_require__.s = "./src/cottontail.js");
+/******/ })
+/************************************************************************/
+/******/ ({
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/common.js":
+/*!********************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/common.js ***!
+ \********************************************************/
+/*! exports provided: EPSILON, ARRAY_TYPE, RANDOM, setMatrixArrayType, toRadian, equals */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EPSILON", function() { return EPSILON; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ARRAY_TYPE", function() { return ARRAY_TYPE; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RANDOM", function() { return RANDOM; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setMatrixArrayType", function() { return setMatrixArrayType; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toRadian", function() { return toRadian; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/**
+ * Common utilities
+ * @module glMatrix
+ */
+
+// Configuration Constants
+const EPSILON = 0.000001;
+let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
+const RANDOM = Math.random;
+
+/**
+ * Sets the type of array used when creating new vectors and matrices
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+function setMatrixArrayType(type) {
+ ARRAY_TYPE = type;
+}
+
+const degree = Math.PI / 180;
+
+/**
+ * Convert Degree To Radian
+ *
+ * @param {Number} a Angle in Degrees
+ */
+function toRadian(a) {
+ return a * degree;
+}
+
+/**
+ * Tests whether or not the arguments have approximately the same value, within an absolute
+ * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+ * than or equal to 1.0, and a relative tolerance is used for larger values)
+ *
+ * @param {Number} a The first number to test.
+ * @param {Number} b The second number to test.
+ * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+ */
+function equals(a, b) {
+ return Math.abs(a - b) <= EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b));
+}
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/mat2.js":
+/*!******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/mat2.js ***!
+ \******************************************************/
+/*! exports provided: create, clone, copy, identity, fromValues, set, transpose, invert, adjoint, determinant, multiply, rotate, scale, fromRotation, fromScaling, str, frob, LDU, add, subtract, exactEquals, equals, multiplyScalar, multiplyScalarAndAdd, mul, sub */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return identity; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transpose", function() { return transpose; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "invert", function() { return invert; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "adjoint", function() { return adjoint; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "determinant", function() { return determinant; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotate", function() { return rotate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotation", function() { return fromRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromScaling", function() { return fromScaling; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "frob", function() { return frob; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LDU", function() { return LDU; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtract", function() { return subtract; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalar", function() { return multiplyScalar; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalarAndAdd", function() { return multiplyScalarAndAdd; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+
+/**
+ * 2x2 Matrix
+ * @module mat2
+ */
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) {
+ out[1] = 0;
+ out[2] = 0;
+ }
+ out[0] = 1;
+ out[3] = 1;
+ return out;
+}
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+function clone(a) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+}
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function copy(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+}
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+function identity(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+}
+
+/**
+ * Create a new mat2 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m10 Component in column 1, row 0 position (index 2)
+ * @param {Number} m11 Component in column 1, row 1 position (index 3)
+ * @returns {mat2} out A new 2x2 matrix
+ */
+function fromValues(m00, m01, m10, m11) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4);
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m10;
+ out[3] = m11;
+ return out;
+}
+
+/**
+ * Set the components of a mat2 to the given values
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m10 Component in column 1, row 0 position (index 2)
+ * @param {Number} m11 Component in column 1, row 1 position (index 3)
+ * @returns {mat2} out
+ */
+function set(out, m00, m01, m10, m11) {
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m10;
+ out[3] = m11;
+ return out;
+}
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function transpose(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache
+ // some values
+ if (out === a) {
+ let a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+}
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function invert(out, a) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+
+ // Calculate the determinant
+ let det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+}
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function adjoint(out, a) {
+ // Caching this value is nessecary if out == a
+ let a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+}
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+ return a[0] * a[3] - a[2] * a[1];
+}
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function multiply(out, a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a2 * b1;
+ out[1] = a1 * b0 + a3 * b1;
+ out[2] = a0 * b2 + a2 * b3;
+ out[3] = a1 * b2 + a3 * b3;
+ return out;
+}
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+function rotate(out, a, rad) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+ out[0] = a0 * c + a2 * s;
+ out[1] = a1 * c + a3 * s;
+ out[2] = a0 * -s + a2 * c;
+ out[3] = a1 * -s + a3 * c;
+ return out;
+}
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+function scale(out, a, v) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ let v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v0;
+ out[2] = a2 * v1;
+ out[3] = a3 * v1;
+ return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ * mat2.identity(dest);
+ * mat2.rotate(dest, dest, rad);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+function fromRotation(out, rad) {
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+ out[0] = c;
+ out[1] = s;
+ out[2] = -s;
+ out[3] = c;
+ return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ * mat2.identity(dest);
+ * mat2.scale(dest, dest, vec);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat2} out
+ */
+function fromScaling(out, v) {
+ out[0] = v[0];
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = v[1];
+ return out;
+}
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat2
+ *
+ * @param {mat2} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+ return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))
+}
+
+/**
+ * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+ * @param {mat2} L the lower triangular matrix
+ * @param {mat2} D the diagonal matrix
+ * @param {mat2} U the upper triangular matrix
+ * @param {mat2} a the input matrix to factorize
+ */
+
+function LDU(L, D, U, a) {
+ L[2] = a[2]/a[0];
+ U[0] = a[0];
+ U[1] = a[1];
+ U[3] = a[3] - L[2] * U[1];
+ return [L, D, U];
+}
+
+/**
+ * Adds two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function subtract(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat2} a The first matrix.
+ * @param {mat2} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat2} a The first matrix.
+ * @param {mat2} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
+ Math.abs(a3 - b3) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)));
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat2} out
+ */
+function multiplyScalar(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+}
+
+/**
+ * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat2} out the receiving vector
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat2} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+}
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Alias for {@link mat2.subtract}
+ * @function
+ */
+const sub = subtract;
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/mat2d.js":
+/*!*******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/mat2d.js ***!
+ \*******************************************************/
+/*! exports provided: create, clone, copy, identity, fromValues, set, invert, determinant, multiply, rotate, scale, translate, fromRotation, fromScaling, fromTranslation, str, frob, add, subtract, multiplyScalar, multiplyScalarAndAdd, exactEquals, equals, mul, sub */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return identity; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "invert", function() { return invert; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "determinant", function() { return determinant; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotate", function() { return rotate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "translate", function() { return translate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotation", function() { return fromRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromScaling", function() { return fromScaling; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromTranslation", function() { return fromTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "frob", function() { return frob; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtract", function() { return subtract; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalar", function() { return multiplyScalar; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalarAndAdd", function() { return multiplyScalarAndAdd; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+
+/**
+ * 2x3 Matrix
+ * @module mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, c, tx,
+ * b, d, ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, c, tx,
+ * b, d, ty,
+ * 0, 0, 1]
+ * </pre>
+ * The last row is ignored so the array is shorter and operations are faster.
+ */
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](6);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) {
+ out[1] = 0;
+ out[2] = 0;
+ out[4] = 0;
+ out[5] = 0;
+ }
+ out[0] = 1;
+ out[3] = 1;
+ return out;
+}
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+function clone(a) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+}
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} 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];
+ return out;
+}
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+function identity(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+}
+
+/**
+ * Create a new mat2d with the given values
+ *
+ * @param {Number} a Component A (index 0)
+ * @param {Number} b Component B (index 1)
+ * @param {Number} c Component C (index 2)
+ * @param {Number} d Component D (index 3)
+ * @param {Number} tx Component TX (index 4)
+ * @param {Number} ty Component TY (index 5)
+ * @returns {mat2d} A new mat2d
+ */
+function fromValues(a, b, c, d, tx, ty) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](6);
+ out[0] = a;
+ out[1] = b;
+ out[2] = c;
+ out[3] = d;
+ out[4] = tx;
+ out[5] = ty;
+ return out;
+}
+
+/**
+ * Set the components of a mat2d to the given values
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {Number} a Component A (index 0)
+ * @param {Number} b Component B (index 1)
+ * @param {Number} c Component C (index 2)
+ * @param {Number} d Component D (index 3)
+ * @param {Number} tx Component TX (index 4)
+ * @param {Number} ty Component TY (index 5)
+ * @returns {mat2d} out
+ */
+function set(out, a, b, c, d, tx, ty) {
+ out[0] = a;
+ out[1] = b;
+ out[2] = c;
+ out[3] = d;
+ out[4] = tx;
+ out[5] = ty;
+ return out;
+}
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+function invert(out, a) {
+ let aa = a[0], ab = a[1], ac = a[2], ad = a[3];
+ let atx = a[4], aty = a[5];
+
+ let det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+}
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+ return a[0] * a[3] - a[1] * a[2];
+}
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function multiply(out, a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
+ let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
+ out[0] = a0 * b0 + a2 * b1;
+ out[1] = a1 * b0 + a3 * b1;
+ out[2] = a0 * b2 + a2 * b3;
+ out[3] = a1 * b2 + a3 * b3;
+ out[4] = a0 * b4 + a2 * b5 + a4;
+ out[5] = a1 * b4 + a3 * b5 + a5;
+ return out;
+}
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+function rotate(out, a, rad) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+ out[0] = a0 * c + a2 * s;
+ out[1] = a1 * c + a3 * s;
+ out[2] = a0 * -s + a2 * c;
+ out[3] = a1 * -s + a3 * c;
+ out[4] = a4;
+ out[5] = a5;
+ return out;
+}
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+function scale(out, a, v) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
+ let v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v0;
+ out[2] = a2 * v1;
+ out[3] = a3 * v1;
+ out[4] = a4;
+ out[5] = a5;
+ return out;
+}
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+function translate(out, a, v) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
+ let v0 = v[0], v1 = v[1];
+ out[0] = a0;
+ out[1] = a1;
+ out[2] = a2;
+ out[3] = a3;
+ out[4] = a0 * v0 + a2 * v1 + a4;
+ out[5] = a1 * v0 + a3 * v1 + a5;
+ return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ * mat2d.identity(dest);
+ * mat2d.rotate(dest, dest, rad);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+function fromRotation(out, rad) {
+ let s = Math.sin(rad), c = Math.cos(rad);
+ out[0] = c;
+ out[1] = s;
+ out[2] = -s;
+ out[3] = c;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ * mat2d.identity(dest);
+ * mat2d.scale(dest, dest, vec);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat2d} out
+ */
+function fromScaling(out, v) {
+ out[0] = v[0];
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = v[1];
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat2d.identity(dest);
+ * mat2d.translate(dest, dest, vec);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {vec2} v Translation vector
+ * @returns {mat2d} out
+ */
+function fromTranslation(out, v) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = v[0];
+ out[5] = v[1];
+ return out;
+}
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat2d
+ *
+ * @param {mat2d} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+ return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))
+}
+
+/**
+ * Adds two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ out[4] = a[4] + b[4];
+ out[5] = a[5] + b[5];
+ return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function subtract(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ out[4] = a[4] - b[4];
+ out[5] = a[5] - b[5];
+ return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat2d} out
+ */
+function multiplyScalar(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ out[4] = a[4] * b;
+ out[5] = a[5] * b;
+ return out;
+}
+
+/**
+ * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat2d} out the receiving vector
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat2d} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ out[4] = a[4] + (b[4] * scale);
+ out[5] = a[5] + (b[5] * scale);
+ return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat2d} a The first matrix.
+ * @param {mat2d} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat2d} a The first matrix.
+ * @param {mat2d} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
+ let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
+ Math.abs(a3 - b3) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
+ Math.abs(a4 - b4) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
+ Math.abs(a5 - b5) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a5), Math.abs(b5)));
+}
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Alias for {@link mat2d.subtract}
+ * @function
+ */
+const sub = subtract;
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/mat3.js":
+/*!******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/mat3.js ***!
+ \******************************************************/
+/*! exports provided: create, fromMat4, clone, copy, fromValues, set, identity, transpose, invert, adjoint, determinant, multiply, translate, rotate, scale, fromTranslation, fromRotation, fromScaling, fromMat2d, fromQuat, normalFromMat4, projection, str, frob, add, subtract, multiplyScalar, multiplyScalarAndAdd, exactEquals, equals, mul, sub */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromMat4", function() { return fromMat4; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return identity; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transpose", function() { return transpose; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "invert", function() { return invert; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "adjoint", function() { return adjoint; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "determinant", function() { return determinant; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "translate", function() { return translate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotate", function() { return rotate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromTranslation", function() { return fromTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotation", function() { return fromRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromScaling", function() { return fromScaling; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromMat2d", function() { return fromMat2d; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromQuat", function() { return fromQuat; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalFromMat4", function() { return normalFromMat4; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "projection", function() { return projection; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "frob", function() { return frob; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtract", function() { return subtract; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalar", function() { return multiplyScalar; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalarAndAdd", function() { return multiplyScalarAndAdd; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+
+/**
+ * 3x3 Matrix
+ * @module mat3
+ */
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](9);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["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;
+}
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+function fromMat4(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+}
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+function clone(a) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](9);
+ 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];
+ return out;
+}
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} 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];
+ return out;
+}
+
+/**
+ * Create a new mat3 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m10 Component in column 1, row 0 position (index 3)
+ * @param {Number} m11 Component in column 1, row 1 position (index 4)
+ * @param {Number} m12 Component in column 1, row 2 position (index 5)
+ * @param {Number} m20 Component in column 2, row 0 position (index 6)
+ * @param {Number} m21 Component in column 2, row 1 position (index 7)
+ * @param {Number} m22 Component in column 2, row 2 position (index 8)
+ * @returns {mat3} A new mat3
+ */
+function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](9);
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m10;
+ out[4] = m11;
+ out[5] = m12;
+ out[6] = m20;
+ out[7] = m21;
+ out[8] = m22;
+ return out;
+}
+
+/**
+ * Set the components of a mat3 to the given values
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m10 Component in column 1, row 0 position (index 3)
+ * @param {Number} m11 Component in column 1, row 1 position (index 4)
+ * @param {Number} m12 Component in column 1, row 2 position (index 5)
+ * @param {Number} m20 Component in column 2, row 0 position (index 6)
+ * @param {Number} m21 Component in column 2, row 1 position (index 7)
+ * @param {Number} m22 Component in column 2, row 2 position (index 8)
+ * @returns {mat3} out
+ */
+function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m10;
+ out[4] = m11;
+ out[5] = m12;
+ out[6] = m20;
+ out[7] = m21;
+ out[8] = m22;
+ return out;
+}
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+function identity(out) {
+ 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;
+}
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function transpose(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ let a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+}
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function invert(out, a) {
+ let a00 = a[0], a01 = a[1], a02 = a[2];
+ let a10 = a[3], a11 = a[4], a12 = a[5];
+ let a20 = a[6], a21 = a[7], a22 = a[8];
+
+ let b01 = a22 * a11 - a12 * a21;
+ let b11 = -a22 * a10 + a12 * a20;
+ let b21 = a21 * a10 - a11 * a20;
+
+ // Calculate the determinant
+ let det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+}
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function adjoint(out, a) {
+ let a00 = a[0], a01 = a[1], a02 = a[2];
+ let a10 = a[3], a11 = a[4], a12 = a[5];
+ let a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+}
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+ let a00 = a[0], a01 = a[1], a02 = a[2];
+ let a10 = a[3], a11 = a[4], a12 = a[5];
+ let a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+}
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function multiply(out, a, b) {
+ let a00 = a[0], a01 = a[1], a02 = a[2];
+ let a10 = a[3], a11 = a[4], a12 = a[5];
+ let a20 = a[6], a21 = a[7], a22 = a[8];
+
+ let b00 = b[0], b01 = b[1], b02 = b[2];
+ let b10 = b[3], b11 = b[4], b12 = b[5];
+ let b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+}
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+function translate(out, a, v) {
+ let a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+}
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+function rotate(out, a, rad) {
+ let a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+function scale(out, a, v) {
+ let x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat3.identity(dest);
+ * mat3.translate(dest, dest, vec);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {vec2} v Translation vector
+ * @returns {mat3} out
+ */
+function fromTranslation(out, v) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = v[0];
+ out[7] = v[1];
+ out[8] = 1;
+ return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ * mat3.identity(dest);
+ * mat3.rotate(dest, dest, rad);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+function fromRotation(out, rad) {
+ let s = Math.sin(rad), c = Math.cos(rad);
+
+ out[0] = c;
+ out[1] = s;
+ out[2] = 0;
+
+ out[3] = -s;
+ out[4] = c;
+ out[5] = 0;
+
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ * mat3.identity(dest);
+ * mat3.scale(dest, dest, vec);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat3} out
+ */
+function fromScaling(out, v) {
+ out[0] = v[0];
+ out[1] = 0;
+ out[2] = 0;
+
+ out[3] = 0;
+ out[4] = v[1];
+ out[5] = 0;
+
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+}
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+function fromMat2d(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+}
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+function fromQuat(out, q) {
+ 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 yx = y * x2;
+ let yy = y * y2;
+ let zx = z * x2;
+ let zy = z * y2;
+ let zz = z * z2;
+ let wx = w * x2;
+ let wy = w * y2;
+ let wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+}
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+function normalFromMat4(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;
+
+ // Calculate the determinant
+ 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] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+}
+
+/**
+ * Generates a 2D projection matrix with the given bounds
+ *
+ * @param {mat3} out mat3 frustum matrix will be written into
+ * @param {number} width Width of your gl context
+ * @param {number} height Height of gl context
+ * @returns {mat3} out
+ */
+function projection(out, width, height) {
+ out[0] = 2 / width;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = -2 / height;
+ out[5] = 0;
+ out[6] = -1;
+ out[7] = 1;
+ out[8] = 1;
+ return out;
+}
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat3
+ *
+ * @param {mat3} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+ return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))
+}
+
+/**
+ * Adds two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ out[4] = a[4] + b[4];
+ out[5] = a[5] + b[5];
+ out[6] = a[6] + b[6];
+ out[7] = a[7] + b[7];
+ out[8] = a[8] + b[8];
+ return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function subtract(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ out[4] = a[4] - b[4];
+ out[5] = a[5] - b[5];
+ out[6] = a[6] - b[6];
+ out[7] = a[7] - b[7];
+ out[8] = a[8] - b[8];
+ return out;
+}
+
+
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat3} out
+ */
+function multiplyScalar(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ out[4] = a[4] * b;
+ out[5] = a[5] * b;
+ out[6] = a[6] * b;
+ out[7] = a[7] * b;
+ out[8] = a[8] * b;
+ return out;
+}
+
+/**
+ * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat3} out the receiving vector
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat3} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ out[4] = a[4] + (b[4] * scale);
+ out[5] = a[5] + (b[5] * scale);
+ out[6] = a[6] + (b[6] * scale);
+ out[7] = a[7] + (b[7] * scale);
+ out[8] = a[8] + (b[8] * scale);
+ return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat3} a The first matrix.
+ * @param {mat3} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] &&
+ a[3] === b[3] && a[4] === b[4] && a[5] === b[5] &&
+ a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat3} a The first matrix.
+ * @param {mat3} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8];
+ let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8];
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
+ Math.abs(a3 - b3) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
+ Math.abs(a4 - b4) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
+ Math.abs(a5 - b5) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
+ Math.abs(a6 - b6) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
+ Math.abs(a7 - b7) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
+ Math.abs(a8 - b8) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a8), Math.abs(b8)));
+}
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Alias for {@link mat3.subtract}
+ * @function
+ */
+const sub = subtract;
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/mat4.js":
+/*!******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/mat4.js ***!
+ \******************************************************/
+/*! exports provided: create, clone, copy, fromValues, set, identity, transpose, invert, adjoint, determinant, multiply, translate, scale, rotate, rotateX, rotateY, rotateZ, fromTranslation, fromScaling, fromRotation, fromXRotation, fromYRotation, fromZRotation, fromRotationTranslation, fromQuat2, getTranslation, getScaling, getRotation, fromRotationTranslationScale, fromRotationTranslationScaleOrigin, fromQuat, frustum, perspective, perspectiveFromFieldOfView, ortho, lookAt, targetTo, str, frob, add, subtract, multiplyScalar, multiplyScalarAndAdd, exactEquals, equals, mul, sub */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return identity; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transpose", function() { return transpose; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "invert", function() { return invert; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "adjoint", function() { return adjoint; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "determinant", function() { return determinant; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "translate", function() { return translate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotate", function() { return rotate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateX", function() { return rotateX; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateY", function() { return rotateY; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateZ", function() { return rotateZ; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromTranslation", function() { return fromTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromScaling", function() { return fromScaling; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotation", function() { return fromRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromXRotation", function() { return fromXRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromYRotation", function() { return fromYRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromZRotation", function() { return fromZRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotationTranslation", function() { return fromRotationTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromQuat2", function() { return fromQuat2; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getTranslation", function() { return getTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getScaling", function() { return getScaling; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getRotation", function() { return getRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotationTranslationScale", function() { return fromRotationTranslationScale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotationTranslationScaleOrigin", function() { return fromRotationTranslationScaleOrigin; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromQuat", function() { return fromQuat; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "frustum", function() { return frustum; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "perspective", function() { return perspective; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "perspectiveFromFieldOfView", function() { return perspectiveFromFieldOfView; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ortho", function() { return ortho; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lookAt", function() { return lookAt; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "targetTo", function() { return targetTo; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "frob", function() { return frob; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtract", function() { return subtract; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalar", function() { return multiplyScalar; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiplyScalarAndAdd", function() { return multiplyScalarAndAdd; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+
+/**
+ * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+ * @module mat4
+ */
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](16);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["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;
+}
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+function clone(a) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](16);
+ 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;
+}
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} 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;
+}
+
+/**
+ * Create a new mat4 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m03 Component in column 0, row 3 position (index 3)
+ * @param {Number} m10 Component in column 1, row 0 position (index 4)
+ * @param {Number} m11 Component in column 1, row 1 position (index 5)
+ * @param {Number} m12 Component in column 1, row 2 position (index 6)
+ * @param {Number} m13 Component in column 1, row 3 position (index 7)
+ * @param {Number} m20 Component in column 2, row 0 position (index 8)
+ * @param {Number} m21 Component in column 2, row 1 position (index 9)
+ * @param {Number} m22 Component in column 2, row 2 position (index 10)
+ * @param {Number} m23 Component in column 2, row 3 position (index 11)
+ * @param {Number} m30 Component in column 3, row 0 position (index 12)
+ * @param {Number} m31 Component in column 3, row 1 position (index 13)
+ * @param {Number} m32 Component in column 3, row 2 position (index 14)
+ * @param {Number} m33 Component in column 3, row 3 position (index 15)
+ * @returns {mat4} A new mat4
+ */
+function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](16);
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m03;
+ out[4] = m10;
+ out[5] = m11;
+ out[6] = m12;
+ out[7] = m13;
+ out[8] = m20;
+ out[9] = m21;
+ out[10] = m22;
+ out[11] = m23;
+ out[12] = m30;
+ out[13] = m31;
+ out[14] = m32;
+ out[15] = m33;
+ return out;
+}
+
+/**
+ * Set the components of a mat4 to the given values
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m03 Component in column 0, row 3 position (index 3)
+ * @param {Number} m10 Component in column 1, row 0 position (index 4)
+ * @param {Number} m11 Component in column 1, row 1 position (index 5)
+ * @param {Number} m12 Component in column 1, row 2 position (index 6)
+ * @param {Number} m13 Component in column 1, row 3 position (index 7)
+ * @param {Number} m20 Component in column 2, row 0 position (index 8)
+ * @param {Number} m21 Component in column 2, row 1 position (index 9)
+ * @param {Number} m22 Component in column 2, row 2 position (index 10)
+ * @param {Number} m23 Component in column 2, row 3 position (index 11)
+ * @param {Number} m30 Component in column 3, row 0 position (index 12)
+ * @param {Number} m31 Component in column 3, row 1 position (index 13)
+ * @param {Number} m32 Component in column 3, row 2 position (index 14)
+ * @param {Number} m33 Component in column 3, row 3 position (index 15)
+ * @returns {mat4} out
+ */
+function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m03;
+ out[4] = m10;
+ out[5] = m11;
+ out[6] = m12;
+ out[7] = m13;
+ out[8] = m20;
+ out[9] = m21;
+ out[10] = m22;
+ out[11] = m23;
+ out[12] = m30;
+ out[13] = m31;
+ out[14] = m32;
+ out[15] = m33;
+ return out;
+}
+
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} 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;
+}
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function transpose(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ let a01 = a[1], a02 = a[2], a03 = a[3];
+ let a12 = a[6], a13 = a[7];
+ let a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+}
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} 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;
+
+ // Calculate the determinant
+ 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;
+}
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function adjoint(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];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+}
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(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;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+}
+
+/**
+ * Multiplies two mat4s
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} 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];
+
+ // Cache only the current line of the second matrix
+ 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;
+}
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+function translate(out, a, v) {
+ let x = v[0], y = v[1], z = v[2];
+ let a00, a01, a02, a03;
+ let a10, a11, a12, a13;
+ let 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;
+}
+
+/**
+ * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+function scale(out, a, v) {
+ let x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+}
+
+/**
+ * Rotates a mat4 by the given angle around the given axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+function rotate(out, a, rad, axis) {
+ let x = axis[0], y = axis[1], z = axis[2];
+ let len = Math.sqrt(x * x + y * y + z * z);
+ let s, c, t;
+ let a00, a01, a02, a03;
+ let a10, a11, a12, a13;
+ let a20, a21, a22, a23;
+ let b00, b01, b02;
+ let b10, b11, b12;
+ let b20, b21, b22;
+
+ if (len < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ 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];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateX(out, a, rad) {
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+ let a10 = a[4];
+ let a11 = a[5];
+ let a12 = a[6];
+ let a13 = a[7];
+ let a20 = a[8];
+ let a21 = a[9];
+ let a22 = a[10];
+ let a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateY(out, a, rad) {
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+ let a00 = a[0];
+ let a01 = a[1];
+ let a02 = a[2];
+ let a03 = a[3];
+ let a20 = a[8];
+ let a21 = a[9];
+ let a22 = a[10];
+ let a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateZ(out, a, rad) {
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+ let a00 = a[0];
+ let a01 = a[1];
+ let a02 = a[2];
+ let a03 = a[3];
+ let a10 = a[4];
+ let a11 = a[5];
+ let a12 = a[6];
+ let a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ 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];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, dest, vec);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+function fromTranslation(out, v) {
+ 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] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+ return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.scale(dest, dest, vec);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {vec3} v Scaling vector
+ * @returns {mat4} out
+ */
+function fromScaling(out, v) {
+ out[0] = v[0];
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = v[1];
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = v[2];
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+}
+
+/**
+ * Creates a matrix from a given angle around a given axis
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.rotate(dest, dest, rad, axis);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+function fromRotation(out, rad, axis) {
+ let x = axis[0], y = axis[1], z = axis[2];
+ let len = Math.sqrt(x * x + y * y + z * z);
+ let s, c, t;
+
+ if (len < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = x * x * t + c;
+ out[1] = y * x * t + z * s;
+ out[2] = z * x * t - y * s;
+ out[3] = 0;
+ out[4] = x * y * t - z * s;
+ out[5] = y * y * t + c;
+ out[6] = z * y * t + x * s;
+ out[7] = 0;
+ out[8] = x * z * t + y * s;
+ out[9] = y * z * t - x * s;
+ out[10] = z * z * t + c;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the X axis
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.rotateX(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromXRotation(out, rad) {
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+
+ // Perform axis-specific matrix multiplication
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = c;
+ out[6] = s;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = -s;
+ out[10] = c;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the Y axis
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.rotateY(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromYRotation(out, rad) {
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+
+ // Perform axis-specific matrix multiplication
+ out[0] = c;
+ out[1] = 0;
+ out[2] = -s;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = s;
+ out[9] = 0;
+ out[10] = c;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the Z axis
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.rotateZ(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromZRotation(out, rad) {
+ let s = Math.sin(rad);
+ let c = Math.cos(rad);
+
+ // Perform axis-specific matrix multiplication
+ out[0] = c;
+ out[1] = s;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = -s;
+ out[5] = c;
+ 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;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * let quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+function fromRotationTranslation(out, q, v) {
+ // Quaternion math
+ 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;
+}
+
+/**
+ * Creates a new mat4 from a dual quat.
+ *
+ * @param {mat4} out Matrix
+ * @param {quat2} a Dual Quaternion
+ * @returns {mat4} mat4 receiving operation result
+ */
+function fromQuat2(out, a) {
+ let translation = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3);
+ let bx = -a[0], by = -a[1], bz = -a[2], bw = a[3],
+ ax = a[4], ay = a[5], az = a[6], aw = a[7];
+
+ let magnitude = bx * bx + by * by + bz * bz + bw * bw;
+ //Only scale if it makes sense
+ if (magnitude > 0) {
+ translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+ translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+ translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+ } else {
+ translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+ translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+ translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+ }
+ fromRotationTranslation(out, a, translation);
+ return out;
+}
+
+/**
+ * Returns the translation vector component of a transformation
+ * matrix. If a matrix is built with fromRotationTranslation,
+ * the returned vector will be the same as the translation vector
+ * originally supplied.
+ * @param {vec3} out Vector to receive translation component
+ * @param {mat4} mat Matrix to be decomposed (input)
+ * @return {vec3} out
+ */
+function getTranslation(out, mat) {
+ out[0] = mat[12];
+ out[1] = mat[13];
+ out[2] = mat[14];
+
+ return out;
+}
+
+/**
+ * Returns the scaling factor component of a transformation
+ * matrix. If a matrix is built with fromRotationTranslationScale
+ * with a normalized Quaternion paramter, the returned vector will be
+ * the same as the scaling vector
+ * originally supplied.
+ * @param {vec3} out Vector to receive scaling factor component
+ * @param {mat4} mat Matrix to be decomposed (input)
+ * @return {vec3} out
+ */
+function getScaling(out, mat) {
+ let m11 = mat[0];
+ let m12 = mat[1];
+ let m13 = mat[2];
+ let m21 = mat[4];
+ let m22 = mat[5];
+ let m23 = mat[6];
+ let m31 = mat[8];
+ let m32 = mat[9];
+ let m33 = mat[10];
+
+ out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
+ out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
+ out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
+
+ return out;
+}
+
+/**
+ * Returns a quaternion representing the rotational component
+ * of a transformation matrix. If a matrix is built with
+ * fromRotationTranslation, the returned quaternion will be the
+ * same as the quaternion originally supplied.
+ * @param {quat} out Quaternion to receive the rotation component
+ * @param {mat4} mat Matrix to be decomposed (input)
+ * @return {quat} out
+ */
+function getRotation(out, mat) {
+ // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+ 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;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation, vector translation and vector scale
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * let quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ * mat4.scale(dest, scale)
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @param {vec3} s Scaling vector
+ * @returns {mat4} out
+ */
+function fromRotationTranslationScale(out, q, v, s) {
+ // Quaternion math
+ 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;
+ let sx = s[0];
+ let sy = s[1];
+ let sz = s[2];
+
+ out[0] = (1 - (yy + zz)) * sx;
+ out[1] = (xy + wz) * sx;
+ out[2] = (xz - wy) * sx;
+ out[3] = 0;
+ out[4] = (xy - wz) * sy;
+ out[5] = (1 - (xx + zz)) * sy;
+ out[6] = (yz + wx) * sy;
+ out[7] = 0;
+ out[8] = (xz + wy) * sz;
+ out[9] = (yz - wx) * sz;
+ out[10] = (1 - (xx + yy)) * sz;
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * mat4.translate(dest, origin);
+ * let quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ * mat4.scale(dest, scale)
+ * mat4.translate(dest, negativeOrigin);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @param {vec3} s Scaling vector
+ * @param {vec3} o The origin vector around which to scale and rotate
+ * @returns {mat4} out
+ */
+function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+ // Quaternion math
+ 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;
+
+ let sx = s[0];
+ let sy = s[1];
+ let sz = s[2];
+
+ let ox = o[0];
+ let oy = o[1];
+ let oz = o[2];
+
+ let out0 = (1 - (yy + zz)) * sx;
+ let out1 = (xy + wz) * sx;
+ let out2 = (xz - wy) * sx;
+ let out4 = (xy - wz) * sy;
+ let out5 = (1 - (xx + zz)) * sy;
+ let out6 = (yz + wx) * sy;
+ let out8 = (xz + wy) * sz;
+ let out9 = (yz - wx) * sz;
+ let out10 = (1 - (xx + yy)) * sz;
+
+ out[0] = out0;
+ out[1] = out1;
+ out[2] = out2;
+ out[3] = 0;
+ out[4] = out4;
+ out[5] = out5;
+ out[6] = out6;
+ out[7] = 0;
+ out[8] = out8;
+ out[9] = out9;
+ out[10] = out10;
+ out[11] = 0;
+ out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+ out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+ out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+ out[15] = 1;
+
+ return out;
+}
+
+/**
+ * Calculates a 4x4 matrix from the given quaternion
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat} q Quaternion to create matrix from
+ *
+ * @returns {mat4} out
+ */
+function fromQuat(out, q) {
+ 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 yx = y * x2;
+ let yy = y * y2;
+ let zx = z * x2;
+ let zy = z * y2;
+ let zz = z * z2;
+ let wx = w * x2;
+ let wy = w * y2;
+ let wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+}
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function frustum(out, left, right, bottom, top, near, far) {
+ let rl = 1 / (right - left);
+ let tb = 1 / (top - bottom);
+ let nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+}
+
+/**
+ * Generates a perspective projection matrix with the given bounds.
+ * Passing null/undefined/no value for far will generate infinite projection matrix.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum, can be null or Infinity
+ * @returns {mat4} 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;
+}
+
+/**
+ * Generates a perspective projection matrix with the given field of view.
+ * This is primarily useful for generating projection matrices to be used
+ * with the still experiemental WebVR API.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function perspectiveFromFieldOfView(out, fov, near, far) {
+ let upTan = Math.tan(fov.upDegrees * Math.PI/180.0);
+ let downTan = Math.tan(fov.downDegrees * Math.PI/180.0);
+ let leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0);
+ let rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0);
+ let xScale = 2.0 / (leftTan + rightTan);
+ let 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;
+}
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function ortho(out, left, right, bottom, top, near, far) {
+ let lr = 1 / (left - right);
+ let bt = 1 / (bottom - top);
+ let 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;
+}
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis.
+ * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+function lookAt(out, eye, center, up) {
+ let x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+ let eyex = eye[0];
+ let eyey = eye[1];
+ let eyez = eye[2];
+ let upx = up[0];
+ let upy = up[1];
+ let upz = up[2];
+ let centerx = center[0];
+ let centery = center[1];
+ let centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] &&
+ Math.abs(eyey - centery) < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] &&
+ Math.abs(eyez - centerz) < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) {
+ return identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+}
+
+/**
+ * Generates a matrix that makes something look at something else.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+function targetTo(out, eye, target, up) {
+ let eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2];
+
+ let z0 = eyex - target[0],
+ z1 = eyey - target[1],
+ z2 = eyez - target[2];
+
+ let len = z0*z0 + z1*z1 + z2*z2;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+ }
+
+ let x0 = upy * z2 - upz * z1,
+ x1 = upz * z0 - upx * z2,
+ x2 = upx * z1 - upy * z0;
+
+ len = x0*x0 + x1*x1 + x2*x2;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = x1;
+ out[2] = x2;
+ out[3] = 0;
+ out[4] = z1 * x2 - z2 * x1;
+ out[5] = z2 * x0 - z0 * x2;
+ out[6] = z0 * x1 - z1 * x0;
+ out[7] = 0;
+ out[8] = z0;
+ out[9] = z1;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = eyex;
+ out[13] = eyey;
+ out[14] = eyez;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat4
+ *
+ * @param {mat4} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+ return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))
+}
+
+/**
+ * Adds two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ out[4] = a[4] + b[4];
+ out[5] = a[5] + b[5];
+ out[6] = a[6] + b[6];
+ out[7] = a[7] + b[7];
+ out[8] = a[8] + b[8];
+ out[9] = a[9] + b[9];
+ out[10] = a[10] + b[10];
+ out[11] = a[11] + b[11];
+ out[12] = a[12] + b[12];
+ out[13] = a[13] + b[13];
+ out[14] = a[14] + b[14];
+ out[15] = a[15] + b[15];
+ return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function subtract(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ out[4] = a[4] - b[4];
+ out[5] = a[5] - b[5];
+ out[6] = a[6] - b[6];
+ out[7] = a[7] - b[7];
+ out[8] = a[8] - b[8];
+ out[9] = a[9] - b[9];
+ out[10] = a[10] - b[10];
+ out[11] = a[11] - b[11];
+ out[12] = a[12] - b[12];
+ out[13] = a[13] - b[13];
+ out[14] = a[14] - b[14];
+ out[15] = a[15] - b[15];
+ return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat4} out
+ */
+function multiplyScalar(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ out[4] = a[4] * b;
+ out[5] = a[5] * b;
+ out[6] = a[6] * b;
+ out[7] = a[7] * b;
+ out[8] = a[8] * b;
+ out[9] = a[9] * b;
+ out[10] = a[10] * b;
+ out[11] = a[11] * b;
+ out[12] = a[12] * b;
+ out[13] = a[13] * b;
+ out[14] = a[14] * b;
+ out[15] = a[15] * b;
+ return out;
+}
+
+/**
+ * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat4} out the receiving vector
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat4} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ out[4] = a[4] + (b[4] * scale);
+ out[5] = a[5] + (b[5] * scale);
+ out[6] = a[6] + (b[6] * scale);
+ out[7] = a[7] + (b[7] * scale);
+ out[8] = a[8] + (b[8] * scale);
+ out[9] = a[9] + (b[9] * scale);
+ out[10] = a[10] + (b[10] * scale);
+ out[11] = a[11] + (b[11] * scale);
+ out[12] = a[12] + (b[12] * scale);
+ out[13] = a[13] + (b[13] * scale);
+ out[14] = a[14] + (b[14] * scale);
+ out[15] = a[15] + (b[15] * scale);
+ return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat4} a The first matrix.
+ * @param {mat4} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&
+ a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] &&
+ a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] &&
+ a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat4} a The first matrix.
+ * @param {mat4} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ let a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7];
+ let a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11];
+ let a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];
+
+ let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ let b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7];
+ let b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11];
+ let b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];
+
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
+ Math.abs(a3 - b3) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
+ Math.abs(a4 - b4) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
+ Math.abs(a5 - b5) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
+ Math.abs(a6 - b6) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
+ Math.abs(a7 - b7) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
+ Math.abs(a8 - b8) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&
+ Math.abs(a9 - b9) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&
+ Math.abs(a10 - b10) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&
+ Math.abs(a11 - b11) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&
+ Math.abs(a12 - b12) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&
+ Math.abs(a13 - b13) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&
+ Math.abs(a14 - b14) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&
+ Math.abs(a15 - b15) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a15), Math.abs(b15)));
+}
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Alias for {@link mat4.subtract}
+ * @function
+ */
+const sub = subtract;
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/quat.js":
+/*!******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/quat.js ***!
+ \******************************************************/
+/*! exports provided: create, identity, setAxisAngle, getAxisAngle, multiply, rotateX, rotateY, rotateZ, calculateW, slerp, random, invert, conjugate, fromMat3, fromEuler, str, clone, fromValues, copy, set, add, mul, scale, dot, lerp, length, len, squaredLength, sqrLen, normalize, exactEquals, equals, rotationTo, sqlerp, setAxes */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return identity; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setAxisAngle", function() { return setAxisAngle; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getAxisAngle", function() { return getAxisAngle; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateX", function() { return rotateX; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateY", function() { return rotateY; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateZ", function() { return rotateZ; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "calculateW", function() { return calculateW; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "slerp", function() { return slerp; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "random", function() { return random; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "invert", function() { return invert; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "conjugate", function() { return conjugate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromMat3", function() { return fromMat3; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromEuler", function() { return fromEuler; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dot", function() { return dot; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lerp", function() { return lerp; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "length", function() { return length; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredLength", function() { return squaredLength; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotationTo", function() { return rotationTo; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqlerp", function() { return sqlerp; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setAxes", function() { return setAxes; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+/* harmony import */ var _mat3_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mat3.js */ "./node_modules/gl-matrix/src/gl-matrix/mat3.js");
+/* harmony import */ var _vec3_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./vec3.js */ "./node_modules/gl-matrix/src/gl-matrix/vec3.js");
+/* harmony import */ var _vec4_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./vec4.js */ "./node_modules/gl-matrix/src/gl-matrix/vec4.js");
+
+
+
+
+
+/**
+ * Quaternion
+ * @module quat
+ */
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ }
+ out[3] = 1;
+ return out;
+}
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+function identity(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+}
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} 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;
+}
+
+/**
+ * Gets the rotation axis and angle for a given
+ * quaternion. If a quaternion is created with
+ * setAxisAngle, this method will return the same
+ * values as providied in the original parameter list
+ * OR functionally equivalent values.
+ * Example: The quaternion formed by axis [0, 0, 1] and
+ * angle -90 is the same as the quaternion formed by
+ * [0, 0, 1] and 270. This method favors the latter.
+ * @param {vec3} out_axis Vector receiving the axis of rotation
+ * @param {quat} q Quaternion to be decomposed
+ * @return {Number} Angle, in radians, of the rotation
+ */
+function getAxisAngle(out_axis, q) {
+ let rad = Math.acos(q[3]) * 2.0;
+ let s = Math.sin(rad / 2.0);
+ if (s > _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) {
+ out_axis[0] = q[0] / s;
+ out_axis[1] = q[1] / s;
+ out_axis[2] = q[2] / s;
+ } else {
+ // If s is zero, return any axis (no rotation - axis does not matter)
+ out_axis[0] = 1;
+ out_axis[1] = 0;
+ out_axis[2] = 0;
+ }
+ return rad;
+}
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+function multiply(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;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateX(out, a, rad) {
+ rad *= 0.5;
+
+ let ax = a[0], ay = a[1], az = a[2], aw = a[3];
+ let bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateY(out, a, rad) {
+ rad *= 0.5;
+
+ let ax = a[0], ay = a[1], az = a[2], aw = a[3];
+ let by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateZ(out, a, rad) {
+ rad *= 0.5;
+
+ let ax = a[0], ay = a[1], az = a[2], aw = a[3];
+ let bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+}
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+function calculateW(out, a) {
+ let x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+}
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {quat} out
+ */
+function slerp(out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+ 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;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ 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;
+}
+
+/**
+ * Generates a random quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+function random(out) {
+ // Implementation of http://planning.cs.uiuc.edu/node198.html
+ // TODO: Calling random 3 times is probably not the fastest solution
+ let u1 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]();
+ let u2 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]();
+ let u3 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]();
+
+ let sqrt1MinusU1 = Math.sqrt(1 - u1);
+ let sqrtU1 = Math.sqrt(u1);
+
+ out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+ out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+ out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+ out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+ return out;
+}
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+function invert(out, a) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ let dot = a0*a0 + a1*a1 + a2*a2 + a3*a3;
+ let invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+}
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+function conjugate(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+}
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+function fromMat3(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ let fTrace = m[0] + m[4] + m[8];
+ let fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[5]-m[7])*fRoot;
+ out[1] = (m[6]-m[2])*fRoot;
+ out[2] = (m[1]-m[3])*fRoot;
+ } else {
+ // |w| <= 1/2
+ 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;
+}
+
+/**
+ * Creates a quaternion from the given euler angle x, y, z.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {x} Angle to rotate around X axis in degrees.
+ * @param {y} Angle to rotate around Y axis in degrees.
+ * @param {z} Angle to rotate around Z axis in degrees.
+ * @returns {quat} out
+ * @function
+ */
+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;
+}
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+const clone = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["clone"];
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+const fromValues = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["fromValues"];
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+const copy = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["copy"];
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+const set = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["set"];
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+const add = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["add"];
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+const scale = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["scale"];
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+const dot = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["dot"];
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+const lerp = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["lerp"];
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+const length = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["length"];
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+const len = length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+const squaredLength = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["squaredLength"];
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+const sqrLen = squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+const normalize = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["normalize"];
+
+/**
+ * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {quat} a The first quaternion.
+ * @param {quat} b The second quaternion.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+const exactEquals = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["exactEquals"];
+
+/**
+ * Returns whether or not the quaternions have approximately the same elements in the same position.
+ *
+ * @param {quat} a The first vector.
+ * @param {quat} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+const equals = _vec4_js__WEBPACK_IMPORTED_MODULE_3__["equals"];
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+const rotationTo = (function() {
+ let tmpvec3 = _vec3_js__WEBPACK_IMPORTED_MODULE_2__["create"]();
+ let xUnitVec3 = _vec3_js__WEBPACK_IMPORTED_MODULE_2__["fromValues"](1,0,0);
+ let yUnitVec3 = _vec3_js__WEBPACK_IMPORTED_MODULE_2__["fromValues"](0,1,0);
+
+ return function(out, a, b) {
+ let dot = _vec3_js__WEBPACK_IMPORTED_MODULE_2__["dot"](a, b);
+ if (dot < -0.999999) {
+ _vec3_js__WEBPACK_IMPORTED_MODULE_2__["cross"](tmpvec3, xUnitVec3, a);
+ if (_vec3_js__WEBPACK_IMPORTED_MODULE_2__["len"](tmpvec3) < 0.000001)
+ _vec3_js__WEBPACK_IMPORTED_MODULE_2__["cross"](tmpvec3, yUnitVec3, a);
+ _vec3_js__WEBPACK_IMPORTED_MODULE_2__["normalize"](tmpvec3, tmpvec3);
+ setAxisAngle(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 {
+ _vec3_js__WEBPACK_IMPORTED_MODULE_2__["cross"](tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Performs a spherical linear interpolation with two control points
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {quat} c the third operand
+ * @param {quat} d the fourth operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {quat} out
+ */
+const sqlerp = (function () {
+ let temp1 = create();
+ let temp2 = create();
+
+ 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;
+ };
+}());
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+const setAxes = (function() {
+ let matr = _mat3_js__WEBPACK_IMPORTED_MODULE_1__["create"]();
+
+ 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(out, fromMat3(out, matr));
+ };
+})();
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/quat2.js":
+/*!*******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/quat2.js ***!
+ \*******************************************************/
+/*! exports provided: create, clone, fromValues, fromRotationTranslationValues, fromRotationTranslation, fromTranslation, fromRotation, fromMat4, copy, identity, set, getReal, getDual, setReal, setDual, getTranslation, translate, rotateX, rotateY, rotateZ, rotateByQuatAppend, rotateByQuatPrepend, rotateAroundAxis, add, multiply, mul, scale, dot, lerp, invert, conjugate, length, len, squaredLength, sqrLen, normalize, str, exactEquals, equals */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotationTranslationValues", function() { return fromRotationTranslationValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotationTranslation", function() { return fromRotationTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromTranslation", function() { return fromTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromRotation", function() { return fromRotation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromMat4", function() { return fromMat4; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return identity; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getReal", function() { return getReal; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getDual", function() { return getDual; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setReal", function() { return setReal; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setDual", function() { return setDual; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getTranslation", function() { return getTranslation; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "translate", function() { return translate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateX", function() { return rotateX; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateY", function() { return rotateY; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateZ", function() { return rotateZ; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateByQuatAppend", function() { return rotateByQuatAppend; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateByQuatPrepend", function() { return rotateByQuatPrepend; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateAroundAxis", function() { return rotateAroundAxis; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dot", function() { return dot; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lerp", function() { return lerp; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "invert", function() { return invert; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "conjugate", function() { return conjugate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "length", function() { return length; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredLength", function() { return squaredLength; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+/* harmony import */ var _quat_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./quat.js */ "./node_modules/gl-matrix/src/gl-matrix/quat.js");
+/* harmony import */ var _mat4_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mat4.js */ "./node_modules/gl-matrix/src/gl-matrix/mat4.js");
+
+
+
+
+/**
+ * Dual Quaternion<br>
+ * Format: [real, dual]<br>
+ * Quaternion format: XYZW<br>
+ * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+ * @module quat2
+ */
+
+
+/**
+ * Creates a new identity dual quat
+ *
+ * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+ */
+function create() {
+ let dq = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](8);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) {
+ dq[0] = 0;
+ dq[1] = 0;
+ dq[2] = 0;
+ dq[4] = 0;
+ dq[5] = 0;
+ dq[6] = 0;
+ dq[7] = 0;
+ }
+ dq[3] = 1;
+ return dq;
+}
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat2} a dual quaternion to clone
+ * @returns {quat2} new dual quaternion
+ * @function
+ */
+function clone(a) {
+ let dq = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](8);
+ dq[0] = a[0];
+ dq[1] = a[1];
+ dq[2] = a[2];
+ dq[3] = a[3];
+ dq[4] = a[4];
+ dq[5] = a[5];
+ dq[6] = a[6];
+ dq[7] = a[7];
+ return dq;
+}
+
+/**
+ * Creates a new dual quat initialized with the given values
+ *
+ * @param {Number} x1 X component
+ * @param {Number} y1 Y component
+ * @param {Number} z1 Z component
+ * @param {Number} w1 W component
+ * @param {Number} x2 X component
+ * @param {Number} y2 Y component
+ * @param {Number} z2 Z component
+ * @param {Number} w2 W component
+ * @returns {quat2} new dual quaternion
+ * @function
+ */
+function fromValues(x1, y1, z1, w1, x2, y2, z2, w2) {
+ let dq = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](8);
+ dq[0] = x1;
+ dq[1] = y1;
+ dq[2] = z1;
+ dq[3] = w1;
+ dq[4] = x2;
+ dq[5] = y2;
+ dq[6] = z2;
+ dq[7] = w2;
+ return dq;
+}
+
+/**
+ * Creates a new dual quat from the given values (quat and translation)
+ *
+ * @param {Number} x1 X component
+ * @param {Number} y1 Y component
+ * @param {Number} z1 Z component
+ * @param {Number} w1 W component
+ * @param {Number} x2 X component (translation)
+ * @param {Number} y2 Y component (translation)
+ * @param {Number} z2 Z component (translation)
+ * @returns {quat2} new dual quaternion
+ * @function
+ */
+function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+ let dq = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](8);
+ dq[0] = x1;
+ dq[1] = y1;
+ dq[2] = z1;
+ dq[3] = w1;
+ let ax = x2 * 0.5,
+ ay = y2 * 0.5,
+ az = z2 * 0.5;
+ dq[4] = ax * w1 + ay * z1 - az * y1;
+ dq[5] = ay * w1 + az * x1 - ax * z1;
+ dq[6] = az * w1 + ax * y1 - ay * x1;
+ dq[7] = -ax * x1 - ay * y1 - az * z1;
+ return dq;
+}
+
+/**
+ * Creates a dual quat from a quaternion and a translation
+ *
+ * @param {quat2} dual quaternion receiving operation result
+ * @param {quat} q quaternion
+ * @param {vec3} t tranlation vector
+ * @returns {quat2} dual quaternion receiving operation result
+ * @function
+ */
+function fromRotationTranslation(out, q, t) {
+ let ax = t[0] * 0.5,
+ ay = t[1] * 0.5,
+ az = t[2] * 0.5,
+ bx = q[0],
+ by = q[1],
+ bz = q[2],
+ bw = q[3];
+ out[0] = bx;
+ out[1] = by;
+ out[2] = bz;
+ out[3] = bw;
+ out[4] = ax * bw + ay * bz - az * by;
+ out[5] = ay * bw + az * bx - ax * bz;
+ out[6] = az * bw + ax * by - ay * bx;
+ out[7] = -ax * bx - ay * by - az * bz;
+ return out;
+}
+
+/**
+ * Creates a dual quat from a translation
+ *
+ * @param {quat2} dual quaternion receiving operation result
+ * @param {vec3} t translation vector
+ * @returns {quat2} dual quaternion receiving operation result
+ * @function
+ */
+function fromTranslation(out, t) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = t[0] * 0.5;
+ out[5] = t[1] * 0.5;
+ out[6] = t[2] * 0.5;
+ out[7] = 0;
+ return out;
+}
+
+/**
+ * Creates a dual quat from a quaternion
+ *
+ * @param {quat2} dual quaternion receiving operation result
+ * @param {quat} q the quaternion
+ * @returns {quat2} dual quaternion receiving operation result
+ * @function
+ */
+function fromRotation(out, q) {
+ out[0] = q[0];
+ out[1] = q[1];
+ out[2] = q[2];
+ out[3] = q[3];
+ out[4] = 0;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ return out;
+}
+
+/**
+ * Creates a new dual quat from a matrix (4x4)
+ *
+ * @param {quat2} out the dual quaternion
+ * @param {mat4} a the matrix
+ * @returns {quat2} dual quat receiving operation result
+ * @function
+ */
+function fromMat4(out, a) {
+ //TODO Optimize this
+ let outer = _quat_js__WEBPACK_IMPORTED_MODULE_1__["create"]();
+ _mat4_js__WEBPACK_IMPORTED_MODULE_2__["getRotation"](outer, a);
+ let t = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3);
+ _mat4_js__WEBPACK_IMPORTED_MODULE_2__["getTranslation"](t, a);
+ fromRotationTranslation(out, outer, t);
+ return out;
+}
+
+/**
+ * Copy the values from one dual quat to another
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the source dual quaternion
+ * @returns {quat2} out
+ * @function
+ */
+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];
+ return out;
+}
+
+/**
+ * Set a dual quat to the identity dual quaternion
+ *
+ * @param {quat2} out the receiving quaternion
+ * @returns {quat2} out
+ */
+function identity(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ return out;
+}
+
+/**
+ * Set the components of a dual quat to the given values
+ *
+ * @param {quat2} out the receiving quaternion
+ * @param {Number} x1 X component
+ * @param {Number} y1 Y component
+ * @param {Number} z1 Z component
+ * @param {Number} w1 W component
+ * @param {Number} x2 X component
+ * @param {Number} y2 Y component
+ * @param {Number} z2 Z component
+ * @param {Number} w2 W component
+ * @returns {quat2} out
+ * @function
+ */
+function set(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+ out[0] = x1;
+ out[1] = y1;
+ out[2] = z1;
+ out[3] = w1;
+
+ out[4] = x2;
+ out[5] = y2;
+ out[6] = z2;
+ out[7] = w2;
+ return out;
+}
+
+/**
+ * Gets the real part of a dual quat
+ * @param {quat} out real part
+ * @param {quat2} a Dual Quaternion
+ * @return {quat} real part
+ */
+const getReal = _quat_js__WEBPACK_IMPORTED_MODULE_1__["copy"];
+
+/**
+ * Gets the dual part of a dual quat
+ * @param {quat} out dual part
+ * @param {quat2} a Dual Quaternion
+ * @return {quat} dual part
+ */
+function getDual(out, a) {
+ out[0] = a[4];
+ out[1] = a[5];
+ out[2] = a[6];
+ out[3] = a[7];
+ return out;
+}
+
+/**
+ * Set the real component of a dual quat to the given quaternion
+ *
+ * @param {quat2} out the receiving quaternion
+ * @param {quat} q a quaternion representing the real part
+ * @returns {quat2} out
+ * @function
+ */
+const setReal = _quat_js__WEBPACK_IMPORTED_MODULE_1__["copy"];
+
+/**
+ * Set the dual component of a dual quat to the given quaternion
+ *
+ * @param {quat2} out the receiving quaternion
+ * @param {quat} q a quaternion representing the dual part
+ * @returns {quat2} out
+ * @function
+ */
+function setDual(out, q) {
+ out[4] = q[0];
+ out[5] = q[1];
+ out[6] = q[2];
+ out[7] = q[3];
+ return out;
+}
+
+/**
+ * Gets the translation of a normalized dual quat
+ * @param {vec3} out translation
+ * @param {quat2} a Dual Quaternion to be decomposed
+ * @return {vec3} translation
+ */
+function getTranslation(out, a) {
+ let ax = a[4],
+ ay = a[5],
+ az = a[6],
+ aw = a[7],
+ bx = -a[0],
+ by = -a[1],
+ bz = -a[2],
+ bw = a[3];
+ out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+ out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+ out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+ return out;
+}
+
+/**
+ * Translates a dual quat by the given vector
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the dual quaternion to translate
+ * @param {vec3} v vector to translate by
+ * @returns {quat2} out
+ */
+function translate(out, a, v) {
+ let ax1 = a[0],
+ ay1 = a[1],
+ az1 = a[2],
+ aw1 = a[3],
+ bx1 = v[0] * 0.5,
+ by1 = v[1] * 0.5,
+ bz1 = v[2] * 0.5,
+ ax2 = a[4],
+ ay2 = a[5],
+ az2 = a[6],
+ aw2 = a[7];
+ out[0] = ax1;
+ out[1] = ay1;
+ out[2] = az1;
+ out[3] = aw1;
+ out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+ out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+ out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+ out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+ return out;
+}
+
+/**
+ * Rotates a dual quat around the X axis
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the dual quaternion to rotate
+ * @param {number} rad how far should the rotation be
+ * @returns {quat2} out
+ */
+function rotateX(out, a, rad) {
+ let bx = -a[0],
+ by = -a[1],
+ bz = -a[2],
+ bw = a[3],
+ ax = a[4],
+ ay = a[5],
+ az = a[6],
+ aw = a[7],
+ ax1 = ax * bw + aw * bx + ay * bz - az * by,
+ ay1 = ay * bw + aw * by + az * bx - ax * bz,
+ az1 = az * bw + aw * bz + ax * by - ay * bx,
+ aw1 = aw * bw - ax * bx - ay * by - az * bz;
+ _quat_js__WEBPACK_IMPORTED_MODULE_1__["rotateX"](out, a, rad);
+ bx = out[0];
+ by = out[1];
+ bz = out[2];
+ bw = out[3];
+ out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+ out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+ out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+ out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+ return out;
+}
+
+/**
+ * Rotates a dual quat around the Y axis
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the dual quaternion to rotate
+ * @param {number} rad how far should the rotation be
+ * @returns {quat2} out
+ */
+function rotateY(out, a, rad) {
+ let bx = -a[0],
+ by = -a[1],
+ bz = -a[2],
+ bw = a[3],
+ ax = a[4],
+ ay = a[5],
+ az = a[6],
+ aw = a[7],
+ ax1 = ax * bw + aw * bx + ay * bz - az * by,
+ ay1 = ay * bw + aw * by + az * bx - ax * bz,
+ az1 = az * bw + aw * bz + ax * by - ay * bx,
+ aw1 = aw * bw - ax * bx - ay * by - az * bz;
+ _quat_js__WEBPACK_IMPORTED_MODULE_1__["rotateY"](out, a, rad);
+ bx = out[0];
+ by = out[1];
+ bz = out[2];
+ bw = out[3];
+ out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+ out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+ out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+ out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+ return out;
+}
+
+/**
+ * Rotates a dual quat around the Z axis
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the dual quaternion to rotate
+ * @param {number} rad how far should the rotation be
+ * @returns {quat2} out
+ */
+function rotateZ(out, a, rad) {
+ let bx = -a[0],
+ by = -a[1],
+ bz = -a[2],
+ bw = a[3],
+ ax = a[4],
+ ay = a[5],
+ az = a[6],
+ aw = a[7],
+ ax1 = ax * bw + aw * bx + ay * bz - az * by,
+ ay1 = ay * bw + aw * by + az * bx - ax * bz,
+ az1 = az * bw + aw * bz + ax * by - ay * bx,
+ aw1 = aw * bw - ax * bx - ay * by - az * bz;
+ _quat_js__WEBPACK_IMPORTED_MODULE_1__["rotateZ"](out, a, rad);
+ bx = out[0];
+ by = out[1];
+ bz = out[2];
+ bw = out[3];
+ out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+ out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+ out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+ out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+ return out;
+}
+
+/**
+ * Rotates a dual quat by a given quaternion (a * q)
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the dual quaternion to rotate
+ * @param {quat} q quaternion to rotate by
+ * @returns {quat2} out
+ */
+function rotateByQuatAppend(out, a, q) {
+ let qx = q[0],
+ qy = q[1],
+ qz = q[2],
+ qw = q[3],
+ ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+
+ out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+ out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+ out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+ out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+ ax = a[4];
+ ay = a[5];
+ az = a[6];
+ aw = a[7];
+ out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+ out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+ out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+ out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+ return out;
+}
+
+/**
+ * Rotates a dual quat by a given quaternion (q * a)
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat} q quaternion to rotate by
+ * @param {quat2} a the dual quaternion to rotate
+ * @returns {quat2} out
+ */
+function rotateByQuatPrepend(out, q, a) {
+ let qx = q[0],
+ qy = q[1],
+ qz = q[2],
+ qw = q[3],
+ bx = a[0],
+ by = a[1],
+ bz = a[2],
+ bw = a[3];
+
+ out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+ out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+ out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+ out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+ bx = a[4];
+ by = a[5];
+ bz = a[6];
+ bw = a[7];
+ out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+ out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+ out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+ out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+ return out;
+}
+
+/**
+ * Rotates a dual quat around a given axis. Does the normalisation automatically
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the dual quaternion to rotate
+ * @param {vec3} axis the axis to rotate around
+ * @param {Number} rad how far the rotation should be
+ * @returns {quat2} out
+ */
+function rotateAroundAxis(out, a, axis, rad) {
+ //Special case for rad = 0
+ if (Math.abs(rad) < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) {
+ return copy(out, a);
+ }
+ let axisLength = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
+
+ rad = rad * 0.5;
+ let s = Math.sin(rad);
+ let bx = s * axis[0] / axisLength;
+ let by = s * axis[1] / axisLength;
+ let bz = s * axis[2] / axisLength;
+ let bw = Math.cos(rad);
+
+ let ax1 = a[0],
+ ay1 = a[1],
+ az1 = a[2],
+ aw1 = a[3];
+ out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+ out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+ out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+ out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+
+ let ax = a[4],
+ ay = a[5],
+ az = a[6],
+ aw = a[7];
+ out[4] = ax * bw + aw * bx + ay * bz - az * by;
+ out[5] = ay * bw + aw * by + az * bx - ax * bz;
+ out[6] = az * bw + aw * bz + ax * by - ay * bx;
+ out[7] = aw * bw - ax * bx - ay * by - az * bz;
+
+ return out;
+}
+
+/**
+ * Adds two dual quat's
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @returns {quat2} out
+ * @function
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ out[4] = a[4] + b[4];
+ out[5] = a[5] + b[5];
+ out[6] = a[6] + b[6];
+ out[7] = a[7] + b[7];
+ return out;
+}
+
+/**
+ * Multiplies two dual quat's
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @returns {quat2} out
+ */
+function multiply(out, a, b) {
+ let ax0 = a[0],
+ ay0 = a[1],
+ az0 = a[2],
+ aw0 = a[3],
+ bx1 = b[4],
+ by1 = b[5],
+ bz1 = b[6],
+ bw1 = b[7],
+ ax1 = a[4],
+ ay1 = a[5],
+ az1 = a[6],
+ aw1 = a[7],
+ bx0 = b[0],
+ by0 = b[1],
+ bz0 = b[2],
+ bw0 = b[3];
+ out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+ out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+ out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+ out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+ out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+ out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+ out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+ out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+ return out;
+}
+
+/**
+ * Alias for {@link quat2.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Scales a dual quat by a scalar number
+ *
+ * @param {quat2} out the receiving dual quat
+ * @param {quat2} a the dual quat to scale
+ * @param {Number} b amount to scale the dual quat by
+ * @returns {quat2} out
+ * @function
+ */
+function scale(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ out[4] = a[4] * b;
+ out[5] = a[5] * b;
+ out[6] = a[6] * b;
+ out[7] = a[7] * b;
+ return out;
+}
+
+/**
+ * Calculates the dot product of two dual quat's (The dot product of the real parts)
+ *
+ * @param {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+const dot = _quat_js__WEBPACK_IMPORTED_MODULE_1__["dot"];
+
+/**
+ * Performs a linear interpolation between two dual quats's
+ * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+ *
+ * @param {quat2} out the receiving dual quat
+ * @param {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {quat2} out
+ */
+function lerp(out, a, b, t) {
+ let mt = 1 - t;
+ if (dot(a, b) < 0) t = -t;
+
+ out[0] = a[0] * mt + b[0] * t;
+ out[1] = a[1] * mt + b[1] * t;
+ out[2] = a[2] * mt + b[2] * t;
+ out[3] = a[3] * mt + b[3] * t;
+ out[4] = a[4] * mt + b[4] * t;
+ out[5] = a[5] * mt + b[5] * t;
+ out[6] = a[6] * mt + b[6] * t;
+ out[7] = a[7] * mt + b[7] * t;
+
+ return out;
+}
+
+/**
+ * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a dual quat to calculate inverse of
+ * @returns {quat2} out
+ */
+function invert(out, a) {
+ let sqlen = squaredLength(a);
+ out[0] = -a[0] / sqlen;
+ out[1] = -a[1] / sqlen;
+ out[2] = -a[2] / sqlen;
+ out[3] = a[3] / sqlen;
+ out[4] = -a[4] / sqlen;
+ out[5] = -a[5] / sqlen;
+ out[6] = -a[6] / sqlen;
+ out[7] = a[7] / sqlen;
+ return out;
+}
+
+/**
+ * Calculates the conjugate of a dual quat
+ * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+ *
+ * @param {quat2} out the receiving quaternion
+ * @param {quat2} a quat to calculate conjugate of
+ * @returns {quat2} out
+ */
+function conjugate(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];
+ return out;
+}
+
+/**
+ * Calculates the length of a dual quat
+ *
+ * @param {quat2} a dual quat to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+const length = _quat_js__WEBPACK_IMPORTED_MODULE_1__["length"];
+
+/**
+ * Alias for {@link quat2.length}
+ * @function
+ */
+const len = length;
+
+/**
+ * Calculates the squared length of a dual quat
+ *
+ * @param {quat2} a dual quat to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+const squaredLength = _quat_js__WEBPACK_IMPORTED_MODULE_1__["squaredLength"];
+
+/**
+ * Alias for {@link quat2.squaredLength}
+ * @function
+ */
+const sqrLen = squaredLength;
+
+/**
+ * Normalize a dual quat
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a dual quaternion to normalize
+ * @returns {quat2} out
+ * @function
+ */
+function normalize(out, a) {
+ let magnitude = squaredLength(a);
+ if (magnitude > 0) {
+ magnitude = Math.sqrt(magnitude);
+
+ let a0 = a[0] / magnitude;
+ let a1 = a[1] / magnitude;
+ let a2 = a[2] / magnitude;
+ let a3 = a[3] / magnitude;
+
+ let b0 = a[4];
+ let b1 = a[5];
+ let b2 = a[6];
+ let b3 = a[7];
+
+ let a_dot_b = (a0 * b0) + (a1 * b1) + (a2 * b2) + (a3 * b3);
+
+ out[0] = a0;
+ out[1] = a1;
+ out[2] = a2;
+ out[3] = a3;
+
+ out[4] = (b0 - (a0 * a_dot_b)) / magnitude;
+ out[5] = (b1 - (a1 * a_dot_b)) / magnitude;
+ out[6] = (b2 - (a2 * a_dot_b)) / magnitude;
+ out[7] = (b3 - (a3 * a_dot_b)) / magnitude;
+ }
+ return out;
+}
+
+/**
+ * Returns a string representation of a dual quatenion
+ *
+ * @param {quat2} a dual quaternion to represent as a string
+ * @returns {String} string representation of the dual quat
+ */
+function str(a) {
+ return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')';
+}
+
+/**
+ * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {quat2} a the first dual quaternion.
+ * @param {quat2} b the second dual quaternion.
+ * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&
+ a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+}
+
+/**
+ * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+ *
+ * @param {quat2} a the first dual quat.
+ * @param {quat2} b the second dual quat.
+ * @returns {Boolean} true if the dual quats are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0],
+ a1 = a[1],
+ a2 = a[2],
+ a3 = a[3],
+ a4 = a[4],
+ a5 = a[5],
+ a6 = a[6],
+ a7 = a[7];
+ let b0 = b[0],
+ b1 = b[1],
+ b2 = b[2],
+ b3 = b[3],
+ b4 = b[4],
+ b5 = b[5],
+ b6 = b[6],
+ b7 = b[7];
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
+ Math.abs(a3 - b3) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
+ Math.abs(a4 - b4) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
+ Math.abs(a5 - b5) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
+ Math.abs(a6 - b6) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
+ Math.abs(a7 - b7) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] * Math.max(1.0, Math.abs(a7), Math.abs(b7)));
+}
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/vec2.js":
+/*!******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/vec2.js ***!
+ \******************************************************/
+/*! exports provided: create, clone, fromValues, copy, set, add, subtract, multiply, divide, ceil, floor, min, max, round, scale, scaleAndAdd, distance, squaredDistance, length, squaredLength, negate, inverse, normalize, dot, cross, lerp, random, transformMat2, transformMat2d, transformMat3, transformMat4, rotate, angle, str, exactEquals, equals, len, sub, mul, div, dist, sqrDist, sqrLen, forEach */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtract", function() { return subtract; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "divide", function() { return divide; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ceil", function() { return ceil; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "floor", function() { return floor; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "round", function() { return round; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scaleAndAdd", function() { return scaleAndAdd; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distance", function() { return distance; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredDistance", function() { return squaredDistance; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "length", function() { return length; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredLength", function() { return squaredLength; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "negate", function() { return negate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "inverse", function() { return inverse; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dot", function() { return dot; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "cross", function() { return cross; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lerp", function() { return lerp; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "random", function() { return random; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat2", function() { return transformMat2; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat2d", function() { return transformMat2d; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat3", function() { return transformMat3; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat4", function() { return transformMat4; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotate", function() { return rotate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "angle", function() { return angle; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "div", function() { return div; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dist", function() { return dist; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrDist", function() { return sqrDist; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+
+/**
+ * 2 Dimensional Vector
+ * @module vec2
+ */
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](2);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ }
+ return out;
+}
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+function clone(a) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+}
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+function fromValues(x, y) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+}
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+function copy(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+}
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+function set(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+}
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function subtract(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+}
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function multiply(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+}
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function divide(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+}
+
+/**
+ * Math.ceil the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to ceil
+ * @returns {vec2} out
+ */
+function ceil(out, a) {
+ out[0] = Math.ceil(a[0]);
+ out[1] = Math.ceil(a[1]);
+ return out;
+}
+
+/**
+ * Math.floor the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to floor
+ * @returns {vec2} out
+ */
+function floor(out, a) {
+ out[0] = Math.floor(a[0]);
+ out[1] = Math.floor(a[1]);
+ return out;
+}
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function min(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+}
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function max(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+}
+
+/**
+ * Math.round the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to round
+ * @returns {vec2} out
+ */
+function round (out, a) {
+ out[0] = Math.round(a[0]);
+ out[1] = Math.round(a[1]);
+ return out;
+}
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+function scale(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+}
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+}
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+}
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+}
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+}
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+}
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+function negate(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+}
+
+/**
+ * Returns the inverse of the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to invert
+ * @returns {vec2} out
+ */
+function inverse(out, a) {
+ out[0] = 1.0 / a[0];
+ out[1] = 1.0 / a[1];
+ return out;
+}
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+function normalize(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+}
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+}
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+function cross(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+}
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {vec2} out
+ */
+function lerp(out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+}
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+function random(out, scale) {
+ scale = scale || 1.0;
+ var r = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+}
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat2(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+}
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat2d(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+}
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat3(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+}
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat4(out, a, m) {
+ let x = a[0];
+ let y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+}
+
+/**
+ * Rotate a 2D vector
+ * @param {vec2} out The receiving vec2
+ * @param {vec2} a The vec2 point to rotate
+ * @param {vec2} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec2} out
+ */
+function rotate(out, a, b, c) {
+ //Translate point to the origin
+ let p0 = a[0] - b[0],
+ p1 = a[1] - b[1],
+ sinC = Math.sin(c),
+ cosC = Math.cos(c);
+
+ //perform rotation and translate to correct position
+ out[0] = p0*cosC - p1*sinC + b[0];
+ out[1] = p0*sinC + p1*cosC + b[1];
+
+ return out;
+}
+
+/**
+ * Get the angle between two 2D vectors
+ * @param {vec2} a The first operand
+ * @param {vec2} b The second operand
+ * @returns {Number} The angle in radians
+ */
+function angle(a, b) {
+ let x1 = a[0],
+ y1 = a[1],
+ x2 = b[0],
+ y2 = b[1];
+
+ let len1 = x1*x1 + y1*y1;
+ if (len1 > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len1 = 1 / Math.sqrt(len1);
+ }
+
+ let len2 = x2*x2 + y2*y2;
+ if (len2 > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len2 = 1 / Math.sqrt(len2);
+ }
+
+ let cosine = (x1 * x2 + y1 * y2) * len1 * len2;
+
+
+ if(cosine > 1.0) {
+ return 0;
+ }
+ else if(cosine < -1.0) {
+ return Math.PI;
+ } else {
+ return Math.acos(cosine);
+ }
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+}
+
+/**
+ * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+ *
+ * @param {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0], a1 = a[1];
+ let b0 = b[0], b1 = b[1];
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)));
+}
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+const len = length;
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+const sub = subtract;
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+const div = divide;
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+const dist = distance;
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+const sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+const sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+const forEach = (function() {
+ let vec = create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ let i, l;
+ 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;
+ };
+})();
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/vec3.js":
+/*!******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/vec3.js ***!
+ \******************************************************/
+/*! exports provided: create, clone, length, fromValues, copy, set, add, subtract, multiply, divide, ceil, floor, min, max, round, scale, scaleAndAdd, distance, squaredDistance, squaredLength, negate, inverse, normalize, dot, cross, lerp, hermite, bezier, random, transformMat4, transformMat3, transformQuat, rotateX, rotateY, rotateZ, angle, str, exactEquals, equals, sub, mul, div, dist, sqrDist, len, sqrLen, forEach */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "length", function() { return length; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtract", function() { return subtract; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "divide", function() { return divide; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ceil", function() { return ceil; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "floor", function() { return floor; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "round", function() { return round; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scaleAndAdd", function() { return scaleAndAdd; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distance", function() { return distance; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredDistance", function() { return squaredDistance; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredLength", function() { return squaredLength; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "negate", function() { return negate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "inverse", function() { return inverse; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dot", function() { return dot; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "cross", function() { return cross; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lerp", function() { return lerp; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hermite", function() { return hermite; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bezier", function() { return bezier; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "random", function() { return random; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat4", function() { return transformMat4; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat3", function() { return transformMat3; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformQuat", function() { return transformQuat; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateX", function() { return rotateX; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateY", function() { return rotateY; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateZ", function() { return rotateZ; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "angle", function() { return angle; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "div", function() { return div; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dist", function() { return dist; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrDist", function() { return sqrDist; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+
+/**
+ * 3 Dimensional Vector
+ * @module vec3
+ */
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ }
+ return out;
+}
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+function clone(a) {
+ var out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+}
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+ let x = a[0];
+ let y = a[1];
+ let z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+}
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+function fromValues(x, y, z) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+}
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+function copy(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+}
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+function set(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+}
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function subtract(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+}
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function multiply(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+}
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function divide(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+}
+
+/**
+ * Math.ceil the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to ceil
+ * @returns {vec3} out
+ */
+function ceil(out, a) {
+ out[0] = Math.ceil(a[0]);
+ out[1] = Math.ceil(a[1]);
+ out[2] = Math.ceil(a[2]);
+ return out;
+}
+
+/**
+ * Math.floor the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to floor
+ * @returns {vec3} out
+ */
+function floor(out, a) {
+ out[0] = Math.floor(a[0]);
+ out[1] = Math.floor(a[1]);
+ out[2] = Math.floor(a[2]);
+ return out;
+}
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function min(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+}
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function max(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+}
+
+/**
+ * Math.round the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to round
+ * @returns {vec3} out
+ */
+function round(out, a) {
+ out[0] = Math.round(a[0]);
+ out[1] = Math.round(a[1]);
+ out[2] = Math.round(a[2]);
+ return out;
+}
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+function scale(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+}
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+}
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+ let x = b[0] - a[0];
+ let y = b[1] - a[1];
+ let z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+}
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+ let x = b[0] - a[0];
+ let y = b[1] - a[1];
+ let z = b[2] - a[2];
+ return x*x + y*y + z*z;
+}
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+ let x = a[0];
+ let y = a[1];
+ let z = a[2];
+ return x*x + y*y + z*z;
+}
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+function negate(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+}
+
+/**
+ * Returns the inverse of the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to invert
+ * @returns {vec3} out
+ */
+function inverse(out, a) {
+ out[0] = 1.0 / a[0];
+ out[1] = 1.0 / a[1];
+ out[2] = 1.0 / a[2];
+ return out;
+}
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} 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) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+}
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+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;
+}
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {vec3} out
+ */
+function lerp(out, a, b, t) {
+ let ax = a[0];
+ let ay = a[1];
+ let az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+}
+
+/**
+ * Performs a hermite interpolation with two control points
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} d the fourth operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {vec3} out
+ */
+function hermite(out, a, b, c, d, t) {
+ let factorTimes2 = t * t;
+ let factor1 = factorTimes2 * (2 * t - 3) + 1;
+ let factor2 = factorTimes2 * (t - 2) + t;
+ let factor3 = factorTimes2 * (t - 1);
+ let factor4 = factorTimes2 * (3 - 2 * t);
+
+ out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+ out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+ out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+ return out;
+}
+
+/**
+ * Performs a bezier interpolation with two control points
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} d the fourth operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {vec3} out
+ */
+function bezier(out, a, b, c, d, t) {
+ let inverseFactor = 1 - t;
+ let inverseFactorTimesTwo = inverseFactor * inverseFactor;
+ let factorTimes2 = t * t;
+ let factor1 = inverseFactorTimesTwo * inverseFactor;
+ let factor2 = 3 * t * inverseFactorTimesTwo;
+ let factor3 = 3 * factorTimes2 * inverseFactor;
+ let factor4 = factorTimes2 * t;
+
+ out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+ out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+ out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+ return out;
+}
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+function random(out, scale) {
+ scale = scale || 1.0;
+
+ let r = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2.0 * Math.PI;
+ let z = (_common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2.0) - 1.0;
+ let zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+}
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+function transformMat4(out, a, m) {
+ let x = a[0], y = a[1], z = a[2];
+ let 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;
+ return out;
+}
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat3} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+function transformMat3(out, a, m) {
+ let x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+}
+
+/**
+ * Transforms the vec3 with a quat
+ * Can also be used for dual quaternions. (Multiply it with the real part)
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+function transformQuat(out, a, q) {
+ // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+ let qx = q[0], qy = q[1], qz = q[2], qw = q[3];
+ let x = a[0], y = a[1], z = a[2];
+ // var qvec = [qx, qy, qz];
+ // var uv = vec3.cross([], qvec, a);
+ let uvx = qy * z - qz * y,
+ uvy = qz * x - qx * z,
+ uvz = qx * y - qy * x;
+ // var uuv = vec3.cross([], qvec, uv);
+ let uuvx = qy * uvz - qz * uvy,
+ uuvy = qz * uvx - qx * uvz,
+ uuvz = qx * uvy - qy * uvx;
+ // vec3.scale(uv, uv, 2 * w);
+ let w2 = qw * 2;
+ uvx *= w2;
+ uvy *= w2;
+ uvz *= w2;
+ // vec3.scale(uuv, uuv, 2);
+ uuvx *= 2;
+ uuvy *= 2;
+ uuvz *= 2;
+ // return vec3.add(out, a, vec3.add(out, uv, uuv));
+ out[0] = x + uvx + uuvx;
+ out[1] = y + uvy + uuvy;
+ out[2] = z + uvz + uuvz;
+ return out;
+}
+
+/**
+ * Rotate a 3D vector around the x-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateX(out, a, b, c){
+ let p = [], r=[];
+ //Translate point to the origin
+ p[0] = a[0] - b[0];
+ p[1] = a[1] - b[1];
+ p[2] = a[2] - b[2];
+
+ //perform rotation
+ r[0] = p[0];
+ r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);
+ r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);
+
+ //translate to correct position
+ out[0] = r[0] + b[0];
+ out[1] = r[1] + b[1];
+ out[2] = r[2] + b[2];
+
+ return out;
+}
+
+/**
+ * Rotate a 3D vector around the y-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateY(out, a, b, c){
+ let p = [], r=[];
+ //Translate point to the origin
+ p[0] = a[0] - b[0];
+ p[1] = a[1] - b[1];
+ p[2] = a[2] - b[2];
+
+ //perform rotation
+ r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);
+ r[1] = p[1];
+ r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);
+
+ //translate to correct position
+ out[0] = r[0] + b[0];
+ out[1] = r[1] + b[1];
+ out[2] = r[2] + b[2];
+
+ return out;
+}
+
+/**
+ * Rotate a 3D vector around the z-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateZ(out, a, b, c){
+ let p = [], r=[];
+ //Translate point to the origin
+ p[0] = a[0] - b[0];
+ p[1] = a[1] - b[1];
+ p[2] = a[2] - b[2];
+
+ //perform rotation
+ r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);
+ r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);
+ r[2] = p[2];
+
+ //translate to correct position
+ out[0] = r[0] + b[0];
+ out[1] = r[1] + b[1];
+ out[2] = r[2] + b[2];
+
+ return out;
+}
+
+/**
+ * Get the angle between two 3D vectors
+ * @param {vec3} a The first operand
+ * @param {vec3} b The second operand
+ * @returns {Number} The angle in radians
+ */
+function angle(a, b) {
+ let tempA = fromValues(a[0], a[1], a[2]);
+ let tempB = fromValues(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);
+ }
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+}
+
+/**
+ * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2];
+ let b0 = b[0], b1 = b[1], b2 = b[2];
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)));
+}
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+const sub = subtract;
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+const div = divide;
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+const dist = distance;
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+const sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+const len = length;
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+const sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+const forEach = (function() {
+ let vec = create();
+
+ 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;
+ };
+})();
+
+
+/***/ }),
+
+/***/ "./node_modules/gl-matrix/src/gl-matrix/vec4.js":
+/*!******************************************************!*\
+ !*** ./node_modules/gl-matrix/src/gl-matrix/vec4.js ***!
+ \******************************************************/
+/*! exports provided: create, clone, fromValues, copy, set, add, subtract, multiply, divide, ceil, floor, min, max, round, scale, scaleAndAdd, distance, squaredDistance, length, squaredLength, negate, inverse, normalize, dot, lerp, random, transformMat4, transformQuat, str, exactEquals, equals, sub, mul, div, dist, sqrDist, len, sqrLen, forEach */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "create", function() { return create; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subtract", function() { return subtract; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multiply", function() { return multiply; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "divide", function() { return divide; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ceil", function() { return ceil; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "floor", function() { return floor; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "round", function() { return round; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scaleAndAdd", function() { return scaleAndAdd; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distance", function() { return distance; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredDistance", function() { return squaredDistance; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "length", function() { return length; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredLength", function() { return squaredLength; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "negate", function() { return negate; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "inverse", function() { return inverse; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dot", function() { return dot; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lerp", function() { return lerp; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "random", function() { return random; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat4", function() { return transformMat4; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformQuat", function() { return transformQuat; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "div", function() { return div; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dist", function() { return dist; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrDist", function() { return sqrDist; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; });
+/* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+
+/**
+ * 4 Dimensional Vector
+ * @module vec4
+ */
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+function create() {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4);
+ if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ }
+ return out;
+}
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+function clone(a) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+}
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+function fromValues(x, y, z, w) {
+ let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+}
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+function copy(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+}
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+function set(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+}
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function add(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function subtract(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+}
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function multiply(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+}
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function divide(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+}
+
+/**
+ * Math.ceil the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to ceil
+ * @returns {vec4} out
+ */
+function ceil(out, a) {
+ out[0] = Math.ceil(a[0]);
+ out[1] = Math.ceil(a[1]);
+ out[2] = Math.ceil(a[2]);
+ out[3] = Math.ceil(a[3]);
+ return out;
+}
+
+/**
+ * Math.floor the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to floor
+ * @returns {vec4} out
+ */
+function floor(out, a) {
+ out[0] = Math.floor(a[0]);
+ out[1] = Math.floor(a[1]);
+ out[2] = Math.floor(a[2]);
+ out[3] = Math.floor(a[3]);
+ return out;
+}
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function min(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+}
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function max(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+}
+
+/**
+ * Math.round the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to round
+ * @returns {vec4} out
+ */
+function round(out, a) {
+ out[0] = Math.round(a[0]);
+ out[1] = Math.round(a[1]);
+ out[2] = Math.round(a[2]);
+ out[3] = Math.round(a[3]);
+ return out;
+}
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+function scale(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+}
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+}
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+ let x = b[0] - a[0];
+ let y = b[1] - a[1];
+ let z = b[2] - a[2];
+ let w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+}
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+ let x = b[0] - a[0];
+ let y = b[1] - a[1];
+ let z = b[2] - a[2];
+ let w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+}
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+ let x = a[0];
+ let y = a[1];
+ let z = a[2];
+ let w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+}
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+ let x = a[0];
+ let y = a[1];
+ let z = a[2];
+ let w = a[3];
+ return x*x + y*y + z*z + w*w;
+}
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+function negate(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+}
+
+/**
+ * Returns the inverse of the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to invert
+ * @returns {vec4} out
+ */
+function inverse(out, a) {
+ out[0] = 1.0 / a[0];
+ out[1] = 1.0 / a[1];
+ out[2] = 1.0 / a[2];
+ out[3] = 1.0 / a[3];
+ return out;
+}
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+function normalize(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;
+}
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+}
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {vec4} out
+ */
+function lerp(out, a, b, t) {
+ let ax = a[0];
+ let ay = a[1];
+ let az = a[2];
+ let aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+}
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+function random(out, scale) {
+ scale = scale || 1.0;
+
+ // Marsaglia, George. Choosing a Point from the Surface of a
+ // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+ // http://projecteuclid.org/euclid.aoms/1177692644;
+ var v1, v2, v3, v4;
+ var s1, s2;
+ do {
+ v1 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1;
+ v2 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1;
+ s1 = v1 * v1 + v2 * v2;
+ } while (s1 >= 1);
+ do {
+ v3 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1;
+ v4 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1;
+ s2 = v3 * v3 + v4 * v4;
+ } while (s2 >= 1);
+
+ var d = Math.sqrt((1 - s1) / s2);
+ out[0] = scale * v1;
+ out[1] = scale * v2;
+ out[2] = scale * v3 * d;
+ out[3] = scale * v4 * d;
+ return out;
+}
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+function transformMat4(out, a, m) {
+ let x = a[0], y = a[1], z = a[2], w = a[3];
+ 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;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+}
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+function transformQuat(out, a, q) {
+ let x = a[0], y = a[1], z = a[2];
+ let qx = q[0], qy = q[1], qz = q[2], qw = q[3];
+
+ // calculate quat * vec
+ let ix = qw * x + qy * z - qz * y;
+ let iy = qw * y + qz * x - qx * z;
+ let iz = qw * z + qx * y - qy * x;
+ let iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ out[3] = a[3];
+ return out;
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+ let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ return (Math.abs(a0 - b0) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
+ Math.abs(a1 - b1) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
+ Math.abs(a2 - b2) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
+ Math.abs(a3 - b3) <= _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]*Math.max(1.0, Math.abs(a3), Math.abs(b3)));
+}
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+const sub = subtract;
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+const mul = multiply;
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+const div = divide;
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+const dist = distance;
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+const sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+const len = length;
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+const sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+const forEach = (function() {
+ let vec = create();
+
+ 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;
+ };
+})();
+
+
+/***/ }),
+
+/***/ "./src/core/material.js":
+/*!******************************!*\
+ !*** ./src/core/material.js ***!
+ \******************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+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; }; }();
+
+exports.stateToBlendFunc = stateToBlendFunc;
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+// 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.
+
+var GL = WebGLRenderingContext; // For enums
+
+var CAP = exports.CAP = {
+ // Enable caps
+ CULL_FACE: 0x001,
+ BLEND: 0x002,
+ DEPTH_TEST: 0x004,
+ STENCIL_TEST: 0x008,
+ COLOR_MASK: 0x010,
+ DEPTH_MASK: 0x020,
+ STENCIL_MASK: 0x040
+};
+
+var MAT_STATE = exports.MAT_STATE = {
+ CAPS_RANGE: 0x000000FF,
+ BLEND_SRC_SHIFT: 8,
+ BLEND_SRC_RANGE: 0x00000F00,
+ BLEND_DST_SHIFT: 12,
+ BLEND_DST_RANGE: 0x0000F000,
+ BLEND_FUNC_RANGE: 0x0000FF00,
+ DEPTH_FUNC_SHIFT: 16,
+ DEPTH_FUNC_RANGE: 0x000F0000
+};
+
+var RENDER_ORDER = exports.RENDER_ORDER = {
+ // Render opaque objects first.
+ OPAQUE: 0,
+
+ // Render the sky after all opaque object to save fill rate.
+ SKY: 1,
+
+ // Render transparent objects next so that the opaqe objects show through.
+ TRANSPARENT: 2,
+
+ // Finally render purely additive effects like pointer rays so that they
+ // can render without depth mask.
+ ADDITIVE: 3,
+
+ // Render order will be picked based on the material properties.
+ DEFAULT: 4
+};
+
+function stateToBlendFunc(state, mask, shift) {
+ var value = (state & mask) >> shift;
+ switch (value) {
+ case 0:
+ case 1:
+ return value;
+ default:
+ return value - 2 + GL.SRC_COLOR;
+ }
+}
+
+var MaterialState = exports.MaterialState = function () {
+ function MaterialState() {
+ _classCallCheck(this, MaterialState);
+
+ this._state = CAP.CULL_FACE | CAP.DEPTH_TEST | CAP.COLOR_MASK | CAP.DEPTH_MASK;
+
+ // Use a fairly commonly desired blend func as the default.
+ this.blendFuncSrc = GL.SRC_ALPHA;
+ this.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;
+
+ this.depthFunc = GL.LESS;
+ }
+
+ _createClass(MaterialState, [{
+ key: "cullFace",
+ get: function get() {
+ return !!(this._state & CAP.CULL_FACE);
+ },
+ set: function set(value) {
+ if (value) {
+ this._state |= CAP.CULL_FACE;
+ } else {
+ this._state &= ~CAP.CULL_FACE;
+ }
+ }
+ }, {
+ key: "blend",
+ get: function get() {
+ return !!(this._state & CAP.BLEND);
+ },
+ set: function set(value) {
+ if (value) {
+ this._state |= CAP.BLEND;
+ } else {
+ this._state &= ~CAP.BLEND;
+ }
+ }
+ }, {
+ key: "depthTest",
+ get: function get() {
+ return !!(this._state & CAP.DEPTH_TEST);
+ },
+ set: function set(value) {
+ if (value) {
+ this._state |= CAP.DEPTH_TEST;
+ } else {
+ this._state &= ~CAP.DEPTH_TEST;
+ }
+ }
+ }, {
+ key: "stencilTest",
+ get: function get() {
+ return !!(this._state & CAP.STENCIL_TEST);
+ },
+ set: function set(value) {
+ if (value) {
+ this._state |= CAP.STENCIL_TEST;
+ } else {
+ this._state &= ~CAP.STENCIL_TEST;
+ }
+ }
+ }, {
+ key: "colorMask",
+ get: function get() {
+ return !!(this._state & CAP.COLOR_MASK);
+ },
+ set: function set(value) {
+ if (value) {
+ this._state |= CAP.COLOR_MASK;
+ } else {
+ this._state &= ~CAP.COLOR_MASK;
+ }
+ }
+ }, {
+ key: "depthMask",
+ get: function get() {
+ return !!(this._state & CAP.DEPTH_MASK);
+ },
+ set: function set(value) {
+ if (value) {
+ this._state |= CAP.DEPTH_MASK;
+ } else {
+ this._state &= ~CAP.DEPTH_MASK;
+ }
+ }
+ }, {
+ key: "depthFunc",
+ get: function get() {
+ return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;
+ },
+ set: function set(value) {
+ value = value - GL.NEVER;
+ this._state &= ~MAT_STATE.DEPTH_FUNC_RANGE;
+ this._state |= value << MAT_STATE.DEPTH_FUNC_SHIFT;
+ }
+ }, {
+ key: "stencilMask",
+ get: function get() {
+ return !!(this._state & CAP.STENCIL_MASK);
+ },
+ set: function set(value) {
+ if (value) {
+ this._state |= CAP.STENCIL_MASK;
+ } else {
+ this._state &= ~CAP.STENCIL_MASK;
+ }
+ }
+ }, {
+ key: "blendFuncSrc",
+ get: function get() {
+ return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);
+ },
+ set: function set(value) {
+ switch (value) {
+ case 0:
+ case 1:
+ break;
+ default:
+ value = value - GL.SRC_COLOR + 2;
+ }
+ this._state &= ~MAT_STATE.BLEND_SRC_RANGE;
+ this._state |= value << MAT_STATE.BLEND_SRC_SHIFT;
+ }
+ }, {
+ key: "blendFuncDst",
+ get: function get() {
+ return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);
+ },
+ set: function set(value) {
+ switch (value) {
+ case 0:
+ case 1:
+ break;
+ default:
+ value = value - GL.SRC_COLOR + 2;
+ }
+ this._state &= ~MAT_STATE.BLEND_DST_RANGE;
+ this._state |= value << MAT_STATE.BLEND_DST_SHIFT;
+ }
+ }]);
+
+ return MaterialState;
+}();
+
+var MaterialSampler = function () {
+ function MaterialSampler(uniformName) {
+ _classCallCheck(this, MaterialSampler);
+
+ this._uniformName = uniformName;
+ this._texture = null;
+ }
+
+ _createClass(MaterialSampler, [{
+ key: "texture",
+ get: function get() {
+ return this._texture;
+ },
+ set: function set(value) {
+ this._texture = value;
+ }
+ }]);
+
+ return MaterialSampler;
+}();
+
+var MaterialUniform = function () {
+ function MaterialUniform(uniformName, defaultValue, length) {
+ _classCallCheck(this, MaterialUniform);
+
+ this._uniformName = uniformName;
+ this._value = defaultValue;
+ this._length = length;
+ if (!this._length) {
+ if (defaultValue instanceof Array) {
+ this._length = defaultValue.length;
+ } else {
+ this._length = 1;
+ }
+ }
+ }
+
+ _createClass(MaterialUniform, [{
+ key: "value",
+ get: function get() {
+ return this._value;
+ },
+ set: function set(value) {
+ this._value = value;
+ }
+ }]);
+
+ return MaterialUniform;
+}();
+
+var Material = exports.Material = function () {
+ function Material() {
+ _classCallCheck(this, Material);
+
+ this.state = new MaterialState();
+ this.renderOrder = RENDER_ORDER.DEFAULT;
+ this._samplers = [];
+ this._uniforms = [];
+ }
+
+ _createClass(Material, [{
+ key: "defineSampler",
+ value: function defineSampler(uniformName) {
+ var sampler = new MaterialSampler(uniformName);
+ this._samplers.push(sampler);
+ return sampler;
+ }
+ }, {
+ key: "defineUniform",
+ value: function defineUniform(uniformName) {
+ var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
+ var length = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
+
+ var uniform = new MaterialUniform(uniformName, defaultValue, length);
+ this._uniforms.push(uniform);
+ return uniform;
+ }
+ }, {
+ key: "getProgramDefines",
+ value: function getProgramDefines(renderPrimitive) {
+ return {};
+ }
+ }, {
+ key: "materialName",
+ get: function get() {
+ return null;
+ }
+ }, {
+ key: "vertexSource",
+ get: function get() {
+ return null;
+ }
+ }, {
+ key: "fragmentSource",
+ get: function get() {
+ return null;
+ }
+ }]);
+
+ return Material;
+}();
+
+/***/ }),
+
+/***/ "./src/core/node.js":
+/*!**************************!*\
+ !*** ./src/core/node.js ***!
+ \**************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Node = undefined;
+
+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; }; }(); // 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.
+
+var _ray = __webpack_require__(/*! ../math/ray.js */ "./src/math/ray.js");
+
+var _glMatrix = __webpack_require__(/*! ../math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var DEFAULT_TRANSLATION = new Float32Array([0, 0, 0]);
+var DEFAULT_ROTATION = new Float32Array([0, 0, 0, 1]);
+var DEFAULT_SCALE = new Float32Array([1, 1, 1]);
+
+var tmpRayMatrix = _glMatrix.mat4.create();
+
+var Node = exports.Node = function () {
+ function Node() {
+ _classCallCheck(this, Node);
+
+ this.name = null; // Only for debugging
+ this.children = [];
+ this.parent = null;
+ this.visible = true;
+ this.selectable = false;
+
+ this._matrix = null;
+
+ this._dirtyTRS = false;
+ this._translation = null;
+ this._rotation = null;
+ this._scale = null;
+
+ this._dirtyWorldMatrix = false;
+ this._worldMatrix = null;
+
+ this._activeFrameId = -1;
+ this._hoverFrameId = -1;
+ this._renderPrimitives = null;
+ this._renderer = null;
+
+ this._selectHandler = null;
+ }
+
+ _createClass(Node, [{
+ key: '_setRenderer',
+ value: function _setRenderer(renderer) {
+ if (this._renderer == renderer) {
+ return;
+ }
+
+ if (this._renderer) {
+ // Changing the renderer removes any previously attached renderPrimitives
+ // from a different renderer.
+ this.clearRenderPrimitives();
+ }
+
+ this._renderer = renderer;
+ if (renderer) {
+ this.onRendererChanged(renderer);
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var child = _step.value;
+
+ child._setRenderer(renderer);
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+ }
+ }, {
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {}
+ // Override in other node types to respond to changes in the renderer.
+
+
+ // Create a clone of this node and all of it's children. Does not duplicate
+ // RenderPrimitives, the cloned nodes will be treated as new instances of the
+ // geometry.
+
+ }, {
+ key: 'clone',
+ value: function clone() {
+ var _this = this;
+
+ var cloneNode = new Node();
+ cloneNode.name = this.name;
+ cloneNode.visible = this.visible;
+ cloneNode._renderer = this._renderer;
+
+ cloneNode._dirtyTRS = this._dirtyTRS;
+
+ if (this._translation) {
+ cloneNode._translation = _glMatrix.vec3.create();
+ _glMatrix.vec3.copy(cloneNode._translation, this._translation);
+ }
+
+ if (this._rotation) {
+ cloneNode._rotation = _glMatrix.quat.create();
+ _glMatrix.quat.copy(cloneNode._rotation, this._rotation);
+ }
+
+ if (this._scale) {
+ cloneNode._scale = _glMatrix.vec3.create();
+ _glMatrix.vec3.copy(cloneNode._scale, this._scale);
+ }
+
+ // Only copy the matrices if they're not already dirty.
+ if (!cloneNode._dirtyTRS && this._matrix) {
+ cloneNode._matrix = _glMatrix.mat4.create();
+ _glMatrix.mat4.copy(cloneNode._matrix, this._matrix);
+ }
+
+ cloneNode._dirtyWorldMatrix = this._dirtyWorldMatrix;
+ if (!cloneNode._dirtyWorldMatrix && this._worldMatrix) {
+ cloneNode._worldMatrix = _glMatrix.mat4.create();
+ _glMatrix.mat4.copy(cloneNode._worldMatrix, this._worldMatrix);
+ }
+
+ this.waitForComplete().then(function () {
+ if (_this._renderPrimitives) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = _this._renderPrimitives[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var primitive = _step2.value;
+
+ cloneNode.addRenderPrimitive(primitive);
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = _this.children[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var child = _step3.value;
+
+ cloneNode.addNode(child.clone());
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+ });
+
+ return cloneNode;
+ }
+ }, {
+ key: 'markActive',
+ value: function markActive(frameId) {
+ if (this.visible && this._renderPrimitives) {
+ this._activeFrameId = frameId;
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = this._renderPrimitives[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var primitive = _step4.value;
+
+ primitive.markActive(frameId);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = this.children[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var child = _step5.value;
+
+ if (child.visible) {
+ child.markActive(frameId);
+ }
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5.return) {
+ _iterator5.return();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+ }
+ }, {
+ key: 'addNode',
+ value: function addNode(value) {
+ if (!value || value.parent == this) {
+ return;
+ }
+
+ if (value.parent) {
+ value.parent.removeNode(value);
+ }
+ value.parent = this;
+
+ this.children.push(value);
+
+ if (this._renderer) {
+ value._setRenderer(this._renderer);
+ }
+ }
+ }, {
+ key: 'removeNode',
+ value: function removeNode(value) {
+ var i = this.children.indexOf(value);
+ if (i > -1) {
+ this.children.splice(i, 1);
+ value.parent = null;
+ }
+ }
+ }, {
+ key: 'clearNodes',
+ value: function clearNodes() {
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = this.children[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var child = _step6.value;
+
+ child.parent = null;
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6.return) {
+ _iterator6.return();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ this.children = [];
+ }
+ }, {
+ key: 'setMatrixDirty',
+ value: function setMatrixDirty() {
+ if (!this._dirtyWorldMatrix) {
+ this._dirtyWorldMatrix = true;
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = this.children[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var child = _step7.value;
+
+ child.setMatrixDirty();
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7.return) {
+ _iterator7.return();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+ }
+ }
+ }, {
+ key: '_updateLocalMatrix',
+ value: function _updateLocalMatrix() {
+ if (!this._matrix) {
+ this._matrix = _glMatrix.mat4.create();
+ }
+
+ if (this._dirtyTRS) {
+ this._dirtyTRS = false;
+ _glMatrix.mat4.fromRotationTranslationScale(this._matrix, this._rotation || DEFAULT_ROTATION, this._translation || DEFAULT_TRANSLATION, this._scale || DEFAULT_SCALE);
+ }
+
+ return this._matrix;
+ }
+ }, {
+ key: 'waitForComplete',
+ value: function waitForComplete() {
+ var _this2 = this;
+
+ var childPromises = [];
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = this.children[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var child = _step8.value;
+
+ childPromises.push(child.waitForComplete());
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8.return) {
+ _iterator8.return();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+
+ if (this._renderPrimitives) {
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = this._renderPrimitives[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var primitive = _step9.value;
+
+ childPromises.push(primitive.waitForComplete());
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9.return) {
+ _iterator9.return();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+ }
+ return Promise.all(childPromises).then(function () {
+ return _this2;
+ });
+ }
+ }, {
+ key: 'addRenderPrimitive',
+ value: function addRenderPrimitive(primitive) {
+ if (!this._renderPrimitives) {
+ this._renderPrimitives = [primitive];
+ } else {
+ this._renderPrimitives.push(primitive);
+ }
+ primitive._instances.push(this);
+ }
+ }, {
+ key: 'removeRenderPrimitive',
+ value: function removeRenderPrimitive(primitive) {
+ if (!this._renderPrimitives) {
+ return;
+ }
+
+ var index = this._renderPrimitives._instances.indexOf(primitive);
+ if (index > -1) {
+ this._renderPrimitives._instances.splice(index, 1);
+
+ index = primitive._instances.indexOf(this);
+ if (index > -1) {
+ primitive._instances.splice(index, 1);
+ }
+
+ if (!this._renderPrimitives.length) {
+ this._renderPrimitives = null;
+ }
+ }
+ }
+ }, {
+ key: 'clearRenderPrimitives',
+ value: function clearRenderPrimitives() {
+ if (this._renderPrimitives) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this._renderPrimitives[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var primitive = _step10.value;
+
+ var index = primitive._instances.indexOf(this);
+ if (index > -1) {
+ primitive._instances.splice(index, 1);
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10.return) {
+ _iterator10.return();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ this._renderPrimitives = null;
+ }
+ }
+ }, {
+ key: '_hitTestSelectableNode',
+ value: function _hitTestSelectableNode(ray) {
+ if (this._renderPrimitives) {
+ var localRay = null;
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this._renderPrimitives[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var primitive = _step11.value;
+
+ if (primitive._min) {
+ if (!localRay) {
+ _glMatrix.mat4.invert(tmpRayMatrix, this.worldMatrix);
+ _glMatrix.mat4.multiply(tmpRayMatrix, tmpRayMatrix, ray.transformMatrix);
+ localRay = new _ray.Ray(tmpRayMatrix);
+ }
+ var intersection = localRay.intersectsAABB(primitive._min, primitive._max);
+ if (intersection) {
+ _glMatrix.vec3.transformMat4(intersection, intersection, this.worldMatrix);
+ return intersection;
+ }
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11.return) {
+ _iterator11.return();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+ }
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.children[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var child = _step12.value;
+
+ var _intersection = child._hitTestSelectableNode(ray);
+ if (_intersection) {
+ return _intersection;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12.return) {
+ _iterator12.return();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: 'hitTest',
+ value: function hitTest(ray) {
+ if (this.selectable && this.visible) {
+ var intersection = this._hitTestSelectableNode(ray);
+
+ if (intersection) {
+ var origin = _glMatrix.vec3.fromValues(ray.origin.x, ray.origin.y, ray.origin.z);
+ return {
+ node: this,
+ intersection: intersection,
+ distance: _glMatrix.vec3.distance(origin, intersection)
+ };
+ }
+ return null;
+ }
+
+ var result = null;
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = this.children[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var child = _step13.value;
+
+ var childResult = child.hitTest(ray);
+ if (childResult) {
+ if (!result || result.distance > childResult.distance) {
+ result = childResult;
+ }
+ }
+ }
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13.return) {
+ _iterator13.return();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ return result;
+ }
+ }, {
+ key: 'onSelect',
+ value: function onSelect(value) {
+ this._selectHandler = value;
+ }
+ }, {
+ key: 'handleSelect',
+
+
+ // Called when a selectable node is selected.
+ value: function handleSelect() {
+ if (this._selectHandler) {
+ this._selectHandler();
+ }
+ }
+
+ // Called when a selectable element is pointed at.
+
+ }, {
+ key: 'onHoverStart',
+ value: function onHoverStart() {}
+
+ // Called when a selectable element is no longer pointed at.
+
+ }, {
+ key: 'onHoverEnd',
+ value: function onHoverEnd() {}
+ }, {
+ key: '_update',
+ value: function _update(timestamp, frameDelta) {
+ this.onUpdate(timestamp, frameDelta);
+
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = this.children[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var child = _step14.value;
+
+ child._update(timestamp, frameDelta);
+ }
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14.return) {
+ _iterator14.return();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+ }
+
+ // Called every frame so that the nodes can animate themselves
+
+ }, {
+ key: 'onUpdate',
+ value: function onUpdate(timestamp, frameDelta) {}
+ }, {
+ key: 'matrix',
+ set: function set(value) {
+ if (value) {
+ if (!this._matrix) {
+ this._matrix = _glMatrix.mat4.create();
+ }
+ _glMatrix.mat4.copy(this._matrix, value);
+ } else {
+ this._matrix = null;
+ }
+ this.setMatrixDirty();
+ this._dirtyTRS = false;
+ this._translation = null;
+ this._rotation = null;
+ this._scale = null;
+ },
+ get: function get() {
+ this.setMatrixDirty();
+
+ return this._updateLocalMatrix();
+ }
+ }, {
+ key: 'worldMatrix',
+ get: function get() {
+ if (!this._worldMatrix) {
+ this._dirtyWorldMatrix = true;
+ this._worldMatrix = _glMatrix.mat4.create();
+ }
+
+ if (this._dirtyWorldMatrix || this._dirtyTRS) {
+ if (this.parent) {
+ // TODO: Some optimizations that could be done here if the node matrix
+ // is an identity matrix.
+ _glMatrix.mat4.mul(this._worldMatrix, this.parent.worldMatrix, this._updateLocalMatrix());
+ } else {
+ _glMatrix.mat4.copy(this._worldMatrix, this._updateLocalMatrix());
+ }
+ this._dirtyWorldMatrix = false;
+ }
+
+ return this._worldMatrix;
+ }
+
+ // TODO: Decompose matrix when fetching these?
+
+ }, {
+ key: 'translation',
+ set: function set(value) {
+ if (value != null) {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ }
+ this._translation = value;
+ },
+ get: function get() {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ if (!this._translation) {
+ this._translation = _glMatrix.vec3.clone(DEFAULT_TRANSLATION);
+ }
+ return this._translation;
+ }
+ }, {
+ key: 'rotation',
+ set: function set(value) {
+ if (value != null) {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ }
+ this._rotation = value;
+ },
+ get: function get() {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ if (!this._rotation) {
+ this._rotation = _glMatrix.quat.clone(DEFAULT_ROTATION);
+ }
+ return this._rotation;
+ }
+ }, {
+ key: 'scale',
+ set: function set(value) {
+ if (value != null) {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ }
+ this._scale = value;
+ },
+ get: function get() {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ if (!this._scale) {
+ this._scale = _glMatrix.vec3.clone(DEFAULT_SCALE);
+ }
+ return this._scale;
+ }
+ }, {
+ key: 'renderPrimitives',
+ get: function get() {
+ return this._renderPrimitives;
+ }
+ }, {
+ key: 'selectHandler',
+ get: function get() {
+ return this._selectHandler;
+ }
+ }]);
+
+ return Node;
+}();
+
+/***/ }),
+
+/***/ "./src/core/primitive.js":
+/*!*******************************!*\
+ !*** ./src/core/primitive.js ***!
+ \*******************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Primitive = exports.PrimitiveAttribute = undefined;
+
+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 _glMatrix = __webpack_require__(/*! ../math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // 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.
+
+var PrimitiveAttribute = exports.PrimitiveAttribute = function PrimitiveAttribute(name, buffer, componentCount, componentType, stride, byteOffset) {
+ _classCallCheck(this, PrimitiveAttribute);
+
+ this.name = name;
+ this.buffer = buffer;
+ this.componentCount = componentCount || 3;
+ this.componentType = componentType || 5126; // gl.FLOAT;
+ this.stride = stride || 0;
+ this.byteOffset = byteOffset || 0;
+ this.normalized = false;
+};
+
+var Primitive = exports.Primitive = function () {
+ function Primitive(attributes, elementCount, mode) {
+ _classCallCheck(this, Primitive);
+
+ this.attributes = attributes || [];
+ this.elementCount = elementCount || 0;
+ this.mode = mode || 4; // gl.TRIANGLES;
+ this.indexBuffer = null;
+ this.indexByteOffset = 0;
+ this.indexType = 0;
+ this._min = null;
+ this._max = null;
+ }
+
+ _createClass(Primitive, [{
+ key: 'setIndexBuffer',
+ value: function setIndexBuffer(indexBuffer, byteOffset, indexType) {
+ this.indexBuffer = indexBuffer;
+ this.indexByteOffset = byteOffset || 0;
+ this.indexType = indexType || 5123; // gl.UNSIGNED_SHORT;
+ }
+ }, {
+ key: 'setBounds',
+ value: function setBounds(min, max) {
+ this._min = _glMatrix.vec3.clone(min);
+ this._max = _glMatrix.vec3.clone(max);
+ }
+ }]);
+
+ return Primitive;
+}();
+
+/***/ }),
+
+/***/ "./src/core/program.js":
+/*!*****************************!*\
+ !*** ./src/core/program.js ***!
+ \*****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+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"); } }
+
+// 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.
+
+var Program = exports.Program = function () {
+ function Program(gl, vertSrc, fragSrc, attribMap, defines) {
+ _classCallCheck(this, Program);
+
+ this._gl = gl;
+ this.program = gl.createProgram();
+ this.attrib = null;
+ this.uniform = null;
+ this.defines = {};
+
+ this._firstUse = true;
+ this._nextUseCallbacks = [];
+
+ var definesString = '';
+ if (defines) {
+ for (var define in defines) {
+ this.defines[define] = defines[define];
+ definesString += '#define ' + define + ' ' + defines[define] + '\n';
+ }
+ }
+
+ this._vertShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.attachShader(this.program, this._vertShader);
+ gl.shaderSource(this._vertShader, definesString + vertSrc);
+ gl.compileShader(this._vertShader);
+
+ this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.attachShader(this.program, this._fragShader);
+ gl.shaderSource(this._fragShader, definesString + fragSrc);
+ gl.compileShader(this._fragShader);
+
+ if (attribMap) {
+ this.attrib = {};
+ for (var attribName in attribMap) {
+ gl.bindAttribLocation(this.program, attribMap[attribName], attribName);
+ this.attrib[attribName] = attribMap[attribName];
+ }
+ }
+
+ gl.linkProgram(this.program);
+ }
+
+ _createClass(Program, [{
+ key: 'onNextUse',
+ value: function onNextUse(callback) {
+ this._nextUseCallbacks.push(callback);
+ }
+ }, {
+ key: 'use',
+ value: function use() {
+ var gl = this._gl;
+
+ // If this is the first time the program has been used do all the error checking and
+ // attrib/uniform querying needed.
+ if (this._firstUse) {
+ this._firstUse = false;
+ if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
+ if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {
+ console.error('Vertex shader compile error: ' + gl.getShaderInfoLog(this._vertShader));
+ } else if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {
+ console.error('Fragment shader compile error: ' + gl.getShaderInfoLog(this._fragShader));
+ } else {
+ console.error('Program link error: ' + gl.getProgramInfoLog(this.program));
+ }
+ gl.deleteProgram(this.program);
+ this.program = null;
+ } else {
+ if (!this.attrib) {
+ this.attrib = {};
+ var attribCount = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);
+ for (var i = 0; i < attribCount; i++) {
+ var attribInfo = gl.getActiveAttrib(this.program, i);
+ this.attrib[attribInfo.name] = gl.getAttribLocation(this.program, attribInfo.name);
+ }
+ }
+
+ this.uniform = {};
+ var uniformCount = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
+ var uniformName = '';
+ for (var _i = 0; _i < uniformCount; _i++) {
+ var uniformInfo = gl.getActiveUniform(this.program, _i);
+ uniformName = uniformInfo.name.replace('[0]', '');
+ this.uniform[uniformName] = gl.getUniformLocation(this.program, uniformName);
+ }
+ }
+ gl.deleteShader(this._vertShader);
+ gl.deleteShader(this._fragShader);
+ }
+
+ gl.useProgram(this.program);
+
+ if (this._nextUseCallbacks.length) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this._nextUseCallbacks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var callback = _step.value;
+
+ callback(this);
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ this._nextUseCallbacks = [];
+ }
+ }
+ }]);
+
+ return Program;
+}();
+
+/***/ }),
+
+/***/ "./src/core/renderer.js":
+/*!******************************!*\
+ !*** ./src/core/renderer.js ***!
+ \******************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Renderer = exports.RenderTexture = exports.RenderView = exports.ATTRIB_MASK = exports.ATTRIB = undefined;
+
+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; }; }(); // 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.
+
+exports.createWebGLContext = createWebGLContext;
+
+var _material = __webpack_require__(/*! ./material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ./node.js */ "./src/core/node.js");
+
+var _program = __webpack_require__(/*! ./program.js */ "./src/core/program.js");
+
+var _texture = __webpack_require__(/*! ./texture.js */ "./src/core/texture.js");
+
+var _glMatrix = __webpack_require__(/*! ../math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var ATTRIB = exports.ATTRIB = {
+ POSITION: 1,
+ NORMAL: 2,
+ TANGENT: 3,
+ TEXCOORD_0: 4,
+ TEXCOORD_1: 5,
+ COLOR_0: 6
+};
+
+var ATTRIB_MASK = exports.ATTRIB_MASK = {
+ POSITION: 0x0001,
+ NORMAL: 0x0002,
+ TANGENT: 0x0004,
+ TEXCOORD_0: 0x0008,
+ TEXCOORD_1: 0x0010,
+ COLOR_0: 0x0020
+};
+
+var GL = WebGLRenderingContext; // For enums
+
+var DEF_LIGHT_DIR = new Float32Array([-0.1, -1.0, -0.2]);
+var DEF_LIGHT_COLOR = new Float32Array([3.0, 3.0, 3.0]);
+
+var PRECISION_REGEX = new RegExp('precision (lowp|mediump|highp) float;');
+
+var VERTEX_SHADER_SINGLE_ENTRY = '\nuniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;\n\nvoid main() {\n gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);\n}\n';
+
+var VERTEX_SHADER_MULTI_ENTRY = '\n#ERROR Multiview rendering is not implemented\nvoid main() {\n gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n}\n';
+
+var FRAGMENT_SHADER_ENTRY = '\nvoid main() {\n gl_FragColor = fragment_main();\n}\n';
+
+function isPowerOfTwo(n) {
+ return (n & n - 1) === 0;
+}
+
+// Creates a WebGL context and initializes it with some common default state.
+function createWebGLContext(glAttribs) {
+ glAttribs = glAttribs || { alpha: false };
+
+ var webglCanvas = document.createElement('canvas');
+ var contextTypes = glAttribs.webgl2 ? ['webgl2'] : ['webgl', 'experimental-webgl'];
+ var context = null;
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = contextTypes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var contextType = _step.value;
+
+ context = webglCanvas.getContext(contextType, glAttribs);
+ if (context) {
+ break;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ if (!context) {
+ var webglType = glAttribs.webgl2 ? 'WebGL 2' : 'WebGL';
+ console.error('This browser does not support ' + webglType + '.');
+ return null;
+ }
+
+ return context;
+}
+
+var RenderView = exports.RenderView = function () {
+ function RenderView(projectionMatrix, viewMatrix) {
+ var viewport = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
+ var eye = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'left';
+
+ _classCallCheck(this, RenderView);
+
+ this.projectionMatrix = projectionMatrix;
+ this.viewMatrix = viewMatrix;
+ this.viewport = viewport;
+ // If an eye isn't given the left eye is assumed.
+ this._eye = eye;
+ this._eyeIndex = eye == 'left' ? 0 : 1;
+ }
+
+ _createClass(RenderView, [{
+ key: 'eye',
+ get: function get() {
+ return this._eye;
+ },
+ set: function set(value) {
+ this._eye = value;
+ this._eyeIndex = value == 'left' ? 0 : 1;
+ }
+ }, {
+ key: 'eyeIndex',
+ get: function get() {
+ return this._eyeIndex;
+ }
+ }]);
+
+ return RenderView;
+}();
+
+var RenderBuffer = function () {
+ function RenderBuffer(target, usage, buffer) {
+ var _this = this;
+
+ var length = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
+
+ _classCallCheck(this, RenderBuffer);
+
+ this._target = target;
+ this._usage = usage;
+ this._length = length;
+ if (buffer instanceof Promise) {
+ this._buffer = null;
+ this._promise = buffer.then(function (buffer) {
+ _this._buffer = buffer;
+ return _this;
+ });
+ } else {
+ this._buffer = buffer;
+ this._promise = Promise.resolve(this);
+ }
+ }
+
+ _createClass(RenderBuffer, [{
+ key: 'waitForComplete',
+ value: function waitForComplete() {
+ return this._promise;
+ }
+ }]);
+
+ return RenderBuffer;
+}();
+
+var RenderPrimitiveAttribute = function RenderPrimitiveAttribute(primitiveAttribute) {
+ _classCallCheck(this, RenderPrimitiveAttribute);
+
+ this._attrib_index = ATTRIB[primitiveAttribute.name];
+ this._componentCount = primitiveAttribute.componentCount;
+ this._componentType = primitiveAttribute.componentType;
+ this._stride = primitiveAttribute.stride;
+ this._byteOffset = primitiveAttribute.byteOffset;
+ this._normalized = primitiveAttribute.normalized;
+};
+
+var RenderPrimitiveAttributeBuffer = function RenderPrimitiveAttributeBuffer(buffer) {
+ _classCallCheck(this, RenderPrimitiveAttributeBuffer);
+
+ this._buffer = buffer;
+ this._attributes = [];
+};
+
+var RenderPrimitive = function () {
+ function RenderPrimitive(primitive) {
+ _classCallCheck(this, RenderPrimitive);
+
+ this._activeFrameId = 0;
+ this._instances = [];
+ this._material = null;
+
+ this.setPrimitive(primitive);
+ }
+
+ _createClass(RenderPrimitive, [{
+ key: 'setPrimitive',
+ value: function setPrimitive(primitive) {
+ this._mode = primitive.mode;
+ this._elementCount = primitive.elementCount;
+ this._promise = null;
+ this._vao = null;
+ this._complete = false;
+ this._attributeBuffers = [];
+ this._attributeMask = 0;
+
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = primitive.attributes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var attribute = _step2.value;
+
+ this._attributeMask |= ATTRIB_MASK[attribute.name];
+ var renderAttribute = new RenderPrimitiveAttribute(attribute);
+ var foundBuffer = false;
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this._attributeBuffers[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var attributeBuffer = _step3.value;
+
+ if (attributeBuffer._buffer == attribute.buffer) {
+ attributeBuffer._attributes.push(renderAttribute);
+ foundBuffer = true;
+ break;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ if (!foundBuffer) {
+ var _attributeBuffer = new RenderPrimitiveAttributeBuffer(attribute.buffer);
+ _attributeBuffer._attributes.push(renderAttribute);
+ this._attributeBuffers.push(_attributeBuffer);
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ this._indexBuffer = null;
+ this._indexByteOffset = 0;
+ this._indexType = 0;
+
+ if (primitive.indexBuffer) {
+ this._indexByteOffset = primitive.indexByteOffset;
+ this._indexType = primitive.indexType;
+ this._indexBuffer = primitive.indexBuffer;
+ }
+
+ if (primitive._min) {
+ this._min = _glMatrix.vec3.clone(primitive._min);
+ this._max = _glMatrix.vec3.clone(primitive._max);
+ } else {
+ this._min = null;
+ this._max = null;
+ }
+
+ if (this._material != null) {
+ this.waitForComplete(); // To flip the _complete flag.
+ }
+ }
+ }, {
+ key: 'setRenderMaterial',
+ value: function setRenderMaterial(material) {
+ this._material = material;
+ this._promise = null;
+ this._complete = false;
+
+ if (this._material != null) {
+ this.waitForComplete(); // To flip the _complete flag.
+ }
+ }
+ }, {
+ key: 'markActive',
+ value: function markActive(frameId) {
+ if (this._complete && this._activeFrameId != frameId) {
+ if (this._material) {
+ if (!this._material.markActive(frameId)) {
+ return;
+ }
+ }
+ this._activeFrameId = frameId;
+ }
+ }
+ }, {
+ key: 'waitForComplete',
+ value: function waitForComplete() {
+ var _this2 = this;
+
+ if (!this._promise) {
+ if (!this._material) {
+ return Promise.reject('RenderPrimitive does not have a material');
+ }
+
+ var completionPromises = [];
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = this._attributeBuffers[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var attributeBuffer = _step4.value;
+
+ if (!attributeBuffer._buffer._buffer) {
+ completionPromises.push(attributeBuffer._buffer._promise);
+ }
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ if (this._indexBuffer && !this._indexBuffer._buffer) {
+ completionPromises.push(this._indexBuffer._promise);
+ }
+
+ this._promise = Promise.all(completionPromises).then(function () {
+ _this2._complete = true;
+ return _this2;
+ });
+ }
+ return this._promise;
+ }
+ }, {
+ key: 'samplers',
+ get: function get() {
+ return this._material._samplerDictionary;
+ }
+ }, {
+ key: 'uniforms',
+ get: function get() {
+ return this._material._uniform_dictionary;
+ }
+ }]);
+
+ return RenderPrimitive;
+}();
+
+var RenderTexture = exports.RenderTexture = function () {
+ function RenderTexture(texture) {
+ _classCallCheck(this, RenderTexture);
+
+ this._texture = texture;
+ this._complete = false;
+ this._activeFrameId = 0;
+ this._activeCallback = null;
+ }
+
+ _createClass(RenderTexture, [{
+ key: 'markActive',
+ value: function markActive(frameId) {
+ if (this._activeCallback && this._activeFrameId != frameId) {
+ this._activeFrameId = frameId;
+ this._activeCallback(this);
+ }
+ }
+ }]);
+
+ return RenderTexture;
+}();
+
+var inverseMatrix = _glMatrix.mat4.create();
+
+function setCap(gl, glEnum, cap, prevState, state) {
+ var change = (state & cap) - (prevState & cap);
+ if (!change) {
+ return;
+ }
+
+ if (change > 0) {
+ gl.enable(glEnum);
+ } else {
+ gl.disable(glEnum);
+ }
+}
+
+var RenderMaterialSampler = function () {
+ function RenderMaterialSampler(renderer, materialSampler, index) {
+ _classCallCheck(this, RenderMaterialSampler);
+
+ this._renderer = renderer;
+ this._uniformName = materialSampler._uniformName;
+ this._renderTexture = renderer._getRenderTexture(materialSampler._texture);
+ this._index = index;
+ }
+
+ _createClass(RenderMaterialSampler, [{
+ key: 'texture',
+ set: function set(value) {
+ this._renderTexture = this._renderer._getRenderTexture(value);
+ }
+ }]);
+
+ return RenderMaterialSampler;
+}();
+
+var RenderMaterialUniform = function () {
+ function RenderMaterialUniform(materialUniform) {
+ _classCallCheck(this, RenderMaterialUniform);
+
+ this._uniformName = materialUniform._uniformName;
+ this._uniform = null;
+ this._length = materialUniform._length;
+ if (materialUniform._value instanceof Array) {
+ this._value = new Float32Array(materialUniform._value);
+ } else {
+ this._value = new Float32Array([materialUniform._value]);
+ }
+ }
+
+ _createClass(RenderMaterialUniform, [{
+ key: 'value',
+ set: function set(value) {
+ if (this._value.length == 1) {
+ this._value[0] = value;
+ } else {
+ for (var i = 0; i < this._value.length; ++i) {
+ this._value[i] = value[i];
+ }
+ }
+ }
+ }]);
+
+ return RenderMaterialUniform;
+}();
+
+var RenderMaterial = function () {
+ function RenderMaterial(renderer, material, program) {
+ _classCallCheck(this, RenderMaterial);
+
+ this._program = program;
+ this._state = material.state._state;
+ this._activeFrameId = 0;
+ this._completeForActiveFrame = false;
+
+ this._samplerDictionary = {};
+ this._samplers = [];
+ for (var i = 0; i < material._samplers.length; ++i) {
+ var renderSampler = new RenderMaterialSampler(renderer, material._samplers[i], i);
+ this._samplers.push(renderSampler);
+ this._samplerDictionary[renderSampler._uniformName] = renderSampler;
+ }
+
+ this._uniform_dictionary = {};
+ this._uniforms = [];
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = material._uniforms[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var uniform = _step5.value;
+
+ var renderUniform = new RenderMaterialUniform(uniform);
+ this._uniforms.push(renderUniform);
+ this._uniform_dictionary[renderUniform._uniformName] = renderUniform;
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5.return) {
+ _iterator5.return();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ this._firstBind = true;
+
+ this._renderOrder = material.renderOrder;
+ if (this._renderOrder == _material.RENDER_ORDER.DEFAULT) {
+ if (this._state & _material.CAP.BLEND) {
+ this._renderOrder = _material.RENDER_ORDER.TRANSPARENT;
+ } else {
+ this._renderOrder = _material.RENDER_ORDER.OPAQUE;
+ }
+ }
+ }
+
+ _createClass(RenderMaterial, [{
+ key: 'bind',
+ value: function bind(gl) {
+ // First time we do a binding, cache the uniform locations and remove
+ // unused uniforms from the list.
+ if (this._firstBind) {
+ for (var i = 0; i < this._samplers.length;) {
+ var sampler = this._samplers[i];
+ if (!this._program.uniform[sampler._uniformName]) {
+ this._samplers.splice(i, 1);
+ continue;
+ }
+ ++i;
+ }
+
+ for (var _i = 0; _i < this._uniforms.length;) {
+ var uniform = this._uniforms[_i];
+ uniform._uniform = this._program.uniform[uniform._uniformName];
+ if (!uniform._uniform) {
+ this._uniforms.splice(_i, 1);
+ continue;
+ }
+ ++_i;
+ }
+ this._firstBind = false;
+ }
+
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = this._samplers[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var _sampler = _step6.value;
+
+ gl.activeTexture(gl.TEXTURE0 + _sampler._index);
+ if (_sampler._renderTexture && _sampler._renderTexture._complete) {
+ gl.bindTexture(gl.TEXTURE_2D, _sampler._renderTexture._texture);
+ } else {
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6.return) {
+ _iterator6.return();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = this._uniforms[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var _uniform = _step7.value;
+
+ switch (_uniform._length) {
+ case 1:
+ gl.uniform1fv(_uniform._uniform, _uniform._value);break;
+ case 2:
+ gl.uniform2fv(_uniform._uniform, _uniform._value);break;
+ case 3:
+ gl.uniform3fv(_uniform._uniform, _uniform._value);break;
+ case 4:
+ gl.uniform4fv(_uniform._uniform, _uniform._value);break;
+ }
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7.return) {
+ _iterator7.return();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+ }
+ }, {
+ key: 'markActive',
+ value: function markActive(frameId) {
+ if (this._activeFrameId != frameId) {
+ this._activeFrameId = frameId;
+ this._completeForActiveFrame = true;
+ for (var i = 0; i < this._samplers.length; ++i) {
+ var sampler = this._samplers[i];
+ if (sampler._renderTexture) {
+ if (!sampler._renderTexture._complete) {
+ this._completeForActiveFrame = false;
+ break;
+ }
+ sampler._renderTexture.markActive(frameId);
+ }
+ }
+ }
+ return this._completeForActiveFrame;
+ }
+
+ // Material State fetchers
+
+ }, {
+ key: '_capsDiff',
+
+
+ // Only really for use from the renderer
+ value: function _capsDiff(otherState) {
+ return otherState & _material.MAT_STATE.CAPS_RANGE ^ this._state & _material.MAT_STATE.CAPS_RANGE;
+ }
+ }, {
+ key: '_blendDiff',
+ value: function _blendDiff(otherState) {
+ if (!(this._state & _material.CAP.BLEND)) {
+ return 0;
+ }
+ return otherState & _material.MAT_STATE.BLEND_FUNC_RANGE ^ this._state & _material.MAT_STATE.BLEND_FUNC_RANGE;
+ }
+ }, {
+ key: '_depthFuncDiff',
+ value: function _depthFuncDiff(otherState) {
+ if (!(this._state & _material.CAP.DEPTH_TEST)) {
+ return 0;
+ }
+ return otherState & _material.MAT_STATE.DEPTH_FUNC_RANGE ^ this._state & _material.MAT_STATE.DEPTH_FUNC_RANGE;
+ }
+ }, {
+ key: 'cullFace',
+ get: function get() {
+ return !!(this._state & _material.CAP.CULL_FACE);
+ }
+ }, {
+ key: 'blend',
+ get: function get() {
+ return !!(this._state & _material.CAP.BLEND);
+ }
+ }, {
+ key: 'depthTest',
+ get: function get() {
+ return !!(this._state & _material.CAP.DEPTH_TEST);
+ }
+ }, {
+ key: 'stencilTest',
+ get: function get() {
+ return !!(this._state & _material.CAP.STENCIL_TEST);
+ }
+ }, {
+ key: 'colorMask',
+ get: function get() {
+ return !!(this._state & _material.CAP.COLOR_MASK);
+ }
+ }, {
+ key: 'depthMask',
+ get: function get() {
+ return !!(this._state & _material.CAP.DEPTH_MASK);
+ }
+ }, {
+ key: 'stencilMask',
+ get: function get() {
+ return !!(this._state & _material.CAP.STENCIL_MASK);
+ }
+ }, {
+ key: 'depthFunc',
+ get: function get() {
+ return ((this._state & _material.MAT_STATE.DEPTH_FUNC_RANGE) >> _material.MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;
+ }
+ }, {
+ key: 'blendFuncSrc',
+ get: function get() {
+ return (0, _material.stateToBlendFunc)(this._state, _material.MAT_STATE.BLEND_SRC_RANGE, _material.MAT_STATE.BLEND_SRC_SHIFT);
+ }
+ }, {
+ key: 'blendFuncDst',
+ get: function get() {
+ return (0, _material.stateToBlendFunc)(this._state, _material.MAT_STATE.BLEND_DST_RANGE, _material.MAT_STATE.BLEND_DST_SHIFT);
+ }
+ }]);
+
+ return RenderMaterial;
+}();
+
+var Renderer = exports.Renderer = function () {
+ function Renderer(gl) {
+ _classCallCheck(this, Renderer);
+
+ this._gl = gl || createWebGLContext();
+ this._frameId = 0;
+ this._programCache = {};
+ this._textureCache = {};
+ this._renderPrimitives = Array(_material.RENDER_ORDER.DEFAULT);
+ this._cameraPositions = [];
+
+ this._vaoExt = gl.getExtension('OES_vertex_array_object');
+
+ var fragHighPrecision = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
+ this._defaultFragPrecision = fragHighPrecision.precision > 0 ? 'highp' : 'mediump';
+
+ this._depthMaskNeedsReset = false;
+ this._colorMaskNeedsReset = false;
+
+ this._globalLightColor = _glMatrix.vec3.clone(DEF_LIGHT_COLOR);
+ this._globalLightDir = _glMatrix.vec3.clone(DEF_LIGHT_DIR);
+ }
+
+ _createClass(Renderer, [{
+ key: 'createRenderBuffer',
+ value: function createRenderBuffer(target, data) {
+ var usage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : GL.STATIC_DRAW;
+
+ var gl = this._gl;
+ var glBuffer = gl.createBuffer();
+
+ if (data instanceof Promise) {
+ var renderBuffer = new RenderBuffer(target, usage, data.then(function (data) {
+ gl.bindBuffer(target, glBuffer);
+ gl.bufferData(target, data, usage);
+ renderBuffer._length = data.byteLength;
+ return glBuffer;
+ }));
+ return renderBuffer;
+ } else {
+ gl.bindBuffer(target, glBuffer);
+ gl.bufferData(target, data, usage);
+ return new RenderBuffer(target, usage, glBuffer, data.byteLength);
+ }
+ }
+ }, {
+ key: 'updateRenderBuffer',
+ value: function updateRenderBuffer(buffer, data) {
+ var _this3 = this;
+
+ var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
+
+ if (buffer._buffer) {
+ var gl = this._gl;
+ gl.bindBuffer(buffer._target, buffer._buffer);
+ if (offset == 0 && buffer._length == data.byteLength) {
+ gl.bufferData(buffer._target, data, buffer._usage);
+ } else {
+ gl.bufferSubData(buffer._target, offset, data);
+ }
+ } else {
+ buffer.waitForComplete().then(function (buffer) {
+ _this3.updateRenderBuffer(buffer, data, offset);
+ });
+ }
+ }
+ }, {
+ key: 'createRenderPrimitive',
+ value: function createRenderPrimitive(primitive, material) {
+ var renderPrimitive = new RenderPrimitive(primitive);
+
+ var program = this._getMaterialProgram(material, renderPrimitive);
+ var renderMaterial = new RenderMaterial(this, material, program);
+ renderPrimitive.setRenderMaterial(renderMaterial);
+
+ if (!this._renderPrimitives[renderMaterial._renderOrder]) {
+ this._renderPrimitives[renderMaterial._renderOrder] = [];
+ }
+
+ this._renderPrimitives[renderMaterial._renderOrder].push(renderPrimitive);
+
+ return renderPrimitive;
+ }
+ }, {
+ key: 'createMesh',
+ value: function createMesh(primitive, material) {
+ var meshNode = new _node.Node();
+ meshNode.addRenderPrimitive(this.createRenderPrimitive(primitive, material));
+ return meshNode;
+ }
+ }, {
+ key: 'drawViews',
+ value: function drawViews(views, rootNode) {
+ if (!rootNode) {
+ return;
+ }
+
+ var gl = this._gl;
+ this._frameId++;
+
+ rootNode.markActive(this._frameId);
+
+ // If there's only one view then flip the algorithm a bit so that we're only
+ // setting the viewport once.
+ if (views.length == 1 && views[0].viewport) {
+ var vp = views[0].viewport;
+ this._gl.viewport(vp.x, vp.y, vp.width, vp.height);
+ }
+
+ // Get the positions of the 'camera' for each view matrix.
+ for (var i = 0; i < views.length; ++i) {
+ _glMatrix.mat4.invert(inverseMatrix, views[i].viewMatrix);
+
+ if (this._cameraPositions.length <= i) {
+ this._cameraPositions.push(_glMatrix.vec3.create());
+ }
+ var cameraPosition = this._cameraPositions[i];
+ _glMatrix.vec3.set(cameraPosition, 0, 0, 0);
+ _glMatrix.vec3.transformMat4(cameraPosition, cameraPosition, inverseMatrix);
+ }
+
+ // Draw each set of render primitives in order
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = this._renderPrimitives[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var renderPrimitives = _step8.value;
+
+ if (renderPrimitives && renderPrimitives.length) {
+ this._drawRenderPrimitiveSet(views, renderPrimitives);
+ }
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8.return) {
+ _iterator8.return();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+
+ if (this._vaoExt) {
+ this._vaoExt.bindVertexArrayOES(null);
+ }
+
+ if (this._depthMaskNeedsReset) {
+ gl.depthMask(true);
+ }
+ if (this._colorMaskNeedsReset) {
+ gl.colorMask(true, true, true, true);
+ }
+ }
+ }, {
+ key: '_drawRenderPrimitiveSet',
+ value: function _drawRenderPrimitiveSet(views, renderPrimitives) {
+ var gl = this._gl;
+ var program = null;
+ var material = null;
+ var attribMask = 0;
+
+ // Loop through every primitive known to the renderer.
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = renderPrimitives[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var primitive = _step9.value;
+
+ // Skip over those that haven't been marked as active for this frame.
+ if (primitive._activeFrameId != this._frameId) {
+ continue;
+ }
+
+ // Bind the primitive material's program if it's different than the one we
+ // were using for the previous primitive.
+ // TODO: The ording of this could be more efficient.
+ if (program != primitive._material._program) {
+ program = primitive._material._program;
+ program.use();
+
+ if (program.uniform.LIGHT_DIRECTION) {
+ gl.uniform3fv(program.uniform.LIGHT_DIRECTION, this._globalLightDir);
+ }
+
+ if (program.uniform.LIGHT_COLOR) {
+ gl.uniform3fv(program.uniform.LIGHT_COLOR, this._globalLightColor);
+ }
+
+ if (views.length == 1) {
+ gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, views[0].projectionMatrix);
+ gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, views[0].viewMatrix);
+ gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[0]);
+ gl.uniform1i(program.uniform.EYE_INDEX, views[0].eyeIndex);
+ }
+ }
+
+ if (material != primitive._material) {
+ this._bindMaterialState(primitive._material, material);
+ primitive._material.bind(gl, program, material);
+ material = primitive._material;
+ }
+
+ if (this._vaoExt) {
+ if (primitive._vao) {
+ this._vaoExt.bindVertexArrayOES(primitive._vao);
+ } else {
+ primitive._vao = this._vaoExt.createVertexArrayOES();
+ this._vaoExt.bindVertexArrayOES(primitive._vao);
+ this._bindPrimitive(primitive);
+ }
+ } else {
+ this._bindPrimitive(primitive, attribMask);
+ attribMask = primitive._attributeMask;
+ }
+
+ for (var i = 0; i < views.length; ++i) {
+ var view = views[i];
+ if (views.length > 1) {
+ if (view.viewport) {
+ var vp = view.viewport;
+ gl.viewport(vp.x, vp.y, vp.width, vp.height);
+ }
+ gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, view.projectionMatrix);
+ gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, view.viewMatrix);
+ gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[i]);
+ gl.uniform1i(program.uniform.EYE_INDEX, view.eyeIndex);
+ }
+
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = primitive._instances[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var instance = _step10.value;
+
+ if (instance._activeFrameId != this._frameId) {
+ continue;
+ }
+
+ gl.uniformMatrix4fv(program.uniform.MODEL_MATRIX, false, instance.worldMatrix);
+
+ if (primitive._indexBuffer) {
+ gl.drawElements(primitive._mode, primitive._elementCount, primitive._indexType, primitive._indexByteOffset);
+ } else {
+ gl.drawArrays(primitive._mode, 0, primitive._elementCount);
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10.return) {
+ _iterator10.return();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+ }
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9.return) {
+ _iterator9.return();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+ }
+ }, {
+ key: '_getRenderTexture',
+ value: function _getRenderTexture(texture) {
+ var _this4 = this;
+
+ if (!texture) {
+ return null;
+ }
+
+ var key = texture.textureKey;
+ if (!key) {
+ throw new Error('Texure does not have a valid key');
+ }
+
+ if (key in this._textureCache) {
+ return this._textureCache[key];
+ } else {
+ var gl = this._gl;
+ var textureHandle = gl.createTexture();
+
+ var renderTexture = new RenderTexture(textureHandle);
+ this._textureCache[key] = renderTexture;
+
+ if (texture instanceof _texture.DataTexture) {
+ gl.bindTexture(gl.TEXTURE_2D, textureHandle);
+ gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.width, texture.height, 0, texture.format, texture._type, texture._data);
+ this._setSamplerParameters(texture);
+ renderTexture._complete = true;
+ } else {
+ texture.waitForComplete().then(function () {
+ gl.bindTexture(gl.TEXTURE_2D, textureHandle);
+ gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);
+ _this4._setSamplerParameters(texture);
+ renderTexture._complete = true;
+
+ if (texture instanceof _texture.VideoTexture) {
+ // Once the video starts playing, set a callback to update it's
+ // contents each frame.
+ texture._video.addEventListener('playing', function () {
+ renderTexture._activeCallback = function () {
+ if (!texture._video.paused && !texture._video.waiting) {
+ gl.bindTexture(gl.TEXTURE_2D, textureHandle);
+ gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);
+ }
+ };
+ });
+ }
+ });
+ }
+
+ return renderTexture;
+ }
+ }
+ }, {
+ key: '_setSamplerParameters',
+ value: function _setSamplerParameters(texture) {
+ var gl = this._gl;
+
+ var sampler = texture.sampler;
+ var powerOfTwo = isPowerOfTwo(texture.width) && isPowerOfTwo(texture.height);
+ var mipmap = powerOfTwo && texture.mipmap;
+ if (mipmap) {
+ gl.generateMipmap(gl.TEXTURE_2D);
+ }
+
+ var minFilter = sampler.minFilter || (mipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
+ var wrapS = sampler.wrapS || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);
+ var wrapT = sampler.wrapT || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, sampler.magFilter || gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
+ }
+ }, {
+ key: '_getProgramKey',
+ value: function _getProgramKey(name, defines) {
+ var key = name + ':';
+
+ for (var define in defines) {
+ key += define + '=' + defines[define] + ',';
+ }
+
+ return key;
+ }
+ }, {
+ key: '_getMaterialProgram',
+ value: function _getMaterialProgram(material, renderPrimitive) {
+ var _this5 = this;
+
+ var materialName = material.materialName;
+ var vertexSource = material.vertexSource;
+ var fragmentSource = material.fragmentSource;
+
+ // These should always be defined for every material
+ if (materialName == null) {
+ throw new Error('Material does not have a name');
+ }
+ if (vertexSource == null) {
+ throw new Error('Material "' + materialName + '" does not have a vertex source');
+ }
+ if (fragmentSource == null) {
+ throw new Error('Material "' + materialName + '" does not have a fragment source');
+ }
+
+ var defines = material.getProgramDefines(renderPrimitive);
+ var key = this._getProgramKey(materialName, defines);
+
+ if (key in this._programCache) {
+ return this._programCache[key];
+ } else {
+ var multiview = false; // Handle this dynamically later
+ var fullVertexSource = vertexSource;
+ fullVertexSource += multiview ? VERTEX_SHADER_MULTI_ENTRY : VERTEX_SHADER_SINGLE_ENTRY;
+
+ var precisionMatch = fragmentSource.match(PRECISION_REGEX);
+ var fragPrecisionHeader = precisionMatch ? '' : 'precision ' + this._defaultFragPrecision + ' float;\n';
+
+ var fullFragmentSource = fragPrecisionHeader + fragmentSource;
+ fullFragmentSource += FRAGMENT_SHADER_ENTRY;
+
+ var program = new _program.Program(this._gl, fullVertexSource, fullFragmentSource, ATTRIB, defines);
+ this._programCache[key] = program;
+
+ program.onNextUse(function (program) {
+ // Bind the samplers to the right texture index. This is constant for
+ // the lifetime of the program.
+ for (var i = 0; i < material._samplers.length; ++i) {
+ var sampler = material._samplers[i];
+ var uniform = program.uniform[sampler._uniformName];
+ if (uniform) {
+ _this5._gl.uniform1i(uniform, i);
+ }
+ }
+ });
+
+ return program;
+ }
+ }
+ }, {
+ key: '_bindPrimitive',
+ value: function _bindPrimitive(primitive, attribMask) {
+ var gl = this._gl;
+
+ // If the active attributes have changed then update the active set.
+ if (attribMask != primitive._attributeMask) {
+ for (var attrib in ATTRIB) {
+ if (primitive._attributeMask & ATTRIB_MASK[attrib]) {
+ gl.enableVertexAttribArray(ATTRIB[attrib]);
+ } else {
+ gl.disableVertexAttribArray(ATTRIB[attrib]);
+ }
+ }
+ }
+
+ // Bind the primitive attributes and indices.
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = primitive._attributeBuffers[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var attributeBuffer = _step11.value;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer._buffer._buffer);
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = attributeBuffer._attributes[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var _attrib = _step12.value;
+
+ gl.vertexAttribPointer(_attrib._attrib_index, _attrib._componentCount, _attrib._componentType, _attrib._normalized, _attrib._stride, _attrib._byteOffset);
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12.return) {
+ _iterator12.return();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11.return) {
+ _iterator11.return();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ if (primitive._indexBuffer) {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, primitive._indexBuffer._buffer);
+ } else {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ }
+ }
+ }, {
+ key: '_bindMaterialState',
+ value: function _bindMaterialState(material) {
+ var prevMaterial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
+
+ var gl = this._gl;
+
+ var state = material._state;
+ var prevState = prevMaterial ? prevMaterial._state : ~state;
+
+ // Return early if both materials use identical state
+ if (state == prevState) {
+ return;
+ }
+
+ // Any caps bits changed?
+ if (material._capsDiff(prevState)) {
+ setCap(gl, gl.CULL_FACE, _material.CAP.CULL_FACE, prevState, state);
+ setCap(gl, gl.BLEND, _material.CAP.BLEND, prevState, state);
+ setCap(gl, gl.DEPTH_TEST, _material.CAP.DEPTH_TEST, prevState, state);
+ setCap(gl, gl.STENCIL_TEST, _material.CAP.STENCIL_TEST, prevState, state);
+
+ var colorMaskChange = (state & _material.CAP.COLOR_MASK) - (prevState & _material.CAP.COLOR_MASK);
+ if (colorMaskChange) {
+ var mask = colorMaskChange > 1;
+ this._colorMaskNeedsReset = !mask;
+ gl.colorMask(mask, mask, mask, mask);
+ }
+
+ var depthMaskChange = (state & _material.CAP.DEPTH_MASK) - (prevState & _material.CAP.DEPTH_MASK);
+ if (depthMaskChange) {
+ this._depthMaskNeedsReset = !(depthMaskChange > 1);
+ gl.depthMask(depthMaskChange > 1);
+ }
+
+ var stencilMaskChange = (state & _material.CAP.STENCIL_MASK) - (prevState & _material.CAP.STENCIL_MASK);
+ if (stencilMaskChange) {
+ gl.stencilMask(stencilMaskChange > 1);
+ }
+ }
+
+ // Blending enabled and blend func changed?
+ if (material._blendDiff(prevState)) {
+ gl.blendFunc(material.blendFuncSrc, material.blendFuncDst);
+ }
+
+ // Depth testing enabled and depth func changed?
+ if (material._depthFuncDiff(prevState)) {
+ gl.depthFunc(material.depthFunc);
+ }
+ }
+ }, {
+ key: 'gl',
+ get: function get() {
+ return this._gl;
+ }
+ }, {
+ key: 'globalLightColor',
+ set: function set(value) {
+ _glMatrix.vec3.copy(this._globalLightColor, value);
+ },
+ get: function get() {
+ return _glMatrix.vec3.clone(this._globalLightColor);
+ }
+ }, {
+ key: 'globalLightDir',
+ set: function set(value) {
+ _glMatrix.vec3.copy(this._globalLightDir, value);
+ },
+ get: function get() {
+ return _glMatrix.vec3.clone(this._globalLightDir);
+ }
+ }]);
+
+ return Renderer;
+}();
+
+/***/ }),
+
+/***/ "./src/core/texture.js":
+/*!*****************************!*\
+ !*** ./src/core/texture.js ***!
+ \*****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+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 _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+// 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.
+
+var GL = WebGLRenderingContext; // For enums
+
+var TextureSampler = exports.TextureSampler = function TextureSampler() {
+ _classCallCheck(this, TextureSampler);
+
+ this.minFilter = null;
+ this.magFilter = null;
+ this.wrapS = null;
+ this.wrapT = null;
+};
+
+var Texture = exports.Texture = function () {
+ function Texture() {
+ _classCallCheck(this, Texture);
+
+ this.sampler = new TextureSampler();
+ this.mipmap = true;
+ // TODO: Anisotropy
+ }
+
+ _createClass(Texture, [{
+ key: 'format',
+ get: function get() {
+ return GL.RGBA;
+ }
+ }, {
+ key: 'width',
+ get: function get() {
+ return 0;
+ }
+ }, {
+ key: 'height',
+ get: function get() {
+ return 0;
+ }
+ }, {
+ key: 'textureKey',
+ get: function get() {
+ return null;
+ }
+ }]);
+
+ return Texture;
+}();
+
+var ImageTexture = exports.ImageTexture = function (_Texture) {
+ _inherits(ImageTexture, _Texture);
+
+ function ImageTexture(img) {
+ _classCallCheck(this, ImageTexture);
+
+ var _this = _possibleConstructorReturn(this, (ImageTexture.__proto__ || Object.getPrototypeOf(ImageTexture)).call(this));
+
+ _this._img = img;
+ _this._imgBitmap = null;
+
+ if (img.src && img.complete) {
+ if (img.naturalWidth) {
+ _this._promise = _this._finishImage();
+ } else {
+ _this._promise = Promise.reject('Image provided had failed to load.');
+ }
+ } else {
+ _this._promise = new Promise(function (resolve, reject) {
+ img.addEventListener('load', function () {
+ return resolve(_this._finishImage());
+ });
+ img.addEventListener('error', reject);
+ });
+ }
+ return _this;
+ }
+
+ _createClass(ImageTexture, [{
+ key: '_finishImage',
+ value: function _finishImage() {
+ var _this2 = this;
+
+ if (window.createImageBitmap) {
+ return window.createImageBitmap(this._img).then(function (imgBitmap) {
+ _this2._imgBitmap = imgBitmap;
+ return Promise.resolve(_this2);
+ });
+ }
+ return Promise.resolve(this);
+ }
+ }, {
+ key: 'waitForComplete',
+ value: function waitForComplete() {
+ return this._promise;
+ }
+ }, {
+ key: 'format',
+ get: function get() {
+ // TODO: Can be RGB in some cases.
+ return GL.RGBA;
+ }
+ }, {
+ key: 'width',
+ get: function get() {
+ return this._img.width;
+ }
+ }, {
+ key: 'height',
+ get: function get() {
+ return this._img.height;
+ }
+ }, {
+ key: 'textureKey',
+ get: function get() {
+ return this._img.src;
+ }
+ }, {
+ key: 'source',
+ get: function get() {
+ return this._imgBitmap || this._img;
+ }
+ }]);
+
+ return ImageTexture;
+}(Texture);
+
+var UrlTexture = exports.UrlTexture = function (_ImageTexture) {
+ _inherits(UrlTexture, _ImageTexture);
+
+ function UrlTexture(url) {
+ _classCallCheck(this, UrlTexture);
+
+ var img = new Image();
+
+ var _this3 = _possibleConstructorReturn(this, (UrlTexture.__proto__ || Object.getPrototypeOf(UrlTexture)).call(this, img));
+
+ img.src = url;
+ return _this3;
+ }
+
+ return UrlTexture;
+}(ImageTexture);
+
+var BlobTexture = exports.BlobTexture = function (_ImageTexture2) {
+ _inherits(BlobTexture, _ImageTexture2);
+
+ function BlobTexture(blob) {
+ _classCallCheck(this, BlobTexture);
+
+ var img = new Image();
+
+ var _this4 = _possibleConstructorReturn(this, (BlobTexture.__proto__ || Object.getPrototypeOf(BlobTexture)).call(this, img));
+
+ img.src = window.URL.createObjectURL(blob);
+ return _this4;
+ }
+
+ return BlobTexture;
+}(ImageTexture);
+
+var VideoTexture = exports.VideoTexture = function (_Texture2) {
+ _inherits(VideoTexture, _Texture2);
+
+ function VideoTexture(video) {
+ _classCallCheck(this, VideoTexture);
+
+ var _this5 = _possibleConstructorReturn(this, (VideoTexture.__proto__ || Object.getPrototypeOf(VideoTexture)).call(this));
+
+ _this5._video = video;
+
+ if (video.readyState >= 2) {
+ _this5._promise = Promise.resolve(_this5);
+ } else if (video.error) {
+ _this5._promise = Promise.reject(video.error);
+ } else {
+ _this5._promise = new Promise(function (resolve, reject) {
+ video.addEventListener('loadeddata', function () {
+ return resolve(_this5);
+ });
+ video.addEventListener('error', reject);
+ });
+ }
+ return _this5;
+ }
+
+ _createClass(VideoTexture, [{
+ key: 'waitForComplete',
+ value: function waitForComplete() {
+ return this._promise;
+ }
+ }, {
+ key: 'format',
+ get: function get() {
+ // TODO: Can be RGB in some cases.
+ return GL.RGBA;
+ }
+ }, {
+ key: 'width',
+ get: function get() {
+ return this._video.videoWidth;
+ }
+ }, {
+ key: 'height',
+ get: function get() {
+ return this._video.videoHeight;
+ }
+ }, {
+ key: 'textureKey',
+ get: function get() {
+ return this._video.src;
+ }
+ }, {
+ key: 'source',
+ get: function get() {
+ return this._video;
+ }
+ }]);
+
+ return VideoTexture;
+}(Texture);
+
+var nextDataTextureIndex = 0;
+
+var DataTexture = exports.DataTexture = function (_Texture3) {
+ _inherits(DataTexture, _Texture3);
+
+ function DataTexture(data, width, height) {
+ var format = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : GL.RGBA;
+ var type = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : GL.UNSIGNED_BYTE;
+
+ _classCallCheck(this, DataTexture);
+
+ var _this6 = _possibleConstructorReturn(this, (DataTexture.__proto__ || Object.getPrototypeOf(DataTexture)).call(this));
+
+ _this6._data = data;
+ _this6._width = width;
+ _this6._height = height;
+ _this6._format = format;
+ _this6._type = type;
+ _this6._key = 'DATA_' + nextDataTextureIndex;
+ nextDataTextureIndex++;
+ return _this6;
+ }
+
+ _createClass(DataTexture, [{
+ key: 'format',
+ get: function get() {
+ return this._format;
+ }
+ }, {
+ key: 'width',
+ get: function get() {
+ return this._width;
+ }
+ }, {
+ key: 'height',
+ get: function get() {
+ return this._height;
+ }
+ }, {
+ key: 'textureKey',
+ get: function get() {
+ return this._key;
+ }
+ }]);
+
+ return DataTexture;
+}(Texture);
+
+var ColorTexture = exports.ColorTexture = function (_DataTexture) {
+ _inherits(ColorTexture, _DataTexture);
+
+ function ColorTexture(r, g, b, a) {
+ _classCallCheck(this, ColorTexture);
+
+ var colorData = new Uint8Array([r * 255.0, g * 255.0, b * 255.0, a * 255.0]);
+
+ var _this7 = _possibleConstructorReturn(this, (ColorTexture.__proto__ || Object.getPrototypeOf(ColorTexture)).call(this, colorData, 1, 1));
+
+ _this7.mipmap = false;
+ _this7._key = 'COLOR_' + colorData[0] + '_' + colorData[1] + '_' + colorData[2] + '_' + colorData[3];
+ return _this7;
+ }
+
+ return ColorTexture;
+}(DataTexture);
+
+/***/ }),
+
+/***/ "./src/cottontail.js":
+/*!***************************!*\
+ !*** ./src/cottontail.js ***!
+ \***************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _node = __webpack_require__(/*! ./core/node.js */ "./src/core/node.js");
+
+Object.defineProperty(exports, 'Node', {
+ enumerable: true,
+ get: function get() {
+ return _node.Node;
+ }
+});
+
+var _renderer = __webpack_require__(/*! ./core/renderer.js */ "./src/core/renderer.js");
+
+Object.defineProperty(exports, 'Renderer', {
+ enumerable: true,
+ get: function get() {
+ return _renderer.Renderer;
+ }
+});
+Object.defineProperty(exports, 'createWebGLContext', {
+ enumerable: true,
+ get: function get() {
+ return _renderer.createWebGLContext;
+ }
+});
+
+var _texture = __webpack_require__(/*! ./core/texture.js */ "./src/core/texture.js");
+
+Object.defineProperty(exports, 'UrlTexture', {
+ enumerable: true,
+ get: function get() {
+ return _texture.UrlTexture;
+ }
+});
+
+var _primitiveStream = __webpack_require__(/*! ./geometry/primitive-stream.js */ "./src/geometry/primitive-stream.js");
+
+Object.defineProperty(exports, 'PrimitiveStream', {
+ enumerable: true,
+ get: function get() {
+ return _primitiveStream.PrimitiveStream;
+ }
+});
+
+var _boxBuilder = __webpack_require__(/*! ./geometry/box-builder.js */ "./src/geometry/box-builder.js");
+
+Object.defineProperty(exports, 'BoxBuilder', {
+ enumerable: true,
+ get: function get() {
+ return _boxBuilder.BoxBuilder;
+ }
+});
+
+var _pbr = __webpack_require__(/*! ./materials/pbr.js */ "./src/materials/pbr.js");
+
+Object.defineProperty(exports, 'PbrMaterial', {
+ enumerable: true,
+ get: function get() {
+ return _pbr.PbrMaterial;
+ }
+});
+
+var _glMatrix = __webpack_require__(/*! ./math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+Object.defineProperty(exports, 'mat4', {
+ enumerable: true,
+ get: function get() {
+ return _glMatrix.mat4;
+ }
+});
+Object.defineProperty(exports, 'mat3', {
+ enumerable: true,
+ get: function get() {
+ return _glMatrix.mat3;
+ }
+});
+Object.defineProperty(exports, 'vec3', {
+ enumerable: true,
+ get: function get() {
+ return _glMatrix.vec3;
+ }
+});
+Object.defineProperty(exports, 'vec4', {
+ enumerable: true,
+ get: function get() {
+ return _glMatrix.vec4;
+ }
+});
+Object.defineProperty(exports, 'quat', {
+ enumerable: true,
+ get: function get() {
+ return _glMatrix.quat;
+ }
+});
+
+var _boundsRenderer = __webpack_require__(/*! ./nodes/bounds-renderer.js */ "./src/nodes/bounds-renderer.js");
+
+Object.defineProperty(exports, 'BoundsRenderer', {
+ enumerable: true,
+ get: function get() {
+ return _boundsRenderer.BoundsRenderer;
+ }
+});
+
+var _button = __webpack_require__(/*! ./nodes/button.js */ "./src/nodes/button.js");
+
+Object.defineProperty(exports, 'ButtonNode', {
+ enumerable: true,
+ get: function get() {
+ return _button.ButtonNode;
+ }
+});
+
+var _dropShadow = __webpack_require__(/*! ./nodes/drop-shadow.js */ "./src/nodes/drop-shadow.js");
+
+Object.defineProperty(exports, 'DropShadowNode', {
+ enumerable: true,
+ get: function get() {
+ return _dropShadow.DropShadowNode;
+ }
+});
+
+var _cubeSea = __webpack_require__(/*! ./nodes/cube-sea.js */ "./src/nodes/cube-sea.js");
+
+Object.defineProperty(exports, 'CubeSeaNode', {
+ enumerable: true,
+ get: function get() {
+ return _cubeSea.CubeSeaNode;
+ }
+});
+
+var _gltf = __webpack_require__(/*! ./nodes/gltf2.js */ "./src/nodes/gltf2.js");
+
+Object.defineProperty(exports, 'Gltf2Node', {
+ enumerable: true,
+ get: function get() {
+ return _gltf.Gltf2Node;
+ }
+});
+
+var _skybox = __webpack_require__(/*! ./nodes/skybox.js */ "./src/nodes/skybox.js");
+
+Object.defineProperty(exports, 'SkyboxNode', {
+ enumerable: true,
+ get: function get() {
+ return _skybox.SkyboxNode;
+ }
+});
+
+var _video = __webpack_require__(/*! ./nodes/video.js */ "./src/nodes/video.js");
+
+Object.defineProperty(exports, 'VideoNode', {
+ enumerable: true,
+ get: function get() {
+ return _video.VideoNode;
+ }
+});
+
+var _scene = __webpack_require__(/*! ./scenes/scene.js */ "./src/scenes/scene.js");
+
+Object.defineProperty(exports, 'WebXRView', {
+ enumerable: true,
+ get: function get() {
+ return _scene.WebXRView;
+ }
+});
+Object.defineProperty(exports, 'Scene', {
+ enumerable: true,
+ get: function get() {
+ return _scene.Scene;
+ }
+});
+
+var _fallbackHelper = __webpack_require__(/*! ./util/fallback-helper.js */ "./src/util/fallback-helper.js");
+
+Object.defineProperty(exports, 'FallbackHelper', {
+ enumerable: true,
+ get: function get() {
+ return _fallbackHelper.FallbackHelper;
+ }
+});
+
+var _queryArgs = __webpack_require__(/*! ./util/query-args.js */ "./src/util/query-args.js");
+
+Object.defineProperty(exports, 'QueryArgs', {
+ enumerable: true,
+ get: function get() {
+ return _queryArgs.QueryArgs;
+ }
+});
+
+/***/ }),
+
+/***/ "./src/geometry/box-builder.js":
+/*!*************************************!*\
+ !*** ./src/geometry/box-builder.js ***!
+ \*************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.BoxBuilder = undefined;
+
+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 _primitiveStream = __webpack_require__(/*! ./primitive-stream.js */ "./src/geometry/primitive-stream.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+var BoxBuilder = exports.BoxBuilder = function (_GeometryBuilderBase) {
+ _inherits(BoxBuilder, _GeometryBuilderBase);
+
+ function BoxBuilder() {
+ _classCallCheck(this, BoxBuilder);
+
+ return _possibleConstructorReturn(this, (BoxBuilder.__proto__ || Object.getPrototypeOf(BoxBuilder)).apply(this, arguments));
+ }
+
+ _createClass(BoxBuilder, [{
+ key: 'pushBox',
+ value: function pushBox(min, max) {
+ var stream = this.primitiveStream;
+
+ var w = max[0] - min[0];
+ var h = max[1] - min[1];
+ var d = max[2] - min[2];
+
+ var wh = w * 0.5;
+ var hh = h * 0.5;
+ var dh = d * 0.5;
+
+ var cx = min[0] + wh;
+ var cy = min[1] + hh;
+ var cz = min[2] + dh;
+
+ stream.startGeometry();
+
+ // Bottom
+ var idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx + 1, idx + 2);
+ stream.pushTriangle(idx, idx + 2, idx + 3);
+
+ // X Y Z U V NX NY NZ
+ stream.pushVertex(-wh + cx, -hh + cy, -dh + cz, 0.0, 1.0, 0.0, -1.0, 0.0);
+ stream.pushVertex(+wh + cx, -hh + cy, -dh + cz, 1.0, 1.0, 0.0, -1.0, 0.0);
+ stream.pushVertex(+wh + cx, -hh + cy, +dh + cz, 1.0, 0.0, 0.0, -1.0, 0.0);
+ stream.pushVertex(-wh + cx, -hh + cy, +dh + cz, 0.0, 0.0, 0.0, -1.0, 0.0);
+
+ // Top
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx + 2, idx + 1);
+ stream.pushTriangle(idx, idx + 3, idx + 2);
+
+ stream.pushVertex(-wh + cx, +hh + cy, -dh + cz, 0.0, 0.0, 0.0, 1.0, 0.0);
+ stream.pushVertex(+wh + cx, +hh + cy, -dh + cz, 1.0, 0.0, 0.0, 1.0, 0.0);
+ stream.pushVertex(+wh + cx, +hh + cy, +dh + cz, 1.0, 1.0, 0.0, 1.0, 0.0);
+ stream.pushVertex(-wh + cx, +hh + cy, +dh + cz, 0.0, 1.0, 0.0, 1.0, 0.0);
+
+ // Left
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx + 2, idx + 1);
+ stream.pushTriangle(idx, idx + 3, idx + 2);
+
+ stream.pushVertex(-wh + cx, -hh + cy, -dh + cz, 0.0, 1.0, -1.0, 0.0, 0.0);
+ stream.pushVertex(-wh + cx, +hh + cy, -dh + cz, 0.0, 0.0, -1.0, 0.0, 0.0);
+ stream.pushVertex(-wh + cx, +hh + cy, +dh + cz, 1.0, 0.0, -1.0, 0.0, 0.0);
+ stream.pushVertex(-wh + cx, -hh + cy, +dh + cz, 1.0, 1.0, -1.0, 0.0, 0.0);
+
+ // Right
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx + 1, idx + 2);
+ stream.pushTriangle(idx, idx + 2, idx + 3);
+
+ stream.pushVertex(+wh + cx, -hh + cy, -dh + cz, 1.0, 1.0, 1.0, 0.0, 0.0);
+ stream.pushVertex(+wh + cx, +hh + cy, -dh + cz, 1.0, 0.0, 1.0, 0.0, 0.0);
+ stream.pushVertex(+wh + cx, +hh + cy, +dh + cz, 0.0, 0.0, 1.0, 0.0, 0.0);
+ stream.pushVertex(+wh + cx, -hh + cy, +dh + cz, 0.0, 1.0, 1.0, 0.0, 0.0);
+
+ // Back
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx + 2, idx + 1);
+ stream.pushTriangle(idx, idx + 3, idx + 2);
+
+ stream.pushVertex(-wh + cx, -hh + cy, -dh + cz, 1.0, 1.0, 0.0, 0.0, -1.0);
+ stream.pushVertex(+wh + cx, -hh + cy, -dh + cz, 0.0, 1.0, 0.0, 0.0, -1.0);
+ stream.pushVertex(+wh + cx, +hh + cy, -dh + cz, 0.0, 0.0, 0.0, 0.0, -1.0);
+ stream.pushVertex(-wh + cx, +hh + cy, -dh + cz, 1.0, 0.0, 0.0, 0.0, -1.0);
+
+ // Front
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx + 1, idx + 2);
+ stream.pushTriangle(idx, idx + 2, idx + 3);
+
+ stream.pushVertex(-wh + cx, -hh + cy, +dh + cz, 0.0, 1.0, 0.0, 0.0, 1.0);
+ stream.pushVertex(+wh + cx, -hh + cy, +dh + cz, 1.0, 1.0, 0.0, 0.0, 1.0);
+ stream.pushVertex(+wh + cx, +hh + cy, +dh + cz, 1.0, 0.0, 0.0, 0.0, 1.0);
+ stream.pushVertex(-wh + cx, +hh + cy, +dh + cz, 0.0, 0.0, 0.0, 0.0, 1.0);
+
+ stream.endGeometry();
+ }
+ }, {
+ key: 'pushCube',
+ value: function pushCube() {
+ var center = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [0, 0, 0];
+ var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1.0;
+
+ var hs = size * 0.5;
+ this.pushBox([center[0] - hs, center[1] - hs, center[2] - hs], [center[0] + hs, center[1] + hs, center[2] + hs]);
+ }
+ }]);
+
+ return BoxBuilder;
+}(_primitiveStream.GeometryBuilderBase);
+
+/***/ }),
+
+/***/ "./src/geometry/primitive-stream.js":
+/*!******************************************!*\
+ !*** ./src/geometry/primitive-stream.js ***!
+ \******************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.GeometryBuilderBase = exports.PrimitiveStream = undefined;
+
+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; }; }(); // 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.
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+var _glMatrix = __webpack_require__(/*! ../math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var GL = WebGLRenderingContext; // For enums
+
+var tempVec3 = _glMatrix.vec3.create();
+
+var PrimitiveStream = exports.PrimitiveStream = function () {
+ function PrimitiveStream(options) {
+ _classCallCheck(this, PrimitiveStream);
+
+ this._vertices = [];
+ this._indices = [];
+
+ this._geometryStarted = false;
+
+ this._vertexOffset = 0;
+ this._vertexIndex = 0;
+ this._highIndex = 0;
+
+ this._flipWinding = false;
+ this._invertNormals = false;
+ this._transform = null;
+ this._normalTransform = null;
+ this._min = null;
+ this._max = null;
+ }
+
+ _createClass(PrimitiveStream, [{
+ key: 'startGeometry',
+ value: function startGeometry() {
+ if (this._geometryStarted) {
+ throw new Error('Attempted to start a new geometry before the previous one was ended.');
+ }
+
+ this._geometryStarted = true;
+ this._vertexIndex = 0;
+ this._highIndex = 0;
+ }
+ }, {
+ key: 'endGeometry',
+ value: function endGeometry() {
+ if (!this._geometryStarted) {
+ throw new Error('Attempted to end a geometry before one was started.');
+ }
+
+ if (this._highIndex >= this._vertexIndex) {
+ throw new Error('Geometry contains indices that are out of bounds.\n (Contains an index of ' + this._highIndex + ' when the vertex count is ' + this._vertexIndex + ')');
+ }
+
+ this._geometryStarted = false;
+ this._vertexOffset += this._vertexIndex;
+
+ // TODO: Anything else need to be done to finish processing here?
+ }
+ }, {
+ key: 'pushVertex',
+ value: function pushVertex(x, y, z) {
+ var u = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
+ var v = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
+ var nx = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
+ var ny = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
+ var nz = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
+
+ if (!this._geometryStarted) {
+ throw new Error('Cannot push vertices before calling startGeometry().');
+ }
+
+ // Transform the incoming vertex if we have a transformation matrix
+ if (this._transform) {
+ tempVec3[0] = x;
+ tempVec3[1] = y;
+ tempVec3[2] = z;
+ _glMatrix.vec3.transformMat4(tempVec3, tempVec3, this._transform);
+ x = tempVec3[0];
+ y = tempVec3[1];
+ z = tempVec3[2];
+
+ tempVec3[0] = nx;
+ tempVec3[1] = ny;
+ tempVec3[2] = nz;
+ _glMatrix.vec3.transformMat3(tempVec3, tempVec3, this._normalTransform);
+ nx = tempVec3[0];
+ ny = tempVec3[1];
+ nz = tempVec3[2];
+ }
+
+ if (this._invertNormals) {
+ nx *= -1.0;
+ ny *= -1.0;
+ nz *= -1.0;
+ }
+
+ this._vertices.push(x, y, z, u, v, nx, ny, nz);
+
+ if (this._min) {
+ this._min[0] = Math.min(this._min[0], x);
+ this._min[1] = Math.min(this._min[1], y);
+ this._min[2] = Math.min(this._min[2], z);
+ this._max[0] = Math.max(this._max[0], x);
+ this._max[1] = Math.max(this._max[1], y);
+ this._max[2] = Math.max(this._max[2], z);
+ } else {
+ this._min = _glMatrix.vec3.fromValues(x, y, z);
+ this._max = _glMatrix.vec3.fromValues(x, y, z);
+ }
+
+ return this._vertexIndex++;
+ }
+ }, {
+ key: 'pushTriangle',
+ value: function pushTriangle(idxA, idxB, idxC) {
+ if (!this._geometryStarted) {
+ throw new Error('Cannot push triangles before calling startGeometry().');
+ }
+
+ this._highIndex = Math.max(this._highIndex, idxA, idxB, idxC);
+
+ idxA += this._vertexOffset;
+ idxB += this._vertexOffset;
+ idxC += this._vertexOffset;
+
+ if (this._flipWinding) {
+ this._indices.push(idxC, idxB, idxA);
+ } else {
+ this._indices.push(idxA, idxB, idxC);
+ }
+ }
+ }, {
+ key: 'clear',
+ value: function clear() {
+ if (this._geometryStarted) {
+ throw new Error('Cannot clear before ending the current geometry.');
+ }
+
+ this._vertices = [];
+ this._indices = [];
+ this._vertexOffset = 0;
+ this._min = null;
+ this._max = null;
+ }
+ }, {
+ key: 'finishPrimitive',
+ value: function finishPrimitive(renderer) {
+ if (!this._vertexOffset) {
+ throw new Error('Attempted to call finishPrimitive() before creating any geometry.');
+ }
+
+ var vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(this._vertices));
+ var indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(this._indices));
+
+ var attribs = [new _primitive.PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 32, 0), new _primitive.PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 32, 12), new _primitive.PrimitiveAttribute('NORMAL', vertexBuffer, 3, GL.FLOAT, 32, 20)];
+
+ var primitive = new _primitive.Primitive(attribs, this._indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+ primitive.setBounds(this._min, this._max);
+
+ return primitive;
+ }
+ }, {
+ key: 'flipWinding',
+ set: function set(value) {
+ if (this._geometryStarted) {
+ throw new Error('Cannot change flipWinding before ending the current geometry.');
+ }
+ this._flipWinding = value;
+ },
+ get: function get() {
+ this._flipWinding;
+ }
+ }, {
+ key: 'invertNormals',
+ set: function set(value) {
+ if (this._geometryStarted) {
+ throw new Error('Cannot change invertNormals before ending the current geometry.');
+ }
+ this._invertNormals = value;
+ },
+ get: function get() {
+ this._invertNormals;
+ }
+ }, {
+ key: 'transform',
+ set: function set(value) {
+ if (this._geometryStarted) {
+ throw new Error('Cannot change transform before ending the current geometry.');
+ }
+ this._transform = value;
+ if (this._transform) {
+ if (!this._normalTransform) {
+ this._normalTransform = _glMatrix.mat3.create();
+ }
+ _glMatrix.mat3.fromMat4(this._normalTransform, this._transform);
+ }
+ },
+ get: function get() {
+ this._transform;
+ }
+ }, {
+ key: 'nextVertexIndex',
+ get: function get() {
+ return this._vertexIndex;
+ }
+ }]);
+
+ return PrimitiveStream;
+}();
+
+var GeometryBuilderBase = exports.GeometryBuilderBase = function () {
+ function GeometryBuilderBase(primitiveStream) {
+ _classCallCheck(this, GeometryBuilderBase);
+
+ if (primitiveStream) {
+ this._stream = primitiveStream;
+ } else {
+ this._stream = new PrimitiveStream();
+ }
+ }
+
+ _createClass(GeometryBuilderBase, [{
+ key: 'finishPrimitive',
+ value: function finishPrimitive(renderer) {
+ return this._stream.finishPrimitive(renderer);
+ }
+ }, {
+ key: 'clear',
+ value: function clear() {
+ this._stream.clear();
+ }
+ }, {
+ key: 'primitiveStream',
+ set: function set(value) {
+ this._stream = value;
+ },
+ get: function get() {
+ return this._stream;
+ }
+ }]);
+
+ return GeometryBuilderBase;
+}();
+
+/***/ }),
+
+/***/ "./src/loaders/gltf2.js":
+/*!******************************!*\
+ !*** ./src/loaders/gltf2.js ***!
+ \******************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Gltf2Loader = undefined;
+
+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; }; }(); // 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.
+
+var _pbr = __webpack_require__(/*! ../materials/pbr.js */ "./src/materials/pbr.js");
+
+var _node2 = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+var _texture = __webpack_require__(/*! ../core/texture.js */ "./src/core/texture.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var GL = WebGLRenderingContext; // For enums
+
+var GLB_MAGIC = 0x46546C67;
+var CHUNK_TYPE = {
+ JSON: 0x4E4F534A,
+ BIN: 0x004E4942
+};
+
+function isAbsoluteUri(uri) {
+ var absRegEx = new RegExp('^' + window.location.protocol, 'i');
+ return !!uri.match(absRegEx);
+}
+
+function isDataUri(uri) {
+ var dataRegEx = /^data:/;
+ return !!uri.match(dataRegEx);
+}
+
+function resolveUri(uri, baseUrl) {
+ if (isAbsoluteUri(uri) || isDataUri(uri)) {
+ return uri;
+ }
+ return baseUrl + uri;
+}
+
+function getComponentCount(type) {
+ switch (type) {
+ case 'SCALAR':
+ return 1;
+ case 'VEC2':
+ return 2;
+ case 'VEC3':
+ return 3;
+ case 'VEC4':
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Gltf2SceneLoader
+ * Loads glTF 2.0 scenes into a renderable node tree.
+ */
+
+var Gltf2Loader = exports.Gltf2Loader = function () {
+ function Gltf2Loader(renderer) {
+ _classCallCheck(this, Gltf2Loader);
+
+ this.renderer = renderer;
+ this._gl = renderer._gl;
+ }
+
+ _createClass(Gltf2Loader, [{
+ key: 'loadFromUrl',
+ value: function loadFromUrl(url) {
+ var _this = this;
+
+ return fetch(url).then(function (response) {
+ var i = url.lastIndexOf('/');
+ var baseUrl = i !== 0 ? url.substring(0, i + 1) : '';
+
+ if (url.endsWith('.gltf')) {
+ return response.json().then(function (json) {
+ return _this.loadFromJson(json, baseUrl);
+ });
+ } else if (url.endsWith('.glb')) {
+ return response.arrayBuffer().then(function (arrayBuffer) {
+ return _this.loadFromBinary(arrayBuffer, baseUrl);
+ });
+ } else {
+ throw new Error('Unrecognized file extension');
+ }
+ });
+ }
+ }, {
+ key: 'loadFromBinary',
+ value: function loadFromBinary(arrayBuffer, baseUrl) {
+ var headerView = new DataView(arrayBuffer, 0, 12);
+ var magic = headerView.getUint32(0, true);
+ var version = headerView.getUint32(4, true);
+ var length = headerView.getUint32(8, true);
+
+ if (magic != GLB_MAGIC) {
+ throw new Error('Invalid magic string in binary header.');
+ }
+
+ if (version != 2) {
+ throw new Error('Incompatible version in binary header.');
+ }
+
+ var chunks = {};
+ var chunkOffset = 12;
+ while (chunkOffset < length) {
+ var chunkHeaderView = new DataView(arrayBuffer, chunkOffset, 8);
+ var chunkLength = chunkHeaderView.getUint32(0, true);
+ var chunkType = chunkHeaderView.getUint32(4, true);
+ chunks[chunkType] = arrayBuffer.slice(chunkOffset + 8, chunkOffset + 8 + chunkLength);
+ chunkOffset += chunkLength + 8;
+ }
+
+ if (!chunks[CHUNK_TYPE.JSON]) {
+ throw new Error('File contained no json chunk.');
+ }
+
+ var decoder = new TextDecoder('utf-8');
+ var jsonString = decoder.decode(chunks[CHUNK_TYPE.JSON]);
+ var json = JSON.parse(jsonString);
+ return this.loadFromJson(json, baseUrl, chunks[CHUNK_TYPE.BIN]);
+ }
+ }, {
+ key: 'loadFromJson',
+ value: function loadFromJson(json, baseUrl, binaryChunk) {
+ if (!json.asset) {
+ throw new Error('Missing asset description.');
+ }
+
+ if (json.asset.minVersion != '2.0' && json.asset.version != '2.0') {
+ throw new Error('Incompatible asset version.');
+ }
+
+ var buffers = [];
+ if (binaryChunk) {
+ buffers[0] = new Gltf2Resource({}, baseUrl, binaryChunk);
+ } else {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = json.buffers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var buffer = _step.value;
+
+ buffers.push(new Gltf2Resource(buffer, baseUrl));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ var bufferViews = [];
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = json.bufferViews[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var bufferView = _step2.value;
+
+ bufferViews.push(new Gltf2BufferView(bufferView, buffers));
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ var images = [];
+ if (json.images) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = json.images[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var image = _step3.value;
+
+ images.push(new Gltf2Resource(image, baseUrl));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+ }
+
+ var textures = [];
+ if (json.textures) {
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = json.textures[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var texture = _step4.value;
+
+ var _image = images[texture.source];
+ var glTexture = _image.texture(bufferViews);
+ if (texture.sampler) {
+ var sampler = sampler[texture.sampler];
+ glTexture.sampler.minFilter = sampler.minFilter;
+ glTexture.sampler.magFilter = sampler.magFilter;
+ glTexture.sampler.wrapS = sampler.wrapS;
+ glTexture.sampler.wrapT = sampler.wrapT;
+ }
+ textures.push(glTexture);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+ }
+
+ function getTexture(textureInfo) {
+ if (!textureInfo) {
+ return null;
+ }
+ return textures[textureInfo.index];
+ }
+
+ var materials = [];
+ if (json.materials) {
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = json.materials[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var material = _step5.value;
+
+ var glMaterial = new _pbr.PbrMaterial();
+ var pbr = material.pbrMetallicRoughness || {};
+
+ glMaterial.baseColorFactor.value = pbr.baseColorFactor || [1, 1, 1, 1];
+ glMaterial.baseColor.texture = getTexture(pbr.baseColorTexture);
+ glMaterial.metallicRoughnessFactor.value = [pbr.metallicFactor || 1.0, pbr.roughnessFactor || 1.0];
+ glMaterial.metallicRoughness.texture = getTexture(pbr.metallicRoughnessTexture);
+ glMaterial.normal.texture = getTexture(json.normalTexture);
+ glMaterial.occlusion.texture = getTexture(json.occlusionTexture);
+ glMaterial.occlusionStrength.value = json.occlusionTexture && json.occlusionTexture.strength ? json.occlusionTexture.strength : 1.0;
+ glMaterial.emissiveFactor.value = material.emissiveFactor || [0, 0, 0];
+ glMaterial.emissive.texture = getTexture(json.emissiveTexture);
+ if (!glMaterial.emissive.texture && json.emissiveFactor) {
+ glMaterial.emissive.texture = new _texture.ColorTexture(1.0, 1.0, 1.0, 1.0);
+ }
+
+ switch (material.alphaMode) {
+ case 'BLEND':
+ glMaterial.state.blend = true;
+ break;
+ case 'MASK':
+ // Not really supported.
+ glMaterial.state.blend = true;
+ break;
+ default:
+ // Includes 'OPAQUE'
+ glMaterial.state.blend = false;
+ }
+
+ // glMaterial.alpha_mode = material.alphaMode;
+ // glMaterial.alpha_cutoff = material.alphaCutoff;
+ glMaterial.state.cullFace = !material.doubleSided;
+
+ materials.push(glMaterial);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5.return) {
+ _iterator5.return();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+ }
+
+ var accessors = json.accessors;
+
+ var meshes = [];
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = json.meshes[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mesh = _step6.value;
+
+ var glMesh = new Gltf2Mesh();
+ meshes.push(glMesh);
+
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = mesh.primitives[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var primitive = _step8.value;
+
+ var _material = null;
+ if ('material' in primitive) {
+ _material = materials[primitive.material];
+ } else {
+ // Create a "default" material if the primitive has none.
+ _material = new _pbr.PbrMaterial();
+ }
+
+ var attributes = [];
+ var elementCount = 0;
+ /* let glPrimitive = new Gltf2Primitive(primitive, material);
+ glMesh.primitives.push(glPrimitive); */
+
+ var min = null;
+ var max = null;
+
+ for (var name in primitive.attributes) {
+ var accessor = accessors[primitive.attributes[name]];
+ var _bufferView = bufferViews[accessor.bufferView];
+ elementCount = accessor.count;
+
+ var glAttribute = new _primitive.PrimitiveAttribute(name, _bufferView.renderBuffer(this.renderer, GL.ARRAY_BUFFER), getComponentCount(accessor.type), accessor.componentType, _bufferView.byteStride || 0, accessor.byteOffset || 0);
+ glAttribute.normalized = accessor.normalized || false;
+
+ if (name == 'POSITION') {
+ min = accessor.min;
+ max = accessor.max;
+ }
+
+ attributes.push(glAttribute);
+ }
+
+ var glPrimitive = new _primitive.Primitive(attributes, elementCount, primitive.mode);
+
+ if ('indices' in primitive) {
+ var _accessor = accessors[primitive.indices];
+ var _bufferView2 = bufferViews[_accessor.bufferView];
+
+ glPrimitive.setIndexBuffer(_bufferView2.renderBuffer(this.renderer, GL.ELEMENT_ARRAY_BUFFER), _accessor.byteOffset || 0, _accessor.componentType);
+ glPrimitive.indexType = _accessor.componentType;
+ glPrimitive.indexByteOffset = _accessor.byteOffset || 0;
+ glPrimitive.elementCount = _accessor.count;
+ }
+
+ if (min && max) {
+ glPrimitive.setBounds(min, max);
+ }
+
+ // After all the attributes have been processed, get a program that is
+ // appropriate for both the material and the primitive attributes.
+ glMesh.primitives.push(this.renderer.createRenderPrimitive(glPrimitive, _material));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8.return) {
+ _iterator8.return();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6.return) {
+ _iterator6.return();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var sceneNode = new _node2.Node();
+ var scene = json.scenes[json.scene];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = scene.nodes[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var nodeId = _step7.value;
+
+ var node = json.nodes[nodeId];
+ sceneNode.addNode(this.processNodes(node, json.nodes, meshes));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7.return) {
+ _iterator7.return();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ return sceneNode;
+ }
+ }, {
+ key: 'processNodes',
+ value: function processNodes(node, nodes, meshes) {
+ var glNode = new _node2.Node();
+ glNode.name = node.name;
+
+ if ('mesh' in node) {
+ var mesh = meshes[node.mesh];
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = mesh.primitives[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var primitive = _step9.value;
+
+ glNode.addRenderPrimitive(primitive);
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9.return) {
+ _iterator9.return();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+ }
+
+ if (node.matrix) {
+ glNode.matrix = new Float32Array(node.matrix);
+ } else if (node.translation || node.rotation || node.scale) {
+ if (node.translation) {
+ glNode.translation = new Float32Array(node.translation);
+ }
+
+ if (node.rotation) {
+ glNode.rotation = new Float32Array(node.rotation);
+ }
+
+ if (node.scale) {
+ glNode.scale = new Float32Array(node.scale);
+ }
+ }
+
+ if (node.children) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = node.children[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var nodeId = _step10.value;
+
+ var _node = nodes[nodeId];
+ glNode.addNode(this.processNodes(_node, nodes, meshes));
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10.return) {
+ _iterator10.return();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+ }
+
+ return glNode;
+ }
+ }]);
+
+ return Gltf2Loader;
+}();
+
+var Gltf2Mesh = function Gltf2Mesh() {
+ _classCallCheck(this, Gltf2Mesh);
+
+ this.primitives = [];
+};
+
+var Gltf2BufferView = function () {
+ function Gltf2BufferView(json, buffers) {
+ _classCallCheck(this, Gltf2BufferView);
+
+ this.buffer = buffers[json.buffer];
+ this.byteOffset = json.byteOffset || 0;
+ this.byteLength = json.byteLength || null;
+ this.byteStride = json.byteStride;
+
+ this._viewPromise = null;
+ this._renderBuffer = null;
+ }
+
+ _createClass(Gltf2BufferView, [{
+ key: 'dataView',
+ value: function dataView() {
+ var _this2 = this;
+
+ if (!this._viewPromise) {
+ this._viewPromise = this.buffer.arrayBuffer().then(function (arrayBuffer) {
+ return new DataView(arrayBuffer, _this2.byteOffset, _this2.byteLength);
+ });
+ }
+ return this._viewPromise;
+ }
+ }, {
+ key: 'renderBuffer',
+ value: function renderBuffer(renderer, target) {
+ if (!this._renderBuffer) {
+ this._renderBuffer = renderer.createRenderBuffer(target, this.dataView());
+ }
+ return this._renderBuffer;
+ }
+ }]);
+
+ return Gltf2BufferView;
+}();
+
+var Gltf2Resource = function () {
+ function Gltf2Resource(json, baseUrl, arrayBuffer) {
+ _classCallCheck(this, Gltf2Resource);
+
+ this.json = json;
+ this.baseUrl = baseUrl;
+
+ this._dataPromise = null;
+ this._texture = null;
+ if (arrayBuffer) {
+ this._dataPromise = Promise.resolve(arrayBuffer);
+ }
+ }
+
+ _createClass(Gltf2Resource, [{
+ key: 'arrayBuffer',
+ value: function arrayBuffer() {
+ if (!this._dataPromise) {
+ if (isDataUri(this.json.uri)) {
+ var base64String = this.json.uri.replace('data:application/octet-stream;base64,', '');
+ var binaryArray = Uint8Array.from(atob(base64String), function (c) {
+ return c.charCodeAt(0);
+ });
+ this._dataPromise = Promise.resolve(binaryArray.buffer);
+ return this._dataPromise;
+ }
+
+ this._dataPromise = fetch(resolveUri(this.json.uri, this.baseUrl)).then(function (response) {
+ return response.arrayBuffer();
+ });
+ }
+ return this._dataPromise;
+ }
+ }, {
+ key: 'texture',
+ value: function texture(bufferViews) {
+ var _this3 = this;
+
+ if (!this._texture) {
+ var img = new Image();
+ this._texture = new _texture.ImageTexture(img);
+
+ if (this.json.uri) {
+ if (isDataUri(this.json.uri)) {
+ img.src = this.json.uri;
+ } else {
+ img.src = '' + this.baseUrl + this.json.uri;
+ }
+ } else {
+ var view = bufferViews[this.json.bufferView];
+ view.dataView().then(function (dataView) {
+ var blob = new Blob([dataView], { type: _this3.json.mimeType });
+ img.src = window.URL.createObjectURL(blob);
+ });
+ }
+ }
+ return this._texture;
+ }
+ }]);
+
+ return Gltf2Resource;
+}();
+
+/***/ }),
+
+/***/ "./src/materials/pbr.js":
+/*!******************************!*\
+ !*** ./src/materials/pbr.js ***!
+ \******************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PbrMaterial = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _renderer = __webpack_require__(/*! ../core/renderer.js */ "./src/core/renderer.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+var VERTEX_SOURCE = '\nattribute vec3 POSITION, NORMAL;\nattribute vec2 TEXCOORD_0, TEXCOORD_1;\n\nuniform vec3 CAMERA_POSITION;\nuniform vec3 LIGHT_DIRECTION;\n\nvarying vec3 vLight; // Vector from vertex to light.\nvarying vec3 vView; // Vector from vertex to camera.\nvarying vec2 vTex;\n\n#ifdef USE_NORMAL_MAP\nattribute vec4 TANGENT;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_VERTEX_COLOR\nattribute vec4 COLOR_0;\nvarying vec4 vCol;\n#endif\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));\n#ifdef USE_NORMAL_MAP\n vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));\n vec3 b = cross(n, t) * TANGENT.w;\n vTBN = mat3(t, b, n);\n#else\n vNorm = n;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n vCol = COLOR_0;\n#endif\n\n vTex = TEXCOORD_0;\n vec4 mPos = model * vec4(POSITION, 1.0);\n vLight = -LIGHT_DIRECTION;\n vView = CAMERA_POSITION - mPos.xyz;\n return proj * view * mPos;\n}';
+
+// These equations are borrowed with love from this docs from Epic because I
+// just don't have anything novel to bring to the PBR scene.
+// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
+var EPIC_PBR_FUNCTIONS = '\nvec3 lambertDiffuse(vec3 cDiff) {\n return cDiff / M_PI;\n}\n\nfloat specD(float a, float nDotH) {\n float aSqr = a * a;\n float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);\n return aSqr / (M_PI * f * f);\n}\n\nfloat specG(float roughness, float nDotL, float nDotV) {\n float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n float gl = nDotL / (nDotL * (1.0 - k) + k);\n float gv = nDotV / (nDotV * (1.0 - k) + k);\n return gl * gv;\n}\n\nvec3 specF(float vDotH, vec3 F0) {\n float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;\n float base = 2.0;\n return F0 + (1.0 - F0) * pow(base, exponent);\n}';
+
+var FRAGMENT_SOURCE = '\n#define M_PI 3.14159265\n\nuniform vec4 baseColorFactor;\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D baseColorTex;\n#endif\n\nvarying vec3 vLight;\nvarying vec3 vView;\nvarying vec2 vTex;\n\n#ifdef USE_VERTEX_COLOR\nvarying vec4 vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\nuniform sampler2D normalTex;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_METAL_ROUGH_MAP\nuniform sampler2D metallicRoughnessTex;\n#endif\nuniform vec2 metallicRoughnessFactor;\n\n#ifdef USE_OCCLUSION\nuniform sampler2D occlusionTex;\nuniform float occlusionStrength;\n#endif\n\n#ifdef USE_EMISSIVE_TEXTURE\nuniform sampler2D emissiveTex;\n#endif\nuniform vec3 emissiveFactor;\n\nuniform vec3 LIGHT_COLOR;\n\nconst vec3 dielectricSpec = vec3(0.04);\nconst vec3 black = vec3(0.0);\n\n' + EPIC_PBR_FUNCTIONS + '\n\nvec4 fragment_main() {\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;\n#else\n vec4 baseColor = baseColorFactor;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n baseColor *= vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\n vec3 n = texture2D(normalTex, vTex).rgb;\n n = normalize(vTBN * (2.0 * n - 1.0));\n#else\n vec3 n = normalize(vNorm);\n#endif\n\n#ifdef FULLY_ROUGH\n float metallic = 0.0;\n#else\n float metallic = metallicRoughnessFactor.x;\n#endif\n\n float roughness = metallicRoughnessFactor.y;\n\n#ifdef USE_METAL_ROUGH_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);\n metallic *= metallicRoughness.b;\n roughness *= metallicRoughness.g;\n#endif\n \n vec3 l = normalize(vLight);\n vec3 v = normalize(vView);\n vec3 h = normalize(l+v);\n\n float nDotL = clamp(dot(n, l), 0.001, 1.0);\n float nDotV = abs(dot(n, v)) + 0.001;\n float nDotH = max(dot(n, h), 0.0);\n float vDotH = max(dot(v, h), 0.0);\n\n // From GLTF Spec\n vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color\n vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color\n float a = roughness * roughness;\n\n#ifdef FULLY_ROUGH\n vec3 specular = F0 * 0.45;\n#else\n vec3 F = specF(vDotH, F0);\n float D = specD(a, nDotH);\n float G = specG(roughness, nDotL, nDotV);\n vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);\n#endif\n float halfLambert = dot(n, l) * 0.5 + 0.5;\n halfLambert *= halfLambert;\n\n vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;\n\n#ifdef USE_OCCLUSION\n float occlusion = texture2D(occlusionTex, vTex).r;\n color = mix(color, color * occlusion, occlusionStrength);\n#endif\n \n vec3 emissive = emissiveFactor;\n#ifdef USE_EMISSIVE_TEXTURE\n emissive *= texture2D(emissiveTex, vTex).rgb;\n#endif\n color += emissive;\n\n // gamma correction\n //color = pow(color, vec3(1.0/2.2));\n\n return vec4(color, baseColor.a);\n}';
+
+var PbrMaterial = exports.PbrMaterial = function (_Material) {
+ _inherits(PbrMaterial, _Material);
+
+ function PbrMaterial() {
+ _classCallCheck(this, PbrMaterial);
+
+ var _this = _possibleConstructorReturn(this, (PbrMaterial.__proto__ || Object.getPrototypeOf(PbrMaterial)).call(this));
+
+ _this.baseColor = _this.defineSampler('baseColorTex');
+ _this.metallicRoughness = _this.defineSampler('metallicRoughnessTex');
+ _this.normal = _this.defineSampler('normalTex');
+ _this.occlusion = _this.defineSampler('occlusionTex');
+ _this.emissive = _this.defineSampler('emissiveTex');
+
+ _this.baseColorFactor = _this.defineUniform('baseColorFactor', [1.0, 1.0, 1.0, 1.0]);
+ _this.metallicRoughnessFactor = _this.defineUniform('metallicRoughnessFactor', [1.0, 1.0]);
+ _this.occlusionStrength = _this.defineUniform('occlusionStrength', 1.0);
+ _this.emissiveFactor = _this.defineUniform('emissiveFactor', [0, 0, 0]);
+ return _this;
+ }
+
+ _createClass(PbrMaterial, [{
+ key: 'getProgramDefines',
+ value: function getProgramDefines(renderPrimitive) {
+ var programDefines = {};
+
+ if (renderPrimitive._attributeMask & _renderer.ATTRIB_MASK.COLOR_0) {
+ programDefines['USE_VERTEX_COLOR'] = 1;
+ }
+
+ if (renderPrimitive._attributeMask & _renderer.ATTRIB_MASK.TEXCOORD_0) {
+ if (this.baseColor.texture) {
+ programDefines['USE_BASE_COLOR_MAP'] = 1;
+ }
+
+ if (this.normal.texture && renderPrimitive._attributeMask & _renderer.ATTRIB_MASK.TANGENT) {
+ programDefines['USE_NORMAL_MAP'] = 1;
+ }
+
+ if (this.metallicRoughness.texture) {
+ programDefines['USE_METAL_ROUGH_MAP'] = 1;
+ }
+
+ if (this.occlusion.texture) {
+ programDefines['USE_OCCLUSION'] = 1;
+ }
+
+ if (this.emissive.texture) {
+ programDefines['USE_EMISSIVE_TEXTURE'] = 1;
+ }
+ }
+
+ if ((!this.metallicRoughness.texture || !(renderPrimitive._attributeMask & _renderer.ATTRIB_MASK.TEXCOORD_0)) && this.metallicRoughnessFactor.value[1] == 1.0) {
+ programDefines['FULLY_ROUGH'] = 1;
+ }
+
+ return programDefines;
+ }
+ }, {
+ key: 'materialName',
+ get: function get() {
+ return 'PBR';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return VERTEX_SOURCE;
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return FRAGMENT_SOURCE;
+ }
+ }]);
+
+ return PbrMaterial;
+}(_material.Material);
+
+/***/ }),
+
+/***/ "./src/math/gl-matrix.js":
+/*!*******************************!*\
+ !*** ./src/math/gl-matrix.js ***!
+ \*******************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.vec4 = exports.vec3 = exports.vec2 = exports.quat2 = exports.quat = exports.mat4 = exports.mat3 = exports.mat2d = exports.mat2 = exports.glMatrix = undefined;
+
+var _common = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js");
+
+var glMatrix = _interopRequireWildcard(_common);
+
+var _mat = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/mat2.js */ "./node_modules/gl-matrix/src/gl-matrix/mat2.js");
+
+var mat2 = _interopRequireWildcard(_mat);
+
+var _mat2d = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/mat2d.js */ "./node_modules/gl-matrix/src/gl-matrix/mat2d.js");
+
+var mat2d = _interopRequireWildcard(_mat2d);
+
+var _mat2 = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/mat3.js */ "./node_modules/gl-matrix/src/gl-matrix/mat3.js");
+
+var mat3 = _interopRequireWildcard(_mat2);
+
+var _mat3 = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/mat4.js */ "./node_modules/gl-matrix/src/gl-matrix/mat4.js");
+
+var mat4 = _interopRequireWildcard(_mat3);
+
+var _quat = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/quat.js */ "./node_modules/gl-matrix/src/gl-matrix/quat.js");
+
+var quat = _interopRequireWildcard(_quat);
+
+var _quat2 = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/quat2.js */ "./node_modules/gl-matrix/src/gl-matrix/quat2.js");
+
+var quat2 = _interopRequireWildcard(_quat2);
+
+var _vec = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/vec2.js */ "./node_modules/gl-matrix/src/gl-matrix/vec2.js");
+
+var vec2 = _interopRequireWildcard(_vec);
+
+var _vec2 = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/vec3.js */ "./node_modules/gl-matrix/src/gl-matrix/vec3.js");
+
+var vec3 = _interopRequireWildcard(_vec2);
+
+var _vec3 = __webpack_require__(/*! ../../node_modules/gl-matrix/src/gl-matrix/vec4.js */ "./node_modules/gl-matrix/src/gl-matrix/vec4.js");
+
+var vec4 = _interopRequireWildcard(_vec3);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+// 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.
+
+exports.glMatrix = glMatrix;
+exports.mat2 = mat2;
+exports.mat2d = mat2d;
+exports.mat3 = mat3;
+exports.mat4 = mat4;
+exports.quat = quat;
+exports.quat2 = quat2;
+exports.vec2 = vec2;
+exports.vec3 = vec3;
+exports.vec4 = vec4;
+
+/***/ }),
+
+/***/ "./src/math/ray.js":
+/*!*************************!*\
+ !*** ./src/math/ray.js ***!
+ \*************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Ray = undefined;
+
+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; }; }(); // 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.
+
+var _glMatrix = __webpack_require__(/*! ./gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var normalMat = _glMatrix.mat3.create();
+
+var RAY_INTERSECTION_OFFSET = 0.02;
+
+var Ray = exports.Ray = function () {
+ function Ray() {
+ var matrix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
+
+ _classCallCheck(this, Ray);
+
+ this.origin = _glMatrix.vec3.create();
+
+ this._dir = _glMatrix.vec3.create();
+ this._dir[2] = -1.0;
+
+ if (matrix) {
+ _glMatrix.vec3.transformMat4(this.origin, this.origin, matrix);
+ _glMatrix.mat3.fromMat4(normalMat, matrix);
+ _glMatrix.vec3.transformMat3(this._dir, this._dir, normalMat);
+ }
+
+ // To force the inverse and sign calculations.
+ this.dir = this._dir;
+ }
+
+ _createClass(Ray, [{
+ key: 'intersectsAABB',
+
+
+ // Borrowed from:
+ // eslint-disable-next-line max-len
+ // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
+ value: function intersectsAABB(min, max) {
+ var r = this;
+
+ var bounds = [min, max];
+
+ var tmin = (bounds[r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];
+ var tmax = (bounds[1 - r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];
+ var tymin = (bounds[r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];
+ var tymax = (bounds[1 - r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];
+
+ if (tmin > tymax || tymin > tmax) {
+ return null;
+ }
+ if (tymin > tmin) {
+ tmin = tymin;
+ }
+ if (tymax < tmax) {
+ tmax = tymax;
+ }
+
+ var tzmin = (bounds[r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];
+ var tzmax = (bounds[1 - r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];
+
+ if (tmin > tzmax || tzmin > tmax) {
+ return null;
+ }
+ if (tzmin > tmin) {
+ tmin = tzmin;
+ }
+ if (tzmax < tmax) {
+ tmax = tzmax;
+ }
+
+ var t = -1;
+ if (tmin > 0 && tmax > 0) {
+ t = Math.min(tmin, tmax);
+ } else if (tmin > 0) {
+ t = tmin;
+ } else if (tmax > 0) {
+ t = tmax;
+ } else {
+ // Intersection is behind the ray origin.
+ return null;
+ }
+
+ // Push ray intersection point back along the ray a bit so that cursors
+ // don't accidentally intersect with the hit surface.
+ t -= RAY_INTERSECTION_OFFSET;
+
+ // Return the point where the ray first intersected with the AABB.
+ var intersectionPoint = _glMatrix.vec3.clone(this._dir);
+ _glMatrix.vec3.scale(intersectionPoint, intersectionPoint, t);
+ _glMatrix.vec3.add(intersectionPoint, intersectionPoint, this.origin);
+ return intersectionPoint;
+ }
+ }, {
+ key: 'dir',
+ get: function get() {
+ return this._dir;
+ },
+ set: function set(value) {
+ this._dir = _glMatrix.vec3.copy(this._dir, value);
+ _glMatrix.vec3.normalize(this._dir, this._dir);
+
+ this.inv_dir = _glMatrix.vec3.fromValues(1.0 / this._dir[0], 1.0 / this._dir[1], 1.0 / this._dir[2]);
+
+ this.sign = [this.inv_dir[0] < 0 ? 1 : 0, this.inv_dir[1] < 0 ? 1 : 0, this.inv_dir[2] < 0 ? 1 : 0];
+ }
+ }]);
+
+ return Ray;
+}();
+
+/***/ }),
+
+/***/ "./src/nodes/bounds-renderer.js":
+/*!**************************************!*\
+ !*** ./src/nodes/bounds-renderer.js ***!
+ \**************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.BoundsRenderer = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+/*
+This file renders a passed in XRStageBounds object and attempts
+to render geometry on the floor to indicate where the bounds is.
+XRStageBounds' `geometry` is a series of XRStageBoundsPoints (in
+clockwise-order) with `x` and `z` properties for each.
+*/
+
+var GL = WebGLRenderingContext; // For enums
+
+var BoundsMaterial = function (_Material) {
+ _inherits(BoundsMaterial, _Material);
+
+ function BoundsMaterial() {
+ _classCallCheck(this, BoundsMaterial);
+
+ var _this = _possibleConstructorReturn(this, (BoundsMaterial.__proto__ || Object.getPrototypeOf(BoundsMaterial)).call(this));
+
+ _this.state.blend = true;
+ _this.state.blendFuncSrc = GL.SRC_ALPHA;
+ _this.state.blendFuncDst = GL.ONE;
+ _this.state.depthTest = false;
+ return _this;
+ }
+
+ _createClass(BoundsMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'BOUNDS_RENDERER';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 1.0);\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n precision mediump float;\n\n vec4 fragment_main() {\n return vec4(0.0, 1.0, 0.0, 0.3);\n }';
+ }
+ }]);
+
+ return BoundsMaterial;
+}(_material.Material);
+
+var BoundsRenderer = exports.BoundsRenderer = function (_Node) {
+ _inherits(BoundsRenderer, _Node);
+
+ function BoundsRenderer() {
+ _classCallCheck(this, BoundsRenderer);
+
+ var _this2 = _possibleConstructorReturn(this, (BoundsRenderer.__proto__ || Object.getPrototypeOf(BoundsRenderer)).call(this));
+
+ _this2._stageBounds = null;
+ return _this2;
+ }
+
+ _createClass(BoundsRenderer, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ this.stageBounds = this._stageBounds;
+ }
+ }, {
+ key: 'stageBounds',
+ get: function get() {
+ return this._stageBounds;
+ },
+ set: function set(stageBounds) {
+ if (this._stageBounds) {
+ this.clearRenderPrimitives();
+ }
+ this._stageBounds = stageBounds;
+ if (!stageBounds || stageBounds.length === 0 || !this._renderer) {
+ return;
+ }
+
+ var verts = [];
+ var indices = [];
+
+ // Tessellate the bounding points from XRStageBounds and connect
+ // each point to a neighbor and 0,0,0.
+ var pointCount = stageBounds.geometry.length;
+ for (var i = 0; i < pointCount; i++) {
+ var point = stageBounds.geometry[i];
+ verts.push(point.x, 0, point.z);
+ indices.push(i, i === 0 ? pointCount - 1 : i - 1, pointCount);
+ }
+ // Center point
+ verts.push(0, 0, 0);
+
+ var vertexBuffer = this._renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(verts));
+ var indexBuffer = this._renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ var attribs = [new _primitive.PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 12, 0)];
+
+ var primitive = new _primitive.Primitive(attribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+
+ var renderPrimitive = this._renderer.createRenderPrimitive(primitive, new BoundsMaterial());
+ this.addRenderPrimitive(renderPrimitive);
+ }
+ }]);
+
+ return BoundsRenderer;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/button.js":
+/*!*****************************!*\
+ !*** ./src/nodes/button.js ***!
+ \*****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ButtonNode = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _primitiveStream = __webpack_require__(/*! ../geometry/primitive-stream.js */ "./src/geometry/primitive-stream.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+var BUTTON_SIZE = 0.1;
+var BUTTON_CORNER_RADIUS = 0.025;
+var BUTTON_CORNER_SEGMENTS = 8;
+var BUTTON_ICON_SIZE = 0.07;
+var BUTTON_LAYER_DISTANCE = 0.005;
+var BUTTON_COLOR = 0.75;
+var BUTTON_ALPHA = 0.85;
+var BUTTON_HOVER_COLOR = 0.9;
+var BUTTON_HOVER_ALPHA = 1.0;
+var BUTTON_HOVER_SCALE = 1.1;
+var BUTTON_HOVER_TRANSITION_TIME_MS = 200;
+
+var ButtonMaterial = function (_Material) {
+ _inherits(ButtonMaterial, _Material);
+
+ function ButtonMaterial() {
+ _classCallCheck(this, ButtonMaterial);
+
+ var _this = _possibleConstructorReturn(this, (ButtonMaterial.__proto__ || Object.getPrototypeOf(ButtonMaterial)).call(this));
+
+ _this.state.blend = true;
+
+ _this.defineUniform('hoverAmount', 0);
+ return _this;
+ }
+
+ _createClass(ButtonMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'BUTTON_MATERIAL';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec3 POSITION;\n\n uniform float hoverAmount;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n float scale = mix(1.0, ' + BUTTON_HOVER_SCALE + ', hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n uniform float hoverAmount;\n\n const vec4 default_color = vec4(' + BUTTON_COLOR + ', ' + BUTTON_COLOR + ', ' + BUTTON_COLOR + ', ' + BUTTON_ALPHA + ');\n const vec4 hover_color = vec4(' + BUTTON_HOVER_COLOR + ', ' + BUTTON_HOVER_COLOR + ',\n ' + BUTTON_HOVER_COLOR + ', ' + BUTTON_HOVER_ALPHA + ');\n\n vec4 fragment_main() {\n return mix(default_color, hover_color, hoverAmount);\n }';
+ }
+ }]);
+
+ return ButtonMaterial;
+}(_material.Material);
+
+var ButtonIconMaterial = function (_Material2) {
+ _inherits(ButtonIconMaterial, _Material2);
+
+ function ButtonIconMaterial() {
+ _classCallCheck(this, ButtonIconMaterial);
+
+ var _this2 = _possibleConstructorReturn(this, (ButtonIconMaterial.__proto__ || Object.getPrototypeOf(ButtonIconMaterial)).call(this));
+
+ _this2.state.blend = true;
+
+ _this2.defineUniform('hoverAmount', 0);
+ _this2.icon = _this2.defineSampler('icon');
+ return _this2;
+ }
+
+ _createClass(ButtonIconMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'BUTTON_ICON_MATERIAL';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n uniform float hoverAmount;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n float scale = mix(1.0, ' + BUTTON_HOVER_SCALE + ', hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n uniform sampler2D icon;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(icon, vTexCoord);\n }';
+ }
+ }]);
+
+ return ButtonIconMaterial;
+}(_material.Material);
+
+var ButtonNode = exports.ButtonNode = function (_Node) {
+ _inherits(ButtonNode, _Node);
+
+ function ButtonNode(iconTexture, callback) {
+ _classCallCheck(this, ButtonNode);
+
+ // All buttons are selectable by default.
+ var _this3 = _possibleConstructorReturn(this, (ButtonNode.__proto__ || Object.getPrototypeOf(ButtonNode)).call(this));
+
+ _this3.selectable = true;
+
+ _this3._selectHandler = callback;
+ _this3._iconTexture = iconTexture;
+ _this3._hovered = false;
+ _this3._hoverT = 0;
+ return _this3;
+ }
+
+ _createClass(ButtonNode, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ var stream = new _primitiveStream.PrimitiveStream();
+
+ var hd = BUTTON_LAYER_DISTANCE * 0.5;
+
+ // Build a rounded rect for the background.
+ var hs = BUTTON_SIZE * 0.5;
+ var ihs = hs - BUTTON_CORNER_RADIUS;
+ stream.startGeometry();
+
+ // Rounded corners and sides
+ var segments = BUTTON_CORNER_SEGMENTS * 4;
+ for (var i = 0; i < segments; ++i) {
+ var rad = i * (Math.PI * 2.0 / segments);
+ var x = Math.cos(rad) * BUTTON_CORNER_RADIUS;
+ var y = Math.sin(rad) * BUTTON_CORNER_RADIUS;
+ var section = Math.floor(i / BUTTON_CORNER_SEGMENTS);
+ switch (section) {
+ case 0:
+ x += ihs;
+ y += ihs;
+ break;
+ case 1:
+ x -= ihs;
+ y += ihs;
+ break;
+ case 2:
+ x -= ihs;
+ y -= ihs;
+ break;
+ case 3:
+ x += ihs;
+ y -= ihs;
+ break;
+ }
+
+ stream.pushVertex(x, y, -hd, 0, 0, 0, 0, 1);
+
+ if (i > 1) {
+ stream.pushTriangle(0, i - 1, i);
+ }
+ }
+
+ stream.endGeometry();
+
+ var buttonPrimitive = stream.finishPrimitive(renderer);
+ this._buttonRenderPrimitive = renderer.createRenderPrimitive(buttonPrimitive, new ButtonMaterial());
+ this.addRenderPrimitive(this._buttonRenderPrimitive);
+
+ // Build a simple textured quad for the foreground.
+ hs = BUTTON_ICON_SIZE * 0.5;
+ stream.clear();
+ stream.startGeometry();
+
+ stream.pushVertex(-hs, hs, hd, 0, 0, 0, 0, 1);
+ stream.pushVertex(-hs, -hs, hd, 0, 1, 0, 0, 1);
+ stream.pushVertex(hs, -hs, hd, 1, 1, 0, 0, 1);
+ stream.pushVertex(hs, hs, hd, 1, 0, 0, 0, 1);
+
+ stream.pushTriangle(0, 1, 2);
+ stream.pushTriangle(0, 2, 3);
+
+ stream.endGeometry();
+
+ var iconPrimitive = stream.finishPrimitive(renderer);
+ var iconMaterial = new ButtonIconMaterial();
+ iconMaterial.icon.texture = this._iconTexture;
+ this._iconRenderPrimitive = renderer.createRenderPrimitive(iconPrimitive, iconMaterial);
+ this.addRenderPrimitive(this._iconRenderPrimitive);
+ }
+ }, {
+ key: 'onHoverStart',
+ value: function onHoverStart() {
+ this._hovered = true;
+ }
+ }, {
+ key: 'onHoverEnd',
+ value: function onHoverEnd() {
+ this._hovered = false;
+ }
+ }, {
+ key: '_updateHoverState',
+ value: function _updateHoverState() {
+ var t = this._hoverT / BUTTON_HOVER_TRANSITION_TIME_MS;
+ // Cubic Ease In/Out
+ // TODO: Get a better animation system
+ var hoverAmount = t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
+ this._buttonRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;
+ this._iconRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;
+ }
+ }, {
+ key: 'onUpdate',
+ value: function onUpdate(timestamp, frameDelta) {
+ if (this._hovered && this._hoverT < BUTTON_HOVER_TRANSITION_TIME_MS) {
+ this._hoverT = Math.min(BUTTON_HOVER_TRANSITION_TIME_MS, this._hoverT + frameDelta);
+ this._updateHoverState();
+ } else if (!this._hovered && this._hoverT > 0) {
+ this._hoverT = Math.max(0.0, this._hoverT - frameDelta);
+ this._updateHoverState();
+ }
+ }
+ }, {
+ key: 'iconTexture',
+ get: function get() {
+ return this._iconTexture;
+ },
+ set: function set(value) {
+ if (this._iconTexture == value) {
+ return;
+ }
+
+ this._iconTexture = value;
+ this._iconRenderPrimitive.samplers.icon.texture = value;
+ }
+ }]);
+
+ return ButtonNode;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/cube-sea.js":
+/*!*******************************!*\
+ !*** ./src/nodes/cube-sea.js ***!
+ \*******************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.CubeSeaNode = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _texture = __webpack_require__(/*! ../core/texture.js */ "./src/core/texture.js");
+
+var _boxBuilder = __webpack_require__(/*! ../geometry/box-builder.js */ "./src/geometry/box-builder.js");
+
+var _glMatrix = __webpack_require__(/*! ../math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+var CubeSeaMaterial = function (_Material) {
+ _inherits(CubeSeaMaterial, _Material);
+
+ function CubeSeaMaterial() {
+ var heavy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+
+ _classCallCheck(this, CubeSeaMaterial);
+
+ var _this = _possibleConstructorReturn(this, (CubeSeaMaterial.__proto__ || Object.getPrototypeOf(CubeSeaMaterial)).call(this));
+
+ _this.heavy = heavy;
+
+ _this.baseColor = _this.defineSampler('baseColor');
+ return _this;
+ }
+
+ _createClass(CubeSeaMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'CUBE_SEA';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n attribute vec3 NORMAL;\n\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n const vec3 lightDir = vec3(0.75, 0.5, 1.0);\n const vec3 ambientColor = vec3(0.5, 0.5, 0.5);\n const vec3 lightColor = vec3(0.75, 0.75, 0.75);\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));\n float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);\n vLight = ambientColor + (lightColor * lightFactor);\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ if (!this.heavy) {
+ return '\n precision mediump float;\n uniform sampler2D baseColor;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec4 fragment_main() {\n return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);\n }';
+ } else {
+ // Used when we want to stress the GPU a bit more.
+ // Stolen with love from https://www.clicktorelease.com/code/codevember-2016/4/
+ return '\n precision mediump float;\n\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec2 dimensions = vec2(64, 64);\n float seed = 0.42;\n\n vec2 hash( vec2 p ) {\n p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));\n return fract(sin(p)*18.5453);\n }\n\n vec3 hash3( vec2 p ) {\n vec3 q = vec3( dot(p,vec2(127.1,311.7)),\n dot(p,vec2(269.5,183.3)),\n dot(p,vec2(419.2,371.9)) );\n return fract(sin(q)*43758.5453);\n }\n\n float iqnoise( in vec2 x, float u, float v ) {\n vec2 p = floor(x);\n vec2 f = fract(x);\n float k = 1.0+63.0*pow(1.0-v,4.0);\n float va = 0.0;\n float wt = 0.0;\n for( int j=-2; j<=2; j++ )\n for( int i=-2; i<=2; i++ ) {\n vec2 g = vec2( float(i),float(j) );\n vec3 o = hash3( p + g )*vec3(u,u,1.0);\n vec2 r = g - f + o.xy;\n float d = dot(r,r);\n float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );\n va += o.z*ww;\n wt += ww;\n }\n return va/wt;\n }\n\n // return distance, and cell id\n vec2 voronoi( in vec2 x ) {\n vec2 n = floor( x );\n vec2 f = fract( x );\n vec3 m = vec3( 8.0 );\n for( int j=-1; j<=1; j++ )\n for( int i=-1; i<=1; i++ ) {\n vec2 g = vec2( float(i), float(j) );\n vec2 o = hash( n + g );\n vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));\n float d = dot( r, r );\n if( d<m.x )\n m = vec3( d, o );\n }\n return vec2( sqrt(m.x), m.y+m.z );\n }\n\n vec4 fragment_main() {\n vec2 uv = ( vTexCoord );\n uv *= vec2( 10., 10. );\n uv += seed;\n vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );\n\n vec2 c = voronoi( uv );\n vec3 col = vec3( c.y / 2. );\n\n float f = iqnoise( 1. * uv + c.y, p.x, p.y );\n col *= 1.0 + .25 * vec3( f );\n\n return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );\n }';
+ }
+ }
+ }]);
+
+ return CubeSeaMaterial;
+}(_material.Material);
+
+var CubeSeaNode = exports.CubeSeaNode = function (_Node) {
+ _inherits(CubeSeaNode, _Node);
+
+ function CubeSeaNode() {
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ _classCallCheck(this, CubeSeaNode);
+
+ // Test variables
+ // If true, use a very heavyweight shader to stress the GPU.
+ var _this2 = _possibleConstructorReturn(this, (CubeSeaNode.__proto__ || Object.getPrototypeOf(CubeSeaNode)).call(this));
+
+ _this2.heavyGpu = !!options.heavyGpu;
+
+ // Number and size of the static cubes. Warning, large values
+ // don't render right due to overflow of the int16 indices.
+ _this2.cubeCount = options.cubeCount || (_this2.heavyGpu ? 12 : 10);
+ _this2.cubeScale = options.cubeScale || 1.0;
+
+ // Draw only half the world cubes. Helps test variable render cost
+ // when combined with heavyGpu.
+ _this2.halfOnly = !!options.halfOnly;
+
+ // Automatically spin the world cubes. Intended for automated testing,
+ // not recommended for viewing in a headset.
+ _this2.autoRotate = !!options.autoRotate;
+
+ _this2._texture = new _texture.UrlTexture(options.imageUrl || 'media/textures/cube-sea.png');
+
+ _this2._material = new CubeSeaMaterial(_this2.heavyGpu);
+ _this2._material.baseColor.texture = _this2._texture;
+
+ _this2._renderPrimitive = null;
+ return _this2;
+ }
+
+ _createClass(CubeSeaNode, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ this._renderPrimitive = null;
+
+ var boxBuilder = new _boxBuilder.BoxBuilder();
+
+ // Build the spinning "hero" cubes
+ boxBuilder.pushCube([0, 0.25, -0.8], 0.1);
+ boxBuilder.pushCube([0.8, 0.25, 0], 0.1);
+ boxBuilder.pushCube([0, 0.25, 0.8], 0.1);
+ boxBuilder.pushCube([-0.8, 0.25, 0], 0.1);
+
+ var heroPrimitive = boxBuilder.finishPrimitive(renderer);
+
+ this.heroNode = renderer.createMesh(heroPrimitive, this._material);
+
+ this.rebuildCubes(boxBuilder);
+
+ this.cubeSeaNode = new _node.Node();
+ this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive);
+
+ this.addNode(this.cubeSeaNode);
+ this.addNode(this.heroNode);
+
+ return this.waitForComplete();
+ }
+ }, {
+ key: 'rebuildCubes',
+ value: function rebuildCubes(boxBuilder) {
+ if (!this._renderer) {
+ return;
+ }
+
+ if (!boxBuilder) {
+ boxBuilder = new _boxBuilder.BoxBuilder();
+ } else {
+ boxBuilder.clear();
+ }
+
+ var size = 0.4 * this.cubeScale;
+
+ // Build the cube sea
+ var halfGrid = this.cubeCount * 0.5;
+ for (var x = 0; x < this.cubeCount; ++x) {
+ for (var y = 0; y < this.cubeCount; ++y) {
+ for (var z = 0; z < this.cubeCount; ++z) {
+ var pos = [x - halfGrid, y - halfGrid, z - halfGrid];
+ // Only draw cubes on one side. Useful for testing variable render
+ // cost that depends on view direction.
+ if (this.halfOnly && pos[0] < 0) {
+ continue;
+ }
+
+ // Don't place a cube in the center of the grid.
+ if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0) {
+ continue;
+ }
+
+ boxBuilder.pushCube(pos, size);
+ }
+ }
+ }
+
+ if (this.cubeCount > 12) {
+ // Each cube has 6 sides with 2 triangles and 3 indices per triangle, so
+ // the total number of indices needed is cubeCount^3 * 36. This exceeds
+ // the short index range past 12 cubes.
+ boxBuilder.indexType = 5125; // gl.UNSIGNED_INT
+ }
+ var cubeSeaPrimitive = boxBuilder.finishPrimitive(this._renderer);
+
+ if (!this._renderPrimitive) {
+ this._renderPrimitive = this._renderer.createRenderPrimitive(cubeSeaPrimitive, this._material);
+ } else {
+ this._renderPrimitive.setPrimitive(cubeSeaPrimitive);
+ }
+ }
+ }, {
+ key: 'onUpdate',
+ value: function onUpdate(timestamp, frameDelta) {
+ if (this.autoRotate) {
+ _glMatrix.mat4.fromRotation(this.cubeSeaNode.matrix, timestamp / 500, [0, -1, 0]);
+ }
+ _glMatrix.mat4.fromRotation(this.heroNode.matrix, timestamp / 2000, [0, 1, 0]);
+ }
+ }]);
+
+ return CubeSeaNode;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/drop-shadow.js":
+/*!**********************************!*\
+ !*** ./src/nodes/drop-shadow.js ***!
+ \**********************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.DropShadowNode = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _primitiveStream = __webpack_require__(/*! ../geometry/primitive-stream.js */ "./src/geometry/primitive-stream.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+var GL = WebGLRenderingContext; // For enums
+
+var SHADOW_SEGMENTS = 32;
+var SHADOW_GROUND_OFFSET = 0.01;
+var SHADOW_CENTER_ALPHA = 0.7;
+var SHADOW_INNER_ALPHA = 0.3;
+var SHADOW_OUTER_ALPHA = 0.0;
+var SHADOW_INNER_RADIUS = 0.6;
+var SHADOW_OUTER_RADIUS = 1.0;
+
+var DropShadowMaterial = function (_Material) {
+ _inherits(DropShadowMaterial, _Material);
+
+ function DropShadowMaterial() {
+ _classCallCheck(this, DropShadowMaterial);
+
+ var _this = _possibleConstructorReturn(this, (DropShadowMaterial.__proto__ || Object.getPrototypeOf(DropShadowMaterial)).call(this));
+
+ _this.state.blend = true;
+ _this.state.blendFuncSrc = GL.ONE;
+ _this.state.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;
+ _this.state.depthFunc = GL.LEQUAL;
+ _this.state.depthMask = false;
+ return _this;
+ }
+
+ _createClass(DropShadowMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'DROP_SHADOW_MATERIAL';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying float vShadow;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vShadow = TEXCOORD_0.x;\n return proj * view * model * vec4(POSITION, 1.0);\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n varying float vShadow;\n\n vec4 fragment_main() {\n return vec4(0.0, 0.0, 0.0, vShadow);\n }';
+ }
+ }]);
+
+ return DropShadowMaterial;
+}(_material.Material);
+
+var DropShadowNode = exports.DropShadowNode = function (_Node) {
+ _inherits(DropShadowNode, _Node);
+
+ function DropShadowNode(iconTexture, callback) {
+ _classCallCheck(this, DropShadowNode);
+
+ return _possibleConstructorReturn(this, (DropShadowNode.__proto__ || Object.getPrototypeOf(DropShadowNode)).call(this));
+ }
+
+ _createClass(DropShadowNode, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ var stream = new _primitiveStream.PrimitiveStream();
+
+ stream.startGeometry();
+
+ // Shadow center
+ stream.pushVertex(0, SHADOW_GROUND_OFFSET, 0, SHADOW_CENTER_ALPHA);
+
+ var segRad = Math.PI * 2.0 / SHADOW_SEGMENTS;
+
+ var idx = void 0;
+ for (var i = 0; i < SHADOW_SEGMENTS; ++i) {
+ idx = stream.nextVertexIndex;
+
+ var rad = i * segRad;
+ var x = Math.cos(rad);
+ var y = Math.sin(rad);
+ stream.pushVertex(x * SHADOW_INNER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_INNER_RADIUS, SHADOW_INNER_ALPHA);
+ stream.pushVertex(x * SHADOW_OUTER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_OUTER_RADIUS, SHADOW_OUTER_ALPHA);
+
+ if (i > 0) {
+ // Inner circle
+ stream.pushTriangle(0, idx, idx - 2);
+
+ // Outer circle
+ stream.pushTriangle(idx, idx + 1, idx - 1);
+ stream.pushTriangle(idx, idx - 1, idx - 2);
+ }
+ }
+
+ stream.pushTriangle(0, 1, idx);
+
+ stream.pushTriangle(1, 2, idx + 1);
+ stream.pushTriangle(1, idx + 1, idx);
+
+ stream.endGeometry();
+
+ var shadowPrimitive = stream.finishPrimitive(renderer);
+ this._shadowRenderPrimitive = renderer.createRenderPrimitive(shadowPrimitive, new DropShadowMaterial());
+ this.addRenderPrimitive(this._shadowRenderPrimitive);
+ }
+ }]);
+
+ return DropShadowNode;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/gltf2.js":
+/*!****************************!*\
+ !*** ./src/nodes/gltf2.js ***!
+ \****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Gltf2Node = undefined;
+
+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 _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _gltf = __webpack_require__(/*! ../loaders/gltf2.js */ "./src/loaders/gltf2.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+// Using a weak map here allows us to cache a loader per-renderer without
+// modifying the renderer object or leaking memory when it's garbage collected.
+var gltfLoaderMap = new WeakMap();
+
+var Gltf2Node = exports.Gltf2Node = function (_Node) {
+ _inherits(Gltf2Node, _Node);
+
+ function Gltf2Node(options) {
+ _classCallCheck(this, Gltf2Node);
+
+ var _this = _possibleConstructorReturn(this, (Gltf2Node.__proto__ || Object.getPrototypeOf(Gltf2Node)).call(this));
+
+ _this._url = options.url;
+
+ _this._promise = null;
+ _this._resolver = null;
+ _this._rejecter = null;
+ return _this;
+ }
+
+ _createClass(Gltf2Node, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ var _this2 = this;
+
+ var loader = gltfLoaderMap.get(renderer);
+ if (!loader) {
+ loader = new _gltf.Gltf2Loader(renderer);
+ gltfLoaderMap.set(renderer, loader);
+ }
+
+ // Do we have a previously resolved promise? If so clear it.
+ if (!this._resolver && this._promise) {
+ this._promise = null;
+ }
+
+ this._ensurePromise();
+
+ loader.loadFromUrl(this._url).then(function (sceneNode) {
+ _this2.addNode(sceneNode);
+ _this2._resolver(sceneNode.waitForComplete());
+ _this2._resolver = null;
+ _this2._rejecter = null;
+ }).catch(function (err) {
+ _this2._rejecter(err);
+ _this2._resolver = null;
+ _this2._rejecter = null;
+ });
+ }
+ }, {
+ key: '_ensurePromise',
+ value: function _ensurePromise() {
+ var _this3 = this;
+
+ if (!this._promise) {
+ this._promise = new Promise(function (resolve, reject) {
+ _this3._resolver = resolve;
+ _this3._rejecter = reject;
+ });
+ }
+ return this._promise;
+ }
+ }, {
+ key: 'waitForComplete',
+ value: function waitForComplete() {
+ return this._ensurePromise();
+ }
+ }]);
+
+ return Gltf2Node;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/input-renderer.js":
+/*!*************************************!*\
+ !*** ./src/nodes/input-renderer.js ***!
+ \*************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.InputRenderer = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+var _texture = __webpack_require__(/*! ../core/texture.js */ "./src/core/texture.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+var GL = WebGLRenderingContext; // For enums
+
+// Laser texture data, 48x1 RGBA (not premultiplied alpha). This represents a
+// "cross section" of the laser beam with a bright core and a feathered edge.
+// Borrowed from Chromium source code.
+var LASER_TEXTURE_DATA = new Uint8Array([0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xbf, 0xbf, 0xbf, 0x04, 0xcc, 0xcc, 0xcc, 0x05, 0xdb, 0xdb, 0xdb, 0x07, 0xcc, 0xcc, 0xcc, 0x0a, 0xd8, 0xd8, 0xd8, 0x0d, 0xd2, 0xd2, 0xd2, 0x11, 0xce, 0xce, 0xce, 0x15, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x1f, 0xcd, 0xcd, 0xcd, 0x24, 0xc8, 0xc8, 0xc8, 0x2a, 0xc9, 0xc9, 0xc9, 0x2f, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x39, 0xc9, 0xc9, 0xc9, 0x3d, 0xc8, 0xc8, 0xc8, 0x41, 0xcb, 0xcb, 0xcb, 0x44, 0xee, 0xee, 0xee, 0x87, 0xfa, 0xfa, 0xfa, 0xc8, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc9, 0xfa, 0xfa, 0xfa, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc8, 0xee, 0xee, 0xee, 0x87, 0xcb, 0xcb, 0xcb, 0x44, 0xc8, 0xc8, 0xc8, 0x41, 0xc9, 0xc9, 0xc9, 0x3d, 0xc9, 0xc9, 0xc9, 0x39, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x2f, 0xc8, 0xc8, 0xc8, 0x2a, 0xcd, 0xcd, 0xcd, 0x24, 0xce, 0xce, 0xce, 0x1f, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x15, 0xd2, 0xd2, 0xd2, 0x11, 0xd8, 0xd8, 0xd8, 0x0d, 0xcc, 0xcc, 0xcc, 0x0a, 0xdb, 0xdb, 0xdb, 0x07, 0xcc, 0xcc, 0xcc, 0x05, 0xbf, 0xbf, 0xbf, 0x04, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01]);
+
+var LASER_LENGTH = 1.0;
+var LASER_DIAMETER = 0.01;
+var LASER_FADE_END = 0.535;
+var LASER_FADE_POINT = 0.5335;
+var LASER_DEFAULT_COLOR = [1.0, 1.0, 1.0, 0.25];
+
+var CURSOR_RADIUS = 0.004;
+var CURSOR_SHADOW_RADIUS = 0.007;
+var CURSOR_SHADOW_INNER_LUMINANCE = 0.5;
+var CURSOR_SHADOW_OUTER_LUMINANCE = 0.0;
+var CURSOR_SHADOW_INNER_OPACITY = 0.75;
+var CURSOR_SHADOW_OUTER_OPACITY = 0.0;
+var CURSOR_OPACITY = 0.9;
+var CURSOR_SEGMENTS = 16;
+var CURSOR_DEFAULT_COLOR = [1.0, 1.0, 1.0, 1.0];
+var CURSOR_DEFAULT_HIDDEN_COLOR = [0.5, 0.5, 0.5, 0.25];
+
+var DEFAULT_RESET_OPTIONS = {
+ controllers: true,
+ lasers: true,
+ cursors: true
+};
+
+var LaserMaterial = function (_Material) {
+ _inherits(LaserMaterial, _Material);
+
+ function LaserMaterial() {
+ _classCallCheck(this, LaserMaterial);
+
+ var _this = _possibleConstructorReturn(this, (LaserMaterial.__proto__ || Object.getPrototypeOf(LaserMaterial)).call(this));
+
+ _this.renderOrder = _material.RENDER_ORDER.ADDITIVE;
+ _this.state.cullFace = false;
+ _this.state.blend = true;
+ _this.state.blendFuncSrc = GL.ONE;
+ _this.state.blendFuncDst = GL.ONE;
+ _this.state.depthMask = false;
+
+ _this.laser = _this.defineSampler('diffuse');
+ _this.laser.texture = new _texture.DataTexture(LASER_TEXTURE_DATA, 48, 1);
+ _this.laserColor = _this.defineUniform('laserColor', LASER_DEFAULT_COLOR);
+ return _this;
+ }
+
+ _createClass(LaserMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'INPUT_LASER';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n precision mediump float;\n\n uniform vec4 laserColor;\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n const float fadePoint = ' + LASER_FADE_POINT + ';\n const float fadeEnd = ' + LASER_FADE_END + ';\n\n vec4 fragment_main() {\n vec2 uv = vTexCoord;\n float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);\n float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);\n vec4 color = laserColor * texture2D(diffuse, vTexCoord);\n float opacity = color.a * front_fade_factor * back_fade_factor;\n return vec4(color.rgb * opacity, opacity);\n }';
+ }
+ }]);
+
+ return LaserMaterial;
+}(_material.Material);
+
+var CURSOR_VERTEX_SHADER = '\nattribute vec4 POSITION;\n\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vLuminance = POSITION.z;\n vOpacity = POSITION.w;\n\n // Billboarded, constant size vertex transform.\n vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);\n screenPos /= screenPos.w;\n screenPos.xy += POSITION.xy;\n return screenPos;\n}';
+
+var CURSOR_FRAGMENT_SHADER = '\nprecision mediump float;\n\nuniform vec4 cursorColor;\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 fragment_main() {\n vec3 color = cursorColor.rgb * vLuminance;\n float opacity = cursorColor.a * vOpacity;\n return vec4(color * opacity, opacity);\n}';
+
+// Cursors are drawn as billboards that always face the camera and are rendered
+// as a fixed size no matter how far away they are.
+
+var CursorMaterial = function (_Material2) {
+ _inherits(CursorMaterial, _Material2);
+
+ function CursorMaterial() {
+ _classCallCheck(this, CursorMaterial);
+
+ var _this2 = _possibleConstructorReturn(this, (CursorMaterial.__proto__ || Object.getPrototypeOf(CursorMaterial)).call(this));
+
+ _this2.renderOrder = _material.RENDER_ORDER.ADDITIVE;
+ _this2.state.cullFace = false;
+ _this2.state.blend = true;
+ _this2.state.blendFuncSrc = GL.ONE;
+ _this2.state.depthMask = false;
+
+ _this2.cursorColor = _this2.defineUniform('cursorColor', CURSOR_DEFAULT_COLOR);
+ return _this2;
+ }
+
+ _createClass(CursorMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'INPUT_CURSOR';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return CURSOR_VERTEX_SHADER;
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return CURSOR_FRAGMENT_SHADER;
+ }
+ }]);
+
+ return CursorMaterial;
+}(_material.Material);
+
+var CursorHiddenMaterial = function (_Material3) {
+ _inherits(CursorHiddenMaterial, _Material3);
+
+ function CursorHiddenMaterial() {
+ _classCallCheck(this, CursorHiddenMaterial);
+
+ var _this3 = _possibleConstructorReturn(this, (CursorHiddenMaterial.__proto__ || Object.getPrototypeOf(CursorHiddenMaterial)).call(this));
+
+ _this3.renderOrder = _material.RENDER_ORDER.ADDITIVE;
+ _this3.state.cullFace = false;
+ _this3.state.blend = true;
+ _this3.state.blendFuncSrc = GL.ONE;
+ _this3.state.depthFunc = GL.GEQUAL;
+ _this3.state.depthMask = false;
+
+ _this3.cursorColor = _this3.defineUniform('cursorColor', CURSOR_DEFAULT_HIDDEN_COLOR);
+ return _this3;
+ }
+
+ // TODO: Rename to "program_name"
+
+
+ _createClass(CursorHiddenMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'INPUT_CURSOR_2';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return CURSOR_VERTEX_SHADER;
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return CURSOR_FRAGMENT_SHADER;
+ }
+ }]);
+
+ return CursorHiddenMaterial;
+}(_material.Material);
+
+var InputRenderer = exports.InputRenderer = function (_Node) {
+ _inherits(InputRenderer, _Node);
+
+ function InputRenderer() {
+ _classCallCheck(this, InputRenderer);
+
+ var _this4 = _possibleConstructorReturn(this, (InputRenderer.__proto__ || Object.getPrototypeOf(InputRenderer)).call(this));
+
+ _this4._maxInputElements = 32;
+
+ _this4._controllers = [];
+ _this4._controllerNode = null;
+ _this4._controllerNodeHandedness = null;
+ _this4._lasers = null;
+ _this4._cursors = null;
+
+ _this4._activeControllers = 0;
+ _this4._activeLasers = 0;
+ _this4._activeCursors = 0;
+ return _this4;
+ }
+
+ _createClass(InputRenderer, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ this._controllers = [];
+ this._controllerNode = null;
+ this._controllerNodeHandedness = null;
+ this._lasers = null;
+ this._cursors = null;
+
+ this._activeControllers = 0;
+ this._activeLasers = 0;
+ this._activeCursors = 0;
+ }
+ }, {
+ key: 'setControllerMesh',
+ value: function setControllerMesh(controllerNode) {
+ var handedness = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'right';
+
+ this._controllerNode = controllerNode;
+ this._controllerNode.visible = false;
+ // FIXME: Temporary fix to initialize for cloning.
+ this.addNode(this._controllerNode);
+ this._controllerNodeHandedness = handedness;
+ }
+ }, {
+ key: 'addController',
+ value: function addController(gripMatrix) {
+ if (!this._controllerNode) {
+ return;
+ }
+
+ var controller = null;
+ if (this._activeControllers < this._controllers.length) {
+ controller = this._controllers[this._activeControllers];
+ } else {
+ controller = this._controllerNode.clone();
+ this.addNode(controller);
+ this._controllers.push(controller);
+ }
+ this._activeControllers = (this._activeControllers + 1) % this._maxInputElements;
+
+ controller.matrix = gripMatrix;
+ controller.visible = true;
+ }
+ }, {
+ key: 'addLaserPointer',
+ value: function addLaserPointer(targetRay) {
+ // Create the laser pointer mesh if needed.
+ if (!this._lasers && this._renderer) {
+ this._lasers = [this._createLaserMesh()];
+ this.addNode(this._lasers[0]);
+ }
+
+ var laser = null;
+ if (this._activeLasers < this._lasers.length) {
+ laser = this._lasers[this._activeLasers];
+ } else {
+ laser = this._lasers[0].clone();
+ this.addNode(laser);
+ this._lasers.push(laser);
+ }
+ this._activeLasers = (this._activeLasers + 1) % this._maxInputElements;
+
+ laser.matrix = targetRay.transformMatrix;
+ laser.visible = true;
+ }
+ }, {
+ key: 'addCursor',
+ value: function addCursor(cursorPos) {
+ // Create the cursor mesh if needed.
+ if (!this._cursors && this._renderer) {
+ this._cursors = [this._createCursorMesh()];
+ this.addNode(this._cursors[0]);
+ }
+
+ var cursor = null;
+ if (this._activeCursors < this._cursors.length) {
+ cursor = this._cursors[this._activeCursors];
+ } else {
+ cursor = this._cursors[0].clone();
+ this.addNode(cursor);
+ this._cursors.push(cursor);
+ }
+ this._activeCursors = (this._activeCursors + 1) % this._maxInputElements;
+
+ cursor.translation = cursorPos;
+ cursor.visible = true;
+ }
+ }, {
+ key: 'reset',
+ value: function reset(options) {
+ if (!options) {
+ options = DEFAULT_RESET_OPTIONS;
+ }
+ if (this._controllers && options.controllers) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this._controllers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var controller = _step.value;
+
+ controller.visible = false;
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ this._activeControllers = 0;
+ }
+ if (this._lasers && options.lasers) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this._lasers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var laser = _step2.value;
+
+ laser.visible = false;
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ this._activeLasers = 0;
+ }
+ if (this._cursors && options.cursors) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this._cursors[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var cursor = _step3.value;
+
+ cursor.visible = false;
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ this._activeCursors = 0;
+ }
+ }
+ }, {
+ key: '_createLaserMesh',
+ value: function _createLaserMesh() {
+ var gl = this._renderer._gl;
+
+ var lr = LASER_DIAMETER * 0.5;
+ var ll = LASER_LENGTH;
+
+ // Laser is rendered as cross-shaped beam
+ var laserVerts = [
+ // X Y Z U V
+ 0.0, lr, 0.0, 0.0, 1.0, 0.0, lr, -ll, 0.0, 0.0, 0.0, -lr, 0.0, 1.0, 1.0, 0.0, -lr, -ll, 1.0, 0.0, lr, 0.0, 0.0, 0.0, 1.0, lr, 0.0, -ll, 0.0, 0.0, -lr, 0.0, 0.0, 1.0, 1.0, -lr, 0.0, -ll, 1.0, 0.0, 0.0, -lr, 0.0, 0.0, 1.0, 0.0, -lr, -ll, 0.0, 0.0, 0.0, lr, 0.0, 1.0, 1.0, 0.0, lr, -ll, 1.0, 0.0, -lr, 0.0, 0.0, 0.0, 1.0, -lr, 0.0, -ll, 0.0, 0.0, lr, 0.0, 0.0, 1.0, 1.0, lr, 0.0, -ll, 1.0, 0.0];
+ var laserIndices = [0, 1, 2, 1, 3, 2, 4, 5, 6, 5, 7, 6, 8, 9, 10, 9, 11, 10, 12, 13, 14, 13, 15, 14];
+
+ var laserVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(laserVerts));
+ var laserIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(laserIndices));
+
+ var laserIndexCount = laserIndices.length;
+
+ var laserAttribs = [new _primitive.PrimitiveAttribute('POSITION', laserVertexBuffer, 3, gl.FLOAT, 20, 0), new _primitive.PrimitiveAttribute('TEXCOORD_0', laserVertexBuffer, 2, gl.FLOAT, 20, 12)];
+
+ var laserPrimitive = new _primitive.Primitive(laserAttribs, laserIndexCount);
+ laserPrimitive.setIndexBuffer(laserIndexBuffer);
+
+ var laserMaterial = new LaserMaterial();
+
+ var laserRenderPrimitive = this._renderer.createRenderPrimitive(laserPrimitive, laserMaterial);
+ var meshNode = new _node.Node();
+ meshNode.addRenderPrimitive(laserRenderPrimitive);
+ return meshNode;
+ }
+ }, {
+ key: '_createCursorMesh',
+ value: function _createCursorMesh() {
+ var gl = this._renderer._gl;
+
+ // Cursor is a circular white dot with a dark "shadow" skirt around the edge
+ // that fades from black to transparent as it moves out from the center.
+ // Cursor verts are packed as [X, Y, Luminance, Opacity]
+ var cursorVerts = [];
+ var cursorIndices = [];
+
+ var segRad = 2.0 * Math.PI / CURSOR_SEGMENTS;
+
+ // Cursor center
+ for (var i = 0; i < CURSOR_SEGMENTS; ++i) {
+ var rad = i * segRad;
+ var x = Math.cos(rad);
+ var y = Math.sin(rad);
+ cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS, 1.0, CURSOR_OPACITY);
+
+ if (i > 1) {
+ cursorIndices.push(0, i - 1, i);
+ }
+ }
+
+ var indexOffset = CURSOR_SEGMENTS;
+
+ // Cursor Skirt
+ for (var _i = 0; _i < CURSOR_SEGMENTS; ++_i) {
+ var _rad = _i * segRad;
+ var _x2 = Math.cos(_rad);
+ var _y = Math.sin(_rad);
+ cursorVerts.push(_x2 * CURSOR_RADIUS, _y * CURSOR_RADIUS, CURSOR_SHADOW_INNER_LUMINANCE, CURSOR_SHADOW_INNER_OPACITY);
+ cursorVerts.push(_x2 * CURSOR_SHADOW_RADIUS, _y * CURSOR_SHADOW_RADIUS, CURSOR_SHADOW_OUTER_LUMINANCE, CURSOR_SHADOW_OUTER_OPACITY);
+
+ if (_i > 0) {
+ var _idx = indexOffset + _i * 2;
+ cursorIndices.push(_idx - 2, _idx - 1, _idx);
+ cursorIndices.push(_idx - 1, _idx + 1, _idx);
+ }
+ }
+
+ var idx = indexOffset + CURSOR_SEGMENTS * 2;
+ cursorIndices.push(idx - 2, idx - 1, indexOffset);
+ cursorIndices.push(idx - 1, indexOffset + 1, indexOffset);
+
+ var cursorVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(cursorVerts));
+ var cursorIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cursorIndices));
+
+ var cursorIndexCount = cursorIndices.length;
+
+ var cursorAttribs = [new _primitive.PrimitiveAttribute('POSITION', cursorVertexBuffer, 4, gl.FLOAT, 16, 0)];
+
+ var cursorPrimitive = new _primitive.Primitive(cursorAttribs, cursorIndexCount);
+ cursorPrimitive.setIndexBuffer(cursorIndexBuffer);
+
+ var cursorMaterial = new CursorMaterial();
+ var cursorHiddenMaterial = new CursorHiddenMaterial();
+
+ // Cursor renders two parts: The bright opaque cursor for areas where it's
+ // not obscured and a more transparent, darker version for areas where it's
+ // behind another object.
+ var cursorRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorMaterial);
+ var cursorHiddenRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorHiddenMaterial);
+ var meshNode = new _node.Node();
+ meshNode.addRenderPrimitive(cursorRenderPrimitive);
+ meshNode.addRenderPrimitive(cursorHiddenRenderPrimitive);
+ return meshNode;
+ }
+ }]);
+
+ return InputRenderer;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/seven-segment-text.js":
+/*!*****************************************!*\
+ !*** ./src/nodes/seven-segment-text.js ***!
+ \*****************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SevenSegmentText = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+/*
+Renders simple text using a seven-segment LED style pattern. Only really good
+for numbers and a limited number of other characters.
+*/
+
+var TEXT_KERNING = 2.0;
+
+var SevenSegmentMaterial = function (_Material) {
+ _inherits(SevenSegmentMaterial, _Material);
+
+ function SevenSegmentMaterial() {
+ _classCallCheck(this, SevenSegmentMaterial);
+
+ return _possibleConstructorReturn(this, (SevenSegmentMaterial.__proto__ || Object.getPrototypeOf(SevenSegmentMaterial)).apply(this, arguments));
+ }
+
+ _createClass(SevenSegmentMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'SEVEN_SEGMENT_TEXT';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 0.0, 1.0);\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n precision mediump float;\n const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n\n vec4 fragment_main() {\n return color;\n }';
+ }
+ }]);
+
+ return SevenSegmentMaterial;
+}(_material.Material);
+
+var SevenSegmentText = exports.SevenSegmentText = function (_Node) {
+ _inherits(SevenSegmentText, _Node);
+
+ function SevenSegmentText() {
+ _classCallCheck(this, SevenSegmentText);
+
+ var _this2 = _possibleConstructorReturn(this, (SevenSegmentText.__proto__ || Object.getPrototypeOf(SevenSegmentText)).call(this));
+
+ _this2._text = '';
+ _this2._charNodes = [];
+ return _this2;
+ }
+
+ _createClass(SevenSegmentText, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ this.clearNodes();
+ this._charNodes = [];
+
+ var vertices = [];
+ var segmentIndices = {};
+ var indices = [];
+
+ var width = 0.5;
+ var thickness = 0.25;
+
+ function defineSegment(id, left, top, right, bottom) {
+ var idx = vertices.length / 2;
+ vertices.push(left, top, right, top, right, bottom, left, bottom);
+
+ segmentIndices[id] = [idx, idx + 2, idx + 1, idx, idx + 3, idx + 2];
+ }
+
+ var characters = {};
+ function defineCharacter(c, segments) {
+ var character = {
+ character: c,
+ offset: indices.length * 2,
+ count: 0
+ };
+
+ for (var i = 0; i < segments.length; ++i) {
+ var idx = segments[i];
+ var segment = segmentIndices[idx];
+ character.count += segment.length;
+ indices.push.apply(indices, _toConsumableArray(segment));
+ }
+
+ characters[c] = character;
+ }
+
+ /* Segment layout is as follows:
+ |-0-|
+ 3 4
+ |-1-|
+ 5 6
+ |-2-|
+ */
+
+ defineSegment(0, -1, 1, width, 1 - thickness);
+ defineSegment(1, -1, thickness * 0.5, width, -thickness * 0.5);
+ defineSegment(2, -1, -1 + thickness, width, -1);
+ defineSegment(3, -1, 1, -1 + thickness, -thickness * 0.5);
+ defineSegment(4, width - thickness, 1, width, -thickness * 0.5);
+ defineSegment(5, -1, thickness * 0.5, -1 + thickness, -1);
+ defineSegment(6, width - thickness, thickness * 0.5, width, -1);
+
+ defineCharacter('0', [0, 2, 3, 4, 5, 6]);
+ defineCharacter('1', [4, 6]);
+ defineCharacter('2', [0, 1, 2, 4, 5]);
+ defineCharacter('3', [0, 1, 2, 4, 6]);
+ defineCharacter('4', [1, 3, 4, 6]);
+ defineCharacter('5', [0, 1, 2, 3, 6]);
+ defineCharacter('6', [0, 1, 2, 3, 5, 6]);
+ defineCharacter('7', [0, 4, 6]);
+ defineCharacter('8', [0, 1, 2, 3, 4, 5, 6]);
+ defineCharacter('9', [0, 1, 2, 3, 4, 6]);
+ defineCharacter('A', [0, 1, 3, 4, 5, 6]);
+ defineCharacter('B', [1, 2, 3, 5, 6]);
+ defineCharacter('C', [0, 2, 3, 5]);
+ defineCharacter('D', [1, 2, 4, 5, 6]);
+ defineCharacter('E', [0, 1, 2, 4, 6]);
+ defineCharacter('F', [0, 1, 3, 5]);
+ defineCharacter('P', [0, 1, 3, 4, 5]);
+ defineCharacter('-', [1]);
+ defineCharacter(' ', []);
+ defineCharacter('_', [2]); // Used for undefined characters
+
+ var gl = renderer.gl;
+ var vertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(vertices));
+ var indexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ var vertexAttribs = [new _primitive.PrimitiveAttribute('POSITION', vertexBuffer, 2, gl.FLOAT, 8, 0)];
+
+ var primitive = new _primitive.Primitive(vertexAttribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+
+ var material = new SevenSegmentMaterial();
+
+ this._charPrimitives = {};
+ for (var char in characters) {
+ var charDef = characters[char];
+ primitive.elementCount = charDef.count;
+ primitive.indexByteOffset = charDef.offset;
+ this._charPrimitives[char] = renderer.createRenderPrimitive(primitive, material);
+ }
+
+ this.text = this._text;
+ }
+ }, {
+ key: 'text',
+ get: function get() {
+ return this._text;
+ },
+ set: function set(value) {
+ this._text = value;
+
+ var i = 0;
+ var charPrimitive = null;
+ for (; i < value.length; ++i) {
+ if (value[i] in this._charPrimitives) {
+ charPrimitive = this._charPrimitives[value[i]];
+ } else {
+ charPrimitive = this._charPrimitives['_'];
+ }
+
+ if (this._charNodes.length <= i) {
+ var node = new _node.Node();
+ node.addRenderPrimitive(charPrimitive);
+ var offset = i * TEXT_KERNING;
+ node.translation = [offset, 0, 0];
+ this._charNodes.push(node);
+ this.addNode(node);
+ } else {
+ // This is sort of an abuse of how these things are expected to work,
+ // but it's the cheapest thing I could think of that didn't break the
+ // world.
+ this._charNodes[i].clearRenderPrimitives();
+ this._charNodes[i].addRenderPrimitive(charPrimitive);
+ this._charNodes[i].visible = true;
+ }
+ }
+
+ // If there's any nodes left over make them invisible
+ for (; i < this._charNodes.length; ++i) {
+ this._charNodes[i].visible = false;
+ }
+ }
+ }]);
+
+ return SevenSegmentText;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/skybox.js":
+/*!*****************************!*\
+ !*** ./src/nodes/skybox.js ***!
+ \*****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SkyboxNode = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _texture = __webpack_require__(/*! ../core/texture.js */ "./src/core/texture.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+/*
+Node for displaying 360 equirect images as a skybox.
+*/
+
+var GL = WebGLRenderingContext; // For enums
+
+var SkyboxMaterial = function (_Material) {
+ _inherits(SkyboxMaterial, _Material);
+
+ function SkyboxMaterial() {
+ _classCallCheck(this, SkyboxMaterial);
+
+ var _this = _possibleConstructorReturn(this, (SkyboxMaterial.__proto__ || Object.getPrototypeOf(SkyboxMaterial)).call(this));
+
+ _this.renderOrder = _material.RENDER_ORDER.SKY;
+ _this.state.depthFunc = GL.LEQUAL;
+ _this.state.depthMask = false;
+
+ _this.image = _this.defineSampler('diffuse');
+
+ _this.texCoordScaleOffset = _this.defineUniform('texCoordScaleOffset', [1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0], 4);
+ return _this;
+ }
+
+ _createClass(SkyboxMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'SKYBOX';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n // Drop the translation portion of the view matrix\n view[3].xyz = vec3(0.0, 0.0, 0.0);\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n\n // Returning the W component for both Z and W forces the geometry depth to\n // the far plane. When combined with a depth func of LEQUAL this makes the\n // sky write to any depth fragment that has not been written to yet.\n return out_vec.xyww;\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }';
+ }
+ }]);
+
+ return SkyboxMaterial;
+}(_material.Material);
+
+var SkyboxNode = exports.SkyboxNode = function (_Node) {
+ _inherits(SkyboxNode, _Node);
+
+ function SkyboxNode(options) {
+ _classCallCheck(this, SkyboxNode);
+
+ var _this2 = _possibleConstructorReturn(this, (SkyboxNode.__proto__ || Object.getPrototypeOf(SkyboxNode)).call(this));
+
+ _this2._url = options.url;
+ _this2._displayMode = options.displayMode || 'mono';
+ _this2._rotationY = options.rotationY || 0;
+ return _this2;
+ }
+
+ _createClass(SkyboxNode, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ var vertices = [];
+ var indices = [];
+
+ var latSegments = 40;
+ var lonSegments = 40;
+
+ // Create the vertices/indices
+ for (var i = 0; i <= latSegments; ++i) {
+ var theta = i * Math.PI / latSegments;
+ var sinTheta = Math.sin(theta);
+ var cosTheta = Math.cos(theta);
+
+ var idxOffsetA = i * (lonSegments + 1);
+ var idxOffsetB = (i + 1) * (lonSegments + 1);
+
+ for (var j = 0; j <= lonSegments; ++j) {
+ var phi = j * 2 * Math.PI / lonSegments + this._rotationY;
+ var x = Math.sin(phi) * sinTheta;
+ var y = cosTheta;
+ var z = -Math.cos(phi) * sinTheta;
+ var u = j / lonSegments;
+ var v = i / latSegments;
+
+ // Vertex shader will force the geometry to the far plane, so the
+ // radius of the sphere is immaterial.
+ vertices.push(x, y, z, u, v);
+
+ if (i < latSegments && j < lonSegments) {
+ var idxA = idxOffsetA + j;
+ var idxB = idxOffsetB + j;
+
+ indices.push(idxA, idxB, idxA + 1, idxB, idxB + 1, idxA + 1);
+ }
+ }
+ }
+
+ var vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));
+ var indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ var attribs = [new _primitive.PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0), new _primitive.PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12)];
+
+ var primitive = new _primitive.Primitive(attribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+
+ var material = new SkyboxMaterial();
+ material.image.texture = new _texture.UrlTexture(this._url);
+
+ switch (this._displayMode) {
+ case 'mono':
+ material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0];
+ break;
+ case 'stereoTopBottom':
+ material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0, 1.0, 0.5, 0.0, 0.5];
+ break;
+ case 'stereoLeftRight':
+ material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0, 0.5, 1.0, 0.5, 0.0];
+ break;
+ }
+
+ var renderPrimitive = renderer.createRenderPrimitive(primitive, material);
+ this.addRenderPrimitive(renderPrimitive);
+ }
+ }]);
+
+ return SkyboxNode;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/stats-viewer.js":
+/*!***********************************!*\
+ !*** ./src/nodes/stats-viewer.js ***!
+ \***********************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.StatsViewer = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+var _sevenSegmentText = __webpack_require__(/*! ./seven-segment-text.js */ "./src/nodes/seven-segment-text.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+/*
+Heavily inspired by Mr. Doobs stats.js, this FPS counter is rendered completely
+with WebGL, allowing it to be shown in cases where overlaid HTML elements aren't
+usable (like WebXR), or if you want the FPS counter to be rendered as part of
+your scene.
+*/
+
+var SEGMENTS = 30;
+var MAX_FPS = 90;
+
+var StatsMaterial = function (_Material) {
+ _inherits(StatsMaterial, _Material);
+
+ function StatsMaterial() {
+ _classCallCheck(this, StatsMaterial);
+
+ return _possibleConstructorReturn(this, (StatsMaterial.__proto__ || Object.getPrototypeOf(StatsMaterial)).apply(this, arguments));
+ }
+
+ _createClass(StatsMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'STATS_VIEWER';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n attribute vec3 POSITION;\n attribute vec3 COLOR_0;\n varying vec4 vColor;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vColor = vec4(COLOR_0, 1.0);\n return proj * view * model * vec4(POSITION, 1.0);\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n precision mediump float;\n varying vec4 vColor;\n\n vec4 fragment_main() {\n return vColor;\n }';
+ }
+ }]);
+
+ return StatsMaterial;
+}(_material.Material);
+
+function segmentToX(i) {
+ return 0.9 / SEGMENTS * i - 0.45;
+}
+
+function fpsToY(value) {
+ return Math.min(value, MAX_FPS) * (0.7 / MAX_FPS) - 0.45;
+}
+
+function fpsToRGB(value) {
+ return {
+ r: Math.max(0.0, Math.min(1.0, 1.0 - value / 60)),
+ g: Math.max(0.0, Math.min(1.0, (value - 15) / (MAX_FPS - 15))),
+ b: Math.max(0.0, Math.min(1.0, (value - 15) / (MAX_FPS - 15)))
+ };
+}
+
+var now = window.performance && performance.now ? performance.now.bind(performance) : Date.now;
+
+var StatsViewer = exports.StatsViewer = function (_Node) {
+ _inherits(StatsViewer, _Node);
+
+ function StatsViewer() {
+ _classCallCheck(this, StatsViewer);
+
+ var _this2 = _possibleConstructorReturn(this, (StatsViewer.__proto__ || Object.getPrototypeOf(StatsViewer)).call(this));
+
+ _this2._performanceMonitoring = false;
+
+ _this2._startTime = now();
+ _this2._prevFrameTime = _this2._startTime;
+ _this2._prevGraphUpdateTime = _this2._startTime;
+ _this2._frames = 0;
+ _this2._fpsAverage = 0;
+ _this2._fpsMin = 0;
+ _this2._fpsStep = _this2._performanceMonitoring ? 1000 : 250;
+ _this2._lastSegment = 0;
+
+ _this2._fpsVertexBuffer = null;
+ _this2._fpsRenderPrimitive = null;
+ _this2._fpsNode = null;
+
+ _this2._sevenSegmentNode = new _sevenSegmentText.SevenSegmentText();
+ // Hard coded because it doesn't change:
+ // Scale by 0.075 in X and Y
+ // Translate into upper left corner w/ z = 0.02
+ _this2._sevenSegmentNode.matrix = new Float32Array([0.075, 0, 0, 0, 0, 0.075, 0, 0, 0, 0, 1, 0, -0.3625, 0.3625, 0.02, 1]);
+ return _this2;
+ }
+
+ _createClass(StatsViewer, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ this.clearNodes();
+
+ var gl = renderer.gl;
+
+ var fpsVerts = [];
+ var fpsIndices = [];
+
+ // Graph geometry
+ for (var i = 0; i < SEGMENTS; ++i) {
+ // Bar top
+ fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+ fpsVerts.push(segmentToX(i + 1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+
+ // Bar bottom
+ fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+ fpsVerts.push(segmentToX(i + 1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+
+ var idx = i * 4;
+ fpsIndices.push(idx, idx + 3, idx + 1, idx + 3, idx, idx + 2);
+ }
+
+ function addBGSquare(left, bottom, right, top, z, r, g, b) {
+ var idx = fpsVerts.length / 6;
+
+ fpsVerts.push(left, bottom, z, r, g, b);
+ fpsVerts.push(right, top, z, r, g, b);
+ fpsVerts.push(left, top, z, r, g, b);
+ fpsVerts.push(right, bottom, z, r, g, b);
+
+ fpsIndices.push(idx, idx + 1, idx + 2, idx, idx + 3, idx + 1);
+ }
+
+ // Panel Background
+ addBGSquare(-0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.125);
+
+ // FPS Background
+ addBGSquare(-0.45, -0.45, 0.45, 0.25, 0.01, 0.0, 0.0, 0.4);
+
+ // 30 FPS line
+ addBGSquare(-0.45, fpsToY(30), 0.45, fpsToY(32), 0.015, 0.5, 0.0, 0.5);
+
+ // 60 FPS line
+ addBGSquare(-0.45, fpsToY(60), 0.45, fpsToY(62), 0.015, 0.2, 0.0, 0.75);
+
+ this._fpsVertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(fpsVerts), gl.DYNAMIC_DRAW);
+ var fpsIndexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(fpsIndices));
+
+ var fpsAttribs = [new _primitive.PrimitiveAttribute('POSITION', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 0), new _primitive.PrimitiveAttribute('COLOR_0', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 12)];
+
+ var fpsPrimitive = new _primitive.Primitive(fpsAttribs, fpsIndices.length);
+ fpsPrimitive.setIndexBuffer(fpsIndexBuffer);
+ fpsPrimitive.setBounds([-0.5, -0.5, 0.0], [0.5, 0.5, 0.015]);
+
+ this._fpsRenderPrimitive = renderer.createRenderPrimitive(fpsPrimitive, new StatsMaterial());
+ this._fpsNode = new _node.Node();
+ this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive);
+
+ this.addNode(this._fpsNode);
+ this.addNode(this._sevenSegmentNode);
+ }
+ }, {
+ key: 'begin',
+ value: function begin() {
+ this._startTime = now();
+ }
+ }, {
+ key: 'end',
+ value: function end() {
+ var time = now();
+
+ var frameFps = 1000 / (time - this._prevFrameTime);
+ this._prevFrameTime = time;
+ this._fpsMin = this._frames ? Math.min(this._fpsMin, frameFps) : frameFps;
+ this._frames++;
+
+ if (time > this._prevGraphUpdateTime + this._fpsStep) {
+ var intervalTime = time - this._prevGraphUpdateTime;
+ this._fpsAverage = Math.round(1000 / (intervalTime / this._frames));
+
+ // Draw both average and minimum FPS for this period
+ // so that dropped frames are more clearly visible.
+ this._updateGraph(this._fpsMin, this._fpsAverage);
+ if (this._performanceMonitoring) {
+ console.log('Average FPS: ' + this._fpsAverage + ' Min FPS: ' + this._fpsMin);
+ }
+
+ this._prevGraphUpdateTime = time;
+ this._frames = 0;
+ this._fpsMin = 0;
+ }
+ }
+ }, {
+ key: '_updateGraph',
+ value: function _updateGraph(valueLow, valueHigh) {
+ var color = fpsToRGB(valueLow);
+ // Draw a range from the low to high value. Artificially widen the
+ // range a bit to ensure that near-equal values still remain
+ // visible - the logic here should match that used by the
+ // "60 FPS line" setup below. Hitting 60fps consistently will
+ // keep the top half of the 60fps background line visible.
+ var y0 = fpsToY(valueLow - 1);
+ var y1 = fpsToY(valueHigh + 1);
+
+ // Update the current segment with the new FPS value
+ var updateVerts = [segmentToX(this._lastSegment), y1, 0.02, color.r, color.g, color.b, segmentToX(this._lastSegment + 1), y1, 0.02, color.r, color.g, color.b, segmentToX(this._lastSegment), y0, 0.02, color.r, color.g, color.b, segmentToX(this._lastSegment + 1), y0, 0.02, color.r, color.g, color.b];
+
+ // Re-shape the next segment into the green "progress" line
+ color.r = 0.2;
+ color.g = 1.0;
+ color.b = 0.2;
+
+ if (this._lastSegment == SEGMENTS - 1) {
+ // If we're updating the last segment we need to do two bufferSubDatas
+ // to update the segment and turn the first segment into the progress line.
+ this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts), this._lastSegment * 24 * 4);
+ updateVerts = [segmentToX(0), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b, segmentToX(.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b, segmentToX(0), fpsToY(0), 0.02, color.r, color.g, color.b, segmentToX(.25), fpsToY(0), 0.02, color.r, color.g, color.b];
+ this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts), 0);
+ } else {
+ updateVerts.push(segmentToX(this._lastSegment + 1), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b, segmentToX(this._lastSegment + 1.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b, segmentToX(this._lastSegment + 1), fpsToY(0), 0.02, color.r, color.g, color.b, segmentToX(this._lastSegment + 1.25), fpsToY(0), 0.02, color.r, color.g, color.b);
+ this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts), this._lastSegment * 24 * 4);
+ }
+
+ this._lastSegment = (this._lastSegment + 1) % SEGMENTS;
+
+ this._sevenSegmentNode.text = this._fpsAverage + ' FP5';
+ }
+ }, {
+ key: 'performanceMonitoring',
+ get: function get() {
+ return this._performanceMonitoring;
+ },
+ set: function set(value) {
+ this._performanceMonitoring = value;
+ this._fpsStep = value ? 1000 : 250;
+ }
+ }]);
+
+ return StatsViewer;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/nodes/video.js":
+/*!****************************!*\
+ !*** ./src/nodes/video.js ***!
+ \****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.VideoNode = undefined;
+
+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 _material = __webpack_require__(/*! ../core/material.js */ "./src/core/material.js");
+
+var _primitive = __webpack_require__(/*! ../core/primitive.js */ "./src/core/primitive.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _texture = __webpack_require__(/*! ../core/texture.js */ "./src/core/texture.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+/*
+Node for displaying 2D or stereo videos on a quad.
+*/
+
+var GL = WebGLRenderingContext; // For enums
+
+var VideoMaterial = function (_Material) {
+ _inherits(VideoMaterial, _Material);
+
+ function VideoMaterial() {
+ _classCallCheck(this, VideoMaterial);
+
+ var _this = _possibleConstructorReturn(this, (VideoMaterial.__proto__ || Object.getPrototypeOf(VideoMaterial)).call(this));
+
+ _this.image = _this.defineSampler('diffuse');
+
+ _this.texCoordScaleOffset = _this.defineUniform('texCoordScaleOffset', [1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0], 4);
+ return _this;
+ }
+
+ _createClass(VideoMaterial, [{
+ key: 'materialName',
+ get: function get() {
+ return 'VIDEO_PLAYER';
+ }
+ }, {
+ key: 'vertexSource',
+ get: function get() {
+ return '\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n return out_vec;\n }';
+ }
+ }, {
+ key: 'fragmentSource',
+ get: function get() {
+ return '\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }';
+ }
+ }]);
+
+ return VideoMaterial;
+}(_material.Material);
+
+var VideoNode = exports.VideoNode = function (_Node) {
+ _inherits(VideoNode, _Node);
+
+ function VideoNode(options) {
+ _classCallCheck(this, VideoNode);
+
+ var _this2 = _possibleConstructorReturn(this, (VideoNode.__proto__ || Object.getPrototypeOf(VideoNode)).call(this));
+
+ _this2._video = options.video;
+ _this2._displayMode = options.displayMode || 'mono';
+
+ _this2._video_texture = new _texture.VideoTexture(_this2._video);
+ return _this2;
+ }
+
+ _createClass(VideoNode, [{
+ key: 'onRendererChanged',
+ value: function onRendererChanged(renderer) {
+ var vertices = [-1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0];
+ var indices = [0, 2, 1, 0, 3, 2];
+
+ var vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));
+ var indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ var attribs = [new _primitive.PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0), new _primitive.PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12)];
+
+ var primitive = new _primitive.Primitive(attribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+ primitive.setBounds([-1.0, -1.0, 0.0], [1.0, 1.0, 0.015]);
+
+ var material = new VideoMaterial();
+ material.image.texture = this._video_texture;
+
+ switch (this._displayMode) {
+ case 'mono':
+ material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0];
+ break;
+ case 'stereoTopBottom':
+ material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0, 1.0, 0.5, 0.0, 0.5];
+ break;
+ case 'stereoLeftRight':
+ material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0, 0.5, 1.0, 0.5, 0.0];
+ break;
+ }
+
+ var renderPrimitive = renderer.createRenderPrimitive(primitive, material);
+ this.addRenderPrimitive(renderPrimitive);
+ }
+ }, {
+ key: 'aspectRatio',
+ get: function get() {
+ var width = this._video.videoWidth;
+ var height = this._video.videoHeight;
+
+ switch (this._displayMode) {
+ case 'stereoTopBottom':
+ height *= 0.5;break;
+ case 'stereoLeftRight':
+ width *= 0.5;break;
+ }
+
+ if (!height || !width) {
+ return 1;
+ }
+
+ return width / height;
+ }
+ }]);
+
+ return VideoNode;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/scenes/scene.js":
+/*!*****************************!*\
+ !*** ./src/scenes/scene.js ***!
+ \*****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Scene = exports.WebXRView = undefined;
+
+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 _renderer = __webpack_require__(/*! ../core/renderer.js */ "./src/core/renderer.js");
+
+var _inputRenderer = __webpack_require__(/*! ../nodes/input-renderer.js */ "./src/nodes/input-renderer.js");
+
+var _statsViewer = __webpack_require__(/*! ../nodes/stats-viewer.js */ "./src/nodes/stats-viewer.js");
+
+var _node = __webpack_require__(/*! ../core/node.js */ "./src/core/node.js");
+
+var _glMatrix = __webpack_require__(/*! ../math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(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; }
+
+function _inherits(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 } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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.
+
+var WebXRView = exports.WebXRView = function (_RenderView) {
+ _inherits(WebXRView, _RenderView);
+
+ function WebXRView(view, layer) {
+ _classCallCheck(this, WebXRView);
+
+ return _possibleConstructorReturn(this, (WebXRView.__proto__ || Object.getPrototypeOf(WebXRView)).call(this, view ? view.projectionMatrix : null, view ? view.viewMatrix : null, layer && view ? layer.getViewport(view) : null, view ? view.eye : 'left'));
+ }
+
+ return WebXRView;
+}(_renderer.RenderView);
+
+var Scene = exports.Scene = function (_Node) {
+ _inherits(Scene, _Node);
+
+ function Scene() {
+ _classCallCheck(this, Scene);
+
+ var _this2 = _possibleConstructorReturn(this, (Scene.__proto__ || Object.getPrototypeOf(Scene)).call(this));
+
+ _this2._timestamp = -1;
+ _this2._frameDelta = 0;
+ _this2._statsStanding = false;
+ _this2._stats = null;
+ _this2._statsEnabled = false;
+ _this2.enableStats(true); // Ensure the stats are added correctly by default.
+
+ _this2._inputRenderer = null;
+ _this2._resetInputEndFrame = true;
+
+ _this2._lastTimestamp = 0;
+
+ _this2._hoverFrame = 0;
+ _this2._hoveredNodes = [];
+
+ _this2.clear = true;
+ return _this2;
+ }
+
+ _createClass(Scene, [{
+ key: 'setRenderer',
+ value: function setRenderer(renderer) {
+ this._setRenderer(renderer);
+ }
+ }, {
+ key: 'loseRenderer',
+ value: function loseRenderer() {
+ if (this._renderer) {
+ this._stats = null;
+ this._renderer = null;
+ this._inputRenderer = null;
+ }
+ }
+ }, {
+ key: 'updateInputSources',
+
+
+ // Helper function that automatically adds the appropriate visual elements for
+ // all input sources.
+ value: function updateInputSources(frame, frameOfRef) {
+ // FIXME: Check for the existence of the API first. This check should be
+ // removed once the input API is part of the official spec.
+ if (!frame.session.getInputSources) {
+ return;
+ }
+
+ var inputSources = frame.session.getInputSources();
+
+ var newHoveredNodes = [];
+ var lastHoverFrame = this._hoverFrame;
+ this._hoverFrame++;
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = inputSources[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var inputSource = _step.value;
+
+ var inputPose = frame.getInputPose(inputSource, frameOfRef);
+
+ if (!inputPose) {
+ continue;
+ }
+
+ // Any time that we have a grip matrix, we'll render a controller.
+ if (inputPose.gripMatrix) {
+ this.inputRenderer.addController(inputPose.gripMatrix);
+ }
+
+ if (inputPose.targetRay) {
+ if (inputSource.targetRayMode == 'tracked-pointer') {
+ // If we have a pointer matrix and the pointer origin is the users
+ // hand (as opposed to their head or the screen) use it to render
+ // a ray coming out of the input device to indicate the pointer
+ // direction.
+ this.inputRenderer.addLaserPointer(inputPose.targetRay);
+ }
+
+ // If we have a pointer matrix we can also use it to render a cursor
+ // for both handheld and gaze-based input sources.
+
+ // Check and see if the pointer is pointing at any selectable objects.
+ var hitResult = this.hitTest(inputPose.targetRay);
+
+ if (hitResult) {
+ // Render a cursor at the intersection point.
+ this.inputRenderer.addCursor(hitResult.intersection);
+
+ if (hitResult.node._hoverFrameId != lastHoverFrame) {
+ hitResult.node.onHoverStart();
+ }
+ hitResult.node._hoverFrameId = this._hoverFrame;
+ newHoveredNodes.push(hitResult.node);
+ } else {
+ // Statically render the cursor 1 meters down the ray since we didn't
+ // hit anything selectable.
+ var cursorDistance = 1.0;
+ var cursorPos = _glMatrix.vec3.fromValues(inputPose.targetRay.origin.x, inputPose.targetRay.origin.y, inputPose.targetRay.origin.z);
+ _glMatrix.vec3.add(cursorPos, cursorPos, [inputPose.targetRay.direction.x * cursorDistance, inputPose.targetRay.direction.y * cursorDistance, inputPose.targetRay.direction.z * cursorDistance]);
+ // let cursorPos = vec3.fromValues(0, 0, -1.0);
+ // vec3.transformMat4(cursorPos, cursorPos, inputPose.targetRay);
+ this.inputRenderer.addCursor(cursorPos);
+ }
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this._hoveredNodes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var hoverNode = _step2.value;
+
+ if (hoverNode._hoverFrameId != this._hoverFrame) {
+ hoverNode.onHoverEnd();
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ this._hoveredNodes = newHoveredNodes;
+ }
+ }, {
+ key: 'handleSelect',
+ value: function handleSelect(inputSource, frame, frameOfRef) {
+ var inputPose = frame.getInputPose(inputSource, frameOfRef);
+
+ if (!inputPose) {
+ return;
+ }
+
+ this.handleSelectPointer(inputPose.targetRay);
+ }
+ }, {
+ key: 'handleSelectPointer',
+ value: function handleSelectPointer(targetRay) {
+ if (targetRay) {
+ // Check and see if the pointer is pointing at any selectable objects.
+ var hitResult = this.hitTest(targetRay);
+
+ if (hitResult) {
+ // Render a cursor at the intersection point.
+ hitResult.node.handleSelect();
+ }
+ }
+ }
+ }, {
+ key: 'enableStats',
+ value: function enableStats(enable) {
+ if (enable == this._statsEnabled) {
+ return;
+ }
+
+ this._statsEnabled = enable;
+
+ if (enable) {
+ this._stats = new _statsViewer.StatsViewer();
+ this._stats.selectable = true;
+ this.addNode(this._stats);
+
+ if (this._statsStanding) {
+ this._stats.translation = [0, 1.4, -0.75];
+ } else {
+ this._stats.translation = [0, -0.3, -0.5];
+ }
+ this._stats.scale = [0.3, 0.3, 0.3];
+ _glMatrix.quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);
+ } else if (!enable) {
+ if (this._stats) {
+ this.removeNode(this._stats);
+ this._stats = null;
+ }
+ }
+ }
+ }, {
+ key: 'standingStats',
+ value: function standingStats(enable) {
+ this._statsStanding = enable;
+ if (this._stats) {
+ if (this._statsStanding) {
+ this._stats.translation = [0, 1.4, -0.75];
+ } else {
+ this._stats.translation = [0, -0.3, -0.5];
+ }
+ this._stats.scale = [0.3, 0.3, 0.3];
+ _glMatrix.quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);
+ }
+ }
+ }, {
+ key: 'draw',
+ value: function draw(projectionMatrix, viewMatrix, eye) {
+ var view = new _renderer.RenderView();
+ view.projectionMatrix = projectionMatrix;
+ view.viewMatrix = viewMatrix;
+ if (eye) {
+ view.eye = eye;
+ }
+
+ this.drawViewArray([view]);
+ }
+
+ /** Draws the scene into the base layer of the XRFrame's session */
+
+ }, {
+ key: 'drawXRFrame',
+ value: function drawXRFrame(xrFrame, pose) {
+ if (!this._renderer || !pose) {
+ return;
+ }
+
+ var gl = this._renderer.gl;
+ var session = xrFrame.session;
+ // Assumed to be a XRWebGLLayer for now.
+ var layer = session.baseLayer;
+
+ if (!gl) {
+ return;
+ }
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
+
+ if (this.clear) {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ }
+
+ var views = [];
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = pose.views[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var view = _step3.value;
+
+ views.push(new WebXRView(view, layer));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ this.drawViewArray(views);
+ }
+ }, {
+ key: 'drawViewArray',
+ value: function drawViewArray(views) {
+ // Don't draw when we don't have a valid context
+ if (!this._renderer) {
+ return;
+ }
+
+ this._renderer.drawViews(views, this);
+ }
+ }, {
+ key: 'startFrame',
+ value: function startFrame() {
+ var prevTimestamp = this._timestamp;
+ this._timestamp = performance.now();
+ if (this._stats) {
+ this._stats.begin();
+ }
+
+ if (prevTimestamp >= 0) {
+ this._frameDelta = this._timestamp - prevTimestamp;
+ } else {
+ this._frameDelta = 0;
+ }
+
+ this._update(this._timestamp, this._frameDelta);
+
+ return this._frameDelta;
+ }
+ }, {
+ key: 'endFrame',
+ value: function endFrame() {
+ if (this._inputRenderer && this._resetInputEndFrame) {
+ this._inputRenderer.reset();
+ }
+
+ if (this._stats) {
+ this._stats.end();
+ }
+ }
+
+ // Override to load scene resources on construction or context restore.
+
+ }, {
+ key: 'onLoadScene',
+ value: function onLoadScene(renderer) {
+ return Promise.resolve();
+ }
+ }, {
+ key: 'inputRenderer',
+ get: function get() {
+ if (!this._inputRenderer) {
+ this._inputRenderer = new _inputRenderer.InputRenderer();
+ this.addNode(this._inputRenderer);
+ }
+ return this._inputRenderer;
+ }
+ }]);
+
+ return Scene;
+}(_node.Node);
+
+/***/ }),
+
+/***/ "./src/util/fallback-helper.js":
+/*!*************************************!*\
+ !*** ./src/util/fallback-helper.js ***!
+ \*************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.FallbackHelper = undefined;
+
+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; }; }(); // 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.
+
+var _glMatrix = __webpack_require__(/*! ../math/gl-matrix.js */ "./src/math/gl-matrix.js");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var LOOK_SPEED = 0.0025;
+
+var FallbackHelper = exports.FallbackHelper = function () {
+ function FallbackHelper(scene, gl) {
+ var _this = this;
+
+ _classCallCheck(this, FallbackHelper);
+
+ this.scene = scene;
+ this.gl = gl;
+ this._emulateStage = false;
+
+ this.lookYaw = 0;
+ this.lookPitch = 0;
+
+ this.viewMatrix = _glMatrix.mat4.create();
+
+ var projectionMatrix = _glMatrix.mat4.create();
+ this.projectionMatrix = projectionMatrix;
+
+ // Using a simple identity matrix for the view.
+ _glMatrix.mat4.identity(this.viewMatrix);
+
+ // We need to track the canvas size in order to resize the WebGL
+ // backbuffer width and height, as well as update the projection matrix
+ // and adjust the viewport.
+ function onResize() {
+ gl.canvas.width = gl.canvas.offsetWidth * window.devicePixelRatio;
+ gl.canvas.height = gl.canvas.offsetHeight * window.devicePixelRatio;
+ _glMatrix.mat4.perspective(projectionMatrix, Math.PI * 0.4, gl.canvas.width / gl.canvas.height, 0.1, 1000.0);
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ }
+ window.addEventListener('resize', onResize);
+ onResize();
+
+ // Upding the view matrix with touch or mouse events.
+ var canvas = gl.canvas;
+ var lastTouchX = 0;
+ var lastTouchY = 0;
+ canvas.addEventListener('touchstart', function (ev) {
+ if (ev.touches.length == 2) {
+ lastTouchX = ev.touches[1].pageX;
+ lastTouchY = ev.touches[1].pageY;
+ }
+ });
+ canvas.addEventListener('touchmove', function (ev) {
+ // Rotate the view when two fingers are being used.
+ if (ev.touches.length == 2) {
+ _this.onLook(ev.touches[1].pageX - lastTouchX, ev.touches[1].pageY - lastTouchY);
+ lastTouchX = ev.touches[1].pageX;
+ lastTouchY = ev.touches[1].pageY;
+ }
+ });
+ canvas.addEventListener('mousemove', function (ev) {
+ // Only rotate when the right button is pressed.
+ if (ev.buttons & 2) {
+ _this.onLook(ev.movementX, ev.movementY);
+ }
+ });
+ canvas.addEventListener('contextmenu', function (ev) {
+ // Prevent context menus on the canvas so that we can use right click to rotate.
+ ev.preventDefault();
+ });
+
+ this.boundOnFrame = this.onFrame.bind(this);
+ window.requestAnimationFrame(this.boundOnFrame);
+ }
+
+ _createClass(FallbackHelper, [{
+ key: 'onLook',
+ value: function onLook(yaw, pitch) {
+ this.lookYaw += yaw * LOOK_SPEED;
+ this.lookPitch += pitch * LOOK_SPEED;
+
+ // Clamp pitch rotation beyond looking straight up or down.
+ if (this.lookPitch < -Math.PI * 0.5) {
+ this.lookPitch = -Math.PI * 0.5;
+ }
+ if (this.lookPitch > Math.PI * 0.5) {
+ this.lookPitch = Math.PI * 0.5;
+ }
+
+ this.updateView();
+ }
+ }, {
+ key: 'onFrame',
+ value: function onFrame(t) {
+ var gl = this.gl;
+ window.requestAnimationFrame(this.boundOnFrame);
+
+ this.scene.startFrame();
+
+ // We can skip setting the framebuffer and viewport every frame, because
+ // it won't change from frame to frame and we're updating the viewport
+ // only when we resize for efficency.
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // We're drawing with our own projection and view matrix now, and we
+ // don't have a list of view to loop through, but otherwise all of the
+ // WebGL drawing logic is exactly the same.
+ this.scene.draw(this.projectionMatrix, this.viewMatrix);
+
+ this.scene.endFrame();
+ }
+ }, {
+ key: 'updateView',
+ value: function updateView() {
+ _glMatrix.mat4.identity(this.viewMatrix);
+
+ _glMatrix.mat4.rotateX(this.viewMatrix, this.viewMatrix, -this.lookPitch);
+ _glMatrix.mat4.rotateY(this.viewMatrix, this.viewMatrix, -this.lookYaw);
+
+ // If we're emulating a stage frame of reference we'll need to move the view
+ // matrix roughly a meter and a half up in the air.
+ if (this._emulateStage) {
+ _glMatrix.mat4.translate(this.viewMatrix, this.viewMatrix, [0, -1.6, 0]);
+ }
+ }
+ }, {
+ key: 'emulateStage',
+ get: function get() {
+ return this._emulateStage;
+ },
+ set: function set(value) {
+ this._emulateStage = value;
+ this.updateView();
+ }
+ }]);
+
+ return FallbackHelper;
+}();
+
+/***/ }),
+
+/***/ "./src/util/query-args.js":
+/*!********************************!*\
+ !*** ./src/util/query-args.js ***!
+ \********************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+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"); } }
+
+// 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.
+
+/*
+Provides a simple way to get values from the query string if they're present
+and use a default value if not. Not strictly a "WebGL" utility, but I use it
+frequently enough for debugging that I wanted to include it here.
+
+Example:
+For the URL http://example.com/index.html?particleCount=1000
+
+QueryArgs.getInt("particleCount", 100); // URL overrides, returns 1000
+QueryArgs.getInt("particleSize", 10); // Not in URL, returns default of 10
+*/
+
+var urlArgs = null;
+window.onhashchange = function () {
+ // Force re-parsing on next access
+ urlArgs = null;
+};
+
+function ensureArgsCached() {
+ if (!urlArgs) {
+ urlArgs = {};
+ var query = window.location.search.substring(1) || window.location.hash.substring(1);
+ var vars = query.split('&');
+ for (var i = 0; i < vars.length; i++) {
+ var pair = vars[i].split('=');
+ urlArgs[pair[0].toLowerCase()] = decodeURIComponent(pair[1]);
+ }
+ }
+}
+
+var QueryArgs = exports.QueryArgs = function () {
+ function QueryArgs() {
+ _classCallCheck(this, QueryArgs);
+ }
+
+ _createClass(QueryArgs, null, [{
+ key: 'getString',
+ value: function getString(name, defaultValue) {
+ ensureArgsCached();
+ var lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return urlArgs[lcaseName];
+ }
+ return defaultValue;
+ }
+ }, {
+ key: 'getInt',
+ value: function getInt(name, defaultValue) {
+ ensureArgsCached();
+ var lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return parseInt(urlArgs[lcaseName], 10);
+ }
+ return defaultValue;
+ }
+ }, {
+ key: 'getFloat',
+ value: function getFloat(name, defaultValue) {
+ ensureArgsCached();
+ var lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return parseFloat(urlArgs[lcaseName]);
+ }
+ return defaultValue;
+ }
+ }, {
+ key: 'getBool',
+ value: function getBool(name, defaultValue) {
+ ensureArgsCached();
+ var lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return parseInt(urlArgs[lcaseName], 10) != 0;
+ }
+ return defaultValue;
+ }
+ }]);
+
+ return QueryArgs;
+}();
+
+/***/ })
+
+/******/ });
+});
+//# sourceMappingURL=cottontail.debug.js.map \ No newline at end of file
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map
new file mode 100644
index 00000000000..1877d6cacd8
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap","webpack:///./node_modules/gl-matrix/src/gl-matrix/common.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat2d.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat3.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat4.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/quat.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/quat2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec3.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec4.js","webpack:///./src/core/material.js","webpack:///./src/core/node.js","webpack:///./src/core/primitive.js","webpack:///./src/core/program.js","webpack:///./src/core/renderer.js","webpack:///./src/core/texture.js","webpack:///./src/cottontail.js","webpack:///./src/geometry/box-builder.js","webpack:///./src/geometry/primitive-stream.js","webpack:///./src/loaders/gltf2.js","webpack:///./src/materials/pbr.js","webpack:///./src/math/gl-matrix.js","webpack:///./src/math/ray.js","webpack:///./src/nodes/bounds-renderer.js","webpack:///./src/nodes/button.js","webpack:///./src/nodes/cube-sea.js","webpack:///./src/nodes/drop-shadow.js","webpack:///./src/nodes/gltf2.js","webpack:///./src/nodes/input-renderer.js","webpack:///./src/nodes/seven-segment-text.js","webpack:///./src/nodes/skybox.js","webpack:///./src/nodes/stats-viewer.js","webpack:///./src/nodes/video.js","webpack:///./src/scenes/scene.js","webpack:///./src/util/fallback-helper.js","webpack:///./src/util/query-args.js"],"names":["stateToBlendFunc","GL","WebGLRenderingContext","CAP","CULL_FACE","BLEND","DEPTH_TEST","STENCIL_TEST","COLOR_MASK","DEPTH_MASK","STENCIL_MASK","MAT_STATE","CAPS_RANGE","BLEND_SRC_SHIFT","BLEND_SRC_RANGE","BLEND_DST_SHIFT","BLEND_DST_RANGE","BLEND_FUNC_RANGE","DEPTH_FUNC_SHIFT","DEPTH_FUNC_RANGE","RENDER_ORDER","OPAQUE","SKY","TRANSPARENT","ADDITIVE","DEFAULT","state","mask","shift","value","SRC_COLOR","MaterialState","_state","blendFuncSrc","SRC_ALPHA","blendFuncDst","ONE_MINUS_SRC_ALPHA","depthFunc","LESS","NEVER","MaterialSampler","uniformName","_uniformName","_texture","MaterialUniform","defaultValue","length","_value","_length","Array","Material","renderOrder","_samplers","_uniforms","sampler","push","uniform","renderPrimitive","DEFAULT_TRANSLATION","Float32Array","DEFAULT_ROTATION","DEFAULT_SCALE","tmpRayMatrix","mat4","create","Node","name","children","parent","visible","selectable","_matrix","_dirtyTRS","_translation","_rotation","_scale","_dirtyWorldMatrix","_worldMatrix","_activeFrameId","_hoverFrameId","_renderPrimitives","_renderer","_selectHandler","renderer","clearRenderPrimitives","onRendererChanged","child","_setRenderer","cloneNode","vec3","copy","quat","waitForComplete","then","primitive","addRenderPrimitive","addNode","clone","frameId","markActive","removeNode","i","indexOf","splice","setMatrixDirty","fromRotationTranslationScale","childPromises","Promise","all","_instances","index","ray","localRay","_min","invert","worldMatrix","multiply","transformMatrix","Ray","intersection","intersectsAABB","_max","transformMat4","_hitTestSelectableNode","origin","fromValues","x","y","z","node","distance","result","childResult","hitTest","timestamp","frameDelta","onUpdate","_update","_updateLocalMatrix","mul","PrimitiveAttribute","buffer","componentCount","componentType","stride","byteOffset","normalized","Primitive","attributes","elementCount","mode","indexBuffer","indexByteOffset","indexType","min","max","Program","gl","vertSrc","fragSrc","attribMap","defines","_gl","program","createProgram","attrib","_firstUse","_nextUseCallbacks","definesString","define","_vertShader","createShader","VERTEX_SHADER","attachShader","shaderSource","compileShader","_fragShader","FRAGMENT_SHADER","attribName","bindAttribLocation","linkProgram","callback","getProgramParameter","LINK_STATUS","getShaderParameter","COMPILE_STATUS","console","error","getShaderInfoLog","getProgramInfoLog","deleteProgram","attribCount","ACTIVE_ATTRIBUTES","attribInfo","getActiveAttrib","getAttribLocation","uniformCount","ACTIVE_UNIFORMS","uniformInfo","getActiveUniform","replace","getUniformLocation","deleteShader","useProgram","createWebGLContext","ATTRIB","POSITION","NORMAL","TANGENT","TEXCOORD_0","TEXCOORD_1","COLOR_0","ATTRIB_MASK","DEF_LIGHT_DIR","DEF_LIGHT_COLOR","PRECISION_REGEX","RegExp","VERTEX_SHADER_SINGLE_ENTRY","VERTEX_SHADER_MULTI_ENTRY","FRAGMENT_SHADER_ENTRY","isPowerOfTwo","n","glAttribs","alpha","webglCanvas","document","createElement","contextTypes","webgl2","context","contextType","getContext","webglType","RenderView","projectionMatrix","viewMatrix","viewport","eye","_eye","_eyeIndex","RenderBuffer","target","usage","_target","_usage","_buffer","_promise","resolve","RenderPrimitiveAttribute","primitiveAttribute","_attrib_index","_componentCount","_componentType","_stride","_byteOffset","_normalized","RenderPrimitiveAttributeBuffer","_attributes","RenderPrimitive","_material","setPrimitive","_mode","_elementCount","_vao","_complete","_attributeBuffers","_attributeMask","attribute","renderAttribute","foundBuffer","attributeBuffer","_indexBuffer","_indexByteOffset","_indexType","material","reject","completionPromises","_samplerDictionary","_uniform_dictionary","RenderTexture","texture","_activeCallback","inverseMatrix","setCap","glEnum","cap","prevState","change","enable","disable","RenderMaterialSampler","materialSampler","_renderTexture","_getRenderTexture","_index","RenderMaterialUniform","materialUniform","_uniform","RenderMaterial","_program","_completeForActiveFrame","renderSampler","renderUniform","_firstBind","_renderOrder","activeTexture","TEXTURE0","bindTexture","TEXTURE_2D","uniform1fv","uniform2fv","uniform3fv","uniform4fv","otherState","Renderer","_frameId","_programCache","_textureCache","_cameraPositions","_vaoExt","getExtension","fragHighPrecision","getShaderPrecisionFormat","HIGH_FLOAT","_defaultFragPrecision","precision","_depthMaskNeedsReset","_colorMaskNeedsReset","_globalLightColor","_globalLightDir","data","STATIC_DRAW","glBuffer","createBuffer","renderBuffer","bindBuffer","bufferData","byteLength","offset","bufferSubData","updateRenderBuffer","_getMaterialProgram","renderMaterial","setRenderMaterial","meshNode","createRenderPrimitive","views","rootNode","vp","width","height","cameraPosition","set","renderPrimitives","_drawRenderPrimitiveSet","bindVertexArrayOES","depthMask","colorMask","attribMask","use","LIGHT_DIRECTION","LIGHT_COLOR","uniformMatrix4fv","PROJECTION_MATRIX","VIEW_MATRIX","CAMERA_POSITION","uniform1i","EYE_INDEX","eyeIndex","_bindMaterialState","bind","createVertexArrayOES","_bindPrimitive","view","instance","MODEL_MATRIX","drawElements","drawArrays","key","textureKey","Error","textureHandle","createTexture","renderTexture","DataTexture","texImage2D","format","_type","_data","_setSamplerParameters","UNSIGNED_BYTE","source","VideoTexture","_video","addEventListener","paused","waiting","powerOfTwo","mipmap","generateMipmap","minFilter","LINEAR_MIPMAP_LINEAR","LINEAR","wrapS","REPEAT","CLAMP_TO_EDGE","wrapT","texParameteri","TEXTURE_MAG_FILTER","magFilter","TEXTURE_MIN_FILTER","TEXTURE_WRAP_S","TEXTURE_WRAP_T","materialName","vertexSource","fragmentSource","getProgramDefines","_getProgramKey","multiview","fullVertexSource","precisionMatch","match","fragPrecisionHeader","fullFragmentSource","onNextUse","enableVertexAttribArray","disableVertexAttribArray","ARRAY_BUFFER","vertexAttribPointer","ELEMENT_ARRAY_BUFFER","prevMaterial","_capsDiff","colorMaskChange","depthMaskChange","stencilMaskChange","stencilMask","_blendDiff","blendFunc","_depthFuncDiff","TextureSampler","Texture","RGBA","ImageTexture","img","_img","_imgBitmap","src","complete","naturalWidth","_finishImage","window","createImageBitmap","imgBitmap","UrlTexture","url","Image","BlobTexture","blob","URL","createObjectURL","video","readyState","videoWidth","videoHeight","nextDataTextureIndex","type","_width","_height","_format","_key","ColorTexture","r","g","b","a","colorData","Uint8Array","PrimitiveStream","BoxBuilder","PbrMaterial","mat3","vec4","BoundsRenderer","ButtonNode","DropShadowNode","CubeSeaNode","Gltf2Node","SkyboxNode","VideoNode","WebXRView","Scene","FallbackHelper","QueryArgs","stream","primitiveStream","w","h","d","wh","hh","dh","cx","cy","cz","startGeometry","idx","nextVertexIndex","pushTriangle","pushVertex","endGeometry","center","size","hs","pushBox","GeometryBuilderBase","tempVec3","options","_vertices","_indices","_geometryStarted","_vertexOffset","_vertexIndex","_highIndex","_flipWinding","_invertNormals","_transform","_normalTransform","u","v","nx","ny","nz","transformMat3","Math","idxA","idxB","idxC","vertexBuffer","createRenderBuffer","Uint16Array","attribs","FLOAT","setIndexBuffer","setBounds","fromMat4","_stream","finishPrimitive","clear","GLB_MAGIC","CHUNK_TYPE","JSON","BIN","isAbsoluteUri","uri","absRegEx","location","protocol","isDataUri","dataRegEx","resolveUri","baseUrl","getComponentCount","Gltf2Loader","fetch","response","lastIndexOf","substring","endsWith","json","loadFromJson","arrayBuffer","loadFromBinary","headerView","DataView","magic","getUint32","version","chunks","chunkOffset","chunkHeaderView","chunkLength","chunkType","slice","decoder","TextDecoder","jsonString","decode","parse","binaryChunk","asset","minVersion","buffers","Gltf2Resource","bufferViews","bufferView","Gltf2BufferView","images","image","textures","glTexture","getTexture","textureInfo","materials","glMaterial","pbr","pbrMetallicRoughness","baseColorFactor","baseColor","baseColorTexture","metallicRoughnessFactor","metallicFactor","roughnessFactor","metallicRoughness","metallicRoughnessTexture","normal","normalTexture","occlusion","occlusionTexture","occlusionStrength","strength","emissiveFactor","emissive","emissiveTexture","alphaMode","blend","cullFace","doubleSided","accessors","meshes","mesh","glMesh","Gltf2Mesh","primitives","accessor","count","glAttribute","byteStride","glPrimitive","indices","sceneNode","scene","scenes","nodes","nodeId","processNodes","glNode","matrix","translation","rotation","scale","_viewPromise","_renderBuffer","dataView","_dataPromise","base64String","binaryArray","from","atob","c","charCodeAt","Blob","mimeType","VERTEX_SOURCE","EPIC_PBR_FUNCTIONS","FRAGMENT_SOURCE","defineSampler","defineUniform","programDefines","glMatrix","mat2","mat2d","quat2","vec2","normalMat","RAY_INTERSECTION_OFFSET","_dir","dir","bounds","tmin","sign","inv_dir","tmax","tymin","tymax","tzmin","tzmax","t","intersectionPoint","add","normalize","BoundsMaterial","ONE","depthTest","_stageBounds","stageBounds","verts","pointCount","geometry","point","BUTTON_SIZE","BUTTON_CORNER_RADIUS","BUTTON_CORNER_SEGMENTS","BUTTON_ICON_SIZE","BUTTON_LAYER_DISTANCE","BUTTON_COLOR","BUTTON_ALPHA","BUTTON_HOVER_COLOR","BUTTON_HOVER_ALPHA","BUTTON_HOVER_SCALE","BUTTON_HOVER_TRANSITION_TIME_MS","ButtonMaterial","ButtonIconMaterial","icon","iconTexture","_iconTexture","_hovered","_hoverT","hd","ihs","segments","rad","PI","cos","sin","section","floor","buttonPrimitive","_buttonRenderPrimitive","iconPrimitive","iconMaterial","_iconRenderPrimitive","hoverAmount","uniforms","_updateHoverState","samplers","CubeSeaMaterial","heavy","heavyGpu","cubeCount","cubeScale","halfOnly","autoRotate","imageUrl","_renderPrimitive","boxBuilder","pushCube","heroPrimitive","heroNode","createMesh","rebuildCubes","cubeSeaNode","halfGrid","pos","cubeSeaPrimitive","fromRotation","SHADOW_SEGMENTS","SHADOW_GROUND_OFFSET","SHADOW_CENTER_ALPHA","SHADOW_INNER_ALPHA","SHADOW_OUTER_ALPHA","SHADOW_INNER_RADIUS","SHADOW_OUTER_RADIUS","DropShadowMaterial","LEQUAL","segRad","shadowPrimitive","_shadowRenderPrimitive","gltfLoaderMap","WeakMap","_url","_resolver","_rejecter","loader","get","_ensurePromise","loadFromUrl","catch","err","LASER_TEXTURE_DATA","LASER_LENGTH","LASER_DIAMETER","LASER_FADE_END","LASER_FADE_POINT","LASER_DEFAULT_COLOR","CURSOR_RADIUS","CURSOR_SHADOW_RADIUS","CURSOR_SHADOW_INNER_LUMINANCE","CURSOR_SHADOW_OUTER_LUMINANCE","CURSOR_SHADOW_INNER_OPACITY","CURSOR_SHADOW_OUTER_OPACITY","CURSOR_OPACITY","CURSOR_SEGMENTS","CURSOR_DEFAULT_COLOR","CURSOR_DEFAULT_HIDDEN_COLOR","DEFAULT_RESET_OPTIONS","controllers","lasers","cursors","LaserMaterial","laser","laserColor","CURSOR_VERTEX_SHADER","CURSOR_FRAGMENT_SHADER","CursorMaterial","cursorColor","CursorHiddenMaterial","GEQUAL","InputRenderer","_maxInputElements","_controllers","_controllerNode","_controllerNodeHandedness","_lasers","_cursors","_activeControllers","_activeLasers","_activeCursors","controllerNode","handedness","gripMatrix","controller","targetRay","_createLaserMesh","cursorPos","_createCursorMesh","cursor","lr","ll","laserVerts","laserIndices","laserVertexBuffer","laserIndexBuffer","laserIndexCount","laserAttribs","laserPrimitive","laserMaterial","laserRenderPrimitive","cursorVerts","cursorIndices","indexOffset","cursorVertexBuffer","cursorIndexBuffer","cursorIndexCount","cursorAttribs","cursorPrimitive","cursorMaterial","cursorHiddenMaterial","cursorRenderPrimitive","cursorHiddenRenderPrimitive","TEXT_KERNING","SevenSegmentMaterial","SevenSegmentText","_text","_charNodes","clearNodes","vertices","segmentIndices","thickness","defineSegment","id","left","top","right","bottom","characters","defineCharacter","character","segment","vertexAttribs","_charPrimitives","char","charDef","text","charPrimitive","SkyboxMaterial","texCoordScaleOffset","_displayMode","displayMode","_rotationY","rotationY","latSegments","lonSegments","theta","sinTheta","cosTheta","idxOffsetA","idxOffsetB","j","phi","SEGMENTS","MAX_FPS","StatsMaterial","segmentToX","fpsToY","fpsToRGB","now","performance","Date","StatsViewer","_performanceMonitoring","_startTime","_prevFrameTime","_prevGraphUpdateTime","_frames","_fpsAverage","_fpsMin","_fpsStep","_lastSegment","_fpsVertexBuffer","_fpsRenderPrimitive","_fpsNode","_sevenSegmentNode","fpsVerts","fpsIndices","addBGSquare","DYNAMIC_DRAW","fpsIndexBuffer","fpsAttribs","fpsPrimitive","time","frameFps","intervalTime","round","_updateGraph","log","valueLow","valueHigh","color","y0","y1","updateVerts","VideoMaterial","_video_texture","layer","getViewport","_timestamp","_frameDelta","_statsStanding","_stats","_statsEnabled","enableStats","_inputRenderer","_resetInputEndFrame","_lastTimestamp","_hoverFrame","_hoveredNodes","frame","frameOfRef","session","getInputSources","inputSources","newHoveredNodes","lastHoverFrame","inputSource","inputPose","getInputPose","inputRenderer","addController","targetRayMode","addLaserPointer","hitResult","addCursor","onHoverStart","cursorDistance","direction","hoverNode","onHoverEnd","handleSelectPointer","handleSelect","fromEuler","drawViewArray","xrFrame","pose","baseLayer","bindFramebuffer","FRAMEBUFFER","framebuffer","COLOR_BUFFER_BIT","DEPTH_BUFFER_BIT","drawViews","prevTimestamp","begin","reset","end","LOOK_SPEED","_emulateStage","lookYaw","lookPitch","identity","onResize","canvas","offsetWidth","devicePixelRatio","offsetHeight","perspective","drawingBufferWidth","drawingBufferHeight","lastTouchX","lastTouchY","ev","touches","pageX","pageY","onLook","buttons","movementX","movementY","preventDefault","boundOnFrame","onFrame","requestAnimationFrame","yaw","pitch","updateView","startFrame","draw","endFrame","rotateX","rotateY","translate","urlArgs","onhashchange","ensureArgsCached","query","search","hash","vars","split","pair","toLowerCase","decodeURIComponent","lcaseName","parseInt","parseFloat"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;;;;;;AClFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACO;AACA;AACA;;AAEP;AACA;AACA;AACA,WAAW,KAAK;AAChB;AACO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;;;;;;;;;;;;ACzCA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAuC;;AAEvC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB;;AAEO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AC9ZP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,MAAM;AACnB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AC/bP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAK;AACf,UAAU,KAAK;AACf;AACA,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAK;AACf,UAAU,KAAK;AACf;AACA,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AAIA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AC1uBP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,YAAY,WAAW,WAAW;AAClC;AACA;AACA;AACA;;AAEA,YAAY,WAAW,YAAY;AACnC;AACA;AACA;AACA;;AAEA,aAAa,YAAY,YAAY;AACrC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH,eAAe,YAAY,YAAY;AACvC,eAAe,YAAY,YAAY;AACvC,eAAe,YAAY,aAAa;;AAExC,iBAAiB,cAAc,cAAc;AAC7C,iBAAiB,cAAc,cAAc;AAC7C,iBAAiB,cAAc,eAAe;;AAE9C;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,YAAY,kDAAgB,GAAG,aAAa;;AAE5C;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,aAAa,YAAY,YAAY;AACrC,aAAa,YAAY,YAAY;AACrC,aAAa,YAAY,aAAa;;AAEtC;AACA,sBAAsB,yBAAyB;AAC/C,0BAA0B,qBAAqB;AAC/C,0BAA0B,yBAAyB;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA,YAAY,kDAAgB,GAAG,aAAa;;AAE5C;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACO;AACP,wBAAwB,qDAAmB;AAC3C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB;AACA,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AClrDP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAuC;AACN;AACA;AACA;;AAEjC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,OAAO;AACnB;AACO;AACP;AACA;AACA,UAAU,kDAAgB;AAC1B;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,kDAAgB;AACvC;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA,WAAW,iDAAe;AAC1B,WAAW,iDAAe;AAC1B,WAAW,iDAAe;;AAE1B;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA,oCAAoC;AACpC;AACA,sBAAsB;AACtB;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,EAAE;AACb,WAAW,EAAE;AACb,WAAW,EAAE;AACb,aAAa,KAAK;AAClB;AACA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACO,cAAc,8CAAU;;AAE/B;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACO,mBAAmB,mDAAe;;AAEzC;AACA;AACA;AACA,WAAW,KAAK;AA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A;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP,eAAe,qDAAmB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP,eAAe,qDAAmB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA,cAAc,+CAAW;AACzB,EAAE,oDAAgB;AAClB,cAAc,qDAAmB;AACjC,EAAE,uDAAmB;AACrB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACO,gBAAgB,6CAAS;;AAEhC;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO,gBAAgB,6CAAS;;AAEhC;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,gDAAY;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,gDAAY;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,gDAAY;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA,sBAAsB,kDAAgB;AACtC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACO,YAAY,4CAAQ;;AAE3B;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACO,eAAe,+CAAW;;AAEjC;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACO,sBAAsB,sDAAkB;;AAE/C;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,kDAAgB;AAC/C,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC;;;;;;;;;;;;;ACr1BA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA,UAAU,iDAAe;AACzB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA,mBAAmB,OAAO;AAC1B,oBAAoB;AACpB;AACA,oBAAoB;AACpB;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;;AChnBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA,UAAU,iDAAe;AACzB,WAAW,iDAAe;AAC1B;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA,mBAAmB,OAAO;AAC1B,oBAAoB,iBAAiB;AACrC;AACA,oBAAoB,iBAAiB;AACrC;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;;AChwBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,iDAAe;AACxB,SAAS,iDAAe;AACxB;AACA,GAAG;AACH;AACA,SAAS,iDAAe;AACxB,SAAS,iDAAe;AACxB;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;;AAEA;AACA;AAC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","file":"cottontail.debug.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse {\n\t\tvar a = factory();\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/cottontail.js\");\n","/**\n * Common utilities\n * @module glMatrix\n */\n\n// Configuration Constants\nexport const EPSILON = 0.000001;\nexport let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;\nexport const RANDOM = Math.random;\n\n/**\n * Sets the type of array used when creating new vectors and matrices\n *\n * @param {Type} type Array type, such as Float32Array or Array\n */\nexport function setMatrixArrayType(type) {\n ARRAY_TYPE = type;\n}\n\nconst degree = Math.PI / 180;\n\n/**\n * Convert Degree To Radian\n *\n * @param {Number} a Angle in Degrees\n */\nexport function toRadian(a) {\n return a * degree;\n}\n\n/**\n * Tests whether or not the arguments have approximately the same value, within an absolute\n * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less\n * than or equal to 1.0, and a relative tolerance is used for larger values)\n *\n * @param {Number} a The first number to test.\n * @param {Number} b The second number to test.\n * @returns {Boolean} True if the numbers are approximately equal, false otherwise.\n */\nexport function equals(a, b) {\n return Math.abs(a - b) <= EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b));\n}\n","import * as glMatrix from \"./common.js\"\n\n/**\n * 2x2 Matrix\n * @module mat2\n */\n\n/**\n * Creates a new identity mat2\n *\n * @returns {mat2} a new 2x2 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(4);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n }\n out[0] = 1;\n out[3] = 1;\n return out;\n}\n\n/**\n * Creates a new mat2 initialized with values from an existing matrix\n *\n * @param {mat2} a matrix to clone\n * @returns {mat2} a new 2x2 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Copy the values from one mat2 to another\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Set a mat2 to the identity matrix\n *\n * @param {mat2} out the receiving matrix\n * @returns {mat2} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n return out;\n}\n\n/**\n * Create a new mat2 with the given values\n *\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m10 Component in column 1, row 0 position (index 2)\n * @param {Number} m11 Component in column 1, row 1 position (index 3)\n * @returns {mat2} out A new 2x2 matrix\n */\nexport function fromValues(m00, m01, m10, m11) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = m00;\n out[1] = m01;\n out[2] = m10;\n out[3] = m11;\n return out;\n}\n\n/**\n * Set the components of a mat2 to the given values\n *\n * @param {mat2} out the receiving matrix\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m10 Component in column 1, row 0 position (index 2)\n * @param {Number} m11 Component in column 1, row 1 position (index 3)\n * @returns {mat2} out\n */\nexport function set(out, m00, m01, m10, m11) {\n out[0] = m00;\n out[1] = m01;\n out[2] = m10;\n out[3] = m11;\n return out;\n}\n\n/**\n * Transpose the values of a mat2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache\n // some values\n if (out === a) {\n let a1 = a[1];\n out[1] = a[2];\n out[2] = a1;\n } else {\n out[0] = a[0];\n out[1] = a[2];\n out[2] = a[1];\n out[3] = a[3];\n }\n\n return out;\n}\n\n/**\n * Inverts a mat2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function invert(out, a) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n\n // Calculate the determinant\n let det = a0 * a3 - a2 * a1;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = a3 * det;\n out[1] = -a1 * det;\n out[2] = -a2 * det;\n out[3] = a0 * det;\n\n return out;\n}\n\n/**\n * Calculates the adjugate of a mat2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function adjoint(out, a) {\n // Caching this value is nessecary if out == a\n let a0 = a[0];\n out[0] = a[3];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = a0;\n\n return out;\n}\n\n/**\n * Calculates the determinant of a mat2\n *\n * @param {mat2} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n return a[0] * a[3] - a[2] * a[1];\n}\n\n/**\n * Multiplies two mat2's\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @returns {mat2} out\n */\nexport function multiply(out, a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n out[0] = a0 * b0 + a2 * b1;\n out[1] = a1 * b0 + a3 * b1;\n out[2] = a0 * b2 + a2 * b3;\n out[3] = a1 * b2 + a3 * b3;\n return out;\n}\n\n/**\n * Rotates a mat2 by the given angle\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2} out\n */\nexport function rotate(out, a, rad) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n out[0] = a0 * c + a2 * s;\n out[1] = a1 * c + a3 * s;\n out[2] = a0 * -s + a2 * c;\n out[3] = a1 * -s + a3 * c;\n return out;\n}\n\n/**\n * Scales the mat2 by the dimensions in the given vec2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the matrix to rotate\n * @param {vec2} v the vec2 to scale the matrix by\n * @returns {mat2} out\n **/\nexport function scale(out, a, v) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let v0 = v[0], v1 = v[1];\n out[0] = a0 * v0;\n out[1] = a1 * v0;\n out[2] = a2 * v1;\n out[3] = a3 * v1;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle\n * This is equivalent to (but much faster than):\n *\n * mat2.identity(dest);\n * mat2.rotate(dest, dest, rad);\n *\n * @param {mat2} out mat2 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2} out\n */\nexport function fromRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n out[0] = c;\n out[1] = s;\n out[2] = -s;\n out[3] = c;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat2.identity(dest);\n * mat2.scale(dest, dest, vec);\n *\n * @param {mat2} out mat2 receiving operation result\n * @param {vec2} v Scaling vector\n * @returns {mat2} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n out[3] = v[1];\n return out;\n}\n\n/**\n * Returns a string representation of a mat2\n *\n * @param {mat2} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat2\n *\n * @param {mat2} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))\n}\n\n/**\n * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix\n * @param {mat2} L the lower triangular matrix\n * @param {mat2} D the diagonal matrix\n * @param {mat2} U the upper triangular matrix\n * @param {mat2} a the input matrix to factorize\n */\n\nexport function LDU(L, D, U, a) {\n L[2] = a[2]/a[0];\n U[0] = a[0];\n U[1] = a[1];\n U[3] = a[3] - L[2] * U[1];\n return [L, D, U];\n}\n\n/**\n * Adds two mat2's\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @returns {mat2} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @returns {mat2} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat2} a The first matrix.\n * @param {mat2} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat2} a The first matrix.\n * @param {mat2} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\n}\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat2} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n return out;\n}\n\n/**\n * Adds two mat2's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat2} out the receiving vector\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat2} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n return out;\n}\n\n/**\n * Alias for {@link mat2.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat2.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 2x3 Matrix\n * @module mat2d\n *\n * @description\n * A mat2d contains six elements defined as:\n * <pre>\n * [a, c, tx,\n * b, d, ty]\n * </pre>\n * This is a short form for the 3x3 matrix:\n * <pre>\n * [a, c, tx,\n * b, d, ty,\n * 0, 0, 1]\n * </pre>\n * The last row is ignored so the array is shorter and operations are faster.\n */\n\n/**\n * Creates a new identity mat2d\n *\n * @returns {mat2d} a new 2x3 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(6);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n out[4] = 0;\n out[5] = 0;\n }\n out[0] = 1;\n out[3] = 1;\n return out;\n}\n\n/**\n * Creates a new mat2d initialized with values from an existing matrix\n *\n * @param {mat2d} a matrix to clone\n * @returns {mat2d} a new 2x3 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(6);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n return out;\n}\n\n/**\n * Copy the values from one mat2d to another\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the source matrix\n * @returns {mat2d} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n return out;\n}\n\n/**\n * Set a mat2d to the identity matrix\n *\n * @param {mat2d} out the receiving matrix\n * @returns {mat2d} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = 0;\n out[5] = 0;\n return out;\n}\n\n/**\n * Create a new mat2d with the given values\n *\n * @param {Number} a Component A (index 0)\n * @param {Number} b Component B (index 1)\n * @param {Number} c Component C (index 2)\n * @param {Number} d Component D (index 3)\n * @param {Number} tx Component TX (index 4)\n * @param {Number} ty Component TY (index 5)\n * @returns {mat2d} A new mat2d\n */\nexport function fromValues(a, b, c, d, tx, ty) {\n let out = new glMatrix.ARRAY_TYPE(6);\n out[0] = a;\n out[1] = b;\n out[2] = c;\n out[3] = d;\n out[4] = tx;\n out[5] = ty;\n return out;\n}\n\n/**\n * Set the components of a mat2d to the given values\n *\n * @param {mat2d} out the receiving matrix\n * @param {Number} a Component A (index 0)\n * @param {Number} b Component B (index 1)\n * @param {Number} c Component C (index 2)\n * @param {Number} d Component D (index 3)\n * @param {Number} tx Component TX (index 4)\n * @param {Number} ty Component TY (index 5)\n * @returns {mat2d} out\n */\nexport function set(out, a, b, c, d, tx, ty) {\n out[0] = a;\n out[1] = b;\n out[2] = c;\n out[3] = d;\n out[4] = tx;\n out[5] = ty;\n return out;\n}\n\n/**\n * Inverts a mat2d\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the source matrix\n * @returns {mat2d} out\n */\nexport function invert(out, a) {\n let aa = a[0], ab = a[1], ac = a[2], ad = a[3];\n let atx = a[4], aty = a[5];\n\n let det = aa * ad - ab * ac;\n if(!det){\n return null;\n }\n det = 1.0 / det;\n\n out[0] = ad * det;\n out[1] = -ab * det;\n out[2] = -ac * det;\n out[3] = aa * det;\n out[4] = (ac * aty - ad * atx) * det;\n out[5] = (ab * atx - aa * aty) * det;\n return out;\n}\n\n/**\n * Calculates the determinant of a mat2d\n *\n * @param {mat2d} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n return a[0] * a[3] - a[1] * a[2];\n}\n\n/**\n * Multiplies two mat2d's\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @returns {mat2d} out\n */\nexport function multiply(out, a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\n out[0] = a0 * b0 + a2 * b1;\n out[1] = a1 * b0 + a3 * b1;\n out[2] = a0 * b2 + a2 * b3;\n out[3] = a1 * b2 + a3 * b3;\n out[4] = a0 * b4 + a2 * b5 + a4;\n out[5] = a1 * b4 + a3 * b5 + a5;\n return out;\n}\n\n/**\n * Rotates a mat2d by the given angle\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2d} out\n */\nexport function rotate(out, a, rad) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n out[0] = a0 * c + a2 * s;\n out[1] = a1 * c + a3 * s;\n out[2] = a0 * -s + a2 * c;\n out[3] = a1 * -s + a3 * c;\n out[4] = a4;\n out[5] = a5;\n return out;\n}\n\n/**\n * Scales the mat2d by the dimensions in the given vec2\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to translate\n * @param {vec2} v the vec2 to scale the matrix by\n * @returns {mat2d} out\n **/\nexport function scale(out, a, v) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let v0 = v[0], v1 = v[1];\n out[0] = a0 * v0;\n out[1] = a1 * v0;\n out[2] = a2 * v1;\n out[3] = a3 * v1;\n out[4] = a4;\n out[5] = a5;\n return out;\n}\n\n/**\n * Translates the mat2d by the dimensions in the given vec2\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to translate\n * @param {vec2} v the vec2 to translate the matrix by\n * @returns {mat2d} out\n **/\nexport function translate(out, a, v) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let v0 = v[0], v1 = v[1];\n out[0] = a0;\n out[1] = a1;\n out[2] = a2;\n out[3] = a3;\n out[4] = a0 * v0 + a2 * v1 + a4;\n out[5] = a1 * v0 + a3 * v1 + a5;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle\n * This is equivalent to (but much faster than):\n *\n * mat2d.identity(dest);\n * mat2d.rotate(dest, dest, rad);\n *\n * @param {mat2d} out mat2d receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2d} out\n */\nexport function fromRotation(out, rad) {\n let s = Math.sin(rad), c = Math.cos(rad);\n out[0] = c;\n out[1] = s;\n out[2] = -s;\n out[3] = c;\n out[4] = 0;\n out[5] = 0;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat2d.identity(dest);\n * mat2d.scale(dest, dest, vec);\n *\n * @param {mat2d} out mat2d receiving operation result\n * @param {vec2} v Scaling vector\n * @returns {mat2d} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n out[3] = v[1];\n out[4] = 0;\n out[5] = 0;\n return out;\n}\n\n/**\n * Creates a matrix from a vector translation\n * This is equivalent to (but much faster than):\n *\n * mat2d.identity(dest);\n * mat2d.translate(dest, dest, vec);\n *\n * @param {mat2d} out mat2d receiving operation result\n * @param {vec2} v Translation vector\n * @returns {mat2d} out\n */\nexport function fromTranslation(out, v) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = v[0];\n out[5] = v[1];\n return out;\n}\n\n/**\n * Returns a string representation of a mat2d\n *\n * @param {mat2d} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +\n a[3] + ', ' + a[4] + ', ' + a[5] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat2d\n *\n * @param {mat2d} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))\n}\n\n/**\n * Adds two mat2d's\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @returns {mat2d} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @returns {mat2d} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n out[4] = a[4] - b[4];\n out[5] = a[5] - b[5];\n return out;\n}\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat2d} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n return out;\n}\n\n/**\n * Adds two mat2d's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat2d} out the receiving vector\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat2d} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n out[4] = a[4] + (b[4] * scale);\n out[5] = a[5] + (b[5] * scale);\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat2d} a The first matrix.\n * @param {mat2d} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat2d} a The first matrix.\n * @param {mat2d} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)));\n}\n\n/**\n * Alias for {@link mat2d.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat2d.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 3x3 Matrix\n * @module mat3\n */\n\n/**\n * Creates a new identity mat3\n *\n * @returns {mat3} a new 3x3 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(9);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n }\n out[0] = 1;\n out[4] = 1;\n out[8] = 1;\n return out;\n}\n\n/**\n * Copies the upper-left 3x3 values into the given mat3.\n *\n * @param {mat3} out the receiving 3x3 matrix\n * @param {mat4} a the source 4x4 matrix\n * @returns {mat3} out\n */\nexport function fromMat4(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[4];\n out[4] = a[5];\n out[5] = a[6];\n out[6] = a[8];\n out[7] = a[9];\n out[8] = a[10];\n return out;\n}\n\n/**\n * Creates a new mat3 initialized with values from an existing matrix\n *\n * @param {mat3} a matrix to clone\n * @returns {mat3} a new 3x3 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(9);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n return out;\n}\n\n/**\n * Copy the values from one mat3 to another\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n return out;\n}\n\n/**\n * Create a new mat3 with the given values\n *\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m10 Component in column 1, row 0 position (index 3)\n * @param {Number} m11 Component in column 1, row 1 position (index 4)\n * @param {Number} m12 Component in column 1, row 2 position (index 5)\n * @param {Number} m20 Component in column 2, row 0 position (index 6)\n * @param {Number} m21 Component in column 2, row 1 position (index 7)\n * @param {Number} m22 Component in column 2, row 2 position (index 8)\n * @returns {mat3} A new mat3\n */\nexport function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {\n let out = new glMatrix.ARRAY_TYPE(9);\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m10;\n out[4] = m11;\n out[5] = m12;\n out[6] = m20;\n out[7] = m21;\n out[8] = m22;\n return out;\n}\n\n/**\n * Set the components of a mat3 to the given values\n *\n * @param {mat3} out the receiving matrix\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m10 Component in column 1, row 0 position (index 3)\n * @param {Number} m11 Component in column 1, row 1 position (index 4)\n * @param {Number} m12 Component in column 1, row 2 position (index 5)\n * @param {Number} m20 Component in column 2, row 0 position (index 6)\n * @param {Number} m21 Component in column 2, row 1 position (index 7)\n * @param {Number} m22 Component in column 2, row 2 position (index 8)\n * @returns {mat3} out\n */\nexport function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m10;\n out[4] = m11;\n out[5] = m12;\n out[6] = m20;\n out[7] = m21;\n out[8] = m22;\n return out;\n}\n\n/**\n * Set a mat3 to the identity matrix\n *\n * @param {mat3} out the receiving matrix\n * @returns {mat3} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 1;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n out[8] = 1;\n return out;\n}\n\n/**\n * Transpose the values of a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache some values\n if (out === a) {\n let a01 = a[1], a02 = a[2], a12 = a[5];\n out[1] = a[3];\n out[2] = a[6];\n out[3] = a01;\n out[5] = a[7];\n out[6] = a02;\n out[7] = a12;\n } else {\n out[0] = a[0];\n out[1] = a[3];\n out[2] = a[6];\n out[3] = a[1];\n out[4] = a[4];\n out[5] = a[7];\n out[6] = a[2];\n out[7] = a[5];\n out[8] = a[8];\n }\n\n return out;\n}\n\n/**\n * Inverts a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function invert(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n let b01 = a22 * a11 - a12 * a21;\n let b11 = -a22 * a10 + a12 * a20;\n let b21 = a21 * a10 - a11 * a20;\n\n // Calculate the determinant\n let det = a00 * b01 + a01 * b11 + a02 * b21;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = b01 * det;\n out[1] = (-a22 * a01 + a02 * a21) * det;\n out[2] = (a12 * a01 - a02 * a11) * det;\n out[3] = b11 * det;\n out[4] = (a22 * a00 - a02 * a20) * det;\n out[5] = (-a12 * a00 + a02 * a10) * det;\n out[6] = b21 * det;\n out[7] = (-a21 * a00 + a01 * a20) * det;\n out[8] = (a11 * a00 - a01 * a10) * det;\n return out;\n}\n\n/**\n * Calculates the adjugate of a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function adjoint(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n out[0] = (a11 * a22 - a12 * a21);\n out[1] = (a02 * a21 - a01 * a22);\n out[2] = (a01 * a12 - a02 * a11);\n out[3] = (a12 * a20 - a10 * a22);\n out[4] = (a00 * a22 - a02 * a20);\n out[5] = (a02 * a10 - a00 * a12);\n out[6] = (a10 * a21 - a11 * a20);\n out[7] = (a01 * a20 - a00 * a21);\n out[8] = (a00 * a11 - a01 * a10);\n return out;\n}\n\n/**\n * Calculates the determinant of a mat3\n *\n * @param {mat3} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);\n}\n\n/**\n * Multiplies two mat3's\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @returns {mat3} out\n */\nexport function multiply(out, a, b) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n let b00 = b[0], b01 = b[1], b02 = b[2];\n let b10 = b[3], b11 = b[4], b12 = b[5];\n let b20 = b[6], b21 = b[7], b22 = b[8];\n\n out[0] = b00 * a00 + b01 * a10 + b02 * a20;\n out[1] = b00 * a01 + b01 * a11 + b02 * a21;\n out[2] = b00 * a02 + b01 * a12 + b02 * a22;\n\n out[3] = b10 * a00 + b11 * a10 + b12 * a20;\n out[4] = b10 * a01 + b11 * a11 + b12 * a21;\n out[5] = b10 * a02 + b11 * a12 + b12 * a22;\n\n out[6] = b20 * a00 + b21 * a10 + b22 * a20;\n out[7] = b20 * a01 + b21 * a11 + b22 * a21;\n out[8] = b20 * a02 + b21 * a12 + b22 * a22;\n return out;\n}\n\n/**\n * Translate a mat3 by the given vector\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to translate\n * @param {vec2} v vector to translate by\n * @returns {mat3} out\n */\nexport function translate(out, a, v) {\n let a00 = a[0], a01 = a[1], a02 = a[2],\n a10 = a[3], a11 = a[4], a12 = a[5],\n a20 = a[6], a21 = a[7], a22 = a[8],\n x = v[0], y = v[1];\n\n out[0] = a00;\n out[1] = a01;\n out[2] = a02;\n\n out[3] = a10;\n out[4] = a11;\n out[5] = a12;\n\n out[6] = x * a00 + y * a10 + a20;\n out[7] = x * a01 + y * a11 + a21;\n out[8] = x * a02 + y * a12 + a22;\n return out;\n}\n\n/**\n * Rotates a mat3 by the given angle\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat3} out\n */\nexport function rotate(out, a, rad) {\n let a00 = a[0], a01 = a[1], a02 = a[2],\n a10 = a[3], a11 = a[4], a12 = a[5],\n a20 = a[6], a21 = a[7], a22 = a[8],\n\n s = Math.sin(rad),\n c = Math.cos(rad);\n\n out[0] = c * a00 + s * a10;\n out[1] = c * a01 + s * a11;\n out[2] = c * a02 + s * a12;\n\n out[3] = c * a10 - s * a00;\n out[4] = c * a11 - s * a01;\n out[5] = c * a12 - s * a02;\n\n out[6] = a20;\n out[7] = a21;\n out[8] = a22;\n return out;\n};\n\n/**\n * Scales the mat3 by the dimensions in the given vec2\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to rotate\n * @param {vec2} v the vec2 to scale the matrix by\n * @returns {mat3} out\n **/\nexport function scale(out, a, v) {\n let x = v[0], y = v[1];\n\n out[0] = x * a[0];\n out[1] = x * a[1];\n out[2] = x * a[2];\n\n out[3] = y * a[3];\n out[4] = y * a[4];\n out[5] = y * a[5];\n\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n return out;\n}\n\n/**\n * Creates a matrix from a vector translation\n * This is equivalent to (but much faster than):\n *\n * mat3.identity(dest);\n * mat3.translate(dest, dest, vec);\n *\n * @param {mat3} out mat3 receiving operation result\n * @param {vec2} v Translation vector\n * @returns {mat3} out\n */\nexport function fromTranslation(out, v) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 1;\n out[5] = 0;\n out[6] = v[0];\n out[7] = v[1];\n out[8] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle\n * This is equivalent to (but much faster than):\n *\n * mat3.identity(dest);\n * mat3.rotate(dest, dest, rad);\n *\n * @param {mat3} out mat3 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat3} out\n */\nexport function fromRotation(out, rad) {\n let s = Math.sin(rad), c = Math.cos(rad);\n\n out[0] = c;\n out[1] = s;\n out[2] = 0;\n\n out[3] = -s;\n out[4] = c;\n out[5] = 0;\n\n out[6] = 0;\n out[7] = 0;\n out[8] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat3.identity(dest);\n * mat3.scale(dest, dest, vec);\n *\n * @param {mat3} out mat3 receiving operation result\n * @param {vec2} v Scaling vector\n * @returns {mat3} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n\n out[3] = 0;\n out[4] = v[1];\n out[5] = 0;\n\n out[6] = 0;\n out[7] = 0;\n out[8] = 1;\n return out;\n}\n\n/**\n * Copies the values from a mat2d into a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat2d} a the matrix to copy\n * @returns {mat3} out\n **/\nexport function fromMat2d(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = 0;\n\n out[3] = a[2];\n out[4] = a[3];\n out[5] = 0;\n\n out[6] = a[4];\n out[7] = a[5];\n out[8] = 1;\n return out;\n}\n\n/**\n* Calculates a 3x3 matrix from the given quaternion\n*\n* @param {mat3} out mat3 receiving operation result\n* @param {quat} q Quaternion to create matrix from\n*\n* @returns {mat3} out\n*/\nexport function fromQuat(out, q) {\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let yx = y * x2;\n let yy = y * y2;\n let zx = z * x2;\n let zy = z * y2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n out[0] = 1 - yy - zz;\n out[3] = yx - wz;\n out[6] = zx + wy;\n\n out[1] = yx + wz;\n out[4] = 1 - xx - zz;\n out[7] = zy - wx;\n\n out[2] = zx - wy;\n out[5] = zy + wx;\n out[8] = 1 - xx - yy;\n\n return out;\n}\n\n/**\n* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix\n*\n* @param {mat3} out mat3 receiving operation result\n* @param {mat4} a Mat4 to derive the normal matrix from\n*\n* @returns {mat3} out\n*/\nexport function normalFromMat4(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n let b00 = a00 * a11 - a01 * a10;\n let b01 = a00 * a12 - a02 * a10;\n let b02 = a00 * a13 - a03 * a10;\n let b03 = a01 * a12 - a02 * a11;\n let b04 = a01 * a13 - a03 * a11;\n let b05 = a02 * a13 - a03 * a12;\n let b06 = a20 * a31 - a21 * a30;\n let b07 = a20 * a32 - a22 * a30;\n let b08 = a20 * a33 - a23 * a30;\n let b09 = a21 * a32 - a22 * a31;\n let b10 = a21 * a33 - a23 * a31;\n let b11 = a22 * a33 - a23 * a32;\n\n // Calculate the determinant\n let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\n out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\n out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\n\n out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\n out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\n out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\n\n out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\n out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\n out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\n\n return out;\n}\n\n/**\n * Generates a 2D projection matrix with the given bounds\n *\n * @param {mat3} out mat3 frustum matrix will be written into\n * @param {number} width Width of your gl context\n * @param {number} height Height of gl context\n * @returns {mat3} out\n */\nexport function projection(out, width, height) {\n out[0] = 2 / width;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = -2 / height;\n out[5] = 0;\n out[6] = -1;\n out[7] = 1;\n out[8] = 1;\n return out;\n}\n\n/**\n * Returns a string representation of a mat3\n *\n * @param {mat3} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +\n a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +\n a[6] + ', ' + a[7] + ', ' + a[8] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat3\n *\n * @param {mat3} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))\n}\n\n/**\n * Adds two mat3's\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @returns {mat3} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n out[6] = a[6] + b[6];\n out[7] = a[7] + b[7];\n out[8] = a[8] + b[8];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @returns {mat3} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n out[4] = a[4] - b[4];\n out[5] = a[5] - b[5];\n out[6] = a[6] - b[6];\n out[7] = a[7] - b[7];\n out[8] = a[8] - b[8];\n return out;\n}\n\n\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat3} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n out[6] = a[6] * b;\n out[7] = a[7] * b;\n out[8] = a[8] * b;\n return out;\n}\n\n/**\n * Adds two mat3's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat3} out the receiving vector\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat3} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n out[4] = a[4] + (b[4] * scale);\n out[5] = a[5] + (b[5] * scale);\n out[6] = a[6] + (b[6] * scale);\n out[7] = a[7] + (b[7] * scale);\n out[8] = a[8] + (b[8] * scale);\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat3} a The first matrix.\n * @param {mat3} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] &&\n a[3] === b[3] && a[4] === b[4] && a[5] === b[5] &&\n a[6] === b[6] && a[7] === b[7] && a[8] === b[8];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat3} a The first matrix.\n * @param {mat3} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\n Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\n Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\n Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)));\n}\n\n/**\n * Alias for {@link mat3.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat3.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.\n * @module mat4\n */\n\n/**\n * Creates a new identity mat4\n *\n * @returns {mat4} a new 4x4 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(16);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n }\n out[0] = 1;\n out[5] = 1;\n out[10] = 1;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a new mat4 initialized with values from an existing matrix\n *\n * @param {mat4} a matrix to clone\n * @returns {mat4} a new 4x4 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(16);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n out[9] = a[9];\n out[10] = a[10];\n out[11] = a[11];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n}\n\n/**\n * Copy the values from one mat4 to another\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n out[9] = a[9];\n out[10] = a[10];\n out[11] = a[11];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n}\n\n/**\n * Create a new mat4 with the given values\n *\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m03 Component in column 0, row 3 position (index 3)\n * @param {Number} m10 Component in column 1, row 0 position (index 4)\n * @param {Number} m11 Component in column 1, row 1 position (index 5)\n * @param {Number} m12 Component in column 1, row 2 position (index 6)\n * @param {Number} m13 Component in column 1, row 3 position (index 7)\n * @param {Number} m20 Component in column 2, row 0 position (index 8)\n * @param {Number} m21 Component in column 2, row 1 position (index 9)\n * @param {Number} m22 Component in column 2, row 2 position (index 10)\n * @param {Number} m23 Component in column 2, row 3 position (index 11)\n * @param {Number} m30 Component in column 3, row 0 position (index 12)\n * @param {Number} m31 Component in column 3, row 1 position (index 13)\n * @param {Number} m32 Component in column 3, row 2 position (index 14)\n * @param {Number} m33 Component in column 3, row 3 position (index 15)\n * @returns {mat4} A new mat4\n */\nexport function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\n let out = new glMatrix.ARRAY_TYPE(16);\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m03;\n out[4] = m10;\n out[5] = m11;\n out[6] = m12;\n out[7] = m13;\n out[8] = m20;\n out[9] = m21;\n out[10] = m22;\n out[11] = m23;\n out[12] = m30;\n out[13] = m31;\n out[14] = m32;\n out[15] = m33;\n return out;\n}\n\n/**\n * Set the components of a mat4 to the given values\n *\n * @param {mat4} out the receiving matrix\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m03 Component in column 0, row 3 position (index 3)\n * @param {Number} m10 Component in column 1, row 0 position (index 4)\n * @param {Number} m11 Component in column 1, row 1 position (index 5)\n * @param {Number} m12 Component in column 1, row 2 position (index 6)\n * @param {Number} m13 Component in column 1, row 3 position (index 7)\n * @param {Number} m20 Component in column 2, row 0 position (index 8)\n * @param {Number} m21 Component in column 2, row 1 position (index 9)\n * @param {Number} m22 Component in column 2, row 2 position (index 10)\n * @param {Number} m23 Component in column 2, row 3 position (index 11)\n * @param {Number} m30 Component in column 3, row 0 position (index 12)\n * @param {Number} m31 Component in column 3, row 1 position (index 13)\n * @param {Number} m32 Component in column 3, row 2 position (index 14)\n * @param {Number} m33 Component in column 3, row 3 position (index 15)\n * @returns {mat4} out\n */\nexport function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m03;\n out[4] = m10;\n out[5] = m11;\n out[6] = m12;\n out[7] = m13;\n out[8] = m20;\n out[9] = m21;\n out[10] = m22;\n out[11] = m23;\n out[12] = m30;\n out[13] = m31;\n out[14] = m32;\n out[15] = m33;\n return out;\n}\n\n\n/**\n * Set a mat4 to the identity matrix\n *\n * @param {mat4} out the receiving matrix\n * @returns {mat4} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Transpose the values of a mat4\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache some values\n if (out === a) {\n let a01 = a[1], a02 = a[2], a03 = a[3];\n let a12 = a[6], a13 = a[7];\n let a23 = a[11];\n\n out[1] = a[4];\n out[2] = a[8];\n out[3] = a[12];\n out[4] = a01;\n out[6] = a[9];\n out[7] = a[13];\n out[8] = a02;\n out[9] = a12;\n out[11] = a[14];\n out[12] = a03;\n out[13] = a13;\n out[14] = a23;\n } else {\n out[0] = a[0];\n out[1] = a[4];\n out[2] = a[8];\n out[3] = a[12];\n out[4] = a[1];\n out[5] = a[5];\n out[6] = a[9];\n out[7] = a[13];\n out[8] = a[2];\n out[9] = a[6];\n out[10] = a[10];\n out[11] = a[14];\n out[12] = a[3];\n out[13] = a[7];\n out[14] = a[11];\n out[15] = a[15];\n }\n\n return out;\n}\n\n/**\n * Inverts a mat4\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function invert(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n let b00 = a00 * a11 - a01 * a10;\n let b01 = a00 * a12 - a02 * a10;\n let b02 = a00 * a13 - a03 * a10;\n let b03 = a01 * a12 - a02 * a11;\n let b04 = a01 * a13 - a03 * a11;\n let b05 = a02 * a13 - a03 * a12;\n let b06 = a20 * a31 - a21 * a30;\n let b07 = a20 * a32 - a22 * a30;\n let b08 = a20 * a33 - a23 * a30;\n let b09 = a21 * a32 - a22 * a31;\n let b10 = a21 * a33 - a23 * a31;\n let b11 = a22 * a33 - a23 * a32;\n\n // Calculate the determinant\n let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\n out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\n out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\n out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;\n out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\n out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\n out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\n out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;\n out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\n out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\n out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\n out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;\n out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;\n out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;\n out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;\n out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;\n\n return out;\n}\n\n/**\n * Calculates the adjugate of a mat4\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function adjoint(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));\n out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));\n out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));\n out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));\n out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));\n out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));\n out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));\n out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));\n out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));\n out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));\n out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));\n out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));\n out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));\n out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));\n out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));\n out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));\n return out;\n}\n\n/**\n * Calculates the determinant of a mat4\n *\n * @param {mat4} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n let b00 = a00 * a11 - a01 * a10;\n let b01 = a00 * a12 - a02 * a10;\n let b02 = a00 * a13 - a03 * a10;\n let b03 = a01 * a12 - a02 * a11;\n let b04 = a01 * a13 - a03 * a11;\n let b05 = a02 * a13 - a03 * a12;\n let b06 = a20 * a31 - a21 * a30;\n let b07 = a20 * a32 - a22 * a30;\n let b08 = a20 * a33 - a23 * a30;\n let b09 = a21 * a32 - a22 * a31;\n let b10 = a21 * a33 - a23 * a31;\n let b11 = a22 * a33 - a23 * a32;\n\n // Calculate the determinant\n return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n}\n\n/**\n * Multiplies two mat4s\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @returns {mat4} out\n */\nexport function multiply(out, a, b) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n // Cache only the current line of the second matrix\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n\n b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];\n out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n\n b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];\n out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n\n b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];\n out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n return out;\n}\n\n/**\n * Translate a mat4 by the given vector\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to translate\n * @param {vec3} v vector to translate by\n * @returns {mat4} out\n */\nexport function translate(out, a, v) {\n let x = v[0], y = v[1], z = v[2];\n let a00, a01, a02, a03;\n let a10, a11, a12, a13;\n let a20, a21, a22, a23;\n\n if (a === out) {\n out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];\n out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];\n out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];\n out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];\n } else {\n a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\n a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\n a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\n\n out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;\n out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;\n out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;\n\n out[12] = a00 * x + a10 * y + a20 * z + a[12];\n out[13] = a01 * x + a11 * y + a21 * z + a[13];\n out[14] = a02 * x + a12 * y + a22 * z + a[14];\n out[15] = a03 * x + a13 * y + a23 * z + a[15];\n }\n\n return out;\n}\n\n/**\n * Scales the mat4 by the dimensions in the given vec3 not using vectorization\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to scale\n * @param {vec3} v the vec3 to scale the matrix by\n * @returns {mat4} out\n **/\nexport function scale(out, a, v) {\n let x = v[0], y = v[1], z = v[2];\n\n out[0] = a[0] * x;\n out[1] = a[1] * x;\n out[2] = a[2] * x;\n out[3] = a[3] * x;\n out[4] = a[4] * y;\n out[5] = a[5] * y;\n out[6] = a[6] * y;\n out[7] = a[7] * y;\n out[8] = a[8] * z;\n out[9] = a[9] * z;\n out[10] = a[10] * z;\n out[11] = a[11] * z;\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n}\n\n/**\n * Rotates a mat4 by the given angle around the given axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @param {vec3} axis the axis to rotate around\n * @returns {mat4} out\n */\nexport function rotate(out, a, rad, axis) {\n let x = axis[0], y = axis[1], z = axis[2];\n let len = Math.sqrt(x * x + y * y + z * z);\n let s, c, t;\n let a00, a01, a02, a03;\n let a10, a11, a12, a13;\n let a20, a21, a22, a23;\n let b00, b01, b02;\n let b10, b11, b12;\n let b20, b21, b22;\n\n if (len < glMatrix.EPSILON) { return null; }\n\n len = 1 / len;\n x *= len;\n y *= len;\n z *= len;\n\n s = Math.sin(rad);\n c = Math.cos(rad);\n t = 1 - c;\n\n a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\n a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\n a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\n\n // Construct the elements of the rotation matrix\n b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;\n b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;\n b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;\n\n // Perform rotation-specific matrix multiplication\n out[0] = a00 * b00 + a10 * b01 + a20 * b02;\n out[1] = a01 * b00 + a11 * b01 + a21 * b02;\n out[2] = a02 * b00 + a12 * b01 + a22 * b02;\n out[3] = a03 * b00 + a13 * b01 + a23 * b02;\n out[4] = a00 * b10 + a10 * b11 + a20 * b12;\n out[5] = a01 * b10 + a11 * b11 + a21 * b12;\n out[6] = a02 * b10 + a12 * b11 + a22 * b12;\n out[7] = a03 * b10 + a13 * b11 + a23 * b12;\n out[8] = a00 * b20 + a10 * b21 + a20 * b22;\n out[9] = a01 * b20 + a11 * b21 + a21 * b22;\n out[10] = a02 * b20 + a12 * b21 + a22 * b22;\n out[11] = a03 * b20 + a13 * b21 + a23 * b22;\n\n if (a !== out) { // If the source and destination differ, copy the unchanged last row\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n return out;\n}\n\n/**\n * Rotates a matrix by the given angle around the X axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function rotateX(out, a, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n let a10 = a[4];\n let a11 = a[5];\n let a12 = a[6];\n let a13 = a[7];\n let a20 = a[8];\n let a21 = a[9];\n let a22 = a[10];\n let a23 = a[11];\n\n if (a !== out) { // If the source and destination differ, copy the unchanged rows\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n\n // Perform axis-specific matrix multiplication\n out[4] = a10 * c + a20 * s;\n out[5] = a11 * c + a21 * s;\n out[6] = a12 * c + a22 * s;\n out[7] = a13 * c + a23 * s;\n out[8] = a20 * c - a10 * s;\n out[9] = a21 * c - a11 * s;\n out[10] = a22 * c - a12 * s;\n out[11] = a23 * c - a13 * s;\n return out;\n}\n\n/**\n * Rotates a matrix by the given angle around the Y axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function rotateY(out, a, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n let a00 = a[0];\n let a01 = a[1];\n let a02 = a[2];\n let a03 = a[3];\n let a20 = a[8];\n let a21 = a[9];\n let a22 = a[10];\n let a23 = a[11];\n\n if (a !== out) { // If the source and destination differ, copy the unchanged rows\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n\n // Perform axis-specific matrix multiplication\n out[0] = a00 * c - a20 * s;\n out[1] = a01 * c - a21 * s;\n out[2] = a02 * c - a22 * s;\n out[3] = a03 * c - a23 * s;\n out[8] = a00 * s + a20 * c;\n out[9] = a01 * s + a21 * c;\n out[10] = a02 * s + a22 * c;\n out[11] = a03 * s + a23 * c;\n return out;\n}\n\n/**\n * Rotates a matrix by the given angle around the Z axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function rotateZ(out, a, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n let a00 = a[0];\n let a01 = a[1];\n let a02 = a[2];\n let a03 = a[3];\n let a10 = a[4];\n let a11 = a[5];\n let a12 = a[6];\n let a13 = a[7];\n\n if (a !== out) { // If the source and destination differ, copy the unchanged last row\n out[8] = a[8];\n out[9] = a[9];\n out[10] = a[10];\n out[11] = a[11];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n\n // Perform axis-specific matrix multiplication\n out[0] = a00 * c + a10 * s;\n out[1] = a01 * c + a11 * s;\n out[2] = a02 * c + a12 * s;\n out[3] = a03 * c + a13 * s;\n out[4] = a10 * c - a00 * s;\n out[5] = a11 * c - a01 * s;\n out[6] = a12 * c - a02 * s;\n out[7] = a13 * c - a03 * s;\n return out;\n}\n\n/**\n * Creates a matrix from a vector translation\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, dest, vec);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {vec3} v Translation vector\n * @returns {mat4} out\n */\nexport function fromTranslation(out, v) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.scale(dest, dest, vec);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {vec3} v Scaling vector\n * @returns {mat4} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = v[1];\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = v[2];\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle around a given axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotate(dest, dest, rad, axis);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @param {vec3} axis the axis to rotate around\n * @returns {mat4} out\n */\nexport function fromRotation(out, rad, axis) {\n let x = axis[0], y = axis[1], z = axis[2];\n let len = Math.sqrt(x * x + y * y + z * z);\n let s, c, t;\n\n if (len < glMatrix.EPSILON) { return null; }\n\n len = 1 / len;\n x *= len;\n y *= len;\n z *= len;\n\n s = Math.sin(rad);\n c = Math.cos(rad);\n t = 1 - c;\n\n // Perform rotation-specific matrix multiplication\n out[0] = x * x * t + c;\n out[1] = y * x * t + z * s;\n out[2] = z * x * t - y * s;\n out[3] = 0;\n out[4] = x * y * t - z * s;\n out[5] = y * y * t + c;\n out[6] = z * y * t + x * s;\n out[7] = 0;\n out[8] = x * z * t + y * s;\n out[9] = y * z * t - x * s;\n out[10] = z * z * t + c;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from the given angle around the X axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotateX(dest, dest, rad);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function fromXRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n\n // Perform axis-specific matrix multiplication\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = c;\n out[6] = s;\n out[7] = 0;\n out[8] = 0;\n out[9] = -s;\n out[10] = c;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from the given angle around the Y axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotateY(dest, dest, rad);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function fromYRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n\n // Perform axis-specific matrix multiplication\n out[0] = c;\n out[1] = 0;\n out[2] = -s;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = s;\n out[9] = 0;\n out[10] = c;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from the given angle around the Z axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotateZ(dest, dest, rad);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function fromZRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n\n // Perform axis-specific matrix multiplication\n out[0] = c;\n out[1] = s;\n out[2] = 0;\n out[3] = 0;\n out[4] = -s;\n out[5] = c;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a quaternion rotation and vector translation\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, vec);\n * let quatMat = mat4.create();\n * quat4.toMat4(quat, quatMat);\n * mat4.multiply(dest, quatMat);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat4} q Rotation quaternion\n * @param {vec3} v Translation vector\n * @returns {mat4} out\n */\nexport function fromRotationTranslation(out, q, v) {\n // Quaternion math\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let xy = x * y2;\n let xz = x * z2;\n let yy = y * y2;\n let yz = y * z2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n out[0] = 1 - (yy + zz);\n out[1] = xy + wz;\n out[2] = xz - wy;\n out[3] = 0;\n out[4] = xy - wz;\n out[5] = 1 - (xx + zz);\n out[6] = yz + wx;\n out[7] = 0;\n out[8] = xz + wy;\n out[9] = yz - wx;\n out[10] = 1 - (xx + yy);\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Creates a new mat4 from a dual quat.\n *\n * @param {mat4} out Matrix\n * @param {quat2} a Dual Quaternion\n * @returns {mat4} mat4 receiving operation result\n */\nexport function fromQuat2(out, a) {\n let translation = new glMatrix.ARRAY_TYPE(3);\n let bx = -a[0], by = -a[1], bz = -a[2], bw = a[3],\n ax = a[4], ay = a[5], az = a[6], aw = a[7];\n\n let magnitude = bx * bx + by * by + bz * bz + bw * bw;\n //Only scale if it makes sense\n if (magnitude > 0) {\n translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;\n translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;\n translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;\n } else {\n translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;\n translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;\n translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;\n }\n fromRotationTranslation(out, a, translation);\n return out;\n}\n\n/**\n * Returns the translation vector component of a transformation\n * matrix. If a matrix is built with fromRotationTranslation,\n * the returned vector will be the same as the translation vector\n * originally supplied.\n * @param {vec3} out Vector to receive translation component\n * @param {mat4} mat Matrix to be decomposed (input)\n * @return {vec3} out\n */\nexport function getTranslation(out, mat) {\n out[0] = mat[12];\n out[1] = mat[13];\n out[2] = mat[14];\n\n return out;\n}\n\n/**\n * Returns the scaling factor component of a transformation\n * matrix. If a matrix is built with fromRotationTranslationScale\n * with a normalized Quaternion paramter, the returned vector will be\n * the same as the scaling vector\n * originally supplied.\n * @param {vec3} out Vector to receive scaling factor component\n * @param {mat4} mat Matrix to be decomposed (input)\n * @return {vec3} out\n */\nexport function getScaling(out, mat) {\n let m11 = mat[0];\n let m12 = mat[1];\n let m13 = mat[2];\n let m21 = mat[4];\n let m22 = mat[5];\n let m23 = mat[6];\n let m31 = mat[8];\n let m32 = mat[9];\n let m33 = mat[10];\n\n out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);\n out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);\n out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);\n\n return out;\n}\n\n/**\n * Returns a quaternion representing the rotational component\n * of a transformation matrix. If a matrix is built with\n * fromRotationTranslation, the returned quaternion will be the\n * same as the quaternion originally supplied.\n * @param {quat} out Quaternion to receive the rotation component\n * @param {mat4} mat Matrix to be decomposed (input)\n * @return {quat} out\n */\nexport function getRotation(out, mat) {\n // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\n let trace = mat[0] + mat[5] + mat[10];\n let S = 0;\n\n if (trace > 0) {\n S = Math.sqrt(trace + 1.0) * 2;\n out[3] = 0.25 * S;\n out[0] = (mat[6] - mat[9]) / S;\n out[1] = (mat[8] - mat[2]) / S;\n out[2] = (mat[1] - mat[4]) / S;\n } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) {\n S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;\n out[3] = (mat[6] - mat[9]) / S;\n out[0] = 0.25 * S;\n out[1] = (mat[1] + mat[4]) / S;\n out[2] = (mat[8] + mat[2]) / S;\n } else if (mat[5] > mat[10]) {\n S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;\n out[3] = (mat[8] - mat[2]) / S;\n out[0] = (mat[1] + mat[4]) / S;\n out[1] = 0.25 * S;\n out[2] = (mat[6] + mat[9]) / S;\n } else {\n S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;\n out[3] = (mat[1] - mat[4]) / S;\n out[0] = (mat[8] + mat[2]) / S;\n out[1] = (mat[6] + mat[9]) / S;\n out[2] = 0.25 * S;\n }\n\n return out;\n}\n\n/**\n * Creates a matrix from a quaternion rotation, vector translation and vector scale\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, vec);\n * let quatMat = mat4.create();\n * quat4.toMat4(quat, quatMat);\n * mat4.multiply(dest, quatMat);\n * mat4.scale(dest, scale)\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat4} q Rotation quaternion\n * @param {vec3} v Translation vector\n * @param {vec3} s Scaling vector\n * @returns {mat4} out\n */\nexport function fromRotationTranslationScale(out, q, v, s) {\n // Quaternion math\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let xy = x * y2;\n let xz = x * z2;\n let yy = y * y2;\n let yz = y * z2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n let sx = s[0];\n let sy = s[1];\n let sz = s[2];\n\n out[0] = (1 - (yy + zz)) * sx;\n out[1] = (xy + wz) * sx;\n out[2] = (xz - wy) * sx;\n out[3] = 0;\n out[4] = (xy - wz) * sy;\n out[5] = (1 - (xx + zz)) * sy;\n out[6] = (yz + wx) * sy;\n out[7] = 0;\n out[8] = (xz + wy) * sz;\n out[9] = (yz - wx) * sz;\n out[10] = (1 - (xx + yy)) * sz;\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, vec);\n * mat4.translate(dest, origin);\n * let quatMat = mat4.create();\n * quat4.toMat4(quat, quatMat);\n * mat4.multiply(dest, quatMat);\n * mat4.scale(dest, scale)\n * mat4.translate(dest, negativeOrigin);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat4} q Rotation quaternion\n * @param {vec3} v Translation vector\n * @param {vec3} s Scaling vector\n * @param {vec3} o The origin vector around which to scale and rotate\n * @returns {mat4} out\n */\nexport function fromRotationTranslationScaleOrigin(out, q, v, s, o) {\n // Quaternion math\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let xy = x * y2;\n let xz = x * z2;\n let yy = y * y2;\n let yz = y * z2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n let sx = s[0];\n let sy = s[1];\n let sz = s[2];\n\n let ox = o[0];\n let oy = o[1];\n let oz = o[2];\n\n let out0 = (1 - (yy + zz)) * sx;\n let out1 = (xy + wz) * sx;\n let out2 = (xz - wy) * sx;\n let out4 = (xy - wz) * sy;\n let out5 = (1 - (xx + zz)) * sy;\n let out6 = (yz + wx) * sy;\n let out8 = (xz + wy) * sz;\n let out9 = (yz - wx) * sz;\n let out10 = (1 - (xx + yy)) * sz;\n\n out[0] = out0;\n out[1] = out1;\n out[2] = out2;\n out[3] = 0;\n out[4] = out4;\n out[5] = out5;\n out[6] = out6;\n out[7] = 0;\n out[8] = out8;\n out[9] = out9;\n out[10] = out10;\n out[11] = 0;\n out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);\n out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);\n out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Calculates a 4x4 matrix from the given quaternion\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat} q Quaternion to create matrix from\n *\n * @returns {mat4} out\n */\nexport function fromQuat(out, q) {\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let yx = y * x2;\n let yy = y * y2;\n let zx = z * x2;\n let zy = z * y2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n out[0] = 1 - yy - zz;\n out[1] = yx + wz;\n out[2] = zx - wy;\n out[3] = 0;\n\n out[4] = yx - wz;\n out[5] = 1 - xx - zz;\n out[6] = zy + wx;\n out[7] = 0;\n\n out[8] = zx + wy;\n out[9] = zy - wx;\n out[10] = 1 - xx - yy;\n out[11] = 0;\n\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Generates a frustum matrix with the given bounds\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {Number} left Left bound of the frustum\n * @param {Number} right Right bound of the frustum\n * @param {Number} bottom Bottom bound of the frustum\n * @param {Number} top Top bound of the frustum\n * @param {Number} near Near bound of the frustum\n * @param {Number} far Far bound of the frustum\n * @returns {mat4} out\n */\nexport function frustum(out, left, right, bottom, top, near, far) {\n let rl = 1 / (right - left);\n let tb = 1 / (top - bottom);\n let nf = 1 / (near - far);\n out[0] = (near * 2) * rl;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = (near * 2) * tb;\n out[6] = 0;\n out[7] = 0;\n out[8] = (right + left) * rl;\n out[9] = (top + bottom) * tb;\n out[10] = (far + near) * nf;\n out[11] = -1;\n out[12] = 0;\n out[13] = 0;\n out[14] = (far * near * 2) * nf;\n out[15] = 0;\n return out;\n}\n\n/**\n * Generates a perspective projection matrix with the given bounds.\n * Passing null/undefined/no value for far will generate infinite projection matrix.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {number} fovy Vertical field of view in radians\n * @param {number} aspect Aspect ratio. typically viewport width/height\n * @param {number} near Near bound of the frustum\n * @param {number} far Far bound of the frustum, can be null or Infinity\n * @returns {mat4} out\n */\nexport function perspective(out, fovy, aspect, near, far) {\n let f = 1.0 / Math.tan(fovy / 2), nf;\n out[0] = f / aspect;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = f;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[11] = -1;\n out[12] = 0;\n out[13] = 0;\n out[15] = 0;\n if (far != null && far !== Infinity) {\n nf = 1 / (near - far);\n out[10] = (far + near) * nf;\n out[14] = (2 * far * near) * nf;\n } else {\n out[10] = -1;\n out[14] = -2 * near;\n }\n return out;\n}\n\n/**\n * Generates a perspective projection matrix with the given field of view.\n * This is primarily useful for generating projection matrices to be used\n * with the still experiemental WebVR API.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees\n * @param {number} near Near bound of the frustum\n * @param {number} far Far bound of the frustum\n * @returns {mat4} out\n */\nexport function perspectiveFromFieldOfView(out, fov, near, far) {\n let upTan = Math.tan(fov.upDegrees * Math.PI/180.0);\n let downTan = Math.tan(fov.downDegrees * Math.PI/180.0);\n let leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0);\n let rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0);\n let xScale = 2.0 / (leftTan + rightTan);\n let yScale = 2.0 / (upTan + downTan);\n\n out[0] = xScale;\n out[1] = 0.0;\n out[2] = 0.0;\n out[3] = 0.0;\n out[4] = 0.0;\n out[5] = yScale;\n out[6] = 0.0;\n out[7] = 0.0;\n out[8] = -((leftTan - rightTan) * xScale * 0.5);\n out[9] = ((upTan - downTan) * yScale * 0.5);\n out[10] = far / (near - far);\n out[11] = -1.0;\n out[12] = 0.0;\n out[13] = 0.0;\n out[14] = (far * near) / (near - far);\n out[15] = 0.0;\n return out;\n}\n\n/**\n * Generates a orthogonal projection matrix with the given bounds\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {number} left Left bound of the frustum\n * @param {number} right Right bound of the frustum\n * @param {number} bottom Bottom bound of the frustum\n * @param {number} top Top bound of the frustum\n * @param {number} near Near bound of the frustum\n * @param {number} far Far bound of the frustum\n * @returns {mat4} out\n */\nexport function ortho(out, left, right, bottom, top, near, far) {\n let lr = 1 / (left - right);\n let bt = 1 / (bottom - top);\n let nf = 1 / (near - far);\n out[0] = -2 * lr;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = -2 * bt;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 2 * nf;\n out[11] = 0;\n out[12] = (left + right) * lr;\n out[13] = (top + bottom) * bt;\n out[14] = (far + near) * nf;\n out[15] = 1;\n return out;\n}\n\n/**\n * Generates a look-at matrix with the given eye position, focal point, and up axis.\n * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {vec3} eye Position of the viewer\n * @param {vec3} center Point the viewer is looking at\n * @param {vec3} up vec3 pointing up\n * @returns {mat4} out\n */\nexport function lookAt(out, eye, center, up) {\n let x0, x1, x2, y0, y1, y2, z0, z1, z2, len;\n let eyex = eye[0];\n let eyey = eye[1];\n let eyez = eye[2];\n let upx = up[0];\n let upy = up[1];\n let upz = up[2];\n let centerx = center[0];\n let centery = center[1];\n let centerz = center[2];\n\n if (Math.abs(eyex - centerx) < glMatrix.EPSILON &&\n Math.abs(eyey - centery) < glMatrix.EPSILON &&\n Math.abs(eyez - centerz) < glMatrix.EPSILON) {\n return identity(out);\n }\n\n z0 = eyex - centerx;\n z1 = eyey - centery;\n z2 = eyez - centerz;\n\n len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);\n z0 *= len;\n z1 *= len;\n z2 *= len;\n\n x0 = upy * z2 - upz * z1;\n x1 = upz * z0 - upx * z2;\n x2 = upx * z1 - upy * z0;\n len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);\n if (!len) {\n x0 = 0;\n x1 = 0;\n x2 = 0;\n } else {\n len = 1 / len;\n x0 *= len;\n x1 *= len;\n x2 *= len;\n }\n\n y0 = z1 * x2 - z2 * x1;\n y1 = z2 * x0 - z0 * x2;\n y2 = z0 * x1 - z1 * x0;\n\n len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);\n if (!len) {\n y0 = 0;\n y1 = 0;\n y2 = 0;\n } else {\n len = 1 / len;\n y0 *= len;\n y1 *= len;\n y2 *= len;\n }\n\n out[0] = x0;\n out[1] = y0;\n out[2] = z0;\n out[3] = 0;\n out[4] = x1;\n out[5] = y1;\n out[6] = z1;\n out[7] = 0;\n out[8] = x2;\n out[9] = y2;\n out[10] = z2;\n out[11] = 0;\n out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);\n out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);\n out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Generates a matrix that makes something look at something else.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {vec3} eye Position of the viewer\n * @param {vec3} center Point the viewer is looking at\n * @param {vec3} up vec3 pointing up\n * @returns {mat4} out\n */\nexport function targetTo(out, eye, target, up) {\n let eyex = eye[0],\n eyey = eye[1],\n eyez = eye[2],\n upx = up[0],\n upy = up[1],\n upz = up[2];\n\n let z0 = eyex - target[0],\n z1 = eyey - target[1],\n z2 = eyez - target[2];\n\n let len = z0*z0 + z1*z1 + z2*z2;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n z0 *= len;\n z1 *= len;\n z2 *= len;\n }\n\n let x0 = upy * z2 - upz * z1,\n x1 = upz * z0 - upx * z2,\n x2 = upx * z1 - upy * z0;\n\n len = x0*x0 + x1*x1 + x2*x2;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n x0 *= len;\n x1 *= len;\n x2 *= len;\n }\n\n out[0] = x0;\n out[1] = x1;\n out[2] = x2;\n out[3] = 0;\n out[4] = z1 * x2 - z2 * x1;\n out[5] = z2 * x0 - z0 * x2;\n out[6] = z0 * x1 - z1 * x0;\n out[7] = 0;\n out[8] = z0;\n out[9] = z1;\n out[10] = z2;\n out[11] = 0;\n out[12] = eyex;\n out[13] = eyey;\n out[14] = eyez;\n out[15] = 1;\n return out;\n};\n\n/**\n * Returns a string representation of a mat4\n *\n * @param {mat4} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +\n a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +\n a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +\n a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat4\n *\n * @param {mat4} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))\n}\n\n/**\n * Adds two mat4's\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @returns {mat4} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n out[6] = a[6] + b[6];\n out[7] = a[7] + b[7];\n out[8] = a[8] + b[8];\n out[9] = a[9] + b[9];\n out[10] = a[10] + b[10];\n out[11] = a[11] + b[11];\n out[12] = a[12] + b[12];\n out[13] = a[13] + b[13];\n out[14] = a[14] + b[14];\n out[15] = a[15] + b[15];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @returns {mat4} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n out[4] = a[4] - b[4];\n out[5] = a[5] - b[5];\n out[6] = a[6] - b[6];\n out[7] = a[7] - b[7];\n out[8] = a[8] - b[8];\n out[9] = a[9] - b[9];\n out[10] = a[10] - b[10];\n out[11] = a[11] - b[11];\n out[12] = a[12] - b[12];\n out[13] = a[13] - b[13];\n out[14] = a[14] - b[14];\n out[15] = a[15] - b[15];\n return out;\n}\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat4} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n out[6] = a[6] * b;\n out[7] = a[7] * b;\n out[8] = a[8] * b;\n out[9] = a[9] * b;\n out[10] = a[10] * b;\n out[11] = a[11] * b;\n out[12] = a[12] * b;\n out[13] = a[13] * b;\n out[14] = a[14] * b;\n out[15] = a[15] * b;\n return out;\n}\n\n/**\n * Adds two mat4's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat4} out the receiving vector\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat4} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n out[4] = a[4] + (b[4] * scale);\n out[5] = a[5] + (b[5] * scale);\n out[6] = a[6] + (b[6] * scale);\n out[7] = a[7] + (b[7] * scale);\n out[8] = a[8] + (b[8] * scale);\n out[9] = a[9] + (b[9] * scale);\n out[10] = a[10] + (b[10] * scale);\n out[11] = a[11] + (b[11] * scale);\n out[12] = a[12] + (b[12] * scale);\n out[13] = a[13] + (b[13] * scale);\n out[14] = a[14] + (b[14] * scale);\n out[15] = a[15] + (b[15] * scale);\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat4} a The first matrix.\n * @param {mat4} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&\n a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] &&\n a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] &&\n a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat4} a The first matrix.\n * @param {mat4} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7];\n let a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11];\n let a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];\n\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n let b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7];\n let b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11];\n let b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];\n\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\n Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\n Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\n Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&\n Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&\n Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&\n Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&\n Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&\n Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&\n Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&\n Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15)));\n}\n\n/**\n * Alias for {@link mat4.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat4.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\"\nimport * as mat3 from \"./mat3.js\"\nimport * as vec3 from \"./vec3.js\"\nimport * as vec4 from \"./vec4.js\"\n\n/**\n * Quaternion\n * @module quat\n */\n\n/**\n * Creates a new identity quat\n *\n * @returns {quat} a new quaternion\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(4);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n }\n out[3] = 1;\n return out;\n}\n\n/**\n * Set a quat to the identity quaternion\n *\n * @param {quat} out the receiving quaternion\n * @returns {quat} out\n */\nexport function identity(out) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n return out;\n}\n\n/**\n * Sets a quat from the given angle and rotation axis,\n * then returns it.\n *\n * @param {quat} out the receiving quaternion\n * @param {vec3} axis the axis around which to rotate\n * @param {Number} rad the angle in radians\n * @returns {quat} out\n **/\nexport function setAxisAngle(out, axis, rad) {\n rad = rad * 0.5;\n let s = Math.sin(rad);\n out[0] = s * axis[0];\n out[1] = s * axis[1];\n out[2] = s * axis[2];\n out[3] = Math.cos(rad);\n return out;\n}\n\n/**\n * Gets the rotation axis and angle for a given\n * quaternion. If a quaternion is created with\n * setAxisAngle, this method will return the same\n * values as providied in the original parameter list\n * OR functionally equivalent values.\n * Example: The quaternion formed by axis [0, 0, 1] and\n * angle -90 is the same as the quaternion formed by\n * [0, 0, 1] and 270. This method favors the latter.\n * @param {vec3} out_axis Vector receiving the axis of rotation\n * @param {quat} q Quaternion to be decomposed\n * @return {Number} Angle, in radians, of the rotation\n */\nexport function getAxisAngle(out_axis, q) {\n let rad = Math.acos(q[3]) * 2.0;\n let s = Math.sin(rad / 2.0);\n if (s > glMatrix.EPSILON) {\n out_axis[0] = q[0] / s;\n out_axis[1] = q[1] / s;\n out_axis[2] = q[2] / s;\n } else {\n // If s is zero, return any axis (no rotation - axis does not matter)\n out_axis[0] = 1;\n out_axis[1] = 0;\n out_axis[2] = 0;\n }\n return rad;\n}\n\n/**\n * Multiplies two quat's\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @returns {quat} out\n */\nexport function multiply(out, a, b) {\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bx = b[0], by = b[1], bz = b[2], bw = b[3];\n\n out[0] = ax * bw + aw * bx + ay * bz - az * by;\n out[1] = ay * bw + aw * by + az * bx - ax * bz;\n out[2] = az * bw + aw * bz + ax * by - ay * bx;\n out[3] = aw * bw - ax * bx - ay * by - az * bz;\n return out;\n}\n\n/**\n * Rotates a quaternion by the given angle about the X axis\n *\n * @param {quat} out quat receiving operation result\n * @param {quat} a quat to rotate\n * @param {number} rad angle (in radians) to rotate\n * @returns {quat} out\n */\nexport function rotateX(out, a, rad) {\n rad *= 0.5;\n\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bx = Math.sin(rad), bw = Math.cos(rad);\n\n out[0] = ax * bw + aw * bx;\n out[1] = ay * bw + az * bx;\n out[2] = az * bw - ay * bx;\n out[3] = aw * bw - ax * bx;\n return out;\n}\n\n/**\n * Rotates a quaternion by the given angle about the Y axis\n *\n * @param {quat} out quat receiving operation result\n * @param {quat} a quat to rotate\n * @param {number} rad angle (in radians) to rotate\n * @returns {quat} out\n */\nexport function rotateY(out, a, rad) {\n rad *= 0.5;\n\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let by = Math.sin(rad), bw = Math.cos(rad);\n\n out[0] = ax * bw - az * by;\n out[1] = ay * bw + aw * by;\n out[2] = az * bw + ax * by;\n out[3] = aw * bw - ay * by;\n return out;\n}\n\n/**\n * Rotates a quaternion by the given angle about the Z axis\n *\n * @param {quat} out quat receiving operation result\n * @param {quat} a quat to rotate\n * @param {number} rad angle (in radians) to rotate\n * @returns {quat} out\n */\nexport function rotateZ(out, a, rad) {\n rad *= 0.5;\n\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bz = Math.sin(rad), bw = Math.cos(rad);\n\n out[0] = ax * bw + ay * bz;\n out[1] = ay * bw - ax * bz;\n out[2] = az * bw + aw * bz;\n out[3] = aw * bw - az * bz;\n return out;\n}\n\n/**\n * Calculates the W component of a quat from the X, Y, and Z components.\n * Assumes that quaternion is 1 unit in length.\n * Any existing W component will be ignored.\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quat to calculate W component of\n * @returns {quat} out\n */\nexport function calculateW(out, a) {\n let x = a[0], y = a[1], z = a[2];\n\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));\n return out;\n}\n\n/**\n * Performs a spherical linear interpolation between two quat\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat} out\n */\nexport function slerp(out, a, b, t) {\n // benchmarks:\n // http://jsperf.com/quaternion-slerp-implementations\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bx = b[0], by = b[1], bz = b[2], bw = b[3];\n\n let omega, cosom, sinom, scale0, scale1;\n\n // calc cosine\n cosom = ax * bx + ay * by + az * bz + aw * bw;\n // adjust signs (if necessary)\n if ( cosom < 0.0 ) {\n cosom = -cosom;\n bx = - bx;\n by = - by;\n bz = - bz;\n bw = - bw;\n }\n // calculate coefficients\n if ( (1.0 - cosom) > glMatrix.EPSILON ) {\n // standard case (slerp)\n omega = Math.acos(cosom);\n sinom = Math.sin(omega);\n scale0 = Math.sin((1.0 - t) * omega) / sinom;\n scale1 = Math.sin(t * omega) / sinom;\n } else {\n // \"from\" and \"to\" quaternions are very close\n // ... so we can do a linear interpolation\n scale0 = 1.0 - t;\n scale1 = t;\n }\n // calculate final values\n out[0] = scale0 * ax + scale1 * bx;\n out[1] = scale0 * ay + scale1 * by;\n out[2] = scale0 * az + scale1 * bz;\n out[3] = scale0 * aw + scale1 * bw;\n\n return out;\n}\n\n/**\n * Generates a random quaternion\n *\n * @param {quat} out the receiving quaternion\n * @returns {quat} out\n */\nexport function random(out) {\n // Implementation of http://planning.cs.uiuc.edu/node198.html\n // TODO: Calling random 3 times is probably not the fastest solution\n let u1 = glMatrix.RANDOM();\n let u2 = glMatrix.RANDOM();\n let u3 = glMatrix.RANDOM();\n\n let sqrt1MinusU1 = Math.sqrt(1 - u1);\n let sqrtU1 = Math.sqrt(u1);\n\n out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);\n out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);\n out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);\n out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);\n return out;\n}\n\n/**\n * Calculates the inverse of a quat\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quat to calculate inverse of\n * @returns {quat} out\n */\nexport function invert(out, a) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let dot = a0*a0 + a1*a1 + a2*a2 + a3*a3;\n let invDot = dot ? 1.0/dot : 0;\n\n // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0\n\n out[0] = -a0*invDot;\n out[1] = -a1*invDot;\n out[2] = -a2*invDot;\n out[3] = a3*invDot;\n return out;\n}\n\n/**\n * Calculates the conjugate of a quat\n * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quat to calculate conjugate of\n * @returns {quat} out\n */\nexport function conjugate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Creates a quaternion from the given 3x3 rotation matrix.\n *\n * NOTE: The resultant quaternion is not normalized, so you should be sure\n * to renormalize the quaternion yourself where necessary.\n *\n * @param {quat} out the receiving quaternion\n * @param {mat3} m rotation matrix\n * @returns {quat} out\n * @function\n */\nexport function fromMat3(out, m) {\n // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes\n // article \"Quaternion Calculus and Fast Animation\".\n let fTrace = m[0] + m[4] + m[8];\n let fRoot;\n\n if ( fTrace > 0.0 ) {\n // |w| > 1/2, may as well choose w > 1/2\n fRoot = Math.sqrt(fTrace + 1.0); // 2w\n out[3] = 0.5 * fRoot;\n fRoot = 0.5/fRoot; // 1/(4w)\n out[0] = (m[5]-m[7])*fRoot;\n out[1] = (m[6]-m[2])*fRoot;\n out[2] = (m[1]-m[3])*fRoot;\n } else {\n // |w| <= 1/2\n let i = 0;\n if ( m[4] > m[0] )\n i = 1;\n if ( m[8] > m[i*3+i] )\n i = 2;\n let j = (i+1)%3;\n let k = (i+2)%3;\n\n fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);\n out[i] = 0.5 * fRoot;\n fRoot = 0.5 / fRoot;\n out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;\n out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;\n out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;\n }\n\n return out;\n}\n\n/**\n * Creates a quaternion from the given euler angle x, y, z.\n *\n * @param {quat} out the receiving quaternion\n * @param {x} Angle to rotate around X axis in degrees.\n * @param {y} Angle to rotate around Y axis in degrees.\n * @param {z} Angle to rotate around Z axis in degrees.\n * @returns {quat} out\n * @function\n */\nexport function fromEuler(out, x, y, z) {\n let halfToRad = 0.5 * Math.PI / 180.0;\n x *= halfToRad;\n y *= halfToRad;\n z *= halfToRad;\n\n let sx = Math.sin(x);\n let cx = Math.cos(x);\n let sy = Math.sin(y);\n let cy = Math.cos(y);\n let sz = Math.sin(z);\n let cz = Math.cos(z);\n\n out[0] = sx * cy * cz - cx * sy * sz;\n out[1] = cx * sy * cz + sx * cy * sz;\n out[2] = cx * cy * sz - sx * sy * cz;\n out[3] = cx * cy * cz + sx * sy * sz;\n\n return out;\n}\n\n/**\n * Returns a string representation of a quatenion\n *\n * @param {quat} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\n}\n\n/**\n * Creates a new quat initialized with values from an existing quaternion\n *\n * @param {quat} a quaternion to clone\n * @returns {quat} a new quaternion\n * @function\n */\nexport const clone = vec4.clone;\n\n/**\n * Creates a new quat initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {quat} a new quaternion\n * @function\n */\nexport const fromValues = vec4.fromValues;\n\n/**\n * Copy the values from one quat to another\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the source quaternion\n * @returns {quat} out\n * @function\n */\nexport const copy = vec4.copy;\n\n/**\n * Set the components of a quat to the given values\n *\n * @param {quat} out the receiving quaternion\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {quat} out\n * @function\n */\nexport const set = vec4.set;\n\n/**\n * Adds two quat's\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @returns {quat} out\n * @function\n */\nexport const add = vec4.add;\n\n/**\n * Alias for {@link quat.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Scales a quat by a scalar number\n *\n * @param {quat} out the receiving vector\n * @param {quat} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {quat} out\n * @function\n */\nexport const scale = vec4.scale;\n\n/**\n * Calculates the dot product of two quat's\n *\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @returns {Number} dot product of a and b\n * @function\n */\nexport const dot = vec4.dot;\n\n/**\n * Performs a linear interpolation between two quat's\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat} out\n * @function\n */\nexport const lerp = vec4.lerp;\n\n/**\n * Calculates the length of a quat\n *\n * @param {quat} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport const length = vec4.length;\n\n/**\n * Alias for {@link quat.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Calculates the squared length of a quat\n *\n * @param {quat} a vector to calculate squared length of\n * @returns {Number} squared length of a\n * @function\n */\nexport const squaredLength = vec4.squaredLength;\n\n/**\n * Alias for {@link quat.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Normalize a quat\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quaternion to normalize\n * @returns {quat} out\n * @function\n */\nexport const normalize = vec4.normalize;\n\n/**\n * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)\n *\n * @param {quat} a The first quaternion.\n * @param {quat} b The second quaternion.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport const exactEquals = vec4.exactEquals;\n\n/**\n * Returns whether or not the quaternions have approximately the same elements in the same position.\n *\n * @param {quat} a The first vector.\n * @param {quat} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport const equals = vec4.equals;\n\n/**\n * Sets a quaternion to represent the shortest rotation from one\n * vector to another.\n *\n * Both vectors are assumed to be unit length.\n *\n * @param {quat} out the receiving quaternion.\n * @param {vec3} a the initial vector\n * @param {vec3} b the destination vector\n * @returns {quat} out\n */\nexport const rotationTo = (function() {\n let tmpvec3 = vec3.create();\n let xUnitVec3 = vec3.fromValues(1,0,0);\n let yUnitVec3 = vec3.fromValues(0,1,0);\n\n return function(out, a, b) {\n let dot = vec3.dot(a, b);\n if (dot < -0.999999) {\n vec3.cross(tmpvec3, xUnitVec3, a);\n if (vec3.len(tmpvec3) < 0.000001)\n vec3.cross(tmpvec3, yUnitVec3, a);\n vec3.normalize(tmpvec3, tmpvec3);\n setAxisAngle(out, tmpvec3, Math.PI);\n return out;\n } else if (dot > 0.999999) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n return out;\n } else {\n vec3.cross(tmpvec3, a, b);\n out[0] = tmpvec3[0];\n out[1] = tmpvec3[1];\n out[2] = tmpvec3[2];\n out[3] = 1 + dot;\n return normalize(out, out);\n }\n };\n})();\n\n/**\n * Performs a spherical linear interpolation with two control points\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @param {quat} c the third operand\n * @param {quat} d the fourth operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat} out\n */\nexport const sqlerp = (function () {\n let temp1 = create();\n let temp2 = create();\n\n return function (out, a, b, c, d, t) {\n slerp(temp1, a, d, t);\n slerp(temp2, b, c, t);\n slerp(out, temp1, temp2, 2 * t * (1 - t));\n\n return out;\n };\n}());\n\n/**\n * Sets the specified quaternion with values corresponding to the given\n * axes. Each axis is a vec3 and is expected to be unit length and\n * perpendicular to all other specified axes.\n *\n * @param {vec3} view the vector representing the viewing direction\n * @param {vec3} right the vector representing the local \"right\" direction\n * @param {vec3} up the vector representing the local \"up\" direction\n * @returns {quat} out\n */\nexport const setAxes = (function() {\n let matr = mat3.create();\n\n return function(out, view, right, up) {\n matr[0] = right[0];\n matr[3] = right[1];\n matr[6] = right[2];\n\n matr[1] = up[0];\n matr[4] = up[1];\n matr[7] = up[2];\n\n matr[2] = -view[0];\n matr[5] = -view[1];\n matr[8] = -view[2];\n\n return normalize(out, fromMat3(out, matr));\n };\n})();\n","import * as glMatrix from \"./common.js\";\nimport * as quat from \"./quat.js\";\nimport * as mat4 from \"./mat4.js\";\n\n/**\n * Dual Quaternion<br>\n * Format: [real, dual]<br>\n * Quaternion format: XYZW<br>\n * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>\n * @module quat2\n */\n\n\n/**\n * Creates a new identity dual quat\n *\n * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]\n */\nexport function create() {\n let dq = new glMatrix.ARRAY_TYPE(8);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n dq[0] = 0;\n dq[1] = 0;\n dq[2] = 0;\n dq[4] = 0;\n dq[5] = 0;\n dq[6] = 0;\n dq[7] = 0;\n }\n dq[3] = 1;\n return dq;\n}\n\n/**\n * Creates a new quat initialized with values from an existing quaternion\n *\n * @param {quat2} a dual quaternion to clone\n * @returns {quat2} new dual quaternion\n * @function\n */\nexport function clone(a) {\n let dq = new glMatrix.ARRAY_TYPE(8);\n dq[0] = a[0];\n dq[1] = a[1];\n dq[2] = a[2];\n dq[3] = a[3];\n dq[4] = a[4];\n dq[5] = a[5];\n dq[6] = a[6];\n dq[7] = a[7];\n return dq;\n}\n\n/**\n * Creates a new dual quat initialized with the given values\n *\n * @param {Number} x1 X component\n * @param {Number} y1 Y component\n * @param {Number} z1 Z component\n * @param {Number} w1 W component\n * @param {Number} x2 X component\n * @param {Number} y2 Y component\n * @param {Number} z2 Z component\n * @param {Number} w2 W component\n * @returns {quat2} new dual quaternion\n * @function\n */\nexport function fromValues(x1, y1, z1, w1, x2, y2, z2, w2) {\n let dq = new glMatrix.ARRAY_TYPE(8);\n dq[0] = x1;\n dq[1] = y1;\n dq[2] = z1;\n dq[3] = w1;\n dq[4] = x2;\n dq[5] = y2;\n dq[6] = z2;\n dq[7] = w2;\n return dq;\n}\n\n/**\n * Creates a new dual quat from the given values (quat and translation)\n *\n * @param {Number} x1 X component\n * @param {Number} y1 Y component\n * @param {Number} z1 Z component\n * @param {Number} w1 W component\n * @param {Number} x2 X component (translation)\n * @param {Number} y2 Y component (translation)\n * @param {Number} z2 Z component (translation)\n * @returns {quat2} new dual quaternion\n * @function\n */\nexport function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {\n let dq = new glMatrix.ARRAY_TYPE(8);\n dq[0] = x1;\n dq[1] = y1;\n dq[2] = z1;\n dq[3] = w1;\n let ax = x2 * 0.5,\n ay = y2 * 0.5,\n az = z2 * 0.5;\n dq[4] = ax * w1 + ay * z1 - az * y1;\n dq[5] = ay * w1 + az * x1 - ax * z1;\n dq[6] = az * w1 + ax * y1 - ay * x1;\n dq[7] = -ax * x1 - ay * y1 - az * z1;\n return dq;\n}\n\n/**\n * Creates a dual quat from a quaternion and a translation\n *\n * @param {quat2} dual quaternion receiving operation result\n * @param {quat} q quaternion\n * @param {vec3} t tranlation vector\n * @returns {quat2} dual quaternion receiving operation result\n * @function\n */\nexport function fromRotationTranslation(out, q, t) {\n let ax = t[0] * 0.5,\n ay = t[1] * 0.5,\n az = t[2] * 0.5,\n bx = q[0],\n by = q[1],\n bz = q[2],\n bw = q[3];\n out[0] = bx;\n out[1] = by;\n out[2] = bz;\n out[3] = bw;\n out[4] = ax * bw + ay * bz - az * by;\n out[5] = ay * bw + az * bx - ax * bz;\n out[6] = az * bw + ax * by - ay * bx;\n out[7] = -ax * bx - ay * by - az * bz;\n return out;\n}\n\n/**\n * Creates a dual quat from a translation\n *\n * @param {quat2} dual quaternion receiving operation result\n * @param {vec3} t translation vector\n * @returns {quat2} dual quaternion receiving operation result\n * @function\n */\nexport function fromTranslation(out, t) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = t[0] * 0.5;\n out[5] = t[1] * 0.5;\n out[6] = t[2] * 0.5;\n out[7] = 0;\n return out;\n}\n\n/**\n * Creates a dual quat from a quaternion\n *\n * @param {quat2} dual quaternion receiving operation result\n * @param {quat} q the quaternion\n * @returns {quat2} dual quaternion receiving operation result\n * @function\n */\nexport function fromRotation(out, q) {\n out[0] = q[0];\n out[1] = q[1];\n out[2] = q[2];\n out[3] = q[3];\n out[4] = 0;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n return out;\n}\n\n/**\n * Creates a new dual quat from a matrix (4x4)\n *\n * @param {quat2} out the dual quaternion\n * @param {mat4} a the matrix\n * @returns {quat2} dual quat receiving operation result\n * @function\n */\nexport function fromMat4(out, a) {\n //TODO Optimize this\n let outer = quat.create();\n mat4.getRotation(outer, a);\n let t = new glMatrix.ARRAY_TYPE(3);\n mat4.getTranslation(t, a);\n fromRotationTranslation(out, outer, t);\n return out;\n}\n\n/**\n * Copy the values from one dual quat to another\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the source dual quaternion\n * @returns {quat2} out\n * @function\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n return out;\n}\n\n/**\n * Set a dual quat to the identity dual quaternion\n *\n * @param {quat2} out the receiving quaternion\n * @returns {quat2} out\n */\nexport function identity(out) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = 0;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n return out;\n}\n\n/**\n * Set the components of a dual quat to the given values\n *\n * @param {quat2} out the receiving quaternion\n * @param {Number} x1 X component\n * @param {Number} y1 Y component\n * @param {Number} z1 Z component\n * @param {Number} w1 W component\n * @param {Number} x2 X component\n * @param {Number} y2 Y component\n * @param {Number} z2 Z component\n * @param {Number} w2 W component\n * @returns {quat2} out\n * @function\n */\nexport function set(out, x1, y1, z1, w1, x2, y2, z2, w2) {\n out[0] = x1;\n out[1] = y1;\n out[2] = z1;\n out[3] = w1;\n\n out[4] = x2;\n out[5] = y2;\n out[6] = z2;\n out[7] = w2;\n return out;\n}\n\n/**\n * Gets the real part of a dual quat\n * @param {quat} out real part\n * @param {quat2} a Dual Quaternion\n * @return {quat} real part\n */\nexport const getReal = quat.copy;\n\n/**\n * Gets the dual part of a dual quat\n * @param {quat} out dual part\n * @param {quat2} a Dual Quaternion\n * @return {quat} dual part\n */\nexport function getDual(out, a) {\n out[0] = a[4];\n out[1] = a[5];\n out[2] = a[6];\n out[3] = a[7];\n return out;\n}\n\n/**\n * Set the real component of a dual quat to the given quaternion\n *\n * @param {quat2} out the receiving quaternion\n * @param {quat} q a quaternion representing the real part\n * @returns {quat2} out\n * @function\n */\nexport const setReal = quat.copy;\n\n/**\n * Set the dual component of a dual quat to the given quaternion\n *\n * @param {quat2} out the receiving quaternion\n * @param {quat} q a quaternion representing the dual part\n * @returns {quat2} out\n * @function\n */\nexport function setDual(out, q) {\n out[4] = q[0];\n out[5] = q[1];\n out[6] = q[2];\n out[7] = q[3];\n return out;\n}\n\n/**\n * Gets the translation of a normalized dual quat\n * @param {vec3} out translation\n * @param {quat2} a Dual Quaternion to be decomposed\n * @return {vec3} translation\n */\nexport function getTranslation(out, a) {\n let ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3];\n out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;\n out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;\n out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;\n return out;\n}\n\n/**\n * Translates a dual quat by the given vector\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to translate\n * @param {vec3} v vector to translate by\n * @returns {quat2} out\n */\nexport function translate(out, a, v) {\n let ax1 = a[0],\n ay1 = a[1],\n az1 = a[2],\n aw1 = a[3],\n bx1 = v[0] * 0.5,\n by1 = v[1] * 0.5,\n bz1 = v[2] * 0.5,\n ax2 = a[4],\n ay2 = a[5],\n az2 = a[6],\n aw2 = a[7];\n out[0] = ax1;\n out[1] = ay1;\n out[2] = az1;\n out[3] = aw1;\n out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;\n out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;\n out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;\n out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;\n return out;\n}\n\n/**\n * Rotates a dual quat around the X axis\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {number} rad how far should the rotation be\n * @returns {quat2} out\n */\nexport function rotateX(out, a, rad) {\n let bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3],\n ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\n az1 = az * bw + aw * bz + ax * by - ay * bx,\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\n quat.rotateX(out, a, rad);\n bx = out[0];\n by = out[1];\n bz = out[2];\n bw = out[3];\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat around the Y axis\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {number} rad how far should the rotation be\n * @returns {quat2} out\n */\nexport function rotateY(out, a, rad) {\n let bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3],\n ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\n az1 = az * bw + aw * bz + ax * by - ay * bx,\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\n quat.rotateY(out, a, rad);\n bx = out[0];\n by = out[1];\n bz = out[2];\n bw = out[3];\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat around the Z axis\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {number} rad how far should the rotation be\n * @returns {quat2} out\n */\nexport function rotateZ(out, a, rad) {\n let bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3],\n ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\n az1 = az * bw + aw * bz + ax * by - ay * bx,\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\n quat.rotateZ(out, a, rad);\n bx = out[0];\n by = out[1];\n bz = out[2];\n bw = out[3];\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat by a given quaternion (a * q)\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {quat} q quaternion to rotate by\n * @returns {quat2} out\n */\nexport function rotateByQuatAppend(out, a, q) {\n let qx = q[0],\n qy = q[1],\n qz = q[2],\n qw = q[3],\n ax = a[0],\n ay = a[1],\n az = a[2],\n aw = a[3];\n\n out[0] = ax * qw + aw * qx + ay * qz - az * qy;\n out[1] = ay * qw + aw * qy + az * qx - ax * qz;\n out[2] = az * qw + aw * qz + ax * qy - ay * qx;\n out[3] = aw * qw - ax * qx - ay * qy - az * qz;\n ax = a[4];\n ay = a[5];\n az = a[6];\n aw = a[7];\n out[4] = ax * qw + aw * qx + ay * qz - az * qy;\n out[5] = ay * qw + aw * qy + az * qx - ax * qz;\n out[6] = az * qw + aw * qz + ax * qy - ay * qx;\n out[7] = aw * qw - ax * qx - ay * qy - az * qz;\n return out;\n}\n\n/**\n * Rotates a dual quat by a given quaternion (q * a)\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat} q quaternion to rotate by\n * @param {quat2} a the dual quaternion to rotate\n * @returns {quat2} out\n */\nexport function rotateByQuatPrepend(out, q, a) {\n let qx = q[0],\n qy = q[1],\n qz = q[2],\n qw = q[3],\n bx = a[0],\n by = a[1],\n bz = a[2],\n bw = a[3];\n\n out[0] = qx * bw + qw * bx + qy * bz - qz * by;\n out[1] = qy * bw + qw * by + qz * bx - qx * bz;\n out[2] = qz * bw + qw * bz + qx * by - qy * bx;\n out[3] = qw * bw - qx * bx - qy * by - qz * bz;\n bx = a[4];\n by = a[5];\n bz = a[6];\n bw = a[7];\n out[4] = qx * bw + qw * bx + qy * bz - qz * by;\n out[5] = qy * bw + qw * by + qz * bx - qx * bz;\n out[6] = qz * bw + qw * bz + qx * by - qy * bx;\n out[7] = qw * bw - qx * bx - qy * by - qz * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat around a given axis. Does the normalisation automatically\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {vec3} axis the axis to rotate around\n * @param {Number} rad how far the rotation should be\n * @returns {quat2} out\n */\nexport function rotateAroundAxis(out, a, axis, rad) {\n //Special case for rad = 0\n if (Math.abs(rad) < glMatrix.EPSILON) {\n return copy(out, a);\n }\n let axisLength = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);\n\n rad = rad * 0.5;\n let s = Math.sin(rad);\n let bx = s * axis[0] / axisLength;\n let by = s * axis[1] / axisLength;\n let bz = s * axis[2] / axisLength;\n let bw = Math.cos(rad);\n\n let ax1 = a[0],\n ay1 = a[1],\n az1 = a[2],\n aw1 = a[3];\n out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n\n let ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7];\n out[4] = ax * bw + aw * bx + ay * bz - az * by;\n out[5] = ay * bw + aw * by + az * bx - ax * bz;\n out[6] = az * bw + aw * bz + ax * by - ay * bx;\n out[7] = aw * bw - ax * bx - ay * by - az * bz;\n\n return out;\n}\n\n/**\n * Adds two dual quat's\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @returns {quat2} out\n * @function\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n out[6] = a[6] + b[6];\n out[7] = a[7] + b[7];\n return out;\n}\n\n/**\n * Multiplies two dual quat's\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @returns {quat2} out\n */\nexport function multiply(out, a, b) {\n let ax0 = a[0],\n ay0 = a[1],\n az0 = a[2],\n aw0 = a[3],\n bx1 = b[4],\n by1 = b[5],\n bz1 = b[6],\n bw1 = b[7],\n ax1 = a[4],\n ay1 = a[5],\n az1 = a[6],\n aw1 = a[7],\n bx0 = b[0],\n by0 = b[1],\n bz0 = b[2],\n bw0 = b[3];\n out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;\n out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;\n out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;\n out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;\n out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;\n out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;\n out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;\n out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;\n return out;\n}\n\n/**\n * Alias for {@link quat2.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Scales a dual quat by a scalar number\n *\n * @param {quat2} out the receiving dual quat\n * @param {quat2} a the dual quat to scale\n * @param {Number} b amount to scale the dual quat by\n * @returns {quat2} out\n * @function\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n out[6] = a[6] * b;\n out[7] = a[7] * b;\n return out;\n}\n\n/**\n * Calculates the dot product of two dual quat's (The dot product of the real parts)\n *\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @returns {Number} dot product of a and b\n * @function\n */\nexport const dot = quat.dot;\n\n/**\n * Performs a linear interpolation between two dual quats's\n * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)\n *\n * @param {quat2} out the receiving dual quat\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat2} out\n */\nexport function lerp(out, a, b, t) {\n let mt = 1 - t;\n if (dot(a, b) < 0) t = -t;\n\n out[0] = a[0] * mt + b[0] * t;\n out[1] = a[1] * mt + b[1] * t;\n out[2] = a[2] * mt + b[2] * t;\n out[3] = a[3] * mt + b[3] * t;\n out[4] = a[4] * mt + b[4] * t;\n out[5] = a[5] * mt + b[5] * t;\n out[6] = a[6] * mt + b[6] * t;\n out[7] = a[7] * mt + b[7] * t;\n\n return out;\n}\n\n/**\n * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a dual quat to calculate inverse of\n * @returns {quat2} out\n */\nexport function invert(out, a) {\n let sqlen = squaredLength(a);\n out[0] = -a[0] / sqlen;\n out[1] = -a[1] / sqlen;\n out[2] = -a[2] / sqlen;\n out[3] = a[3] / sqlen;\n out[4] = -a[4] / sqlen;\n out[5] = -a[5] / sqlen;\n out[6] = -a[6] / sqlen;\n out[7] = a[7] / sqlen;\n return out;\n}\n\n/**\n * Calculates the conjugate of a dual quat\n * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.\n *\n * @param {quat2} out the receiving quaternion\n * @param {quat2} a quat to calculate conjugate of\n * @returns {quat2} out\n */\nexport function conjugate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = a[3];\n out[4] = -a[4];\n out[5] = -a[5];\n out[6] = -a[6];\n out[7] = a[7];\n return out;\n}\n\n/**\n * Calculates the length of a dual quat\n *\n * @param {quat2} a dual quat to calculate length of\n * @returns {Number} length of a\n * @function\n */\nexport const length = quat.length;\n\n/**\n * Alias for {@link quat2.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Calculates the squared length of a dual quat\n *\n * @param {quat2} a dual quat to calculate squared length of\n * @returns {Number} squared length of a\n * @function\n */\nexport const squaredLength = quat.squaredLength;\n\n/**\n * Alias for {@link quat2.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Normalize a dual quat\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a dual quaternion to normalize\n * @returns {quat2} out\n * @function\n */\nexport function normalize(out, a) {\n let magnitude = squaredLength(a);\n if (magnitude > 0) {\n magnitude = Math.sqrt(magnitude);\n\n let a0 = a[0] / magnitude;\n let a1 = a[1] / magnitude;\n let a2 = a[2] / magnitude;\n let a3 = a[3] / magnitude;\n\n let b0 = a[4];\n let b1 = a[5];\n let b2 = a[6];\n let b3 = a[7];\n\n let a_dot_b = (a0 * b0) + (a1 * b1) + (a2 * b2) + (a3 * b3);\n\n out[0] = a0;\n out[1] = a1;\n out[2] = a2;\n out[3] = a3;\n\n out[4] = (b0 - (a0 * a_dot_b)) / magnitude;\n out[5] = (b1 - (a1 * a_dot_b)) / magnitude;\n out[6] = (b2 - (a2 * a_dot_b)) / magnitude;\n out[7] = (b3 - (a3 * a_dot_b)) / magnitude;\n }\n return out;\n}\n\n/**\n * Returns a string representation of a dual quatenion\n *\n * @param {quat2} a dual quaternion to represent as a string\n * @returns {String} string representation of the dual quat\n */\nexport function str(a) {\n return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +\n a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')';\n}\n\n/**\n * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)\n *\n * @param {quat2} a the first dual quaternion.\n * @param {quat2} b the second dual quaternion.\n * @returns {Boolean} true if the dual quaternions are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&\n a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];\n}\n\n/**\n * Returns whether or not the dual quaternions have approximately the same elements in the same position.\n *\n * @param {quat2} a the first dual quat.\n * @param {quat2} b the second dual quat.\n * @returns {Boolean} true if the dual quats are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0],\n a1 = a[1],\n a2 = a[2],\n a3 = a[3],\n a4 = a[4],\n a5 = a[5],\n a6 = a[6],\n a7 = a[7];\n let b0 = b[0],\n b1 = b[1],\n b2 = b[2],\n b3 = b[3],\n b4 = b[4],\n b5 = b[5],\n b6 = b[6],\n b7 = b[7];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\n Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\n Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)));\n}\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 2 Dimensional Vector\n * @module vec2\n */\n\n/**\n * Creates a new, empty vec2\n *\n * @returns {vec2} a new 2D vector\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(2);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n }\n return out;\n}\n\n/**\n * Creates a new vec2 initialized with values from an existing vector\n *\n * @param {vec2} a vector to clone\n * @returns {vec2} a new 2D vector\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(2);\n out[0] = a[0];\n out[1] = a[1];\n return out;\n}\n\n/**\n * Creates a new vec2 initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @returns {vec2} a new 2D vector\n */\nexport function fromValues(x, y) {\n let out = new glMatrix.ARRAY_TYPE(2);\n out[0] = x;\n out[1] = y;\n return out;\n}\n\n/**\n * Copy the values from one vec2 to another\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the source vector\n * @returns {vec2} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n return out;\n}\n\n/**\n * Set the components of a vec2 to the given values\n *\n * @param {vec2} out the receiving vector\n * @param {Number} x X component\n * @param {Number} y Y component\n * @returns {vec2} out\n */\nexport function set(out, x, y) {\n out[0] = x;\n out[1] = y;\n return out;\n}\n\n/**\n * Adds two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n return out;\n}\n\n/**\n * Subtracts vector b from vector a\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n return out;\n}\n\n/**\n * Multiplies two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function multiply(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n return out;\n}\n\n/**\n * Divides two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function divide(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n return out;\n}\n\n/**\n * Math.ceil the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to ceil\n * @returns {vec2} out\n */\nexport function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n return out;\n}\n\n/**\n * Math.floor the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to floor\n * @returns {vec2} out\n */\nexport function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n return out;\n}\n\n/**\n * Returns the minimum of two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function min(out, a, b) {\n out[0] = Math.min(a[0], b[0]);\n out[1] = Math.min(a[1], b[1]);\n return out;\n}\n\n/**\n * Returns the maximum of two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function max(out, a, b) {\n out[0] = Math.max(a[0], b[0]);\n out[1] = Math.max(a[1], b[1]);\n return out;\n}\n\n/**\n * Math.round the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to round\n * @returns {vec2} out\n */\nexport function round (out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n return out;\n}\n\n/**\n * Scales a vec2 by a scalar number\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {vec2} out\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n return out;\n}\n\n/**\n * Adds two vec2's after scaling the second operand by a scalar value\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @param {Number} scale the amount to scale b by before adding\n * @returns {vec2} out\n */\nexport function scaleAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n return out;\n}\n\n/**\n * Calculates the euclidian distance between two vec2's\n *\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {Number} distance between a and b\n */\nexport function distance(a, b) {\n var x = b[0] - a[0],\n y = b[1] - a[1];\n return Math.sqrt(x*x + y*y);\n}\n\n/**\n * Calculates the squared euclidian distance between two vec2's\n *\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {Number} squared distance between a and b\n */\nexport function squaredDistance(a, b) {\n var x = b[0] - a[0],\n y = b[1] - a[1];\n return x*x + y*y;\n}\n\n/**\n * Calculates the length of a vec2\n *\n * @param {vec2} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport function length(a) {\n var x = a[0],\n y = a[1];\n return Math.sqrt(x*x + y*y);\n}\n\n/**\n * Calculates the squared length of a vec2\n *\n * @param {vec2} a vector to calculate squared length of\n * @returns {Number} squared length of a\n */\nexport function squaredLength (a) {\n var x = a[0],\n y = a[1];\n return x*x + y*y;\n}\n\n/**\n * Negates the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to negate\n * @returns {vec2} out\n */\nexport function negate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n return out;\n}\n\n/**\n * Returns the inverse of the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to invert\n * @returns {vec2} out\n */\nexport function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n return out;\n}\n\n/**\n * Normalize a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to normalize\n * @returns {vec2} out\n */\nexport function normalize(out, a) {\n var x = a[0],\n y = a[1];\n var len = x*x + y*y;\n if (len > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len = 1 / Math.sqrt(len);\n out[0] = a[0] * len;\n out[1] = a[1] * len;\n }\n return out;\n}\n\n/**\n * Calculates the dot product of two vec2's\n *\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {Number} dot product of a and b\n */\nexport function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1];\n}\n\n/**\n * Computes the cross product of two vec2's\n * Note that the cross product must by definition produce a 3D vector\n *\n * @param {vec3} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec3} out\n */\nexport function cross(out, a, b) {\n var z = a[0] * b[1] - a[1] * b[0];\n out[0] = out[1] = 0;\n out[2] = z;\n return out;\n}\n\n/**\n * Performs a linear interpolation between two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec2} out\n */\nexport function lerp(out, a, b, t) {\n var ax = a[0],\n ay = a[1];\n out[0] = ax + t * (b[0] - ax);\n out[1] = ay + t * (b[1] - ay);\n return out;\n}\n\n/**\n * Generates a random vector with the given scale\n *\n * @param {vec2} out the receiving vector\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\n * @returns {vec2} out\n */\nexport function random(out, scale) {\n scale = scale || 1.0;\n var r = glMatrix.RANDOM() * 2.0 * Math.PI;\n out[0] = Math.cos(r) * scale;\n out[1] = Math.sin(r) * scale;\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat2} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat2(out, a, m) {\n var x = a[0],\n y = a[1];\n out[0] = m[0] * x + m[2] * y;\n out[1] = m[1] * x + m[3] * y;\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat2d\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat2d} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat2d(out, a, m) {\n var x = a[0],\n y = a[1];\n out[0] = m[0] * x + m[2] * y + m[4];\n out[1] = m[1] * x + m[3] * y + m[5];\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat3\n * 3rd vector component is implicitly '1'\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat3} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat3(out, a, m) {\n var x = a[0],\n y = a[1];\n out[0] = m[0] * x + m[3] * y + m[6];\n out[1] = m[1] * x + m[4] * y + m[7];\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat4\n * 3rd vector component is implicitly '0'\n * 4th vector component is implicitly '1'\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat4} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat4(out, a, m) {\n let x = a[0];\n let y = a[1];\n out[0] = m[0] * x + m[4] * y + m[12];\n out[1] = m[1] * x + m[5] * y + m[13];\n return out;\n}\n\n/**\n * Rotate a 2D vector\n * @param {vec2} out The receiving vec2\n * @param {vec2} a The vec2 point to rotate\n * @param {vec2} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec2} out\n */\nexport function rotate(out, a, b, c) {\n //Translate point to the origin\n let p0 = a[0] - b[0],\n p1 = a[1] - b[1],\n sinC = Math.sin(c),\n cosC = Math.cos(c);\n \n //perform rotation and translate to correct position\n out[0] = p0*cosC - p1*sinC + b[0];\n out[1] = p0*sinC + p1*cosC + b[1];\n\n return out;\n}\n\n/**\n * Get the angle between two 2D vectors\n * @param {vec2} a The first operand\n * @param {vec2} b The second operand\n * @returns {Number} The angle in radians\n */\nexport function angle(a, b) {\n let x1 = a[0],\n y1 = a[1],\n x2 = b[0],\n y2 = b[1];\n \n let len1 = x1*x1 + y1*y1;\n if (len1 > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len1 = 1 / Math.sqrt(len1);\n }\n \n let len2 = x2*x2 + y2*y2;\n if (len2 > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len2 = 1 / Math.sqrt(len2);\n }\n \n let cosine = (x1 * x2 + y1 * y2) * len1 * len2;\n \n \n if(cosine > 1.0) {\n return 0;\n }\n else if(cosine < -1.0) {\n return Math.PI;\n } else {\n return Math.acos(cosine);\n }\n}\n\n/**\n * Returns a string representation of a vector\n *\n * @param {vec2} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'vec2(' + a[0] + ', ' + a[1] + ')';\n}\n\n/**\n * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)\n *\n * @param {vec2} a The first vector.\n * @param {vec2} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1];\n}\n\n/**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n *\n * @param {vec2} a The first vector.\n * @param {vec2} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1];\n let b0 = b[0], b1 = b[1];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)));\n}\n\n/**\n * Alias for {@link vec2.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Alias for {@link vec2.subtract}\n * @function\n */\nexport const sub = subtract;\n\n/**\n * Alias for {@link vec2.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link vec2.divide}\n * @function\n */\nexport const div = divide;\n\n/**\n * Alias for {@link vec2.distance}\n * @function\n */\nexport const dist = distance;\n\n/**\n * Alias for {@link vec2.squaredDistance}\n * @function\n */\nexport const sqrDist = squaredDistance;\n\n/**\n * Alias for {@link vec2.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Perform some operation over an array of vec2s.\n *\n * @param {Array} a the array of vectors to iterate over\n * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed\n * @param {Number} offset Number of elements to skip at the beginning of the array\n * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array\n * @param {Function} fn Function to call for each vector in the array\n * @param {Object} [arg] additional argument to pass to fn\n * @returns {Array} a\n * @function\n */\nexport const forEach = (function() {\n let vec = create();\n\n return function(a, stride, offset, count, fn, arg) {\n let i, l;\n if(!stride) {\n stride = 2;\n }\n\n if(!offset) {\n offset = 0;\n }\n\n if(count) {\n l = Math.min((count * stride) + offset, a.length);\n } else {\n l = a.length;\n }\n\n for(i = offset; i < l; i += stride) {\n vec[0] = a[i]; vec[1] = a[i+1];\n fn(vec, vec, arg);\n a[i] = vec[0]; a[i+1] = vec[1];\n }\n\n return a;\n };\n})();\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 3 Dimensional Vector\n * @module vec3\n */\n\n/**\n * Creates a new, empty vec3\n *\n * @returns {vec3} a new 3D vector\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(3);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n }\n return out;\n}\n\n/**\n * Creates a new vec3 initialized with values from an existing vector\n *\n * @param {vec3} a vector to clone\n * @returns {vec3} a new 3D vector\n */\nexport function clone(a) {\n var out = new glMatrix.ARRAY_TYPE(3);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n return out;\n}\n\n/**\n * Calculates the length of a vec3\n *\n * @param {vec3} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport function length(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n return Math.sqrt(x*x + y*y + z*z);\n}\n\n/**\n * Creates a new vec3 initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @returns {vec3} a new 3D vector\n */\nexport function fromValues(x, y, z) {\n let out = new glMatrix.ARRAY_TYPE(3);\n out[0] = x;\n out[1] = y;\n out[2] = z;\n return out;\n}\n\n/**\n * Copy the values from one vec3 to another\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the source vector\n * @returns {vec3} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n return out;\n}\n\n/**\n * Set the components of a vec3 to the given values\n *\n * @param {vec3} out the receiving vector\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @returns {vec3} out\n */\nexport function set(out, x, y, z) {\n out[0] = x;\n out[1] = y;\n out[2] = z;\n return out;\n}\n\n/**\n * Adds two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n return out;\n}\n\n/**\n * Subtracts vector b from vector a\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n return out;\n}\n\n/**\n * Multiplies two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function multiply(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n out[2] = a[2] * b[2];\n return out;\n}\n\n/**\n * Divides two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function divide(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n out[2] = a[2] / b[2];\n return out;\n}\n\n/**\n * Math.ceil the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to ceil\n * @returns {vec3} out\n */\nexport function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n out[2] = Math.ceil(a[2]);\n return out;\n}\n\n/**\n * Math.floor the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to floor\n * @returns {vec3} out\n */\nexport function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n out[2] = Math.floor(a[2]);\n return out;\n}\n\n/**\n * Returns the minimum of two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function min(out, a, b) {\n out[0] = Math.min(a[0], b[0]);\n out[1] = Math.min(a[1], b[1]);\n out[2] = Math.min(a[2], b[2]);\n return out;\n}\n\n/**\n * Returns the maximum of two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function max(out, a, b) {\n out[0] = Math.max(a[0], b[0]);\n out[1] = Math.max(a[1], b[1]);\n out[2] = Math.max(a[2], b[2]);\n return out;\n}\n\n/**\n * Math.round the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to round\n * @returns {vec3} out\n */\nexport function round(out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n out[2] = Math.round(a[2]);\n return out;\n}\n\n/**\n * Scales a vec3 by a scalar number\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {vec3} out\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n return out;\n}\n\n/**\n * Adds two vec3's after scaling the second operand by a scalar value\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {Number} scale the amount to scale b by before adding\n * @returns {vec3} out\n */\nexport function scaleAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n return out;\n}\n\n/**\n * Calculates the euclidian distance between two vec3's\n *\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {Number} distance between a and b\n */\nexport function distance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n return Math.sqrt(x*x + y*y + z*z);\n}\n\n/**\n * Calculates the squared euclidian distance between two vec3's\n *\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {Number} squared distance between a and b\n */\nexport function squaredDistance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n return x*x + y*y + z*z;\n}\n\n/**\n * Calculates the squared length of a vec3\n *\n * @param {vec3} a vector to calculate squared length of\n * @returns {Number} squared length of a\n */\nexport function squaredLength(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n return x*x + y*y + z*z;\n}\n\n/**\n * Negates the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to negate\n * @returns {vec3} out\n */\nexport function negate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n return out;\n}\n\n/**\n * Returns the inverse of the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to invert\n * @returns {vec3} out\n */\nexport function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n out[2] = 1.0 / a[2];\n return out;\n}\n\n/**\n * Normalize a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to normalize\n * @returns {vec3} out\n */\nexport function normalize(out, a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let len = x*x + y*y + z*z;\n if (len > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len = 1 / Math.sqrt(len);\n out[0] = a[0] * len;\n out[1] = a[1] * len;\n out[2] = a[2] * len;\n }\n return out;\n}\n\n/**\n * Calculates the dot product of two vec3's\n *\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {Number} dot product of a and b\n */\nexport function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n}\n\n/**\n * Computes the cross product of two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function cross(out, a, b) {\n let ax = a[0], ay = a[1], az = a[2];\n let bx = b[0], by = b[1], bz = b[2];\n\n out[0] = ay * bz - az * by;\n out[1] = az * bx - ax * bz;\n out[2] = ax * by - ay * bx;\n return out;\n}\n\n/**\n * Performs a linear interpolation between two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec3} out\n */\nexport function lerp(out, a, b, t) {\n let ax = a[0];\n let ay = a[1];\n let az = a[2];\n out[0] = ax + t * (b[0] - ax);\n out[1] = ay + t * (b[1] - ay);\n out[2] = az + t * (b[2] - az);\n return out;\n}\n\n/**\n * Performs a hermite interpolation with two control points\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {vec3} c the third operand\n * @param {vec3} d the fourth operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec3} out\n */\nexport function hermite(out, a, b, c, d, t) {\n let factorTimes2 = t * t;\n let factor1 = factorTimes2 * (2 * t - 3) + 1;\n let factor2 = factorTimes2 * (t - 2) + t;\n let factor3 = factorTimes2 * (t - 1);\n let factor4 = factorTimes2 * (3 - 2 * t);\n\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\n\n return out;\n}\n\n/**\n * Performs a bezier interpolation with two control points\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {vec3} c the third operand\n * @param {vec3} d the fourth operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec3} out\n */\nexport function bezier(out, a, b, c, d, t) {\n let inverseFactor = 1 - t;\n let inverseFactorTimesTwo = inverseFactor * inverseFactor;\n let factorTimes2 = t * t;\n let factor1 = inverseFactorTimesTwo * inverseFactor;\n let factor2 = 3 * t * inverseFactorTimesTwo;\n let factor3 = 3 * factorTimes2 * inverseFactor;\n let factor4 = factorTimes2 * t;\n\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\n\n return out;\n}\n\n/**\n * Generates a random vector with the given scale\n *\n * @param {vec3} out the receiving vector\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\n * @returns {vec3} out\n */\nexport function random(out, scale) {\n scale = scale || 1.0;\n\n let r = glMatrix.RANDOM() * 2.0 * Math.PI;\n let z = (glMatrix.RANDOM() * 2.0) - 1.0;\n let zScale = Math.sqrt(1.0-z*z) * scale;\n\n out[0] = Math.cos(r) * zScale;\n out[1] = Math.sin(r) * zScale;\n out[2] = z * scale;\n return out;\n}\n\n/**\n * Transforms the vec3 with a mat4.\n * 4th vector component is implicitly '1'\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to transform\n * @param {mat4} m matrix to transform with\n * @returns {vec3} out\n */\nexport function transformMat4(out, a, m) {\n let x = a[0], y = a[1], z = a[2];\n let w = m[3] * x + m[7] * y + m[11] * z + m[15];\n w = w || 1.0;\n out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;\n out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;\n out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;\n return out;\n}\n\n/**\n * Transforms the vec3 with a mat3.\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to transform\n * @param {mat3} m the 3x3 matrix to transform with\n * @returns {vec3} out\n */\nexport function transformMat3(out, a, m) {\n let x = a[0], y = a[1], z = a[2];\n out[0] = x * m[0] + y * m[3] + z * m[6];\n out[1] = x * m[1] + y * m[4] + z * m[7];\n out[2] = x * m[2] + y * m[5] + z * m[8];\n return out;\n}\n\n/**\n * Transforms the vec3 with a quat\n * Can also be used for dual quaternions. (Multiply it with the real part)\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to transform\n * @param {quat} q quaternion to transform with\n * @returns {vec3} out\n */\nexport function transformQuat(out, a, q) {\n // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed\n let qx = q[0], qy = q[1], qz = q[2], qw = q[3];\n let x = a[0], y = a[1], z = a[2];\n // var qvec = [qx, qy, qz];\n // var uv = vec3.cross([], qvec, a);\n let uvx = qy * z - qz * y,\n uvy = qz * x - qx * z,\n uvz = qx * y - qy * x;\n // var uuv = vec3.cross([], qvec, uv);\n let uuvx = qy * uvz - qz * uvy,\n uuvy = qz * uvx - qx * uvz,\n uuvz = qx * uvy - qy * uvx;\n // vec3.scale(uv, uv, 2 * w);\n let w2 = qw * 2;\n uvx *= w2;\n uvy *= w2;\n uvz *= w2;\n // vec3.scale(uuv, uuv, 2);\n uuvx *= 2;\n uuvy *= 2;\n uuvz *= 2;\n // return vec3.add(out, a, vec3.add(out, uv, uuv));\n out[0] = x + uvx + uuvx;\n out[1] = y + uvy + uuvy;\n out[2] = z + uvz + uuvz;\n return out;\n}\n\n/**\n * Rotate a 3D vector around the x-axis\n * @param {vec3} out The receiving vec3\n * @param {vec3} a The vec3 point to rotate\n * @param {vec3} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec3} out\n */\nexport function rotateX(out, a, b, c){\n let p = [], r=[];\n //Translate point to the origin\n p[0] = a[0] - b[0];\n p[1] = a[1] - b[1];\n p[2] = a[2] - b[2];\n\n //perform rotation\n r[0] = p[0];\n r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);\n r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);\n\n //translate to correct position\n out[0] = r[0] + b[0];\n out[1] = r[1] + b[1];\n out[2] = r[2] + b[2];\n\n return out;\n}\n\n/**\n * Rotate a 3D vector around the y-axis\n * @param {vec3} out The receiving vec3\n * @param {vec3} a The vec3 point to rotate\n * @param {vec3} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec3} out\n */\nexport function rotateY(out, a, b, c){\n let p = [], r=[];\n //Translate point to the origin\n p[0] = a[0] - b[0];\n p[1] = a[1] - b[1];\n p[2] = a[2] - b[2];\n\n //perform rotation\n r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);\n r[1] = p[1];\n r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);\n\n //translate to correct position\n out[0] = r[0] + b[0];\n out[1] = r[1] + b[1];\n out[2] = r[2] + b[2];\n\n return out;\n}\n\n/**\n * Rotate a 3D vector around the z-axis\n * @param {vec3} out The receiving vec3\n * @param {vec3} a The vec3 point to rotate\n * @param {vec3} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec3} out\n */\nexport function rotateZ(out, a, b, c){\n let p = [], r=[];\n //Translate point to the origin\n p[0] = a[0] - b[0];\n p[1] = a[1] - b[1];\n p[2] = a[2] - b[2];\n\n //perform rotation\n r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);\n r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);\n r[2] = p[2];\n\n //translate to correct position\n out[0] = r[0] + b[0];\n out[1] = r[1] + b[1];\n out[2] = r[2] + b[2];\n\n return out;\n}\n\n/**\n * Get the angle between two 3D vectors\n * @param {vec3} a The first operand\n * @param {vec3} b The second operand\n * @returns {Number} The angle in radians\n */\nexport function angle(a, b) {\n let tempA = fromValues(a[0], a[1], a[2]);\n let tempB = fromValues(b[0], b[1], b[2]);\n\n normalize(tempA, tempA);\n normalize(tempB, tempB);\n\n let cosine = dot(tempA, tempB);\n\n if(cosine > 1.0) {\n return 0;\n }\n else if(cosine < -1.0) {\n return Math.PI;\n } else {\n return Math.acos(cosine);\n }\n}\n\n/**\n * Returns a string representation of a vector\n *\n * @param {vec3} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';\n}\n\n/**\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\n *\n * @param {vec3} a The first vector.\n * @param {vec3} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\n}\n\n/**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n *\n * @param {vec3} a The first vector.\n * @param {vec3} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2];\n let b0 = b[0], b1 = b[1], b2 = b[2];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)));\n}\n\n/**\n * Alias for {@link vec3.subtract}\n * @function\n */\nexport const sub = subtract;\n\n/**\n * Alias for {@link vec3.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link vec3.divide}\n * @function\n */\nexport const div = divide;\n\n/**\n * Alias for {@link vec3.distance}\n * @function\n */\nexport const dist = distance;\n\n/**\n * Alias for {@link vec3.squaredDistance}\n * @function\n */\nexport const sqrDist = squaredDistance;\n\n/**\n * Alias for {@link vec3.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Alias for {@link vec3.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Perform some operation over an array of vec3s.\n *\n * @param {Array} a the array of vectors to iterate over\n * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed\n * @param {Number} offset Number of elements to skip at the beginning of the array\n * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array\n * @param {Function} fn Function to call for each vector in the array\n * @param {Object} [arg] additional argument to pass to fn\n * @returns {Array} a\n * @function\n */\nexport const forEach = (function() {\n let vec = create();\n\n return function(a, stride, offset, count, fn, arg) {\n let i, l;\n if(!stride) {\n stride = 3;\n }\n\n if(!offset) {\n offset = 0;\n }\n\n if(count) {\n l = Math.min((count * stride) + offset, a.length);\n } else {\n l = a.length;\n }\n\n for(i = offset; i < l; i += stride) {\n vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];\n fn(vec, vec, arg);\n a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];\n }\n\n return a;\n };\n})();\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 4 Dimensional Vector\n * @module vec4\n */\n\n/**\n * Creates a new, empty vec4\n *\n * @returns {vec4} a new 4D vector\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(4);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n }\n return out;\n}\n\n/**\n * Creates a new vec4 initialized with values from an existing vector\n *\n * @param {vec4} a vector to clone\n * @returns {vec4} a new 4D vector\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Creates a new vec4 initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {vec4} a new 4D vector\n */\nexport function fromValues(x, y, z, w) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n}\n\n/**\n * Copy the values from one vec4 to another\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the source vector\n * @returns {vec4} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Set the components of a vec4 to the given values\n *\n * @param {vec4} out the receiving vector\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {vec4} out\n */\nexport function set(out, x, y, z, w) {\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n}\n\n/**\n * Adds two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n return out;\n}\n\n/**\n * Subtracts vector b from vector a\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n return out;\n}\n\n/**\n * Multiplies two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function multiply(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n out[2] = a[2] * b[2];\n out[3] = a[3] * b[3];\n return out;\n}\n\n/**\n * Divides two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function divide(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n out[2] = a[2] / b[2];\n out[3] = a[3] / b[3];\n return out;\n}\n\n/**\n * Math.ceil the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to ceil\n * @returns {vec4} out\n */\nexport function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n out[2] = Math.ceil(a[2]);\n out[3] = Math.ceil(a[3]);\n return out;\n}\n\n/**\n * Math.floor the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to floor\n * @returns {vec4} out\n */\nexport function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n out[2] = Math.floor(a[2]);\n out[3] = Math.floor(a[3]);\n return out;\n}\n\n/**\n * Returns the minimum of two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function min(out, a, b) {\n out[0] = Math.min(a[0], b[0]);\n out[1] = Math.min(a[1], b[1]);\n out[2] = Math.min(a[2], b[2]);\n out[3] = Math.min(a[3], b[3]);\n return out;\n}\n\n/**\n * Returns the maximum of two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function max(out, a, b) {\n out[0] = Math.max(a[0], b[0]);\n out[1] = Math.max(a[1], b[1]);\n out[2] = Math.max(a[2], b[2]);\n out[3] = Math.max(a[3], b[3]);\n return out;\n}\n\n/**\n * Math.round the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to round\n * @returns {vec4} out\n */\nexport function round(out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n out[2] = Math.round(a[2]);\n out[3] = Math.round(a[3]);\n return out;\n}\n\n/**\n * Scales a vec4 by a scalar number\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {vec4} out\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n return out;\n}\n\n/**\n * Adds two vec4's after scaling the second operand by a scalar value\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @param {Number} scale the amount to scale b by before adding\n * @returns {vec4} out\n */\nexport function scaleAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n return out;\n}\n\n/**\n * Calculates the euclidian distance between two vec4's\n *\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {Number} distance between a and b\n */\nexport function distance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n let w = b[3] - a[3];\n return Math.sqrt(x*x + y*y + z*z + w*w);\n}\n\n/**\n * Calculates the squared euclidian distance between two vec4's\n *\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {Number} squared distance between a and b\n */\nexport function squaredDistance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n let w = b[3] - a[3];\n return x*x + y*y + z*z + w*w;\n}\n\n/**\n * Calculates the length of a vec4\n *\n * @param {vec4} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport function length(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let w = a[3];\n return Math.sqrt(x*x + y*y + z*z + w*w);\n}\n\n/**\n * Calculates the squared length of a vec4\n *\n * @param {vec4} a vector to calculate squared length of\n * @returns {Number} squared length of a\n */\nexport function squaredLength(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let w = a[3];\n return x*x + y*y + z*z + w*w;\n}\n\n/**\n * Negates the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to negate\n * @returns {vec4} out\n */\nexport function negate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = -a[3];\n return out;\n}\n\n/**\n * Returns the inverse of the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to invert\n * @returns {vec4} out\n */\nexport function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n out[2] = 1.0 / a[2];\n out[3] = 1.0 / a[3];\n return out;\n}\n\n/**\n * Normalize a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to normalize\n * @returns {vec4} out\n */\nexport function normalize(out, a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let w = a[3];\n let len = x*x + y*y + z*z + w*w;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n out[0] = x * len;\n out[1] = y * len;\n out[2] = z * len;\n out[3] = w * len;\n }\n return out;\n}\n\n/**\n * Calculates the dot product of two vec4's\n *\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {Number} dot product of a and b\n */\nexport function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];\n}\n\n/**\n * Performs a linear interpolation between two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec4} out\n */\nexport function lerp(out, a, b, t) {\n let ax = a[0];\n let ay = a[1];\n let az = a[2];\n let aw = a[3];\n out[0] = ax + t * (b[0] - ax);\n out[1] = ay + t * (b[1] - ay);\n out[2] = az + t * (b[2] - az);\n out[3] = aw + t * (b[3] - aw);\n return out;\n}\n\n/**\n * Generates a random vector with the given scale\n *\n * @param {vec4} out the receiving vector\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\n * @returns {vec4} out\n */\nexport function random(out, scale) {\n scale = scale || 1.0;\n\n // Marsaglia, George. Choosing a Point from the Surface of a\n // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.\n // http://projecteuclid.org/euclid.aoms/1177692644;\n var v1, v2, v3, v4;\n var s1, s2;\n do {\n v1 = glMatrix.RANDOM() * 2 - 1;\n v2 = glMatrix.RANDOM() * 2 - 1;\n s1 = v1 * v1 + v2 * v2;\n } while (s1 >= 1);\n do {\n v3 = glMatrix.RANDOM() * 2 - 1;\n v4 = glMatrix.RANDOM() * 2 - 1;\n s2 = v3 * v3 + v4 * v4;\n } while (s2 >= 1);\n\n var d = Math.sqrt((1 - s1) / s2);\n out[0] = scale * v1;\n out[1] = scale * v2;\n out[2] = scale * v3 * d;\n out[3] = scale * v4 * d;\n return out;\n}\n\n/**\n * Transforms the vec4 with a mat4.\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the vector to transform\n * @param {mat4} m matrix to transform with\n * @returns {vec4} out\n */\nexport function transformMat4(out, a, m) {\n let x = a[0], y = a[1], z = a[2], w = a[3];\n out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;\n out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;\n out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;\n out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;\n return out;\n}\n\n/**\n * Transforms the vec4 with a quat\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the vector to transform\n * @param {quat} q quaternion to transform with\n * @returns {vec4} out\n */\nexport function transformQuat(out, a, q) {\n let x = a[0], y = a[1], z = a[2];\n let qx = q[0], qy = q[1], qz = q[2], qw = q[3];\n\n // calculate quat * vec\n let ix = qw * x + qy * z - qz * y;\n let iy = qw * y + qz * x - qx * z;\n let iz = qw * z + qx * y - qy * x;\n let iw = -qx * x - qy * y - qz * z;\n\n // calculate result * inverse quat\n out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;\n out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;\n out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;\n out[3] = a[3];\n return out;\n}\n\n/**\n * Returns a string representation of a vector\n *\n * @param {vec4} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\n}\n\n/**\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\n *\n * @param {vec4} a The first vector.\n * @param {vec4} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\n}\n\n/**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n *\n * @param {vec4} a The first vector.\n * @param {vec4} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\n}\n\n/**\n * Alias for {@link vec4.subtract}\n * @function\n */\nexport const sub = subtract;\n\n/**\n * Alias for {@link vec4.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link vec4.divide}\n * @function\n */\nexport const div = divide;\n\n/**\n * Alias for {@link vec4.distance}\n * @function\n */\nexport const dist = distance;\n\n/**\n * Alias for {@link vec4.squaredDistance}\n * @function\n */\nexport const sqrDist = squaredDistance;\n\n/**\n * Alias for {@link vec4.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Alias for {@link vec4.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Perform some operation over an array of vec4s.\n *\n * @param {Array} a the array of vectors to iterate over\n * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed\n * @param {Number} offset Number of elements to skip at the beginning of the array\n * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array\n * @param {Function} fn Function to call for each vector in the array\n * @param {Object} [arg] additional argument to pass to fn\n * @returns {Array} a\n * @function\n */\nexport const forEach = (function() {\n let vec = create();\n\n return function(a, stride, offset, count, fn, arg) {\n let i, l;\n if(!stride) {\n stride = 4;\n }\n\n if(!offset) {\n offset = 0;\n }\n\n if(count) {\n l = Math.min((count * stride) + offset, a.length);\n } else {\n l = a.length;\n }\n\n for(i = offset; i < l; i += stride) {\n vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];\n fn(vec, vec, arg);\n a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];\n }\n\n return a;\n };\n})();\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nconst GL = WebGLRenderingContext; // For enums\n\nexport const CAP = {\n // Enable caps\n CULL_FACE: 0x001,\n BLEND: 0x002,\n DEPTH_TEST: 0x004,\n STENCIL_TEST: 0x008,\n COLOR_MASK: 0x010,\n DEPTH_MASK: 0x020,\n STENCIL_MASK: 0x040,\n};\n\nexport const MAT_STATE = {\n CAPS_RANGE: 0x000000FF,\n BLEND_SRC_SHIFT: 8,\n BLEND_SRC_RANGE: 0x00000F00,\n BLEND_DST_SHIFT: 12,\n BLEND_DST_RANGE: 0x0000F000,\n BLEND_FUNC_RANGE: 0x0000FF00,\n DEPTH_FUNC_SHIFT: 16,\n DEPTH_FUNC_RANGE: 0x000F0000,\n};\n\nexport const RENDER_ORDER = {\n // Render opaque objects first.\n OPAQUE: 0,\n\n // Render the sky after all opaque object to save fill rate.\n SKY: 1,\n\n // Render transparent objects next so that the opaqe objects show through.\n TRANSPARENT: 2,\n\n // Finally render purely additive effects like pointer rays so that they\n // can render without depth mask.\n ADDITIVE: 3,\n\n // Render order will be picked based on the material properties.\n DEFAULT: 4,\n};\n\nexport function stateToBlendFunc(state, mask, shift) {\n let value = (state & mask) >> shift;\n switch (value) {\n case 0:\n case 1:\n return value;\n default:\n return (value - 2) + GL.SRC_COLOR;\n }\n}\n\nexport class MaterialState {\n constructor() {\n this._state = CAP.CULL_FACE |\n CAP.DEPTH_TEST |\n CAP.COLOR_MASK |\n CAP.DEPTH_MASK;\n\n // Use a fairly commonly desired blend func as the default.\n this.blendFuncSrc = GL.SRC_ALPHA;\n this.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;\n\n this.depthFunc = GL.LESS;\n }\n\n get cullFace() {\n return !!(this._state & CAP.CULL_FACE);\n }\n set cullFace(value) {\n if (value) {\n this._state |= CAP.CULL_FACE;\n } else {\n this._state &= ~CAP.CULL_FACE;\n }\n }\n\n get blend() {\n return !!(this._state & CAP.BLEND);\n }\n set blend(value) {\n if (value) {\n this._state |= CAP.BLEND;\n } else {\n this._state &= ~CAP.BLEND;\n }\n }\n\n get depthTest() {\n return !!(this._state & CAP.DEPTH_TEST);\n }\n set depthTest(value) {\n if (value) {\n this._state |= CAP.DEPTH_TEST;\n } else {\n this._state &= ~CAP.DEPTH_TEST;\n }\n }\n\n get stencilTest() {\n return !!(this._state & CAP.STENCIL_TEST);\n }\n set stencilTest(value) {\n if (value) {\n this._state |= CAP.STENCIL_TEST;\n } else {\n this._state &= ~CAP.STENCIL_TEST;\n }\n }\n\n get colorMask() {\n return !!(this._state & CAP.COLOR_MASK);\n }\n set colorMask(value) {\n if (value) {\n this._state |= CAP.COLOR_MASK;\n } else {\n this._state &= ~CAP.COLOR_MASK;\n }\n }\n\n get depthMask() {\n return !!(this._state & CAP.DEPTH_MASK);\n }\n set depthMask(value) {\n if (value) {\n this._state |= CAP.DEPTH_MASK;\n } else {\n this._state &= ~CAP.DEPTH_MASK;\n }\n }\n\n get depthFunc() {\n return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;\n }\n set depthFunc(value) {\n value = value - GL.NEVER;\n this._state &= ~MAT_STATE.DEPTH_FUNC_RANGE;\n this._state |= (value << MAT_STATE.DEPTH_FUNC_SHIFT);\n }\n\n get stencilMask() {\n return !!(this._state & CAP.STENCIL_MASK);\n }\n set stencilMask(value) {\n if (value) {\n this._state |= CAP.STENCIL_MASK;\n } else {\n this._state &= ~CAP.STENCIL_MASK;\n }\n }\n\n get blendFuncSrc() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);\n }\n set blendFuncSrc(value) {\n switch (value) {\n case 0:\n case 1:\n break;\n default:\n value = (value - GL.SRC_COLOR) + 2;\n }\n this._state &= ~MAT_STATE.BLEND_SRC_RANGE;\n this._state |= (value << MAT_STATE.BLEND_SRC_SHIFT);\n }\n\n get blendFuncDst() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);\n }\n set blendFuncDst(value) {\n switch (value) {\n case 0:\n case 1:\n break;\n default:\n value = (value - GL.SRC_COLOR) + 2;\n }\n this._state &= ~MAT_STATE.BLEND_DST_RANGE;\n this._state |= (value << MAT_STATE.BLEND_DST_SHIFT);\n }\n}\n\nclass MaterialSampler {\n constructor(uniformName) {\n this._uniformName = uniformName;\n this._texture = null;\n }\n\n get texture() {\n return this._texture;\n }\n\n set texture(value) {\n this._texture = value;\n }\n}\n\nclass MaterialUniform {\n constructor(uniformName, defaultValue, length) {\n this._uniformName = uniformName;\n this._value = defaultValue;\n this._length = length;\n if (!this._length) {\n if (defaultValue instanceof Array) {\n this._length = defaultValue.length;\n } else {\n this._length = 1;\n }\n }\n }\n\n get value() {\n return this._value;\n }\n\n set value(value) {\n this._value = value;\n }\n}\n\nexport class Material {\n constructor() {\n this.state = new MaterialState;\n this.renderOrder = RENDER_ORDER.DEFAULT;\n this._samplers = [];\n this._uniforms = [];\n }\n\n defineSampler(uniformName) {\n let sampler = new MaterialSampler(uniformName);\n this._samplers.push(sampler);\n return sampler;\n }\n\n defineUniform(uniformName, defaultValue=null, length=0) {\n let uniform = new MaterialUniform(uniformName, defaultValue, length);\n this._uniforms.push(uniform);\n return uniform;\n }\n\n get materialName() {\n return null;\n }\n\n get vertexSource() {\n return null;\n }\n\n get fragmentSource() {\n return null;\n }\n\n getProgramDefines(renderPrimitive) {\n return {};\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Ray} from '../math/ray.js';\nimport {mat4, vec3, quat} from '../math/gl-matrix.js';\n\nconst DEFAULT_TRANSLATION = new Float32Array([0, 0, 0]);\nconst DEFAULT_ROTATION = new Float32Array([0, 0, 0, 1]);\nconst DEFAULT_SCALE = new Float32Array([1, 1, 1]);\n\nlet tmpRayMatrix = mat4.create();\n\nexport class Node {\n constructor() {\n this.name = null; // Only for debugging\n this.children = [];\n this.parent = null;\n this.visible = true;\n this.selectable = false;\n\n this._matrix = null;\n\n this._dirtyTRS = false;\n this._translation = null;\n this._rotation = null;\n this._scale = null;\n\n this._dirtyWorldMatrix = false;\n this._worldMatrix = null;\n\n this._activeFrameId = -1;\n this._hoverFrameId = -1;\n this._renderPrimitives = null;\n this._renderer = null;\n\n this._selectHandler = null;\n }\n\n _setRenderer(renderer) {\n if (this._renderer == renderer) {\n return;\n }\n\n if (this._renderer) {\n // Changing the renderer removes any previously attached renderPrimitives\n // from a different renderer.\n this.clearRenderPrimitives();\n }\n\n this._renderer = renderer;\n if (renderer) {\n this.onRendererChanged(renderer);\n\n for (let child of this.children) {\n child._setRenderer(renderer);\n }\n }\n }\n\n onRendererChanged(renderer) {\n // Override in other node types to respond to changes in the renderer.\n }\n\n // Create a clone of this node and all of it's children. Does not duplicate\n // RenderPrimitives, the cloned nodes will be treated as new instances of the\n // geometry.\n clone() {\n let cloneNode = new Node();\n cloneNode.name = this.name;\n cloneNode.visible = this.visible;\n cloneNode._renderer = this._renderer;\n\n cloneNode._dirtyTRS = this._dirtyTRS;\n\n if (this._translation) {\n cloneNode._translation = vec3.create();\n vec3.copy(cloneNode._translation, this._translation);\n }\n\n if (this._rotation) {\n cloneNode._rotation = quat.create();\n quat.copy(cloneNode._rotation, this._rotation);\n }\n\n if (this._scale) {\n cloneNode._scale = vec3.create();\n vec3.copy(cloneNode._scale, this._scale);\n }\n\n // Only copy the matrices if they're not already dirty.\n if (!cloneNode._dirtyTRS && this._matrix) {\n cloneNode._matrix = mat4.create();\n mat4.copy(cloneNode._matrix, this._matrix);\n }\n\n cloneNode._dirtyWorldMatrix = this._dirtyWorldMatrix;\n if (!cloneNode._dirtyWorldMatrix && this._worldMatrix) {\n cloneNode._worldMatrix = mat4.create();\n mat4.copy(cloneNode._worldMatrix, this._worldMatrix);\n }\n\n this.waitForComplete().then(() => {\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n cloneNode.addRenderPrimitive(primitive);\n }\n }\n\n for (let child of this.children) {\n cloneNode.addNode(child.clone());\n }\n });\n\n return cloneNode;\n }\n\n markActive(frameId) {\n if (this.visible && this._renderPrimitives) {\n this._activeFrameId = frameId;\n for (let primitive of this._renderPrimitives) {\n primitive.markActive(frameId);\n }\n }\n\n for (let child of this.children) {\n if (child.visible) {\n child.markActive(frameId);\n }\n }\n }\n\n addNode(value) {\n if (!value || value.parent == this) {\n return;\n }\n\n if (value.parent) {\n value.parent.removeNode(value);\n }\n value.parent = this;\n\n this.children.push(value);\n\n if (this._renderer) {\n value._setRenderer(this._renderer);\n }\n }\n\n removeNode(value) {\n let i = this.children.indexOf(value);\n if (i > -1) {\n this.children.splice(i, 1);\n value.parent = null;\n }\n }\n\n clearNodes() {\n for (let child of this.children) {\n child.parent = null;\n }\n this.children = [];\n }\n\n setMatrixDirty() {\n if (!this._dirtyWorldMatrix) {\n this._dirtyWorldMatrix = true;\n for (let child of this.children) {\n child.setMatrixDirty();\n }\n }\n }\n\n _updateLocalMatrix() {\n if (!this._matrix) {\n this._matrix = mat4.create();\n }\n\n if (this._dirtyTRS) {\n this._dirtyTRS = false;\n mat4.fromRotationTranslationScale(\n this._matrix,\n this._rotation || DEFAULT_ROTATION,\n this._translation || DEFAULT_TRANSLATION,\n this._scale || DEFAULT_SCALE);\n }\n\n return this._matrix;\n }\n\n set matrix(value) {\n if (value) {\n if (!this._matrix) {\n this._matrix = mat4.create();\n }\n mat4.copy(this._matrix, value);\n } else {\n this._matrix = null;\n }\n this.setMatrixDirty();\n this._dirtyTRS = false;\n this._translation = null;\n this._rotation = null;\n this._scale = null;\n }\n\n get matrix() {\n this.setMatrixDirty();\n\n return this._updateLocalMatrix();\n }\n\n get worldMatrix() {\n if (!this._worldMatrix) {\n this._dirtyWorldMatrix = true;\n this._worldMatrix = mat4.create();\n }\n\n if (this._dirtyWorldMatrix || this._dirtyTRS) {\n if (this.parent) {\n // TODO: Some optimizations that could be done here if the node matrix\n // is an identity matrix.\n mat4.mul(this._worldMatrix, this.parent.worldMatrix, this._updateLocalMatrix());\n } else {\n mat4.copy(this._worldMatrix, this._updateLocalMatrix());\n }\n this._dirtyWorldMatrix = false;\n }\n\n return this._worldMatrix;\n }\n\n // TODO: Decompose matrix when fetching these?\n set translation(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._translation = value;\n }\n\n get translation() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._translation) {\n this._translation = vec3.clone(DEFAULT_TRANSLATION);\n }\n return this._translation;\n }\n\n set rotation(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._rotation = value;\n }\n\n get rotation() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._rotation) {\n this._rotation = quat.clone(DEFAULT_ROTATION);\n }\n return this._rotation;\n }\n\n set scale(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._scale = value;\n }\n\n get scale() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._scale) {\n this._scale = vec3.clone(DEFAULT_SCALE);\n }\n return this._scale;\n }\n\n waitForComplete() {\n let childPromises = [];\n for (let child of this.children) {\n childPromises.push(child.waitForComplete());\n }\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n childPromises.push(primitive.waitForComplete());\n }\n }\n return Promise.all(childPromises).then(() => this);\n }\n\n get renderPrimitives() {\n return this._renderPrimitives;\n }\n\n addRenderPrimitive(primitive) {\n if (!this._renderPrimitives) {\n this._renderPrimitives = [primitive];\n } else {\n this._renderPrimitives.push(primitive);\n }\n primitive._instances.push(this);\n }\n\n removeRenderPrimitive(primitive) {\n if (!this._renderPrimitives) {\n return;\n }\n\n let index = this._renderPrimitives._instances.indexOf(primitive);\n if (index > -1) {\n this._renderPrimitives._instances.splice(index, 1);\n\n index = primitive._instances.indexOf(this);\n if (index > -1) {\n primitive._instances.splice(index, 1);\n }\n\n if (!this._renderPrimitives.length) {\n this._renderPrimitives = null;\n }\n }\n }\n\n clearRenderPrimitives() {\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n let index = primitive._instances.indexOf(this);\n if (index > -1) {\n primitive._instances.splice(index, 1);\n }\n }\n this._renderPrimitives = null;\n }\n }\n\n _hitTestSelectableNode(ray) {\n if (this._renderPrimitives) {\n let localRay = null;\n for (let primitive of this._renderPrimitives) {\n if (primitive._min) {\n if (!localRay) {\n mat4.invert(tmpRayMatrix, this.worldMatrix);\n mat4.multiply(tmpRayMatrix, tmpRayMatrix, ray.transformMatrix);\n localRay = new Ray(tmpRayMatrix);\n }\n let intersection = localRay.intersectsAABB(primitive._min, primitive._max);\n if (intersection) {\n vec3.transformMat4(intersection, intersection, this.worldMatrix);\n return intersection;\n }\n }\n }\n }\n for (let child of this.children) {\n let intersection = child._hitTestSelectableNode(ray);\n if (intersection) {\n return intersection;\n }\n }\n return null;\n }\n\n hitTest(ray) {\n if (this.selectable && this.visible) {\n let intersection = this._hitTestSelectableNode(ray);\n\n if (intersection) {\n let origin = vec3.fromValues(ray.origin.x, ray.origin.y, ray.origin.z);\n return {\n node: this,\n intersection: intersection,\n distance: vec3.distance(origin, intersection),\n };\n }\n return null;\n }\n\n let result = null;\n for (let child of this.children) {\n let childResult = child.hitTest(ray);\n if (childResult) {\n if (!result || result.distance > childResult.distance) {\n result = childResult;\n }\n }\n }\n return result;\n }\n\n onSelect(value) {\n this._selectHandler = value;\n }\n\n get selectHandler() {\n return this._selectHandler;\n }\n\n // Called when a selectable node is selected.\n handleSelect() {\n if (this._selectHandler) {\n this._selectHandler();\n }\n }\n\n // Called when a selectable element is pointed at.\n onHoverStart() {\n\n }\n\n // Called when a selectable element is no longer pointed at.\n onHoverEnd() {\n\n }\n\n _update(timestamp, frameDelta) {\n this.onUpdate(timestamp, frameDelta);\n\n for (let child of this.children) {\n child._update(timestamp, frameDelta);\n }\n }\n\n // Called every frame so that the nodes can animate themselves\n onUpdate(timestamp, frameDelta) {\n\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {vec3} from '../math/gl-matrix.js';\n\nexport class PrimitiveAttribute {\n constructor(name, buffer, componentCount, componentType, stride, byteOffset) {\n this.name = name;\n this.buffer = buffer;\n this.componentCount = componentCount || 3;\n this.componentType = componentType || 5126; // gl.FLOAT;\n this.stride = stride || 0;\n this.byteOffset = byteOffset || 0;\n this.normalized = false;\n }\n}\n\nexport class Primitive {\n constructor(attributes, elementCount, mode) {\n this.attributes = attributes || [];\n this.elementCount = elementCount || 0;\n this.mode = mode || 4; // gl.TRIANGLES;\n this.indexBuffer = null;\n this.indexByteOffset = 0;\n this.indexType = 0;\n this._min = null;\n this._max = null;\n }\n\n setIndexBuffer(indexBuffer, byteOffset, indexType) {\n this.indexBuffer = indexBuffer;\n this.indexByteOffset = byteOffset || 0;\n this.indexType = indexType || 5123; // gl.UNSIGNED_SHORT;\n }\n\n setBounds(min, max) {\n this._min = vec3.clone(min);\n this._max = vec3.clone(max);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nexport class Program {\n constructor(gl, vertSrc, fragSrc, attribMap, defines) {\n this._gl = gl;\n this.program = gl.createProgram();\n this.attrib = null;\n this.uniform = null;\n this.defines = {};\n\n this._firstUse = true;\n this._nextUseCallbacks = [];\n\n let definesString = '';\n if (defines) {\n for (let define in defines) {\n this.defines[define] = defines[define];\n definesString += `#define ${define} ${defines[define]}\\n`;\n }\n }\n\n this._vertShader = gl.createShader(gl.VERTEX_SHADER);\n gl.attachShader(this.program, this._vertShader);\n gl.shaderSource(this._vertShader, definesString + vertSrc);\n gl.compileShader(this._vertShader);\n\n this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);\n gl.attachShader(this.program, this._fragShader);\n gl.shaderSource(this._fragShader, definesString + fragSrc);\n gl.compileShader(this._fragShader);\n\n if (attribMap) {\n this.attrib = {};\n for (let attribName in attribMap) {\n gl.bindAttribLocation(this.program, attribMap[attribName], attribName);\n this.attrib[attribName] = attribMap[attribName];\n }\n }\n\n gl.linkProgram(this.program);\n }\n\n onNextUse(callback) {\n this._nextUseCallbacks.push(callback);\n }\n\n use() {\n let gl = this._gl;\n\n // If this is the first time the program has been used do all the error checking and\n // attrib/uniform querying needed.\n if (this._firstUse) {\n this._firstUse = false;\n if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {\n if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {\n console.error('Vertex shader compile error: ' + gl.getShaderInfoLog(this._vertShader));\n } else if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {\n console.error('Fragment shader compile error: ' + gl.getShaderInfoLog(this._fragShader));\n } else {\n console.error('Program link error: ' + gl.getProgramInfoLog(this.program));\n }\n gl.deleteProgram(this.program);\n this.program = null;\n } else {\n if (!this.attrib) {\n this.attrib = {};\n let attribCount = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);\n for (let i = 0; i < attribCount; i++) {\n let attribInfo = gl.getActiveAttrib(this.program, i);\n this.attrib[attribInfo.name] = gl.getAttribLocation(this.program, attribInfo.name);\n }\n }\n\n this.uniform = {};\n let uniformCount = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);\n let uniformName = '';\n for (let i = 0; i < uniformCount; i++) {\n let uniformInfo = gl.getActiveUniform(this.program, i);\n uniformName = uniformInfo.name.replace('[0]', '');\n this.uniform[uniformName] = gl.getUniformLocation(this.program, uniformName);\n }\n }\n gl.deleteShader(this._vertShader);\n gl.deleteShader(this._fragShader);\n }\n\n gl.useProgram(this.program);\n\n if (this._nextUseCallbacks.length) {\n for (let callback of this._nextUseCallbacks) {\n callback(this);\n }\n this._nextUseCallbacks = [];\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {CAP, MAT_STATE, RENDER_ORDER, stateToBlendFunc} from './material.js';\nimport {Node} from './node.js';\nimport {Program} from './program.js';\nimport {DataTexture, VideoTexture} from './texture.js';\nimport {mat4, vec3} from '../math/gl-matrix.js';\n\nexport const ATTRIB = {\n POSITION: 1,\n NORMAL: 2,\n TANGENT: 3,\n TEXCOORD_0: 4,\n TEXCOORD_1: 5,\n COLOR_0: 6,\n};\n\nexport const ATTRIB_MASK = {\n POSITION: 0x0001,\n NORMAL: 0x0002,\n TANGENT: 0x0004,\n TEXCOORD_0: 0x0008,\n TEXCOORD_1: 0x0010,\n COLOR_0: 0x0020,\n};\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst DEF_LIGHT_DIR = new Float32Array([-0.1, -1.0, -0.2]);\nconst DEF_LIGHT_COLOR = new Float32Array([3.0, 3.0, 3.0]);\n\nconst PRECISION_REGEX = new RegExp('precision (lowp|mediump|highp) float;');\n\nconst VERTEX_SHADER_SINGLE_ENTRY = `\nuniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;\n\nvoid main() {\n gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);\n}\n`;\n\nconst VERTEX_SHADER_MULTI_ENTRY = `\n#ERROR Multiview rendering is not implemented\nvoid main() {\n gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER_ENTRY = `\nvoid main() {\n gl_FragColor = fragment_main();\n}\n`;\n\nfunction isPowerOfTwo(n) {\n return (n & (n - 1)) === 0;\n}\n\n// Creates a WebGL context and initializes it with some common default state.\nexport function createWebGLContext(glAttribs) {\n glAttribs = glAttribs || {alpha: false};\n\n let webglCanvas = document.createElement('canvas');\n let contextTypes = glAttribs.webgl2 ? ['webgl2'] : ['webgl', 'experimental-webgl'];\n let context = null;\n\n for (let contextType of contextTypes) {\n context = webglCanvas.getContext(contextType, glAttribs);\n if (context) {\n break;\n }\n }\n\n if (!context) {\n let webglType = (glAttribs.webgl2 ? 'WebGL 2' : 'WebGL');\n console.error('This browser does not support ' + webglType + '.');\n return null;\n }\n\n return context;\n}\n\nexport class RenderView {\n constructor(projectionMatrix, viewMatrix, viewport = null, eye = 'left') {\n this.projectionMatrix = projectionMatrix;\n this.viewMatrix = viewMatrix;\n this.viewport = viewport;\n // If an eye isn't given the left eye is assumed.\n this._eye = eye;\n this._eyeIndex = (eye == 'left' ? 0 : 1);\n }\n\n get eye() {\n return this._eye;\n }\n\n set eye(value) {\n this._eye = value;\n this._eyeIndex = (value == 'left' ? 0 : 1);\n }\n\n get eyeIndex() {\n return this._eyeIndex;\n }\n}\n\nclass RenderBuffer {\n constructor(target, usage, buffer, length = 0) {\n this._target = target;\n this._usage = usage;\n this._length = length;\n if (buffer instanceof Promise) {\n this._buffer = null;\n this._promise = buffer.then((buffer) => {\n this._buffer = buffer;\n return this;\n });\n } else {\n this._buffer = buffer;\n this._promise = Promise.resolve(this);\n }\n }\n\n waitForComplete() {\n return this._promise;\n }\n}\n\nclass RenderPrimitiveAttribute {\n constructor(primitiveAttribute) {\n this._attrib_index = ATTRIB[primitiveAttribute.name];\n this._componentCount = primitiveAttribute.componentCount;\n this._componentType = primitiveAttribute.componentType;\n this._stride = primitiveAttribute.stride;\n this._byteOffset = primitiveAttribute.byteOffset;\n this._normalized = primitiveAttribute.normalized;\n }\n}\n\nclass RenderPrimitiveAttributeBuffer {\n constructor(buffer) {\n this._buffer = buffer;\n this._attributes = [];\n }\n}\n\nclass RenderPrimitive {\n constructor(primitive) {\n this._activeFrameId = 0;\n this._instances = [];\n this._material = null;\n\n this.setPrimitive(primitive);\n }\n\n setPrimitive(primitive) {\n this._mode = primitive.mode;\n this._elementCount = primitive.elementCount;\n this._promise = null;\n this._vao = null;\n this._complete = false;\n this._attributeBuffers = [];\n this._attributeMask = 0;\n\n for (let attribute of primitive.attributes) {\n this._attributeMask |= ATTRIB_MASK[attribute.name];\n let renderAttribute = new RenderPrimitiveAttribute(attribute);\n let foundBuffer = false;\n for (let attributeBuffer of this._attributeBuffers) {\n if (attributeBuffer._buffer == attribute.buffer) {\n attributeBuffer._attributes.push(renderAttribute);\n foundBuffer = true;\n break;\n }\n }\n if (!foundBuffer) {\n let attributeBuffer = new RenderPrimitiveAttributeBuffer(attribute.buffer);\n attributeBuffer._attributes.push(renderAttribute);\n this._attributeBuffers.push(attributeBuffer);\n }\n }\n\n this._indexBuffer = null;\n this._indexByteOffset = 0;\n this._indexType = 0;\n\n if (primitive.indexBuffer) {\n this._indexByteOffset = primitive.indexByteOffset;\n this._indexType = primitive.indexType;\n this._indexBuffer = primitive.indexBuffer;\n }\n\n if (primitive._min) {\n this._min = vec3.clone(primitive._min);\n this._max = vec3.clone(primitive._max);\n } else {\n this._min = null;\n this._max = null;\n }\n\n if (this._material != null) {\n this.waitForComplete(); // To flip the _complete flag.\n }\n }\n\n setRenderMaterial(material) {\n this._material = material;\n this._promise = null;\n this._complete = false;\n\n if (this._material != null) {\n this.waitForComplete(); // To flip the _complete flag.\n }\n }\n\n markActive(frameId) {\n if (this._complete && this._activeFrameId != frameId) {\n if (this._material) {\n if (!this._material.markActive(frameId)) {\n return;\n }\n }\n this._activeFrameId = frameId;\n }\n }\n\n get samplers() {\n return this._material._samplerDictionary;\n }\n\n get uniforms() {\n return this._material._uniform_dictionary;\n }\n\n waitForComplete() {\n if (!this._promise) {\n if (!this._material) {\n return Promise.reject('RenderPrimitive does not have a material');\n }\n\n let completionPromises = [];\n\n for (let attributeBuffer of this._attributeBuffers) {\n if (!attributeBuffer._buffer._buffer) {\n completionPromises.push(attributeBuffer._buffer._promise);\n }\n }\n\n if (this._indexBuffer && !this._indexBuffer._buffer) {\n completionPromises.push(this._indexBuffer._promise);\n }\n\n this._promise = Promise.all(completionPromises).then(() => {\n this._complete = true;\n return this;\n });\n }\n return this._promise;\n }\n}\n\nexport class RenderTexture {\n constructor(texture) {\n this._texture = texture;\n this._complete = false;\n this._activeFrameId = 0;\n this._activeCallback = null;\n }\n\n markActive(frameId) {\n if (this._activeCallback && this._activeFrameId != frameId) {\n this._activeFrameId = frameId;\n this._activeCallback(this);\n }\n }\n}\n\nconst inverseMatrix = mat4.create();\n\nfunction setCap(gl, glEnum, cap, prevState, state) {\n let change = (state & cap) - (prevState & cap);\n if (!change) {\n return;\n }\n\n if (change > 0) {\n gl.enable(glEnum);\n } else {\n gl.disable(glEnum);\n }\n}\n\nclass RenderMaterialSampler {\n constructor(renderer, materialSampler, index) {\n this._renderer = renderer;\n this._uniformName = materialSampler._uniformName;\n this._renderTexture = renderer._getRenderTexture(materialSampler._texture);\n this._index = index;\n }\n\n set texture(value) {\n this._renderTexture = this._renderer._getRenderTexture(value);\n }\n}\n\nclass RenderMaterialUniform {\n constructor(materialUniform) {\n this._uniformName = materialUniform._uniformName;\n this._uniform = null;\n this._length = materialUniform._length;\n if (materialUniform._value instanceof Array) {\n this._value = new Float32Array(materialUniform._value);\n } else {\n this._value = new Float32Array([materialUniform._value]);\n }\n }\n\n set value(value) {\n if (this._value.length == 1) {\n this._value[0] = value;\n } else {\n for (let i = 0; i < this._value.length; ++i) {\n this._value[i] = value[i];\n }\n }\n }\n}\n\nclass RenderMaterial {\n constructor(renderer, material, program) {\n this._program = program;\n this._state = material.state._state;\n this._activeFrameId = 0;\n this._completeForActiveFrame = false;\n\n this._samplerDictionary = {};\n this._samplers = [];\n for (let i = 0; i < material._samplers.length; ++i) {\n let renderSampler = new RenderMaterialSampler(renderer, material._samplers[i], i);\n this._samplers.push(renderSampler);\n this._samplerDictionary[renderSampler._uniformName] = renderSampler;\n }\n\n this._uniform_dictionary = {};\n this._uniforms = [];\n for (let uniform of material._uniforms) {\n let renderUniform = new RenderMaterialUniform(uniform);\n this._uniforms.push(renderUniform);\n this._uniform_dictionary[renderUniform._uniformName] = renderUniform;\n }\n\n this._firstBind = true;\n\n this._renderOrder = material.renderOrder;\n if (this._renderOrder == RENDER_ORDER.DEFAULT) {\n if (this._state & CAP.BLEND) {\n this._renderOrder = RENDER_ORDER.TRANSPARENT;\n } else {\n this._renderOrder = RENDER_ORDER.OPAQUE;\n }\n }\n }\n\n bind(gl) {\n // First time we do a binding, cache the uniform locations and remove\n // unused uniforms from the list.\n if (this._firstBind) {\n for (let i = 0; i < this._samplers.length;) {\n let sampler = this._samplers[i];\n if (!this._program.uniform[sampler._uniformName]) {\n this._samplers.splice(i, 1);\n continue;\n }\n ++i;\n }\n\n for (let i = 0; i < this._uniforms.length;) {\n let uniform = this._uniforms[i];\n uniform._uniform = this._program.uniform[uniform._uniformName];\n if (!uniform._uniform) {\n this._uniforms.splice(i, 1);\n continue;\n }\n ++i;\n }\n this._firstBind = false;\n }\n\n for (let sampler of this._samplers) {\n gl.activeTexture(gl.TEXTURE0 + sampler._index);\n if (sampler._renderTexture && sampler._renderTexture._complete) {\n gl.bindTexture(gl.TEXTURE_2D, sampler._renderTexture._texture);\n } else {\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n }\n\n for (let uniform of this._uniforms) {\n switch (uniform._length) {\n case 1: gl.uniform1fv(uniform._uniform, uniform._value); break;\n case 2: gl.uniform2fv(uniform._uniform, uniform._value); break;\n case 3: gl.uniform3fv(uniform._uniform, uniform._value); break;\n case 4: gl.uniform4fv(uniform._uniform, uniform._value); break;\n }\n }\n }\n\n markActive(frameId) {\n if (this._activeFrameId != frameId) {\n this._activeFrameId = frameId;\n this._completeForActiveFrame = true;\n for (let i = 0; i < this._samplers.length; ++i) {\n let sampler = this._samplers[i];\n if (sampler._renderTexture) {\n if (!sampler._renderTexture._complete) {\n this._completeForActiveFrame = false;\n break;\n }\n sampler._renderTexture.markActive(frameId);\n }\n }\n }\n return this._completeForActiveFrame;\n }\n\n // Material State fetchers\n get cullFace() {\n return !!(this._state & CAP.CULL_FACE);\n }\n get blend() {\n return !!(this._state & CAP.BLEND);\n }\n get depthTest() {\n return !!(this._state & CAP.DEPTH_TEST);\n }\n get stencilTest() {\n return !!(this._state & CAP.STENCIL_TEST);\n }\n get colorMask() {\n return !!(this._state & CAP.COLOR_MASK);\n }\n get depthMask() {\n return !!(this._state & CAP.DEPTH_MASK);\n }\n get stencilMask() {\n return !!(this._state & CAP.STENCIL_MASK);\n }\n get depthFunc() {\n return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;\n }\n get blendFuncSrc() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);\n }\n get blendFuncDst() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);\n }\n\n // Only really for use from the renderer\n _capsDiff(otherState) {\n return (otherState & MAT_STATE.CAPS_RANGE) ^ (this._state & MAT_STATE.CAPS_RANGE);\n }\n\n _blendDiff(otherState) {\n if (!(this._state & CAP.BLEND)) {\n return 0;\n }\n return (otherState & MAT_STATE.BLEND_FUNC_RANGE) ^ (this._state & MAT_STATE.BLEND_FUNC_RANGE);\n }\n\n _depthFuncDiff(otherState) {\n if (!(this._state & CAP.DEPTH_TEST)) {\n return 0;\n }\n return (otherState & MAT_STATE.DEPTH_FUNC_RANGE) ^ (this._state & MAT_STATE.DEPTH_FUNC_RANGE);\n }\n}\n\nexport class Renderer {\n constructor(gl) {\n this._gl = gl || createWebGLContext();\n this._frameId = 0;\n this._programCache = {};\n this._textureCache = {};\n this._renderPrimitives = Array(RENDER_ORDER.DEFAULT);\n this._cameraPositions = [];\n\n this._vaoExt = gl.getExtension('OES_vertex_array_object');\n\n let fragHighPrecision = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);\n this._defaultFragPrecision = fragHighPrecision.precision > 0 ? 'highp' : 'mediump';\n\n this._depthMaskNeedsReset = false;\n this._colorMaskNeedsReset = false;\n\n this._globalLightColor = vec3.clone(DEF_LIGHT_COLOR);\n this._globalLightDir = vec3.clone(DEF_LIGHT_DIR);\n }\n\n get gl() {\n return this._gl;\n }\n\n set globalLightColor(value) {\n vec3.copy(this._globalLightColor, value);\n }\n\n get globalLightColor() {\n return vec3.clone(this._globalLightColor);\n }\n\n set globalLightDir(value) {\n vec3.copy(this._globalLightDir, value);\n }\n\n get globalLightDir() {\n return vec3.clone(this._globalLightDir);\n }\n\n createRenderBuffer(target, data, usage = GL.STATIC_DRAW) {\n let gl = this._gl;\n let glBuffer = gl.createBuffer();\n\n if (data instanceof Promise) {\n let renderBuffer = new RenderBuffer(target, usage, data.then((data) => {\n gl.bindBuffer(target, glBuffer);\n gl.bufferData(target, data, usage);\n renderBuffer._length = data.byteLength;\n return glBuffer;\n }));\n return renderBuffer;\n } else {\n gl.bindBuffer(target, glBuffer);\n gl.bufferData(target, data, usage);\n return new RenderBuffer(target, usage, glBuffer, data.byteLength);\n }\n }\n\n updateRenderBuffer(buffer, data, offset = 0) {\n if (buffer._buffer) {\n let gl = this._gl;\n gl.bindBuffer(buffer._target, buffer._buffer);\n if (offset == 0 && buffer._length == data.byteLength) {\n gl.bufferData(buffer._target, data, buffer._usage);\n } else {\n gl.bufferSubData(buffer._target, offset, data);\n }\n } else {\n buffer.waitForComplete().then((buffer) => {\n this.updateRenderBuffer(buffer, data, offset);\n });\n }\n }\n\n createRenderPrimitive(primitive, material) {\n let renderPrimitive = new RenderPrimitive(primitive);\n\n let program = this._getMaterialProgram(material, renderPrimitive);\n let renderMaterial = new RenderMaterial(this, material, program);\n renderPrimitive.setRenderMaterial(renderMaterial);\n\n if (!this._renderPrimitives[renderMaterial._renderOrder]) {\n this._renderPrimitives[renderMaterial._renderOrder] = [];\n }\n\n this._renderPrimitives[renderMaterial._renderOrder].push(renderPrimitive);\n\n return renderPrimitive;\n }\n\n createMesh(primitive, material) {\n let meshNode = new Node();\n meshNode.addRenderPrimitive(this.createRenderPrimitive(primitive, material));\n return meshNode;\n }\n\n drawViews(views, rootNode) {\n if (!rootNode) {\n return;\n }\n\n let gl = this._gl;\n this._frameId++;\n\n rootNode.markActive(this._frameId);\n\n // If there's only one view then flip the algorithm a bit so that we're only\n // setting the viewport once.\n if (views.length == 1 && views[0].viewport) {\n let vp = views[0].viewport;\n this._gl.viewport(vp.x, vp.y, vp.width, vp.height);\n }\n\n // Get the positions of the 'camera' for each view matrix.\n for (let i = 0; i < views.length; ++i) {\n mat4.invert(inverseMatrix, views[i].viewMatrix);\n\n if (this._cameraPositions.length <= i) {\n this._cameraPositions.push(vec3.create());\n }\n let cameraPosition = this._cameraPositions[i];\n vec3.set(cameraPosition, 0, 0, 0);\n vec3.transformMat4(cameraPosition, cameraPosition, inverseMatrix);\n }\n\n // Draw each set of render primitives in order\n for (let renderPrimitives of this._renderPrimitives) {\n if (renderPrimitives && renderPrimitives.length) {\n this._drawRenderPrimitiveSet(views, renderPrimitives);\n }\n }\n\n if (this._vaoExt) {\n this._vaoExt.bindVertexArrayOES(null);\n }\n\n if (this._depthMaskNeedsReset) {\n gl.depthMask(true);\n }\n if (this._colorMaskNeedsReset) {\n gl.colorMask(true, true, true, true);\n }\n }\n\n _drawRenderPrimitiveSet(views, renderPrimitives) {\n let gl = this._gl;\n let program = null;\n let material = null;\n let attribMask = 0;\n\n // Loop through every primitive known to the renderer.\n for (let primitive of renderPrimitives) {\n // Skip over those that haven't been marked as active for this frame.\n if (primitive._activeFrameId != this._frameId) {\n continue;\n }\n\n // Bind the primitive material's program if it's different than the one we\n // were using for the previous primitive.\n // TODO: The ording of this could be more efficient.\n if (program != primitive._material._program) {\n program = primitive._material._program;\n program.use();\n\n if (program.uniform.LIGHT_DIRECTION) {\n gl.uniform3fv(program.uniform.LIGHT_DIRECTION, this._globalLightDir);\n }\n\n if (program.uniform.LIGHT_COLOR) {\n gl.uniform3fv(program.uniform.LIGHT_COLOR, this._globalLightColor);\n }\n\n if (views.length == 1) {\n gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, views[0].projectionMatrix);\n gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, views[0].viewMatrix);\n gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[0]);\n gl.uniform1i(program.uniform.EYE_INDEX, views[0].eyeIndex);\n }\n }\n\n if (material != primitive._material) {\n this._bindMaterialState(primitive._material, material);\n primitive._material.bind(gl, program, material);\n material = primitive._material;\n }\n\n if (this._vaoExt) {\n if (primitive._vao) {\n this._vaoExt.bindVertexArrayOES(primitive._vao);\n } else {\n primitive._vao = this._vaoExt.createVertexArrayOES();\n this._vaoExt.bindVertexArrayOES(primitive._vao);\n this._bindPrimitive(primitive);\n }\n } else {\n this._bindPrimitive(primitive, attribMask);\n attribMask = primitive._attributeMask;\n }\n\n for (let i = 0; i < views.length; ++i) {\n let view = views[i];\n if (views.length > 1) {\n if (view.viewport) {\n let vp = view.viewport;\n gl.viewport(vp.x, vp.y, vp.width, vp.height);\n }\n gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, view.projectionMatrix);\n gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, view.viewMatrix);\n gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[i]);\n gl.uniform1i(program.uniform.EYE_INDEX, view.eyeIndex);\n }\n\n for (let instance of primitive._instances) {\n if (instance._activeFrameId != this._frameId) {\n continue;\n }\n\n gl.uniformMatrix4fv(program.uniform.MODEL_MATRIX, false, instance.worldMatrix);\n\n if (primitive._indexBuffer) {\n gl.drawElements(primitive._mode, primitive._elementCount,\n primitive._indexType, primitive._indexByteOffset);\n } else {\n gl.drawArrays(primitive._mode, 0, primitive._elementCount);\n }\n }\n }\n }\n }\n\n _getRenderTexture(texture) {\n if (!texture) {\n return null;\n }\n\n let key = texture.textureKey;\n if (!key) {\n throw new Error('Texure does not have a valid key');\n }\n\n if (key in this._textureCache) {\n return this._textureCache[key];\n } else {\n let gl = this._gl;\n let textureHandle = gl.createTexture();\n\n let renderTexture = new RenderTexture(textureHandle);\n this._textureCache[key] = renderTexture;\n\n if (texture instanceof DataTexture) {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.width, texture.height,\n 0, texture.format, texture._type, texture._data);\n this._setSamplerParameters(texture);\n renderTexture._complete = true;\n } else {\n texture.waitForComplete().then(() => {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);\n this._setSamplerParameters(texture);\n renderTexture._complete = true;\n\n if (texture instanceof VideoTexture) {\n // Once the video starts playing, set a callback to update it's\n // contents each frame.\n texture._video.addEventListener('playing', () => {\n renderTexture._activeCallback = () => {\n if (!texture._video.paused && !texture._video.waiting) {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);\n }\n };\n });\n }\n });\n }\n\n return renderTexture;\n }\n }\n\n _setSamplerParameters(texture) {\n let gl = this._gl;\n\n let sampler = texture.sampler;\n let powerOfTwo = isPowerOfTwo(texture.width) && isPowerOfTwo(texture.height);\n let mipmap = powerOfTwo && texture.mipmap;\n if (mipmap) {\n gl.generateMipmap(gl.TEXTURE_2D);\n }\n\n let minFilter = sampler.minFilter || (mipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);\n let wrapS = sampler.wrapS || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);\n let wrapT = sampler.wrapT || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);\n\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, sampler.magFilter || gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);\n }\n\n _getProgramKey(name, defines) {\n let key = `${name}:`;\n\n for (let define in defines) {\n key += `${define}=${defines[define]},`;\n }\n\n return key;\n }\n\n _getMaterialProgram(material, renderPrimitive) {\n let materialName = material.materialName;\n let vertexSource = material.vertexSource;\n let fragmentSource = material.fragmentSource;\n\n // These should always be defined for every material\n if (materialName == null) {\n throw new Error('Material does not have a name');\n }\n if (vertexSource == null) {\n throw new Error(`Material \"${materialName}\" does not have a vertex source`);\n }\n if (fragmentSource == null) {\n throw new Error(`Material \"${materialName}\" does not have a fragment source`);\n }\n\n let defines = material.getProgramDefines(renderPrimitive);\n let key = this._getProgramKey(materialName, defines);\n\n if (key in this._programCache) {\n return this._programCache[key];\n } else {\n let multiview = false; // Handle this dynamically later\n let fullVertexSource = vertexSource;\n fullVertexSource += multiview ? VERTEX_SHADER_MULTI_ENTRY :\n VERTEX_SHADER_SINGLE_ENTRY;\n\n let precisionMatch = fragmentSource.match(PRECISION_REGEX);\n let fragPrecisionHeader = precisionMatch ? '' : `precision ${this._defaultFragPrecision} float;\\n`;\n\n let fullFragmentSource = fragPrecisionHeader + fragmentSource;\n fullFragmentSource += FRAGMENT_SHADER_ENTRY;\n\n let program = new Program(this._gl, fullVertexSource, fullFragmentSource, ATTRIB, defines);\n this._programCache[key] = program;\n\n program.onNextUse((program) => {\n // Bind the samplers to the right texture index. This is constant for\n // the lifetime of the program.\n for (let i = 0; i < material._samplers.length; ++i) {\n let sampler = material._samplers[i];\n let uniform = program.uniform[sampler._uniformName];\n if (uniform) {\n this._gl.uniform1i(uniform, i);\n }\n }\n });\n\n return program;\n }\n }\n\n _bindPrimitive(primitive, attribMask) {\n let gl = this._gl;\n\n // If the active attributes have changed then update the active set.\n if (attribMask != primitive._attributeMask) {\n for (let attrib in ATTRIB) {\n if (primitive._attributeMask & ATTRIB_MASK[attrib]) {\n gl.enableVertexAttribArray(ATTRIB[attrib]);\n } else {\n gl.disableVertexAttribArray(ATTRIB[attrib]);\n }\n }\n }\n\n // Bind the primitive attributes and indices.\n for (let attributeBuffer of primitive._attributeBuffers) {\n gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer._buffer._buffer);\n for (let attrib of attributeBuffer._attributes) {\n gl.vertexAttribPointer(\n attrib._attrib_index, attrib._componentCount, attrib._componentType,\n attrib._normalized, attrib._stride, attrib._byteOffset);\n }\n }\n\n if (primitive._indexBuffer) {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, primitive._indexBuffer._buffer);\n } else {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n }\n }\n\n _bindMaterialState(material, prevMaterial = null) {\n let gl = this._gl;\n\n let state = material._state;\n let prevState = prevMaterial ? prevMaterial._state : ~state;\n\n // Return early if both materials use identical state\n if (state == prevState) {\n return;\n }\n\n // Any caps bits changed?\n if (material._capsDiff(prevState)) {\n setCap(gl, gl.CULL_FACE, CAP.CULL_FACE, prevState, state);\n setCap(gl, gl.BLEND, CAP.BLEND, prevState, state);\n setCap(gl, gl.DEPTH_TEST, CAP.DEPTH_TEST, prevState, state);\n setCap(gl, gl.STENCIL_TEST, CAP.STENCIL_TEST, prevState, state);\n\n let colorMaskChange = (state & CAP.COLOR_MASK) - (prevState & CAP.COLOR_MASK);\n if (colorMaskChange) {\n let mask = colorMaskChange > 1;\n this._colorMaskNeedsReset = !mask;\n gl.colorMask(mask, mask, mask, mask);\n }\n\n let depthMaskChange = (state & CAP.DEPTH_MASK) - (prevState & CAP.DEPTH_MASK);\n if (depthMaskChange) {\n this._depthMaskNeedsReset = !(depthMaskChange > 1);\n gl.depthMask(depthMaskChange > 1);\n }\n\n let stencilMaskChange = (state & CAP.STENCIL_MASK) - (prevState & CAP.STENCIL_MASK);\n if (stencilMaskChange) {\n gl.stencilMask(stencilMaskChange > 1);\n }\n }\n\n // Blending enabled and blend func changed?\n if (material._blendDiff(prevState)) {\n gl.blendFunc(material.blendFuncSrc, material.blendFuncDst);\n }\n\n // Depth testing enabled and depth func changed?\n if (material._depthFuncDiff(prevState)) {\n gl.depthFunc(material.depthFunc);\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nconst GL = WebGLRenderingContext; // For enums\n\nexport class TextureSampler {\n constructor() {\n this.minFilter = null;\n this.magFilter = null;\n this.wrapS = null;\n this.wrapT = null;\n }\n}\n\nexport class Texture {\n constructor() {\n this.sampler = new TextureSampler();\n this.mipmap = true;\n // TODO: Anisotropy\n }\n\n get format() {\n return GL.RGBA;\n }\n\n get width() {\n return 0;\n }\n\n get height() {\n return 0;\n }\n\n get textureKey() {\n return null;\n }\n}\n\nexport class ImageTexture extends Texture {\n constructor(img) {\n super();\n\n this._img = img;\n this._imgBitmap = null;\n\n if (img.src && img.complete) {\n if (img.naturalWidth) {\n this._promise = this._finishImage();\n } else {\n this._promise = Promise.reject('Image provided had failed to load.');\n }\n } else {\n this._promise = new Promise((resolve, reject) => {\n img.addEventListener('load', () => resolve(this._finishImage()));\n img.addEventListener('error', reject);\n });\n }\n }\n\n _finishImage() {\n if (window.createImageBitmap) {\n return window.createImageBitmap(this._img).then((imgBitmap) => {\n this._imgBitmap = imgBitmap;\n return Promise.resolve(this);\n });\n }\n return Promise.resolve(this);\n }\n\n get format() {\n // TODO: Can be RGB in some cases.\n return GL.RGBA;\n }\n\n get width() {\n return this._img.width;\n }\n\n get height() {\n return this._img.height;\n }\n\n waitForComplete() {\n return this._promise;\n }\n\n get textureKey() {\n return this._img.src;\n }\n\n get source() {\n return this._imgBitmap || this._img;\n }\n}\n\nexport class UrlTexture extends ImageTexture {\n constructor(url) {\n let img = new Image();\n super(img);\n img.src = url;\n }\n}\n\nexport class BlobTexture extends ImageTexture {\n constructor(blob) {\n let img = new Image();\n super(img);\n img.src = window.URL.createObjectURL(blob);\n }\n}\n\nexport class VideoTexture extends Texture {\n constructor(video) {\n super();\n\n this._video = video;\n\n if (video.readyState >= 2) {\n this._promise = Promise.resolve(this);\n } else if (video.error) {\n this._promise = Promise.reject(video.error);\n } else {\n this._promise = new Promise((resolve, reject) => {\n video.addEventListener('loadeddata', () => resolve(this));\n video.addEventListener('error', reject);\n });\n }\n }\n\n get format() {\n // TODO: Can be RGB in some cases.\n return GL.RGBA;\n }\n\n get width() {\n return this._video.videoWidth;\n }\n\n get height() {\n return this._video.videoHeight;\n }\n\n waitForComplete() {\n return this._promise;\n }\n\n get textureKey() {\n return this._video.src;\n }\n\n get source() {\n return this._video;\n }\n}\n\nlet nextDataTextureIndex = 0;\n\nexport class DataTexture extends Texture {\n constructor(data, width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE) {\n super();\n\n this._data = data;\n this._width = width;\n this._height = height;\n this._format = format;\n this._type = type;\n this._key = `DATA_${nextDataTextureIndex}`;\n nextDataTextureIndex++;\n }\n\n get format() {\n return this._format;\n }\n\n get width() {\n return this._width;\n }\n\n get height() {\n return this._height;\n }\n\n get textureKey() {\n return this._key;\n }\n}\n\nexport class ColorTexture extends DataTexture {\n constructor(r, g, b, a) {\n let colorData = new Uint8Array([r*255.0, g*255.0, b*255.0, a*255.0]);\n super(colorData, 1, 1);\n\n this.mipmap = false;\n this._key = `COLOR_${colorData[0]}_${colorData[1]}_${colorData[2]}_${colorData[3]}`;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nexport {Node} from './core/node.js';\nexport {Renderer, createWebGLContext} from './core/renderer.js';\nexport {UrlTexture} from './core/texture.js';\n\nexport {PrimitiveStream} from './geometry/primitive-stream.js';\nexport {BoxBuilder} from './geometry/box-builder.js';\n\nexport {PbrMaterial} from './materials/pbr.js';\n\nexport {mat4, mat3, vec3, vec4, quat} from './math/gl-matrix.js';\n\nexport {BoundsRenderer} from './nodes/bounds-renderer.js';\nexport {ButtonNode} from './nodes/button.js';\nexport {DropShadowNode} from './nodes/drop-shadow.js';\nexport {CubeSeaNode} from './nodes/cube-sea.js';\nexport {Gltf2Node} from './nodes/gltf2.js';\nexport {SkyboxNode} from './nodes/skybox.js';\nexport {VideoNode} from './nodes/video.js';\n\nexport {WebXRView, Scene} from './scenes/scene.js';\n\nexport {FallbackHelper} from './util/fallback-helper.js';\nexport {QueryArgs} from './util/query-args.js';\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {GeometryBuilderBase} from './primitive-stream.js';\n\nexport class BoxBuilder extends GeometryBuilderBase {\n pushBox(min, max) {\n let stream = this.primitiveStream;\n\n let w = max[0] - min[0];\n let h = max[1] - min[1];\n let d = max[2] - min[2];\n\n let wh = w * 0.5;\n let hh = h * 0.5;\n let dh = d * 0.5;\n\n let cx = min[0] + wh;\n let cy = min[1] + hh;\n let cz = min[2] + dh;\n\n stream.startGeometry();\n\n // Bottom\n let idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n // X Y Z U V NX NY NZ\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, -1.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, -1.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 0.0, 0.0, -1.0, 0.0);\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 0.0, 0.0, -1.0, 0.0);\n\n // Top\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 1.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 1.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 1.0, 0.0, 1.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 1.0, 0.0, 1.0, 0.0);\n\n // Left\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, -1.0, 0.0, 0.0);\n\n // Right\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 1.0, 0.0, 0.0);\n\n // Back\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, 0.0, -1.0);\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, 0.0, -1.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 0.0, -1.0);\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 0.0, -1.0);\n\n // Front\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 0.0, 0.0, 1.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, 0.0, 0.0, 1.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, 0.0, 0.0, 1.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 0.0, 0.0, 1.0);\n\n stream.endGeometry();\n }\n\n pushCube(center = [0, 0, 0], size = 1.0) {\n let hs = size * 0.5;\n this.pushBox([center[0] - hs, center[1] - hs, center[2] - hs],\n [center[0] + hs, center[1] + hs, center[2] + hs]);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {mat3, vec3} from '../math/gl-matrix.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst tempVec3 = vec3.create();\n\nexport class PrimitiveStream {\n constructor(options) {\n this._vertices = [];\n this._indices = [];\n\n this._geometryStarted = false;\n\n this._vertexOffset = 0;\n this._vertexIndex = 0;\n this._highIndex = 0;\n\n this._flipWinding = false;\n this._invertNormals = false;\n this._transform = null;\n this._normalTransform = null;\n this._min = null;\n this._max = null;\n }\n\n set flipWinding(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change flipWinding before ending the current geometry.`);\n }\n this._flipWinding = value;\n }\n\n get flipWinding() {\n this._flipWinding;\n }\n\n set invertNormals(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change invertNormals before ending the current geometry.`);\n }\n this._invertNormals = value;\n }\n\n get invertNormals() {\n this._invertNormals;\n }\n\n set transform(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change transform before ending the current geometry.`);\n }\n this._transform = value;\n if (this._transform) {\n if (!this._normalTransform) {\n this._normalTransform = mat3.create();\n }\n mat3.fromMat4(this._normalTransform, this._transform);\n }\n }\n\n get transform() {\n this._transform;\n }\n\n startGeometry() {\n if (this._geometryStarted) {\n throw new Error(`Attempted to start a new geometry before the previous one was ended.`);\n }\n\n this._geometryStarted = true;\n this._vertexIndex = 0;\n this._highIndex = 0;\n }\n\n endGeometry() {\n if (!this._geometryStarted) {\n throw new Error(`Attempted to end a geometry before one was started.`);\n }\n\n if (this._highIndex >= this._vertexIndex) {\n throw new Error(`Geometry contains indices that are out of bounds.\n (Contains an index of ${this._highIndex} when the vertex count is ${this._vertexIndex})`);\n }\n\n this._geometryStarted = false;\n this._vertexOffset += this._vertexIndex;\n\n // TODO: Anything else need to be done to finish processing here?\n }\n\n pushVertex(x, y, z, u = 0, v = 0, nx = 0, ny = 0, nz = 1) {\n if (!this._geometryStarted) {\n throw new Error(`Cannot push vertices before calling startGeometry().`);\n }\n\n // Transform the incoming vertex if we have a transformation matrix\n if (this._transform) {\n tempVec3[0] = x;\n tempVec3[1] = y;\n tempVec3[2] = z;\n vec3.transformMat4(tempVec3, tempVec3, this._transform);\n x = tempVec3[0];\n y = tempVec3[1];\n z = tempVec3[2];\n\n tempVec3[0] = nx;\n tempVec3[1] = ny;\n tempVec3[2] = nz;\n vec3.transformMat3(tempVec3, tempVec3, this._normalTransform);\n nx = tempVec3[0];\n ny = tempVec3[1];\n nz = tempVec3[2];\n }\n\n if (this._invertNormals) {\n nx *= -1.0;\n ny *= -1.0;\n nz *= -1.0;\n }\n\n this._vertices.push(x, y, z, u, v, nx, ny, nz);\n\n if (this._min) {\n this._min[0] = Math.min(this._min[0], x);\n this._min[1] = Math.min(this._min[1], y);\n this._min[2] = Math.min(this._min[2], z);\n this._max[0] = Math.max(this._max[0], x);\n this._max[1] = Math.max(this._max[1], y);\n this._max[2] = Math.max(this._max[2], z);\n } else {\n this._min = vec3.fromValues(x, y, z);\n this._max = vec3.fromValues(x, y, z);\n }\n\n return this._vertexIndex++;\n }\n\n get nextVertexIndex() {\n return this._vertexIndex;\n }\n\n pushTriangle(idxA, idxB, idxC) {\n if (!this._geometryStarted) {\n throw new Error(`Cannot push triangles before calling startGeometry().`);\n }\n\n this._highIndex = Math.max(this._highIndex, idxA, idxB, idxC);\n\n idxA += this._vertexOffset;\n idxB += this._vertexOffset;\n idxC += this._vertexOffset;\n\n if (this._flipWinding) {\n this._indices.push(idxC, idxB, idxA);\n } else {\n this._indices.push(idxA, idxB, idxC);\n }\n }\n\n clear() {\n if (this._geometryStarted) {\n throw new Error(`Cannot clear before ending the current geometry.`);\n }\n\n this._vertices = [];\n this._indices = [];\n this._vertexOffset = 0;\n this._min = null;\n this._max = null;\n }\n\n finishPrimitive(renderer) {\n if (!this._vertexOffset) {\n throw new Error(`Attempted to call finishPrimitive() before creating any geometry.`);\n }\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(this._vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(this._indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 32, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 32, 12),\n new PrimitiveAttribute('NORMAL', vertexBuffer, 3, GL.FLOAT, 32, 20),\n ];\n\n let primitive = new Primitive(attribs, this._indices.length);\n primitive.setIndexBuffer(indexBuffer);\n primitive.setBounds(this._min, this._max);\n\n return primitive;\n }\n}\n\nexport class GeometryBuilderBase {\n constructor(primitiveStream) {\n if (primitiveStream) {\n this._stream = primitiveStream;\n } else {\n this._stream = new PrimitiveStream();\n }\n }\n\n set primitiveStream(value) {\n this._stream = value;\n }\n\n get primitiveStream() {\n return this._stream;\n }\n\n finishPrimitive(renderer) {\n return this._stream.finishPrimitive(renderer);\n }\n\n clear() {\n this._stream.clear();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {PbrMaterial} from '../materials/pbr.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {ImageTexture, ColorTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst GLB_MAGIC = 0x46546C67;\nconst CHUNK_TYPE = {\n JSON: 0x4E4F534A,\n BIN: 0x004E4942,\n};\n\nfunction isAbsoluteUri(uri) {\n let absRegEx = new RegExp('^'+window.location.protocol, 'i');\n return !!uri.match(absRegEx);\n}\n\nfunction isDataUri(uri) {\n let dataRegEx = /^data:/;\n return !!uri.match(dataRegEx);\n}\n\nfunction resolveUri(uri, baseUrl) {\n if (isAbsoluteUri(uri) || isDataUri(uri)) {\n return uri;\n }\n return baseUrl + uri;\n}\n\nfunction getComponentCount(type) {\n switch (type) {\n case 'SCALAR': return 1;\n case 'VEC2': return 2;\n case 'VEC3': return 3;\n case 'VEC4': return 4;\n default: return 0;\n }\n}\n\n/**\n * Gltf2SceneLoader\n * Loads glTF 2.0 scenes into a renderable node tree.\n */\n\nexport class Gltf2Loader {\n constructor(renderer) {\n this.renderer = renderer;\n this._gl = renderer._gl;\n }\n\n loadFromUrl(url) {\n return fetch(url)\n .then((response) => {\n let i = url.lastIndexOf('/');\n let baseUrl = (i !== 0) ? url.substring(0, i + 1) : '';\n\n if (url.endsWith('.gltf')) {\n return response.json().then((json) => {\n return this.loadFromJson(json, baseUrl);\n });\n } else if (url.endsWith('.glb')) {\n return response.arrayBuffer().then((arrayBuffer) => {\n return this.loadFromBinary(arrayBuffer, baseUrl);\n });\n } else {\n throw new Error('Unrecognized file extension');\n }\n });\n }\n\n loadFromBinary(arrayBuffer, baseUrl) {\n let headerView = new DataView(arrayBuffer, 0, 12);\n let magic = headerView.getUint32(0, true);\n let version = headerView.getUint32(4, true);\n let length = headerView.getUint32(8, true);\n\n if (magic != GLB_MAGIC) {\n throw new Error('Invalid magic string in binary header.');\n }\n\n if (version != 2) {\n throw new Error('Incompatible version in binary header.');\n }\n\n let chunks = {};\n let chunkOffset = 12;\n while (chunkOffset < length) {\n let chunkHeaderView = new DataView(arrayBuffer, chunkOffset, 8);\n let chunkLength = chunkHeaderView.getUint32(0, true);\n let chunkType = chunkHeaderView.getUint32(4, true);\n chunks[chunkType] = arrayBuffer.slice(chunkOffset + 8, chunkOffset + 8 + chunkLength);\n chunkOffset += chunkLength + 8;\n }\n\n if (!chunks[CHUNK_TYPE.JSON]) {\n throw new Error('File contained no json chunk.');\n }\n\n let decoder = new TextDecoder('utf-8');\n let jsonString = decoder.decode(chunks[CHUNK_TYPE.JSON]);\n let json = JSON.parse(jsonString);\n return this.loadFromJson(json, baseUrl, chunks[CHUNK_TYPE.BIN]);\n }\n\n loadFromJson(json, baseUrl, binaryChunk) {\n if (!json.asset) {\n throw new Error('Missing asset description.');\n }\n\n if (json.asset.minVersion != '2.0' && json.asset.version != '2.0') {\n throw new Error('Incompatible asset version.');\n }\n\n let buffers = [];\n if (binaryChunk) {\n buffers[0] = new Gltf2Resource({}, baseUrl, binaryChunk);\n } else {\n for (let buffer of json.buffers) {\n buffers.push(new Gltf2Resource(buffer, baseUrl));\n }\n }\n\n let bufferViews = [];\n for (let bufferView of json.bufferViews) {\n bufferViews.push(new Gltf2BufferView(bufferView, buffers));\n }\n\n let images = [];\n if (json.images) {\n for (let image of json.images) {\n images.push(new Gltf2Resource(image, baseUrl));\n }\n }\n\n let textures = [];\n if (json.textures) {\n for (let texture of json.textures) {\n let image = images[texture.source];\n let glTexture = image.texture(bufferViews);\n if (texture.sampler) {\n let sampler = sampler[texture.sampler];\n glTexture.sampler.minFilter = sampler.minFilter;\n glTexture.sampler.magFilter = sampler.magFilter;\n glTexture.sampler.wrapS = sampler.wrapS;\n glTexture.sampler.wrapT = sampler.wrapT;\n }\n textures.push(glTexture);\n }\n }\n\n function getTexture(textureInfo) {\n if (!textureInfo) {\n return null;\n }\n return textures[textureInfo.index];\n }\n\n let materials = [];\n if (json.materials) {\n for (let material of json.materials) {\n let glMaterial = new PbrMaterial();\n let pbr = material.pbrMetallicRoughness || {};\n\n glMaterial.baseColorFactor.value = pbr.baseColorFactor || [1, 1, 1, 1];\n glMaterial.baseColor.texture = getTexture(pbr.baseColorTexture);\n glMaterial.metallicRoughnessFactor.value = [\n pbr.metallicFactor || 1.0,\n pbr.roughnessFactor || 1.0,\n ];\n glMaterial.metallicRoughness.texture = getTexture(pbr.metallicRoughnessTexture);\n glMaterial.normal.texture = getTexture(json.normalTexture);\n glMaterial.occlusion.texture = getTexture(json.occlusionTexture);\n glMaterial.occlusionStrength.value = (json.occlusionTexture && json.occlusionTexture.strength) ?\n json.occlusionTexture.strength : 1.0;\n glMaterial.emissiveFactor.value = material.emissiveFactor || [0, 0, 0];\n glMaterial.emissive.texture = getTexture(json.emissiveTexture);\n if (!glMaterial.emissive.texture && json.emissiveFactor) {\n glMaterial.emissive.texture = new ColorTexture(1.0, 1.0, 1.0, 1.0);\n }\n\n switch (material.alphaMode) {\n case 'BLEND':\n glMaterial.state.blend = true;\n break;\n case 'MASK':\n // Not really supported.\n glMaterial.state.blend = true;\n break;\n default: // Includes 'OPAQUE'\n glMaterial.state.blend = false;\n }\n\n // glMaterial.alpha_mode = material.alphaMode;\n // glMaterial.alpha_cutoff = material.alphaCutoff;\n glMaterial.state.cullFace = !(material.doubleSided);\n\n materials.push(glMaterial);\n }\n }\n\n let accessors = json.accessors;\n\n let meshes = [];\n for (let mesh of json.meshes) {\n let glMesh = new Gltf2Mesh();\n meshes.push(glMesh);\n\n for (let primitive of mesh.primitives) {\n let material = null;\n if ('material' in primitive) {\n material = materials[primitive.material];\n } else {\n // Create a \"default\" material if the primitive has none.\n material = new PbrMaterial();\n }\n\n let attributes = [];\n let elementCount = 0;\n /* let glPrimitive = new Gltf2Primitive(primitive, material);\n glMesh.primitives.push(glPrimitive); */\n\n let min = null;\n let max = null;\n\n for (let name in primitive.attributes) {\n let accessor = accessors[primitive.attributes[name]];\n let bufferView = bufferViews[accessor.bufferView];\n elementCount = accessor.count;\n\n let glAttribute = new PrimitiveAttribute(\n name,\n bufferView.renderBuffer(this.renderer, GL.ARRAY_BUFFER),\n getComponentCount(accessor.type),\n accessor.componentType,\n bufferView.byteStride || 0,\n accessor.byteOffset || 0\n );\n glAttribute.normalized = accessor.normalized || false;\n\n if (name == 'POSITION') {\n min = accessor.min;\n max = accessor.max;\n }\n\n attributes.push(glAttribute);\n }\n\n let glPrimitive = new Primitive(attributes, elementCount, primitive.mode);\n\n if ('indices' in primitive) {\n let accessor = accessors[primitive.indices];\n let bufferView = bufferViews[accessor.bufferView];\n\n glPrimitive.setIndexBuffer(\n bufferView.renderBuffer(this.renderer, GL.ELEMENT_ARRAY_BUFFER),\n accessor.byteOffset || 0,\n accessor.componentType\n );\n glPrimitive.indexType = accessor.componentType;\n glPrimitive.indexByteOffset = accessor.byteOffset || 0;\n glPrimitive.elementCount = accessor.count;\n }\n\n if (min && max) {\n glPrimitive.setBounds(min, max);\n }\n\n // After all the attributes have been processed, get a program that is\n // appropriate for both the material and the primitive attributes.\n glMesh.primitives.push(\n this.renderer.createRenderPrimitive(glPrimitive, material));\n }\n }\n\n let sceneNode = new Node();\n let scene = json.scenes[json.scene];\n for (let nodeId of scene.nodes) {\n let node = json.nodes[nodeId];\n sceneNode.addNode(\n this.processNodes(node, json.nodes, meshes));\n }\n\n return sceneNode;\n }\n\n processNodes(node, nodes, meshes) {\n let glNode = new Node();\n glNode.name = node.name;\n\n if ('mesh' in node) {\n let mesh = meshes[node.mesh];\n for (let primitive of mesh.primitives) {\n glNode.addRenderPrimitive(primitive);\n }\n }\n\n if (node.matrix) {\n glNode.matrix = new Float32Array(node.matrix);\n } else if (node.translation || node.rotation || node.scale) {\n if (node.translation) {\n glNode.translation = new Float32Array(node.translation);\n }\n\n if (node.rotation) {\n glNode.rotation = new Float32Array(node.rotation);\n }\n\n if (node.scale) {\n glNode.scale = new Float32Array(node.scale);\n }\n }\n\n if (node.children) {\n for (let nodeId of node.children) {\n let node = nodes[nodeId];\n glNode.addNode(this.processNodes(node, nodes, meshes));\n }\n }\n\n return glNode;\n }\n}\n\nclass Gltf2Mesh {\n constructor() {\n this.primitives = [];\n }\n}\n\nclass Gltf2BufferView {\n constructor(json, buffers) {\n this.buffer = buffers[json.buffer];\n this.byteOffset = json.byteOffset || 0;\n this.byteLength = json.byteLength || null;\n this.byteStride = json.byteStride;\n\n this._viewPromise = null;\n this._renderBuffer = null;\n }\n\n dataView() {\n if (!this._viewPromise) {\n this._viewPromise = this.buffer.arrayBuffer().then((arrayBuffer) => {\n return new DataView(arrayBuffer, this.byteOffset, this.byteLength);\n });\n }\n return this._viewPromise;\n }\n\n renderBuffer(renderer, target) {\n if (!this._renderBuffer) {\n this._renderBuffer = renderer.createRenderBuffer(target, this.dataView());\n }\n return this._renderBuffer;\n }\n}\n\nclass Gltf2Resource {\n constructor(json, baseUrl, arrayBuffer) {\n this.json = json;\n this.baseUrl = baseUrl;\n\n this._dataPromise = null;\n this._texture = null;\n if (arrayBuffer) {\n this._dataPromise = Promise.resolve(arrayBuffer);\n }\n }\n\n arrayBuffer() {\n if (!this._dataPromise) {\n if (isDataUri(this.json.uri)) {\n let base64String = this.json.uri.replace('data:application/octet-stream;base64,', '');\n let binaryArray = Uint8Array.from(atob(base64String), (c) => c.charCodeAt(0));\n this._dataPromise = Promise.resolve(binaryArray.buffer);\n return this._dataPromise;\n }\n\n this._dataPromise = fetch(resolveUri(this.json.uri, this.baseUrl))\n .then((response) => response.arrayBuffer());\n }\n return this._dataPromise;\n }\n\n texture(bufferViews) {\n if (!this._texture) {\n let img = new Image();\n this._texture = new ImageTexture(img);\n\n if (this.json.uri) {\n if (isDataUri(this.json.uri)) {\n img.src = this.json.uri;\n } else {\n img.src = `${this.baseUrl}${this.json.uri}`;\n }\n } else {\n let view = bufferViews[this.json.bufferView];\n view.dataView().then((dataView) => {\n let blob = new Blob([dataView], {type: this.json.mimeType});\n img.src = window.URL.createObjectURL(blob);\n });\n }\n }\n return this._texture;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {ATTRIB_MASK} from '../core/renderer.js';\n\nconst VERTEX_SOURCE = `\nattribute vec3 POSITION, NORMAL;\nattribute vec2 TEXCOORD_0, TEXCOORD_1;\n\nuniform vec3 CAMERA_POSITION;\nuniform vec3 LIGHT_DIRECTION;\n\nvarying vec3 vLight; // Vector from vertex to light.\nvarying vec3 vView; // Vector from vertex to camera.\nvarying vec2 vTex;\n\n#ifdef USE_NORMAL_MAP\nattribute vec4 TANGENT;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_VERTEX_COLOR\nattribute vec4 COLOR_0;\nvarying vec4 vCol;\n#endif\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));\n#ifdef USE_NORMAL_MAP\n vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));\n vec3 b = cross(n, t) * TANGENT.w;\n vTBN = mat3(t, b, n);\n#else\n vNorm = n;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n vCol = COLOR_0;\n#endif\n\n vTex = TEXCOORD_0;\n vec4 mPos = model * vec4(POSITION, 1.0);\n vLight = -LIGHT_DIRECTION;\n vView = CAMERA_POSITION - mPos.xyz;\n return proj * view * mPos;\n}`;\n\n// These equations are borrowed with love from this docs from Epic because I\n// just don't have anything novel to bring to the PBR scene.\n// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf\nconst EPIC_PBR_FUNCTIONS = `\nvec3 lambertDiffuse(vec3 cDiff) {\n return cDiff / M_PI;\n}\n\nfloat specD(float a, float nDotH) {\n float aSqr = a * a;\n float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);\n return aSqr / (M_PI * f * f);\n}\n\nfloat specG(float roughness, float nDotL, float nDotV) {\n float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n float gl = nDotL / (nDotL * (1.0 - k) + k);\n float gv = nDotV / (nDotV * (1.0 - k) + k);\n return gl * gv;\n}\n\nvec3 specF(float vDotH, vec3 F0) {\n float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;\n float base = 2.0;\n return F0 + (1.0 - F0) * pow(base, exponent);\n}`;\n\nconst FRAGMENT_SOURCE = `\n#define M_PI 3.14159265\n\nuniform vec4 baseColorFactor;\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D baseColorTex;\n#endif\n\nvarying vec3 vLight;\nvarying vec3 vView;\nvarying vec2 vTex;\n\n#ifdef USE_VERTEX_COLOR\nvarying vec4 vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\nuniform sampler2D normalTex;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_METAL_ROUGH_MAP\nuniform sampler2D metallicRoughnessTex;\n#endif\nuniform vec2 metallicRoughnessFactor;\n\n#ifdef USE_OCCLUSION\nuniform sampler2D occlusionTex;\nuniform float occlusionStrength;\n#endif\n\n#ifdef USE_EMISSIVE_TEXTURE\nuniform sampler2D emissiveTex;\n#endif\nuniform vec3 emissiveFactor;\n\nuniform vec3 LIGHT_COLOR;\n\nconst vec3 dielectricSpec = vec3(0.04);\nconst vec3 black = vec3(0.0);\n\n${EPIC_PBR_FUNCTIONS}\n\nvec4 fragment_main() {\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;\n#else\n vec4 baseColor = baseColorFactor;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n baseColor *= vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\n vec3 n = texture2D(normalTex, vTex).rgb;\n n = normalize(vTBN * (2.0 * n - 1.0));\n#else\n vec3 n = normalize(vNorm);\n#endif\n\n#ifdef FULLY_ROUGH\n float metallic = 0.0;\n#else\n float metallic = metallicRoughnessFactor.x;\n#endif\n\n float roughness = metallicRoughnessFactor.y;\n\n#ifdef USE_METAL_ROUGH_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);\n metallic *= metallicRoughness.b;\n roughness *= metallicRoughness.g;\n#endif\n \n vec3 l = normalize(vLight);\n vec3 v = normalize(vView);\n vec3 h = normalize(l+v);\n\n float nDotL = clamp(dot(n, l), 0.001, 1.0);\n float nDotV = abs(dot(n, v)) + 0.001;\n float nDotH = max(dot(n, h), 0.0);\n float vDotH = max(dot(v, h), 0.0);\n\n // From GLTF Spec\n vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color\n vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color\n float a = roughness * roughness;\n\n#ifdef FULLY_ROUGH\n vec3 specular = F0 * 0.45;\n#else\n vec3 F = specF(vDotH, F0);\n float D = specD(a, nDotH);\n float G = specG(roughness, nDotL, nDotV);\n vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);\n#endif\n float halfLambert = dot(n, l) * 0.5 + 0.5;\n halfLambert *= halfLambert;\n\n vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;\n\n#ifdef USE_OCCLUSION\n float occlusion = texture2D(occlusionTex, vTex).r;\n color = mix(color, color * occlusion, occlusionStrength);\n#endif\n \n vec3 emissive = emissiveFactor;\n#ifdef USE_EMISSIVE_TEXTURE\n emissive *= texture2D(emissiveTex, vTex).rgb;\n#endif\n color += emissive;\n\n // gamma correction\n //color = pow(color, vec3(1.0/2.2));\n\n return vec4(color, baseColor.a);\n}`;\n\nexport class PbrMaterial extends Material {\n constructor() {\n super();\n\n this.baseColor = this.defineSampler('baseColorTex');\n this.metallicRoughness = this.defineSampler('metallicRoughnessTex');\n this.normal = this.defineSampler('normalTex');\n this.occlusion = this.defineSampler('occlusionTex');\n this.emissive = this.defineSampler('emissiveTex');\n\n this.baseColorFactor = this.defineUniform('baseColorFactor', [1.0, 1.0, 1.0, 1.0]);\n this.metallicRoughnessFactor = this.defineUniform('metallicRoughnessFactor', [1.0, 1.0]);\n this.occlusionStrength = this.defineUniform('occlusionStrength', 1.0);\n this.emissiveFactor = this.defineUniform('emissiveFactor', [0, 0, 0]);\n }\n\n get materialName() {\n return 'PBR';\n }\n\n get vertexSource() {\n return VERTEX_SOURCE;\n }\n\n get fragmentSource() {\n return FRAGMENT_SOURCE;\n }\n\n getProgramDefines(renderPrimitive) {\n let programDefines = {};\n\n if (renderPrimitive._attributeMask & ATTRIB_MASK.COLOR_0) {\n programDefines['USE_VERTEX_COLOR'] = 1;\n }\n\n if (renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0) {\n if (this.baseColor.texture) {\n programDefines['USE_BASE_COLOR_MAP'] = 1;\n }\n\n if (this.normal.texture && (renderPrimitive._attributeMask & ATTRIB_MASK.TANGENT)) {\n programDefines['USE_NORMAL_MAP'] = 1;\n }\n\n if (this.metallicRoughness.texture) {\n programDefines['USE_METAL_ROUGH_MAP'] = 1;\n }\n\n if (this.occlusion.texture) {\n programDefines['USE_OCCLUSION'] = 1;\n }\n\n if (this.emissive.texture) {\n programDefines['USE_EMISSIVE_TEXTURE'] = 1;\n }\n }\n\n if ((!this.metallicRoughness.texture ||\n !(renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0)) &&\n this.metallicRoughnessFactor.value[1] == 1.0) {\n programDefines['FULLY_ROUGH'] = 1;\n }\n\n return programDefines;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport * as glMatrix from '../../node_modules/gl-matrix/src/gl-matrix/common.js';\nimport * as mat2 from '../../node_modules/gl-matrix/src/gl-matrix/mat2.js';\nimport * as mat2d from '../../node_modules/gl-matrix/src/gl-matrix/mat2d.js';\nimport * as mat3 from '../../node_modules/gl-matrix/src/gl-matrix/mat3.js';\nimport * as mat4 from '../../node_modules/gl-matrix/src/gl-matrix/mat4.js';\nimport * as quat from '../../node_modules/gl-matrix/src/gl-matrix/quat.js';\nimport * as quat2 from '../../node_modules/gl-matrix/src/gl-matrix/quat2.js';\nimport * as vec2 from '../../node_modules/gl-matrix/src/gl-matrix/vec2.js';\nimport * as vec3 from '../../node_modules/gl-matrix/src/gl-matrix/vec3.js';\nimport * as vec4 from '../../node_modules/gl-matrix/src/gl-matrix/vec4.js';\n\nexport {\n glMatrix,\n mat2,\n mat2d,\n mat3,\n mat4,\n quat,\n quat2,\n vec2,\n vec3,\n vec4,\n};\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {mat3, vec3} from './gl-matrix.js';\n\nlet normalMat = mat3.create();\n\nconst RAY_INTERSECTION_OFFSET = 0.02;\n\nexport class Ray {\n constructor(matrix = null) {\n this.origin = vec3.create();\n\n this._dir = vec3.create();\n this._dir[2] = -1.0;\n\n if (matrix) {\n vec3.transformMat4(this.origin, this.origin, matrix);\n mat3.fromMat4(normalMat, matrix);\n vec3.transformMat3(this._dir, this._dir, normalMat);\n }\n\n // To force the inverse and sign calculations.\n this.dir = this._dir;\n }\n\n get dir() {\n return this._dir;\n }\n\n set dir(value) {\n this._dir = vec3.copy(this._dir, value);\n vec3.normalize(this._dir, this._dir);\n\n this.inv_dir = vec3.fromValues(\n 1.0 / this._dir[0],\n 1.0 / this._dir[1],\n 1.0 / this._dir[2]);\n\n this.sign = [\n (this.inv_dir[0] < 0) ? 1 : 0,\n (this.inv_dir[1] < 0) ? 1 : 0,\n (this.inv_dir[2] < 0) ? 1 : 0,\n ];\n }\n\n // Borrowed from:\n // eslint-disable-next-line max-len\n // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection\n intersectsAABB(min, max) {\n let r = this;\n\n let bounds = [min, max];\n\n let tmin = (bounds[r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];\n let tmax = (bounds[1-r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];\n let tymin = (bounds[r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];\n let tymax = (bounds[1-r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];\n\n if ((tmin > tymax) || (tymin > tmax)) {\n return null;\n }\n if (tymin > tmin) {\n tmin = tymin;\n }\n if (tymax < tmax) {\n tmax = tymax;\n }\n\n let tzmin = (bounds[r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];\n let tzmax = (bounds[1-r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];\n\n if ((tmin > tzmax) || (tzmin > tmax)) {\n return null;\n }\n if (tzmin > tmin) {\n tmin = tzmin;\n }\n if (tzmax < tmax) {\n tmax = tzmax;\n }\n\n let t = -1;\n if (tmin > 0 && tmax > 0) {\n t = Math.min(tmin, tmax);\n } else if (tmin > 0) {\n t = tmin;\n } else if (tmax > 0) {\n t = tmax;\n } else {\n // Intersection is behind the ray origin.\n return null;\n }\n\n // Push ray intersection point back along the ray a bit so that cursors\n // don't accidentally intersect with the hit surface.\n t -= RAY_INTERSECTION_OFFSET;\n\n // Return the point where the ray first intersected with the AABB.\n let intersectionPoint = vec3.clone(this._dir);\n vec3.scale(intersectionPoint, intersectionPoint, t);\n vec3.add(intersectionPoint, intersectionPoint, this.origin);\n return intersectionPoint;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nThis file renders a passed in XRStageBounds object and attempts\nto render geometry on the floor to indicate where the bounds is.\nXRStageBounds' `geometry` is a series of XRStageBoundsPoints (in\nclockwise-order) with `x` and `z` properties for each.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass BoundsMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n this.state.blendFuncSrc = GL.SRC_ALPHA;\n this.state.blendFuncDst = GL.ONE;\n this.state.depthTest = false;\n }\n\n get materialName() {\n return 'BOUNDS_RENDERER';\n }\n\n get vertexSource() {\n return `\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n\n vec4 fragment_main() {\n return vec4(0.0, 1.0, 0.0, 0.3);\n }`;\n }\n}\n\nexport class BoundsRenderer extends Node {\n constructor() {\n super();\n\n this._stageBounds = null;\n }\n\n onRendererChanged(renderer) {\n this.stageBounds = this._stageBounds;\n }\n\n get stageBounds() {\n return this._stageBounds;\n }\n\n set stageBounds(stageBounds) {\n if (this._stageBounds) {\n this.clearRenderPrimitives();\n }\n this._stageBounds = stageBounds;\n if (!stageBounds || stageBounds.length === 0 || !this._renderer) {\n return;\n }\n\n let verts = [];\n let indices = [];\n\n // Tessellate the bounding points from XRStageBounds and connect\n // each point to a neighbor and 0,0,0.\n const pointCount = stageBounds.geometry.length;\n for (let i = 0; i < pointCount; i++) {\n const point = stageBounds.geometry[i];\n verts.push(point.x, 0, point.z);\n indices.push(i, i === 0 ? pointCount - 1 : i - 1, pointCount);\n }\n // Center point\n verts.push(0, 0, 0);\n\n let vertexBuffer = this._renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(verts));\n let indexBuffer = this._renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 12, 0),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let renderPrimitive = this._renderer.createRenderPrimitive(primitive, new BoundsMaterial());\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {PrimitiveStream} from '../geometry/primitive-stream.js';\n\nconst BUTTON_SIZE = 0.1;\nconst BUTTON_CORNER_RADIUS = 0.025;\nconst BUTTON_CORNER_SEGMENTS = 8;\nconst BUTTON_ICON_SIZE = 0.07;\nconst BUTTON_LAYER_DISTANCE = 0.005;\nconst BUTTON_COLOR = 0.75;\nconst BUTTON_ALPHA = 0.85;\nconst BUTTON_HOVER_COLOR = 0.9;\nconst BUTTON_HOVER_ALPHA = 1.0;\nconst BUTTON_HOVER_SCALE = 1.1;\nconst BUTTON_HOVER_TRANSITION_TIME_MS = 200;\n\nclass ButtonMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n\n this.defineUniform('hoverAmount', 0);\n }\n\n get materialName() {\n return 'BUTTON_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n\n uniform float hoverAmount;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform float hoverAmount;\n\n const vec4 default_color = vec4(${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_ALPHA});\n const vec4 hover_color = vec4(${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_COLOR},\n ${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_ALPHA});\n\n vec4 fragment_main() {\n return mix(default_color, hover_color, hoverAmount);\n }`;\n }\n}\n\nclass ButtonIconMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n\n this.defineUniform('hoverAmount', 0);\n this.icon = this.defineSampler('icon');\n }\n\n get materialName() {\n return 'BUTTON_ICON_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n uniform float hoverAmount;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D icon;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(icon, vTexCoord);\n }`;\n }\n}\n\nexport class ButtonNode extends Node {\n constructor(iconTexture, callback) {\n super();\n\n // All buttons are selectable by default.\n this.selectable = true;\n\n this._selectHandler = callback;\n this._iconTexture = iconTexture;\n this._hovered = false;\n this._hoverT = 0;\n }\n\n get iconTexture() {\n return this._iconTexture;\n }\n\n set iconTexture(value) {\n if (this._iconTexture == value) {\n return;\n }\n\n this._iconTexture = value;\n this._iconRenderPrimitive.samplers.icon.texture = value;\n }\n\n onRendererChanged(renderer) {\n let stream = new PrimitiveStream();\n\n let hd = BUTTON_LAYER_DISTANCE * 0.5;\n\n // Build a rounded rect for the background.\n let hs = BUTTON_SIZE * 0.5;\n let ihs = hs - BUTTON_CORNER_RADIUS;\n stream.startGeometry();\n\n // Rounded corners and sides\n let segments = BUTTON_CORNER_SEGMENTS * 4;\n for (let i = 0; i < segments; ++i) {\n let rad = i * ((Math.PI * 2.0) / segments);\n let x = Math.cos(rad) * BUTTON_CORNER_RADIUS;\n let y = Math.sin(rad) * BUTTON_CORNER_RADIUS;\n let section = Math.floor(i / BUTTON_CORNER_SEGMENTS);\n switch (section) {\n case 0:\n x += ihs;\n y += ihs;\n break;\n case 1:\n x -= ihs;\n y += ihs;\n break;\n case 2:\n x -= ihs;\n y -= ihs;\n break;\n case 3:\n x += ihs;\n y -= ihs;\n break;\n }\n\n stream.pushVertex(x, y, -hd, 0, 0, 0, 0, 1);\n\n if (i > 1) {\n stream.pushTriangle(0, i-1, i);\n }\n }\n\n stream.endGeometry();\n\n let buttonPrimitive = stream.finishPrimitive(renderer);\n this._buttonRenderPrimitive = renderer.createRenderPrimitive(buttonPrimitive, new ButtonMaterial());\n this.addRenderPrimitive(this._buttonRenderPrimitive);\n\n // Build a simple textured quad for the foreground.\n hs = BUTTON_ICON_SIZE * 0.5;\n stream.clear();\n stream.startGeometry();\n\n stream.pushVertex(-hs, hs, hd, 0, 0, 0, 0, 1);\n stream.pushVertex(-hs, -hs, hd, 0, 1, 0, 0, 1);\n stream.pushVertex(hs, -hs, hd, 1, 1, 0, 0, 1);\n stream.pushVertex(hs, hs, hd, 1, 0, 0, 0, 1);\n\n stream.pushTriangle(0, 1, 2);\n stream.pushTriangle(0, 2, 3);\n\n stream.endGeometry();\n\n let iconPrimitive = stream.finishPrimitive(renderer);\n let iconMaterial = new ButtonIconMaterial();\n iconMaterial.icon.texture = this._iconTexture;\n this._iconRenderPrimitive = renderer.createRenderPrimitive(iconPrimitive, iconMaterial);\n this.addRenderPrimitive(this._iconRenderPrimitive);\n }\n\n onHoverStart() {\n this._hovered = true;\n }\n\n onHoverEnd() {\n this._hovered = false;\n }\n\n _updateHoverState() {\n let t = this._hoverT / BUTTON_HOVER_TRANSITION_TIME_MS;\n // Cubic Ease In/Out\n // TODO: Get a better animation system\n let hoverAmount = t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1;\n this._buttonRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;\n this._iconRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;\n }\n\n onUpdate(timestamp, frameDelta) {\n if (this._hovered && this._hoverT < BUTTON_HOVER_TRANSITION_TIME_MS) {\n this._hoverT = Math.min(BUTTON_HOVER_TRANSITION_TIME_MS, this._hoverT + frameDelta);\n this._updateHoverState();\n } else if (!this._hovered && this._hoverT > 0) {\n this._hoverT = Math.max(0.0, this._hoverT - frameDelta);\n this._updateHoverState();\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {UrlTexture} from '../core/texture.js';\nimport {BoxBuilder} from '../geometry/box-builder.js';\nimport {mat4} from '../math/gl-matrix.js';\n\nclass CubeSeaMaterial extends Material {\n constructor(heavy = false) {\n super();\n\n this.heavy = heavy;\n\n this.baseColor = this.defineSampler('baseColor');\n }\n\n get materialName() {\n return 'CUBE_SEA';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n attribute vec3 NORMAL;\n\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n const vec3 lightDir = vec3(0.75, 0.5, 1.0);\n const vec3 ambientColor = vec3(0.5, 0.5, 0.5);\n const vec3 lightColor = vec3(0.75, 0.75, 0.75);\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));\n float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);\n vLight = ambientColor + (lightColor * lightFactor);\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n if (!this.heavy) {\n return `\n precision mediump float;\n uniform sampler2D baseColor;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec4 fragment_main() {\n return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);\n }`;\n } else {\n // Used when we want to stress the GPU a bit more.\n // Stolen with love from https://www.clicktorelease.com/code/codevember-2016/4/\n return `\n precision mediump float;\n\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec2 dimensions = vec2(64, 64);\n float seed = 0.42;\n\n vec2 hash( vec2 p ) {\n p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));\n return fract(sin(p)*18.5453);\n }\n\n vec3 hash3( vec2 p ) {\n vec3 q = vec3( dot(p,vec2(127.1,311.7)),\n dot(p,vec2(269.5,183.3)),\n dot(p,vec2(419.2,371.9)) );\n return fract(sin(q)*43758.5453);\n }\n\n float iqnoise( in vec2 x, float u, float v ) {\n vec2 p = floor(x);\n vec2 f = fract(x);\n float k = 1.0+63.0*pow(1.0-v,4.0);\n float va = 0.0;\n float wt = 0.0;\n for( int j=-2; j<=2; j++ )\n for( int i=-2; i<=2; i++ ) {\n vec2 g = vec2( float(i),float(j) );\n vec3 o = hash3( p + g )*vec3(u,u,1.0);\n vec2 r = g - f + o.xy;\n float d = dot(r,r);\n float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );\n va += o.z*ww;\n wt += ww;\n }\n return va/wt;\n }\n\n // return distance, and cell id\n vec2 voronoi( in vec2 x ) {\n vec2 n = floor( x );\n vec2 f = fract( x );\n vec3 m = vec3( 8.0 );\n for( int j=-1; j<=1; j++ )\n for( int i=-1; i<=1; i++ ) {\n vec2 g = vec2( float(i), float(j) );\n vec2 o = hash( n + g );\n vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));\n float d = dot( r, r );\n if( d<m.x )\n m = vec3( d, o );\n }\n return vec2( sqrt(m.x), m.y+m.z );\n }\n\n vec4 fragment_main() {\n vec2 uv = ( vTexCoord );\n uv *= vec2( 10., 10. );\n uv += seed;\n vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );\n\n vec2 c = voronoi( uv );\n vec3 col = vec3( c.y / 2. );\n\n float f = iqnoise( 1. * uv + c.y, p.x, p.y );\n col *= 1.0 + .25 * vec3( f );\n\n return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );\n }`;\n }\n }\n}\n\nexport class CubeSeaNode extends Node {\n constructor(options = {}) {\n super();\n\n // Test variables\n // If true, use a very heavyweight shader to stress the GPU.\n this.heavyGpu = !!options.heavyGpu;\n\n // Number and size of the static cubes. Warning, large values\n // don't render right due to overflow of the int16 indices.\n this.cubeCount = options.cubeCount || (this.heavyGpu ? 12 : 10);\n this.cubeScale = options.cubeScale || 1.0;\n\n // Draw only half the world cubes. Helps test variable render cost\n // when combined with heavyGpu.\n this.halfOnly = !!options.halfOnly;\n\n // Automatically spin the world cubes. Intended for automated testing,\n // not recommended for viewing in a headset.\n this.autoRotate = !!options.autoRotate;\n\n this._texture = new UrlTexture(options.imageUrl || 'media/textures/cube-sea.png');\n\n this._material = new CubeSeaMaterial(this.heavyGpu);\n this._material.baseColor.texture = this._texture;\n\n this._renderPrimitive = null;\n }\n\n onRendererChanged(renderer) {\n this._renderPrimitive = null;\n\n let boxBuilder = new BoxBuilder();\n\n // Build the spinning \"hero\" cubes\n boxBuilder.pushCube([0, 0.25, -0.8], 0.1);\n boxBuilder.pushCube([0.8, 0.25, 0], 0.1);\n boxBuilder.pushCube([0, 0.25, 0.8], 0.1);\n boxBuilder.pushCube([-0.8, 0.25, 0], 0.1);\n\n let heroPrimitive = boxBuilder.finishPrimitive(renderer);\n\n this.heroNode = renderer.createMesh(heroPrimitive, this._material);\n\n this.rebuildCubes(boxBuilder);\n\n this.cubeSeaNode = new Node();\n this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive);\n\n this.addNode(this.cubeSeaNode);\n this.addNode(this.heroNode);\n\n return this.waitForComplete();\n }\n\n rebuildCubes(boxBuilder) {\n if (!this._renderer) {\n return;\n }\n\n if (!boxBuilder) {\n boxBuilder = new BoxBuilder();\n } else {\n boxBuilder.clear();\n }\n\n let size = 0.4 * this.cubeScale;\n\n // Build the cube sea\n let halfGrid = this.cubeCount * 0.5;\n for (let x = 0; x < this.cubeCount; ++x) {\n for (let y = 0; y < this.cubeCount; ++y) {\n for (let z = 0; z < this.cubeCount; ++z) {\n let pos = [x - halfGrid, y - halfGrid, z - halfGrid];\n // Only draw cubes on one side. Useful for testing variable render\n // cost that depends on view direction.\n if (this.halfOnly && pos[0] < 0) {\n continue;\n }\n\n // Don't place a cube in the center of the grid.\n if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0) {\n continue;\n }\n\n boxBuilder.pushCube(pos, size);\n }\n }\n }\n\n if (this.cubeCount > 12) {\n // Each cube has 6 sides with 2 triangles and 3 indices per triangle, so\n // the total number of indices needed is cubeCount^3 * 36. This exceeds\n // the short index range past 12 cubes.\n boxBuilder.indexType = 5125; // gl.UNSIGNED_INT\n }\n let cubeSeaPrimitive = boxBuilder.finishPrimitive(this._renderer);\n\n if (!this._renderPrimitive) {\n this._renderPrimitive = this._renderer.createRenderPrimitive(cubeSeaPrimitive, this._material);\n } else {\n this._renderPrimitive.setPrimitive(cubeSeaPrimitive);\n }\n }\n\n onUpdate(timestamp, frameDelta) {\n if (this.autoRotate) {\n mat4.fromRotation(this.cubeSeaNode.matrix, timestamp / 500, [0, -1, 0]);\n }\n mat4.fromRotation(this.heroNode.matrix, timestamp / 2000, [0, 1, 0]);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {PrimitiveStream} from '../geometry/primitive-stream.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst SHADOW_SEGMENTS = 32;\nconst SHADOW_GROUND_OFFSET = 0.01;\nconst SHADOW_CENTER_ALPHA = 0.7;\nconst SHADOW_INNER_ALPHA = 0.3;\nconst SHADOW_OUTER_ALPHA = 0.0;\nconst SHADOW_INNER_RADIUS = 0.6;\nconst SHADOW_OUTER_RADIUS = 1.0;\n\nclass DropShadowMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;\n this.state.depthFunc = GL.LEQUAL;\n this.state.depthMask = false;\n }\n\n get materialName() {\n return 'DROP_SHADOW_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying float vShadow;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vShadow = TEXCOORD_0.x;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n varying float vShadow;\n\n vec4 fragment_main() {\n return vec4(0.0, 0.0, 0.0, vShadow);\n }`;\n }\n}\n\nexport class DropShadowNode extends Node {\n constructor(iconTexture, callback) {\n super();\n }\n\n onRendererChanged(renderer) {\n let stream = new PrimitiveStream();\n\n stream.startGeometry();\n\n // Shadow center\n stream.pushVertex(0, SHADOW_GROUND_OFFSET, 0, SHADOW_CENTER_ALPHA);\n\n let segRad = ((Math.PI * 2.0) / SHADOW_SEGMENTS);\n\n let idx;\n for (let i = 0; i < SHADOW_SEGMENTS; ++i) {\n idx = stream.nextVertexIndex;\n\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n stream.pushVertex(x * SHADOW_INNER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_INNER_RADIUS, SHADOW_INNER_ALPHA);\n stream.pushVertex(x * SHADOW_OUTER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_OUTER_RADIUS, SHADOW_OUTER_ALPHA);\n\n if (i > 0) {\n // Inner circle\n stream.pushTriangle(0, idx, idx-2);\n\n // Outer circle\n stream.pushTriangle(idx, idx+1, idx-1);\n stream.pushTriangle(idx, idx-1, idx-2);\n }\n }\n\n stream.pushTriangle(0, 1, idx);\n\n stream.pushTriangle(1, 2, idx+1);\n stream.pushTriangle(1, idx+1, idx);\n\n stream.endGeometry();\n\n let shadowPrimitive = stream.finishPrimitive(renderer);\n this._shadowRenderPrimitive = renderer.createRenderPrimitive(shadowPrimitive, new DropShadowMaterial());\n this.addRenderPrimitive(this._shadowRenderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Node} from '../core/node.js';\nimport {Gltf2Loader} from '../loaders/gltf2.js';\n\n// Using a weak map here allows us to cache a loader per-renderer without\n// modifying the renderer object or leaking memory when it's garbage collected.\nlet gltfLoaderMap = new WeakMap();\n\nexport class Gltf2Node extends Node {\n constructor(options) {\n super();\n this._url = options.url;\n\n this._promise = null;\n this._resolver = null;\n this._rejecter = null;\n }\n\n onRendererChanged(renderer) {\n let loader = gltfLoaderMap.get(renderer);\n if (!loader) {\n loader = new Gltf2Loader(renderer);\n gltfLoaderMap.set(renderer, loader);\n }\n\n // Do we have a previously resolved promise? If so clear it.\n if (!this._resolver && this._promise) {\n this._promise = null;\n }\n\n this._ensurePromise();\n\n loader.loadFromUrl(this._url).then((sceneNode) => {\n this.addNode(sceneNode);\n this._resolver(sceneNode.waitForComplete());\n this._resolver = null;\n this._rejecter = null;\n }).catch((err) => {\n this._rejecter(err);\n this._resolver = null;\n this._rejecter = null;\n });\n }\n\n _ensurePromise() {\n if (!this._promise) {\n this._promise = new Promise((resolve, reject) => {\n this._resolver = resolve;\n this._rejecter = reject;\n });\n }\n return this._promise;\n }\n\n waitForComplete() {\n return this._ensurePromise();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material, RENDER_ORDER} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {DataTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\n// Laser texture data, 48x1 RGBA (not premultiplied alpha). This represents a\n// \"cross section\" of the laser beam with a bright core and a feathered edge.\n// Borrowed from Chromium source code.\nconst LASER_TEXTURE_DATA = new Uint8Array([\n0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xbf, 0xbf, 0xbf, 0x04, 0xcc, 0xcc, 0xcc, 0x05,\n0xdb, 0xdb, 0xdb, 0x07, 0xcc, 0xcc, 0xcc, 0x0a, 0xd8, 0xd8, 0xd8, 0x0d, 0xd2, 0xd2, 0xd2, 0x11,\n0xce, 0xce, 0xce, 0x15, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x1f, 0xcd, 0xcd, 0xcd, 0x24,\n0xc8, 0xc8, 0xc8, 0x2a, 0xc9, 0xc9, 0xc9, 0x2f, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x39,\n0xc9, 0xc9, 0xc9, 0x3d, 0xc8, 0xc8, 0xc8, 0x41, 0xcb, 0xcb, 0xcb, 0x44, 0xee, 0xee, 0xee, 0x87,\n0xfa, 0xfa, 0xfa, 0xc8, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc9,\n0xfa, 0xfa, 0xfa, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc8,\n0xee, 0xee, 0xee, 0x87, 0xcb, 0xcb, 0xcb, 0x44, 0xc8, 0xc8, 0xc8, 0x41, 0xc9, 0xc9, 0xc9, 0x3d,\n0xc9, 0xc9, 0xc9, 0x39, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x2f, 0xc8, 0xc8, 0xc8, 0x2a,\n0xcd, 0xcd, 0xcd, 0x24, 0xce, 0xce, 0xce, 0x1f, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x15,\n0xd2, 0xd2, 0xd2, 0x11, 0xd8, 0xd8, 0xd8, 0x0d, 0xcc, 0xcc, 0xcc, 0x0a, 0xdb, 0xdb, 0xdb, 0x07,\n0xcc, 0xcc, 0xcc, 0x05, 0xbf, 0xbf, 0xbf, 0x04, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01,\n]);\n\nconst LASER_LENGTH = 1.0;\nconst LASER_DIAMETER = 0.01;\nconst LASER_FADE_END = 0.535;\nconst LASER_FADE_POINT = 0.5335;\nconst LASER_DEFAULT_COLOR = [1.0, 1.0, 1.0, 0.25];\n\nconst CURSOR_RADIUS = 0.004;\nconst CURSOR_SHADOW_RADIUS = 0.007;\nconst CURSOR_SHADOW_INNER_LUMINANCE = 0.5;\nconst CURSOR_SHADOW_OUTER_LUMINANCE = 0.0;\nconst CURSOR_SHADOW_INNER_OPACITY = 0.75;\nconst CURSOR_SHADOW_OUTER_OPACITY = 0.0;\nconst CURSOR_OPACITY = 0.9;\nconst CURSOR_SEGMENTS = 16;\nconst CURSOR_DEFAULT_COLOR = [1.0, 1.0, 1.0, 1.0];\nconst CURSOR_DEFAULT_HIDDEN_COLOR = [0.5, 0.5, 0.5, 0.25];\n\nconst DEFAULT_RESET_OPTIONS = {\n controllers: true,\n lasers: true,\n cursors: true,\n};\n\nclass LaserMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.blendFuncDst = GL.ONE;\n this.state.depthMask = false;\n\n this.laser = this.defineSampler('diffuse');\n this.laser.texture = new DataTexture(LASER_TEXTURE_DATA, 48, 1);\n this.laserColor = this.defineUniform('laserColor', LASER_DEFAULT_COLOR);\n }\n\n get materialName() {\n return 'INPUT_LASER';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n\n uniform vec4 laserColor;\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n const float fadePoint = ${LASER_FADE_POINT};\n const float fadeEnd = ${LASER_FADE_END};\n\n vec4 fragment_main() {\n vec2 uv = vTexCoord;\n float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);\n float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);\n vec4 color = laserColor * texture2D(diffuse, vTexCoord);\n float opacity = color.a * front_fade_factor * back_fade_factor;\n return vec4(color.rgb * opacity, opacity);\n }`;\n }\n}\n\nconst CURSOR_VERTEX_SHADER = `\nattribute vec4 POSITION;\n\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vLuminance = POSITION.z;\n vOpacity = POSITION.w;\n\n // Billboarded, constant size vertex transform.\n vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);\n screenPos /= screenPos.w;\n screenPos.xy += POSITION.xy;\n return screenPos;\n}`;\n\nconst CURSOR_FRAGMENT_SHADER = `\nprecision mediump float;\n\nuniform vec4 cursorColor;\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 fragment_main() {\n vec3 color = cursorColor.rgb * vLuminance;\n float opacity = cursorColor.a * vOpacity;\n return vec4(color * opacity, opacity);\n}`;\n\n// Cursors are drawn as billboards that always face the camera and are rendered\n// as a fixed size no matter how far away they are.\nclass CursorMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.depthMask = false;\n\n this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_COLOR);\n }\n\n get materialName() {\n return 'INPUT_CURSOR';\n }\n\n get vertexSource() {\n return CURSOR_VERTEX_SHADER;\n }\n\n get fragmentSource() {\n return CURSOR_FRAGMENT_SHADER;\n }\n}\n\nclass CursorHiddenMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.depthFunc = GL.GEQUAL;\n this.state.depthMask = false;\n\n this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_HIDDEN_COLOR);\n }\n\n // TODO: Rename to \"program_name\"\n get materialName() {\n return 'INPUT_CURSOR_2';\n }\n\n get vertexSource() {\n return CURSOR_VERTEX_SHADER;\n }\n\n get fragmentSource() {\n return CURSOR_FRAGMENT_SHADER;\n }\n}\n\nexport class InputRenderer extends Node {\n constructor() {\n super();\n\n this._maxInputElements = 32;\n\n this._controllers = [];\n this._controllerNode = null;\n this._controllerNodeHandedness = null;\n this._lasers = null;\n this._cursors = null;\n\n this._activeControllers = 0;\n this._activeLasers = 0;\n this._activeCursors = 0;\n }\n\n onRendererChanged(renderer) {\n this._controllers = [];\n this._controllerNode = null;\n this._controllerNodeHandedness = null;\n this._lasers = null;\n this._cursors = null;\n\n this._activeControllers = 0;\n this._activeLasers = 0;\n this._activeCursors = 0;\n }\n\n setControllerMesh(controllerNode, handedness = 'right') {\n this._controllerNode = controllerNode;\n this._controllerNode.visible = false;\n // FIXME: Temporary fix to initialize for cloning.\n this.addNode(this._controllerNode);\n this._controllerNodeHandedness = handedness;\n }\n\n addController(gripMatrix) {\n if (!this._controllerNode) {\n return;\n }\n\n let controller = null;\n if (this._activeControllers < this._controllers.length) {\n controller = this._controllers[this._activeControllers];\n } else {\n controller = this._controllerNode.clone();\n this.addNode(controller);\n this._controllers.push(controller);\n }\n this._activeControllers = (this._activeControllers + 1) % this._maxInputElements;\n\n controller.matrix = gripMatrix;\n controller.visible = true;\n }\n\n addLaserPointer(targetRay) {\n // Create the laser pointer mesh if needed.\n if (!this._lasers && this._renderer) {\n this._lasers = [this._createLaserMesh()];\n this.addNode(this._lasers[0]);\n }\n\n let laser = null;\n if (this._activeLasers < this._lasers.length) {\n laser = this._lasers[this._activeLasers];\n } else {\n laser = this._lasers[0].clone();\n this.addNode(laser);\n this._lasers.push(laser);\n }\n this._activeLasers = (this._activeLasers + 1) % this._maxInputElements;\n\n laser.matrix = targetRay.transformMatrix;\n laser.visible = true;\n }\n\n addCursor(cursorPos) {\n // Create the cursor mesh if needed.\n if (!this._cursors && this._renderer) {\n this._cursors = [this._createCursorMesh()];\n this.addNode(this._cursors[0]);\n }\n\n let cursor = null;\n if (this._activeCursors < this._cursors.length) {\n cursor = this._cursors[this._activeCursors];\n } else {\n cursor = this._cursors[0].clone();\n this.addNode(cursor);\n this._cursors.push(cursor);\n }\n this._activeCursors = (this._activeCursors + 1) % this._maxInputElements;\n\n cursor.translation = cursorPos;\n cursor.visible = true;\n }\n\n reset(options) {\n if (!options) {\n options = DEFAULT_RESET_OPTIONS;\n }\n if (this._controllers && options.controllers) {\n for (let controller of this._controllers) {\n controller.visible = false;\n }\n this._activeControllers = 0;\n }\n if (this._lasers && options.lasers) {\n for (let laser of this._lasers) {\n laser.visible = false;\n }\n this._activeLasers = 0;\n }\n if (this._cursors && options.cursors) {\n for (let cursor of this._cursors) {\n cursor.visible = false;\n }\n this._activeCursors = 0;\n }\n }\n\n _createLaserMesh() {\n let gl = this._renderer._gl;\n\n let lr = LASER_DIAMETER * 0.5;\n let ll = LASER_LENGTH;\n\n // Laser is rendered as cross-shaped beam\n let laserVerts = [\n // X Y Z U V\n 0.0, lr, 0.0, 0.0, 1.0,\n 0.0, lr, -ll, 0.0, 0.0,\n 0.0, -lr, 0.0, 1.0, 1.0,\n 0.0, -lr, -ll, 1.0, 0.0,\n\n lr, 0.0, 0.0, 0.0, 1.0,\n lr, 0.0, -ll, 0.0, 0.0,\n -lr, 0.0, 0.0, 1.0, 1.0,\n -lr, 0.0, -ll, 1.0, 0.0,\n\n 0.0, -lr, 0.0, 0.0, 1.0,\n 0.0, -lr, -ll, 0.0, 0.0,\n 0.0, lr, 0.0, 1.0, 1.0,\n 0.0, lr, -ll, 1.0, 0.0,\n\n -lr, 0.0, 0.0, 0.0, 1.0,\n -lr, 0.0, -ll, 0.0, 0.0,\n lr, 0.0, 0.0, 1.0, 1.0,\n lr, 0.0, -ll, 1.0, 0.0,\n ];\n let laserIndices = [\n 0, 1, 2, 1, 3, 2,\n 4, 5, 6, 5, 7, 6,\n 8, 9, 10, 9, 11, 10,\n 12, 13, 14, 13, 15, 14,\n ];\n\n let laserVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(laserVerts));\n let laserIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(laserIndices));\n\n let laserIndexCount = laserIndices.length;\n\n let laserAttribs = [\n new PrimitiveAttribute('POSITION', laserVertexBuffer, 3, gl.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', laserVertexBuffer, 2, gl.FLOAT, 20, 12),\n ];\n\n let laserPrimitive = new Primitive(laserAttribs, laserIndexCount);\n laserPrimitive.setIndexBuffer(laserIndexBuffer);\n\n let laserMaterial = new LaserMaterial();\n\n let laserRenderPrimitive = this._renderer.createRenderPrimitive(laserPrimitive, laserMaterial);\n let meshNode = new Node();\n meshNode.addRenderPrimitive(laserRenderPrimitive);\n return meshNode;\n }\n\n _createCursorMesh() {\n let gl = this._renderer._gl;\n\n // Cursor is a circular white dot with a dark \"shadow\" skirt around the edge\n // that fades from black to transparent as it moves out from the center.\n // Cursor verts are packed as [X, Y, Luminance, Opacity]\n let cursorVerts = [];\n let cursorIndices = [];\n\n let segRad = (2.0 * Math.PI) / CURSOR_SEGMENTS;\n\n // Cursor center\n for (let i = 0; i < CURSOR_SEGMENTS; ++i) {\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS, 1.0, CURSOR_OPACITY);\n\n if (i > 1) {\n cursorIndices.push(0, i-1, i);\n }\n }\n\n let indexOffset = CURSOR_SEGMENTS;\n\n // Cursor Skirt\n for (let i = 0; i < CURSOR_SEGMENTS; ++i) {\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS,\n CURSOR_SHADOW_INNER_LUMINANCE, CURSOR_SHADOW_INNER_OPACITY);\n cursorVerts.push(x * CURSOR_SHADOW_RADIUS, y * CURSOR_SHADOW_RADIUS,\n CURSOR_SHADOW_OUTER_LUMINANCE, CURSOR_SHADOW_OUTER_OPACITY);\n\n if (i > 0) {\n let idx = indexOffset + (i * 2);\n cursorIndices.push(idx-2, idx-1, idx);\n cursorIndices.push(idx-1, idx+1, idx);\n }\n }\n\n let idx = indexOffset + (CURSOR_SEGMENTS * 2);\n cursorIndices.push(idx-2, idx-1, indexOffset);\n cursorIndices.push(idx-1, indexOffset+1, indexOffset);\n\n let cursorVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(cursorVerts));\n let cursorIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cursorIndices));\n\n let cursorIndexCount = cursorIndices.length;\n\n let cursorAttribs = [\n new PrimitiveAttribute('POSITION', cursorVertexBuffer, 4, gl.FLOAT, 16, 0),\n ];\n\n let cursorPrimitive = new Primitive(cursorAttribs, cursorIndexCount);\n cursorPrimitive.setIndexBuffer(cursorIndexBuffer);\n\n let cursorMaterial = new CursorMaterial();\n let cursorHiddenMaterial = new CursorHiddenMaterial();\n\n // Cursor renders two parts: The bright opaque cursor for areas where it's\n // not obscured and a more transparent, darker version for areas where it's\n // behind another object.\n let cursorRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorMaterial);\n let cursorHiddenRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorHiddenMaterial);\n let meshNode = new Node();\n meshNode.addRenderPrimitive(cursorRenderPrimitive);\n meshNode.addRenderPrimitive(cursorHiddenRenderPrimitive);\n return meshNode;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nRenders simple text using a seven-segment LED style pattern. Only really good\nfor numbers and a limited number of other characters.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\n\nconst TEXT_KERNING = 2.0;\n\nclass SevenSegmentMaterial extends Material {\n get materialName() {\n return 'SEVEN_SEGMENT_TEXT';\n }\n\n get vertexSource() {\n return `\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 0.0, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n\n vec4 fragment_main() {\n return color;\n }`;\n }\n}\n\nexport class SevenSegmentText extends Node {\n constructor() {\n super();\n\n this._text = '';\n this._charNodes = [];\n }\n\n onRendererChanged(renderer) {\n this.clearNodes();\n this._charNodes = [];\n\n let vertices = [];\n let segmentIndices = {};\n let indices = [];\n\n const width = 0.5;\n const thickness = 0.25;\n\n function defineSegment(id, left, top, right, bottom) {\n let idx = vertices.length / 2;\n vertices.push(\n left, top,\n right, top,\n right, bottom,\n left, bottom);\n\n segmentIndices[id] = [\n idx, idx+2, idx+1,\n idx, idx+3, idx+2,\n ];\n }\n\n let characters = {};\n function defineCharacter(c, segments) {\n let character = {\n character: c,\n offset: indices.length * 2,\n count: 0,\n };\n\n for (let i = 0; i < segments.length; ++i) {\n let idx = segments[i];\n let segment = segmentIndices[idx];\n character.count += segment.length;\n indices.push(...segment);\n }\n\n characters[c] = character;\n }\n\n /* Segment layout is as follows:\n\n |-0-|\n 3 4\n |-1-|\n 5 6\n |-2-|\n\n */\n\n defineSegment(0, -1, 1, width, 1-thickness);\n defineSegment(1, -1, thickness*0.5, width, -thickness*0.5);\n defineSegment(2, -1, -1+thickness, width, -1);\n defineSegment(3, -1, 1, -1+thickness, -thickness*0.5);\n defineSegment(4, width-thickness, 1, width, -thickness*0.5);\n defineSegment(5, -1, thickness*0.5, -1+thickness, -1);\n defineSegment(6, width-thickness, thickness*0.5, width, -1);\n\n\n defineCharacter('0', [0, 2, 3, 4, 5, 6]);\n defineCharacter('1', [4, 6]);\n defineCharacter('2', [0, 1, 2, 4, 5]);\n defineCharacter('3', [0, 1, 2, 4, 6]);\n defineCharacter('4', [1, 3, 4, 6]);\n defineCharacter('5', [0, 1, 2, 3, 6]);\n defineCharacter('6', [0, 1, 2, 3, 5, 6]);\n defineCharacter('7', [0, 4, 6]);\n defineCharacter('8', [0, 1, 2, 3, 4, 5, 6]);\n defineCharacter('9', [0, 1, 2, 3, 4, 6]);\n defineCharacter('A', [0, 1, 3, 4, 5, 6]);\n defineCharacter('B', [1, 2, 3, 5, 6]);\n defineCharacter('C', [0, 2, 3, 5]);\n defineCharacter('D', [1, 2, 4, 5, 6]);\n defineCharacter('E', [0, 1, 2, 4, 6]);\n defineCharacter('F', [0, 1, 3, 5]);\n defineCharacter('P', [0, 1, 3, 4, 5]);\n defineCharacter('-', [1]);\n defineCharacter(' ', []);\n defineCharacter('_', [2]); // Used for undefined characters\n\n let gl = renderer.gl;\n let vertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let vertexAttribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 2, gl.FLOAT, 8, 0),\n ];\n\n let primitive = new Primitive(vertexAttribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let material = new SevenSegmentMaterial();\n\n this._charPrimitives = {};\n for (let char in characters) {\n let charDef = characters[char];\n primitive.elementCount = charDef.count;\n primitive.indexByteOffset = charDef.offset;\n this._charPrimitives[char] = renderer.createRenderPrimitive(primitive, material);\n }\n\n this.text = this._text;\n }\n\n get text() {\n return this._text;\n }\n\n set text(value) {\n this._text = value;\n\n let i = 0;\n let charPrimitive = null;\n for (; i < value.length; ++i) {\n if (value[i] in this._charPrimitives) {\n charPrimitive = this._charPrimitives[value[i]];\n } else {\n charPrimitive = this._charPrimitives['_'];\n }\n\n if (this._charNodes.length <= i) {\n let node = new Node();\n node.addRenderPrimitive(charPrimitive);\n let offset = i * TEXT_KERNING;\n node.translation = [offset, 0, 0];\n this._charNodes.push(node);\n this.addNode(node);\n } else {\n // This is sort of an abuse of how these things are expected to work,\n // but it's the cheapest thing I could think of that didn't break the\n // world.\n this._charNodes[i].clearRenderPrimitives();\n this._charNodes[i].addRenderPrimitive(charPrimitive);\n this._charNodes[i].visible = true;\n }\n }\n\n // If there's any nodes left over make them invisible\n for (; i < this._charNodes.length; ++i) {\n this._charNodes[i].visible = false;\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nNode for displaying 360 equirect images as a skybox.\n*/\n\nimport {Material, RENDER_ORDER} from '../core/material.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {Node} from '../core/node.js';\nimport {UrlTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass SkyboxMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.SKY;\n this.state.depthFunc = GL.LEQUAL;\n this.state.depthMask = false;\n\n this.image = this.defineSampler('diffuse');\n\n this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',\n [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0], 4);\n }\n\n get materialName() {\n return 'SKYBOX';\n }\n\n get vertexSource() {\n return `\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n // Drop the translation portion of the view matrix\n view[3].xyz = vec3(0.0, 0.0, 0.0);\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n\n // Returning the W component for both Z and W forces the geometry depth to\n // the far plane. When combined with a depth func of LEQUAL this makes the\n // sky write to any depth fragment that has not been written to yet.\n return out_vec.xyww;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }`;\n }\n}\n\nexport class SkyboxNode extends Node {\n constructor(options) {\n super();\n\n this._url = options.url;\n this._displayMode = options.displayMode || 'mono';\n this._rotationY = options.rotationY || 0;\n }\n\n onRendererChanged(renderer) {\n let vertices = [];\n let indices = [];\n\n let latSegments = 40;\n let lonSegments = 40;\n\n // Create the vertices/indices\n for (let i=0; i <= latSegments; ++i) {\n let theta = i * Math.PI / latSegments;\n let sinTheta = Math.sin(theta);\n let cosTheta = Math.cos(theta);\n\n let idxOffsetA = i * (lonSegments+1);\n let idxOffsetB = (i+1) * (lonSegments+1);\n\n for (let j=0; j <= lonSegments; ++j) {\n let phi = (j * 2 * Math.PI / lonSegments) + this._rotationY;\n let x = Math.sin(phi) * sinTheta;\n let y = cosTheta;\n let z = -Math.cos(phi) * sinTheta;\n let u = (j / lonSegments);\n let v = (i / latSegments);\n\n // Vertex shader will force the geometry to the far plane, so the\n // radius of the sphere is immaterial.\n vertices.push(x, y, z, u, v);\n\n if (i < latSegments && j < lonSegments) {\n let idxA = idxOffsetA+j;\n let idxB = idxOffsetB+j;\n\n indices.push(idxA, idxB, idxA+1,\n idxB, idxB+1, idxA+1);\n }\n }\n }\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let material = new SkyboxMaterial();\n material.image.texture = new UrlTexture(this._url);\n\n switch (this._displayMode) {\n case 'mono':\n material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0];\n break;\n case 'stereoTopBottom':\n material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,\n 1.0, 0.5, 0.0, 0.5];\n break;\n case 'stereoLeftRight':\n material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,\n 0.5, 1.0, 0.5, 0.0];\n break;\n }\n\n let renderPrimitive = renderer.createRenderPrimitive(primitive, material);\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nHeavily inspired by Mr. Doobs stats.js, this FPS counter is rendered completely\nwith WebGL, allowing it to be shown in cases where overlaid HTML elements aren't\nusable (like WebXR), or if you want the FPS counter to be rendered as part of\nyour scene.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {SevenSegmentText} from './seven-segment-text.js';\n\nconst SEGMENTS = 30;\nconst MAX_FPS = 90;\n\nclass StatsMaterial extends Material {\n get materialName() {\n return 'STATS_VIEWER';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec3 COLOR_0;\n varying vec4 vColor;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vColor = vec4(COLOR_0, 1.0);\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n varying vec4 vColor;\n\n vec4 fragment_main() {\n return vColor;\n }`;\n }\n}\n\nfunction segmentToX(i) {\n return ((0.9/SEGMENTS) * i) - 0.45;\n}\n\nfunction fpsToY(value) {\n return (Math.min(value, MAX_FPS) * (0.7 / MAX_FPS)) - 0.45;\n}\n\nfunction fpsToRGB(value) {\n return {\n r: Math.max(0.0, Math.min(1.0, 1.0 - (value/60))),\n g: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),\n b: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),\n };\n}\n\nlet now = (window.performance && performance.now) ? performance.now.bind(performance) : Date.now;\n\nexport class StatsViewer extends Node {\n constructor() {\n super();\n\n this._performanceMonitoring = false;\n\n this._startTime = now();\n this._prevFrameTime = this._startTime;\n this._prevGraphUpdateTime = this._startTime;\n this._frames = 0;\n this._fpsAverage = 0;\n this._fpsMin = 0;\n this._fpsStep = this._performanceMonitoring ? 1000 : 250;\n this._lastSegment = 0;\n\n this._fpsVertexBuffer = null;\n this._fpsRenderPrimitive = null;\n this._fpsNode = null;\n\n this._sevenSegmentNode = new SevenSegmentText();\n // Hard coded because it doesn't change:\n // Scale by 0.075 in X and Y\n // Translate into upper left corner w/ z = 0.02\n this._sevenSegmentNode.matrix = new Float32Array([\n 0.075, 0, 0, 0,\n 0, 0.075, 0, 0,\n 0, 0, 1, 0,\n -0.3625, 0.3625, 0.02, 1,\n ]);\n }\n\n onRendererChanged(renderer) {\n this.clearNodes();\n\n let gl = renderer.gl;\n\n let fpsVerts = [];\n let fpsIndices = [];\n\n // Graph geometry\n for (let i = 0; i < SEGMENTS; ++i) {\n // Bar top\n fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n\n // Bar bottom\n fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n\n let idx = i * 4;\n fpsIndices.push(idx, idx+3, idx+1,\n idx+3, idx, idx+2);\n }\n\n function addBGSquare(left, bottom, right, top, z, r, g, b) {\n let idx = fpsVerts.length / 6;\n\n fpsVerts.push(left, bottom, z, r, g, b);\n fpsVerts.push(right, top, z, r, g, b);\n fpsVerts.push(left, top, z, r, g, b);\n fpsVerts.push(right, bottom, z, r, g, b);\n\n fpsIndices.push(idx, idx+1, idx+2,\n idx, idx+3, idx+1);\n }\n\n // Panel Background\n addBGSquare(-0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.125);\n\n // FPS Background\n addBGSquare(-0.45, -0.45, 0.45, 0.25, 0.01, 0.0, 0.0, 0.4);\n\n // 30 FPS line\n addBGSquare(-0.45, fpsToY(30), 0.45, fpsToY(32), 0.015, 0.5, 0.0, 0.5);\n\n // 60 FPS line\n addBGSquare(-0.45, fpsToY(60), 0.45, fpsToY(62), 0.015, 0.2, 0.0, 0.75);\n\n this._fpsVertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(fpsVerts), gl.DYNAMIC_DRAW);\n let fpsIndexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(fpsIndices));\n\n let fpsAttribs = [\n new PrimitiveAttribute('POSITION', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 0),\n new PrimitiveAttribute('COLOR_0', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 12),\n ];\n\n let fpsPrimitive = new Primitive(fpsAttribs, fpsIndices.length);\n fpsPrimitive.setIndexBuffer(fpsIndexBuffer);\n fpsPrimitive.setBounds([-0.5, -0.5, 0.0], [0.5, 0.5, 0.015]);\n\n this._fpsRenderPrimitive = renderer.createRenderPrimitive(fpsPrimitive, new StatsMaterial());\n this._fpsNode = new Node();\n this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive);\n\n this.addNode(this._fpsNode);\n this.addNode(this._sevenSegmentNode);\n }\n\n get performanceMonitoring() {\n return this._performanceMonitoring;\n }\n\n set performanceMonitoring(value) {\n this._performanceMonitoring = value;\n this._fpsStep = value ? 1000 : 250;\n }\n\n begin() {\n this._startTime = now();\n }\n\n end() {\n let time = now();\n\n let frameFps = 1000 / (time - this._prevFrameTime);\n this._prevFrameTime = time;\n this._fpsMin = this._frames ? Math.min(this._fpsMin, frameFps) : frameFps;\n this._frames++;\n\n if (time > this._prevGraphUpdateTime + this._fpsStep) {\n let intervalTime = time - this._prevGraphUpdateTime;\n this._fpsAverage = Math.round(1000 / (intervalTime / this._frames));\n\n // Draw both average and minimum FPS for this period\n // so that dropped frames are more clearly visible.\n this._updateGraph(this._fpsMin, this._fpsAverage);\n if (this._performanceMonitoring) {\n console.log(`Average FPS: ${this._fpsAverage} Min FPS: ${this._fpsMin}`);\n }\n\n this._prevGraphUpdateTime = time;\n this._frames = 0;\n this._fpsMin = 0;\n }\n }\n\n _updateGraph(valueLow, valueHigh) {\n let color = fpsToRGB(valueLow);\n // Draw a range from the low to high value. Artificially widen the\n // range a bit to ensure that near-equal values still remain\n // visible - the logic here should match that used by the\n // \"60 FPS line\" setup below. Hitting 60fps consistently will\n // keep the top half of the 60fps background line visible.\n let y0 = fpsToY(valueLow - 1);\n let y1 = fpsToY(valueHigh + 1);\n\n // Update the current segment with the new FPS value\n let updateVerts = [\n segmentToX(this._lastSegment), y1, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), y1, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment), y0, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), y0, 0.02, color.r, color.g, color.b,\n ];\n\n // Re-shape the next segment into the green \"progress\" line\n color.r = 0.2;\n color.g = 1.0;\n color.b = 0.2;\n\n if (this._lastSegment == SEGMENTS - 1) {\n // If we're updating the last segment we need to do two bufferSubDatas\n // to update the segment and turn the first segment into the progress line.\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),\n this._lastSegment * 24 * 4);\n updateVerts = [\n segmentToX(0), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(0), fpsToY(0), 0.02, color.r, color.g, color.b,\n segmentToX(.25), fpsToY(0), 0.02, color.r, color.g, color.b,\n ];\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts), 0);\n } else {\n updateVerts.push(\n segmentToX(this._lastSegment+1), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), fpsToY(0), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1.25), fpsToY(0), 0.02, color.r, color.g, color.b\n );\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),\n this._lastSegment * 24 * 4);\n }\n\n this._lastSegment = (this._lastSegment+1) % SEGMENTS;\n\n this._sevenSegmentNode.text = `${this._fpsAverage} FP5`;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nNode for displaying 2D or stereo videos on a quad.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {Node} from '../core/node.js';\nimport {VideoTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass VideoMaterial extends Material {\n constructor() {\n super();\n\n this.image = this.defineSampler('diffuse');\n\n this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',\n [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0], 4);\n }\n\n get materialName() {\n return 'VIDEO_PLAYER';\n }\n\n get vertexSource() {\n return `\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n return out_vec;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }`;\n }\n}\n\nexport class VideoNode extends Node {\n constructor(options) {\n super();\n\n this._video = options.video;\n this._displayMode = options.displayMode || 'mono';\n\n this._video_texture = new VideoTexture(this._video);\n }\n\n get aspectRatio() {\n let width = this._video.videoWidth;\n let height = this._video.videoHeight;\n\n switch (this._displayMode) {\n case 'stereoTopBottom': height *= 0.5; break;\n case 'stereoLeftRight': width *= 0.5; break;\n }\n\n if (!height || !width) {\n return 1;\n }\n\n return width / height;\n }\n\n onRendererChanged(renderer) {\n let vertices = [\n -1.0, 1.0, 0.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 1.0, 0.0,\n 1.0, -1.0, 0.0, 1.0, 1.0,\n -1.0, -1.0, 0.0, 0.0, 1.0,\n ];\n let indices = [\n 0, 2, 1,\n 0, 3, 2,\n ];\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n primitive.setBounds([-1.0, -1.0, 0.0], [1.0, 1.0, 0.015]);\n\n let material = new VideoMaterial();\n material.image.texture = this._video_texture;\n\n switch (this._displayMode) {\n case 'mono':\n material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0];\n break;\n case 'stereoTopBottom':\n material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,\n 1.0, 0.5, 0.0, 0.5];\n break;\n case 'stereoLeftRight':\n material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,\n 0.5, 1.0, 0.5, 0.0];\n break;\n }\n\n let renderPrimitive = renderer.createRenderPrimitive(primitive, material);\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {RenderView} from '../core/renderer.js';\nimport {InputRenderer} from '../nodes/input-renderer.js';\nimport {StatsViewer} from '../nodes/stats-viewer.js';\nimport {Node} from '../core/node.js';\nimport {vec3, quat} from '../math/gl-matrix.js';\n\nexport class WebXRView extends RenderView {\n constructor(view, layer) {\n super(\n view ? view.projectionMatrix : null,\n view ? view.viewMatrix : null,\n (layer && view) ? layer.getViewport(view) : null,\n view ? view.eye : 'left'\n );\n }\n}\n\nexport class Scene extends Node {\n constructor() {\n super();\n\n this._timestamp = -1;\n this._frameDelta = 0;\n this._statsStanding = false;\n this._stats = null;\n this._statsEnabled = false;\n this.enableStats(true); // Ensure the stats are added correctly by default.\n\n this._inputRenderer = null;\n this._resetInputEndFrame = true;\n\n this._lastTimestamp = 0;\n\n this._hoverFrame = 0;\n this._hoveredNodes = [];\n\n this.clear = true;\n }\n\n setRenderer(renderer) {\n this._setRenderer(renderer);\n }\n\n loseRenderer() {\n if (this._renderer) {\n this._stats = null;\n this._renderer = null;\n this._inputRenderer = null;\n }\n }\n\n get inputRenderer() {\n if (!this._inputRenderer) {\n this._inputRenderer = new InputRenderer();\n this.addNode(this._inputRenderer);\n }\n return this._inputRenderer;\n }\n\n // Helper function that automatically adds the appropriate visual elements for\n // all input sources.\n updateInputSources(frame, frameOfRef) {\n // FIXME: Check for the existence of the API first. This check should be\n // removed once the input API is part of the official spec.\n if (!frame.session.getInputSources) {\n return;\n }\n\n let inputSources = frame.session.getInputSources();\n\n let newHoveredNodes = [];\n let lastHoverFrame = this._hoverFrame;\n this._hoverFrame++;\n\n for (let inputSource of inputSources) {\n let inputPose = frame.getInputPose(inputSource, frameOfRef);\n\n if (!inputPose) {\n continue;\n }\n\n // Any time that we have a grip matrix, we'll render a controller.\n if (inputPose.gripMatrix) {\n this.inputRenderer.addController(inputPose.gripMatrix);\n }\n\n if (inputPose.targetRay) {\n if (inputSource.targetRayMode == 'tracked-pointer') {\n // If we have a pointer matrix and the pointer origin is the users\n // hand (as opposed to their head or the screen) use it to render\n // a ray coming out of the input device to indicate the pointer\n // direction.\n this.inputRenderer.addLaserPointer(inputPose.targetRay);\n }\n\n // If we have a pointer matrix we can also use it to render a cursor\n // for both handheld and gaze-based input sources.\n\n // Check and see if the pointer is pointing at any selectable objects.\n let hitResult = this.hitTest(inputPose.targetRay);\n\n if (hitResult) {\n // Render a cursor at the intersection point.\n this.inputRenderer.addCursor(hitResult.intersection);\n\n if (hitResult.node._hoverFrameId != lastHoverFrame) {\n hitResult.node.onHoverStart();\n }\n hitResult.node._hoverFrameId = this._hoverFrame;\n newHoveredNodes.push(hitResult.node);\n } else {\n // Statically render the cursor 1 meters down the ray since we didn't\n // hit anything selectable.\n let cursorDistance = 1.0;\n let cursorPos = vec3.fromValues(\n inputPose.targetRay.origin.x,\n inputPose.targetRay.origin.y,\n inputPose.targetRay.origin.z\n );\n vec3.add(cursorPos, cursorPos, [\n inputPose.targetRay.direction.x * cursorDistance,\n inputPose.targetRay.direction.y * cursorDistance,\n inputPose.targetRay.direction.z * cursorDistance,\n ]);\n // let cursorPos = vec3.fromValues(0, 0, -1.0);\n // vec3.transformMat4(cursorPos, cursorPos, inputPose.targetRay);\n this.inputRenderer.addCursor(cursorPos);\n }\n }\n }\n\n for (let hoverNode of this._hoveredNodes) {\n if (hoverNode._hoverFrameId != this._hoverFrame) {\n hoverNode.onHoverEnd();\n }\n }\n\n this._hoveredNodes = newHoveredNodes;\n }\n\n handleSelect(inputSource, frame, frameOfRef) {\n let inputPose = frame.getInputPose(inputSource, frameOfRef);\n\n if (!inputPose) {\n return;\n }\n\n this.handleSelectPointer(inputPose.targetRay);\n }\n\n handleSelectPointer(targetRay) {\n if (targetRay) {\n // Check and see if the pointer is pointing at any selectable objects.\n let hitResult = this.hitTest(targetRay);\n\n if (hitResult) {\n // Render a cursor at the intersection point.\n hitResult.node.handleSelect();\n }\n }\n }\n\n enableStats(enable) {\n if (enable == this._statsEnabled) {\n return;\n }\n\n this._statsEnabled = enable;\n\n if (enable) {\n this._stats = new StatsViewer();\n this._stats.selectable = true;\n this.addNode(this._stats);\n\n if (this._statsStanding) {\n this._stats.translation = [0, 1.4, -0.75];\n } else {\n this._stats.translation = [0, -0.3, -0.5];\n }\n this._stats.scale = [0.3, 0.3, 0.3];\n quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);\n } else if (!enable) {\n if (this._stats) {\n this.removeNode(this._stats);\n this._stats = null;\n }\n }\n }\n\n standingStats(enable) {\n this._statsStanding = enable;\n if (this._stats) {\n if (this._statsStanding) {\n this._stats.translation = [0, 1.4, -0.75];\n } else {\n this._stats.translation = [0, -0.3, -0.5];\n }\n this._stats.scale = [0.3, 0.3, 0.3];\n quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);\n }\n }\n\n draw(projectionMatrix, viewMatrix, eye) {\n let view = new RenderView();\n view.projectionMatrix = projectionMatrix;\n view.viewMatrix = viewMatrix;\n if (eye) {\n view.eye = eye;\n }\n\n this.drawViewArray([view]);\n }\n\n /** Draws the scene into the base layer of the XRFrame's session */\n drawXRFrame(xrFrame, pose) {\n if (!this._renderer || !pose) {\n return;\n }\n\n let gl = this._renderer.gl;\n let session = xrFrame.session;\n // Assumed to be a XRWebGLLayer for now.\n let layer = session.baseLayer;\n\n if (!gl) {\n return;\n }\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);\n\n if (this.clear) {\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n }\n\n let views = [];\n for (let view of pose.views) {\n views.push(new WebXRView(view, layer));\n }\n\n this.drawViewArray(views);\n }\n\n drawViewArray(views) {\n // Don't draw when we don't have a valid context\n if (!this._renderer) {\n return;\n }\n\n this._renderer.drawViews(views, this);\n }\n\n startFrame() {\n let prevTimestamp = this._timestamp;\n this._timestamp = performance.now();\n if (this._stats) {\n this._stats.begin();\n }\n\n if (prevTimestamp >= 0) {\n this._frameDelta = this._timestamp - prevTimestamp;\n } else {\n this._frameDelta = 0;\n }\n\n this._update(this._timestamp, this._frameDelta);\n\n return this._frameDelta;\n }\n\n endFrame() {\n if (this._inputRenderer && this._resetInputEndFrame) {\n this._inputRenderer.reset();\n }\n\n if (this._stats) {\n this._stats.end();\n }\n }\n\n // Override to load scene resources on construction or context restore.\n onLoadScene(renderer) {\n return Promise.resolve();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {mat4} from '../math/gl-matrix.js';\n\nconst LOOK_SPEED = 0.0025;\n\nexport class FallbackHelper {\n constructor(scene, gl) {\n this.scene = scene;\n this.gl = gl;\n this._emulateStage = false;\n\n this.lookYaw = 0;\n this.lookPitch = 0;\n\n this.viewMatrix = mat4.create();\n\n let projectionMatrix = mat4.create();\n this.projectionMatrix = projectionMatrix;\n\n // Using a simple identity matrix for the view.\n mat4.identity(this.viewMatrix);\n\n // We need to track the canvas size in order to resize the WebGL\n // backbuffer width and height, as well as update the projection matrix\n // and adjust the viewport.\n function onResize() {\n gl.canvas.width = gl.canvas.offsetWidth * window.devicePixelRatio;\n gl.canvas.height = gl.canvas.offsetHeight * window.devicePixelRatio;\n mat4.perspective(projectionMatrix, Math.PI*0.4,\n gl.canvas.width/gl.canvas.height,\n 0.1, 1000.0);\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n }\n window.addEventListener('resize', onResize);\n onResize();\n\n // Upding the view matrix with touch or mouse events.\n let canvas = gl.canvas;\n let lastTouchX = 0;\n let lastTouchY = 0;\n canvas.addEventListener('touchstart', (ev) => {\n if (ev.touches.length == 2) {\n lastTouchX = ev.touches[1].pageX;\n lastTouchY = ev.touches[1].pageY;\n }\n });\n canvas.addEventListener('touchmove', (ev) => {\n // Rotate the view when two fingers are being used.\n if (ev.touches.length == 2) {\n this.onLook(ev.touches[1].pageX - lastTouchX, ev.touches[1].pageY - lastTouchY);\n lastTouchX = ev.touches[1].pageX;\n lastTouchY = ev.touches[1].pageY;\n }\n });\n canvas.addEventListener('mousemove', (ev) => {\n // Only rotate when the right button is pressed.\n if (ev.buttons & 2) {\n this.onLook(ev.movementX, ev.movementY);\n }\n });\n canvas.addEventListener('contextmenu', (ev) => {\n // Prevent context menus on the canvas so that we can use right click to rotate.\n ev.preventDefault();\n });\n\n this.boundOnFrame = this.onFrame.bind(this);\n window.requestAnimationFrame(this.boundOnFrame);\n }\n\n onLook(yaw, pitch) {\n this.lookYaw += yaw * LOOK_SPEED;\n this.lookPitch += pitch * LOOK_SPEED;\n\n // Clamp pitch rotation beyond looking straight up or down.\n if (this.lookPitch < -Math.PI*0.5) {\n this.lookPitch = -Math.PI*0.5;\n }\n if (this.lookPitch > Math.PI*0.5) {\n this.lookPitch = Math.PI*0.5;\n }\n\n this.updateView();\n }\n\n onFrame(t) {\n let gl = this.gl;\n window.requestAnimationFrame(this.boundOnFrame);\n\n this.scene.startFrame();\n\n // We can skip setting the framebuffer and viewport every frame, because\n // it won't change from frame to frame and we're updating the viewport\n // only when we resize for efficency.\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n\n // We're drawing with our own projection and view matrix now, and we\n // don't have a list of view to loop through, but otherwise all of the\n // WebGL drawing logic is exactly the same.\n this.scene.draw(this.projectionMatrix, this.viewMatrix);\n\n this.scene.endFrame();\n }\n\n get emulateStage() {\n return this._emulateStage;\n }\n\n set emulateStage(value) {\n this._emulateStage = value;\n this.updateView();\n }\n\n updateView() {\n mat4.identity(this.viewMatrix);\n\n mat4.rotateX(this.viewMatrix, this.viewMatrix, -this.lookPitch);\n mat4.rotateY(this.viewMatrix, this.viewMatrix, -this.lookYaw);\n\n // If we're emulating a stage frame of reference we'll need to move the view\n // matrix roughly a meter and a half up in the air.\n if (this._emulateStage) {\n mat4.translate(this.viewMatrix, this.viewMatrix, [0, -1.6, 0]);\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nProvides a simple way to get values from the query string if they're present\nand use a default value if not. Not strictly a \"WebGL\" utility, but I use it\nfrequently enough for debugging that I wanted to include it here.\n\nExample:\nFor the URL http://example.com/index.html?particleCount=1000\n\nQueryArgs.getInt(\"particleCount\", 100); // URL overrides, returns 1000\nQueryArgs.getInt(\"particleSize\", 10); // Not in URL, returns default of 10\n*/\n\nlet urlArgs = null;\nwindow.onhashchange = function() {\n // Force re-parsing on next access\n urlArgs = null;\n};\n\nfunction ensureArgsCached() {\n if (!urlArgs) {\n urlArgs = {};\n let query = window.location.search.substring(1) || window.location.hash.substring(1);\n let vars = query.split('&');\n for (let i = 0; i < vars.length; i++) {\n let pair = vars[i].split('=');\n urlArgs[pair[0].toLowerCase()] = decodeURIComponent(pair[1]);\n }\n }\n}\n\nexport class QueryArgs {\n static getString(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return urlArgs[lcaseName];\n }\n return defaultValue;\n }\n\n static getInt(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseInt(urlArgs[lcaseName], 10);\n }\n return defaultValue;\n }\n\n static getFloat(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseFloat(urlArgs[lcaseName]);\n }\n return defaultValue;\n }\n\n static getBool(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseInt(urlArgs[lcaseName], 10) != 0;\n }\n return defaultValue;\n }\n}\n"],"sourceRoot":""} \ No newline at end of file
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js
new file mode 100644
index 00000000000..a7a02da35a9
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js
@@ -0,0 +1,22 @@
+/*!
+ * 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.
+ *
+ */
+!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r=e();for(var n in r)("object"==typeof exports?exports:t)[n]=r[n]}}(window,function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)r.d(n,i,function(e){return t[e]}.bind(null,i));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=15)}([function(t,e,r){"use strict";r.r(e),r.d(e,"EPSILON",function(){return n}),r.d(e,"ARRAY_TYPE",function(){return i}),r.d(e,"RANDOM",function(){return o}),r.d(e,"setMatrixArrayType",function(){return a}),r.d(e,"toRadian",function(){return s}),r.d(e,"equals",function(){return c});const n=1e-6;let i="undefined"!=typeof Float32Array?Float32Array:Array;const o=Math.random;function a(t){i=t}const u=Math.PI/180;function s(t){return t*u}function c(t,e){return Math.abs(t-e)<=n*Math.max(1,Math.abs(t),Math.abs(e))}},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"fromValues",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"add",function(){return c}),r.d(e,"subtract",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"divide",function(){return h}),r.d(e,"ceil",function(){return d}),r.d(e,"floor",function(){return v}),r.d(e,"min",function(){return _}),r.d(e,"max",function(){return m}),r.d(e,"round",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"scaleAndAdd",function(){return b}),r.d(e,"distance",function(){return g}),r.d(e,"squaredDistance",function(){return M}),r.d(e,"length",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return E}),r.d(e,"inverse",function(){return w}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"lerp",function(){return P}),r.d(e,"random",function(){return S}),r.d(e,"transformMat4",function(){return A}),r.d(e,"transformQuat",function(){return N}),r.d(e,"str",function(){return C}),r.d(e,"exactEquals",function(){return I}),r.d(e,"equals",function(){return L}),r.d(e,"sub",function(){return k}),r.d(e,"mul",function(){return F}),r.d(e,"div",function(){return D}),r.d(e,"dist",function(){return j}),r.d(e,"sqrDist",function(){return B}),r.d(e,"len",function(){return U}),r.d(e,"sqrLen",function(){return V}),r.d(e,"forEach",function(){return Y});var n=r(0);function i(){let t=new n.ARRAY_TYPE(4);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function o(t){let e=new n.ARRAY_TYPE(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function a(t,e,r,i){let o=new n.ARRAY_TYPE(4);return o[0]=t,o[1]=e,o[2]=r,o[3]=i,o}function u(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}function s(t,e,r,n,i){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t}function c(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t}function f(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t}function l(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t[2]=e[2]*r[2],t[3]=e[3]*r[3],t}function h(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t[2]=e[2]/r[2],t[3]=e[3]/r[3],t}function d(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t[3]=Math.ceil(e[3]),t}function v(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t[3]=Math.floor(e[3]),t}function _(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t[2]=Math.min(e[2],r[2]),t[3]=Math.min(e[3],r[3]),t}function m(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t[2]=Math.max(e[2],r[2]),t[3]=Math.max(e[3],r[3]),t}function p(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t[3]=Math.round(e[3]),t}function y(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t}function b(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t}function g(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2],o=e[3]-t[3];return Math.sqrt(r*r+n*n+i*i+o*o)}function M(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2],o=e[3]-t[3];return r*r+n*n+i*i+o*o}function x(t){let e=t[0],r=t[1],n=t[2],i=t[3];return Math.sqrt(e*e+r*r+n*n+i*i)}function T(t){let e=t[0],r=t[1],n=t[2],i=t[3];return e*e+r*r+n*n+i*i}function E(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t}function w(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t[3]=1/e[3],t}function O(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*r+n*n+i*i+o*o;return a>0&&(a=1/Math.sqrt(a),t[0]=r*a,t[1]=n*a,t[2]=i*a,t[3]=o*a),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]}function P(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=e[3];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t[2]=a+n*(r[2]-a),t[3]=u+n*(r[3]-u),t}function S(t,e){var r,i,o,a,u,s;e=e||1;do{u=(r=2*n.RANDOM()-1)*r+(i=2*n.RANDOM()-1)*i}while(u>=1);do{s=(o=2*n.RANDOM()-1)*o+(a=2*n.RANDOM()-1)*a}while(s>=1);var c=Math.sqrt((1-u)/s);return t[0]=e*r,t[1]=e*i,t[2]=e*o*c,t[3]=e*a*c,t}function A(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3];return t[0]=r[0]*n+r[4]*i+r[8]*o+r[12]*a,t[1]=r[1]*n+r[5]*i+r[9]*o+r[13]*a,t[2]=r[2]*n+r[6]*i+r[10]*o+r[14]*a,t[3]=r[3]*n+r[7]*i+r[11]*o+r[15]*a,t}function N(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[0],u=r[1],s=r[2],c=r[3],f=c*n+u*o-s*i,l=c*i+s*n-a*o,h=c*o+a*i-u*n,d=-a*n-u*i-s*o;return t[0]=f*c+d*-a+l*-s-h*-u,t[1]=l*c+d*-u+h*-a-f*-s,t[2]=h*c+d*-s+f*-u-l*-a,t[3]=e[3],t}function C(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function I(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]}function L(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=e[0],s=e[1],c=e[2],f=e[3];return Math.abs(r-u)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(u))&&Math.abs(i-s)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(o-c)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(c))&&Math.abs(a-f)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(f))}const k=f,F=l,D=h,j=g,B=M,U=x,V=T,Y=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=4),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],t[2]=e[u+2],t[3]=e[u+3],o(t,t,a),e[u]=t[0],e[u+1]=t[1],e[u+2]=t[2],e[u+3]=t[3];return e}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Node=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(16),o=r(6);var a=new Float32Array([0,0,0]),u=new Float32Array([0,0,0,1]),s=new Float32Array([1,1,1]),c=o.mat4.create();e.Node=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.name=null,this.children=[],this.parent=null,this.visible=!0,this.selectable=!1,this._matrix=null,this._dirtyTRS=!1,this._translation=null,this._rotation=null,this._scale=null,this._dirtyWorldMatrix=!1,this._worldMatrix=null,this._activeFrameId=-1,this._hoverFrameId=-1,this._renderPrimitives=null,this._renderer=null,this._selectHandler=null}return n(t,[{key:"_setRenderer",value:function(t){if(this._renderer!=t&&(this._renderer&&this.clearRenderPrimitives(),this._renderer=t,t)){this.onRendererChanged(t);var e=!0,r=!1,n=void 0;try{for(var i,o=this.children[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value._setRenderer(t)}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}}}},{key:"onRendererChanged",value:function(t){}},{key:"clone",value:function(){var e=this,r=new t;return r.name=this.name,r.visible=this.visible,r._renderer=this._renderer,r._dirtyTRS=this._dirtyTRS,this._translation&&(r._translation=o.vec3.create(),o.vec3.copy(r._translation,this._translation)),this._rotation&&(r._rotation=o.quat.create(),o.quat.copy(r._rotation,this._rotation)),this._scale&&(r._scale=o.vec3.create(),o.vec3.copy(r._scale,this._scale)),!r._dirtyTRS&&this._matrix&&(r._matrix=o.mat4.create(),o.mat4.copy(r._matrix,this._matrix)),r._dirtyWorldMatrix=this._dirtyWorldMatrix,!r._dirtyWorldMatrix&&this._worldMatrix&&(r._worldMatrix=o.mat4.create(),o.mat4.copy(r._worldMatrix,this._worldMatrix)),this.waitForComplete().then(function(){if(e._renderPrimitives){var t=!0,n=!1,i=void 0;try{for(var o,a=e._renderPrimitives[Symbol.iterator]();!(t=(o=a.next()).done);t=!0){var u=o.value;r.addRenderPrimitive(u)}}catch(t){n=!0,i=t}finally{try{!t&&a.return&&a.return()}finally{if(n)throw i}}}var s=!0,c=!1,f=void 0;try{for(var l,h=e.children[Symbol.iterator]();!(s=(l=h.next()).done);s=!0){var d=l.value;r.addNode(d.clone())}}catch(t){c=!0,f=t}finally{try{!s&&h.return&&h.return()}finally{if(c)throw f}}}),r}},{key:"markActive",value:function(t){if(this.visible&&this._renderPrimitives){this._activeFrameId=t;var e=!0,r=!1,n=void 0;try{for(var i,o=this._renderPrimitives[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value.markActive(t)}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}}var a=!0,u=!1,s=void 0;try{for(var c,f=this.children[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;l.visible&&l.markActive(t)}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}},{key:"addNode",value:function(t){t&&t.parent!=this&&(t.parent&&t.parent.removeNode(t),t.parent=this,this.children.push(t),this._renderer&&t._setRenderer(this._renderer))}},{key:"removeNode",value:function(t){var e=this.children.indexOf(t);e>-1&&(this.children.splice(e,1),t.parent=null)}},{key:"clearNodes",value:function(){var t=!0,e=!1,r=void 0;try{for(var n,i=this.children[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){n.value.parent=null}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}this.children=[]}},{key:"setMatrixDirty",value:function(){if(!this._dirtyWorldMatrix){this._dirtyWorldMatrix=!0;var t=!0,e=!1,r=void 0;try{for(var n,i=this.children[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){n.value.setMatrixDirty()}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}}}},{key:"_updateLocalMatrix",value:function(){return this._matrix||(this._matrix=o.mat4.create()),this._dirtyTRS&&(this._dirtyTRS=!1,o.mat4.fromRotationTranslationScale(this._matrix,this._rotation||u,this._translation||a,this._scale||s)),this._matrix}},{key:"waitForComplete",value:function(){var t=this,e=[],r=!0,n=!1,i=void 0;try{for(var o,a=this.children[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){var u=o.value;e.push(u.waitForComplete())}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}if(this._renderPrimitives){var s=!0,c=!1,f=void 0;try{for(var l,h=this._renderPrimitives[Symbol.iterator]();!(s=(l=h.next()).done);s=!0){var d=l.value;e.push(d.waitForComplete())}}catch(t){c=!0,f=t}finally{try{!s&&h.return&&h.return()}finally{if(c)throw f}}}return Promise.all(e).then(function(){return t})}},{key:"addRenderPrimitive",value:function(t){this._renderPrimitives?this._renderPrimitives.push(t):this._renderPrimitives=[t],t._instances.push(this)}},{key:"removeRenderPrimitive",value:function(t){if(this._renderPrimitives){var e=this._renderPrimitives._instances.indexOf(t);e>-1&&(this._renderPrimitives._instances.splice(e,1),(e=t._instances.indexOf(this))>-1&&t._instances.splice(e,1),this._renderPrimitives.length||(this._renderPrimitives=null))}}},{key:"clearRenderPrimitives",value:function(){if(this._renderPrimitives){var t=!0,e=!1,r=void 0;try{for(var n,i=this._renderPrimitives[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){var o=n.value,a=o._instances.indexOf(this);a>-1&&o._instances.splice(a,1)}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}this._renderPrimitives=null}}},{key:"_hitTestSelectableNode",value:function(t){if(this._renderPrimitives){var e=null,r=!0,n=!1,a=void 0;try{for(var u,s=this._renderPrimitives[Symbol.iterator]();!(r=(u=s.next()).done);r=!0){var f=u.value;if(f._min){e||(o.mat4.invert(c,this.worldMatrix),o.mat4.multiply(c,c,t.transformMatrix),e=new i.Ray(c));var l=e.intersectsAABB(f._min,f._max);if(l)return o.vec3.transformMat4(l,l,this.worldMatrix),l}}}catch(t){n=!0,a=t}finally{try{!r&&s.return&&s.return()}finally{if(n)throw a}}}var h=!0,d=!1,v=void 0;try{for(var _,m=this.children[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=_.value._hitTestSelectableNode(t);if(p)return p}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}return null}},{key:"hitTest",value:function(t){if(this.selectable&&this.visible){var e=this._hitTestSelectableNode(t);if(e){var r=o.vec3.fromValues(t.origin.x,t.origin.y,t.origin.z);return{node:this,intersection:e,distance:o.vec3.distance(r,e)}}return null}var n=null,i=!0,a=!1,u=void 0;try{for(var s,c=this.children[Symbol.iterator]();!(i=(s=c.next()).done);i=!0){var f=s.value.hitTest(t);f&&(!n||n.distance>f.distance)&&(n=f)}}catch(t){a=!0,u=t}finally{try{!i&&c.return&&c.return()}finally{if(a)throw u}}return n}},{key:"onSelect",value:function(t){this._selectHandler=t}},{key:"handleSelect",value:function(){this._selectHandler&&this._selectHandler()}},{key:"onHoverStart",value:function(){}},{key:"onHoverEnd",value:function(){}},{key:"_update",value:function(t,e){this.onUpdate(t,e);var r=!0,n=!1,i=void 0;try{for(var o,a=this.children[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){o.value._update(t,e)}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}}},{key:"onUpdate",value:function(t,e){}},{key:"matrix",set:function(t){t?(this._matrix||(this._matrix=o.mat4.create()),o.mat4.copy(this._matrix,t)):this._matrix=null,this.setMatrixDirty(),this._dirtyTRS=!1,this._translation=null,this._rotation=null,this._scale=null},get:function(){return this.setMatrixDirty(),this._updateLocalMatrix()}},{key:"worldMatrix",get:function(){return this._worldMatrix||(this._dirtyWorldMatrix=!0,this._worldMatrix=o.mat4.create()),(this._dirtyWorldMatrix||this._dirtyTRS)&&(this.parent?o.mat4.mul(this._worldMatrix,this.parent.worldMatrix,this._updateLocalMatrix()):o.mat4.copy(this._worldMatrix,this._updateLocalMatrix()),this._dirtyWorldMatrix=!1),this._worldMatrix}},{key:"translation",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._translation=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._translation||(this._translation=o.vec3.clone(a)),this._translation}},{key:"rotation",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._rotation=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._rotation||(this._rotation=o.quat.clone(u)),this._rotation}},{key:"scale",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._scale=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._scale||(this._scale=o.vec3.clone(s)),this._scale}},{key:"renderPrimitives",get:function(){return this._renderPrimitives}},{key:"selectHandler",get:function(){return this._selectHandler}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}e.stateToBlendFunc=c;var o=WebGLRenderingContext,a=e.CAP={CULL_FACE:1,BLEND:2,DEPTH_TEST:4,STENCIL_TEST:8,COLOR_MASK:16,DEPTH_MASK:32,STENCIL_MASK:64},u=e.MAT_STATE={CAPS_RANGE:255,BLEND_SRC_SHIFT:8,BLEND_SRC_RANGE:3840,BLEND_DST_SHIFT:12,BLEND_DST_RANGE:61440,BLEND_FUNC_RANGE:65280,DEPTH_FUNC_SHIFT:16,DEPTH_FUNC_RANGE:983040},s=e.RENDER_ORDER={OPAQUE:0,SKY:1,TRANSPARENT:2,ADDITIVE:3,DEFAULT:4};function c(t,e,r){var n=(t&e)>>r;switch(n){case 0:case 1:return n;default:return n-2+o.SRC_COLOR}}var f=e.MaterialState=function(){function t(){i(this,t),this._state=a.CULL_FACE|a.DEPTH_TEST|a.COLOR_MASK|a.DEPTH_MASK,this.blendFuncSrc=o.SRC_ALPHA,this.blendFuncDst=o.ONE_MINUS_SRC_ALPHA,this.depthFunc=o.LESS}return n(t,[{key:"cullFace",get:function(){return!!(this._state&a.CULL_FACE)},set:function(t){t?this._state|=a.CULL_FACE:this._state&=~a.CULL_FACE}},{key:"blend",get:function(){return!!(this._state&a.BLEND)},set:function(t){t?this._state|=a.BLEND:this._state&=~a.BLEND}},{key:"depthTest",get:function(){return!!(this._state&a.DEPTH_TEST)},set:function(t){t?this._state|=a.DEPTH_TEST:this._state&=~a.DEPTH_TEST}},{key:"stencilTest",get:function(){return!!(this._state&a.STENCIL_TEST)},set:function(t){t?this._state|=a.STENCIL_TEST:this._state&=~a.STENCIL_TEST}},{key:"colorMask",get:function(){return!!(this._state&a.COLOR_MASK)},set:function(t){t?this._state|=a.COLOR_MASK:this._state&=~a.COLOR_MASK}},{key:"depthMask",get:function(){return!!(this._state&a.DEPTH_MASK)},set:function(t){t?this._state|=a.DEPTH_MASK:this._state&=~a.DEPTH_MASK}},{key:"depthFunc",get:function(){return((this._state&u.DEPTH_FUNC_RANGE)>>u.DEPTH_FUNC_SHIFT)+o.NEVER},set:function(t){t-=o.NEVER,this._state&=~u.DEPTH_FUNC_RANGE,this._state|=t<<u.DEPTH_FUNC_SHIFT}},{key:"stencilMask",get:function(){return!!(this._state&a.STENCIL_MASK)},set:function(t){t?this._state|=a.STENCIL_MASK:this._state&=~a.STENCIL_MASK}},{key:"blendFuncSrc",get:function(){return c(this._state,u.BLEND_SRC_RANGE,u.BLEND_SRC_SHIFT)},set:function(t){switch(t){case 0:case 1:break;default:t=t-o.SRC_COLOR+2}this._state&=~u.BLEND_SRC_RANGE,this._state|=t<<u.BLEND_SRC_SHIFT}},{key:"blendFuncDst",get:function(){return c(this._state,u.BLEND_DST_RANGE,u.BLEND_DST_SHIFT)},set:function(t){switch(t){case 0:case 1:break;default:t=t-o.SRC_COLOR+2}this._state&=~u.BLEND_DST_RANGE,this._state|=t<<u.BLEND_DST_SHIFT}}]),t}(),l=function(){function t(e){i(this,t),this._uniformName=e,this._texture=null}return n(t,[{key:"texture",get:function(){return this._texture},set:function(t){this._texture=t}}]),t}(),h=function(){function t(e,r,n){i(this,t),this._uniformName=e,this._value=r,this._length=n,this._length||(r instanceof Array?this._length=r.length:this._length=1)}return n(t,[{key:"value",get:function(){return this._value},set:function(t){this._value=t}}]),t}();e.Material=function(){function t(){i(this,t),this.state=new f,this.renderOrder=s.DEFAULT,this._samplers=[],this._uniforms=[]}return n(t,[{key:"defineSampler",value:function(t){var e=new l(t);return this._samplers.push(e),e}},{key:"defineUniform",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,n=new h(t,e,r);return this._uniforms.push(n),n}},{key:"getProgramDefines",value:function(t){return{}}},{key:"materialName",get:function(){return null}},{key:"vertexSource",get:function(){return null}},{key:"fragmentSource",get:function(){return null}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return u}),r.d(e,"identity",function(){return s}),r.d(e,"setAxisAngle",function(){return c}),r.d(e,"getAxisAngle",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"rotateX",function(){return h}),r.d(e,"rotateY",function(){return d}),r.d(e,"rotateZ",function(){return v}),r.d(e,"calculateW",function(){return _}),r.d(e,"slerp",function(){return m}),r.d(e,"random",function(){return p}),r.d(e,"invert",function(){return y}),r.d(e,"conjugate",function(){return b}),r.d(e,"fromMat3",function(){return g}),r.d(e,"fromEuler",function(){return M}),r.d(e,"str",function(){return x}),r.d(e,"clone",function(){return T}),r.d(e,"fromValues",function(){return E}),r.d(e,"copy",function(){return w}),r.d(e,"set",function(){return O}),r.d(e,"add",function(){return R}),r.d(e,"mul",function(){return P}),r.d(e,"scale",function(){return S}),r.d(e,"dot",function(){return A}),r.d(e,"lerp",function(){return N}),r.d(e,"length",function(){return C}),r.d(e,"len",function(){return I}),r.d(e,"squaredLength",function(){return L}),r.d(e,"sqrLen",function(){return k}),r.d(e,"normalize",function(){return F}),r.d(e,"exactEquals",function(){return D}),r.d(e,"equals",function(){return j}),r.d(e,"rotationTo",function(){return B}),r.d(e,"sqlerp",function(){return U}),r.d(e,"setAxes",function(){return V});var n=r(0),i=r(12),o=r(5),a=r(1);function u(){let t=new n.ARRAY_TYPE(4);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function s(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t}function c(t,e,r){r*=.5;let n=Math.sin(r);return t[0]=n*e[0],t[1]=n*e[1],t[2]=n*e[2],t[3]=Math.cos(r),t}function f(t,e){let r=2*Math.acos(e[3]),i=Math.sin(r/2);return i>n.EPSILON?(t[0]=e[0]/i,t[1]=e[1]/i,t[2]=e[2]/i):(t[0]=1,t[1]=0,t[2]=0),r}function l(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*f+a*u+i*c-o*s,t[1]=i*f+a*s+o*u-n*c,t[2]=o*f+a*c+n*s-i*u,t[3]=a*f-n*u-i*s-o*c,t}function h(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+a*u,t[1]=i*s+o*u,t[2]=o*s-i*u,t[3]=a*s-n*u,t}function d(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s-o*u,t[1]=i*s+a*u,t[2]=o*s+n*u,t[3]=a*s-i*u,t}function v(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+i*u,t[1]=i*s-n*u,t[2]=o*s+a*u,t[3]=a*s-o*u,t}function _(t,e){let r=e[0],n=e[1],i=e[2];return t[0]=r,t[1]=n,t[2]=i,t[3]=Math.sqrt(Math.abs(1-r*r-n*n-i*i)),t}function m(t,e,r,i){let o,a,u,s,c,f=e[0],l=e[1],h=e[2],d=e[3],v=r[0],_=r[1],m=r[2],p=r[3];return(a=f*v+l*_+h*m+d*p)<0&&(a=-a,v=-v,_=-_,m=-m,p=-p),1-a>n.EPSILON?(o=Math.acos(a),u=Math.sin(o),s=Math.sin((1-i)*o)/u,c=Math.sin(i*o)/u):(s=1-i,c=i),t[0]=s*f+c*v,t[1]=s*l+c*_,t[2]=s*h+c*m,t[3]=s*d+c*p,t}function p(t){let e=n.RANDOM(),r=n.RANDOM(),i=n.RANDOM(),o=Math.sqrt(1-e),a=Math.sqrt(e);return t[0]=o*Math.sin(2*Math.PI*r),t[1]=o*Math.cos(2*Math.PI*r),t[2]=a*Math.sin(2*Math.PI*i),t[3]=a*Math.cos(2*Math.PI*i),t}function y(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*r+n*n+i*i+o*o,u=a?1/a:0;return t[0]=-r*u,t[1]=-n*u,t[2]=-i*u,t[3]=o*u,t}function b(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t}function g(t,e){let r,n=e[0]+e[4]+e[8];if(n>0)r=Math.sqrt(n+1),t[3]=.5*r,r=.5/r,t[0]=(e[5]-e[7])*r,t[1]=(e[6]-e[2])*r,t[2]=(e[1]-e[3])*r;else{let n=0;e[4]>e[0]&&(n=1),e[8]>e[3*n+n]&&(n=2);let i=(n+1)%3,o=(n+2)%3;r=Math.sqrt(e[3*n+n]-e[3*i+i]-e[3*o+o]+1),t[n]=.5*r,r=.5/r,t[3]=(e[3*i+o]-e[3*o+i])*r,t[i]=(e[3*i+n]+e[3*n+i])*r,t[o]=(e[3*o+n]+e[3*n+o])*r}return t}function M(t,e,r,n){let i=.5*Math.PI/180;e*=i,r*=i,n*=i;let o=Math.sin(e),a=Math.cos(e),u=Math.sin(r),s=Math.cos(r),c=Math.sin(n),f=Math.cos(n);return t[0]=o*s*f-a*u*c,t[1]=a*u*f+o*s*c,t[2]=a*s*c-o*u*f,t[3]=a*s*f+o*u*c,t}function x(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}const T=a.clone,E=a.fromValues,w=a.copy,O=a.set,R=a.add,P=l,S=a.scale,A=a.dot,N=a.lerp,C=a.length,I=C,L=a.squaredLength,k=L,F=a.normalize,D=a.exactEquals,j=a.equals,B=function(){let t=o.create(),e=o.fromValues(1,0,0),r=o.fromValues(0,1,0);return function(n,i,a){let u=o.dot(i,a);return u<-.999999?(o.cross(t,e,i),o.len(t)<1e-6&&o.cross(t,r,i),o.normalize(t,t),c(n,t,Math.PI),n):u>.999999?(n[0]=0,n[1]=0,n[2]=0,n[3]=1,n):(o.cross(t,i,a),n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=1+u,F(n,n))}}(),U=function(){let t=u(),e=u();return function(r,n,i,o,a,u){return m(t,n,a,u),m(e,i,o,u),m(r,t,e,2*u*(1-u)),r}}(),V=function(){let t=i.create();return function(e,r,n,i){return t[0]=n[0],t[3]=n[1],t[6]=n[2],t[1]=i[0],t[4]=i[1],t[7]=i[2],t[2]=-r[0],t[5]=-r[1],t[8]=-r[2],F(e,g(e,t))}}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"length",function(){return a}),r.d(e,"fromValues",function(){return u}),r.d(e,"copy",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"add",function(){return f}),r.d(e,"subtract",function(){return l}),r.d(e,"multiply",function(){return h}),r.d(e,"divide",function(){return d}),r.d(e,"ceil",function(){return v}),r.d(e,"floor",function(){return _}),r.d(e,"min",function(){return m}),r.d(e,"max",function(){return p}),r.d(e,"round",function(){return y}),r.d(e,"scale",function(){return b}),r.d(e,"scaleAndAdd",function(){return g}),r.d(e,"distance",function(){return M}),r.d(e,"squaredDistance",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return E}),r.d(e,"inverse",function(){return w}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"cross",function(){return P}),r.d(e,"lerp",function(){return S}),r.d(e,"hermite",function(){return A}),r.d(e,"bezier",function(){return N}),r.d(e,"random",function(){return C}),r.d(e,"transformMat4",function(){return I}),r.d(e,"transformMat3",function(){return L}),r.d(e,"transformQuat",function(){return k}),r.d(e,"rotateX",function(){return F}),r.d(e,"rotateY",function(){return D}),r.d(e,"rotateZ",function(){return j}),r.d(e,"angle",function(){return B}),r.d(e,"str",function(){return U}),r.d(e,"exactEquals",function(){return V}),r.d(e,"equals",function(){return Y}),r.d(e,"sub",function(){return G}),r.d(e,"mul",function(){return q}),r.d(e,"div",function(){return H}),r.d(e,"dist",function(){return X}),r.d(e,"sqrDist",function(){return W}),r.d(e,"len",function(){return K}),r.d(e,"sqrLen",function(){return z}),r.d(e,"forEach",function(){return Q});var n=r(0);function i(){let t=new n.ARRAY_TYPE(3);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function o(t){var e=new n.ARRAY_TYPE(3);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function a(t){let e=t[0],r=t[1],n=t[2];return Math.sqrt(e*e+r*r+n*n)}function u(t,e,r){let i=new n.ARRAY_TYPE(3);return i[0]=t,i[1]=e,i[2]=r,i}function s(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function c(t,e,r,n){return t[0]=e,t[1]=r,t[2]=n,t}function f(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t}function l(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t}function h(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t[2]=e[2]*r[2],t}function d(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t[2]=e[2]/r[2],t}function v(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t}function _(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t}function m(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t[2]=Math.min(e[2],r[2]),t}function p(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t[2]=Math.max(e[2],r[2]),t}function y(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t}function b(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t}function g(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t}function M(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2];return Math.sqrt(r*r+n*n+i*i)}function x(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2];return r*r+n*n+i*i}function T(t){let e=t[0],r=t[1],n=t[2];return e*e+r*r+n*n}function E(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t}function w(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t}function O(t,e){let r=e[0],n=e[1],i=e[2],o=r*r+n*n+i*i;return o>0&&(o=1/Math.sqrt(o),t[0]=e[0]*o,t[1]=e[1]*o,t[2]=e[2]*o),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function P(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[0],u=r[1],s=r[2];return t[0]=i*s-o*u,t[1]=o*a-n*s,t[2]=n*u-i*a,t}function S(t,e,r,n){let i=e[0],o=e[1],a=e[2];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t[2]=a+n*(r[2]-a),t}function A(t,e,r,n,i,o){let a=o*o,u=a*(2*o-3)+1,s=a*(o-2)+o,c=a*(o-1),f=a*(3-2*o);return t[0]=e[0]*u+r[0]*s+n[0]*c+i[0]*f,t[1]=e[1]*u+r[1]*s+n[1]*c+i[1]*f,t[2]=e[2]*u+r[2]*s+n[2]*c+i[2]*f,t}function N(t,e,r,n,i,o){let a=1-o,u=a*a,s=o*o,c=u*a,f=3*o*u,l=3*s*a,h=s*o;return t[0]=e[0]*c+r[0]*f+n[0]*l+i[0]*h,t[1]=e[1]*c+r[1]*f+n[1]*l+i[1]*h,t[2]=e[2]*c+r[2]*f+n[2]*l+i[2]*h,t}function C(t,e){e=e||1;let r=2*n.RANDOM()*Math.PI,i=2*n.RANDOM()-1,o=Math.sqrt(1-i*i)*e;return t[0]=Math.cos(r)*o,t[1]=Math.sin(r)*o,t[2]=i*e,t}function I(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[3]*n+r[7]*i+r[11]*o+r[15];return a=a||1,t[0]=(r[0]*n+r[4]*i+r[8]*o+r[12])/a,t[1]=(r[1]*n+r[5]*i+r[9]*o+r[13])/a,t[2]=(r[2]*n+r[6]*i+r[10]*o+r[14])/a,t}function L(t,e,r){let n=e[0],i=e[1],o=e[2];return t[0]=n*r[0]+i*r[3]+o*r[6],t[1]=n*r[1]+i*r[4]+o*r[7],t[2]=n*r[2]+i*r[5]+o*r[8],t}function k(t,e,r){let n=r[0],i=r[1],o=r[2],a=r[3],u=e[0],s=e[1],c=e[2],f=i*c-o*s,l=o*u-n*c,h=n*s-i*u,d=i*h-o*l,v=o*f-n*h,_=n*l-i*f,m=2*a;return f*=m,l*=m,h*=m,d*=2,v*=2,_*=2,t[0]=u+f+d,t[1]=s+l+v,t[2]=c+h+_,t}function F(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[0],o[1]=i[1]*Math.cos(n)-i[2]*Math.sin(n),o[2]=i[1]*Math.sin(n)+i[2]*Math.cos(n),t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function D(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[2]*Math.sin(n)+i[0]*Math.cos(n),o[1]=i[1],o[2]=i[2]*Math.cos(n)-i[0]*Math.sin(n),t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function j(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[0]*Math.cos(n)-i[1]*Math.sin(n),o[1]=i[0]*Math.sin(n)+i[1]*Math.cos(n),o[2]=i[2],t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function B(t,e){let r=u(t[0],t[1],t[2]),n=u(e[0],e[1],e[2]);O(r,r),O(n,n);let i=R(r,n);return i>1?0:i<-1?Math.PI:Math.acos(i)}function U(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"}function V(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]}function Y(t,e){let r=t[0],i=t[1],o=t[2],a=e[0],u=e[1],s=e[2];return Math.abs(r-a)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(i-u)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(u))&&Math.abs(o-s)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(s))}const G=l,q=h,H=d,X=M,W=x,K=a,z=T,Q=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=3),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],t[2]=e[u+2],o(t,t,a),e[u]=t[0],e[u+1]=t[1],e[u+2]=t[2];return e}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.vec4=e.vec3=e.vec2=e.quat2=e.quat=e.mat4=e.mat3=e.mat2d=e.mat2=e.glMatrix=void 0;var n=d(r(0)),i=d(r(17)),o=d(r(18)),a=d(r(12)),u=d(r(10)),s=d(r(4)),c=d(r(19)),f=d(r(20)),l=d(r(5)),h=d(r(1));function d(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e.default=t,e}e.glMatrix=n,e.mat2=i,e.mat2d=o,e.mat3=a,e.mat4=u,e.quat=s,e.quat2=c,e.vec2=f,e.vec3=l,e.vec4=h},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Primitive=e.PrimitiveAttribute=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}e.PrimitiveAttribute=function t(e,r,n,i,a,u){o(this,t),this.name=e,this.buffer=r,this.componentCount=n||3,this.componentType=i||5126,this.stride=a||0,this.byteOffset=u||0,this.normalized=!1},e.Primitive=function(){function t(e,r,n){o(this,t),this.attributes=e||[],this.elementCount=r||0,this.mode=n||4,this.indexBuffer=null,this.indexByteOffset=0,this.indexType=0,this._min=null,this._max=null}return n(t,[{key:"setIndexBuffer",value:function(t,e,r){this.indexBuffer=t,this.indexByteOffset=e||0,this.indexType=r||5123}},{key:"setBounds",value:function(t,e){this._min=i.vec3.clone(t),this._max=i.vec3.clone(e)}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var u=WebGLRenderingContext,s=e.TextureSampler=function t(){a(this,t),this.minFilter=null,this.magFilter=null,this.wrapS=null,this.wrapT=null},c=e.Texture=function(){function t(){a(this,t),this.sampler=new s,this.mipmap=!0}return n(t,[{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return 0}},{key:"height",get:function(){return 0}},{key:"textureKey",get:function(){return null}}]),t}(),f=e.ImageTexture=function(t){function e(t){a(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._img=t,r._imgBitmap=null,t.src&&t.complete?t.naturalWidth?r._promise=r._finishImage():r._promise=Promise.reject("Image provided had failed to load."):r._promise=new Promise(function(e,n){t.addEventListener("load",function(){return e(r._finishImage())}),t.addEventListener("error",n)}),r}return o(e,c),n(e,[{key:"_finishImage",value:function(){var t=this;return window.createImageBitmap?window.createImageBitmap(this._img).then(function(e){return t._imgBitmap=e,Promise.resolve(t)}):Promise.resolve(this)}},{key:"waitForComplete",value:function(){return this._promise}},{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return this._img.width}},{key:"height",get:function(){return this._img.height}},{key:"textureKey",get:function(){return this._img.src}},{key:"source",get:function(){return this._imgBitmap||this._img}}]),e}(),l=(e.UrlTexture=function(t){function e(t){a(this,e);var r=new Image,n=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,r));return r.src=t,n}return o(e,f),e}(),e.BlobTexture=function(t){function e(t){a(this,e);var r=new Image,n=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,r));return r.src=window.URL.createObjectURL(t),n}return o(e,f),e}(),e.VideoTexture=function(t){function e(t){a(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._video=t,t.readyState>=2?r._promise=Promise.resolve(r):t.error?r._promise=Promise.reject(t.error):r._promise=new Promise(function(e,n){t.addEventListener("loadeddata",function(){return e(r)}),t.addEventListener("error",n)}),r}return o(e,c),n(e,[{key:"waitForComplete",value:function(){return this._promise}},{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return this._video.videoWidth}},{key:"height",get:function(){return this._video.videoHeight}},{key:"textureKey",get:function(){return this._video.src}},{key:"source",get:function(){return this._video}}]),e}(),0),h=e.DataTexture=function(t){function e(t,r,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:u.RGBA,s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:u.UNSIGNED_BYTE;a(this,e);var c=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return c._data=t,c._width=r,c._height=n,c._format=o,c._type=s,c._key="DATA_"+l,l++,c}return o(e,c),n(e,[{key:"format",get:function(){return this._format}},{key:"width",get:function(){return this._width}},{key:"height",get:function(){return this._height}},{key:"textureKey",get:function(){return this._key}}]),e}();e.ColorTexture=function(t){function e(t,r,n,o){a(this,e);var u=new Uint8Array([255*t,255*r,255*n,255*o]),s=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,u,1,1));return s.mipmap=!1,s._key="COLOR_"+u[0]+"_"+u[1]+"_"+u[2]+"_"+u[3],s}return o(e,h),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.GeometryBuilderBase=e.PrimitiveStream=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(7),o=r(6);function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var u=WebGLRenderingContext,s=o.vec3.create(),c=e.PrimitiveStream=function(){function t(e){a(this,t),this._vertices=[],this._indices=[],this._geometryStarted=!1,this._vertexOffset=0,this._vertexIndex=0,this._highIndex=0,this._flipWinding=!1,this._invertNormals=!1,this._transform=null,this._normalTransform=null,this._min=null,this._max=null}return n(t,[{key:"startGeometry",value:function(){if(this._geometryStarted)throw new Error("Attempted to start a new geometry before the previous one was ended.");this._geometryStarted=!0,this._vertexIndex=0,this._highIndex=0}},{key:"endGeometry",value:function(){if(!this._geometryStarted)throw new Error("Attempted to end a geometry before one was started.");if(this._highIndex>=this._vertexIndex)throw new Error("Geometry contains indices that are out of bounds.\n (Contains an index of "+this._highIndex+" when the vertex count is "+this._vertexIndex+")");this._geometryStarted=!1,this._vertexOffset+=this._vertexIndex}},{key:"pushVertex",value:function(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,u=arguments.length>6&&void 0!==arguments[6]?arguments[6]:0,c=arguments.length>7&&void 0!==arguments[7]?arguments[7]:1;if(!this._geometryStarted)throw new Error("Cannot push vertices before calling startGeometry().");return this._transform&&(s[0]=t,s[1]=e,s[2]=r,o.vec3.transformMat4(s,s,this._transform),t=s[0],e=s[1],r=s[2],s[0]=a,s[1]=u,s[2]=c,o.vec3.transformMat3(s,s,this._normalTransform),a=s[0],u=s[1],c=s[2]),this._invertNormals&&(a*=-1,u*=-1,c*=-1),this._vertices.push(t,e,r,n,i,a,u,c),this._min?(this._min[0]=Math.min(this._min[0],t),this._min[1]=Math.min(this._min[1],e),this._min[2]=Math.min(this._min[2],r),this._max[0]=Math.max(this._max[0],t),this._max[1]=Math.max(this._max[1],e),this._max[2]=Math.max(this._max[2],r)):(this._min=o.vec3.fromValues(t,e,r),this._max=o.vec3.fromValues(t,e,r)),this._vertexIndex++}},{key:"pushTriangle",value:function(t,e,r){if(!this._geometryStarted)throw new Error("Cannot push triangles before calling startGeometry().");this._highIndex=Math.max(this._highIndex,t,e,r),t+=this._vertexOffset,e+=this._vertexOffset,r+=this._vertexOffset,this._flipWinding?this._indices.push(r,e,t):this._indices.push(t,e,r)}},{key:"clear",value:function(){if(this._geometryStarted)throw new Error("Cannot clear before ending the current geometry.");this._vertices=[],this._indices=[],this._vertexOffset=0,this._min=null,this._max=null}},{key:"finishPrimitive",value:function(t){if(!this._vertexOffset)throw new Error("Attempted to call finishPrimitive() before creating any geometry.");var e=t.createRenderBuffer(u.ARRAY_BUFFER,new Float32Array(this._vertices)),r=t.createRenderBuffer(u.ELEMENT_ARRAY_BUFFER,new Uint16Array(this._indices)),n=[new i.PrimitiveAttribute("POSITION",e,3,u.FLOAT,32,0),new i.PrimitiveAttribute("TEXCOORD_0",e,2,u.FLOAT,32,12),new i.PrimitiveAttribute("NORMAL",e,3,u.FLOAT,32,20)],o=new i.Primitive(n,this._indices.length);return o.setIndexBuffer(r),o.setBounds(this._min,this._max),o}},{key:"flipWinding",set:function(t){if(this._geometryStarted)throw new Error("Cannot change flipWinding before ending the current geometry.");this._flipWinding=t},get:function(){this._flipWinding}},{key:"invertNormals",set:function(t){if(this._geometryStarted)throw new Error("Cannot change invertNormals before ending the current geometry.");this._invertNormals=t},get:function(){this._invertNormals}},{key:"transform",set:function(t){if(this._geometryStarted)throw new Error("Cannot change transform before ending the current geometry.");this._transform=t,this._transform&&(this._normalTransform||(this._normalTransform=o.mat3.create()),o.mat3.fromMat4(this._normalTransform,this._transform))},get:function(){this._transform}},{key:"nextVertexIndex",get:function(){return this._vertexIndex}}]),t}();e.GeometryBuilderBase=function(){function t(e){a(this,t),this._stream=e||new c}return n(t,[{key:"finishPrimitive",value:function(t){return this._stream.finishPrimitive(t)}},{key:"clear",value:function(){this._stream.clear()}},{key:"primitiveStream",set:function(t){this._stream=t},get:function(){return this._stream}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"fromValues",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"identity",function(){return c}),r.d(e,"transpose",function(){return f}),r.d(e,"invert",function(){return l}),r.d(e,"adjoint",function(){return h}),r.d(e,"determinant",function(){return d}),r.d(e,"multiply",function(){return v}),r.d(e,"translate",function(){return _}),r.d(e,"scale",function(){return m}),r.d(e,"rotate",function(){return p}),r.d(e,"rotateX",function(){return y}),r.d(e,"rotateY",function(){return b}),r.d(e,"rotateZ",function(){return g}),r.d(e,"fromTranslation",function(){return M}),r.d(e,"fromScaling",function(){return x}),r.d(e,"fromRotation",function(){return T}),r.d(e,"fromXRotation",function(){return E}),r.d(e,"fromYRotation",function(){return w}),r.d(e,"fromZRotation",function(){return O}),r.d(e,"fromRotationTranslation",function(){return R}),r.d(e,"fromQuat2",function(){return P}),r.d(e,"getTranslation",function(){return S}),r.d(e,"getScaling",function(){return A}),r.d(e,"getRotation",function(){return N}),r.d(e,"fromRotationTranslationScale",function(){return C}),r.d(e,"fromRotationTranslationScaleOrigin",function(){return I}),r.d(e,"fromQuat",function(){return L}),r.d(e,"frustum",function(){return k}),r.d(e,"perspective",function(){return F}),r.d(e,"perspectiveFromFieldOfView",function(){return D}),r.d(e,"ortho",function(){return j}),r.d(e,"lookAt",function(){return B}),r.d(e,"targetTo",function(){return U}),r.d(e,"str",function(){return V}),r.d(e,"frob",function(){return Y}),r.d(e,"add",function(){return G}),r.d(e,"subtract",function(){return q}),r.d(e,"multiplyScalar",function(){return H}),r.d(e,"multiplyScalarAndAdd",function(){return X}),r.d(e,"exactEquals",function(){return W}),r.d(e,"equals",function(){return K}),r.d(e,"mul",function(){return z}),r.d(e,"sub",function(){return Q});var n=r(0);function i(){let t=new n.ARRAY_TYPE(16);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t}function o(t){let e=new n.ARRAY_TYPE(16);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 a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function u(t,e,r,i,o,a,u,s,c,f,l,h,d,v,_,m){let p=new n.ARRAY_TYPE(16);return p[0]=t,p[1]=e,p[2]=r,p[3]=i,p[4]=o,p[5]=a,p[6]=u,p[7]=s,p[8]=c,p[9]=f,p[10]=l,p[11]=h,p[12]=d,p[13]=v,p[14]=_,p[15]=m,p}function s(t,e,r,n,i,o,a,u,s,c,f,l,h,d,v,_,m){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t[8]=c,t[9]=f,t[10]=l,t[11]=h,t[12]=d,t[13]=v,t[14]=_,t[15]=m,t}function c(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function f(t,e){if(t===e){let r=e[1],n=e[2],i=e[3],o=e[6],a=e[7],u=e[11];t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=r,t[6]=e[9],t[7]=e[13],t[8]=n,t[9]=o,t[11]=e[14],t[12]=i,t[13]=a,t[14]=u}else t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=e[14],t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=e[15];return t}function l(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15],y=r*u-n*a,b=r*s-i*a,g=r*c-o*a,M=n*s-i*u,x=n*c-o*u,T=i*c-o*s,E=f*_-l*v,w=f*m-h*v,O=f*p-d*v,R=l*m-h*_,P=l*p-d*_,S=h*p-d*m,A=y*S-b*P+g*R+M*O-x*w+T*E;return A?(A=1/A,t[0]=(u*S-s*P+c*R)*A,t[1]=(i*P-n*S-o*R)*A,t[2]=(_*T-m*x+p*M)*A,t[3]=(h*x-l*T-d*M)*A,t[4]=(s*O-a*S-c*w)*A,t[5]=(r*S-i*O+o*w)*A,t[6]=(m*g-v*T-p*b)*A,t[7]=(f*T-h*g+d*b)*A,t[8]=(a*P-u*O+c*E)*A,t[9]=(n*O-r*P-o*E)*A,t[10]=(v*x-_*g+p*y)*A,t[11]=(l*g-f*x-d*y)*A,t[12]=(u*w-a*R-s*E)*A,t[13]=(r*R-n*w+i*E)*A,t[14]=(_*b-v*M-m*y)*A,t[15]=(f*M-l*b+h*y)*A,t):null}function h(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15];return t[0]=u*(h*p-d*m)-l*(s*p-c*m)+_*(s*d-c*h),t[1]=-(n*(h*p-d*m)-l*(i*p-o*m)+_*(i*d-o*h)),t[2]=n*(s*p-c*m)-u*(i*p-o*m)+_*(i*c-o*s),t[3]=-(n*(s*d-c*h)-u*(i*d-o*h)+l*(i*c-o*s)),t[4]=-(a*(h*p-d*m)-f*(s*p-c*m)+v*(s*d-c*h)),t[5]=r*(h*p-d*m)-f*(i*p-o*m)+v*(i*d-o*h),t[6]=-(r*(s*p-c*m)-a*(i*p-o*m)+v*(i*c-o*s)),t[7]=r*(s*d-c*h)-a*(i*d-o*h)+f*(i*c-o*s),t[8]=a*(l*p-d*_)-f*(u*p-c*_)+v*(u*d-c*l),t[9]=-(r*(l*p-d*_)-f*(n*p-o*_)+v*(n*d-o*l)),t[10]=r*(u*p-c*_)-a*(n*p-o*_)+v*(n*c-o*u),t[11]=-(r*(u*d-c*l)-a*(n*d-o*l)+f*(n*c-o*u)),t[12]=-(a*(l*m-h*_)-f*(u*m-s*_)+v*(u*h-s*l)),t[13]=r*(l*m-h*_)-f*(n*m-i*_)+v*(n*h-i*l),t[14]=-(r*(u*m-s*_)-a*(n*m-i*_)+v*(n*s-i*u)),t[15]=r*(u*h-s*l)-a*(n*h-i*l)+f*(n*s-i*u),t}function d(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=t[4],a=t[5],u=t[6],s=t[7],c=t[8],f=t[9],l=t[10],h=t[11],d=t[12],v=t[13],_=t[14],m=t[15];return(e*a-r*o)*(l*m-h*_)-(e*u-n*o)*(f*m-h*v)+(e*s-i*o)*(f*_-l*v)+(r*u-n*a)*(c*m-h*d)-(r*s-i*a)*(c*_-l*d)+(n*s-i*u)*(c*v-f*d)}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=e[9],d=e[10],v=e[11],_=e[12],m=e[13],p=e[14],y=e[15],b=r[0],g=r[1],M=r[2],x=r[3];return t[0]=b*n+g*u+M*l+x*_,t[1]=b*i+g*s+M*h+x*m,t[2]=b*o+g*c+M*d+x*p,t[3]=b*a+g*f+M*v+x*y,b=r[4],g=r[5],M=r[6],x=r[7],t[4]=b*n+g*u+M*l+x*_,t[5]=b*i+g*s+M*h+x*m,t[6]=b*o+g*c+M*d+x*p,t[7]=b*a+g*f+M*v+x*y,b=r[8],g=r[9],M=r[10],x=r[11],t[8]=b*n+g*u+M*l+x*_,t[9]=b*i+g*s+M*h+x*m,t[10]=b*o+g*c+M*d+x*p,t[11]=b*a+g*f+M*v+x*y,b=r[12],g=r[13],M=r[14],x=r[15],t[12]=b*n+g*u+M*l+x*_,t[13]=b*i+g*s+M*h+x*m,t[14]=b*o+g*c+M*d+x*p,t[15]=b*a+g*f+M*v+x*y,t}function _(t,e,r){let n,i,o,a,u,s,c,f,l,h,d,v,_=r[0],m=r[1],p=r[2];return e===t?(t[12]=e[0]*_+e[4]*m+e[8]*p+e[12],t[13]=e[1]*_+e[5]*m+e[9]*p+e[13],t[14]=e[2]*_+e[6]*m+e[10]*p+e[14],t[15]=e[3]*_+e[7]*m+e[11]*p+e[15]):(n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=e[9],d=e[10],v=e[11],t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=u,t[5]=s,t[6]=c,t[7]=f,t[8]=l,t[9]=h,t[10]=d,t[11]=v,t[12]=n*_+u*m+l*p+e[12],t[13]=i*_+s*m+h*p+e[13],t[14]=o*_+c*m+d*p+e[14],t[15]=a*_+f*m+v*p+e[15]),t}function m(t,e,r){let n=r[0],i=r[1],o=r[2];return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t[3]=e[3]*n,t[4]=e[4]*i,t[5]=e[5]*i,t[6]=e[6]*i,t[7]=e[7]*i,t[8]=e[8]*o,t[9]=e[9]*o,t[10]=e[10]*o,t[11]=e[11]*o,t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function p(t,e,r,i){let o,a,u,s,c,f,l,h,d,v,_,m,p,y,b,g,M,x,T,E,w,O,R,P,S=i[0],A=i[1],N=i[2],C=Math.sqrt(S*S+A*A+N*N);return C<n.EPSILON?null:(S*=C=1/C,A*=C,N*=C,o=Math.sin(r),u=1-(a=Math.cos(r)),s=e[0],c=e[1],f=e[2],l=e[3],h=e[4],d=e[5],v=e[6],_=e[7],m=e[8],p=e[9],y=e[10],b=e[11],g=S*S*u+a,M=A*S*u+N*o,x=N*S*u-A*o,T=S*A*u-N*o,E=A*A*u+a,w=N*A*u+S*o,O=S*N*u+A*o,R=A*N*u-S*o,P=N*N*u+a,t[0]=s*g+h*M+m*x,t[1]=c*g+d*M+p*x,t[2]=f*g+v*M+y*x,t[3]=l*g+_*M+b*x,t[4]=s*T+h*E+m*w,t[5]=c*T+d*E+p*w,t[6]=f*T+v*E+y*w,t[7]=l*T+_*E+b*w,t[8]=s*O+h*R+m*P,t[9]=c*O+d*R+p*P,t[10]=f*O+v*R+y*P,t[11]=l*O+_*R+b*P,e!==t&&(t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t)}function y(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[4],a=e[5],u=e[6],s=e[7],c=e[8],f=e[9],l=e[10],h=e[11];return e!==t&&(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[4]=o*i+c*n,t[5]=a*i+f*n,t[6]=u*i+l*n,t[7]=s*i+h*n,t[8]=c*i-o*n,t[9]=f*i-a*n,t[10]=l*i-u*n,t[11]=h*i-s*n,t}function b(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[0],a=e[1],u=e[2],s=e[3],c=e[8],f=e[9],l=e[10],h=e[11];return e!==t&&(t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=o*i-c*n,t[1]=a*i-f*n,t[2]=u*i-l*n,t[3]=s*i-h*n,t[8]=o*n+c*i,t[9]=a*n+f*i,t[10]=u*n+l*i,t[11]=s*n+h*i,t}function g(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[0],a=e[1],u=e[2],s=e[3],c=e[4],f=e[5],l=e[6],h=e[7];return e!==t&&(t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=o*i+c*n,t[1]=a*i+f*n,t[2]=u*i+l*n,t[3]=s*i+h*n,t[4]=c*i-o*n,t[5]=f*i-a*n,t[6]=l*i-u*n,t[7]=h*i-s*n,t}function M(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=e[0],t[13]=e[1],t[14]=e[2],t[15]=1,t}function x(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=e[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=e[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function T(t,e,r){let i,o,a,u=r[0],s=r[1],c=r[2],f=Math.sqrt(u*u+s*s+c*c);return f<n.EPSILON?null:(u*=f=1/f,s*=f,c*=f,i=Math.sin(e),a=1-(o=Math.cos(e)),t[0]=u*u*a+o,t[1]=s*u*a+c*i,t[2]=c*u*a-s*i,t[3]=0,t[4]=u*s*a-c*i,t[5]=s*s*a+o,t[6]=c*s*a+u*i,t[7]=0,t[8]=u*c*a+s*i,t[9]=s*c*a-u*i,t[10]=c*c*a+o,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)}function E(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n,t[6]=r,t[7]=0,t[8]=0,t[9]=-r,t[10]=n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function w(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=0,t[2]=-r,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=r,t[9]=0,t[10]=n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function O(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=0,t[3]=0,t[4]=-r,t[5]=n,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function R(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=n+n,s=i+i,c=o+o,f=n*u,l=n*s,h=n*c,d=i*s,v=i*c,_=o*c,m=a*u,p=a*s,y=a*c;return t[0]=1-(d+_),t[1]=l+y,t[2]=h-p,t[3]=0,t[4]=l-y,t[5]=1-(f+_),t[6]=v+m,t[7]=0,t[8]=h+p,t[9]=v-m,t[10]=1-(f+d),t[11]=0,t[12]=r[0],t[13]=r[1],t[14]=r[2],t[15]=1,t}function P(t,e){let r=new n.ARRAY_TYPE(3),i=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=i*i+o*o+a*a+u*u;return h>0?(r[0]=2*(s*u+l*i+c*a-f*o)/h,r[1]=2*(c*u+l*o+f*i-s*a)/h,r[2]=2*(f*u+l*a+s*o-c*i)/h):(r[0]=2*(s*u+l*i+c*a-f*o),r[1]=2*(c*u+l*o+f*i-s*a),r[2]=2*(f*u+l*a+s*o-c*i)),R(t,e,r),t}function S(t,e){return t[0]=e[12],t[1]=e[13],t[2]=e[14],t}function A(t,e){let r=e[0],n=e[1],i=e[2],o=e[4],a=e[5],u=e[6],s=e[8],c=e[9],f=e[10];return t[0]=Math.sqrt(r*r+n*n+i*i),t[1]=Math.sqrt(o*o+a*a+u*u),t[2]=Math.sqrt(s*s+c*c+f*f),t}function N(t,e){let r=e[0]+e[5]+e[10],n=0;return r>0?(n=2*Math.sqrt(r+1),t[3]=.25*n,t[0]=(e[6]-e[9])/n,t[1]=(e[8]-e[2])/n,t[2]=(e[1]-e[4])/n):e[0]>e[5]&&e[0]>e[10]?(n=2*Math.sqrt(1+e[0]-e[5]-e[10]),t[3]=(e[6]-e[9])/n,t[0]=.25*n,t[1]=(e[1]+e[4])/n,t[2]=(e[8]+e[2])/n):e[5]>e[10]?(n=2*Math.sqrt(1+e[5]-e[0]-e[10]),t[3]=(e[8]-e[2])/n,t[0]=(e[1]+e[4])/n,t[1]=.25*n,t[2]=(e[6]+e[9])/n):(n=2*Math.sqrt(1+e[10]-e[0]-e[5]),t[3]=(e[1]-e[4])/n,t[0]=(e[8]+e[2])/n,t[1]=(e[6]+e[9])/n,t[2]=.25*n),t}function C(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=e[3],s=i+i,c=o+o,f=a+a,l=i*s,h=i*c,d=i*f,v=o*c,_=o*f,m=a*f,p=u*s,y=u*c,b=u*f,g=n[0],M=n[1],x=n[2];return t[0]=(1-(v+m))*g,t[1]=(h+b)*g,t[2]=(d-y)*g,t[3]=0,t[4]=(h-b)*M,t[5]=(1-(l+m))*M,t[6]=(_+p)*M,t[7]=0,t[8]=(d+y)*x,t[9]=(_-p)*x,t[10]=(1-(l+v))*x,t[11]=0,t[12]=r[0],t[13]=r[1],t[14]=r[2],t[15]=1,t}function I(t,e,r,n,i){let o=e[0],a=e[1],u=e[2],s=e[3],c=o+o,f=a+a,l=u+u,h=o*c,d=o*f,v=o*l,_=a*f,m=a*l,p=u*l,y=s*c,b=s*f,g=s*l,M=n[0],x=n[1],T=n[2],E=i[0],w=i[1],O=i[2],R=(1-(_+p))*M,P=(d+g)*M,S=(v-b)*M,A=(d-g)*x,N=(1-(h+p))*x,C=(m+y)*x,I=(v+b)*T,L=(m-y)*T,k=(1-(h+_))*T;return t[0]=R,t[1]=P,t[2]=S,t[3]=0,t[4]=A,t[5]=N,t[6]=C,t[7]=0,t[8]=I,t[9]=L,t[10]=k,t[11]=0,t[12]=r[0]+E-(R*E+A*w+I*O),t[13]=r[1]+w-(P*E+N*w+L*O),t[14]=r[2]+O-(S*E+C*w+k*O),t[15]=1,t}function L(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r+r,u=n+n,s=i+i,c=r*a,f=n*a,l=n*u,h=i*a,d=i*u,v=i*s,_=o*a,m=o*u,p=o*s;return t[0]=1-l-v,t[1]=f+p,t[2]=h-m,t[3]=0,t[4]=f-p,t[5]=1-c-v,t[6]=d+_,t[7]=0,t[8]=h+m,t[9]=d-_,t[10]=1-c-l,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function k(t,e,r,n,i,o,a){let u=1/(r-e),s=1/(i-n),c=1/(o-a);return t[0]=2*o*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*o*s,t[6]=0,t[7]=0,t[8]=(r+e)*u,t[9]=(i+n)*s,t[10]=(a+o)*c,t[11]=-1,t[12]=0,t[13]=0,t[14]=a*o*2*c,t[15]=0,t}function F(t,e,r,n,i){let o,a=1/Math.tan(e/2);return t[0]=a/r,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=a,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=i&&i!==1/0?(o=1/(n-i),t[10]=(i+n)*o,t[14]=2*i*n*o):(t[10]=-1,t[14]=-2*n),t}function D(t,e,r,n){let i=Math.tan(e.upDegrees*Math.PI/180),o=Math.tan(e.downDegrees*Math.PI/180),a=Math.tan(e.leftDegrees*Math.PI/180),u=Math.tan(e.rightDegrees*Math.PI/180),s=2/(a+u),c=2/(i+o);return t[0]=s,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=c,t[6]=0,t[7]=0,t[8]=-(a-u)*s*.5,t[9]=(i-o)*c*.5,t[10]=n/(r-n),t[11]=-1,t[12]=0,t[13]=0,t[14]=n*r/(r-n),t[15]=0,t}function j(t,e,r,n,i,o,a){let u=1/(e-r),s=1/(n-i),c=1/(o-a);return t[0]=-2*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*s,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(e+r)*u,t[13]=(i+n)*s,t[14]=(a+o)*c,t[15]=1,t}function B(t,e,r,i){let o,a,u,s,f,l,h,d,v,_,m=e[0],p=e[1],y=e[2],b=i[0],g=i[1],M=i[2],x=r[0],T=r[1],E=r[2];return Math.abs(m-x)<n.EPSILON&&Math.abs(p-T)<n.EPSILON&&Math.abs(y-E)<n.EPSILON?c(t):(h=m-x,d=p-T,v=y-E,o=g*(v*=_=1/Math.sqrt(h*h+d*d+v*v))-M*(d*=_),a=M*(h*=_)-b*v,u=b*d-g*h,(_=Math.sqrt(o*o+a*a+u*u))?(o*=_=1/_,a*=_,u*=_):(o=0,a=0,u=0),s=d*u-v*a,f=v*o-h*u,l=h*a-d*o,(_=Math.sqrt(s*s+f*f+l*l))?(s*=_=1/_,f*=_,l*=_):(s=0,f=0,l=0),t[0]=o,t[1]=s,t[2]=h,t[3]=0,t[4]=a,t[5]=f,t[6]=d,t[7]=0,t[8]=u,t[9]=l,t[10]=v,t[11]=0,t[12]=-(o*m+a*p+u*y),t[13]=-(s*m+f*p+l*y),t[14]=-(h*m+d*p+v*y),t[15]=1,t)}function U(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=n[0],s=n[1],c=n[2],f=i-r[0],l=o-r[1],h=a-r[2],d=f*f+l*l+h*h;d>0&&(f*=d=1/Math.sqrt(d),l*=d,h*=d);let v=s*h-c*l,_=c*f-u*h,m=u*l-s*f;return(d=v*v+_*_+m*m)>0&&(v*=d=1/Math.sqrt(d),_*=d,m*=d),t[0]=v,t[1]=_,t[2]=m,t[3]=0,t[4]=l*m-h*_,t[5]=h*v-f*m,t[6]=f*_-l*v,t[7]=0,t[8]=f,t[9]=l,t[10]=h,t[11]=0,t[12]=i,t[13]=o,t[14]=a,t[15]=1,t}function V(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"}function Y(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2)+Math.pow(t[9],2)+Math.pow(t[10],2)+Math.pow(t[11],2)+Math.pow(t[12],2)+Math.pow(t[13],2)+Math.pow(t[14],2)+Math.pow(t[15],2))}function G(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t[8]=e[8]+r[8],t[9]=e[9]+r[9],t[10]=e[10]+r[10],t[11]=e[11]+r[11],t[12]=e[12]+r[12],t[13]=e[13]+r[13],t[14]=e[14]+r[14],t[15]=e[15]+r[15],t}function q(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t[6]=e[6]-r[6],t[7]=e[7]-r[7],t[8]=e[8]-r[8],t[9]=e[9]-r[9],t[10]=e[10]-r[10],t[11]=e[11]-r[11],t[12]=e[12]-r[12],t[13]=e[13]-r[13],t[14]=e[14]-r[14],t[15]=e[15]-r[15],t}function H(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*r,t[9]=e[9]*r,t[10]=e[10]*r,t[11]=e[11]*r,t[12]=e[12]*r,t[13]=e[13]*r,t[14]=e[14]*r,t[15]=e[15]*r,t}function X(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t[6]=e[6]+r[6]*n,t[7]=e[7]+r[7]*n,t[8]=e[8]+r[8]*n,t[9]=e[9]+r[9]*n,t[10]=e[10]+r[10]*n,t[11]=e[11]+r[11]*n,t[12]=e[12]+r[12]*n,t[13]=e[13]+r[13]*n,t[14]=e[14]+r[14]*n,t[15]=e[15]+r[15]*n,t}function W(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]&&t[8]===e[8]&&t[9]===e[9]&&t[10]===e[10]&&t[11]===e[11]&&t[12]===e[12]&&t[13]===e[13]&&t[14]===e[14]&&t[15]===e[15]}function K(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=t[8],h=t[9],d=t[10],v=t[11],_=t[12],m=t[13],p=t[14],y=t[15],b=e[0],g=e[1],M=e[2],x=e[3],T=e[4],E=e[5],w=e[6],O=e[7],R=e[8],P=e[9],S=e[10],A=e[11],N=e[12],C=e[13],I=e[14],L=e[15];return Math.abs(r-b)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(b))&&Math.abs(i-g)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(g))&&Math.abs(o-M)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(M))&&Math.abs(a-x)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(x))&&Math.abs(u-T)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(T))&&Math.abs(s-E)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(E))&&Math.abs(c-w)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(f-O)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(O))&&Math.abs(l-R)<=n.EPSILON*Math.max(1,Math.abs(l),Math.abs(R))&&Math.abs(h-P)<=n.EPSILON*Math.max(1,Math.abs(h),Math.abs(P))&&Math.abs(d-S)<=n.EPSILON*Math.max(1,Math.abs(d),Math.abs(S))&&Math.abs(v-A)<=n.EPSILON*Math.max(1,Math.abs(v),Math.abs(A))&&Math.abs(_-N)<=n.EPSILON*Math.max(1,Math.abs(_),Math.abs(N))&&Math.abs(m-C)<=n.EPSILON*Math.max(1,Math.abs(m),Math.abs(C))&&Math.abs(p-I)<=n.EPSILON*Math.max(1,Math.abs(p),Math.abs(I))&&Math.abs(y-L)<=n.EPSILON*Math.max(1,Math.abs(y),Math.abs(L))}const z=v,Q=q},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Renderer=e.RenderTexture=e.RenderView=e.ATTRIB_MASK=e.ATTRIB=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.createWebGLContext=p;var i=r(3),o=r(2),a=r(21),u=r(8),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var f=e.ATTRIB={POSITION:1,NORMAL:2,TANGENT:3,TEXCOORD_0:4,TEXCOORD_1:5,COLOR_0:6},l=e.ATTRIB_MASK={POSITION:1,NORMAL:2,TANGENT:4,TEXCOORD_0:8,TEXCOORD_1:16,COLOR_0:32},h=WebGLRenderingContext,d=new Float32Array([-.1,-1,-.2]),v=new Float32Array([3,3,3]),_=new RegExp("precision (lowp|mediump|highp) float;");function m(t){return 0==(t&t-1)}function p(t){t=t||{alpha:!1};var e=document.createElement("canvas"),r=t.webgl2?["webgl2"]:["webgl","experimental-webgl"],n=null,i=!0,o=!1,a=void 0;try{for(var u,s=r[Symbol.iterator]();!(i=(u=s.next()).done);i=!0){var c=u.value;if(n=e.getContext(c,t))break}}catch(t){o=!0,a=t}finally{try{!i&&s.return&&s.return()}finally{if(o)throw a}}if(!n){var f=t.webgl2?"WebGL 2":"WebGL";return console.error("This browser does not support "+f+"."),null}return n}e.RenderView=function(){function t(e,r){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"left";c(this,t),this.projectionMatrix=e,this.viewMatrix=r,this.viewport=n,this._eye=i,this._eyeIndex="left"==i?0:1}return n(t,[{key:"eye",get:function(){return this._eye},set:function(t){this._eye=t,this._eyeIndex="left"==t?0:1}},{key:"eyeIndex",get:function(){return this._eyeIndex}}]),t}();var y=function(){function t(e,r,n){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;c(this,t),this._target=e,this._usage=r,this._length=o,n instanceof Promise?(this._buffer=null,this._promise=n.then(function(t){return i._buffer=t,i})):(this._buffer=n,this._promise=Promise.resolve(this))}return n(t,[{key:"waitForComplete",value:function(){return this._promise}}]),t}(),b=function t(e){c(this,t),this._attrib_index=f[e.name],this._componentCount=e.componentCount,this._componentType=e.componentType,this._stride=e.stride,this._byteOffset=e.byteOffset,this._normalized=e.normalized},g=function t(e){c(this,t),this._buffer=e,this._attributes=[]},M=function(){function t(e){c(this,t),this._activeFrameId=0,this._instances=[],this._material=null,this.setPrimitive(e)}return n(t,[{key:"setPrimitive",value:function(t){this._mode=t.mode,this._elementCount=t.elementCount,this._promise=null,this._vao=null,this._complete=!1,this._attributeBuffers=[],this._attributeMask=0;var e=!0,r=!1,n=void 0;try{for(var i,o=t.attributes[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){var a=i.value;this._attributeMask|=l[a.name];var u=new b(a),c=!1,f=!0,h=!1,d=void 0;try{for(var v,_=this._attributeBuffers[Symbol.iterator]();!(f=(v=_.next()).done);f=!0){var m=v.value;if(m._buffer==a.buffer){m._attributes.push(u),c=!0;break}}}catch(t){h=!0,d=t}finally{try{!f&&_.return&&_.return()}finally{if(h)throw d}}if(!c){var p=new g(a.buffer);p._attributes.push(u),this._attributeBuffers.push(p)}}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}this._indexBuffer=null,this._indexByteOffset=0,this._indexType=0,t.indexBuffer&&(this._indexByteOffset=t.indexByteOffset,this._indexType=t.indexType,this._indexBuffer=t.indexBuffer),t._min?(this._min=s.vec3.clone(t._min),this._max=s.vec3.clone(t._max)):(this._min=null,this._max=null),null!=this._material&&this.waitForComplete()}},{key:"setRenderMaterial",value:function(t){this._material=t,this._promise=null,this._complete=!1,null!=this._material&&this.waitForComplete()}},{key:"markActive",value:function(t){if(this._complete&&this._activeFrameId!=t){if(this._material&&!this._material.markActive(t))return;this._activeFrameId=t}}},{key:"waitForComplete",value:function(){var t=this;if(!this._promise){if(!this._material)return Promise.reject("RenderPrimitive does not have a material");var e=[],r=!0,n=!1,i=void 0;try{for(var o,a=this._attributeBuffers[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){var u=o.value;u._buffer._buffer||e.push(u._buffer._promise)}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}this._indexBuffer&&!this._indexBuffer._buffer&&e.push(this._indexBuffer._promise),this._promise=Promise.all(e).then(function(){return t._complete=!0,t})}return this._promise}},{key:"samplers",get:function(){return this._material._samplerDictionary}},{key:"uniforms",get:function(){return this._material._uniform_dictionary}}]),t}(),x=e.RenderTexture=function(){function t(e){c(this,t),this._texture=e,this._complete=!1,this._activeFrameId=0,this._activeCallback=null}return n(t,[{key:"markActive",value:function(t){this._activeCallback&&this._activeFrameId!=t&&(this._activeFrameId=t,this._activeCallback(this))}}]),t}(),T=s.mat4.create();function E(t,e,r,n,i){var o=(i&r)-(n&r);o&&(o>0?t.enable(e):t.disable(e))}var w=function(){function t(e,r,n){c(this,t),this._renderer=e,this._uniformName=r._uniformName,this._renderTexture=e._getRenderTexture(r._texture),this._index=n}return n(t,[{key:"texture",set:function(t){this._renderTexture=this._renderer._getRenderTexture(t)}}]),t}(),O=function(){function t(e){c(this,t),this._uniformName=e._uniformName,this._uniform=null,this._length=e._length,e._value instanceof Array?this._value=new Float32Array(e._value):this._value=new Float32Array([e._value])}return n(t,[{key:"value",set:function(t){if(1==this._value.length)this._value[0]=t;else for(var e=0;e<this._value.length;++e)this._value[e]=t[e]}}]),t}(),R=function(){function t(e,r,n){c(this,t),this._program=n,this._state=r.state._state,this._activeFrameId=0,this._completeForActiveFrame=!1,this._samplerDictionary={},this._samplers=[];for(var o=0;o<r._samplers.length;++o){var a=new w(e,r._samplers[o],o);this._samplers.push(a),this._samplerDictionary[a._uniformName]=a}this._uniform_dictionary={},this._uniforms=[];var u=!0,s=!1,f=void 0;try{for(var l,h=r._uniforms[Symbol.iterator]();!(u=(l=h.next()).done);u=!0){var d=l.value,v=new O(d);this._uniforms.push(v),this._uniform_dictionary[v._uniformName]=v}}catch(t){s=!0,f=t}finally{try{!u&&h.return&&h.return()}finally{if(s)throw f}}this._firstBind=!0,this._renderOrder=r.renderOrder,this._renderOrder==i.RENDER_ORDER.DEFAULT&&(this._state&i.CAP.BLEND?this._renderOrder=i.RENDER_ORDER.TRANSPARENT:this._renderOrder=i.RENDER_ORDER.OPAQUE)}return n(t,[{key:"bind",value:function(t){if(this._firstBind){for(var e=0;e<this._samplers.length;){var r=this._samplers[e];this._program.uniform[r._uniformName]?++e:this._samplers.splice(e,1)}for(var n=0;n<this._uniforms.length;){var i=this._uniforms[n];i._uniform=this._program.uniform[i._uniformName],i._uniform?++n:this._uniforms.splice(n,1)}this._firstBind=!1}var o=!0,a=!1,u=void 0;try{for(var s,c=this._samplers[Symbol.iterator]();!(o=(s=c.next()).done);o=!0){var f=s.value;t.activeTexture(t.TEXTURE0+f._index),f._renderTexture&&f._renderTexture._complete?t.bindTexture(t.TEXTURE_2D,f._renderTexture._texture):t.bindTexture(t.TEXTURE_2D,null)}}catch(t){a=!0,u=t}finally{try{!o&&c.return&&c.return()}finally{if(a)throw u}}var l=!0,h=!1,d=void 0;try{for(var v,_=this._uniforms[Symbol.iterator]();!(l=(v=_.next()).done);l=!0){var m=v.value;switch(m._length){case 1:t.uniform1fv(m._uniform,m._value);break;case 2:t.uniform2fv(m._uniform,m._value);break;case 3:t.uniform3fv(m._uniform,m._value);break;case 4:t.uniform4fv(m._uniform,m._value)}}}catch(t){h=!0,d=t}finally{try{!l&&_.return&&_.return()}finally{if(h)throw d}}}},{key:"markActive",value:function(t){if(this._activeFrameId!=t){this._activeFrameId=t,this._completeForActiveFrame=!0;for(var e=0;e<this._samplers.length;++e){var r=this._samplers[e];if(r._renderTexture){if(!r._renderTexture._complete){this._completeForActiveFrame=!1;break}r._renderTexture.markActive(t)}}}return this._completeForActiveFrame}},{key:"_capsDiff",value:function(t){return t&i.MAT_STATE.CAPS_RANGE^this._state&i.MAT_STATE.CAPS_RANGE}},{key:"_blendDiff",value:function(t){return this._state&i.CAP.BLEND?t&i.MAT_STATE.BLEND_FUNC_RANGE^this._state&i.MAT_STATE.BLEND_FUNC_RANGE:0}},{key:"_depthFuncDiff",value:function(t){return this._state&i.CAP.DEPTH_TEST?t&i.MAT_STATE.DEPTH_FUNC_RANGE^this._state&i.MAT_STATE.DEPTH_FUNC_RANGE:0}},{key:"cullFace",get:function(){return!!(this._state&i.CAP.CULL_FACE)}},{key:"blend",get:function(){return!!(this._state&i.CAP.BLEND)}},{key:"depthTest",get:function(){return!!(this._state&i.CAP.DEPTH_TEST)}},{key:"stencilTest",get:function(){return!!(this._state&i.CAP.STENCIL_TEST)}},{key:"colorMask",get:function(){return!!(this._state&i.CAP.COLOR_MASK)}},{key:"depthMask",get:function(){return!!(this._state&i.CAP.DEPTH_MASK)}},{key:"stencilMask",get:function(){return!!(this._state&i.CAP.STENCIL_MASK)}},{key:"depthFunc",get:function(){return((this._state&i.MAT_STATE.DEPTH_FUNC_RANGE)>>i.MAT_STATE.DEPTH_FUNC_SHIFT)+h.NEVER}},{key:"blendFuncSrc",get:function(){return(0,i.stateToBlendFunc)(this._state,i.MAT_STATE.BLEND_SRC_RANGE,i.MAT_STATE.BLEND_SRC_SHIFT)}},{key:"blendFuncDst",get:function(){return(0,i.stateToBlendFunc)(this._state,i.MAT_STATE.BLEND_DST_RANGE,i.MAT_STATE.BLEND_DST_SHIFT)}}]),t}();e.Renderer=function(){function t(e){c(this,t),this._gl=e||p(),this._frameId=0,this._programCache={},this._textureCache={},this._renderPrimitives=Array(i.RENDER_ORDER.DEFAULT),this._cameraPositions=[],this._vaoExt=e.getExtension("OES_vertex_array_object");var r=e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT);this._defaultFragPrecision=r.precision>0?"highp":"mediump",this._depthMaskNeedsReset=!1,this._colorMaskNeedsReset=!1,this._globalLightColor=s.vec3.clone(v),this._globalLightDir=s.vec3.clone(d)}return n(t,[{key:"createRenderBuffer",value:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:h.STATIC_DRAW,n=this._gl,i=n.createBuffer();if(e instanceof Promise){var o=new y(t,r,e.then(function(e){return n.bindBuffer(t,i),n.bufferData(t,e,r),o._length=e.byteLength,i}));return o}return n.bindBuffer(t,i),n.bufferData(t,e,r),new y(t,r,i,e.byteLength)}},{key:"updateRenderBuffer",value:function(t,e){var r=this,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(t._buffer){var i=this._gl;i.bindBuffer(t._target,t._buffer),0==n&&t._length==e.byteLength?i.bufferData(t._target,e,t._usage):i.bufferSubData(t._target,n,e)}else t.waitForComplete().then(function(t){r.updateRenderBuffer(t,e,n)})}},{key:"createRenderPrimitive",value:function(t,e){var r=new M(t),n=this._getMaterialProgram(e,r),i=new R(this,e,n);return r.setRenderMaterial(i),this._renderPrimitives[i._renderOrder]||(this._renderPrimitives[i._renderOrder]=[]),this._renderPrimitives[i._renderOrder].push(r),r}},{key:"createMesh",value:function(t,e){var r=new o.Node;return r.addRenderPrimitive(this.createRenderPrimitive(t,e)),r}},{key:"drawViews",value:function(t,e){if(e){var r=this._gl;if(this._frameId++,e.markActive(this._frameId),1==t.length&&t[0].viewport){var n=t[0].viewport;this._gl.viewport(n.x,n.y,n.width,n.height)}for(var i=0;i<t.length;++i){s.mat4.invert(T,t[i].viewMatrix),this._cameraPositions.length<=i&&this._cameraPositions.push(s.vec3.create());var o=this._cameraPositions[i];s.vec3.set(o,0,0,0),s.vec3.transformMat4(o,o,T)}var a=!0,u=!1,c=void 0;try{for(var f,l=this._renderPrimitives[Symbol.iterator]();!(a=(f=l.next()).done);a=!0){var h=f.value;h&&h.length&&this._drawRenderPrimitiveSet(t,h)}}catch(t){u=!0,c=t}finally{try{!a&&l.return&&l.return()}finally{if(u)throw c}}this._vaoExt&&this._vaoExt.bindVertexArrayOES(null),this._depthMaskNeedsReset&&r.depthMask(!0),this._colorMaskNeedsReset&&r.colorMask(!0,!0,!0,!0)}}},{key:"_drawRenderPrimitiveSet",value:function(t,e){var r=this._gl,n=null,i=null,o=0,a=!0,u=!1,s=void 0;try{for(var c,f=e[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;if(l._activeFrameId==this._frameId){n!=l._material._program&&((n=l._material._program).use(),n.uniform.LIGHT_DIRECTION&&r.uniform3fv(n.uniform.LIGHT_DIRECTION,this._globalLightDir),n.uniform.LIGHT_COLOR&&r.uniform3fv(n.uniform.LIGHT_COLOR,this._globalLightColor),1==t.length&&(r.uniformMatrix4fv(n.uniform.PROJECTION_MATRIX,!1,t[0].projectionMatrix),r.uniformMatrix4fv(n.uniform.VIEW_MATRIX,!1,t[0].viewMatrix),r.uniform3fv(n.uniform.CAMERA_POSITION,this._cameraPositions[0]),r.uniform1i(n.uniform.EYE_INDEX,t[0].eyeIndex))),i!=l._material&&(this._bindMaterialState(l._material,i),l._material.bind(r,n,i),i=l._material),this._vaoExt?l._vao?this._vaoExt.bindVertexArrayOES(l._vao):(l._vao=this._vaoExt.createVertexArrayOES(),this._vaoExt.bindVertexArrayOES(l._vao),this._bindPrimitive(l)):(this._bindPrimitive(l,o),o=l._attributeMask);for(var h=0;h<t.length;++h){var d=t[h];if(t.length>1){if(d.viewport){var v=d.viewport;r.viewport(v.x,v.y,v.width,v.height)}r.uniformMatrix4fv(n.uniform.PROJECTION_MATRIX,!1,d.projectionMatrix),r.uniformMatrix4fv(n.uniform.VIEW_MATRIX,!1,d.viewMatrix),r.uniform3fv(n.uniform.CAMERA_POSITION,this._cameraPositions[h]),r.uniform1i(n.uniform.EYE_INDEX,d.eyeIndex)}var _=!0,m=!1,p=void 0;try{for(var y,b=l._instances[Symbol.iterator]();!(_=(y=b.next()).done);_=!0){var g=y.value;g._activeFrameId==this._frameId&&(r.uniformMatrix4fv(n.uniform.MODEL_MATRIX,!1,g.worldMatrix),l._indexBuffer?r.drawElements(l._mode,l._elementCount,l._indexType,l._indexByteOffset):r.drawArrays(l._mode,0,l._elementCount))}}catch(t){m=!0,p=t}finally{try{!_&&b.return&&b.return()}finally{if(m)throw p}}}}}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}},{key:"_getRenderTexture",value:function(t){var e=this;if(!t)return null;var r=t.textureKey;if(!r)throw new Error("Texure does not have a valid key");if(r in this._textureCache)return this._textureCache[r];var n=this._gl,i=n.createTexture(),o=new x(i);return this._textureCache[r]=o,t instanceof u.DataTexture?(n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.width,t.height,0,t.format,t._type,t._data),this._setSamplerParameters(t),o._complete=!0):t.waitForComplete().then(function(){n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.format,n.UNSIGNED_BYTE,t.source),e._setSamplerParameters(t),o._complete=!0,t instanceof u.VideoTexture&&t._video.addEventListener("playing",function(){o._activeCallback=function(){t._video.paused||t._video.waiting||(n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.format,n.UNSIGNED_BYTE,t.source))}})}),o}},{key:"_setSamplerParameters",value:function(t){var e=this._gl,r=t.sampler,n=m(t.width)&&m(t.height),i=n&&t.mipmap;i&&e.generateMipmap(e.TEXTURE_2D);var o=r.minFilter||(i?e.LINEAR_MIPMAP_LINEAR:e.LINEAR),a=r.wrapS||(n?e.REPEAT:e.CLAMP_TO_EDGE),u=r.wrapT||(n?e.REPEAT:e.CLAMP_TO_EDGE);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,r.magFilter||e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,o),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,a),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,u)}},{key:"_getProgramKey",value:function(t,e){var r=t+":";for(var n in e)r+=n+"="+e[n]+",";return r}},{key:"_getMaterialProgram",value:function(t,e){var r=this,n=t.materialName,i=t.vertexSource,o=t.fragmentSource;if(null==n)throw new Error("Material does not have a name");if(null==i)throw new Error('Material "'+n+'" does not have a vertex source');if(null==o)throw new Error('Material "'+n+'" does not have a fragment source');var u=t.getProgramDefines(e),s=this._getProgramKey(n,u);if(s in this._programCache)return this._programCache[s];var c=i;c+="\nuniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;\n\nvoid main() {\n gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);\n}\n";var l=(o.match(_)?"":"precision "+this._defaultFragPrecision+" float;\n")+o;l+="\nvoid main() {\n gl_FragColor = fragment_main();\n}\n";var h=new a.Program(this._gl,c,l,f,u);return this._programCache[s]=h,h.onNextUse(function(e){for(var n=0;n<t._samplers.length;++n){var i=t._samplers[n],o=e.uniform[i._uniformName];o&&r._gl.uniform1i(o,n)}}),h}},{key:"_bindPrimitive",value:function(t,e){var r=this._gl;if(e!=t._attributeMask)for(var n in f)t._attributeMask&l[n]?r.enableVertexAttribArray(f[n]):r.disableVertexAttribArray(f[n]);var i=!0,o=!1,a=void 0;try{for(var u,s=t._attributeBuffers[Symbol.iterator]();!(i=(u=s.next()).done);i=!0){var c=u.value;r.bindBuffer(r.ARRAY_BUFFER,c._buffer._buffer);var h=!0,d=!1,v=void 0;try{for(var _,m=c._attributes[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=_.value;r.vertexAttribPointer(p._attrib_index,p._componentCount,p._componentType,p._normalized,p._stride,p._byteOffset)}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}}}catch(t){o=!0,a=t}finally{try{!i&&s.return&&s.return()}finally{if(o)throw a}}t._indexBuffer?r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,t._indexBuffer._buffer):r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,null)}},{key:"_bindMaterialState",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=this._gl,n=t._state,o=e?e._state:~n;if(n!=o){if(t._capsDiff(o)){E(r,r.CULL_FACE,i.CAP.CULL_FACE,o,n),E(r,r.BLEND,i.CAP.BLEND,o,n),E(r,r.DEPTH_TEST,i.CAP.DEPTH_TEST,o,n),E(r,r.STENCIL_TEST,i.CAP.STENCIL_TEST,o,n);var a=(n&i.CAP.COLOR_MASK)-(o&i.CAP.COLOR_MASK);if(a){var u=a>1;this._colorMaskNeedsReset=!u,r.colorMask(u,u,u,u)}var s=(n&i.CAP.DEPTH_MASK)-(o&i.CAP.DEPTH_MASK);s&&(this._depthMaskNeedsReset=!(s>1),r.depthMask(s>1));var c=(n&i.CAP.STENCIL_MASK)-(o&i.CAP.STENCIL_MASK);c&&r.stencilMask(c>1)}t._blendDiff(o)&&r.blendFunc(t.blendFuncSrc,t.blendFuncDst),t._depthFuncDiff(o)&&r.depthFunc(t.depthFunc)}}},{key:"gl",get:function(){return this._gl}},{key:"globalLightColor",set:function(t){s.vec3.copy(this._globalLightColor,t)},get:function(){return s.vec3.clone(this._globalLightColor)}},{key:"globalLightDir",set:function(t){s.vec3.copy(this._globalLightDir,t)},get:function(){return s.vec3.clone(this._globalLightDir)}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"fromMat4",function(){return o}),r.d(e,"clone",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"identity",function(){return f}),r.d(e,"transpose",function(){return l}),r.d(e,"invert",function(){return h}),r.d(e,"adjoint",function(){return d}),r.d(e,"determinant",function(){return v}),r.d(e,"multiply",function(){return _}),r.d(e,"translate",function(){return m}),r.d(e,"rotate",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"fromTranslation",function(){return b}),r.d(e,"fromRotation",function(){return g}),r.d(e,"fromScaling",function(){return M}),r.d(e,"fromMat2d",function(){return x}),r.d(e,"fromQuat",function(){return T}),r.d(e,"normalFromMat4",function(){return E}),r.d(e,"projection",function(){return w}),r.d(e,"str",function(){return O}),r.d(e,"frob",function(){return R}),r.d(e,"add",function(){return P}),r.d(e,"subtract",function(){return S}),r.d(e,"multiplyScalar",function(){return A}),r.d(e,"multiplyScalarAndAdd",function(){return N}),r.d(e,"exactEquals",function(){return C}),r.d(e,"equals",function(){return I}),r.d(e,"mul",function(){return L}),r.d(e,"sub",function(){return k});var n=r(0);function i(){let t=new n.ARRAY_TYPE(9);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function o(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t}function a(t){let e=new n.ARRAY_TYPE(9);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}function u(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t}function s(t,e,r,i,o,a,u,s,c){let f=new n.ARRAY_TYPE(9);return f[0]=t,f[1]=e,f[2]=r,f[3]=i,f[4]=o,f[5]=a,f[6]=u,f[7]=s,f[8]=c,f}function c(t,e,r,n,i,o,a,u,s,c){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t[8]=c,t}function f(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function l(t,e){if(t===e){let r=e[1],n=e[2],i=e[5];t[1]=e[3],t[2]=e[6],t[3]=r,t[5]=e[7],t[6]=n,t[7]=i}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8];return t}function h(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=f*a-u*c,h=-f*o+u*s,d=c*o-a*s,v=r*l+n*h+i*d;return v?(v=1/v,t[0]=l*v,t[1]=(-f*n+i*c)*v,t[2]=(u*n-i*a)*v,t[3]=h*v,t[4]=(f*r-i*s)*v,t[5]=(-u*r+i*o)*v,t[6]=d*v,t[7]=(-c*r+n*s)*v,t[8]=(a*r-n*o)*v,t):null}function d(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8];return t[0]=a*f-u*c,t[1]=i*c-n*f,t[2]=n*u-i*a,t[3]=u*s-o*f,t[4]=r*f-i*s,t[5]=i*o-r*u,t[6]=o*c-a*s,t[7]=n*s-r*c,t[8]=r*a-n*o,t}function v(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=t[4],a=t[5],u=t[6],s=t[7],c=t[8];return e*(c*o-a*s)+r*(-c*i+a*u)+n*(s*i-o*u)}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=r[0],d=r[1],v=r[2],_=r[3],m=r[4],p=r[5],y=r[6],b=r[7],g=r[8];return t[0]=h*n+d*a+v*c,t[1]=h*i+d*u+v*f,t[2]=h*o+d*s+v*l,t[3]=_*n+m*a+p*c,t[4]=_*i+m*u+p*f,t[5]=_*o+m*s+p*l,t[6]=y*n+b*a+g*c,t[7]=y*i+b*u+g*f,t[8]=y*o+b*s+g*l,t}function m(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=r[0],d=r[1];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=u,t[5]=s,t[6]=h*n+d*a+c,t[7]=h*i+d*u+f,t[8]=h*o+d*s+l,t}function p(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=Math.sin(r),d=Math.cos(r);return t[0]=d*n+h*a,t[1]=d*i+h*u,t[2]=d*o+h*s,t[3]=d*a-h*n,t[4]=d*u-h*i,t[5]=d*s-h*o,t[6]=c,t[7]=f,t[8]=l,t}function y(t,e,r){let n=r[0],i=r[1];return t[0]=n*e[0],t[1]=n*e[1],t[2]=n*e[2],t[3]=i*e[3],t[4]=i*e[4],t[5]=i*e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t}function b(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=e[0],t[7]=e[1],t[8]=1,t}function g(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=0,t[3]=-r,t[4]=n,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function M(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=0,t[4]=e[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function x(t,e){return t[0]=e[0],t[1]=e[1],t[2]=0,t[3]=e[2],t[4]=e[3],t[5]=0,t[6]=e[4],t[7]=e[5],t[8]=1,t}function T(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r+r,u=n+n,s=i+i,c=r*a,f=n*a,l=n*u,h=i*a,d=i*u,v=i*s,_=o*a,m=o*u,p=o*s;return t[0]=1-l-v,t[3]=f-p,t[6]=h+m,t[1]=f+p,t[4]=1-c-v,t[7]=d-_,t[2]=h-m,t[5]=d+_,t[8]=1-c-l,t}function E(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15],y=r*u-n*a,b=r*s-i*a,g=r*c-o*a,M=n*s-i*u,x=n*c-o*u,T=i*c-o*s,E=f*_-l*v,w=f*m-h*v,O=f*p-d*v,R=l*m-h*_,P=l*p-d*_,S=h*p-d*m,A=y*S-b*P+g*R+M*O-x*w+T*E;return A?(A=1/A,t[0]=(u*S-s*P+c*R)*A,t[1]=(s*O-a*S-c*w)*A,t[2]=(a*P-u*O+c*E)*A,t[3]=(i*P-n*S-o*R)*A,t[4]=(r*S-i*O+o*w)*A,t[5]=(n*O-r*P-o*E)*A,t[6]=(_*T-m*x+p*M)*A,t[7]=(m*g-v*T-p*b)*A,t[8]=(v*x-_*g+p*y)*A,t):null}function w(t,e,r){return t[0]=2/e,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/r,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t}function O(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"}function R(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2))}function P(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t[8]=e[8]+r[8],t}function S(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t[6]=e[6]-r[6],t[7]=e[7]-r[7],t[8]=e[8]-r[8],t}function A(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*r,t}function N(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t[6]=e[6]+r[6]*n,t[7]=e[7]+r[7]*n,t[8]=e[8]+r[8]*n,t}function C(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]&&t[8]===e[8]}function I(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=t[8],h=e[0],d=e[1],v=e[2],_=e[3],m=e[4],p=e[5],y=e[6],b=e[7],g=e[8];return Math.abs(r-h)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(i-d)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(d))&&Math.abs(o-v)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(a-_)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(_))&&Math.abs(u-m)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(m))&&Math.abs(s-p)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(c-y)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(y))&&Math.abs(f-b)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(b))&&Math.abs(l-g)<=n.EPSILON*Math.max(1,Math.abs(l),Math.abs(g))}const L=_,k=S},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BoxBuilder=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(9);e.BoxBuilder=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.GeometryBuilderBase),n(e,[{key:"pushBox",value:function(t,e){var r=this.primitiveStream,n=.5*(e[0]-t[0]),i=.5*(e[1]-t[1]),o=.5*(e[2]-t[2]),a=t[0]+n,u=t[1]+i,s=t[2]+o;r.startGeometry();var c=r.nextVertexIndex;r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(-n+a,-i+u,-o+s,0,1,0,-1,0),r.pushVertex(+n+a,-i+u,-o+s,1,1,0,-1,0),r.pushVertex(+n+a,-i+u,+o+s,1,0,0,-1,0),r.pushVertex(-n+a,-i+u,+o+s,0,0,0,-1,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,+i+u,-o+s,0,0,0,1,0),r.pushVertex(+n+a,+i+u,-o+s,1,0,0,1,0),r.pushVertex(+n+a,+i+u,+o+s,1,1,0,1,0),r.pushVertex(-n+a,+i+u,+o+s,0,1,0,1,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,-i+u,-o+s,0,1,-1,0,0),r.pushVertex(-n+a,+i+u,-o+s,0,0,-1,0,0),r.pushVertex(-n+a,+i+u,+o+s,1,0,-1,0,0),r.pushVertex(-n+a,-i+u,+o+s,1,1,-1,0,0),c=r.nextVertexIndex,r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(+n+a,-i+u,-o+s,1,1,1,0,0),r.pushVertex(+n+a,+i+u,-o+s,1,0,1,0,0),r.pushVertex(+n+a,+i+u,+o+s,0,0,1,0,0),r.pushVertex(+n+a,-i+u,+o+s,0,1,1,0,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,-i+u,-o+s,1,1,0,0,-1),r.pushVertex(+n+a,-i+u,-o+s,0,1,0,0,-1),r.pushVertex(+n+a,+i+u,-o+s,0,0,0,0,-1),r.pushVertex(-n+a,+i+u,-o+s,1,0,0,0,-1),c=r.nextVertexIndex,r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(-n+a,-i+u,+o+s,0,1,0,0,1),r.pushVertex(+n+a,-i+u,+o+s,1,1,0,0,1),r.pushVertex(+n+a,+i+u,+o+s,1,0,0,0,1),r.pushVertex(-n+a,+i+u,+o+s,0,0,0,0,1),r.endGeometry()}},{key:"pushCube",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[0,0,0],e=.5*(arguments.length>1&&void 0!==arguments[1]?arguments[1]:1);this.pushBox([t[0]-e,t[1]-e,t[2]-e],[t[0]+e,t[1]+e,t[2]+e])}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.PbrMaterial=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(11);e.PbrMaterial=function(t){function e(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e);var t=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.baseColor=t.defineSampler("baseColorTex"),t.metallicRoughness=t.defineSampler("metallicRoughnessTex"),t.normal=t.defineSampler("normalTex"),t.occlusion=t.defineSampler("occlusionTex"),t.emissive=t.defineSampler("emissiveTex"),t.baseColorFactor=t.defineUniform("baseColorFactor",[1,1,1,1]),t.metallicRoughnessFactor=t.defineUniform("metallicRoughnessFactor",[1,1]),t.occlusionStrength=t.defineUniform("occlusionStrength",1),t.emissiveFactor=t.defineUniform("emissiveFactor",[0,0,0]),t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.Material),n(e,[{key:"getProgramDefines",value:function(t){var e={};return t._attributeMask&o.ATTRIB_MASK.COLOR_0&&(e.USE_VERTEX_COLOR=1),t._attributeMask&o.ATTRIB_MASK.TEXCOORD_0&&(this.baseColor.texture&&(e.USE_BASE_COLOR_MAP=1),this.normal.texture&&t._attributeMask&o.ATTRIB_MASK.TANGENT&&(e.USE_NORMAL_MAP=1),this.metallicRoughness.texture&&(e.USE_METAL_ROUGH_MAP=1),this.occlusion.texture&&(e.USE_OCCLUSION=1),this.emissive.texture&&(e.USE_EMISSIVE_TEXTURE=1)),this.metallicRoughness.texture&&t._attributeMask&o.ATTRIB_MASK.TEXCOORD_0||1!=this.metallicRoughnessFactor.value[1]||(e.FULLY_ROUGH=1),e}},{key:"materialName",get:function(){return"PBR"}},{key:"vertexSource",get:function(){return"\nattribute vec3 POSITION, NORMAL;\nattribute vec2 TEXCOORD_0, TEXCOORD_1;\n\nuniform vec3 CAMERA_POSITION;\nuniform vec3 LIGHT_DIRECTION;\n\nvarying vec3 vLight; // Vector from vertex to light.\nvarying vec3 vView; // Vector from vertex to camera.\nvarying vec2 vTex;\n\n#ifdef USE_NORMAL_MAP\nattribute vec4 TANGENT;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_VERTEX_COLOR\nattribute vec4 COLOR_0;\nvarying vec4 vCol;\n#endif\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));\n#ifdef USE_NORMAL_MAP\n vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));\n vec3 b = cross(n, t) * TANGENT.w;\n vTBN = mat3(t, b, n);\n#else\n vNorm = n;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n vCol = COLOR_0;\n#endif\n\n vTex = TEXCOORD_0;\n vec4 mPos = model * vec4(POSITION, 1.0);\n vLight = -LIGHT_DIRECTION;\n vView = CAMERA_POSITION - mPos.xyz;\n return proj * view * mPos;\n}"}},{key:"fragmentSource",get:function(){return"\n#define M_PI 3.14159265\n\nuniform vec4 baseColorFactor;\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D baseColorTex;\n#endif\n\nvarying vec3 vLight;\nvarying vec3 vView;\nvarying vec2 vTex;\n\n#ifdef USE_VERTEX_COLOR\nvarying vec4 vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\nuniform sampler2D normalTex;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_METAL_ROUGH_MAP\nuniform sampler2D metallicRoughnessTex;\n#endif\nuniform vec2 metallicRoughnessFactor;\n\n#ifdef USE_OCCLUSION\nuniform sampler2D occlusionTex;\nuniform float occlusionStrength;\n#endif\n\n#ifdef USE_EMISSIVE_TEXTURE\nuniform sampler2D emissiveTex;\n#endif\nuniform vec3 emissiveFactor;\n\nuniform vec3 LIGHT_COLOR;\n\nconst vec3 dielectricSpec = vec3(0.04);\nconst vec3 black = vec3(0.0);\n\n\nvec3 lambertDiffuse(vec3 cDiff) {\n return cDiff / M_PI;\n}\n\nfloat specD(float a, float nDotH) {\n float aSqr = a * a;\n float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);\n return aSqr / (M_PI * f * f);\n}\n\nfloat specG(float roughness, float nDotL, float nDotV) {\n float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n float gl = nDotL / (nDotL * (1.0 - k) + k);\n float gv = nDotV / (nDotV * (1.0 - k) + k);\n return gl * gv;\n}\n\nvec3 specF(float vDotH, vec3 F0) {\n float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;\n float base = 2.0;\n return F0 + (1.0 - F0) * pow(base, exponent);\n}\n\nvec4 fragment_main() {\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;\n#else\n vec4 baseColor = baseColorFactor;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n baseColor *= vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\n vec3 n = texture2D(normalTex, vTex).rgb;\n n = normalize(vTBN * (2.0 * n - 1.0));\n#else\n vec3 n = normalize(vNorm);\n#endif\n\n#ifdef FULLY_ROUGH\n float metallic = 0.0;\n#else\n float metallic = metallicRoughnessFactor.x;\n#endif\n\n float roughness = metallicRoughnessFactor.y;\n\n#ifdef USE_METAL_ROUGH_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);\n metallic *= metallicRoughness.b;\n roughness *= metallicRoughness.g;\n#endif\n \n vec3 l = normalize(vLight);\n vec3 v = normalize(vView);\n vec3 h = normalize(l+v);\n\n float nDotL = clamp(dot(n, l), 0.001, 1.0);\n float nDotV = abs(dot(n, v)) + 0.001;\n float nDotH = max(dot(n, h), 0.0);\n float vDotH = max(dot(v, h), 0.0);\n\n // From GLTF Spec\n vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color\n vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color\n float a = roughness * roughness;\n\n#ifdef FULLY_ROUGH\n vec3 specular = F0 * 0.45;\n#else\n vec3 F = specF(vDotH, F0);\n float D = specD(a, nDotH);\n float G = specG(roughness, nDotL, nDotV);\n vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);\n#endif\n float halfLambert = dot(n, l) * 0.5 + 0.5;\n halfLambert *= halfLambert;\n\n vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;\n\n#ifdef USE_OCCLUSION\n float occlusion = texture2D(occlusionTex, vTex).r;\n color = mix(color, color * occlusion, occlusionStrength);\n#endif\n \n vec3 emissive = emissiveFactor;\n#ifdef USE_EMISSIVE_TEXTURE\n emissive *= texture2D(emissiveTex, vTex).rgb;\n#endif\n color += emissive;\n\n // gamma correction\n //color = pow(color, vec3(1.0/2.2));\n\n return vec4(color, baseColor.a);\n}"}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=r(2);Object.defineProperty(e,"Node",{enumerable:!0,get:function(){return n.Node}});var i=r(11);Object.defineProperty(e,"Renderer",{enumerable:!0,get:function(){return i.Renderer}}),Object.defineProperty(e,"createWebGLContext",{enumerable:!0,get:function(){return i.createWebGLContext}});var o=r(8);Object.defineProperty(e,"UrlTexture",{enumerable:!0,get:function(){return o.UrlTexture}});var a=r(9);Object.defineProperty(e,"PrimitiveStream",{enumerable:!0,get:function(){return a.PrimitiveStream}});var u=r(13);Object.defineProperty(e,"BoxBuilder",{enumerable:!0,get:function(){return u.BoxBuilder}});var s=r(14);Object.defineProperty(e,"PbrMaterial",{enumerable:!0,get:function(){return s.PbrMaterial}});var c=r(6);Object.defineProperty(e,"mat4",{enumerable:!0,get:function(){return c.mat4}}),Object.defineProperty(e,"mat3",{enumerable:!0,get:function(){return c.mat3}}),Object.defineProperty(e,"vec3",{enumerable:!0,get:function(){return c.vec3}}),Object.defineProperty(e,"vec4",{enumerable:!0,get:function(){return c.vec4}}),Object.defineProperty(e,"quat",{enumerable:!0,get:function(){return c.quat}});var f=r(22);Object.defineProperty(e,"BoundsRenderer",{enumerable:!0,get:function(){return f.BoundsRenderer}});var l=r(23);Object.defineProperty(e,"ButtonNode",{enumerable:!0,get:function(){return l.ButtonNode}});var h=r(24);Object.defineProperty(e,"DropShadowNode",{enumerable:!0,get:function(){return h.DropShadowNode}});var d=r(25);Object.defineProperty(e,"CubeSeaNode",{enumerable:!0,get:function(){return d.CubeSeaNode}});var v=r(26);Object.defineProperty(e,"Gltf2Node",{enumerable:!0,get:function(){return v.Gltf2Node}});var _=r(28);Object.defineProperty(e,"SkyboxNode",{enumerable:!0,get:function(){return _.SkyboxNode}});var m=r(29);Object.defineProperty(e,"VideoNode",{enumerable:!0,get:function(){return m.VideoNode}});var p=r(30);Object.defineProperty(e,"WebXRView",{enumerable:!0,get:function(){return p.WebXRView}}),Object.defineProperty(e,"Scene",{enumerable:!0,get:function(){return p.Scene}});var y=r(34);Object.defineProperty(e,"FallbackHelper",{enumerable:!0,get:function(){return y.FallbackHelper}});var b=r(35);Object.defineProperty(e,"QueryArgs",{enumerable:!0,get:function(){return b.QueryArgs}})},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Ray=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);var o=i.mat3.create();e.Ray=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.origin=i.vec3.create(),this._dir=i.vec3.create(),this._dir[2]=-1,e&&(i.vec3.transformMat4(this.origin,this.origin,e),i.mat3.fromMat4(o,e),i.vec3.transformMat3(this._dir,this._dir,o)),this.dir=this._dir}return n(t,[{key:"intersectsAABB",value:function(t,e){var r=this,n=[t,e],o=(n[r.sign[0]][0]-r.origin[0])*r.inv_dir[0],a=(n[1-r.sign[0]][0]-r.origin[0])*r.inv_dir[0],u=(n[r.sign[1]][1]-r.origin[1])*r.inv_dir[1],s=(n[1-r.sign[1]][1]-r.origin[1])*r.inv_dir[1];if(o>s||u>a)return null;u>o&&(o=u),s<a&&(a=s);var c=(n[r.sign[2]][2]-r.origin[2])*r.inv_dir[2],f=(n[1-r.sign[2]][2]-r.origin[2])*r.inv_dir[2];if(o>f||c>a)return null;c>o&&(o=c),f<a&&(a=f);var l=-1;if(o>0&&a>0)l=Math.min(o,a);else if(o>0)l=o;else{if(!(a>0))return null;l=a}l-=.02;var h=i.vec3.clone(this._dir);return i.vec3.scale(h,h,l),i.vec3.add(h,h,this.origin),h}},{key:"dir",get:function(){return this._dir},set:function(t){this._dir=i.vec3.copy(this._dir,t),i.vec3.normalize(this._dir,this._dir),this.inv_dir=i.vec3.fromValues(1/this._dir[0],1/this._dir[1],1/this._dir[2]),this.sign=[this.inv_dir[0]<0?1:0,this.inv_dir[1]<0?1:0,this.inv_dir[2]<0?1:0]}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"identity",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"transpose",function(){return f}),r.d(e,"invert",function(){return l}),r.d(e,"adjoint",function(){return h}),r.d(e,"determinant",function(){return d}),r.d(e,"multiply",function(){return v}),r.d(e,"rotate",function(){return _}),r.d(e,"scale",function(){return m}),r.d(e,"fromRotation",function(){return p}),r.d(e,"fromScaling",function(){return y}),r.d(e,"str",function(){return b}),r.d(e,"frob",function(){return g}),r.d(e,"LDU",function(){return M}),r.d(e,"add",function(){return x}),r.d(e,"subtract",function(){return T}),r.d(e,"exactEquals",function(){return E}),r.d(e,"equals",function(){return w}),r.d(e,"multiplyScalar",function(){return O}),r.d(e,"multiplyScalarAndAdd",function(){return R}),r.d(e,"mul",function(){return P}),r.d(e,"sub",function(){return S});var n=r(0);function i(){let t=new n.ARRAY_TYPE(4);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t}function o(t){let e=new n.ARRAY_TYPE(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}function u(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t}function s(t,e,r,i){let o=new n.ARRAY_TYPE(4);return o[0]=t,o[1]=e,o[2]=r,o[3]=i,o}function c(t,e,r,n,i){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t}function f(t,e){if(t===e){let r=e[1];t[1]=e[2],t[2]=r}else t[0]=e[0],t[1]=e[2],t[2]=e[1],t[3]=e[3];return t}function l(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*o-i*n;return a?(a=1/a,t[0]=o*a,t[1]=-n*a,t[2]=-i*a,t[3]=r*a,t):null}function h(t,e){let r=e[0];return t[0]=e[3],t[1]=-e[1],t[2]=-e[2],t[3]=r,t}function d(t){return t[0]*t[3]-t[2]*t[1]}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*u+o*s,t[1]=i*u+a*s,t[2]=n*c+o*f,t[3]=i*c+a*f,t}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+o*u,t[1]=i*s+a*u,t[2]=n*-u+o*s,t[3]=i*-u+a*s,t}function m(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1];return t[0]=n*u,t[1]=i*u,t[2]=o*s,t[3]=a*s,t}function p(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=-r,t[3]=n,t}function y(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=e[1],t}function b(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function g(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2))}function M(t,e,r,n){return t[2]=n[2]/n[0],r[0]=n[0],r[1]=n[1],r[3]=n[3]-t[2]*r[1],[t,e,r]}function x(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t}function T(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t}function E(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]}function w(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=e[0],s=e[1],c=e[2],f=e[3];return Math.abs(r-u)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(u))&&Math.abs(i-s)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(o-c)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(c))&&Math.abs(a-f)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(f))}function O(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t}function R(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t}const P=v,S=T},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"identity",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"invert",function(){return f}),r.d(e,"determinant",function(){return l}),r.d(e,"multiply",function(){return h}),r.d(e,"rotate",function(){return d}),r.d(e,"scale",function(){return v}),r.d(e,"translate",function(){return _}),r.d(e,"fromRotation",function(){return m}),r.d(e,"fromScaling",function(){return p}),r.d(e,"fromTranslation",function(){return y}),r.d(e,"str",function(){return b}),r.d(e,"frob",function(){return g}),r.d(e,"add",function(){return M}),r.d(e,"subtract",function(){return x}),r.d(e,"multiplyScalar",function(){return T}),r.d(e,"multiplyScalarAndAdd",function(){return E}),r.d(e,"exactEquals",function(){return w}),r.d(e,"equals",function(){return O}),r.d(e,"mul",function(){return R}),r.d(e,"sub",function(){return P});var n=r(0);function i(){let t=new n.ARRAY_TYPE(6);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t}function o(t){let e=new n.ARRAY_TYPE(6);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}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function u(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function s(t,e,r,i,o,a){let u=new n.ARRAY_TYPE(6);return u[0]=t,u[1]=e,u[2]=r,u[3]=i,u[4]=o,u[5]=a,u}function c(t,e,r,n,i,o,a){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t}function f(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=r*o-n*i;return s?(s=1/s,t[0]=o*s,t[1]=-n*s,t[2]=-i*s,t[3]=r*s,t[4]=(i*u-o*a)*s,t[5]=(n*a-r*u)*s,t):null}function l(t){return t[0]*t[3]-t[1]*t[2]}function h(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1],l=r[2],h=r[3],d=r[4],v=r[5];return t[0]=n*c+o*f,t[1]=i*c+a*f,t[2]=n*l+o*h,t[3]=i*l+a*h,t[4]=n*d+o*v+u,t[5]=i*d+a*v+s,t}function d(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=Math.sin(r),f=Math.cos(r);return t[0]=n*f+o*c,t[1]=i*f+a*c,t[2]=n*-c+o*f,t[3]=i*-c+a*f,t[4]=u,t[5]=s,t}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1];return t[0]=n*c,t[1]=i*c,t[2]=o*f,t[3]=a*f,t[4]=u,t[5]=s,t}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=n*c+o*f+u,t[5]=i*c+a*f+s,t}function m(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=-r,t[3]=n,t[4]=0,t[5]=0,t}function p(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=e[1],t[4]=0,t[5]=0,t}function y(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=e[0],t[5]=e[1],t}function b(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"}function g(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+1)}function M(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t}function x(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t}function T(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t}function E(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t}function w(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]}function O(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=e[0],f=e[1],l=e[2],h=e[3],d=e[4],v=e[5];return Math.abs(r-c)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(c))&&Math.abs(i-f)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(f))&&Math.abs(o-l)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(l))&&Math.abs(a-h)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(h))&&Math.abs(u-d)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(d))&&Math.abs(s-v)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(v))}const R=h,P=x},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return a}),r.d(e,"clone",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"fromRotationTranslationValues",function(){return c}),r.d(e,"fromRotationTranslation",function(){return f}),r.d(e,"fromTranslation",function(){return l}),r.d(e,"fromRotation",function(){return h}),r.d(e,"fromMat4",function(){return d}),r.d(e,"copy",function(){return v}),r.d(e,"identity",function(){return _}),r.d(e,"set",function(){return m}),r.d(e,"getReal",function(){return p}),r.d(e,"getDual",function(){return y}),r.d(e,"setReal",function(){return b}),r.d(e,"setDual",function(){return g}),r.d(e,"getTranslation",function(){return M}),r.d(e,"translate",function(){return x}),r.d(e,"rotateX",function(){return T}),r.d(e,"rotateY",function(){return E}),r.d(e,"rotateZ",function(){return w}),r.d(e,"rotateByQuatAppend",function(){return O}),r.d(e,"rotateByQuatPrepend",function(){return R}),r.d(e,"rotateAroundAxis",function(){return P}),r.d(e,"add",function(){return S}),r.d(e,"multiply",function(){return A}),r.d(e,"mul",function(){return N}),r.d(e,"scale",function(){return C}),r.d(e,"dot",function(){return I}),r.d(e,"lerp",function(){return L}),r.d(e,"invert",function(){return k}),r.d(e,"conjugate",function(){return F}),r.d(e,"length",function(){return D}),r.d(e,"len",function(){return j}),r.d(e,"squaredLength",function(){return B}),r.d(e,"sqrLen",function(){return U}),r.d(e,"normalize",function(){return V}),r.d(e,"str",function(){return Y}),r.d(e,"exactEquals",function(){return G}),r.d(e,"equals",function(){return q});var n=r(0),i=r(4),o=r(10);function a(){let t=new n.ARRAY_TYPE(8);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t}function u(t){let e=new n.ARRAY_TYPE(8);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}function s(t,e,r,i,o,a,u,s){let c=new n.ARRAY_TYPE(8);return c[0]=t,c[1]=e,c[2]=r,c[3]=i,c[4]=o,c[5]=a,c[6]=u,c[7]=s,c}function c(t,e,r,i,o,a,u){let s=new n.ARRAY_TYPE(8);s[0]=t,s[1]=e,s[2]=r,s[3]=i;let c=.5*o,f=.5*a,l=.5*u;return s[4]=c*i+f*r-l*e,s[5]=f*i+l*t-c*r,s[6]=l*i+c*e-f*t,s[7]=-c*t-f*e-l*r,s}function f(t,e,r){let n=.5*r[0],i=.5*r[1],o=.5*r[2],a=e[0],u=e[1],s=e[2],c=e[3];return t[0]=a,t[1]=u,t[2]=s,t[3]=c,t[4]=n*c+i*s-o*u,t[5]=i*c+o*a-n*s,t[6]=o*c+n*u-i*a,t[7]=-n*a-i*u-o*s,t}function l(t,e){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*e[0],t[5]=.5*e[1],t[6]=.5*e[2],t[7]=0,t}function h(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function d(t,e){let r=i.create();o.getRotation(r,e);let a=new n.ARRAY_TYPE(3);return o.getTranslation(a,e),f(t,r,a),t}function v(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t}function _(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function m(t,e,r,n,i,o,a,u,s){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t}const p=i.copy;function y(t,e){return t[0]=e[4],t[1]=e[5],t[2]=e[6],t[3]=e[7],t}const b=i.copy;function g(t,e){return t[4]=e[0],t[5]=e[1],t[6]=e[2],t[7]=e[3],t}function M(t,e){let r=e[4],n=e[5],i=e[6],o=e[7],a=-e[0],u=-e[1],s=-e[2],c=e[3];return t[0]=2*(r*c+o*a+n*s-i*u),t[1]=2*(n*c+o*u+i*a-r*s),t[2]=2*(i*c+o*s+r*u-n*a),t}function x(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=.5*r[0],s=.5*r[1],c=.5*r[2],f=e[4],l=e[5],h=e[6],d=e[7];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=a*u+i*c-o*s+f,t[5]=a*s+o*u-n*c+l,t[6]=a*c+n*s-i*u+h,t[7]=-n*u-i*s-o*c+d,t}function T(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateX(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function E(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateY(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function w(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateZ(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function O(t,e,r){let n=r[0],i=r[1],o=r[2],a=r[3],u=e[0],s=e[1],c=e[2],f=e[3];return t[0]=u*a+f*n+s*o-c*i,t[1]=s*a+f*i+c*n-u*o,t[2]=c*a+f*o+u*i-s*n,t[3]=f*a-u*n-s*i-c*o,u=e[4],s=e[5],c=e[6],f=e[7],t[4]=u*a+f*n+s*o-c*i,t[5]=s*a+f*i+c*n-u*o,t[6]=c*a+f*o+u*i-s*n,t[7]=f*a-u*n-s*i-c*o,t}function R(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*f+a*u+i*c-o*s,t[1]=i*f+a*s+o*u-n*c,t[2]=o*f+a*c+n*s-i*u,t[3]=a*f-n*u-i*s-o*c,u=r[4],s=r[5],c=r[6],f=r[7],t[4]=n*f+a*u+i*c-o*s,t[5]=i*f+a*s+o*u-n*c,t[6]=o*f+a*c+n*s-i*u,t[7]=a*f-n*u-i*s-o*c,t}function P(t,e,r,i){if(Math.abs(i)<n.EPSILON)return v(t,e);let o=Math.sqrt(r[0]*r[0]+r[1]*r[1]+r[2]*r[2]);i*=.5;let a=Math.sin(i),u=a*r[0]/o,s=a*r[1]/o,c=a*r[2]/o,f=Math.cos(i),l=e[0],h=e[1],d=e[2],_=e[3];t[0]=l*f+_*u+h*c-d*s,t[1]=h*f+_*s+d*u-l*c,t[2]=d*f+_*c+l*s-h*u,t[3]=_*f-l*u-h*s-d*c;let m=e[4],p=e[5],y=e[6],b=e[7];return t[4]=m*f+b*u+p*c-y*s,t[5]=p*f+b*s+y*u-m*c,t[6]=y*f+b*c+m*s-p*u,t[7]=b*f-m*u-p*s-y*c,t}function S(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t}function A(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[4],s=r[5],c=r[6],f=r[7],l=e[4],h=e[5],d=e[6],v=e[7],_=r[0],m=r[1],p=r[2],y=r[3];return t[0]=n*y+a*_+i*p-o*m,t[1]=i*y+a*m+o*_-n*p,t[2]=o*y+a*p+n*m-i*_,t[3]=a*y-n*_-i*m-o*p,t[4]=n*f+a*u+i*c-o*s+l*y+v*_+h*p-d*m,t[5]=i*f+a*s+o*u-n*c+h*y+v*m+d*_-l*p,t[6]=o*f+a*c+n*s-i*u+d*y+v*p+l*m-h*_,t[7]=a*f-n*u-i*s-o*c+v*y-l*_-h*m-d*p,t}const N=A;function C(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t}const I=i.dot;function L(t,e,r,n){let i=1-n;return I(e,r)<0&&(n=-n),t[0]=e[0]*i+r[0]*n,t[1]=e[1]*i+r[1]*n,t[2]=e[2]*i+r[2]*n,t[3]=e[3]*i+r[3]*n,t[4]=e[4]*i+r[4]*n,t[5]=e[5]*i+r[5]*n,t[6]=e[6]*i+r[6]*n,t[7]=e[7]*i+r[7]*n,t}function k(t,e){let r=B(e);return t[0]=-e[0]/r,t[1]=-e[1]/r,t[2]=-e[2]/r,t[3]=e[3]/r,t[4]=-e[4]/r,t[5]=-e[5]/r,t[6]=-e[6]/r,t[7]=e[7]/r,t}function F(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t[4]=-e[4],t[5]=-e[5],t[6]=-e[6],t[7]=e[7],t}const D=i.length,j=D,B=i.squaredLength,U=B;function V(t,e){let r=B(e);if(r>0){r=Math.sqrt(r);let n=e[0]/r,i=e[1]/r,o=e[2]/r,a=e[3]/r,u=e[4],s=e[5],c=e[6],f=e[7],l=n*u+i*s+o*c+a*f;t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=(u-n*l)/r,t[5]=(s-i*l)/r,t[6]=(c-o*l)/r,t[7]=(f-a*l)/r}return t}function Y(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"}function G(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]}function q(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=e[0],h=e[1],d=e[2],v=e[3],_=e[4],m=e[5],p=e[6],y=e[7];return Math.abs(r-l)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(l))&&Math.abs(i-h)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(h))&&Math.abs(o-d)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(d))&&Math.abs(a-v)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(v))&&Math.abs(u-_)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(_))&&Math.abs(s-m)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(m))&&Math.abs(c-p)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(p))&&Math.abs(f-y)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(y))}},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"fromValues",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"add",function(){return c}),r.d(e,"subtract",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"divide",function(){return h}),r.d(e,"ceil",function(){return d}),r.d(e,"floor",function(){return v}),r.d(e,"min",function(){return _}),r.d(e,"max",function(){return m}),r.d(e,"round",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"scaleAndAdd",function(){return b}),r.d(e,"distance",function(){return g}),r.d(e,"squaredDistance",function(){return M}),r.d(e,"length",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return E}),r.d(e,"inverse",function(){return w}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"cross",function(){return P}),r.d(e,"lerp",function(){return S}),r.d(e,"random",function(){return A}),r.d(e,"transformMat2",function(){return N}),r.d(e,"transformMat2d",function(){return C}),r.d(e,"transformMat3",function(){return I}),r.d(e,"transformMat4",function(){return L}),r.d(e,"rotate",function(){return k}),r.d(e,"angle",function(){return F}),r.d(e,"str",function(){return D}),r.d(e,"exactEquals",function(){return j}),r.d(e,"equals",function(){return B}),r.d(e,"len",function(){return U}),r.d(e,"sub",function(){return V}),r.d(e,"mul",function(){return Y}),r.d(e,"div",function(){return G}),r.d(e,"dist",function(){return q}),r.d(e,"sqrDist",function(){return H}),r.d(e,"sqrLen",function(){return X}),r.d(e,"forEach",function(){return W});var n=r(0);function i(){let t=new n.ARRAY_TYPE(2);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0),t}function o(t){let e=new n.ARRAY_TYPE(2);return e[0]=t[0],e[1]=t[1],e}function a(t,e){let r=new n.ARRAY_TYPE(2);return r[0]=t,r[1]=e,r}function u(t,e){return t[0]=e[0],t[1]=e[1],t}function s(t,e,r){return t[0]=e,t[1]=r,t}function c(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t}function f(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t}function l(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t}function h(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t}function d(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t}function v(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t}function _(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t}function m(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t}function p(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t}function y(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t}function b(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t}function g(t,e){var r=e[0]-t[0],n=e[1]-t[1];return Math.sqrt(r*r+n*n)}function M(t,e){var r=e[0]-t[0],n=e[1]-t[1];return r*r+n*n}function x(t){var e=t[0],r=t[1];return Math.sqrt(e*e+r*r)}function T(t){var e=t[0],r=t[1];return e*e+r*r}function E(t,e){return t[0]=-e[0],t[1]=-e[1],t}function w(t,e){return t[0]=1/e[0],t[1]=1/e[1],t}function O(t,e){var r=e[0],n=e[1],i=r*r+n*n;return i>0&&(i=1/Math.sqrt(i),t[0]=e[0]*i,t[1]=e[1]*i),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]}function P(t,e,r){var n=e[0]*r[1]-e[1]*r[0];return t[0]=t[1]=0,t[2]=n,t}function S(t,e,r,n){var i=e[0],o=e[1];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t}function A(t,e){e=e||1;var r=2*n.RANDOM()*Math.PI;return t[0]=Math.cos(r)*e,t[1]=Math.sin(r)*e,t}function N(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[2]*i,t[1]=r[1]*n+r[3]*i,t}function C(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[2]*i+r[4],t[1]=r[1]*n+r[3]*i+r[5],t}function I(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[3]*i+r[6],t[1]=r[1]*n+r[4]*i+r[7],t}function L(t,e,r){let n=e[0],i=e[1];return t[0]=r[0]*n+r[4]*i+r[12],t[1]=r[1]*n+r[5]*i+r[13],t}function k(t,e,r,n){let i=e[0]-r[0],o=e[1]-r[1],a=Math.sin(n),u=Math.cos(n);return t[0]=i*u-o*a+r[0],t[1]=i*a+o*u+r[1],t}function F(t,e){let r=t[0],n=t[1],i=e[0],o=e[1],a=r*r+n*n;a>0&&(a=1/Math.sqrt(a));let u=i*i+o*o;u>0&&(u=1/Math.sqrt(u));let s=(r*i+n*o)*a*u;return s>1?0:s<-1?Math.PI:Math.acos(s)}function D(t){return"vec2("+t[0]+", "+t[1]+")"}function j(t,e){return t[0]===e[0]&&t[1]===e[1]}function B(t,e){let r=t[0],i=t[1],o=e[0],a=e[1];return Math.abs(r-o)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(i-a)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(a))}const U=x,V=f,Y=l,G=h,q=g,H=M,X=T,W=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=2),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],o(t,t,a),e[u]=t[0],e[u+1]=t[1];return e}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.Program=function(){function t(e,r,n,i,o){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this._gl=e,this.program=e.createProgram(),this.attrib=null,this.uniform=null,this.defines={},this._firstUse=!0,this._nextUseCallbacks=[];var a="";if(o)for(var u in o)this.defines[u]=o[u],a+="#define "+u+" "+o[u]+"\n";if(this._vertShader=e.createShader(e.VERTEX_SHADER),e.attachShader(this.program,this._vertShader),e.shaderSource(this._vertShader,a+r),e.compileShader(this._vertShader),this._fragShader=e.createShader(e.FRAGMENT_SHADER),e.attachShader(this.program,this._fragShader),e.shaderSource(this._fragShader,a+n),e.compileShader(this._fragShader),i)for(var s in this.attrib={},i)e.bindAttribLocation(this.program,i[s],s),this.attrib[s]=i[s];e.linkProgram(this.program)}return n(t,[{key:"onNextUse",value:function(t){this._nextUseCallbacks.push(t)}},{key:"use",value:function(){var t=this._gl;if(this._firstUse){if(this._firstUse=!1,t.getProgramParameter(this.program,t.LINK_STATUS)){if(!this.attrib){this.attrib={};for(var e=t.getProgramParameter(this.program,t.ACTIVE_ATTRIBUTES),r=0;r<e;r++){var n=t.getActiveAttrib(this.program,r);this.attrib[n.name]=t.getAttribLocation(this.program,n.name)}}this.uniform={};for(var i=t.getProgramParameter(this.program,t.ACTIVE_UNIFORMS),o="",a=0;a<i;a++){o=t.getActiveUniform(this.program,a).name.replace("[0]",""),this.uniform[o]=t.getUniformLocation(this.program,o)}}else t.getShaderParameter(this._vertShader,t.COMPILE_STATUS)?t.getShaderParameter(this._fragShader,t.COMPILE_STATUS)?console.error("Program link error: "+t.getProgramInfoLog(this.program)):console.error("Fragment shader compile error: "+t.getShaderInfoLog(this._fragShader)):console.error("Vertex shader compile error: "+t.getShaderInfoLog(this._vertShader)),t.deleteProgram(this.program),this.program=null;t.deleteShader(this._vertShader),t.deleteShader(this._fragShader)}if(t.useProgram(this.program),this._nextUseCallbacks.length){var u=!0,s=!1,c=void 0;try{for(var f,l=this._nextUseCallbacks[Symbol.iterator]();!(u=(f=l.next()).done);u=!0){(0,f.value)(this)}}catch(t){s=!0,c=t}finally{try{!u&&l.return&&l.return()}finally{if(s)throw c}}this._nextUseCallbacks=[]}}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BoundsRenderer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=WebGLRenderingContext,l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.state.blendFuncSrc=f.SRC_ALPHA,t.state.blendFuncDst=f.ONE,t.state.depthTest=!1,t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BOUNDS_RENDERER"}},{key:"vertexSource",get:function(){return"\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n\n vec4 fragment_main() {\n return vec4(0.0, 1.0, 0.0, 0.3);\n }"}}]),e}();e.BoundsRenderer=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._stageBounds=null,t}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.stageBounds=this._stageBounds}},{key:"stageBounds",get:function(){return this._stageBounds},set:function(t){if(this._stageBounds&&this.clearRenderPrimitives(),this._stageBounds=t,t&&0!==t.length&&this._renderer){for(var e=[],r=[],n=t.geometry.length,i=0;i<n;i++){var o=t.geometry[i];e.push(o.x,0,o.z),r.push(i,0===i?n-1:i-1,n)}e.push(0,0,0);var u=this._renderer.createRenderBuffer(f.ARRAY_BUFFER,new Float32Array(e)),s=this._renderer.createRenderBuffer(f.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),c=[new a.PrimitiveAttribute("POSITION",u,3,f.FLOAT,12,0)],h=new a.Primitive(c,r.length);h.setIndexBuffer(s);var d=this._renderer.createRenderPrimitive(h,new l);this.addRenderPrimitive(d)}}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.ButtonNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(9);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.defineUniform("hoverAmount",0),t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BUTTON_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n\n uniform float hoverAmount;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n float scale = mix(1.0, 1.1, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform float hoverAmount;\n\n const vec4 default_color = vec4(0.75, 0.75, 0.75, 0.85);\n const vec4 hover_color = vec4(0.9, 0.9,\n 0.9, 1);\n\n vec4 fragment_main() {\n return mix(default_color, hover_color, hoverAmount);\n }"}}]),e}(),l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.defineUniform("hoverAmount",0),t.icon=t.defineSampler("icon"),t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BUTTON_ICON_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n uniform float hoverAmount;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n float scale = mix(1.0, 1.1, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D icon;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(icon, vTexCoord);\n }"}}]),e}();e.ButtonNode=function(t){function e(t,r){u(this,e);var n=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return n.selectable=!0,n._selectHandler=r,n._iconTexture=t,n._hovered=!1,n._hoverT=0,n}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=new a.PrimitiveStream,r=.0025,n=.05,i=n-.025;e.startGeometry();for(var o=0;o<32;++o){var u=o*(2*Math.PI/32),s=.025*Math.cos(u),c=.025*Math.sin(u);switch(Math.floor(o/8)){case 0:s+=i,c+=i;break;case 1:s-=i,c+=i;break;case 2:s-=i,c-=i;break;case 3:s+=i,c-=i}e.pushVertex(s,c,-r,0,0,0,0,1),o>1&&e.pushTriangle(0,o-1,o)}e.endGeometry();var h=e.finishPrimitive(t);this._buttonRenderPrimitive=t.createRenderPrimitive(h,new f),this.addRenderPrimitive(this._buttonRenderPrimitive),n=.035,e.clear(),e.startGeometry(),e.pushVertex(-n,n,r,0,0,0,0,1),e.pushVertex(-n,-n,r,0,1,0,0,1),e.pushVertex(n,-n,r,1,1,0,0,1),e.pushVertex(n,n,r,1,0,0,0,1),e.pushTriangle(0,1,2),e.pushTriangle(0,2,3),e.endGeometry();var d=e.finishPrimitive(t),v=new l;v.icon.texture=this._iconTexture,this._iconRenderPrimitive=t.createRenderPrimitive(d,v),this.addRenderPrimitive(this._iconRenderPrimitive)}},{key:"onHoverStart",value:function(){this._hovered=!0}},{key:"onHoverEnd",value:function(){this._hovered=!1}},{key:"_updateHoverState",value:function(){var t=this._hoverT/200,e=t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1;this._buttonRenderPrimitive.uniforms.hoverAmount.value=e,this._iconRenderPrimitive.uniforms.hoverAmount.value=e}},{key:"onUpdate",value:function(t,e){this._hovered&&this._hoverT<200?(this._hoverT=Math.min(200,this._hoverT+e),this._updateHoverState()):!this._hovered&&this._hoverT>0&&(this._hoverT=Math.max(0,this._hoverT-e),this._updateHoverState())}},{key:"iconTexture",get:function(){return this._iconTexture},set:function(t){this._iconTexture!=t&&(this._iconTexture=t,this._iconRenderPrimitive.samplers.icon.texture=t)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.DropShadowNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(9);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=WebGLRenderingContext,l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.state.blendFuncSrc=f.ONE,t.state.blendFuncDst=f.ONE_MINUS_SRC_ALPHA,t.state.depthFunc=f.LEQUAL,t.state.depthMask=!1,t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"DROP_SHADOW_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying float vShadow;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vShadow = TEXCOORD_0.x;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n varying float vShadow;\n\n vec4 fragment_main() {\n return vec4(0.0, 0.0, 0.0, vShadow);\n }"}}]),e}();e.DropShadowNode=function(t){function e(t,r){return u(this,e),s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this))}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=new a.PrimitiveStream;e.startGeometry(),e.pushVertex(0,.01,0,.7);for(var r=2*Math.PI/32,n=void 0,i=0;i<32;++i){n=e.nextVertexIndex;var o=i*r,u=Math.cos(o),s=Math.sin(o);e.pushVertex(.6*u,.01,.6*s,.3),e.pushVertex(1*u,.01,1*s,0),i>0&&(e.pushTriangle(0,n,n-2),e.pushTriangle(n,n+1,n-1),e.pushTriangle(n,n-1,n-2))}e.pushTriangle(0,1,n),e.pushTriangle(1,2,n+1),e.pushTriangle(1,n+1,n),e.endGeometry();var c=e.finishPrimitive(t);this._shadowRenderPrimitive=t.createRenderPrimitive(c,new l),this.addRenderPrimitive(this._shadowRenderPrimitive)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.CubeSeaNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(8),u=r(13),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function f(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var h=function(t){function e(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];c(this,e);var r=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.heavy=t,r.baseColor=r.defineSampler("baseColor"),r}return l(e,i.Material),n(e,[{key:"materialName",get:function(){return"CUBE_SEA"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n attribute vec3 NORMAL;\n\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n const vec3 lightDir = vec3(0.75, 0.5, 1.0);\n const vec3 ambientColor = vec3(0.5, 0.5, 0.5);\n const vec3 lightColor = vec3(0.75, 0.75, 0.75);\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));\n float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);\n vLight = ambientColor + (lightColor * lightFactor);\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return this.heavy?"\n precision mediump float;\n\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec2 dimensions = vec2(64, 64);\n float seed = 0.42;\n\n vec2 hash( vec2 p ) {\n p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));\n return fract(sin(p)*18.5453);\n }\n\n vec3 hash3( vec2 p ) {\n vec3 q = vec3( dot(p,vec2(127.1,311.7)),\n dot(p,vec2(269.5,183.3)),\n dot(p,vec2(419.2,371.9)) );\n return fract(sin(q)*43758.5453);\n }\n\n float iqnoise( in vec2 x, float u, float v ) {\n vec2 p = floor(x);\n vec2 f = fract(x);\n float k = 1.0+63.0*pow(1.0-v,4.0);\n float va = 0.0;\n float wt = 0.0;\n for( int j=-2; j<=2; j++ )\n for( int i=-2; i<=2; i++ ) {\n vec2 g = vec2( float(i),float(j) );\n vec3 o = hash3( p + g )*vec3(u,u,1.0);\n vec2 r = g - f + o.xy;\n float d = dot(r,r);\n float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );\n va += o.z*ww;\n wt += ww;\n }\n return va/wt;\n }\n\n // return distance, and cell id\n vec2 voronoi( in vec2 x ) {\n vec2 n = floor( x );\n vec2 f = fract( x );\n vec3 m = vec3( 8.0 );\n for( int j=-1; j<=1; j++ )\n for( int i=-1; i<=1; i++ ) {\n vec2 g = vec2( float(i), float(j) );\n vec2 o = hash( n + g );\n vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));\n float d = dot( r, r );\n if( d<m.x )\n m = vec3( d, o );\n }\n return vec2( sqrt(m.x), m.y+m.z );\n }\n\n vec4 fragment_main() {\n vec2 uv = ( vTexCoord );\n uv *= vec2( 10., 10. );\n uv += seed;\n vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );\n\n vec2 c = voronoi( uv );\n vec3 col = vec3( c.y / 2. );\n\n float f = iqnoise( 1. * uv + c.y, p.x, p.y );\n col *= 1.0 + .25 * vec3( f );\n\n return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );\n }":"\n precision mediump float;\n uniform sampler2D baseColor;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec4 fragment_main() {\n return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);\n }"}}]),e}();e.CubeSeaNode=function(t){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};c(this,e);var r=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.heavyGpu=!!t.heavyGpu,r.cubeCount=t.cubeCount||(r.heavyGpu?12:10),r.cubeScale=t.cubeScale||1,r.halfOnly=!!t.halfOnly,r.autoRotate=!!t.autoRotate,r._texture=new a.UrlTexture(t.imageUrl||"media/textures/cube-sea.png"),r._material=new h(r.heavyGpu),r._material.baseColor.texture=r._texture,r._renderPrimitive=null,r}return l(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this._renderPrimitive=null;var e=new u.BoxBuilder;e.pushCube([0,.25,-.8],.1),e.pushCube([.8,.25,0],.1),e.pushCube([0,.25,.8],.1),e.pushCube([-.8,.25,0],.1);var r=e.finishPrimitive(t);return this.heroNode=t.createMesh(r,this._material),this.rebuildCubes(e),this.cubeSeaNode=new o.Node,this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive),this.addNode(this.cubeSeaNode),this.addNode(this.heroNode),this.waitForComplete()}},{key:"rebuildCubes",value:function(t){if(this._renderer){t?t.clear():t=new u.BoxBuilder;for(var e=.4*this.cubeScale,r=.5*this.cubeCount,n=0;n<this.cubeCount;++n)for(var i=0;i<this.cubeCount;++i)for(var o=0;o<this.cubeCount;++o){var a=[n-r,i-r,o-r];this.halfOnly&&a[0]<0||(0==a[0]&&0==a[1]&&0==a[2]||t.pushCube(a,e))}this.cubeCount>12&&(t.indexType=5125);var s=t.finishPrimitive(this._renderer);this._renderPrimitive?this._renderPrimitive.setPrimitive(s):this._renderPrimitive=this._renderer.createRenderPrimitive(s,this._material)}}},{key:"onUpdate",value:function(t,e){this.autoRotate&&s.mat4.fromRotation(this.cubeSeaNode.matrix,t/500,[0,-1,0]),s.mat4.fromRotation(this.heroNode.matrix,t/2e3,[0,1,0])}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Gltf2Node=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(2),o=r(27);var a=new WeakMap;e.Gltf2Node=function(t){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e);var r=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._url=t.url,r._promise=null,r._resolver=null,r._rejecter=null,r}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=this,r=a.get(t);r||(r=new o.Gltf2Loader(t),a.set(t,r)),!this._resolver&&this._promise&&(this._promise=null),this._ensurePromise(),r.loadFromUrl(this._url).then(function(t){e.addNode(t),e._resolver(t.waitForComplete()),e._resolver=null,e._rejecter=null}).catch(function(t){e._rejecter(t),e._resolver=null,e._rejecter=null})}},{key:"_ensurePromise",value:function(){var t=this;return this._promise||(this._promise=new Promise(function(e,r){t._resolver=e,t._rejecter=r})),this._promise}},{key:"waitForComplete",value:function(){return this._ensurePromise()}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Gltf2Loader=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(14),o=r(2),a=r(7),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var c=WebGLRenderingContext,f=1313821514,l=5130562;function h(t){return!!t.match(/^data:/)}function d(t,e){return function(t){var e=new RegExp("^"+window.location.protocol,"i");return!!t.match(e)}(t)||h(t)?t:e+t}function v(t){switch(t){case"SCALAR":return 1;case"VEC2":return 2;case"VEC3":return 3;case"VEC4":return 4;default:return 0}}e.Gltf2Loader=function(){function t(e){s(this,t),this.renderer=e,this._gl=e._gl}return n(t,[{key:"loadFromUrl",value:function(t){var e=this;return fetch(t).then(function(r){var n=t.lastIndexOf("/"),i=0!==n?t.substring(0,n+1):"";if(t.endsWith(".gltf"))return r.json().then(function(t){return e.loadFromJson(t,i)});if(t.endsWith(".glb"))return r.arrayBuffer().then(function(t){return e.loadFromBinary(t,i)});throw new Error("Unrecognized file extension")})}},{key:"loadFromBinary",value:function(t,e){var r=new DataView(t,0,12),n=r.getUint32(0,!0),i=r.getUint32(4,!0),o=r.getUint32(8,!0);if(1179937895!=n)throw new Error("Invalid magic string in binary header.");if(2!=i)throw new Error("Incompatible version in binary header.");for(var a={},u=12;u<o;){var s=new DataView(t,u,8),c=s.getUint32(0,!0);a[s.getUint32(4,!0)]=t.slice(u+8,u+8+c),u+=c+8}if(!a[f])throw new Error("File contained no json chunk.");var h=new TextDecoder("utf-8").decode(a[f]),d=JSON.parse(h);return this.loadFromJson(d,e,a[l])}},{key:"loadFromJson",value:function(t,e,r){if(!t.asset)throw new Error("Missing asset description.");if("2.0"!=t.asset.minVersion&&"2.0"!=t.asset.version)throw new Error("Incompatible asset version.");var n=[];if(r)n[0]=new p({},e,r);else{var s=!0,f=!1,l=void 0;try{for(var h,d=t.buffers[Symbol.iterator]();!(s=(h=d.next()).done);s=!0){var y=h.value;n.push(new p(y,e))}}catch(t){f=!0,l=t}finally{try{!s&&d.return&&d.return()}finally{if(f)throw l}}}var b=[],g=!0,M=!1,x=void 0;try{for(var T,E=t.bufferViews[Symbol.iterator]();!(g=(T=E.next()).done);g=!0){var w=T.value;b.push(new m(w,n))}}catch(t){M=!0,x=t}finally{try{!g&&E.return&&E.return()}finally{if(M)throw x}}var O=[];if(t.images){var R=!0,P=!1,S=void 0;try{for(var A,N=t.images[Symbol.iterator]();!(R=(A=N.next()).done);R=!0){var C=A.value;O.push(new p(C,e))}}catch(t){P=!0,S=t}finally{try{!R&&N.return&&N.return()}finally{if(P)throw S}}}var I=[];if(t.textures){var L=!0,k=!1,F=void 0;try{for(var D,j=t.textures[Symbol.iterator]();!(L=(D=j.next()).done);L=!0){var B=D.value,U=O[B.source].texture(b);if(B.sampler){var V=V[B.sampler];U.sampler.minFilter=V.minFilter,U.sampler.magFilter=V.magFilter,U.sampler.wrapS=V.wrapS,U.sampler.wrapT=V.wrapT}I.push(U)}}catch(t){k=!0,F=t}finally{try{!L&&j.return&&j.return()}finally{if(k)throw F}}}function Y(t){return t?I[t.index]:null}var G=[];if(t.materials){var q=!0,H=!1,X=void 0;try{for(var W,K=t.materials[Symbol.iterator]();!(q=(W=K.next()).done);q=!0){var z=W.value,Q=new i.PbrMaterial,J=z.pbrMetallicRoughness||{};switch(Q.baseColorFactor.value=J.baseColorFactor||[1,1,1,1],Q.baseColor.texture=Y(J.baseColorTexture),Q.metallicRoughnessFactor.value=[J.metallicFactor||1,J.roughnessFactor||1],Q.metallicRoughness.texture=Y(J.metallicRoughnessTexture),Q.normal.texture=Y(t.normalTexture),Q.occlusion.texture=Y(t.occlusionTexture),Q.occlusionStrength.value=t.occlusionTexture&&t.occlusionTexture.strength?t.occlusionTexture.strength:1,Q.emissiveFactor.value=z.emissiveFactor||[0,0,0],Q.emissive.texture=Y(t.emissiveTexture),!Q.emissive.texture&&t.emissiveFactor&&(Q.emissive.texture=new u.ColorTexture(1,1,1,1)),z.alphaMode){case"BLEND":case"MASK":Q.state.blend=!0;break;default:Q.state.blend=!1}Q.state.cullFace=!z.doubleSided,G.push(Q)}}catch(t){H=!0,X=t}finally{try{!q&&K.return&&K.return()}finally{if(H)throw X}}}var Z=t.accessors,$=[],tt=!0,et=!1,rt=void 0;try{for(var nt,it=t.meshes[Symbol.iterator]();!(tt=(nt=it.next()).done);tt=!0){var ot=nt.value,at=new _;$.push(at);var ut=!0,st=!1,ct=void 0;try{for(var ft,lt=ot.primitives[Symbol.iterator]();!(ut=(ft=lt.next()).done);ut=!0){var ht=ft.value,dt=null;dt="material"in ht?G[ht.material]:new i.PbrMaterial;var vt=[],_t=0,mt=null,pt=null;for(var yt in ht.attributes){var bt=Z[ht.attributes[yt]],gt=b[bt.bufferView];_t=bt.count;var Mt=new a.PrimitiveAttribute(yt,gt.renderBuffer(this.renderer,c.ARRAY_BUFFER),v(bt.type),bt.componentType,gt.byteStride||0,bt.byteOffset||0);Mt.normalized=bt.normalized||!1,"POSITION"==yt&&(mt=bt.min,pt=bt.max),vt.push(Mt)}var xt=new a.Primitive(vt,_t,ht.mode);if("indices"in ht){var Tt=Z[ht.indices],Et=b[Tt.bufferView];xt.setIndexBuffer(Et.renderBuffer(this.renderer,c.ELEMENT_ARRAY_BUFFER),Tt.byteOffset||0,Tt.componentType),xt.indexType=Tt.componentType,xt.indexByteOffset=Tt.byteOffset||0,xt.elementCount=Tt.count}mt&&pt&&xt.setBounds(mt,pt),at.primitives.push(this.renderer.createRenderPrimitive(xt,dt))}}catch(t){st=!0,ct=t}finally{try{!ut&&lt.return&&lt.return()}finally{if(st)throw ct}}}}catch(t){et=!0,rt=t}finally{try{!tt&&it.return&&it.return()}finally{if(et)throw rt}}var wt=new o.Node,Ot=t.scenes[t.scene],Rt=!0,Pt=!1,St=void 0;try{for(var At,Nt=Ot.nodes[Symbol.iterator]();!(Rt=(At=Nt.next()).done);Rt=!0){var Ct=At.value,It=t.nodes[Ct];wt.addNode(this.processNodes(It,t.nodes,$))}}catch(t){Pt=!0,St=t}finally{try{!Rt&&Nt.return&&Nt.return()}finally{if(Pt)throw St}}return wt}},{key:"processNodes",value:function(t,e,r){var n=new o.Node;if(n.name=t.name,"mesh"in t){var i=r[t.mesh],a=!0,u=!1,s=void 0;try{for(var c,f=i.primitives[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;n.addRenderPrimitive(l)}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}if(t.matrix?n.matrix=new Float32Array(t.matrix):(t.translation||t.rotation||t.scale)&&(t.translation&&(n.translation=new Float32Array(t.translation)),t.rotation&&(n.rotation=new Float32Array(t.rotation)),t.scale&&(n.scale=new Float32Array(t.scale))),t.children){var h=!0,d=!1,v=void 0;try{for(var _,m=t.children[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=e[_.value];n.addNode(this.processNodes(p,e,r))}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}}return n}}]),t}();var _=function t(){s(this,t),this.primitives=[]},m=function(){function t(e,r){s(this,t),this.buffer=r[e.buffer],this.byteOffset=e.byteOffset||0,this.byteLength=e.byteLength||null,this.byteStride=e.byteStride,this._viewPromise=null,this._renderBuffer=null}return n(t,[{key:"dataView",value:function(){var t=this;return this._viewPromise||(this._viewPromise=this.buffer.arrayBuffer().then(function(e){return new DataView(e,t.byteOffset,t.byteLength)})),this._viewPromise}},{key:"renderBuffer",value:function(t,e){return this._renderBuffer||(this._renderBuffer=t.createRenderBuffer(e,this.dataView())),this._renderBuffer}}]),t}(),p=function(){function t(e,r,n){s(this,t),this.json=e,this.baseUrl=r,this._dataPromise=null,this._texture=null,n&&(this._dataPromise=Promise.resolve(n))}return n(t,[{key:"arrayBuffer",value:function(){if(!this._dataPromise){if(h(this.json.uri)){var t=this.json.uri.replace("data:application/octet-stream;base64,",""),e=Uint8Array.from(atob(t),function(t){return t.charCodeAt(0)});return this._dataPromise=Promise.resolve(e.buffer),this._dataPromise}this._dataPromise=fetch(d(this.json.uri,this.baseUrl)).then(function(t){return t.arrayBuffer()})}return this._dataPromise}},{key:"texture",value:function(t){var e=this;if(!this._texture){var r=new Image;if(this._texture=new u.ImageTexture(r),this.json.uri)h(this.json.uri)?r.src=this.json.uri:r.src=""+this.baseUrl+this.json.uri;else t[this.json.bufferView].dataView().then(function(t){var n=new Blob([t],{type:e.json.mimeType});r.src=window.URL.createObjectURL(n)})}return this._texture}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SkyboxNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(7),a=r(2),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.SKY,t.state.depthFunc=l.LEQUAL,t.state.depthMask=!1,t.image=t.defineSampler("diffuse"),t.texCoordScaleOffset=t.defineUniform("texCoordScaleOffset",[1,1,0,0,1,1,0,0],4),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"SKYBOX"}},{key:"vertexSource",get:function(){return"\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n // Drop the translation portion of the view matrix\n view[3].xyz = vec3(0.0, 0.0, 0.0);\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n\n // Returning the W component for both Z and W forces the geometry depth to\n // the far plane. When combined with a depth func of LEQUAL this makes the\n // sky write to any depth fragment that has not been written to yet.\n return out_vec.xyww;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }"}}]),e}();e.SkyboxNode=function(t){function e(t){s(this,e);var r=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._url=t.url,r._displayMode=t.displayMode||"mono",r._rotationY=t.rotationY||0,r}return f(e,a.Node),n(e,[{key:"onRendererChanged",value:function(t){for(var e=[],r=[],n=0;n<=40;++n)for(var i=n*Math.PI/40,a=Math.sin(i),s=Math.cos(i),c=41*n,f=41*(n+1),d=0;d<=40;++d){var v=2*d*Math.PI/40+this._rotationY,_=Math.sin(v)*a,m=s,p=-Math.cos(v)*a,y=d/40,b=n/40;if(e.push(_,m,p,y,b),n<40&&d<40){var g=c+d,M=f+d;r.push(g,M,g+1,M,M+1,g+1)}}var x=t.createRenderBuffer(l.ARRAY_BUFFER,new Float32Array(e)),T=t.createRenderBuffer(l.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),E=[new o.PrimitiveAttribute("POSITION",x,3,l.FLOAT,20,0),new o.PrimitiveAttribute("TEXCOORD_0",x,2,l.FLOAT,20,12)],w=new o.Primitive(E,r.length);w.setIndexBuffer(T);var O=new h;switch(O.image.texture=new u.UrlTexture(this._url),this._displayMode){case"mono":O.texCoordScaleOffset.value=[1,1,0,0,1,1,0,0];break;case"stereoTopBottom":O.texCoordScaleOffset.value=[1,.5,0,0,1,.5,0,.5];break;case"stereoLeftRight":O.texCoordScaleOffset.value=[.5,1,0,0,.5,1,.5,0]}var R=t.createRenderPrimitive(w,O);this.addRenderPrimitive(R)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.VideoNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(7),a=r(2),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.image=t.defineSampler("diffuse"),t.texCoordScaleOffset=t.defineUniform("texCoordScaleOffset",[1,1,0,0,1,1,0,0],4),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"VIDEO_PLAYER"}},{key:"vertexSource",get:function(){return"\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n return out_vec;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }"}}]),e}();e.VideoNode=function(t){function e(t){s(this,e);var r=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._video=t.video,r._displayMode=t.displayMode||"mono",r._video_texture=new u.VideoTexture(r._video),r}return f(e,a.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=[0,2,1,0,3,2],r=t.createRenderBuffer(l.ARRAY_BUFFER,new Float32Array([-1,1,0,0,0,1,1,0,1,0,1,-1,0,1,1,-1,-1,0,0,1])),n=t.createRenderBuffer(l.ELEMENT_ARRAY_BUFFER,new Uint16Array(e)),i=[new o.PrimitiveAttribute("POSITION",r,3,l.FLOAT,20,0),new o.PrimitiveAttribute("TEXCOORD_0",r,2,l.FLOAT,20,12)],a=new o.Primitive(i,e.length);a.setIndexBuffer(n),a.setBounds([-1,-1,0],[1,1,.015]);var u=new h;switch(u.image.texture=this._video_texture,this._displayMode){case"mono":u.texCoordScaleOffset.value=[1,1,0,0,1,1,0,0];break;case"stereoTopBottom":u.texCoordScaleOffset.value=[1,.5,0,0,1,.5,0,.5];break;case"stereoLeftRight":u.texCoordScaleOffset.value=[.5,1,0,0,.5,1,.5,0]}var s=t.createRenderPrimitive(a,u);this.addRenderPrimitive(s)}},{key:"aspectRatio",get:function(){var t=this._video.videoWidth,e=this._video.videoHeight;switch(this._displayMode){case"stereoTopBottom":e*=.5;break;case"stereoLeftRight":t*=.5}return e&&t?t/e:1}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Scene=e.WebXRView=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(11),o=r(31),a=r(32),u=r(2),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function f(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var h=e.WebXRView=function(t){function e(t,r){return c(this,e),f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t?t.projectionMatrix:null,t?t.viewMatrix:null,r&&t?r.getViewport(t):null,t?t.eye:"left"))}return l(e,i.RenderView),e}();e.Scene=function(t){function e(){c(this,e);var t=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._timestamp=-1,t._frameDelta=0,t._statsStanding=!1,t._stats=null,t._statsEnabled=!1,t.enableStats(!0),t._inputRenderer=null,t._resetInputEndFrame=!0,t._lastTimestamp=0,t._hoverFrame=0,t._hoveredNodes=[],t.clear=!0,t}return l(e,u.Node),n(e,[{key:"setRenderer",value:function(t){this._setRenderer(t)}},{key:"loseRenderer",value:function(){this._renderer&&(this._stats=null,this._renderer=null,this._inputRenderer=null)}},{key:"updateInputSources",value:function(t,e){if(t.session.getInputSources){var r=t.session.getInputSources(),n=[],i=this._hoverFrame;this._hoverFrame++;var o=!0,a=!1,u=void 0;try{for(var c,f=r[Symbol.iterator]();!(o=(c=f.next()).done);o=!0){var l=c.value,h=t.getInputPose(l,e);if(h&&(h.gripMatrix&&this.inputRenderer.addController(h.gripMatrix),h.targetRay)){"tracked-pointer"==l.targetRayMode&&this.inputRenderer.addLaserPointer(h.targetRay);var d=this.hitTest(h.targetRay);if(d)this.inputRenderer.addCursor(d.intersection),d.node._hoverFrameId!=i&&d.node.onHoverStart(),d.node._hoverFrameId=this._hoverFrame,n.push(d.node);else{var v=s.vec3.fromValues(h.targetRay.origin.x,h.targetRay.origin.y,h.targetRay.origin.z);s.vec3.add(v,v,[1*h.targetRay.direction.x,1*h.targetRay.direction.y,1*h.targetRay.direction.z]),this.inputRenderer.addCursor(v)}}}}catch(t){a=!0,u=t}finally{try{!o&&f.return&&f.return()}finally{if(a)throw u}}var _=!0,m=!1,p=void 0;try{for(var y,b=this._hoveredNodes[Symbol.iterator]();!(_=(y=b.next()).done);_=!0){var g=y.value;g._hoverFrameId!=this._hoverFrame&&g.onHoverEnd()}}catch(t){m=!0,p=t}finally{try{!_&&b.return&&b.return()}finally{if(m)throw p}}this._hoveredNodes=n}}},{key:"handleSelect",value:function(t,e,r){var n=e.getInputPose(t,r);n&&this.handleSelectPointer(n.targetRay)}},{key:"handleSelectPointer",value:function(t){if(t){var e=this.hitTest(t);e&&e.node.handleSelect()}}},{key:"enableStats",value:function(t){t!=this._statsEnabled&&(this._statsEnabled=t,t?(this._stats=new a.StatsViewer,this._stats.selectable=!0,this.addNode(this._stats),this._statsStanding?this._stats.translation=[0,1.4,-.75]:this._stats.translation=[0,-.3,-.5],this._stats.scale=[.3,.3,.3],s.quat.fromEuler(this._stats.rotation,-45,0,0)):t||this._stats&&(this.removeNode(this._stats),this._stats=null))}},{key:"standingStats",value:function(t){this._statsStanding=t,this._stats&&(this._statsStanding?this._stats.translation=[0,1.4,-.75]:this._stats.translation=[0,-.3,-.5],this._stats.scale=[.3,.3,.3],s.quat.fromEuler(this._stats.rotation,-45,0,0))}},{key:"draw",value:function(t,e,r){var n=new i.RenderView;n.projectionMatrix=t,n.viewMatrix=e,r&&(n.eye=r),this.drawViewArray([n])}},{key:"drawXRFrame",value:function(t,e){if(this._renderer&&e){var r=this._renderer.gl,n=t.session.baseLayer;if(r){r.bindFramebuffer(r.FRAMEBUFFER,n.framebuffer),this.clear&&r.clear(r.COLOR_BUFFER_BIT|r.DEPTH_BUFFER_BIT);var i=[],o=!0,a=!1,u=void 0;try{for(var s,c=e.views[Symbol.iterator]();!(o=(s=c.next()).done);o=!0){var f=s.value;i.push(new h(f,n))}}catch(t){a=!0,u=t}finally{try{!o&&c.return&&c.return()}finally{if(a)throw u}}this.drawViewArray(i)}}}},{key:"drawViewArray",value:function(t){this._renderer&&this._renderer.drawViews(t,this)}},{key:"startFrame",value:function(){var t=this._timestamp;return this._timestamp=performance.now(),this._stats&&this._stats.begin(),this._frameDelta=t>=0?this._timestamp-t:0,this._update(this._timestamp,this._frameDelta),this._frameDelta}},{key:"endFrame",value:function(){this._inputRenderer&&this._resetInputEndFrame&&this._inputRenderer.reset(),this._stats&&this._stats.end()}},{key:"onLoadScene",value:function(t){return Promise.resolve()}},{key:"inputRenderer",get:function(){return this._inputRenderer||(this._inputRenderer=new o.InputRenderer,this.addNode(this._inputRenderer)),this._inputRenderer}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.InputRenderer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=new Uint8Array([255,255,255,1,255,255,255,2,191,191,191,4,204,204,204,5,219,219,219,7,204,204,204,10,216,216,216,13,210,210,210,17,206,206,206,21,206,206,206,26,206,206,206,31,205,205,205,36,200,200,200,42,201,201,201,47,201,201,201,52,201,201,201,57,201,201,201,61,200,200,200,65,203,203,203,68,238,238,238,135,250,250,250,200,249,249,249,201,249,249,249,201,250,250,250,201,250,250,250,201,249,249,249,201,249,249,249,201,250,250,250,200,238,238,238,135,203,203,203,68,200,200,200,65,201,201,201,61,201,201,201,57,201,201,201,52,201,201,201,47,200,200,200,42,205,205,205,36,206,206,206,31,206,206,206,26,206,206,206,21,210,210,210,17,216,216,216,13,204,204,204,10,219,219,219,7,204,204,204,5,191,191,191,4,255,255,255,2,255,255,255,1]),d=[1,1,1,.25],v=[1,1,1,1],_=[.5,.5,.5,.25],m={controllers:!0,lasers:!0,cursors:!0},p=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.blendFuncDst=l.ONE,t.state.depthMask=!1,t.laser=t.defineSampler("diffuse"),t.laser.texture=new u.DataTexture(h,48,1),t.laserColor=t.defineUniform("laserColor",d),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_LASER"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n\n uniform vec4 laserColor;\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n const float fadePoint = 0.5335;\n const float fadeEnd = 0.535;\n\n vec4 fragment_main() {\n vec2 uv = vTexCoord;\n float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);\n float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);\n vec4 color = laserColor * texture2D(diffuse, vTexCoord);\n float opacity = color.a * front_fade_factor * back_fade_factor;\n return vec4(color.rgb * opacity, opacity);\n }"}}]),e}(),y="\nattribute vec4 POSITION;\n\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vLuminance = POSITION.z;\n vOpacity = POSITION.w;\n\n // Billboarded, constant size vertex transform.\n vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);\n screenPos /= screenPos.w;\n screenPos.xy += POSITION.xy;\n return screenPos;\n}",b="\nprecision mediump float;\n\nuniform vec4 cursorColor;\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 fragment_main() {\n vec3 color = cursorColor.rgb * vLuminance;\n float opacity = cursorColor.a * vOpacity;\n return vec4(color * opacity, opacity);\n}",g=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.depthMask=!1,t.cursorColor=t.defineUniform("cursorColor",v),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_CURSOR"}},{key:"vertexSource",get:function(){return y}},{key:"fragmentSource",get:function(){return b}}]),e}(),M=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.depthFunc=l.GEQUAL,t.state.depthMask=!1,t.cursorColor=t.defineUniform("cursorColor",_),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_CURSOR_2"}},{key:"vertexSource",get:function(){return y}},{key:"fragmentSource",get:function(){return b}}]),e}();e.InputRenderer=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._maxInputElements=32,t._controllers=[],t._controllerNode=null,t._controllerNodeHandedness=null,t._lasers=null,t._cursors=null,t._activeControllers=0,t._activeLasers=0,t._activeCursors=0,t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this._controllers=[],this._controllerNode=null,this._controllerNodeHandedness=null,this._lasers=null,this._cursors=null,this._activeControllers=0,this._activeLasers=0,this._activeCursors=0}},{key:"setControllerMesh",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"right";this._controllerNode=t,this._controllerNode.visible=!1,this.addNode(this._controllerNode),this._controllerNodeHandedness=e}},{key:"addController",value:function(t){if(this._controllerNode){var e=null;this._activeControllers<this._controllers.length?e=this._controllers[this._activeControllers]:(e=this._controllerNode.clone(),this.addNode(e),this._controllers.push(e)),this._activeControllers=(this._activeControllers+1)%this._maxInputElements,e.matrix=t,e.visible=!0}}},{key:"addLaserPointer",value:function(t){!this._lasers&&this._renderer&&(this._lasers=[this._createLaserMesh()],this.addNode(this._lasers[0]));var e=null;this._activeLasers<this._lasers.length?e=this._lasers[this._activeLasers]:(e=this._lasers[0].clone(),this.addNode(e),this._lasers.push(e)),this._activeLasers=(this._activeLasers+1)%this._maxInputElements,e.matrix=t.transformMatrix,e.visible=!0}},{key:"addCursor",value:function(t){!this._cursors&&this._renderer&&(this._cursors=[this._createCursorMesh()],this.addNode(this._cursors[0]));var e=null;this._activeCursors<this._cursors.length?e=this._cursors[this._activeCursors]:(e=this._cursors[0].clone(),this.addNode(e),this._cursors.push(e)),this._activeCursors=(this._activeCursors+1)%this._maxInputElements,e.translation=t,e.visible=!0}},{key:"reset",value:function(t){if(t||(t=m),this._controllers&&t.controllers){var e=!0,r=!1,n=void 0;try{for(var i,o=this._controllers[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value.visible=!1}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}this._activeControllers=0}if(this._lasers&&t.lasers){var a=!0,u=!1,s=void 0;try{for(var c,f=this._lasers[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){c.value.visible=!1}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}this._activeLasers=0}if(this._cursors&&t.cursors){var l=!0,h=!1,d=void 0;try{for(var v,_=this._cursors[Symbol.iterator]();!(l=(v=_.next()).done);l=!0){v.value.visible=!1}}catch(t){h=!0,d=t}finally{try{!l&&_.return&&_.return()}finally{if(h)throw d}}this._activeCursors=0}}},{key:"_createLaserMesh",value:function(){var t=this._renderer._gl,e=.005,r=[0,e,0,0,1,0,e,-1,0,0,0,-e,0,1,1,0,-e,-1,1,0,e,0,0,0,1,e,0,-1,0,0,-e,0,0,1,1,-e,0,-1,1,0,0,-e,0,0,1,0,-e,-1,0,0,0,e,0,1,1,0,e,-1,1,0,-e,0,0,0,1,-e,0,-1,0,0,e,0,0,1,1,e,0,-1,1,0],n=[0,1,2,1,3,2,4,5,6,5,7,6,8,9,10,9,11,10,12,13,14,13,15,14],i=this._renderer.createRenderBuffer(t.ARRAY_BUFFER,new Float32Array(r)),u=this._renderer.createRenderBuffer(t.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),s=n.length,c=[new a.PrimitiveAttribute("POSITION",i,3,t.FLOAT,20,0),new a.PrimitiveAttribute("TEXCOORD_0",i,2,t.FLOAT,20,12)],f=new a.Primitive(c,s);f.setIndexBuffer(u);var l=new p,h=this._renderer.createRenderPrimitive(f,l),d=new o.Node;return d.addRenderPrimitive(h),d}},{key:"_createCursorMesh",value:function(){for(var t=this._renderer._gl,e=[],r=[],n=2*Math.PI/16,i=0;i<16;++i){var u=i*n,s=Math.cos(u),c=Math.sin(u);e.push(.004*s,.004*c,1,.9),i>1&&r.push(0,i-1,i)}for(var f=0;f<16;++f){var l=f*n,h=Math.cos(l),d=Math.sin(l);if(e.push(.004*h,.004*d,.5,.75),e.push(.007*h,.007*d,0,0),f>0){var v=16+2*f;r.push(v-2,v-1,v),r.push(v-1,v+1,v)}}r.push(46,47,16),r.push(47,17,16);var _=this._renderer.createRenderBuffer(t.ARRAY_BUFFER,new Float32Array(e)),m=this._renderer.createRenderBuffer(t.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),p=r.length,y=[new a.PrimitiveAttribute("POSITION",_,4,t.FLOAT,16,0)],b=new a.Primitive(y,p);b.setIndexBuffer(m);var x=new g,T=new M,E=this._renderer.createRenderPrimitive(b,x),w=this._renderer.createRenderPrimitive(b,T),O=new o.Node;return O.addRenderPrimitive(E),O.addRenderPrimitive(w),O}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.StatsViewer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7),u=r(33);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=30,h=90,d=function(t){function e(){return s(this,e),c(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"STATS_VIEWER"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec3 COLOR_0;\n varying vec4 vColor;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vColor = vec4(COLOR_0, 1.0);\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n varying vec4 vColor;\n\n vec4 fragment_main() {\n return vColor;\n }"}}]),e}();function v(t){return.9/l*t-.45}function _(t){return Math.min(t,h)*(.7/h)-.45}var m=window.performance&&performance.now?performance.now.bind(performance):Date.now;e.StatsViewer=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._performanceMonitoring=!1,t._startTime=m(),t._prevFrameTime=t._startTime,t._prevGraphUpdateTime=t._startTime,t._frames=0,t._fpsAverage=0,t._fpsMin=0,t._fpsStep=t._performanceMonitoring?1e3:250,t._lastSegment=0,t._fpsVertexBuffer=null,t._fpsRenderPrimitive=null,t._fpsNode=null,t._sevenSegmentNode=new u.SevenSegmentText,t._sevenSegmentNode.matrix=new Float32Array([.075,0,0,0,0,.075,0,0,0,0,1,0,-.3625,.3625,.02,1]),t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.clearNodes();for(var e=t.gl,r=[],n=[],i=0;i<l;++i){r.push(v(i),_(0),.02,0,1,1),r.push(v(i+1),_(0),.02,0,1,1),r.push(v(i),_(0),.02,0,1,1),r.push(v(i+1),_(0),.02,0,1,1);var u=4*i;n.push(u,u+3,u+1,u+3,u,u+2)}function s(t,e,i,o,a,u,s,c){var f=r.length/6;r.push(t,e,a,u,s,c),r.push(i,o,a,u,s,c),r.push(t,o,a,u,s,c),r.push(i,e,a,u,s,c),n.push(f,f+1,f+2,f,f+3,f+1)}s(-.5,-.5,.5,.5,0,0,0,.125),s(-.45,-.45,.45,.25,.01,0,0,.4),s(-.45,_(30),.45,_(32),.015,.5,0,.5),s(-.45,_(60),.45,_(62),.015,.2,0,.75),this._fpsVertexBuffer=t.createRenderBuffer(e.ARRAY_BUFFER,new Float32Array(r),e.DYNAMIC_DRAW);var c=t.createRenderBuffer(e.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),f=[new a.PrimitiveAttribute("POSITION",this._fpsVertexBuffer,3,e.FLOAT,24,0),new a.PrimitiveAttribute("COLOR_0",this._fpsVertexBuffer,3,e.FLOAT,24,12)],h=new a.Primitive(f,n.length);h.setIndexBuffer(c),h.setBounds([-.5,-.5,0],[.5,.5,.015]),this._fpsRenderPrimitive=t.createRenderPrimitive(h,new d),this._fpsNode=new o.Node,this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive),this.addNode(this._fpsNode),this.addNode(this._sevenSegmentNode)}},{key:"begin",value:function(){this._startTime=m()}},{key:"end",value:function(){var t=m(),e=1e3/(t-this._prevFrameTime);if(this._prevFrameTime=t,this._fpsMin=this._frames?Math.min(this._fpsMin,e):e,this._frames++,t>this._prevGraphUpdateTime+this._fpsStep){var r=t-this._prevGraphUpdateTime;this._fpsAverage=Math.round(1e3/(r/this._frames)),this._updateGraph(this._fpsMin,this._fpsAverage),this._performanceMonitoring&&console.log("Average FPS: "+this._fpsAverage+" Min FPS: "+this._fpsMin),this._prevGraphUpdateTime=t,this._frames=0,this._fpsMin=0}}},{key:"_updateGraph",value:function(t,e){var r,n=(r=t,{r:Math.max(0,Math.min(1,1-r/60)),g:Math.max(0,Math.min(1,(r-15)/(h-15))),b:Math.max(0,Math.min(1,(r-15)/(h-15)))}),i=_(t-1),o=_(e+1),a=[v(this._lastSegment),o,.02,n.r,n.g,n.b,v(this._lastSegment+1),o,.02,n.r,n.g,n.b,v(this._lastSegment),i,.02,n.r,n.g,n.b,v(this._lastSegment+1),i,.02,n.r,n.g,n.b];n.r=.2,n.g=1,n.b=.2,this._lastSegment==l-1?(this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),24*this._lastSegment*4),a=[v(0),_(h),.02,n.r,n.g,n.b,v(.25),_(h),.02,n.r,n.g,n.b,v(0),_(0),.02,n.r,n.g,n.b,v(.25),_(0),.02,n.r,n.g,n.b],this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),0)):(a.push(v(this._lastSegment+1),_(h),.02,n.r,n.g,n.b,v(this._lastSegment+1.25),_(h),.02,n.r,n.g,n.b,v(this._lastSegment+1),_(0),.02,n.r,n.g,n.b,v(this._lastSegment+1.25),_(0),.02,n.r,n.g,n.b),this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),24*this._lastSegment*4)),this._lastSegment=(this._lastSegment+1)%l,this._sevenSegmentNode.text=this._fpsAverage+" FP5"}},{key:"performanceMonitoring",get:function(){return this._performanceMonitoring},set:function(t){this._performanceMonitoring=t,this._fpsStep=t?1e3:250}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SevenSegmentText=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7);function u(t){if(Array.isArray(t)){for(var e=0,r=Array(t.length);e<t.length;e++)r[e]=t[e];return r}return Array.from(t)}function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=function(t){function e(){return s(this,e),c(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"SEVEN_SEGMENT_TEXT"}},{key:"vertexSource",get:function(){return"\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 0.0, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n\n vec4 fragment_main() {\n return color;\n }"}}]),e}();e.SevenSegmentText=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._text="",t._charNodes=[],t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.clearNodes(),this._charNodes=[];var e=[],r={},n=[];function i(t,n,i,o,a){var u=e.length/2;e.push(n,i,o,i,o,a,n,a),r[t]=[u,u+2,u+1,u,u+3,u+2]}var o={};function s(t,e){for(var i={character:t,offset:2*n.length,count:0},a=0;a<e.length;++a){var s=e[a],c=r[s];i.count+=c.length,n.push.apply(n,u(c))}o[t]=i}i(0,-1,1,.5,.75),i(1,-1,.125,.5,-.125),i(2,-1,-.75,.5,-1),i(3,-1,1,-.75,-.125),i(4,.25,1,.5,-.125),i(5,-1,.125,-.75,-1),i(6,.25,.125,.5,-1),s("0",[0,2,3,4,5,6]),s("1",[4,6]),s("2",[0,1,2,4,5]),s("3",[0,1,2,4,6]),s("4",[1,3,4,6]),s("5",[0,1,2,3,6]),s("6",[0,1,2,3,5,6]),s("7",[0,4,6]),s("8",[0,1,2,3,4,5,6]),s("9",[0,1,2,3,4,6]),s("A",[0,1,3,4,5,6]),s("B",[1,2,3,5,6]),s("C",[0,2,3,5]),s("D",[1,2,4,5,6]),s("E",[0,1,2,4,6]),s("F",[0,1,3,5]),s("P",[0,1,3,4,5]),s("-",[1]),s(" ",[]),s("_",[2]);var c=t.gl,f=t.createRenderBuffer(c.ARRAY_BUFFER,new Float32Array(e)),h=t.createRenderBuffer(c.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),d=[new a.PrimitiveAttribute("POSITION",f,2,c.FLOAT,8,0)],v=new a.Primitive(d,n.length);v.setIndexBuffer(h);var _=new l;for(var m in this._charPrimitives={},o){var p=o[m];v.elementCount=p.count,v.indexByteOffset=p.offset,this._charPrimitives[m]=t.createRenderPrimitive(v,_)}this.text=this._text}},{key:"text",get:function(){return this._text},set:function(t){this._text=t;for(var e=0,r=null;e<t.length;++e)if(r=t[e]in this._charPrimitives?this._charPrimitives[t[e]]:this._charPrimitives._,this._charNodes.length<=e){var n=new o.Node;n.addRenderPrimitive(r);var i=2*e;n.translation=[i,0,0],this._charNodes.push(n),this.addNode(n)}else this._charNodes[e].clearRenderPrimitives(),this._charNodes[e].addRenderPrimitive(r),this._charNodes[e].visible=!0;for(;e<this._charNodes.length;++e)this._charNodes[e].visible=!1}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.FallbackHelper=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);e.FallbackHelper=function(){function t(e,r){var n=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.scene=e,this.gl=r,this._emulateStage=!1,this.lookYaw=0,this.lookPitch=0,this.viewMatrix=i.mat4.create();var o=i.mat4.create();function a(){r.canvas.width=r.canvas.offsetWidth*window.devicePixelRatio,r.canvas.height=r.canvas.offsetHeight*window.devicePixelRatio,i.mat4.perspective(o,.4*Math.PI,r.canvas.width/r.canvas.height,.1,1e3),r.viewport(0,0,r.drawingBufferWidth,r.drawingBufferHeight)}this.projectionMatrix=o,i.mat4.identity(this.viewMatrix),window.addEventListener("resize",a),a();var u=r.canvas,s=0,c=0;u.addEventListener("touchstart",function(t){2==t.touches.length&&(s=t.touches[1].pageX,c=t.touches[1].pageY)}),u.addEventListener("touchmove",function(t){2==t.touches.length&&(n.onLook(t.touches[1].pageX-s,t.touches[1].pageY-c),s=t.touches[1].pageX,c=t.touches[1].pageY)}),u.addEventListener("mousemove",function(t){2&t.buttons&&n.onLook(t.movementX,t.movementY)}),u.addEventListener("contextmenu",function(t){t.preventDefault()}),this.boundOnFrame=this.onFrame.bind(this),window.requestAnimationFrame(this.boundOnFrame)}return n(t,[{key:"onLook",value:function(t,e){this.lookYaw+=.0025*t,this.lookPitch+=.0025*e,this.lookPitch<.5*-Math.PI&&(this.lookPitch=.5*-Math.PI),this.lookPitch>.5*Math.PI&&(this.lookPitch=.5*Math.PI),this.updateView()}},{key:"onFrame",value:function(t){var e=this.gl;window.requestAnimationFrame(this.boundOnFrame),this.scene.startFrame(),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT),this.scene.draw(this.projectionMatrix,this.viewMatrix),this.scene.endFrame()}},{key:"updateView",value:function(){i.mat4.identity(this.viewMatrix),i.mat4.rotateX(this.viewMatrix,this.viewMatrix,-this.lookPitch),i.mat4.rotateY(this.viewMatrix,this.viewMatrix,-this.lookYaw),this._emulateStage&&i.mat4.translate(this.viewMatrix,this.viewMatrix,[0,-1.6,0])}},{key:"emulateStage",get:function(){return this._emulateStage},set:function(t){this._emulateStage=t,this.updateView()}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();var i=null;function o(){if(!i){i={};for(var t=(window.location.search.substring(1)||window.location.hash.substring(1)).split("&"),e=0;e<t.length;e++){var r=t[e].split("=");i[r[0].toLowerCase()]=decodeURIComponent(r[1])}}}window.onhashchange=function(){i=null};e.QueryArgs=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t)}return n(t,null,[{key:"getString",value:function(t,e){o();var r=t.toLowerCase();return r in i?i[r]:e}},{key:"getInt",value:function(t,e){o();var r=t.toLowerCase();return r in i?parseInt(i[r],10):e}},{key:"getFloat",value:function(t,e){o();var r=t.toLowerCase();return r in i?parseFloat(i[r]):e}},{key:"getBool",value:function(t,e){o();var r=t.toLowerCase();return r in i?0!=parseInt(i[r],10):e}}]),t}()}])}); \ No newline at end of file
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json
new file mode 100644
index 00000000000..41ce01b40e9
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "cottontail",
+ "version": "0.0.1",
+ "description": "Minimalist WebXR rendering framework",
+ "license": "MIT",
+ "readme": "README.md",
+ "babel": {
+ "presets": [
+ "env"
+ ]
+ },
+ "scripts": {
+ "build": "webpack",
+ "build-debug": "webpack --config webpack.config.debug.js",
+ "build-all": "eslint -c .eslintrc.json src && webpack && webpack --config webpack.config.debug.js",
+ "watch": "webpack --watch",
+ "watch-debug": "webpack --config webpack.config.debug.js --watch",
+ "lint": "eslint -c .eslintrc.json src"
+ },
+ "devDependencies": {
+ "babel-core": "^6.26.2",
+ "babel-loader": "^7.1.4",
+ "babel-preset-env": "^1.6.1",
+ "eslint": "^4.19.1",
+ "eslint-config-google": "^0.9.1",
+ "gl-matrix": "^2.5.1",
+ "webpack": "^4.29.0",
+ "webpack-cli": "^3.2.1"
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/material.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/material.js
new file mode 100644
index 00000000000..9939eef147d
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/material.js
@@ -0,0 +1,278 @@
+// 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.
+
+const GL = WebGLRenderingContext; // For enums
+
+export const CAP = {
+ // Enable caps
+ CULL_FACE: 0x001,
+ BLEND: 0x002,
+ DEPTH_TEST: 0x004,
+ STENCIL_TEST: 0x008,
+ COLOR_MASK: 0x010,
+ DEPTH_MASK: 0x020,
+ STENCIL_MASK: 0x040,
+};
+
+export const MAT_STATE = {
+ CAPS_RANGE: 0x000000FF,
+ BLEND_SRC_SHIFT: 8,
+ BLEND_SRC_RANGE: 0x00000F00,
+ BLEND_DST_SHIFT: 12,
+ BLEND_DST_RANGE: 0x0000F000,
+ BLEND_FUNC_RANGE: 0x0000FF00,
+ DEPTH_FUNC_SHIFT: 16,
+ DEPTH_FUNC_RANGE: 0x000F0000,
+};
+
+export const RENDER_ORDER = {
+ // Render opaque objects first.
+ OPAQUE: 0,
+
+ // Render the sky after all opaque object to save fill rate.
+ SKY: 1,
+
+ // Render transparent objects next so that the opaqe objects show through.
+ TRANSPARENT: 2,
+
+ // Finally render purely additive effects like pointer rays so that they
+ // can render without depth mask.
+ ADDITIVE: 3,
+
+ // Render order will be picked based on the material properties.
+ DEFAULT: 4,
+};
+
+export function stateToBlendFunc(state, mask, shift) {
+ let value = (state & mask) >> shift;
+ switch (value) {
+ case 0:
+ case 1:
+ return value;
+ default:
+ return (value - 2) + GL.SRC_COLOR;
+ }
+}
+
+export class MaterialState {
+ constructor() {
+ this._state = CAP.CULL_FACE |
+ CAP.DEPTH_TEST |
+ CAP.COLOR_MASK |
+ CAP.DEPTH_MASK;
+
+ // Use a fairly commonly desired blend func as the default.
+ this.blendFuncSrc = GL.SRC_ALPHA;
+ this.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;
+
+ this.depthFunc = GL.LESS;
+ }
+
+ get cullFace() {
+ return !!(this._state & CAP.CULL_FACE);
+ }
+ set cullFace(value) {
+ if (value) {
+ this._state |= CAP.CULL_FACE;
+ } else {
+ this._state &= ~CAP.CULL_FACE;
+ }
+ }
+
+ get blend() {
+ return !!(this._state & CAP.BLEND);
+ }
+ set blend(value) {
+ if (value) {
+ this._state |= CAP.BLEND;
+ } else {
+ this._state &= ~CAP.BLEND;
+ }
+ }
+
+ get depthTest() {
+ return !!(this._state & CAP.DEPTH_TEST);
+ }
+ set depthTest(value) {
+ if (value) {
+ this._state |= CAP.DEPTH_TEST;
+ } else {
+ this._state &= ~CAP.DEPTH_TEST;
+ }
+ }
+
+ get stencilTest() {
+ return !!(this._state & CAP.STENCIL_TEST);
+ }
+ set stencilTest(value) {
+ if (value) {
+ this._state |= CAP.STENCIL_TEST;
+ } else {
+ this._state &= ~CAP.STENCIL_TEST;
+ }
+ }
+
+ get colorMask() {
+ return !!(this._state & CAP.COLOR_MASK);
+ }
+ set colorMask(value) {
+ if (value) {
+ this._state |= CAP.COLOR_MASK;
+ } else {
+ this._state &= ~CAP.COLOR_MASK;
+ }
+ }
+
+ get depthMask() {
+ return !!(this._state & CAP.DEPTH_MASK);
+ }
+ set depthMask(value) {
+ if (value) {
+ this._state |= CAP.DEPTH_MASK;
+ } else {
+ this._state &= ~CAP.DEPTH_MASK;
+ }
+ }
+
+ get depthFunc() {
+ return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;
+ }
+ set depthFunc(value) {
+ value = value - GL.NEVER;
+ this._state &= ~MAT_STATE.DEPTH_FUNC_RANGE;
+ this._state |= (value << MAT_STATE.DEPTH_FUNC_SHIFT);
+ }
+
+ get stencilMask() {
+ return !!(this._state & CAP.STENCIL_MASK);
+ }
+ set stencilMask(value) {
+ if (value) {
+ this._state |= CAP.STENCIL_MASK;
+ } else {
+ this._state &= ~CAP.STENCIL_MASK;
+ }
+ }
+
+ get blendFuncSrc() {
+ return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);
+ }
+ set blendFuncSrc(value) {
+ switch (value) {
+ case 0:
+ case 1:
+ break;
+ default:
+ value = (value - GL.SRC_COLOR) + 2;
+ }
+ this._state &= ~MAT_STATE.BLEND_SRC_RANGE;
+ this._state |= (value << MAT_STATE.BLEND_SRC_SHIFT);
+ }
+
+ get blendFuncDst() {
+ return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);
+ }
+ set blendFuncDst(value) {
+ switch (value) {
+ case 0:
+ case 1:
+ break;
+ default:
+ value = (value - GL.SRC_COLOR) + 2;
+ }
+ this._state &= ~MAT_STATE.BLEND_DST_RANGE;
+ this._state |= (value << MAT_STATE.BLEND_DST_SHIFT);
+ }
+}
+
+class MaterialSampler {
+ constructor(uniformName) {
+ this._uniformName = uniformName;
+ this._texture = null;
+ }
+
+ get texture() {
+ return this._texture;
+ }
+
+ set texture(value) {
+ this._texture = value;
+ }
+}
+
+class MaterialUniform {
+ constructor(uniformName, defaultValue, length) {
+ this._uniformName = uniformName;
+ this._value = defaultValue;
+ this._length = length;
+ if (!this._length) {
+ if (defaultValue instanceof Array) {
+ this._length = defaultValue.length;
+ } else {
+ this._length = 1;
+ }
+ }
+ }
+
+ get value() {
+ return this._value;
+ }
+
+ set value(value) {
+ this._value = value;
+ }
+}
+
+export class Material {
+ constructor() {
+ this.state = new MaterialState;
+ this.renderOrder = RENDER_ORDER.DEFAULT;
+ this._samplers = [];
+ this._uniforms = [];
+ }
+
+ defineSampler(uniformName) {
+ let sampler = new MaterialSampler(uniformName);
+ this._samplers.push(sampler);
+ return sampler;
+ }
+
+ defineUniform(uniformName, defaultValue=null, length=0) {
+ let uniform = new MaterialUniform(uniformName, defaultValue, length);
+ this._uniforms.push(uniform);
+ return uniform;
+ }
+
+ get materialName() {
+ return null;
+ }
+
+ get vertexSource() {
+ return null;
+ }
+
+ get fragmentSource() {
+ return null;
+ }
+
+ getProgramDefines(renderPrimitive) {
+ return {};
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/node.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/node.js
new file mode 100644
index 00000000000..37a072e31b6
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/node.js
@@ -0,0 +1,450 @@
+// 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.
+
+import {Ray} from '../math/ray.js';
+import {mat4, vec3, quat} from '../math/gl-matrix.js';
+
+const DEFAULT_TRANSLATION = new Float32Array([0, 0, 0]);
+const DEFAULT_ROTATION = new Float32Array([0, 0, 0, 1]);
+const DEFAULT_SCALE = new Float32Array([1, 1, 1]);
+
+let tmpRayMatrix = mat4.create();
+
+export class Node {
+ constructor() {
+ this.name = null; // Only for debugging
+ this.children = [];
+ this.parent = null;
+ this.visible = true;
+ this.selectable = false;
+
+ this._matrix = null;
+
+ this._dirtyTRS = false;
+ this._translation = null;
+ this._rotation = null;
+ this._scale = null;
+
+ this._dirtyWorldMatrix = false;
+ this._worldMatrix = null;
+
+ this._activeFrameId = -1;
+ this._hoverFrameId = -1;
+ this._renderPrimitives = null;
+ this._renderer = null;
+
+ this._selectHandler = null;
+ }
+
+ _setRenderer(renderer) {
+ if (this._renderer == renderer) {
+ return;
+ }
+
+ if (this._renderer) {
+ // Changing the renderer removes any previously attached renderPrimitives
+ // from a different renderer.
+ this.clearRenderPrimitives();
+ }
+
+ this._renderer = renderer;
+ if (renderer) {
+ this.onRendererChanged(renderer);
+
+ for (let child of this.children) {
+ child._setRenderer(renderer);
+ }
+ }
+ }
+
+ onRendererChanged(renderer) {
+ // Override in other node types to respond to changes in the renderer.
+ }
+
+ // Create a clone of this node and all of it's children. Does not duplicate
+ // RenderPrimitives, the cloned nodes will be treated as new instances of the
+ // geometry.
+ clone() {
+ let cloneNode = new Node();
+ cloneNode.name = this.name;
+ cloneNode.visible = this.visible;
+ cloneNode._renderer = this._renderer;
+
+ cloneNode._dirtyTRS = this._dirtyTRS;
+
+ if (this._translation) {
+ cloneNode._translation = vec3.create();
+ vec3.copy(cloneNode._translation, this._translation);
+ }
+
+ if (this._rotation) {
+ cloneNode._rotation = quat.create();
+ quat.copy(cloneNode._rotation, this._rotation);
+ }
+
+ if (this._scale) {
+ cloneNode._scale = vec3.create();
+ vec3.copy(cloneNode._scale, this._scale);
+ }
+
+ // Only copy the matrices if they're not already dirty.
+ if (!cloneNode._dirtyTRS && this._matrix) {
+ cloneNode._matrix = mat4.create();
+ mat4.copy(cloneNode._matrix, this._matrix);
+ }
+
+ cloneNode._dirtyWorldMatrix = this._dirtyWorldMatrix;
+ if (!cloneNode._dirtyWorldMatrix && this._worldMatrix) {
+ cloneNode._worldMatrix = mat4.create();
+ mat4.copy(cloneNode._worldMatrix, this._worldMatrix);
+ }
+
+ this.waitForComplete().then(() => {
+ if (this._renderPrimitives) {
+ for (let primitive of this._renderPrimitives) {
+ cloneNode.addRenderPrimitive(primitive);
+ }
+ }
+
+ for (let child of this.children) {
+ cloneNode.addNode(child.clone());
+ }
+ });
+
+ return cloneNode;
+ }
+
+ markActive(frameId) {
+ if (this.visible && this._renderPrimitives) {
+ this._activeFrameId = frameId;
+ for (let primitive of this._renderPrimitives) {
+ primitive.markActive(frameId);
+ }
+ }
+
+ for (let child of this.children) {
+ if (child.visible) {
+ child.markActive(frameId);
+ }
+ }
+ }
+
+ addNode(value) {
+ if (!value || value.parent == this) {
+ return;
+ }
+
+ if (value.parent) {
+ value.parent.removeNode(value);
+ }
+ value.parent = this;
+
+ this.children.push(value);
+
+ if (this._renderer) {
+ value._setRenderer(this._renderer);
+ }
+ }
+
+ removeNode(value) {
+ let i = this.children.indexOf(value);
+ if (i > -1) {
+ this.children.splice(i, 1);
+ value.parent = null;
+ }
+ }
+
+ clearNodes() {
+ for (let child of this.children) {
+ child.parent = null;
+ }
+ this.children = [];
+ }
+
+ setMatrixDirty() {
+ if (!this._dirtyWorldMatrix) {
+ this._dirtyWorldMatrix = true;
+ for (let child of this.children) {
+ child.setMatrixDirty();
+ }
+ }
+ }
+
+ _updateLocalMatrix() {
+ if (!this._matrix) {
+ this._matrix = mat4.create();
+ }
+
+ if (this._dirtyTRS) {
+ this._dirtyTRS = false;
+ mat4.fromRotationTranslationScale(
+ this._matrix,
+ this._rotation || DEFAULT_ROTATION,
+ this._translation || DEFAULT_TRANSLATION,
+ this._scale || DEFAULT_SCALE);
+ }
+
+ return this._matrix;
+ }
+
+ set matrix(value) {
+ if (value) {
+ if (!this._matrix) {
+ this._matrix = mat4.create();
+ }
+ mat4.copy(this._matrix, value);
+ } else {
+ this._matrix = null;
+ }
+ this.setMatrixDirty();
+ this._dirtyTRS = false;
+ this._translation = null;
+ this._rotation = null;
+ this._scale = null;
+ }
+
+ get matrix() {
+ this.setMatrixDirty();
+
+ return this._updateLocalMatrix();
+ }
+
+ get worldMatrix() {
+ if (!this._worldMatrix) {
+ this._dirtyWorldMatrix = true;
+ this._worldMatrix = mat4.create();
+ }
+
+ if (this._dirtyWorldMatrix || this._dirtyTRS) {
+ if (this.parent) {
+ // TODO: Some optimizations that could be done here if the node matrix
+ // is an identity matrix.
+ mat4.mul(this._worldMatrix, this.parent.worldMatrix, this._updateLocalMatrix());
+ } else {
+ mat4.copy(this._worldMatrix, this._updateLocalMatrix());
+ }
+ this._dirtyWorldMatrix = false;
+ }
+
+ return this._worldMatrix;
+ }
+
+ // TODO: Decompose matrix when fetching these?
+ set translation(value) {
+ if (value != null) {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ }
+ this._translation = value;
+ }
+
+ get translation() {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ if (!this._translation) {
+ this._translation = vec3.clone(DEFAULT_TRANSLATION);
+ }
+ return this._translation;
+ }
+
+ set rotation(value) {
+ if (value != null) {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ }
+ this._rotation = value;
+ }
+
+ get rotation() {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ if (!this._rotation) {
+ this._rotation = quat.clone(DEFAULT_ROTATION);
+ }
+ return this._rotation;
+ }
+
+ set scale(value) {
+ if (value != null) {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ }
+ this._scale = value;
+ }
+
+ get scale() {
+ this._dirtyTRS = true;
+ this.setMatrixDirty();
+ if (!this._scale) {
+ this._scale = vec3.clone(DEFAULT_SCALE);
+ }
+ return this._scale;
+ }
+
+ waitForComplete() {
+ let childPromises = [];
+ for (let child of this.children) {
+ childPromises.push(child.waitForComplete());
+ }
+ if (this._renderPrimitives) {
+ for (let primitive of this._renderPrimitives) {
+ childPromises.push(primitive.waitForComplete());
+ }
+ }
+ return Promise.all(childPromises).then(() => this);
+ }
+
+ get renderPrimitives() {
+ return this._renderPrimitives;
+ }
+
+ addRenderPrimitive(primitive) {
+ if (!this._renderPrimitives) {
+ this._renderPrimitives = [primitive];
+ } else {
+ this._renderPrimitives.push(primitive);
+ }
+ primitive._instances.push(this);
+ }
+
+ removeRenderPrimitive(primitive) {
+ if (!this._renderPrimitives) {
+ return;
+ }
+
+ let index = this._renderPrimitives._instances.indexOf(primitive);
+ if (index > -1) {
+ this._renderPrimitives._instances.splice(index, 1);
+
+ index = primitive._instances.indexOf(this);
+ if (index > -1) {
+ primitive._instances.splice(index, 1);
+ }
+
+ if (!this._renderPrimitives.length) {
+ this._renderPrimitives = null;
+ }
+ }
+ }
+
+ clearRenderPrimitives() {
+ if (this._renderPrimitives) {
+ for (let primitive of this._renderPrimitives) {
+ let index = primitive._instances.indexOf(this);
+ if (index > -1) {
+ primitive._instances.splice(index, 1);
+ }
+ }
+ this._renderPrimitives = null;
+ }
+ }
+
+ _hitTestSelectableNode(ray) {
+ if (this._renderPrimitives) {
+ let localRay = null;
+ for (let primitive of this._renderPrimitives) {
+ if (primitive._min) {
+ if (!localRay) {
+ mat4.invert(tmpRayMatrix, this.worldMatrix);
+ mat4.multiply(tmpRayMatrix, tmpRayMatrix, ray.transformMatrix);
+ localRay = new Ray(tmpRayMatrix);
+ }
+ let intersection = localRay.intersectsAABB(primitive._min, primitive._max);
+ if (intersection) {
+ vec3.transformMat4(intersection, intersection, this.worldMatrix);
+ return intersection;
+ }
+ }
+ }
+ }
+ for (let child of this.children) {
+ let intersection = child._hitTestSelectableNode(ray);
+ if (intersection) {
+ return intersection;
+ }
+ }
+ return null;
+ }
+
+ hitTest(ray) {
+ if (this.selectable && this.visible) {
+ let intersection = this._hitTestSelectableNode(ray);
+
+ if (intersection) {
+ let origin = vec3.fromValues(ray.origin.x, ray.origin.y, ray.origin.z);
+ return {
+ node: this,
+ intersection: intersection,
+ distance: vec3.distance(origin, intersection),
+ };
+ }
+ return null;
+ }
+
+ let result = null;
+ for (let child of this.children) {
+ let childResult = child.hitTest(ray);
+ if (childResult) {
+ if (!result || result.distance > childResult.distance) {
+ result = childResult;
+ }
+ }
+ }
+ return result;
+ }
+
+ onSelect(value) {
+ this._selectHandler = value;
+ }
+
+ get selectHandler() {
+ return this._selectHandler;
+ }
+
+ // Called when a selectable node is selected.
+ handleSelect() {
+ if (this._selectHandler) {
+ this._selectHandler();
+ }
+ }
+
+ // Called when a selectable element is pointed at.
+ onHoverStart() {
+
+ }
+
+ // Called when a selectable element is no longer pointed at.
+ onHoverEnd() {
+
+ }
+
+ _update(timestamp, frameDelta) {
+ this.onUpdate(timestamp, frameDelta);
+
+ for (let child of this.children) {
+ child._update(timestamp, frameDelta);
+ }
+ }
+
+ // Called every frame so that the nodes can animate themselves
+ onUpdate(timestamp, frameDelta) {
+
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/primitive.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/primitive.js
new file mode 100644
index 00000000000..ece48ec49e9
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/primitive.js
@@ -0,0 +1,57 @@
+// 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.
+
+import {vec3} from '../math/gl-matrix.js';
+
+export class PrimitiveAttribute {
+ constructor(name, buffer, componentCount, componentType, stride, byteOffset) {
+ this.name = name;
+ this.buffer = buffer;
+ this.componentCount = componentCount || 3;
+ this.componentType = componentType || 5126; // gl.FLOAT;
+ this.stride = stride || 0;
+ this.byteOffset = byteOffset || 0;
+ this.normalized = false;
+ }
+}
+
+export class Primitive {
+ constructor(attributes, elementCount, mode) {
+ this.attributes = attributes || [];
+ this.elementCount = elementCount || 0;
+ this.mode = mode || 4; // gl.TRIANGLES;
+ this.indexBuffer = null;
+ this.indexByteOffset = 0;
+ this.indexType = 0;
+ this._min = null;
+ this._max = null;
+ }
+
+ setIndexBuffer(indexBuffer, byteOffset, indexType) {
+ this.indexBuffer = indexBuffer;
+ this.indexByteOffset = byteOffset || 0;
+ this.indexType = indexType || 5123; // gl.UNSIGNED_SHORT;
+ }
+
+ setBounds(min, max) {
+ this._min = vec3.clone(min);
+ this._max = vec3.clone(max);
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/program.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/program.js
new file mode 100644
index 00000000000..2c01857236a
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/program.js
@@ -0,0 +1,114 @@
+// 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.
+
+export class Program {
+ constructor(gl, vertSrc, fragSrc, attribMap, defines) {
+ this._gl = gl;
+ this.program = gl.createProgram();
+ this.attrib = null;
+ this.uniform = null;
+ this.defines = {};
+
+ this._firstUse = true;
+ this._nextUseCallbacks = [];
+
+ let definesString = '';
+ if (defines) {
+ for (let define in defines) {
+ this.defines[define] = defines[define];
+ definesString += `#define ${define} ${defines[define]}\n`;
+ }
+ }
+
+ this._vertShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.attachShader(this.program, this._vertShader);
+ gl.shaderSource(this._vertShader, definesString + vertSrc);
+ gl.compileShader(this._vertShader);
+
+ this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.attachShader(this.program, this._fragShader);
+ gl.shaderSource(this._fragShader, definesString + fragSrc);
+ gl.compileShader(this._fragShader);
+
+ if (attribMap) {
+ this.attrib = {};
+ for (let attribName in attribMap) {
+ gl.bindAttribLocation(this.program, attribMap[attribName], attribName);
+ this.attrib[attribName] = attribMap[attribName];
+ }
+ }
+
+ gl.linkProgram(this.program);
+ }
+
+ onNextUse(callback) {
+ this._nextUseCallbacks.push(callback);
+ }
+
+ use() {
+ let gl = this._gl;
+
+ // If this is the first time the program has been used do all the error checking and
+ // attrib/uniform querying needed.
+ if (this._firstUse) {
+ this._firstUse = false;
+ if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
+ if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {
+ console.error('Vertex shader compile error: ' + gl.getShaderInfoLog(this._vertShader));
+ } else if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {
+ console.error('Fragment shader compile error: ' + gl.getShaderInfoLog(this._fragShader));
+ } else {
+ console.error('Program link error: ' + gl.getProgramInfoLog(this.program));
+ }
+ gl.deleteProgram(this.program);
+ this.program = null;
+ } else {
+ if (!this.attrib) {
+ this.attrib = {};
+ let attribCount = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);
+ for (let i = 0; i < attribCount; i++) {
+ let attribInfo = gl.getActiveAttrib(this.program, i);
+ this.attrib[attribInfo.name] = gl.getAttribLocation(this.program, attribInfo.name);
+ }
+ }
+
+ this.uniform = {};
+ let uniformCount = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
+ let uniformName = '';
+ for (let i = 0; i < uniformCount; i++) {
+ let uniformInfo = gl.getActiveUniform(this.program, i);
+ uniformName = uniformInfo.name.replace('[0]', '');
+ this.uniform[uniformName] = gl.getUniformLocation(this.program, uniformName);
+ }
+ }
+ gl.deleteShader(this._vertShader);
+ gl.deleteShader(this._fragShader);
+ }
+
+ gl.useProgram(this.program);
+
+ if (this._nextUseCallbacks.length) {
+ for (let callback of this._nextUseCallbacks) {
+ callback(this);
+ }
+ this._nextUseCallbacks = [];
+ }
+ }
+}
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
new file mode 100644
index 00000000000..661eb2bfcaf
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/renderer.js
@@ -0,0 +1,939 @@
+// 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.
+
+import {CAP, MAT_STATE, RENDER_ORDER, stateToBlendFunc} from './material.js';
+import {Node} from './node.js';
+import {Program} from './program.js';
+import {DataTexture, VideoTexture} from './texture.js';
+import {mat4, vec3} from '../math/gl-matrix.js';
+
+export const ATTRIB = {
+ POSITION: 1,
+ NORMAL: 2,
+ TANGENT: 3,
+ TEXCOORD_0: 4,
+ TEXCOORD_1: 5,
+ COLOR_0: 6,
+};
+
+export const ATTRIB_MASK = {
+ POSITION: 0x0001,
+ NORMAL: 0x0002,
+ TANGENT: 0x0004,
+ TEXCOORD_0: 0x0008,
+ TEXCOORD_1: 0x0010,
+ COLOR_0: 0x0020,
+};
+
+const GL = WebGLRenderingContext; // For enums
+
+const DEF_LIGHT_DIR = new Float32Array([-0.1, -1.0, -0.2]);
+const DEF_LIGHT_COLOR = new Float32Array([3.0, 3.0, 3.0]);
+
+const PRECISION_REGEX = new RegExp('precision (lowp|mediump|highp) float;');
+
+const VERTEX_SHADER_SINGLE_ENTRY = `
+uniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;
+
+void main() {
+ gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);
+}
+`;
+
+const VERTEX_SHADER_MULTI_ENTRY = `
+#ERROR Multiview rendering is not implemented
+void main() {
+ gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+}
+`;
+
+const FRAGMENT_SHADER_ENTRY = `
+void main() {
+ gl_FragColor = fragment_main();
+}
+`;
+
+function isPowerOfTwo(n) {
+ return (n & (n - 1)) === 0;
+}
+
+// Creates a WebGL context and initializes it with some common default state.
+export function createWebGLContext(glAttribs) {
+ glAttribs = glAttribs || {alpha: false};
+
+ let webglCanvas = document.createElement('canvas');
+ let contextTypes = glAttribs.webgl2 ? ['webgl2'] : ['webgl', 'experimental-webgl'];
+ let context = null;
+
+ for (let contextType of contextTypes) {
+ context = webglCanvas.getContext(contextType, glAttribs);
+ if (context) {
+ break;
+ }
+ }
+
+ if (!context) {
+ let webglType = (glAttribs.webgl2 ? 'WebGL 2' : 'WebGL');
+ console.error('This browser does not support ' + webglType + '.');
+ return null;
+ }
+
+ return context;
+}
+
+export class RenderView {
+ constructor(projectionMatrix, viewMatrix, viewport = null, eye = 'left') {
+ this.projectionMatrix = projectionMatrix;
+ this.viewMatrix = viewMatrix;
+ this.viewport = viewport;
+ // If an eye isn't given the left eye is assumed.
+ this._eye = eye;
+ this._eyeIndex = (eye == 'left' ? 0 : 1);
+ }
+
+ get eye() {
+ return this._eye;
+ }
+
+ set eye(value) {
+ this._eye = value;
+ this._eyeIndex = (value == 'left' ? 0 : 1);
+ }
+
+ get eyeIndex() {
+ return this._eyeIndex;
+ }
+}
+
+class RenderBuffer {
+ constructor(target, usage, buffer, length = 0) {
+ this._target = target;
+ this._usage = usage;
+ this._length = length;
+ if (buffer instanceof Promise) {
+ this._buffer = null;
+ this._promise = buffer.then((buffer) => {
+ this._buffer = buffer;
+ return this;
+ });
+ } else {
+ this._buffer = buffer;
+ this._promise = Promise.resolve(this);
+ }
+ }
+
+ waitForComplete() {
+ return this._promise;
+ }
+}
+
+class RenderPrimitiveAttribute {
+ constructor(primitiveAttribute) {
+ this._attrib_index = ATTRIB[primitiveAttribute.name];
+ this._componentCount = primitiveAttribute.componentCount;
+ this._componentType = primitiveAttribute.componentType;
+ this._stride = primitiveAttribute.stride;
+ this._byteOffset = primitiveAttribute.byteOffset;
+ this._normalized = primitiveAttribute.normalized;
+ }
+}
+
+class RenderPrimitiveAttributeBuffer {
+ constructor(buffer) {
+ this._buffer = buffer;
+ this._attributes = [];
+ }
+}
+
+class RenderPrimitive {
+ constructor(primitive) {
+ this._activeFrameId = 0;
+ this._instances = [];
+ this._material = null;
+
+ this.setPrimitive(primitive);
+ }
+
+ setPrimitive(primitive) {
+ this._mode = primitive.mode;
+ this._elementCount = primitive.elementCount;
+ this._promise = null;
+ this._vao = null;
+ this._complete = false;
+ this._attributeBuffers = [];
+ this._attributeMask = 0;
+
+ for (let attribute of primitive.attributes) {
+ this._attributeMask |= ATTRIB_MASK[attribute.name];
+ let renderAttribute = new RenderPrimitiveAttribute(attribute);
+ let foundBuffer = false;
+ for (let attributeBuffer of this._attributeBuffers) {
+ if (attributeBuffer._buffer == attribute.buffer) {
+ attributeBuffer._attributes.push(renderAttribute);
+ foundBuffer = true;
+ break;
+ }
+ }
+ if (!foundBuffer) {
+ let attributeBuffer = new RenderPrimitiveAttributeBuffer(attribute.buffer);
+ attributeBuffer._attributes.push(renderAttribute);
+ this._attributeBuffers.push(attributeBuffer);
+ }
+ }
+
+ this._indexBuffer = null;
+ this._indexByteOffset = 0;
+ this._indexType = 0;
+
+ if (primitive.indexBuffer) {
+ this._indexByteOffset = primitive.indexByteOffset;
+ this._indexType = primitive.indexType;
+ this._indexBuffer = primitive.indexBuffer;
+ }
+
+ if (primitive._min) {
+ this._min = vec3.clone(primitive._min);
+ this._max = vec3.clone(primitive._max);
+ } else {
+ this._min = null;
+ this._max = null;
+ }
+
+ if (this._material != null) {
+ this.waitForComplete(); // To flip the _complete flag.
+ }
+ }
+
+ setRenderMaterial(material) {
+ this._material = material;
+ this._promise = null;
+ this._complete = false;
+
+ if (this._material != null) {
+ this.waitForComplete(); // To flip the _complete flag.
+ }
+ }
+
+ markActive(frameId) {
+ if (this._complete && this._activeFrameId != frameId) {
+ if (this._material) {
+ if (!this._material.markActive(frameId)) {
+ return;
+ }
+ }
+ this._activeFrameId = frameId;
+ }
+ }
+
+ get samplers() {
+ return this._material._samplerDictionary;
+ }
+
+ get uniforms() {
+ return this._material._uniform_dictionary;
+ }
+
+ waitForComplete() {
+ if (!this._promise) {
+ if (!this._material) {
+ return Promise.reject('RenderPrimitive does not have a material');
+ }
+
+ let completionPromises = [];
+
+ for (let attributeBuffer of this._attributeBuffers) {
+ if (!attributeBuffer._buffer._buffer) {
+ completionPromises.push(attributeBuffer._buffer._promise);
+ }
+ }
+
+ if (this._indexBuffer && !this._indexBuffer._buffer) {
+ completionPromises.push(this._indexBuffer._promise);
+ }
+
+ this._promise = Promise.all(completionPromises).then(() => {
+ this._complete = true;
+ return this;
+ });
+ }
+ return this._promise;
+ }
+}
+
+export class RenderTexture {
+ constructor(texture) {
+ this._texture = texture;
+ this._complete = false;
+ this._activeFrameId = 0;
+ this._activeCallback = null;
+ }
+
+ markActive(frameId) {
+ if (this._activeCallback && this._activeFrameId != frameId) {
+ this._activeFrameId = frameId;
+ this._activeCallback(this);
+ }
+ }
+}
+
+const inverseMatrix = mat4.create();
+
+function setCap(gl, glEnum, cap, prevState, state) {
+ let change = (state & cap) - (prevState & cap);
+ if (!change) {
+ return;
+ }
+
+ if (change > 0) {
+ gl.enable(glEnum);
+ } else {
+ gl.disable(glEnum);
+ }
+}
+
+class RenderMaterialSampler {
+ constructor(renderer, materialSampler, index) {
+ this._renderer = renderer;
+ this._uniformName = materialSampler._uniformName;
+ this._renderTexture = renderer._getRenderTexture(materialSampler._texture);
+ this._index = index;
+ }
+
+ set texture(value) {
+ this._renderTexture = this._renderer._getRenderTexture(value);
+ }
+}
+
+class RenderMaterialUniform {
+ constructor(materialUniform) {
+ this._uniformName = materialUniform._uniformName;
+ this._uniform = null;
+ this._length = materialUniform._length;
+ if (materialUniform._value instanceof Array) {
+ this._value = new Float32Array(materialUniform._value);
+ } else {
+ this._value = new Float32Array([materialUniform._value]);
+ }
+ }
+
+ set value(value) {
+ if (this._value.length == 1) {
+ this._value[0] = value;
+ } else {
+ for (let i = 0; i < this._value.length; ++i) {
+ this._value[i] = value[i];
+ }
+ }
+ }
+}
+
+class RenderMaterial {
+ constructor(renderer, material, program) {
+ this._program = program;
+ this._state = material.state._state;
+ this._activeFrameId = 0;
+ this._completeForActiveFrame = false;
+
+ this._samplerDictionary = {};
+ this._samplers = [];
+ for (let i = 0; i < material._samplers.length; ++i) {
+ let renderSampler = new RenderMaterialSampler(renderer, material._samplers[i], i);
+ this._samplers.push(renderSampler);
+ this._samplerDictionary[renderSampler._uniformName] = renderSampler;
+ }
+
+ this._uniform_dictionary = {};
+ this._uniforms = [];
+ for (let uniform of material._uniforms) {
+ let renderUniform = new RenderMaterialUniform(uniform);
+ this._uniforms.push(renderUniform);
+ this._uniform_dictionary[renderUniform._uniformName] = renderUniform;
+ }
+
+ this._firstBind = true;
+
+ this._renderOrder = material.renderOrder;
+ if (this._renderOrder == RENDER_ORDER.DEFAULT) {
+ if (this._state & CAP.BLEND) {
+ this._renderOrder = RENDER_ORDER.TRANSPARENT;
+ } else {
+ this._renderOrder = RENDER_ORDER.OPAQUE;
+ }
+ }
+ }
+
+ bind(gl) {
+ // First time we do a binding, cache the uniform locations and remove
+ // unused uniforms from the list.
+ if (this._firstBind) {
+ for (let i = 0; i < this._samplers.length;) {
+ let sampler = this._samplers[i];
+ if (!this._program.uniform[sampler._uniformName]) {
+ this._samplers.splice(i, 1);
+ continue;
+ }
+ ++i;
+ }
+
+ for (let i = 0; i < this._uniforms.length;) {
+ let uniform = this._uniforms[i];
+ uniform._uniform = this._program.uniform[uniform._uniformName];
+ if (!uniform._uniform) {
+ this._uniforms.splice(i, 1);
+ continue;
+ }
+ ++i;
+ }
+ this._firstBind = false;
+ }
+
+ for (let sampler of this._samplers) {
+ gl.activeTexture(gl.TEXTURE0 + sampler._index);
+ if (sampler._renderTexture && sampler._renderTexture._complete) {
+ gl.bindTexture(gl.TEXTURE_2D, sampler._renderTexture._texture);
+ } else {
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+ }
+
+ for (let uniform of this._uniforms) {
+ switch (uniform._length) {
+ case 1: gl.uniform1fv(uniform._uniform, uniform._value); break;
+ case 2: gl.uniform2fv(uniform._uniform, uniform._value); break;
+ case 3: gl.uniform3fv(uniform._uniform, uniform._value); break;
+ case 4: gl.uniform4fv(uniform._uniform, uniform._value); break;
+ }
+ }
+ }
+
+ markActive(frameId) {
+ if (this._activeFrameId != frameId) {
+ this._activeFrameId = frameId;
+ this._completeForActiveFrame = true;
+ for (let i = 0; i < this._samplers.length; ++i) {
+ let sampler = this._samplers[i];
+ if (sampler._renderTexture) {
+ if (!sampler._renderTexture._complete) {
+ this._completeForActiveFrame = false;
+ break;
+ }
+ sampler._renderTexture.markActive(frameId);
+ }
+ }
+ }
+ return this._completeForActiveFrame;
+ }
+
+ // Material State fetchers
+ get cullFace() {
+ return !!(this._state & CAP.CULL_FACE);
+ }
+ get blend() {
+ return !!(this._state & CAP.BLEND);
+ }
+ get depthTest() {
+ return !!(this._state & CAP.DEPTH_TEST);
+ }
+ get stencilTest() {
+ return !!(this._state & CAP.STENCIL_TEST);
+ }
+ get colorMask() {
+ return !!(this._state & CAP.COLOR_MASK);
+ }
+ get depthMask() {
+ return !!(this._state & CAP.DEPTH_MASK);
+ }
+ get stencilMask() {
+ return !!(this._state & CAP.STENCIL_MASK);
+ }
+ get depthFunc() {
+ return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;
+ }
+ get blendFuncSrc() {
+ return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);
+ }
+ get blendFuncDst() {
+ return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);
+ }
+
+ // Only really for use from the renderer
+ _capsDiff(otherState) {
+ return (otherState & MAT_STATE.CAPS_RANGE) ^ (this._state & MAT_STATE.CAPS_RANGE);
+ }
+
+ _blendDiff(otherState) {
+ if (!(this._state & CAP.BLEND)) {
+ return 0;
+ }
+ return (otherState & MAT_STATE.BLEND_FUNC_RANGE) ^ (this._state & MAT_STATE.BLEND_FUNC_RANGE);
+ }
+
+ _depthFuncDiff(otherState) {
+ if (!(this._state & CAP.DEPTH_TEST)) {
+ return 0;
+ }
+ return (otherState & MAT_STATE.DEPTH_FUNC_RANGE) ^ (this._state & MAT_STATE.DEPTH_FUNC_RANGE);
+ }
+}
+
+export class Renderer {
+ constructor(gl) {
+ this._gl = gl || createWebGLContext();
+ this._frameId = 0;
+ this._programCache = {};
+ this._textureCache = {};
+ this._renderPrimitives = Array(RENDER_ORDER.DEFAULT);
+ this._cameraPositions = [];
+
+ this._vaoExt = gl.getExtension('OES_vertex_array_object');
+
+ let fragHighPrecision = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
+ this._defaultFragPrecision = fragHighPrecision.precision > 0 ? 'highp' : 'mediump';
+
+ this._depthMaskNeedsReset = false;
+ this._colorMaskNeedsReset = false;
+
+ this._globalLightColor = vec3.clone(DEF_LIGHT_COLOR);
+ this._globalLightDir = vec3.clone(DEF_LIGHT_DIR);
+ }
+
+ get gl() {
+ return this._gl;
+ }
+
+ set globalLightColor(value) {
+ vec3.copy(this._globalLightColor, value);
+ }
+
+ get globalLightColor() {
+ return vec3.clone(this._globalLightColor);
+ }
+
+ set globalLightDir(value) {
+ vec3.copy(this._globalLightDir, value);
+ }
+
+ get globalLightDir() {
+ return vec3.clone(this._globalLightDir);
+ }
+
+ createRenderBuffer(target, data, usage = GL.STATIC_DRAW) {
+ let gl = this._gl;
+ let glBuffer = gl.createBuffer();
+
+ if (data instanceof Promise) {
+ let renderBuffer = new RenderBuffer(target, usage, data.then((data) => {
+ gl.bindBuffer(target, glBuffer);
+ gl.bufferData(target, data, usage);
+ renderBuffer._length = data.byteLength;
+ return glBuffer;
+ }));
+ return renderBuffer;
+ } else {
+ gl.bindBuffer(target, glBuffer);
+ gl.bufferData(target, data, usage);
+ return new RenderBuffer(target, usage, glBuffer, data.byteLength);
+ }
+ }
+
+ updateRenderBuffer(buffer, data, offset = 0) {
+ if (buffer._buffer) {
+ let gl = this._gl;
+ gl.bindBuffer(buffer._target, buffer._buffer);
+ if (offset == 0 && buffer._length == data.byteLength) {
+ gl.bufferData(buffer._target, data, buffer._usage);
+ } else {
+ gl.bufferSubData(buffer._target, offset, data);
+ }
+ } else {
+ buffer.waitForComplete().then((buffer) => {
+ this.updateRenderBuffer(buffer, data, offset);
+ });
+ }
+ }
+
+ createRenderPrimitive(primitive, material) {
+ let renderPrimitive = new RenderPrimitive(primitive);
+
+ let program = this._getMaterialProgram(material, renderPrimitive);
+ let renderMaterial = new RenderMaterial(this, material, program);
+ renderPrimitive.setRenderMaterial(renderMaterial);
+
+ if (!this._renderPrimitives[renderMaterial._renderOrder]) {
+ this._renderPrimitives[renderMaterial._renderOrder] = [];
+ }
+
+ this._renderPrimitives[renderMaterial._renderOrder].push(renderPrimitive);
+
+ return renderPrimitive;
+ }
+
+ createMesh(primitive, material) {
+ let meshNode = new Node();
+ meshNode.addRenderPrimitive(this.createRenderPrimitive(primitive, material));
+ return meshNode;
+ }
+
+ drawViews(views, rootNode) {
+ if (!rootNode) {
+ return;
+ }
+
+ let gl = this._gl;
+ this._frameId++;
+
+ rootNode.markActive(this._frameId);
+
+ // If there's only one view then flip the algorithm a bit so that we're only
+ // setting the viewport once.
+ if (views.length == 1 && views[0].viewport) {
+ let vp = views[0].viewport;
+ this._gl.viewport(vp.x, vp.y, vp.width, vp.height);
+ }
+
+ // Get the positions of the 'camera' for each view matrix.
+ for (let i = 0; i < views.length; ++i) {
+ mat4.invert(inverseMatrix, views[i].viewMatrix);
+
+ if (this._cameraPositions.length <= i) {
+ this._cameraPositions.push(vec3.create());
+ }
+ let cameraPosition = this._cameraPositions[i];
+ vec3.set(cameraPosition, 0, 0, 0);
+ vec3.transformMat4(cameraPosition, cameraPosition, inverseMatrix);
+ }
+
+ // Draw each set of render primitives in order
+ for (let renderPrimitives of this._renderPrimitives) {
+ if (renderPrimitives && renderPrimitives.length) {
+ this._drawRenderPrimitiveSet(views, renderPrimitives);
+ }
+ }
+
+ if (this._vaoExt) {
+ this._vaoExt.bindVertexArrayOES(null);
+ }
+
+ if (this._depthMaskNeedsReset) {
+ gl.depthMask(true);
+ }
+ if (this._colorMaskNeedsReset) {
+ gl.colorMask(true, true, true, true);
+ }
+ }
+
+ _drawRenderPrimitiveSet(views, renderPrimitives) {
+ let gl = this._gl;
+ let program = null;
+ let material = null;
+ let attribMask = 0;
+
+ // Loop through every primitive known to the renderer.
+ for (let primitive of renderPrimitives) {
+ // Skip over those that haven't been marked as active for this frame.
+ if (primitive._activeFrameId != this._frameId) {
+ continue;
+ }
+
+ // Bind the primitive material's program if it's different than the one we
+ // were using for the previous primitive.
+ // TODO: The ording of this could be more efficient.
+ if (program != primitive._material._program) {
+ program = primitive._material._program;
+ program.use();
+
+ if (program.uniform.LIGHT_DIRECTION) {
+ gl.uniform3fv(program.uniform.LIGHT_DIRECTION, this._globalLightDir);
+ }
+
+ if (program.uniform.LIGHT_COLOR) {
+ gl.uniform3fv(program.uniform.LIGHT_COLOR, this._globalLightColor);
+ }
+
+ if (views.length == 1) {
+ gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, views[0].projectionMatrix);
+ gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, views[0].viewMatrix);
+ gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[0]);
+ gl.uniform1i(program.uniform.EYE_INDEX, views[0].eyeIndex);
+ }
+ }
+
+ if (material != primitive._material) {
+ this._bindMaterialState(primitive._material, material);
+ primitive._material.bind(gl, program, material);
+ material = primitive._material;
+ }
+
+ if (this._vaoExt) {
+ if (primitive._vao) {
+ this._vaoExt.bindVertexArrayOES(primitive._vao);
+ } else {
+ primitive._vao = this._vaoExt.createVertexArrayOES();
+ this._vaoExt.bindVertexArrayOES(primitive._vao);
+ this._bindPrimitive(primitive);
+ }
+ } else {
+ this._bindPrimitive(primitive, attribMask);
+ attribMask = primitive._attributeMask;
+ }
+
+ for (let i = 0; i < views.length; ++i) {
+ let view = views[i];
+ if (views.length > 1) {
+ if (view.viewport) {
+ let vp = view.viewport;
+ gl.viewport(vp.x, vp.y, vp.width, vp.height);
+ }
+ gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, view.projectionMatrix);
+ gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, view.viewMatrix);
+ gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[i]);
+ gl.uniform1i(program.uniform.EYE_INDEX, view.eyeIndex);
+ }
+
+ for (let instance of primitive._instances) {
+ if (instance._activeFrameId != this._frameId) {
+ continue;
+ }
+
+ gl.uniformMatrix4fv(program.uniform.MODEL_MATRIX, false, instance.worldMatrix);
+
+ if (primitive._indexBuffer) {
+ gl.drawElements(primitive._mode, primitive._elementCount,
+ primitive._indexType, primitive._indexByteOffset);
+ } else {
+ gl.drawArrays(primitive._mode, 0, primitive._elementCount);
+ }
+ }
+ }
+ }
+ }
+
+ _getRenderTexture(texture) {
+ if (!texture) {
+ return null;
+ }
+
+ let key = texture.textureKey;
+ if (!key) {
+ throw new Error('Texure does not have a valid key');
+ }
+
+ if (key in this._textureCache) {
+ return this._textureCache[key];
+ } else {
+ let gl = this._gl;
+ let textureHandle = gl.createTexture();
+
+ let renderTexture = new RenderTexture(textureHandle);
+ this._textureCache[key] = renderTexture;
+
+ if (texture instanceof DataTexture) {
+ gl.bindTexture(gl.TEXTURE_2D, textureHandle);
+ gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.width, texture.height,
+ 0, texture.format, texture._type, texture._data);
+ this._setSamplerParameters(texture);
+ renderTexture._complete = true;
+ } else {
+ texture.waitForComplete().then(() => {
+ gl.bindTexture(gl.TEXTURE_2D, textureHandle);
+ gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);
+ this._setSamplerParameters(texture);
+ renderTexture._complete = true;
+
+ if (texture instanceof VideoTexture) {
+ // Once the video starts playing, set a callback to update it's
+ // contents each frame.
+ texture._video.addEventListener('playing', () => {
+ renderTexture._activeCallback = () => {
+ if (!texture._video.paused && !texture._video.waiting) {
+ gl.bindTexture(gl.TEXTURE_2D, textureHandle);
+ gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);
+ }
+ };
+ });
+ }
+ });
+ }
+
+ return renderTexture;
+ }
+ }
+
+ _setSamplerParameters(texture) {
+ let gl = this._gl;
+
+ let sampler = texture.sampler;
+ let powerOfTwo = isPowerOfTwo(texture.width) && isPowerOfTwo(texture.height);
+ let mipmap = powerOfTwo && texture.mipmap;
+ if (mipmap) {
+ gl.generateMipmap(gl.TEXTURE_2D);
+ }
+
+ let minFilter = sampler.minFilter || (mipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
+ let wrapS = sampler.wrapS || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);
+ let wrapT = sampler.wrapT || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, sampler.magFilter || gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
+ }
+
+ _getProgramKey(name, defines) {
+ let key = `${name}:`;
+
+ for (let define in defines) {
+ key += `${define}=${defines[define]},`;
+ }
+
+ return key;
+ }
+
+ _getMaterialProgram(material, renderPrimitive) {
+ let materialName = material.materialName;
+ let vertexSource = material.vertexSource;
+ let fragmentSource = material.fragmentSource;
+
+ // These should always be defined for every material
+ if (materialName == null) {
+ throw new Error('Material does not have a name');
+ }
+ if (vertexSource == null) {
+ throw new Error(`Material "${materialName}" does not have a vertex source`);
+ }
+ if (fragmentSource == null) {
+ throw new Error(`Material "${materialName}" does not have a fragment source`);
+ }
+
+ let defines = material.getProgramDefines(renderPrimitive);
+ let key = this._getProgramKey(materialName, defines);
+
+ if (key in this._programCache) {
+ return this._programCache[key];
+ } else {
+ let multiview = false; // Handle this dynamically later
+ let fullVertexSource = vertexSource;
+ fullVertexSource += multiview ? VERTEX_SHADER_MULTI_ENTRY :
+ VERTEX_SHADER_SINGLE_ENTRY;
+
+ let precisionMatch = fragmentSource.match(PRECISION_REGEX);
+ let fragPrecisionHeader = precisionMatch ? '' : `precision ${this._defaultFragPrecision} float;\n`;
+
+ let fullFragmentSource = fragPrecisionHeader + fragmentSource;
+ fullFragmentSource += FRAGMENT_SHADER_ENTRY;
+
+ let program = new Program(this._gl, fullVertexSource, fullFragmentSource, ATTRIB, defines);
+ this._programCache[key] = program;
+
+ program.onNextUse((program) => {
+ // Bind the samplers to the right texture index. This is constant for
+ // the lifetime of the program.
+ for (let i = 0; i < material._samplers.length; ++i) {
+ let sampler = material._samplers[i];
+ let uniform = program.uniform[sampler._uniformName];
+ if (uniform) {
+ this._gl.uniform1i(uniform, i);
+ }
+ }
+ });
+
+ return program;
+ }
+ }
+
+ _bindPrimitive(primitive, attribMask) {
+ let gl = this._gl;
+
+ // If the active attributes have changed then update the active set.
+ if (attribMask != primitive._attributeMask) {
+ for (let attrib in ATTRIB) {
+ if (primitive._attributeMask & ATTRIB_MASK[attrib]) {
+ gl.enableVertexAttribArray(ATTRIB[attrib]);
+ } else {
+ gl.disableVertexAttribArray(ATTRIB[attrib]);
+ }
+ }
+ }
+
+ // Bind the primitive attributes and indices.
+ for (let attributeBuffer of primitive._attributeBuffers) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer._buffer._buffer);
+ for (let attrib of attributeBuffer._attributes) {
+ gl.vertexAttribPointer(
+ attrib._attrib_index, attrib._componentCount, attrib._componentType,
+ attrib._normalized, attrib._stride, attrib._byteOffset);
+ }
+ }
+
+ if (primitive._indexBuffer) {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, primitive._indexBuffer._buffer);
+ } else {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ }
+ }
+
+ _bindMaterialState(material, prevMaterial = null) {
+ let gl = this._gl;
+
+ let state = material._state;
+ let prevState = prevMaterial ? prevMaterial._state : ~state;
+
+ // Return early if both materials use identical state
+ if (state == prevState) {
+ return;
+ }
+
+ // Any caps bits changed?
+ if (material._capsDiff(prevState)) {
+ setCap(gl, gl.CULL_FACE, CAP.CULL_FACE, prevState, state);
+ setCap(gl, gl.BLEND, CAP.BLEND, prevState, state);
+ setCap(gl, gl.DEPTH_TEST, CAP.DEPTH_TEST, prevState, state);
+ setCap(gl, gl.STENCIL_TEST, CAP.STENCIL_TEST, prevState, state);
+
+ let colorMaskChange = (state & CAP.COLOR_MASK) - (prevState & CAP.COLOR_MASK);
+ if (colorMaskChange) {
+ let mask = colorMaskChange > 1;
+ this._colorMaskNeedsReset = !mask;
+ gl.colorMask(mask, mask, mask, mask);
+ }
+
+ let depthMaskChange = (state & CAP.DEPTH_MASK) - (prevState & CAP.DEPTH_MASK);
+ if (depthMaskChange) {
+ this._depthMaskNeedsReset = !(depthMaskChange > 1);
+ gl.depthMask(depthMaskChange > 1);
+ }
+
+ let stencilMaskChange = (state & CAP.STENCIL_MASK) - (prevState & CAP.STENCIL_MASK);
+ if (stencilMaskChange) {
+ gl.stencilMask(stencilMaskChange > 1);
+ }
+ }
+
+ // Blending enabled and blend func changed?
+ if (material._blendDiff(prevState)) {
+ gl.blendFunc(material.blendFuncSrc, material.blendFuncDst);
+ }
+
+ // Depth testing enabled and depth func changed?
+ if (material._depthFuncDiff(prevState)) {
+ gl.depthFunc(material.depthFunc);
+ }
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/texture.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/texture.js
new file mode 100644
index 00000000000..d8c70656884
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/core/texture.js
@@ -0,0 +1,213 @@
+// 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.
+
+const GL = WebGLRenderingContext; // For enums
+
+export class TextureSampler {
+ constructor() {
+ this.minFilter = null;
+ this.magFilter = null;
+ this.wrapS = null;
+ this.wrapT = null;
+ }
+}
+
+export class Texture {
+ constructor() {
+ this.sampler = new TextureSampler();
+ this.mipmap = true;
+ // TODO: Anisotropy
+ }
+
+ get format() {
+ return GL.RGBA;
+ }
+
+ get width() {
+ return 0;
+ }
+
+ get height() {
+ return 0;
+ }
+
+ get textureKey() {
+ return null;
+ }
+}
+
+export class ImageTexture extends Texture {
+ constructor(img) {
+ super();
+
+ this._img = img;
+ this._imgBitmap = null;
+
+ if (img.src && img.complete) {
+ if (img.naturalWidth) {
+ this._promise = this._finishImage();
+ } else {
+ this._promise = Promise.reject('Image provided had failed to load.');
+ }
+ } else {
+ this._promise = new Promise((resolve, reject) => {
+ img.addEventListener('load', () => resolve(this._finishImage()));
+ img.addEventListener('error', reject);
+ });
+ }
+ }
+
+ _finishImage() {
+ if (window.createImageBitmap) {
+ return window.createImageBitmap(this._img).then((imgBitmap) => {
+ this._imgBitmap = imgBitmap;
+ return Promise.resolve(this);
+ });
+ }
+ return Promise.resolve(this);
+ }
+
+ get format() {
+ // TODO: Can be RGB in some cases.
+ return GL.RGBA;
+ }
+
+ get width() {
+ return this._img.width;
+ }
+
+ get height() {
+ return this._img.height;
+ }
+
+ waitForComplete() {
+ return this._promise;
+ }
+
+ get textureKey() {
+ return this._img.src;
+ }
+
+ get source() {
+ return this._imgBitmap || this._img;
+ }
+}
+
+export class UrlTexture extends ImageTexture {
+ constructor(url) {
+ let img = new Image();
+ super(img);
+ img.src = url;
+ }
+}
+
+export class BlobTexture extends ImageTexture {
+ constructor(blob) {
+ let img = new Image();
+ super(img);
+ img.src = window.URL.createObjectURL(blob);
+ }
+}
+
+export class VideoTexture extends Texture {
+ constructor(video) {
+ super();
+
+ this._video = video;
+
+ if (video.readyState >= 2) {
+ this._promise = Promise.resolve(this);
+ } else if (video.error) {
+ this._promise = Promise.reject(video.error);
+ } else {
+ this._promise = new Promise((resolve, reject) => {
+ video.addEventListener('loadeddata', () => resolve(this));
+ video.addEventListener('error', reject);
+ });
+ }
+ }
+
+ get format() {
+ // TODO: Can be RGB in some cases.
+ return GL.RGBA;
+ }
+
+ get width() {
+ return this._video.videoWidth;
+ }
+
+ get height() {
+ return this._video.videoHeight;
+ }
+
+ waitForComplete() {
+ return this._promise;
+ }
+
+ get textureKey() {
+ return this._video.src;
+ }
+
+ get source() {
+ return this._video;
+ }
+}
+
+let nextDataTextureIndex = 0;
+
+export class DataTexture extends Texture {
+ constructor(data, width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE) {
+ super();
+
+ this._data = data;
+ this._width = width;
+ this._height = height;
+ this._format = format;
+ this._type = type;
+ this._key = `DATA_${nextDataTextureIndex}`;
+ nextDataTextureIndex++;
+ }
+
+ get format() {
+ return this._format;
+ }
+
+ get width() {
+ return this._width;
+ }
+
+ get height() {
+ return this._height;
+ }
+
+ get textureKey() {
+ return this._key;
+ }
+}
+
+export class ColorTexture extends DataTexture {
+ constructor(r, g, b, a) {
+ let colorData = new Uint8Array([r*255.0, g*255.0, b*255.0, a*255.0]);
+ super(colorData, 1, 1);
+
+ this.mipmap = false;
+ this._key = `COLOR_${colorData[0]}_${colorData[1]}_${colorData[2]}_${colorData[3]}`;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/cottontail.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/cottontail.js
new file mode 100644
index 00000000000..26eabba5333
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/cottontail.js
@@ -0,0 +1,43 @@
+// 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.
+
+export {Node} from './core/node.js';
+export {Renderer, createWebGLContext} from './core/renderer.js';
+export {UrlTexture} from './core/texture.js';
+
+export {PrimitiveStream} from './geometry/primitive-stream.js';
+export {BoxBuilder} from './geometry/box-builder.js';
+
+export {PbrMaterial} from './materials/pbr.js';
+
+export {mat4, mat3, vec3, vec4, quat} from './math/gl-matrix.js';
+
+export {BoundsRenderer} from './nodes/bounds-renderer.js';
+export {ButtonNode} from './nodes/button.js';
+export {DropShadowNode} from './nodes/drop-shadow.js';
+export {CubeSeaNode} from './nodes/cube-sea.js';
+export {Gltf2Node} from './nodes/gltf2.js';
+export {SkyboxNode} from './nodes/skybox.js';
+export {VideoNode} from './nodes/video.js';
+
+export {WebXRView, Scene} from './scenes/scene.js';
+
+export {FallbackHelper} from './util/fallback-helper.js';
+export {QueryArgs} from './util/query-args.js';
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/box-builder.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/box-builder.js
new file mode 100644
index 00000000000..c052032d523
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/box-builder.js
@@ -0,0 +1,110 @@
+// 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.
+
+import {GeometryBuilderBase} from './primitive-stream.js';
+
+export class BoxBuilder extends GeometryBuilderBase {
+ pushBox(min, max) {
+ let stream = this.primitiveStream;
+
+ let w = max[0] - min[0];
+ let h = max[1] - min[1];
+ let d = max[2] - min[2];
+
+ let wh = w * 0.5;
+ let hh = h * 0.5;
+ let dh = d * 0.5;
+
+ let cx = min[0] + wh;
+ let cy = min[1] + hh;
+ let cz = min[2] + dh;
+
+ stream.startGeometry();
+
+ // Bottom
+ let idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx+1, idx+2);
+ stream.pushTriangle(idx, idx+2, idx+3);
+
+ // X Y Z U V NX NY NZ
+ stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, -1.0, 0.0);
+ stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, -1.0, 0.0);
+ stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 0.0, 0.0, -1.0, 0.0);
+ stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 0.0, 0.0, -1.0, 0.0);
+
+ // Top
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx+2, idx+1);
+ stream.pushTriangle(idx, idx+3, idx+2);
+
+ stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 1.0, 0.0);
+ stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 1.0, 0.0);
+ stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 1.0, 0.0, 1.0, 0.0);
+ stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 1.0, 0.0, 1.0, 0.0);
+
+ // Left
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx+2, idx+1);
+ stream.pushTriangle(idx, idx+3, idx+2);
+
+ stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, -1.0, 0.0, 0.0);
+ stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, -1.0, 0.0, 0.0);
+ stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, -1.0, 0.0, 0.0);
+ stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, -1.0, 0.0, 0.0);
+
+ // Right
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx+1, idx+2);
+ stream.pushTriangle(idx, idx+2, idx+3);
+
+ stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 1.0, 0.0, 0.0);
+ stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 1.0, 0.0, 0.0);
+ stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 1.0, 0.0, 0.0);
+ stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 1.0, 0.0, 0.0);
+
+ // Back
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx+2, idx+1);
+ stream.pushTriangle(idx, idx+3, idx+2);
+
+ stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, 0.0, -1.0);
+ stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, 0.0, -1.0);
+ stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 0.0, -1.0);
+ stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 0.0, -1.0);
+
+ // Front
+ idx = stream.nextVertexIndex;
+ stream.pushTriangle(idx, idx+1, idx+2);
+ stream.pushTriangle(idx, idx+2, idx+3);
+
+ stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 0.0, 0.0, 1.0);
+ stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, 0.0, 0.0, 1.0);
+ stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, 0.0, 0.0, 1.0);
+ stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 0.0, 0.0, 1.0);
+
+ stream.endGeometry();
+ }
+
+ pushCube(center = [0, 0, 0], size = 1.0) {
+ let hs = size * 0.5;
+ this.pushBox([center[0] - hs, center[1] - hs, center[2] - hs],
+ [center[0] + hs, center[1] + hs, center[2] + hs]);
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/cone-builder.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/cone-builder.js
new file mode 100644
index 00000000000..b1270156661
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/cone-builder.js
@@ -0,0 +1,78 @@
+// 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.
+
+import {GeometryBuilderBase} from './primitive-stream.js';
+
+export class ConeBuilder extends GeometryBuilderBase {
+ pushCone(size = 0.5) {
+ let stream = this.primitiveStream;
+ let coneSegments = 64;
+
+ stream.startGeometry();
+
+ // Cone side vertices
+ for (let i = 0; i < coneSegments; ++i) {
+ let idx = stream.nextVertexIndex;
+
+ stream.pushTriangle(idx, idx + 1, idx + 2);
+
+ let rad = ((Math.PI * 2) / coneSegments) * i;
+ let rad2 = ((Math.PI * 2) / coneSegments) * (i + 1);
+
+ stream.pushVertex(
+ Math.sin(rad) * (size / 2), -size, Math.cos(rad) * (size / 2),
+ i / coneSegments, 0.0,
+ Math.sin(rad), 0.25, Math.cos(rad));
+
+ stream.pushVertex(
+ Math.sin(rad2) * (size / 2), -size, Math.cos(rad2) * (size / 2),
+ i / coneSegments, 0.0,
+ Math.sin(rad2), 0.25, Math.cos(rad2));
+
+ stream.pushVertex(
+ 0, size, 0,
+ i / coneSegments, 1.0,
+ Math.sin((rad + rad2) / 2), 0.25, Math.cos((rad + rad2) / 2));
+ }
+
+ // Base triangles
+ let baseCenterIndex = stream.nextVertexIndex;
+ stream.pushVertex(
+ 0, -size, 0,
+ 0.5, 0.5,
+ 0, -1, 0);
+ for (let i = 0; i < coneSegments; ++i) {
+ let idx = stream.nextVertexIndex;
+ stream.pushTriangle(baseCenterIndex, idx, idx + 1);
+ let rad = ((Math.PI * 2) / coneSegments) * i;
+ let rad2 = ((Math.PI * 2) / coneSegments) * (i + 1);
+ stream.pushVertex(
+ Math.sin(rad2) * (size / 2.0), -size, Math.cos(rad2) * (size / 2.0),
+ (Math.sin(rad2) + 1.0) * 0.5, (Math.cos(rad2) + 1.0) * 0.5,
+ 0, -1, 0);
+ stream.pushVertex(
+ Math.sin(rad) * (size / 2.0), -size, Math.cos(rad) * (size / 2.0),
+ (Math.sin(rad) + 1.0) * 0.5, (Math.cos(rad) + 1.0) * 0.5,
+ 0, -1, 0);
+ }
+
+ stream.endGeometry();
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/primitive-stream.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/primitive-stream.js
new file mode 100644
index 00000000000..92d48617f51
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/geometry/primitive-stream.js
@@ -0,0 +1,239 @@
+// 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.
+
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+import {mat3, vec3} from '../math/gl-matrix.js';
+
+const GL = WebGLRenderingContext; // For enums
+
+const tempVec3 = vec3.create();
+
+export class PrimitiveStream {
+ constructor(options) {
+ this._vertices = [];
+ this._indices = [];
+
+ this._geometryStarted = false;
+
+ this._vertexOffset = 0;
+ this._vertexIndex = 0;
+ this._highIndex = 0;
+
+ this._flipWinding = false;
+ this._invertNormals = false;
+ this._transform = null;
+ this._normalTransform = null;
+ this._min = null;
+ this._max = null;
+ }
+
+ set flipWinding(value) {
+ if (this._geometryStarted) {
+ throw new Error(`Cannot change flipWinding before ending the current geometry.`);
+ }
+ this._flipWinding = value;
+ }
+
+ get flipWinding() {
+ this._flipWinding;
+ }
+
+ set invertNormals(value) {
+ if (this._geometryStarted) {
+ throw new Error(`Cannot change invertNormals before ending the current geometry.`);
+ }
+ this._invertNormals = value;
+ }
+
+ get invertNormals() {
+ this._invertNormals;
+ }
+
+ set transform(value) {
+ if (this._geometryStarted) {
+ throw new Error(`Cannot change transform before ending the current geometry.`);
+ }
+ this._transform = value;
+ if (this._transform) {
+ if (!this._normalTransform) {
+ this._normalTransform = mat3.create();
+ }
+ mat3.fromMat4(this._normalTransform, this._transform);
+ }
+ }
+
+ get transform() {
+ this._transform;
+ }
+
+ startGeometry() {
+ if (this._geometryStarted) {
+ throw new Error(`Attempted to start a new geometry before the previous one was ended.`);
+ }
+
+ this._geometryStarted = true;
+ this._vertexIndex = 0;
+ this._highIndex = 0;
+ }
+
+ endGeometry() {
+ if (!this._geometryStarted) {
+ throw new Error(`Attempted to end a geometry before one was started.`);
+ }
+
+ if (this._highIndex >= this._vertexIndex) {
+ throw new Error(`Geometry contains indices that are out of bounds.
+ (Contains an index of ${this._highIndex} when the vertex count is ${this._vertexIndex})`);
+ }
+
+ this._geometryStarted = false;
+ this._vertexOffset += this._vertexIndex;
+
+ // TODO: Anything else need to be done to finish processing here?
+ }
+
+ pushVertex(x, y, z, u = 0, v = 0, nx = 0, ny = 0, nz = 1) {
+ if (!this._geometryStarted) {
+ throw new Error(`Cannot push vertices before calling startGeometry().`);
+ }
+
+ // Transform the incoming vertex if we have a transformation matrix
+ if (this._transform) {
+ tempVec3[0] = x;
+ tempVec3[1] = y;
+ tempVec3[2] = z;
+ vec3.transformMat4(tempVec3, tempVec3, this._transform);
+ x = tempVec3[0];
+ y = tempVec3[1];
+ z = tempVec3[2];
+
+ tempVec3[0] = nx;
+ tempVec3[1] = ny;
+ tempVec3[2] = nz;
+ vec3.transformMat3(tempVec3, tempVec3, this._normalTransform);
+ nx = tempVec3[0];
+ ny = tempVec3[1];
+ nz = tempVec3[2];
+ }
+
+ if (this._invertNormals) {
+ nx *= -1.0;
+ ny *= -1.0;
+ nz *= -1.0;
+ }
+
+ this._vertices.push(x, y, z, u, v, nx, ny, nz);
+
+ if (this._min) {
+ this._min[0] = Math.min(this._min[0], x);
+ this._min[1] = Math.min(this._min[1], y);
+ this._min[2] = Math.min(this._min[2], z);
+ this._max[0] = Math.max(this._max[0], x);
+ this._max[1] = Math.max(this._max[1], y);
+ this._max[2] = Math.max(this._max[2], z);
+ } else {
+ this._min = vec3.fromValues(x, y, z);
+ this._max = vec3.fromValues(x, y, z);
+ }
+
+ return this._vertexIndex++;
+ }
+
+ get nextVertexIndex() {
+ return this._vertexIndex;
+ }
+
+ pushTriangle(idxA, idxB, idxC) {
+ if (!this._geometryStarted) {
+ throw new Error(`Cannot push triangles before calling startGeometry().`);
+ }
+
+ this._highIndex = Math.max(this._highIndex, idxA, idxB, idxC);
+
+ idxA += this._vertexOffset;
+ idxB += this._vertexOffset;
+ idxC += this._vertexOffset;
+
+ if (this._flipWinding) {
+ this._indices.push(idxC, idxB, idxA);
+ } else {
+ this._indices.push(idxA, idxB, idxC);
+ }
+ }
+
+ clear() {
+ if (this._geometryStarted) {
+ throw new Error(`Cannot clear before ending the current geometry.`);
+ }
+
+ this._vertices = [];
+ this._indices = [];
+ this._vertexOffset = 0;
+ this._min = null;
+ this._max = null;
+ }
+
+ finishPrimitive(renderer) {
+ if (!this._vertexOffset) {
+ throw new Error(`Attempted to call finishPrimitive() before creating any geometry.`);
+ }
+
+ let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(this._vertices));
+ let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(this._indices));
+
+ let attribs = [
+ new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 32, 0),
+ new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 32, 12),
+ new PrimitiveAttribute('NORMAL', vertexBuffer, 3, GL.FLOAT, 32, 20),
+ ];
+
+ let primitive = new Primitive(attribs, this._indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+ primitive.setBounds(this._min, this._max);
+
+ return primitive;
+ }
+}
+
+export class GeometryBuilderBase {
+ constructor(primitiveStream) {
+ if (primitiveStream) {
+ this._stream = primitiveStream;
+ } else {
+ this._stream = new PrimitiveStream();
+ }
+ }
+
+ set primitiveStream(value) {
+ this._stream = value;
+ }
+
+ get primitiveStream() {
+ return this._stream;
+ }
+
+ finishPrimitive(renderer) {
+ return this._stream.finishPrimitive(renderer);
+ }
+
+ clear() {
+ this._stream.clear();
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/loaders/gltf2.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/loaders/gltf2.js
new file mode 100644
index 00000000000..8429adbebf9
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/loaders/gltf2.js
@@ -0,0 +1,427 @@
+// 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.
+
+import {PbrMaterial} from '../materials/pbr.js';
+import {Node} from '../core/node.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+import {ImageTexture, ColorTexture} from '../core/texture.js';
+
+const GL = WebGLRenderingContext; // For enums
+
+const GLB_MAGIC = 0x46546C67;
+const CHUNK_TYPE = {
+ JSON: 0x4E4F534A,
+ BIN: 0x004E4942,
+};
+
+function isAbsoluteUri(uri) {
+ let absRegEx = new RegExp('^'+window.location.protocol, 'i');
+ return !!uri.match(absRegEx);
+}
+
+function isDataUri(uri) {
+ let dataRegEx = /^data:/;
+ return !!uri.match(dataRegEx);
+}
+
+function resolveUri(uri, baseUrl) {
+ if (isAbsoluteUri(uri) || isDataUri(uri)) {
+ return uri;
+ }
+ return baseUrl + uri;
+}
+
+function getComponentCount(type) {
+ switch (type) {
+ case 'SCALAR': return 1;
+ case 'VEC2': return 2;
+ case 'VEC3': return 3;
+ case 'VEC4': return 4;
+ default: return 0;
+ }
+}
+
+/**
+ * Gltf2SceneLoader
+ * Loads glTF 2.0 scenes into a renderable node tree.
+ */
+
+export class Gltf2Loader {
+ constructor(renderer) {
+ this.renderer = renderer;
+ this._gl = renderer._gl;
+ }
+
+ loadFromUrl(url) {
+ return fetch(url)
+ .then((response) => {
+ let i = url.lastIndexOf('/');
+ let baseUrl = (i !== 0) ? url.substring(0, i + 1) : '';
+
+ if (url.endsWith('.gltf')) {
+ return response.json().then((json) => {
+ return this.loadFromJson(json, baseUrl);
+ });
+ } else if (url.endsWith('.glb')) {
+ return response.arrayBuffer().then((arrayBuffer) => {
+ return this.loadFromBinary(arrayBuffer, baseUrl);
+ });
+ } else {
+ throw new Error('Unrecognized file extension');
+ }
+ });
+ }
+
+ loadFromBinary(arrayBuffer, baseUrl) {
+ let headerView = new DataView(arrayBuffer, 0, 12);
+ let magic = headerView.getUint32(0, true);
+ let version = headerView.getUint32(4, true);
+ let length = headerView.getUint32(8, true);
+
+ if (magic != GLB_MAGIC) {
+ throw new Error('Invalid magic string in binary header.');
+ }
+
+ if (version != 2) {
+ throw new Error('Incompatible version in binary header.');
+ }
+
+ let chunks = {};
+ let chunkOffset = 12;
+ while (chunkOffset < length) {
+ let chunkHeaderView = new DataView(arrayBuffer, chunkOffset, 8);
+ let chunkLength = chunkHeaderView.getUint32(0, true);
+ let chunkType = chunkHeaderView.getUint32(4, true);
+ chunks[chunkType] = arrayBuffer.slice(chunkOffset + 8, chunkOffset + 8 + chunkLength);
+ chunkOffset += chunkLength + 8;
+ }
+
+ if (!chunks[CHUNK_TYPE.JSON]) {
+ throw new Error('File contained no json chunk.');
+ }
+
+ let decoder = new TextDecoder('utf-8');
+ let jsonString = decoder.decode(chunks[CHUNK_TYPE.JSON]);
+ let json = JSON.parse(jsonString);
+ return this.loadFromJson(json, baseUrl, chunks[CHUNK_TYPE.BIN]);
+ }
+
+ loadFromJson(json, baseUrl, binaryChunk) {
+ if (!json.asset) {
+ throw new Error('Missing asset description.');
+ }
+
+ if (json.asset.minVersion != '2.0' && json.asset.version != '2.0') {
+ throw new Error('Incompatible asset version.');
+ }
+
+ let buffers = [];
+ if (binaryChunk) {
+ buffers[0] = new Gltf2Resource({}, baseUrl, binaryChunk);
+ } else {
+ for (let buffer of json.buffers) {
+ buffers.push(new Gltf2Resource(buffer, baseUrl));
+ }
+ }
+
+ let bufferViews = [];
+ for (let bufferView of json.bufferViews) {
+ bufferViews.push(new Gltf2BufferView(bufferView, buffers));
+ }
+
+ let images = [];
+ if (json.images) {
+ for (let image of json.images) {
+ images.push(new Gltf2Resource(image, baseUrl));
+ }
+ }
+
+ let textures = [];
+ if (json.textures) {
+ for (let texture of json.textures) {
+ let image = images[texture.source];
+ let glTexture = image.texture(bufferViews);
+ if (texture.sampler) {
+ let sampler = sampler[texture.sampler];
+ glTexture.sampler.minFilter = sampler.minFilter;
+ glTexture.sampler.magFilter = sampler.magFilter;
+ glTexture.sampler.wrapS = sampler.wrapS;
+ glTexture.sampler.wrapT = sampler.wrapT;
+ }
+ textures.push(glTexture);
+ }
+ }
+
+ function getTexture(textureInfo) {
+ if (!textureInfo) {
+ return null;
+ }
+ return textures[textureInfo.index];
+ }
+
+ let materials = [];
+ if (json.materials) {
+ for (let material of json.materials) {
+ let glMaterial = new PbrMaterial();
+ let pbr = material.pbrMetallicRoughness || {};
+
+ glMaterial.baseColorFactor.value = pbr.baseColorFactor || [1, 1, 1, 1];
+ glMaterial.baseColor.texture = getTexture(pbr.baseColorTexture);
+ glMaterial.metallicRoughnessFactor.value = [
+ pbr.metallicFactor || 1.0,
+ pbr.roughnessFactor || 1.0,
+ ];
+ glMaterial.metallicRoughness.texture = getTexture(pbr.metallicRoughnessTexture);
+ glMaterial.normal.texture = getTexture(json.normalTexture);
+ glMaterial.occlusion.texture = getTexture(json.occlusionTexture);
+ glMaterial.occlusionStrength.value = (json.occlusionTexture && json.occlusionTexture.strength) ?
+ json.occlusionTexture.strength : 1.0;
+ glMaterial.emissiveFactor.value = material.emissiveFactor || [0, 0, 0];
+ glMaterial.emissive.texture = getTexture(json.emissiveTexture);
+ if (!glMaterial.emissive.texture && json.emissiveFactor) {
+ glMaterial.emissive.texture = new ColorTexture(1.0, 1.0, 1.0, 1.0);
+ }
+
+ switch (material.alphaMode) {
+ case 'BLEND':
+ glMaterial.state.blend = true;
+ break;
+ case 'MASK':
+ // Not really supported.
+ glMaterial.state.blend = true;
+ break;
+ default: // Includes 'OPAQUE'
+ glMaterial.state.blend = false;
+ }
+
+ // glMaterial.alpha_mode = material.alphaMode;
+ // glMaterial.alpha_cutoff = material.alphaCutoff;
+ glMaterial.state.cullFace = !(material.doubleSided);
+
+ materials.push(glMaterial);
+ }
+ }
+
+ let accessors = json.accessors;
+
+ let meshes = [];
+ for (let mesh of json.meshes) {
+ let glMesh = new Gltf2Mesh();
+ meshes.push(glMesh);
+
+ for (let primitive of mesh.primitives) {
+ let material = null;
+ if ('material' in primitive) {
+ material = materials[primitive.material];
+ } else {
+ // Create a "default" material if the primitive has none.
+ material = new PbrMaterial();
+ }
+
+ let attributes = [];
+ let elementCount = 0;
+ /* let glPrimitive = new Gltf2Primitive(primitive, material);
+ glMesh.primitives.push(glPrimitive); */
+
+ let min = null;
+ let max = null;
+
+ for (let name in primitive.attributes) {
+ let accessor = accessors[primitive.attributes[name]];
+ let bufferView = bufferViews[accessor.bufferView];
+ elementCount = accessor.count;
+
+ let glAttribute = new PrimitiveAttribute(
+ name,
+ bufferView.renderBuffer(this.renderer, GL.ARRAY_BUFFER),
+ getComponentCount(accessor.type),
+ accessor.componentType,
+ bufferView.byteStride || 0,
+ accessor.byteOffset || 0
+ );
+ glAttribute.normalized = accessor.normalized || false;
+
+ if (name == 'POSITION') {
+ min = accessor.min;
+ max = accessor.max;
+ }
+
+ attributes.push(glAttribute);
+ }
+
+ let glPrimitive = new Primitive(attributes, elementCount, primitive.mode);
+
+ if ('indices' in primitive) {
+ let accessor = accessors[primitive.indices];
+ let bufferView = bufferViews[accessor.bufferView];
+
+ glPrimitive.setIndexBuffer(
+ bufferView.renderBuffer(this.renderer, GL.ELEMENT_ARRAY_BUFFER),
+ accessor.byteOffset || 0,
+ accessor.componentType
+ );
+ glPrimitive.indexType = accessor.componentType;
+ glPrimitive.indexByteOffset = accessor.byteOffset || 0;
+ glPrimitive.elementCount = accessor.count;
+ }
+
+ if (min && max) {
+ glPrimitive.setBounds(min, max);
+ }
+
+ // After all the attributes have been processed, get a program that is
+ // appropriate for both the material and the primitive attributes.
+ glMesh.primitives.push(
+ this.renderer.createRenderPrimitive(glPrimitive, material));
+ }
+ }
+
+ let sceneNode = new Node();
+ let scene = json.scenes[json.scene];
+ for (let nodeId of scene.nodes) {
+ let node = json.nodes[nodeId];
+ sceneNode.addNode(
+ this.processNodes(node, json.nodes, meshes));
+ }
+
+ return sceneNode;
+ }
+
+ processNodes(node, nodes, meshes) {
+ let glNode = new Node();
+ glNode.name = node.name;
+
+ if ('mesh' in node) {
+ let mesh = meshes[node.mesh];
+ for (let primitive of mesh.primitives) {
+ glNode.addRenderPrimitive(primitive);
+ }
+ }
+
+ if (node.matrix) {
+ glNode.matrix = new Float32Array(node.matrix);
+ } else if (node.translation || node.rotation || node.scale) {
+ if (node.translation) {
+ glNode.translation = new Float32Array(node.translation);
+ }
+
+ if (node.rotation) {
+ glNode.rotation = new Float32Array(node.rotation);
+ }
+
+ if (node.scale) {
+ glNode.scale = new Float32Array(node.scale);
+ }
+ }
+
+ if (node.children) {
+ for (let nodeId of node.children) {
+ let node = nodes[nodeId];
+ glNode.addNode(this.processNodes(node, nodes, meshes));
+ }
+ }
+
+ return glNode;
+ }
+}
+
+class Gltf2Mesh {
+ constructor() {
+ this.primitives = [];
+ }
+}
+
+class Gltf2BufferView {
+ constructor(json, buffers) {
+ this.buffer = buffers[json.buffer];
+ this.byteOffset = json.byteOffset || 0;
+ this.byteLength = json.byteLength || null;
+ this.byteStride = json.byteStride;
+
+ this._viewPromise = null;
+ this._renderBuffer = null;
+ }
+
+ dataView() {
+ if (!this._viewPromise) {
+ this._viewPromise = this.buffer.arrayBuffer().then((arrayBuffer) => {
+ return new DataView(arrayBuffer, this.byteOffset, this.byteLength);
+ });
+ }
+ return this._viewPromise;
+ }
+
+ renderBuffer(renderer, target) {
+ if (!this._renderBuffer) {
+ this._renderBuffer = renderer.createRenderBuffer(target, this.dataView());
+ }
+ return this._renderBuffer;
+ }
+}
+
+class Gltf2Resource {
+ constructor(json, baseUrl, arrayBuffer) {
+ this.json = json;
+ this.baseUrl = baseUrl;
+
+ this._dataPromise = null;
+ this._texture = null;
+ if (arrayBuffer) {
+ this._dataPromise = Promise.resolve(arrayBuffer);
+ }
+ }
+
+ arrayBuffer() {
+ if (!this._dataPromise) {
+ if (isDataUri(this.json.uri)) {
+ let base64String = this.json.uri.replace('data:application/octet-stream;base64,', '');
+ let binaryArray = Uint8Array.from(atob(base64String), (c) => c.charCodeAt(0));
+ this._dataPromise = Promise.resolve(binaryArray.buffer);
+ return this._dataPromise;
+ }
+
+ this._dataPromise = fetch(resolveUri(this.json.uri, this.baseUrl))
+ .then((response) => response.arrayBuffer());
+ }
+ return this._dataPromise;
+ }
+
+ texture(bufferViews) {
+ if (!this._texture) {
+ let img = new Image();
+ this._texture = new ImageTexture(img);
+
+ if (this.json.uri) {
+ if (isDataUri(this.json.uri)) {
+ img.src = this.json.uri;
+ } else {
+ img.src = `${this.baseUrl}${this.json.uri}`;
+ }
+ } else {
+ let view = bufferViews[this.json.bufferView];
+ view.dataView().then((dataView) => {
+ let blob = new Blob([dataView], {type: this.json.mimeType});
+ img.src = window.URL.createObjectURL(blob);
+ });
+ }
+ }
+ return this._texture;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/materials/pbr.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/materials/pbr.js
new file mode 100644
index 00000000000..d3ff6593ba9
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/materials/pbr.js
@@ -0,0 +1,281 @@
+// 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.
+
+import {Material} from '../core/material.js';
+import {ATTRIB_MASK} from '../core/renderer.js';
+
+const VERTEX_SOURCE = `
+attribute vec3 POSITION, NORMAL;
+attribute vec2 TEXCOORD_0, TEXCOORD_1;
+
+uniform vec3 CAMERA_POSITION;
+uniform vec3 LIGHT_DIRECTION;
+
+varying vec3 vLight; // Vector from vertex to light.
+varying vec3 vView; // Vector from vertex to camera.
+varying vec2 vTex;
+
+#ifdef USE_NORMAL_MAP
+attribute vec4 TANGENT;
+varying mat3 vTBN;
+#else
+varying vec3 vNorm;
+#endif
+
+#ifdef USE_VERTEX_COLOR
+attribute vec4 COLOR_0;
+varying vec4 vCol;
+#endif
+
+vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));
+#ifdef USE_NORMAL_MAP
+ vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));
+ vec3 b = cross(n, t) * TANGENT.w;
+ vTBN = mat3(t, b, n);
+#else
+ vNorm = n;
+#endif
+
+#ifdef USE_VERTEX_COLOR
+ vCol = COLOR_0;
+#endif
+
+ vTex = TEXCOORD_0;
+ vec4 mPos = model * vec4(POSITION, 1.0);
+ vLight = -LIGHT_DIRECTION;
+ vView = CAMERA_POSITION - mPos.xyz;
+ return proj * view * mPos;
+}`;
+
+// These equations are borrowed with love from this docs from Epic because I
+// just don't have anything novel to bring to the PBR scene.
+// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
+const EPIC_PBR_FUNCTIONS = `
+vec3 lambertDiffuse(vec3 cDiff) {
+ return cDiff / M_PI;
+}
+
+float specD(float a, float nDotH) {
+ float aSqr = a * a;
+ float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);
+ return aSqr / (M_PI * f * f);
+}
+
+float specG(float roughness, float nDotL, float nDotV) {
+ float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;
+ float gl = nDotL / (nDotL * (1.0 - k) + k);
+ float gv = nDotV / (nDotV * (1.0 - k) + k);
+ return gl * gv;
+}
+
+vec3 specF(float vDotH, vec3 F0) {
+ float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;
+ float base = 2.0;
+ return F0 + (1.0 - F0) * pow(base, exponent);
+}`;
+
+const FRAGMENT_SOURCE = `
+#define M_PI 3.14159265
+
+uniform vec4 baseColorFactor;
+#ifdef USE_BASE_COLOR_MAP
+uniform sampler2D baseColorTex;
+#endif
+
+varying vec3 vLight;
+varying vec3 vView;
+varying vec2 vTex;
+
+#ifdef USE_VERTEX_COLOR
+varying vec4 vCol;
+#endif
+
+#ifdef USE_NORMAL_MAP
+uniform sampler2D normalTex;
+varying mat3 vTBN;
+#else
+varying vec3 vNorm;
+#endif
+
+#ifdef USE_METAL_ROUGH_MAP
+uniform sampler2D metallicRoughnessTex;
+#endif
+uniform vec2 metallicRoughnessFactor;
+
+#ifdef USE_OCCLUSION
+uniform sampler2D occlusionTex;
+uniform float occlusionStrength;
+#endif
+
+#ifdef USE_EMISSIVE_TEXTURE
+uniform sampler2D emissiveTex;
+#endif
+uniform vec3 emissiveFactor;
+
+uniform vec3 LIGHT_COLOR;
+
+const vec3 dielectricSpec = vec3(0.04);
+const vec3 black = vec3(0.0);
+
+${EPIC_PBR_FUNCTIONS}
+
+vec4 fragment_main() {
+#ifdef USE_BASE_COLOR_MAP
+ vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;
+#else
+ vec4 baseColor = baseColorFactor;
+#endif
+
+#ifdef USE_VERTEX_COLOR
+ baseColor *= vCol;
+#endif
+
+#ifdef USE_NORMAL_MAP
+ vec3 n = texture2D(normalTex, vTex).rgb;
+ n = normalize(vTBN * (2.0 * n - 1.0));
+#else
+ vec3 n = normalize(vNorm);
+#endif
+
+#ifdef FULLY_ROUGH
+ float metallic = 0.0;
+#else
+ float metallic = metallicRoughnessFactor.x;
+#endif
+
+ float roughness = metallicRoughnessFactor.y;
+
+#ifdef USE_METAL_ROUGH_MAP
+ vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);
+ metallic *= metallicRoughness.b;
+ roughness *= metallicRoughness.g;
+#endif
+
+ vec3 l = normalize(vLight);
+ vec3 v = normalize(vView);
+ vec3 h = normalize(l+v);
+
+ float nDotL = clamp(dot(n, l), 0.001, 1.0);
+ float nDotV = abs(dot(n, v)) + 0.001;
+ float nDotH = max(dot(n, h), 0.0);
+ float vDotH = max(dot(v, h), 0.0);
+
+ // From GLTF Spec
+ vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color
+ vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color
+ float a = roughness * roughness;
+
+#ifdef FULLY_ROUGH
+ vec3 specular = F0 * 0.45;
+#else
+ vec3 F = specF(vDotH, F0);
+ float D = specD(a, nDotH);
+ float G = specG(roughness, nDotL, nDotV);
+ vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);
+#endif
+ float halfLambert = dot(n, l) * 0.5 + 0.5;
+ halfLambert *= halfLambert;
+
+ vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;
+
+#ifdef USE_OCCLUSION
+ float occlusion = texture2D(occlusionTex, vTex).r;
+ color = mix(color, color * occlusion, occlusionStrength);
+#endif
+
+ vec3 emissive = emissiveFactor;
+#ifdef USE_EMISSIVE_TEXTURE
+ emissive *= texture2D(emissiveTex, vTex).rgb;
+#endif
+ color += emissive;
+
+ // gamma correction
+ //color = pow(color, vec3(1.0/2.2));
+
+ return vec4(color, baseColor.a);
+}`;
+
+export class PbrMaterial extends Material {
+ constructor() {
+ super();
+
+ this.baseColor = this.defineSampler('baseColorTex');
+ this.metallicRoughness = this.defineSampler('metallicRoughnessTex');
+ this.normal = this.defineSampler('normalTex');
+ this.occlusion = this.defineSampler('occlusionTex');
+ this.emissive = this.defineSampler('emissiveTex');
+
+ this.baseColorFactor = this.defineUniform('baseColorFactor', [1.0, 1.0, 1.0, 1.0]);
+ this.metallicRoughnessFactor = this.defineUniform('metallicRoughnessFactor', [1.0, 1.0]);
+ this.occlusionStrength = this.defineUniform('occlusionStrength', 1.0);
+ this.emissiveFactor = this.defineUniform('emissiveFactor', [0, 0, 0]);
+ }
+
+ get materialName() {
+ return 'PBR';
+ }
+
+ get vertexSource() {
+ return VERTEX_SOURCE;
+ }
+
+ get fragmentSource() {
+ return FRAGMENT_SOURCE;
+ }
+
+ getProgramDefines(renderPrimitive) {
+ let programDefines = {};
+
+ if (renderPrimitive._attributeMask & ATTRIB_MASK.COLOR_0) {
+ programDefines['USE_VERTEX_COLOR'] = 1;
+ }
+
+ if (renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0) {
+ if (this.baseColor.texture) {
+ programDefines['USE_BASE_COLOR_MAP'] = 1;
+ }
+
+ if (this.normal.texture && (renderPrimitive._attributeMask & ATTRIB_MASK.TANGENT)) {
+ programDefines['USE_NORMAL_MAP'] = 1;
+ }
+
+ if (this.metallicRoughness.texture) {
+ programDefines['USE_METAL_ROUGH_MAP'] = 1;
+ }
+
+ if (this.occlusion.texture) {
+ programDefines['USE_OCCLUSION'] = 1;
+ }
+
+ if (this.emissive.texture) {
+ programDefines['USE_EMISSIVE_TEXTURE'] = 1;
+ }
+ }
+
+ if ((!this.metallicRoughness.texture ||
+ !(renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0)) &&
+ this.metallicRoughnessFactor.value[1] == 1.0) {
+ programDefines['FULLY_ROUGH'] = 1;
+ }
+
+ return programDefines;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/gl-matrix.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/gl-matrix.js
new file mode 100644
index 00000000000..fbd22d39c84
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/gl-matrix.js
@@ -0,0 +1,43 @@
+// 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.
+
+import * as glMatrix from '../../node_modules/gl-matrix/src/gl-matrix/common.js';
+import * as mat2 from '../../node_modules/gl-matrix/src/gl-matrix/mat2.js';
+import * as mat2d from '../../node_modules/gl-matrix/src/gl-matrix/mat2d.js';
+import * as mat3 from '../../node_modules/gl-matrix/src/gl-matrix/mat3.js';
+import * as mat4 from '../../node_modules/gl-matrix/src/gl-matrix/mat4.js';
+import * as quat from '../../node_modules/gl-matrix/src/gl-matrix/quat.js';
+import * as quat2 from '../../node_modules/gl-matrix/src/gl-matrix/quat2.js';
+import * as vec2 from '../../node_modules/gl-matrix/src/gl-matrix/vec2.js';
+import * as vec3 from '../../node_modules/gl-matrix/src/gl-matrix/vec3.js';
+import * as vec4 from '../../node_modules/gl-matrix/src/gl-matrix/vec4.js';
+
+export {
+ glMatrix,
+ mat2,
+ mat2d,
+ mat3,
+ mat4,
+ quat,
+ quat2,
+ vec2,
+ vec3,
+ vec4,
+};
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/ray.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/ray.js
new file mode 100644
index 00000000000..3ece441d901
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/math/ray.js
@@ -0,0 +1,122 @@
+// 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.
+
+import {mat3, vec3} from './gl-matrix.js';
+
+let normalMat = mat3.create();
+
+const RAY_INTERSECTION_OFFSET = 0.02;
+
+export class Ray {
+ constructor(matrix = null) {
+ this.origin = vec3.create();
+
+ this._dir = vec3.create();
+ this._dir[2] = -1.0;
+
+ if (matrix) {
+ vec3.transformMat4(this.origin, this.origin, matrix);
+ mat3.fromMat4(normalMat, matrix);
+ vec3.transformMat3(this._dir, this._dir, normalMat);
+ }
+
+ // To force the inverse and sign calculations.
+ this.dir = this._dir;
+ }
+
+ get dir() {
+ return this._dir;
+ }
+
+ set dir(value) {
+ this._dir = vec3.copy(this._dir, value);
+ vec3.normalize(this._dir, this._dir);
+
+ this.inv_dir = vec3.fromValues(
+ 1.0 / this._dir[0],
+ 1.0 / this._dir[1],
+ 1.0 / this._dir[2]);
+
+ this.sign = [
+ (this.inv_dir[0] < 0) ? 1 : 0,
+ (this.inv_dir[1] < 0) ? 1 : 0,
+ (this.inv_dir[2] < 0) ? 1 : 0,
+ ];
+ }
+
+ // Borrowed from:
+ // eslint-disable-next-line max-len
+ // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
+ intersectsAABB(min, max) {
+ let r = this;
+
+ let bounds = [min, max];
+
+ let tmin = (bounds[r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];
+ let tmax = (bounds[1-r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];
+ let tymin = (bounds[r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];
+ let tymax = (bounds[1-r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];
+
+ if ((tmin > tymax) || (tymin > tmax)) {
+ return null;
+ }
+ if (tymin > tmin) {
+ tmin = tymin;
+ }
+ if (tymax < tmax) {
+ tmax = tymax;
+ }
+
+ let tzmin = (bounds[r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];
+ let tzmax = (bounds[1-r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];
+
+ if ((tmin > tzmax) || (tzmin > tmax)) {
+ return null;
+ }
+ if (tzmin > tmin) {
+ tmin = tzmin;
+ }
+ if (tzmax < tmax) {
+ tmax = tzmax;
+ }
+
+ let t = -1;
+ if (tmin > 0 && tmax > 0) {
+ t = Math.min(tmin, tmax);
+ } else if (tmin > 0) {
+ t = tmin;
+ } else if (tmax > 0) {
+ t = tmax;
+ } else {
+ // Intersection is behind the ray origin.
+ return null;
+ }
+
+ // Push ray intersection point back along the ray a bit so that cursors
+ // don't accidentally intersect with the hit surface.
+ t -= RAY_INTERSECTION_OFFSET;
+
+ // Return the point where the ray first intersected with the AABB.
+ let intersectionPoint = vec3.clone(this._dir);
+ vec3.scale(intersectionPoint, intersectionPoint, t);
+ vec3.add(intersectionPoint, intersectionPoint, this.origin);
+ return intersectionPoint;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js
new file mode 100644
index 00000000000..081efa14dcb
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js
@@ -0,0 +1,118 @@
+// 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.
+
+/*
+This file renders a passed in XRStageBounds object and attempts
+to render geometry on the floor to indicate where the bounds is.
+XRStageBounds' `geometry` is a series of XRStageBoundsPoints (in
+clockwise-order) with `x` and `z` properties for each.
+*/
+
+import {Material} from '../core/material.js';
+import {Node} from '../core/node.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+
+const GL = WebGLRenderingContext; // For enums
+
+class BoundsMaterial extends Material {
+ constructor() {
+ super();
+
+ this.state.blend = true;
+ this.state.blendFuncSrc = GL.SRC_ALPHA;
+ this.state.blendFuncDst = GL.ONE;
+ this.state.depthTest = false;
+ }
+
+ get materialName() {
+ return 'BOUNDS_RENDERER';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec2 POSITION;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ return proj * view * model * vec4(POSITION, 1.0);
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ precision mediump float;
+
+ vec4 fragment_main() {
+ return vec4(0.0, 1.0, 0.0, 0.3);
+ }`;
+ }
+}
+
+export class BoundsRenderer extends Node {
+ constructor() {
+ super();
+
+ this._stageBounds = null;
+ }
+
+ onRendererChanged(renderer) {
+ this.stageBounds = this._stageBounds;
+ }
+
+ get stageBounds() {
+ return this._stageBounds;
+ }
+
+ set stageBounds(stageBounds) {
+ if (this._stageBounds) {
+ this.clearRenderPrimitives();
+ }
+ this._stageBounds = stageBounds;
+ if (!stageBounds || stageBounds.length === 0 || !this._renderer) {
+ return;
+ }
+
+ let verts = [];
+ let indices = [];
+
+ // Tessellate the bounding points from XRStageBounds and connect
+ // each point to a neighbor and 0,0,0.
+ const pointCount = stageBounds.geometry.length;
+ for (let i = 0; i < pointCount; i++) {
+ const point = stageBounds.geometry[i];
+ verts.push(point.x, 0, point.z);
+ indices.push(i, i === 0 ? pointCount - 1 : i - 1, pointCount);
+ }
+ // Center point
+ verts.push(0, 0, 0);
+
+ let vertexBuffer = this._renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(verts));
+ let indexBuffer = this._renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ let attribs = [
+ new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 12, 0),
+ ];
+
+ let primitive = new Primitive(attribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+
+ let renderPrimitive = this._renderer.createRenderPrimitive(primitive, new BoundsMaterial());
+ this.addRenderPrimitive(renderPrimitive);
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/button.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/button.js
new file mode 100644
index 00000000000..6c6c4fe387e
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/button.js
@@ -0,0 +1,242 @@
+// 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.
+
+import {Material} from '../core/material.js';
+import {Node} from '../core/node.js';
+import {PrimitiveStream} from '../geometry/primitive-stream.js';
+
+const BUTTON_SIZE = 0.1;
+const BUTTON_CORNER_RADIUS = 0.025;
+const BUTTON_CORNER_SEGMENTS = 8;
+const BUTTON_ICON_SIZE = 0.07;
+const BUTTON_LAYER_DISTANCE = 0.005;
+const BUTTON_COLOR = 0.75;
+const BUTTON_ALPHA = 0.85;
+const BUTTON_HOVER_COLOR = 0.9;
+const BUTTON_HOVER_ALPHA = 1.0;
+const BUTTON_HOVER_SCALE = 1.1;
+const BUTTON_HOVER_TRANSITION_TIME_MS = 200;
+
+class ButtonMaterial extends Material {
+ constructor() {
+ super();
+
+ this.state.blend = true;
+
+ this.defineUniform('hoverAmount', 0);
+ }
+
+ get materialName() {
+ return 'BUTTON_MATERIAL';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec3 POSITION;
+
+ uniform float hoverAmount;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);
+ vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);
+ return proj * view * model * pos;
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ uniform float hoverAmount;
+
+ const vec4 default_color = vec4(${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_ALPHA});
+ const vec4 hover_color = vec4(${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_COLOR},
+ ${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_ALPHA});
+
+ vec4 fragment_main() {
+ return mix(default_color, hover_color, hoverAmount);
+ }`;
+ }
+}
+
+class ButtonIconMaterial extends Material {
+ constructor() {
+ super();
+
+ this.state.blend = true;
+
+ this.defineUniform('hoverAmount', 0);
+ this.icon = this.defineSampler('icon');
+ }
+
+ get materialName() {
+ return 'BUTTON_ICON_MATERIAL';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec3 POSITION;
+ attribute vec2 TEXCOORD_0;
+
+ uniform float hoverAmount;
+
+ varying vec2 vTexCoord;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vTexCoord = TEXCOORD_0;
+ float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);
+ vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);
+ return proj * view * model * pos;
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ uniform sampler2D icon;
+ varying vec2 vTexCoord;
+
+ vec4 fragment_main() {
+ return texture2D(icon, vTexCoord);
+ }`;
+ }
+}
+
+export class ButtonNode extends Node {
+ constructor(iconTexture, callback) {
+ super();
+
+ // All buttons are selectable by default.
+ this.selectable = true;
+
+ this._selectHandler = callback;
+ this._iconTexture = iconTexture;
+ this._hovered = false;
+ this._hoverT = 0;
+ }
+
+ get iconTexture() {
+ return this._iconTexture;
+ }
+
+ set iconTexture(value) {
+ if (this._iconTexture == value) {
+ return;
+ }
+
+ this._iconTexture = value;
+ this._iconRenderPrimitive.samplers.icon.texture = value;
+ }
+
+ onRendererChanged(renderer) {
+ let stream = new PrimitiveStream();
+
+ let hd = BUTTON_LAYER_DISTANCE * 0.5;
+
+ // Build a rounded rect for the background.
+ let hs = BUTTON_SIZE * 0.5;
+ let ihs = hs - BUTTON_CORNER_RADIUS;
+ stream.startGeometry();
+
+ // Rounded corners and sides
+ let segments = BUTTON_CORNER_SEGMENTS * 4;
+ for (let i = 0; i < segments; ++i) {
+ let rad = i * ((Math.PI * 2.0) / segments);
+ let x = Math.cos(rad) * BUTTON_CORNER_RADIUS;
+ let y = Math.sin(rad) * BUTTON_CORNER_RADIUS;
+ let section = Math.floor(i / BUTTON_CORNER_SEGMENTS);
+ switch (section) {
+ case 0:
+ x += ihs;
+ y += ihs;
+ break;
+ case 1:
+ x -= ihs;
+ y += ihs;
+ break;
+ case 2:
+ x -= ihs;
+ y -= ihs;
+ break;
+ case 3:
+ x += ihs;
+ y -= ihs;
+ break;
+ }
+
+ stream.pushVertex(x, y, -hd, 0, 0, 0, 0, 1);
+
+ if (i > 1) {
+ stream.pushTriangle(0, i-1, i);
+ }
+ }
+
+ stream.endGeometry();
+
+ let buttonPrimitive = stream.finishPrimitive(renderer);
+ this._buttonRenderPrimitive = renderer.createRenderPrimitive(buttonPrimitive, new ButtonMaterial());
+ this.addRenderPrimitive(this._buttonRenderPrimitive);
+
+ // Build a simple textured quad for the foreground.
+ hs = BUTTON_ICON_SIZE * 0.5;
+ stream.clear();
+ stream.startGeometry();
+
+ stream.pushVertex(-hs, hs, hd, 0, 0, 0, 0, 1);
+ stream.pushVertex(-hs, -hs, hd, 0, 1, 0, 0, 1);
+ stream.pushVertex(hs, -hs, hd, 1, 1, 0, 0, 1);
+ stream.pushVertex(hs, hs, hd, 1, 0, 0, 0, 1);
+
+ stream.pushTriangle(0, 1, 2);
+ stream.pushTriangle(0, 2, 3);
+
+ stream.endGeometry();
+
+ let iconPrimitive = stream.finishPrimitive(renderer);
+ let iconMaterial = new ButtonIconMaterial();
+ iconMaterial.icon.texture = this._iconTexture;
+ this._iconRenderPrimitive = renderer.createRenderPrimitive(iconPrimitive, iconMaterial);
+ this.addRenderPrimitive(this._iconRenderPrimitive);
+ }
+
+ onHoverStart() {
+ this._hovered = true;
+ }
+
+ onHoverEnd() {
+ this._hovered = false;
+ }
+
+ _updateHoverState() {
+ let t = this._hoverT / BUTTON_HOVER_TRANSITION_TIME_MS;
+ // Cubic Ease In/Out
+ // TODO: Get a better animation system
+ let hoverAmount = t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1;
+ this._buttonRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;
+ this._iconRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;
+ }
+
+ onUpdate(timestamp, frameDelta) {
+ if (this._hovered && this._hoverT < BUTTON_HOVER_TRANSITION_TIME_MS) {
+ this._hoverT = Math.min(BUTTON_HOVER_TRANSITION_TIME_MS, this._hoverT + frameDelta);
+ this._updateHoverState();
+ } else if (!this._hovered && this._hoverT > 0) {
+ this._hoverT = Math.max(0.0, this._hoverT - frameDelta);
+ this._updateHoverState();
+ }
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/cube-sea.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/cube-sea.js
new file mode 100644
index 00000000000..cade3c27d8b
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/cube-sea.js
@@ -0,0 +1,263 @@
+// 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.
+
+import {Material} from '../core/material.js';
+import {Node} from '../core/node.js';
+import {UrlTexture} from '../core/texture.js';
+import {BoxBuilder} from '../geometry/box-builder.js';
+import {mat4} from '../math/gl-matrix.js';
+
+class CubeSeaMaterial extends Material {
+ constructor(heavy = false) {
+ super();
+
+ this.heavy = heavy;
+
+ this.baseColor = this.defineSampler('baseColor');
+ }
+
+ get materialName() {
+ return 'CUBE_SEA';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec3 POSITION;
+ attribute vec2 TEXCOORD_0;
+ attribute vec3 NORMAL;
+
+ varying vec2 vTexCoord;
+ varying vec3 vLight;
+
+ const vec3 lightDir = vec3(0.75, 0.5, 1.0);
+ const vec3 ambientColor = vec3(0.5, 0.5, 0.5);
+ 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));
+ float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);
+ vLight = ambientColor + (lightColor * lightFactor);
+ vTexCoord = TEXCOORD_0;
+ return proj * view * model * vec4(POSITION, 1.0);
+ }`;
+ }
+
+ get fragmentSource() {
+ if (!this.heavy) {
+ return `
+ precision mediump float;
+ uniform sampler2D baseColor;
+ varying vec2 vTexCoord;
+ varying vec3 vLight;
+
+ vec4 fragment_main() {
+ return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);
+ }`;
+ } else {
+ // Used when we want to stress the GPU a bit more.
+ // Stolen with love from https://www.clicktorelease.com/code/codevember-2016/4/
+ return `
+ precision mediump float;
+
+ uniform sampler2D diffuse;
+ varying vec2 vTexCoord;
+ varying vec3 vLight;
+
+ vec2 dimensions = vec2(64, 64);
+ float seed = 0.42;
+
+ vec2 hash( vec2 p ) {
+ p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));
+ return fract(sin(p)*18.5453);
+ }
+
+ vec3 hash3( vec2 p ) {
+ vec3 q = vec3( dot(p,vec2(127.1,311.7)),
+ dot(p,vec2(269.5,183.3)),
+ dot(p,vec2(419.2,371.9)) );
+ return fract(sin(q)*43758.5453);
+ }
+
+ float iqnoise( in vec2 x, float u, float v ) {
+ vec2 p = floor(x);
+ vec2 f = fract(x);
+ float k = 1.0+63.0*pow(1.0-v,4.0);
+ float va = 0.0;
+ float wt = 0.0;
+ for( int j=-2; j<=2; j++ )
+ for( int i=-2; i<=2; i++ ) {
+ vec2 g = vec2( float(i),float(j) );
+ vec3 o = hash3( p + g )*vec3(u,u,1.0);
+ vec2 r = g - f + o.xy;
+ float d = dot(r,r);
+ float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );
+ va += o.z*ww;
+ wt += ww;
+ }
+ return va/wt;
+ }
+
+ // return distance, and cell id
+ vec2 voronoi( in vec2 x ) {
+ vec2 n = floor( x );
+ vec2 f = fract( x );
+ vec3 m = vec3( 8.0 );
+ for( int j=-1; j<=1; j++ )
+ for( int i=-1; i<=1; i++ ) {
+ vec2 g = vec2( float(i), float(j) );
+ vec2 o = hash( n + g );
+ vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));
+ float d = dot( r, r );
+ if( d<m.x )
+ m = vec3( d, o );
+ }
+ return vec2( sqrt(m.x), m.y+m.z );
+ }
+
+ vec4 fragment_main() {
+ vec2 uv = ( vTexCoord );
+ uv *= vec2( 10., 10. );
+ uv += seed;
+ vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );
+
+ vec2 c = voronoi( uv );
+ vec3 col = vec3( c.y / 2. );
+
+ float f = iqnoise( 1. * uv + c.y, p.x, p.y );
+ col *= 1.0 + .25 * vec3( f );
+
+ return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );
+ }`;
+ }
+ }
+}
+
+export class CubeSeaNode extends Node {
+ constructor(options = {}) {
+ super();
+
+ // Test variables
+ // If true, use a very heavyweight shader to stress the GPU.
+ this.heavyGpu = !!options.heavyGpu;
+
+ // Number and size of the static cubes. Warning, large values
+ // don't render right due to overflow of the int16 indices.
+ this.cubeCount = options.cubeCount || (this.heavyGpu ? 12 : 10);
+ this.cubeScale = options.cubeScale || 1.0;
+
+ // Draw only half the world cubes. Helps test variable render cost
+ // when combined with heavyGpu.
+ this.halfOnly = !!options.halfOnly;
+
+ // Automatically spin the world cubes. Intended for automated testing,
+ // not recommended for viewing in a headset.
+ this.autoRotate = !!options.autoRotate;
+
+ this._texture = new UrlTexture(options.imageUrl || 'media/textures/cube-sea.png');
+
+ this._material = new CubeSeaMaterial(this.heavyGpu);
+ this._material.baseColor.texture = this._texture;
+
+ this._renderPrimitive = null;
+ }
+
+ onRendererChanged(renderer) {
+ this._renderPrimitive = null;
+
+ let boxBuilder = new BoxBuilder();
+
+ // Build the spinning "hero" cubes
+ boxBuilder.pushCube([0, 0.25, -0.8], 0.1);
+ boxBuilder.pushCube([0.8, 0.25, 0], 0.1);
+ boxBuilder.pushCube([0, 0.25, 0.8], 0.1);
+ boxBuilder.pushCube([-0.8, 0.25, 0], 0.1);
+
+ let heroPrimitive = boxBuilder.finishPrimitive(renderer);
+
+ this.heroNode = renderer.createMesh(heroPrimitive, this._material);
+
+ this.rebuildCubes(boxBuilder);
+
+ this.cubeSeaNode = new Node();
+ this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive);
+
+ this.addNode(this.cubeSeaNode);
+ this.addNode(this.heroNode);
+
+ return this.waitForComplete();
+ }
+
+ rebuildCubes(boxBuilder) {
+ if (!this._renderer) {
+ return;
+ }
+
+ if (!boxBuilder) {
+ boxBuilder = new BoxBuilder();
+ } else {
+ boxBuilder.clear();
+ }
+
+ let size = 0.4 * this.cubeScale;
+
+ // Build the cube sea
+ let halfGrid = this.cubeCount * 0.5;
+ for (let x = 0; x < this.cubeCount; ++x) {
+ for (let y = 0; y < this.cubeCount; ++y) {
+ for (let z = 0; z < this.cubeCount; ++z) {
+ let pos = [x - halfGrid, y - halfGrid, z - halfGrid];
+ // Only draw cubes on one side. Useful for testing variable render
+ // cost that depends on view direction.
+ if (this.halfOnly && pos[0] < 0) {
+ continue;
+ }
+
+ // Don't place a cube in the center of the grid.
+ if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0) {
+ continue;
+ }
+
+ boxBuilder.pushCube(pos, size);
+ }
+ }
+ }
+
+ if (this.cubeCount > 12) {
+ // Each cube has 6 sides with 2 triangles and 3 indices per triangle, so
+ // the total number of indices needed is cubeCount^3 * 36. This exceeds
+ // the short index range past 12 cubes.
+ boxBuilder.indexType = 5125; // gl.UNSIGNED_INT
+ }
+ let cubeSeaPrimitive = boxBuilder.finishPrimitive(this._renderer);
+
+ if (!this._renderPrimitive) {
+ this._renderPrimitive = this._renderer.createRenderPrimitive(cubeSeaPrimitive, this._material);
+ } else {
+ this._renderPrimitive.setPrimitive(cubeSeaPrimitive);
+ }
+ }
+
+ onUpdate(timestamp, frameDelta) {
+ if (this.autoRotate) {
+ mat4.fromRotation(this.cubeSeaNode.matrix, timestamp / 500, [0, -1, 0]);
+ }
+ mat4.fromRotation(this.heroNode.matrix, timestamp / 2000, [0, 1, 0]);
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/drop-shadow.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/drop-shadow.js
new file mode 100644
index 00000000000..09db3f5bb5e
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/drop-shadow.js
@@ -0,0 +1,119 @@
+// 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.
+
+import {Material} from '../core/material.js';
+import {Node} from '../core/node.js';
+import {PrimitiveStream} from '../geometry/primitive-stream.js';
+
+const GL = WebGLRenderingContext; // For enums
+
+const SHADOW_SEGMENTS = 32;
+const SHADOW_GROUND_OFFSET = 0.01;
+const SHADOW_CENTER_ALPHA = 0.7;
+const SHADOW_INNER_ALPHA = 0.3;
+const SHADOW_OUTER_ALPHA = 0.0;
+const SHADOW_INNER_RADIUS = 0.6;
+const SHADOW_OUTER_RADIUS = 1.0;
+
+class DropShadowMaterial extends Material {
+ constructor() {
+ super();
+
+ this.state.blend = true;
+ this.state.blendFuncSrc = GL.ONE;
+ this.state.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;
+ this.state.depthFunc = GL.LEQUAL;
+ this.state.depthMask = false;
+ }
+
+ get materialName() {
+ return 'DROP_SHADOW_MATERIAL';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec3 POSITION;
+ attribute vec2 TEXCOORD_0;
+
+ varying float vShadow;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vShadow = TEXCOORD_0.x;
+ return proj * view * model * vec4(POSITION, 1.0);
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ varying float vShadow;
+
+ vec4 fragment_main() {
+ return vec4(0.0, 0.0, 0.0, vShadow);
+ }`;
+ }
+}
+
+export class DropShadowNode extends Node {
+ constructor(iconTexture, callback) {
+ super();
+ }
+
+ onRendererChanged(renderer) {
+ let stream = new PrimitiveStream();
+
+ stream.startGeometry();
+
+ // Shadow center
+ stream.pushVertex(0, SHADOW_GROUND_OFFSET, 0, SHADOW_CENTER_ALPHA);
+
+ let segRad = ((Math.PI * 2.0) / SHADOW_SEGMENTS);
+
+ let idx;
+ for (let i = 0; i < SHADOW_SEGMENTS; ++i) {
+ idx = stream.nextVertexIndex;
+
+ let rad = i * segRad;
+ let x = Math.cos(rad);
+ let y = Math.sin(rad);
+ stream.pushVertex(x * SHADOW_INNER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_INNER_RADIUS, SHADOW_INNER_ALPHA);
+ stream.pushVertex(x * SHADOW_OUTER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_OUTER_RADIUS, SHADOW_OUTER_ALPHA);
+
+ if (i > 0) {
+ // Inner circle
+ stream.pushTriangle(0, idx, idx-2);
+
+ // Outer circle
+ stream.pushTriangle(idx, idx+1, idx-1);
+ stream.pushTriangle(idx, idx-1, idx-2);
+ }
+ }
+
+ stream.pushTriangle(0, 1, idx);
+
+ stream.pushTriangle(1, 2, idx+1);
+ stream.pushTriangle(1, idx+1, idx);
+
+ stream.endGeometry();
+
+ let shadowPrimitive = stream.finishPrimitive(renderer);
+ this._shadowRenderPrimitive = renderer.createRenderPrimitive(shadowPrimitive, new DropShadowMaterial());
+ this.addRenderPrimitive(this._shadowRenderPrimitive);
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/gltf2.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/gltf2.js
new file mode 100644
index 00000000000..e8158f9d06d
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/gltf2.js
@@ -0,0 +1,77 @@
+// 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.
+
+import {Node} from '../core/node.js';
+import {Gltf2Loader} from '../loaders/gltf2.js';
+
+// Using a weak map here allows us to cache a loader per-renderer without
+// modifying the renderer object or leaking memory when it's garbage collected.
+let gltfLoaderMap = new WeakMap();
+
+export class Gltf2Node extends Node {
+ constructor(options) {
+ super();
+ this._url = options.url;
+
+ this._promise = null;
+ this._resolver = null;
+ this._rejecter = null;
+ }
+
+ onRendererChanged(renderer) {
+ let loader = gltfLoaderMap.get(renderer);
+ if (!loader) {
+ loader = new Gltf2Loader(renderer);
+ gltfLoaderMap.set(renderer, loader);
+ }
+
+ // Do we have a previously resolved promise? If so clear it.
+ if (!this._resolver && this._promise) {
+ this._promise = null;
+ }
+
+ this._ensurePromise();
+
+ loader.loadFromUrl(this._url).then((sceneNode) => {
+ this.addNode(sceneNode);
+ this._resolver(sceneNode.waitForComplete());
+ this._resolver = null;
+ this._rejecter = null;
+ }).catch((err) => {
+ this._rejecter(err);
+ this._resolver = null;
+ this._rejecter = null;
+ });
+ }
+
+ _ensurePromise() {
+ if (!this._promise) {
+ this._promise = new Promise((resolve, reject) => {
+ this._resolver = resolve;
+ this._rejecter = reject;
+ });
+ }
+ return this._promise;
+ }
+
+ waitForComplete() {
+ return this._ensurePromise();
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/input-renderer.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/input-renderer.js
new file mode 100644
index 00000000000..fd89982d085
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/input-renderer.js
@@ -0,0 +1,457 @@
+// 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.
+
+import {Material, RENDER_ORDER} from '../core/material.js';
+import {Node} from '../core/node.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+import {DataTexture} from '../core/texture.js';
+
+const GL = WebGLRenderingContext; // For enums
+
+// Laser texture data, 48x1 RGBA (not premultiplied alpha). This represents a
+// "cross section" of the laser beam with a bright core and a feathered edge.
+// Borrowed from Chromium source code.
+const LASER_TEXTURE_DATA = new Uint8Array([
+0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xbf, 0xbf, 0xbf, 0x04, 0xcc, 0xcc, 0xcc, 0x05,
+0xdb, 0xdb, 0xdb, 0x07, 0xcc, 0xcc, 0xcc, 0x0a, 0xd8, 0xd8, 0xd8, 0x0d, 0xd2, 0xd2, 0xd2, 0x11,
+0xce, 0xce, 0xce, 0x15, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x1f, 0xcd, 0xcd, 0xcd, 0x24,
+0xc8, 0xc8, 0xc8, 0x2a, 0xc9, 0xc9, 0xc9, 0x2f, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x39,
+0xc9, 0xc9, 0xc9, 0x3d, 0xc8, 0xc8, 0xc8, 0x41, 0xcb, 0xcb, 0xcb, 0x44, 0xee, 0xee, 0xee, 0x87,
+0xfa, 0xfa, 0xfa, 0xc8, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc9,
+0xfa, 0xfa, 0xfa, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc8,
+0xee, 0xee, 0xee, 0x87, 0xcb, 0xcb, 0xcb, 0x44, 0xc8, 0xc8, 0xc8, 0x41, 0xc9, 0xc9, 0xc9, 0x3d,
+0xc9, 0xc9, 0xc9, 0x39, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x2f, 0xc8, 0xc8, 0xc8, 0x2a,
+0xcd, 0xcd, 0xcd, 0x24, 0xce, 0xce, 0xce, 0x1f, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x15,
+0xd2, 0xd2, 0xd2, 0x11, 0xd8, 0xd8, 0xd8, 0x0d, 0xcc, 0xcc, 0xcc, 0x0a, 0xdb, 0xdb, 0xdb, 0x07,
+0xcc, 0xcc, 0xcc, 0x05, 0xbf, 0xbf, 0xbf, 0x04, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01,
+]);
+
+const LASER_LENGTH = 1.0;
+const LASER_DIAMETER = 0.01;
+const LASER_FADE_END = 0.535;
+const LASER_FADE_POINT = 0.5335;
+const LASER_DEFAULT_COLOR = [1.0, 1.0, 1.0, 0.25];
+
+const CURSOR_RADIUS = 0.004;
+const CURSOR_SHADOW_RADIUS = 0.007;
+const CURSOR_SHADOW_INNER_LUMINANCE = 0.5;
+const CURSOR_SHADOW_OUTER_LUMINANCE = 0.0;
+const CURSOR_SHADOW_INNER_OPACITY = 0.75;
+const CURSOR_SHADOW_OUTER_OPACITY = 0.0;
+const CURSOR_OPACITY = 0.9;
+const CURSOR_SEGMENTS = 16;
+const CURSOR_DEFAULT_COLOR = [1.0, 1.0, 1.0, 1.0];
+const CURSOR_DEFAULT_HIDDEN_COLOR = [0.5, 0.5, 0.5, 0.25];
+
+const DEFAULT_RESET_OPTIONS = {
+ controllers: true,
+ lasers: true,
+ cursors: true,
+};
+
+class LaserMaterial extends Material {
+ constructor() {
+ super();
+ this.renderOrder = RENDER_ORDER.ADDITIVE;
+ this.state.cullFace = false;
+ this.state.blend = true;
+ this.state.blendFuncSrc = GL.ONE;
+ this.state.blendFuncDst = GL.ONE;
+ this.state.depthMask = false;
+
+ this.laser = this.defineSampler('diffuse');
+ this.laser.texture = new DataTexture(LASER_TEXTURE_DATA, 48, 1);
+ this.laserColor = this.defineUniform('laserColor', LASER_DEFAULT_COLOR);
+ }
+
+ get materialName() {
+ return 'INPUT_LASER';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec3 POSITION;
+ attribute vec2 TEXCOORD_0;
+
+ varying vec2 vTexCoord;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vTexCoord = TEXCOORD_0;
+ return proj * view * model * vec4(POSITION, 1.0);
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ precision mediump float;
+
+ uniform vec4 laserColor;
+ uniform sampler2D diffuse;
+ varying vec2 vTexCoord;
+
+ const float fadePoint = ${LASER_FADE_POINT};
+ const float fadeEnd = ${LASER_FADE_END};
+
+ vec4 fragment_main() {
+ vec2 uv = vTexCoord;
+ float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);
+ float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);
+ vec4 color = laserColor * texture2D(diffuse, vTexCoord);
+ float opacity = color.a * front_fade_factor * back_fade_factor;
+ return vec4(color.rgb * opacity, opacity);
+ }`;
+ }
+}
+
+const CURSOR_VERTEX_SHADER = `
+attribute vec4 POSITION;
+
+varying float vLuminance;
+varying float vOpacity;
+
+vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vLuminance = POSITION.z;
+ vOpacity = POSITION.w;
+
+ // Billboarded, constant size vertex transform.
+ vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);
+ screenPos /= screenPos.w;
+ screenPos.xy += POSITION.xy;
+ return screenPos;
+}`;
+
+const CURSOR_FRAGMENT_SHADER = `
+precision mediump float;
+
+uniform vec4 cursorColor;
+varying float vLuminance;
+varying float vOpacity;
+
+vec4 fragment_main() {
+ vec3 color = cursorColor.rgb * vLuminance;
+ float opacity = cursorColor.a * vOpacity;
+ return vec4(color * opacity, opacity);
+}`;
+
+// Cursors are drawn as billboards that always face the camera and are rendered
+// as a fixed size no matter how far away they are.
+class CursorMaterial extends Material {
+ constructor() {
+ super();
+ this.renderOrder = RENDER_ORDER.ADDITIVE;
+ this.state.cullFace = false;
+ this.state.blend = true;
+ this.state.blendFuncSrc = GL.ONE;
+ this.state.depthMask = false;
+
+ this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_COLOR);
+ }
+
+ get materialName() {
+ return 'INPUT_CURSOR';
+ }
+
+ get vertexSource() {
+ return CURSOR_VERTEX_SHADER;
+ }
+
+ get fragmentSource() {
+ return CURSOR_FRAGMENT_SHADER;
+ }
+}
+
+class CursorHiddenMaterial extends Material {
+ constructor() {
+ super();
+ this.renderOrder = RENDER_ORDER.ADDITIVE;
+ this.state.cullFace = false;
+ this.state.blend = true;
+ this.state.blendFuncSrc = GL.ONE;
+ this.state.depthFunc = GL.GEQUAL;
+ this.state.depthMask = false;
+
+ this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_HIDDEN_COLOR);
+ }
+
+ // TODO: Rename to "program_name"
+ get materialName() {
+ return 'INPUT_CURSOR_2';
+ }
+
+ get vertexSource() {
+ return CURSOR_VERTEX_SHADER;
+ }
+
+ get fragmentSource() {
+ return CURSOR_FRAGMENT_SHADER;
+ }
+}
+
+export class InputRenderer extends Node {
+ constructor() {
+ super();
+
+ this._maxInputElements = 32;
+
+ this._controllers = [];
+ this._controllerNode = null;
+ this._controllerNodeHandedness = null;
+ this._lasers = null;
+ this._cursors = null;
+
+ this._activeControllers = 0;
+ this._activeLasers = 0;
+ this._activeCursors = 0;
+ }
+
+ onRendererChanged(renderer) {
+ this._controllers = [];
+ this._controllerNode = null;
+ this._controllerNodeHandedness = null;
+ this._lasers = null;
+ this._cursors = null;
+
+ this._activeControllers = 0;
+ this._activeLasers = 0;
+ this._activeCursors = 0;
+ }
+
+ setControllerMesh(controllerNode, handedness = 'right') {
+ this._controllerNode = controllerNode;
+ this._controllerNode.visible = false;
+ // FIXME: Temporary fix to initialize for cloning.
+ this.addNode(this._controllerNode);
+ this._controllerNodeHandedness = handedness;
+ }
+
+ addController(gripMatrix) {
+ if (!this._controllerNode) {
+ return;
+ }
+
+ let controller = null;
+ if (this._activeControllers < this._controllers.length) {
+ controller = this._controllers[this._activeControllers];
+ } else {
+ controller = this._controllerNode.clone();
+ this.addNode(controller);
+ this._controllers.push(controller);
+ }
+ this._activeControllers = (this._activeControllers + 1) % this._maxInputElements;
+
+ controller.matrix = gripMatrix;
+ controller.visible = true;
+ }
+
+ addLaserPointer(targetRay) {
+ // Create the laser pointer mesh if needed.
+ if (!this._lasers && this._renderer) {
+ this._lasers = [this._createLaserMesh()];
+ this.addNode(this._lasers[0]);
+ }
+
+ let laser = null;
+ if (this._activeLasers < this._lasers.length) {
+ laser = this._lasers[this._activeLasers];
+ } else {
+ laser = this._lasers[0].clone();
+ this.addNode(laser);
+ this._lasers.push(laser);
+ }
+ this._activeLasers = (this._activeLasers + 1) % this._maxInputElements;
+
+ laser.matrix = targetRay.transformMatrix;
+ laser.visible = true;
+ }
+
+ addCursor(cursorPos) {
+ // Create the cursor mesh if needed.
+ if (!this._cursors && this._renderer) {
+ this._cursors = [this._createCursorMesh()];
+ this.addNode(this._cursors[0]);
+ }
+
+ let cursor = null;
+ if (this._activeCursors < this._cursors.length) {
+ cursor = this._cursors[this._activeCursors];
+ } else {
+ cursor = this._cursors[0].clone();
+ this.addNode(cursor);
+ this._cursors.push(cursor);
+ }
+ this._activeCursors = (this._activeCursors + 1) % this._maxInputElements;
+
+ cursor.translation = cursorPos;
+ cursor.visible = true;
+ }
+
+ reset(options) {
+ if (!options) {
+ options = DEFAULT_RESET_OPTIONS;
+ }
+ if (this._controllers && options.controllers) {
+ for (let controller of this._controllers) {
+ controller.visible = false;
+ }
+ this._activeControllers = 0;
+ }
+ if (this._lasers && options.lasers) {
+ for (let laser of this._lasers) {
+ laser.visible = false;
+ }
+ this._activeLasers = 0;
+ }
+ if (this._cursors && options.cursors) {
+ for (let cursor of this._cursors) {
+ cursor.visible = false;
+ }
+ this._activeCursors = 0;
+ }
+ }
+
+ _createLaserMesh() {
+ let gl = this._renderer._gl;
+
+ let lr = LASER_DIAMETER * 0.5;
+ let ll = LASER_LENGTH;
+
+ // Laser is rendered as cross-shaped beam
+ let laserVerts = [
+ // X Y Z U V
+ 0.0, lr, 0.0, 0.0, 1.0,
+ 0.0, lr, -ll, 0.0, 0.0,
+ 0.0, -lr, 0.0, 1.0, 1.0,
+ 0.0, -lr, -ll, 1.0, 0.0,
+
+ lr, 0.0, 0.0, 0.0, 1.0,
+ lr, 0.0, -ll, 0.0, 0.0,
+ -lr, 0.0, 0.0, 1.0, 1.0,
+ -lr, 0.0, -ll, 1.0, 0.0,
+
+ 0.0, -lr, 0.0, 0.0, 1.0,
+ 0.0, -lr, -ll, 0.0, 0.0,
+ 0.0, lr, 0.0, 1.0, 1.0,
+ 0.0, lr, -ll, 1.0, 0.0,
+
+ -lr, 0.0, 0.0, 0.0, 1.0,
+ -lr, 0.0, -ll, 0.0, 0.0,
+ lr, 0.0, 0.0, 1.0, 1.0,
+ lr, 0.0, -ll, 1.0, 0.0,
+ ];
+ let laserIndices = [
+ 0, 1, 2, 1, 3, 2,
+ 4, 5, 6, 5, 7, 6,
+ 8, 9, 10, 9, 11, 10,
+ 12, 13, 14, 13, 15, 14,
+ ];
+
+ let laserVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(laserVerts));
+ let laserIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(laserIndices));
+
+ let laserIndexCount = laserIndices.length;
+
+ let laserAttribs = [
+ new PrimitiveAttribute('POSITION', laserVertexBuffer, 3, gl.FLOAT, 20, 0),
+ new PrimitiveAttribute('TEXCOORD_0', laserVertexBuffer, 2, gl.FLOAT, 20, 12),
+ ];
+
+ let laserPrimitive = new Primitive(laserAttribs, laserIndexCount);
+ laserPrimitive.setIndexBuffer(laserIndexBuffer);
+
+ let laserMaterial = new LaserMaterial();
+
+ let laserRenderPrimitive = this._renderer.createRenderPrimitive(laserPrimitive, laserMaterial);
+ let meshNode = new Node();
+ meshNode.addRenderPrimitive(laserRenderPrimitive);
+ return meshNode;
+ }
+
+ _createCursorMesh() {
+ let gl = this._renderer._gl;
+
+ // Cursor is a circular white dot with a dark "shadow" skirt around the edge
+ // that fades from black to transparent as it moves out from the center.
+ // Cursor verts are packed as [X, Y, Luminance, Opacity]
+ let cursorVerts = [];
+ let cursorIndices = [];
+
+ let segRad = (2.0 * Math.PI) / CURSOR_SEGMENTS;
+
+ // Cursor center
+ for (let i = 0; i < CURSOR_SEGMENTS; ++i) {
+ let rad = i * segRad;
+ let x = Math.cos(rad);
+ let y = Math.sin(rad);
+ cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS, 1.0, CURSOR_OPACITY);
+
+ if (i > 1) {
+ cursorIndices.push(0, i-1, i);
+ }
+ }
+
+ let indexOffset = CURSOR_SEGMENTS;
+
+ // Cursor Skirt
+ for (let i = 0; i < CURSOR_SEGMENTS; ++i) {
+ let rad = i * segRad;
+ let x = Math.cos(rad);
+ let y = Math.sin(rad);
+ cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS,
+ CURSOR_SHADOW_INNER_LUMINANCE, CURSOR_SHADOW_INNER_OPACITY);
+ cursorVerts.push(x * CURSOR_SHADOW_RADIUS, y * CURSOR_SHADOW_RADIUS,
+ CURSOR_SHADOW_OUTER_LUMINANCE, CURSOR_SHADOW_OUTER_OPACITY);
+
+ if (i > 0) {
+ let idx = indexOffset + (i * 2);
+ cursorIndices.push(idx-2, idx-1, idx);
+ cursorIndices.push(idx-1, idx+1, idx);
+ }
+ }
+
+ let idx = indexOffset + (CURSOR_SEGMENTS * 2);
+ cursorIndices.push(idx-2, idx-1, indexOffset);
+ cursorIndices.push(idx-1, indexOffset+1, indexOffset);
+
+ let cursorVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(cursorVerts));
+ let cursorIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cursorIndices));
+
+ let cursorIndexCount = cursorIndices.length;
+
+ let cursorAttribs = [
+ new PrimitiveAttribute('POSITION', cursorVertexBuffer, 4, gl.FLOAT, 16, 0),
+ ];
+
+ let cursorPrimitive = new Primitive(cursorAttribs, cursorIndexCount);
+ cursorPrimitive.setIndexBuffer(cursorIndexBuffer);
+
+ let cursorMaterial = new CursorMaterial();
+ let cursorHiddenMaterial = new CursorHiddenMaterial();
+
+ // Cursor renders two parts: The bright opaque cursor for areas where it's
+ // not obscured and a more transparent, darker version for areas where it's
+ // behind another object.
+ let cursorRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorMaterial);
+ let cursorHiddenRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorHiddenMaterial);
+ let meshNode = new Node();
+ meshNode.addRenderPrimitive(cursorRenderPrimitive);
+ meshNode.addRenderPrimitive(cursorHiddenRenderPrimitive);
+ return meshNode;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/seven-segment-text.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/seven-segment-text.js
new file mode 100644
index 00000000000..b8a07e4e8a6
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/seven-segment-text.js
@@ -0,0 +1,210 @@
+// 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.
+
+/*
+Renders simple text using a seven-segment LED style pattern. Only really good
+for numbers and a limited number of other characters.
+*/
+
+import {Material} from '../core/material.js';
+import {Node} from '../core/node.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+
+const TEXT_KERNING = 2.0;
+
+class SevenSegmentMaterial extends Material {
+ get materialName() {
+ return 'SEVEN_SEGMENT_TEXT';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec2 POSITION;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ return proj * view * model * vec4(POSITION, 0.0, 1.0);
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ precision mediump float;
+ const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);
+
+ vec4 fragment_main() {
+ return color;
+ }`;
+ }
+}
+
+export class SevenSegmentText extends Node {
+ constructor() {
+ super();
+
+ this._text = '';
+ this._charNodes = [];
+ }
+
+ onRendererChanged(renderer) {
+ this.clearNodes();
+ this._charNodes = [];
+
+ let vertices = [];
+ let segmentIndices = {};
+ let indices = [];
+
+ const width = 0.5;
+ const thickness = 0.25;
+
+ function defineSegment(id, left, top, right, bottom) {
+ let idx = vertices.length / 2;
+ vertices.push(
+ left, top,
+ right, top,
+ right, bottom,
+ left, bottom);
+
+ segmentIndices[id] = [
+ idx, idx+2, idx+1,
+ idx, idx+3, idx+2,
+ ];
+ }
+
+ let characters = {};
+ function defineCharacter(c, segments) {
+ let character = {
+ character: c,
+ offset: indices.length * 2,
+ count: 0,
+ };
+
+ for (let i = 0; i < segments.length; ++i) {
+ let idx = segments[i];
+ let segment = segmentIndices[idx];
+ character.count += segment.length;
+ indices.push(...segment);
+ }
+
+ characters[c] = character;
+ }
+
+ /* Segment layout is as follows:
+
+ |-0-|
+ 3 4
+ |-1-|
+ 5 6
+ |-2-|
+
+ */
+
+ defineSegment(0, -1, 1, width, 1-thickness);
+ defineSegment(1, -1, thickness*0.5, width, -thickness*0.5);
+ defineSegment(2, -1, -1+thickness, width, -1);
+ defineSegment(3, -1, 1, -1+thickness, -thickness*0.5);
+ defineSegment(4, width-thickness, 1, width, -thickness*0.5);
+ defineSegment(5, -1, thickness*0.5, -1+thickness, -1);
+ defineSegment(6, width-thickness, thickness*0.5, width, -1);
+
+
+ defineCharacter('0', [0, 2, 3, 4, 5, 6]);
+ defineCharacter('1', [4, 6]);
+ defineCharacter('2', [0, 1, 2, 4, 5]);
+ defineCharacter('3', [0, 1, 2, 4, 6]);
+ defineCharacter('4', [1, 3, 4, 6]);
+ defineCharacter('5', [0, 1, 2, 3, 6]);
+ defineCharacter('6', [0, 1, 2, 3, 5, 6]);
+ defineCharacter('7', [0, 4, 6]);
+ defineCharacter('8', [0, 1, 2, 3, 4, 5, 6]);
+ defineCharacter('9', [0, 1, 2, 3, 4, 6]);
+ defineCharacter('A', [0, 1, 3, 4, 5, 6]);
+ defineCharacter('B', [1, 2, 3, 5, 6]);
+ defineCharacter('C', [0, 2, 3, 5]);
+ defineCharacter('D', [1, 2, 4, 5, 6]);
+ defineCharacter('E', [0, 1, 2, 4, 6]);
+ defineCharacter('F', [0, 1, 3, 5]);
+ defineCharacter('P', [0, 1, 3, 4, 5]);
+ defineCharacter('-', [1]);
+ defineCharacter(' ', []);
+ defineCharacter('_', [2]); // Used for undefined characters
+
+ let gl = renderer.gl;
+ let vertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(vertices));
+ let indexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ let vertexAttribs = [
+ new PrimitiveAttribute('POSITION', vertexBuffer, 2, gl.FLOAT, 8, 0),
+ ];
+
+ let primitive = new Primitive(vertexAttribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+
+ let material = new SevenSegmentMaterial();
+
+ this._charPrimitives = {};
+ for (let char in characters) {
+ let charDef = characters[char];
+ primitive.elementCount = charDef.count;
+ primitive.indexByteOffset = charDef.offset;
+ this._charPrimitives[char] = renderer.createRenderPrimitive(primitive, material);
+ }
+
+ this.text = this._text;
+ }
+
+ get text() {
+ return this._text;
+ }
+
+ set text(value) {
+ this._text = value;
+
+ let i = 0;
+ let charPrimitive = null;
+ for (; i < value.length; ++i) {
+ if (value[i] in this._charPrimitives) {
+ charPrimitive = this._charPrimitives[value[i]];
+ } else {
+ charPrimitive = this._charPrimitives['_'];
+ }
+
+ if (this._charNodes.length <= i) {
+ let node = new Node();
+ node.addRenderPrimitive(charPrimitive);
+ let offset = i * TEXT_KERNING;
+ node.translation = [offset, 0, 0];
+ this._charNodes.push(node);
+ this.addNode(node);
+ } else {
+ // This is sort of an abuse of how these things are expected to work,
+ // but it's the cheapest thing I could think of that didn't break the
+ // world.
+ this._charNodes[i].clearRenderPrimitives();
+ this._charNodes[i].addRenderPrimitive(charPrimitive);
+ this._charNodes[i].visible = true;
+ }
+ }
+
+ // If there's any nodes left over make them invisible
+ for (; i < this._charNodes.length; ++i) {
+ this._charNodes[i].visible = false;
+ }
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/skybox.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/skybox.js
new file mode 100644
index 00000000000..dcd5a776a70
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/skybox.js
@@ -0,0 +1,162 @@
+// 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.
+
+/*
+Node for displaying 360 equirect images as a skybox.
+*/
+
+import {Material, RENDER_ORDER} from '../core/material.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+import {Node} from '../core/node.js';
+import {UrlTexture} from '../core/texture.js';
+
+const GL = WebGLRenderingContext; // For enums
+
+class SkyboxMaterial extends Material {
+ constructor() {
+ super();
+ this.renderOrder = RENDER_ORDER.SKY;
+ this.state.depthFunc = GL.LEQUAL;
+ this.state.depthMask = false;
+
+ this.image = this.defineSampler('diffuse');
+
+ this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',
+ [1.0, 1.0, 0.0, 0.0,
+ 1.0, 1.0, 0.0, 0.0], 4);
+ }
+
+ get materialName() {
+ return 'SKYBOX';
+ }
+
+ get vertexSource() {
+ return `
+ uniform int EYE_INDEX;
+ uniform vec4 texCoordScaleOffset[2];
+ attribute vec3 POSITION;
+ attribute vec2 TEXCOORD_0;
+ varying vec2 vTexCoord;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];
+ vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;
+ // Drop the translation portion of the view matrix
+ view[3].xyz = vec3(0.0, 0.0, 0.0);
+ vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);
+
+ // Returning the W component for both Z and W forces the geometry depth to
+ // the far plane. When combined with a depth func of LEQUAL this makes the
+ // sky write to any depth fragment that has not been written to yet.
+ return out_vec.xyww;
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ uniform sampler2D diffuse;
+ varying vec2 vTexCoord;
+
+ vec4 fragment_main() {
+ return texture2D(diffuse, vTexCoord);
+ }`;
+ }
+}
+
+export class SkyboxNode extends Node {
+ constructor(options) {
+ super();
+
+ this._url = options.url;
+ this._displayMode = options.displayMode || 'mono';
+ this._rotationY = options.rotationY || 0;
+ }
+
+ onRendererChanged(renderer) {
+ let vertices = [];
+ let indices = [];
+
+ let latSegments = 40;
+ let lonSegments = 40;
+
+ // Create the vertices/indices
+ for (let i=0; i <= latSegments; ++i) {
+ let theta = i * Math.PI / latSegments;
+ let sinTheta = Math.sin(theta);
+ let cosTheta = Math.cos(theta);
+
+ let idxOffsetA = i * (lonSegments+1);
+ let idxOffsetB = (i+1) * (lonSegments+1);
+
+ for (let j=0; j <= lonSegments; ++j) {
+ let phi = (j * 2 * Math.PI / lonSegments) + this._rotationY;
+ let x = Math.sin(phi) * sinTheta;
+ let y = cosTheta;
+ let z = -Math.cos(phi) * sinTheta;
+ let u = (j / lonSegments);
+ let v = (i / latSegments);
+
+ // Vertex shader will force the geometry to the far plane, so the
+ // radius of the sphere is immaterial.
+ vertices.push(x, y, z, u, v);
+
+ if (i < latSegments && j < lonSegments) {
+ let idxA = idxOffsetA+j;
+ let idxB = idxOffsetB+j;
+
+ indices.push(idxA, idxB, idxA+1,
+ idxB, idxB+1, idxA+1);
+ }
+ }
+ }
+
+ let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));
+ let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ let attribs = [
+ new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),
+ new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),
+ ];
+
+ let primitive = new Primitive(attribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+
+ let material = new SkyboxMaterial();
+ material.image.texture = new UrlTexture(this._url);
+
+ switch (this._displayMode) {
+ case 'mono':
+ material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,
+ 1.0, 1.0, 0.0, 0.0];
+ break;
+ case 'stereoTopBottom':
+ material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,
+ 1.0, 0.5, 0.0, 0.5];
+ break;
+ case 'stereoLeftRight':
+ material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,
+ 0.5, 1.0, 0.5, 0.0];
+ break;
+ }
+
+ let renderPrimitive = renderer.createRenderPrimitive(primitive, material);
+ this.addRenderPrimitive(renderPrimitive);
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/stats-viewer.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/stats-viewer.js
new file mode 100644
index 00000000000..1ef9bf0bddd
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/stats-viewer.js
@@ -0,0 +1,268 @@
+// 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.
+
+/*
+Heavily inspired by Mr. Doobs stats.js, this FPS counter is rendered completely
+with WebGL, allowing it to be shown in cases where overlaid HTML elements aren't
+usable (like WebXR), or if you want the FPS counter to be rendered as part of
+your scene.
+*/
+
+import {Material} from '../core/material.js';
+import {Node} from '../core/node.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+import {SevenSegmentText} from './seven-segment-text.js';
+
+const SEGMENTS = 30;
+const MAX_FPS = 90;
+
+class StatsMaterial extends Material {
+ get materialName() {
+ return 'STATS_VIEWER';
+ }
+
+ get vertexSource() {
+ return `
+ attribute vec3 POSITION;
+ attribute vec3 COLOR_0;
+ varying vec4 vColor;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vColor = vec4(COLOR_0, 1.0);
+ return proj * view * model * vec4(POSITION, 1.0);
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ precision mediump float;
+ varying vec4 vColor;
+
+ vec4 fragment_main() {
+ return vColor;
+ }`;
+ }
+}
+
+function segmentToX(i) {
+ return ((0.9/SEGMENTS) * i) - 0.45;
+}
+
+function fpsToY(value) {
+ return (Math.min(value, MAX_FPS) * (0.7 / MAX_FPS)) - 0.45;
+}
+
+function fpsToRGB(value) {
+ return {
+ r: Math.max(0.0, Math.min(1.0, 1.0 - (value/60))),
+ g: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),
+ b: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),
+ };
+}
+
+let now = (window.performance && performance.now) ? performance.now.bind(performance) : Date.now;
+
+export class StatsViewer extends Node {
+ constructor() {
+ super();
+
+ this._performanceMonitoring = false;
+
+ this._startTime = now();
+ this._prevFrameTime = this._startTime;
+ this._prevGraphUpdateTime = this._startTime;
+ this._frames = 0;
+ this._fpsAverage = 0;
+ this._fpsMin = 0;
+ this._fpsStep = this._performanceMonitoring ? 1000 : 250;
+ this._lastSegment = 0;
+
+ this._fpsVertexBuffer = null;
+ this._fpsRenderPrimitive = null;
+ this._fpsNode = null;
+
+ this._sevenSegmentNode = new SevenSegmentText();
+ // Hard coded because it doesn't change:
+ // Scale by 0.075 in X and Y
+ // Translate into upper left corner w/ z = 0.02
+ this._sevenSegmentNode.matrix = new Float32Array([
+ 0.075, 0, 0, 0,
+ 0, 0.075, 0, 0,
+ 0, 0, 1, 0,
+ -0.3625, 0.3625, 0.02, 1,
+ ]);
+ }
+
+ onRendererChanged(renderer) {
+ this.clearNodes();
+
+ let gl = renderer.gl;
+
+ let fpsVerts = [];
+ let fpsIndices = [];
+
+ // Graph geometry
+ for (let i = 0; i < SEGMENTS; ++i) {
+ // Bar top
+ fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+ fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+
+ // Bar bottom
+ fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+ fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);
+
+ let idx = i * 4;
+ fpsIndices.push(idx, idx+3, idx+1,
+ idx+3, idx, idx+2);
+ }
+
+ function addBGSquare(left, bottom, right, top, z, r, g, b) {
+ let idx = fpsVerts.length / 6;
+
+ fpsVerts.push(left, bottom, z, r, g, b);
+ fpsVerts.push(right, top, z, r, g, b);
+ fpsVerts.push(left, top, z, r, g, b);
+ fpsVerts.push(right, bottom, z, r, g, b);
+
+ fpsIndices.push(idx, idx+1, idx+2,
+ idx, idx+3, idx+1);
+ }
+
+ // Panel Background
+ addBGSquare(-0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.125);
+
+ // FPS Background
+ addBGSquare(-0.45, -0.45, 0.45, 0.25, 0.01, 0.0, 0.0, 0.4);
+
+ // 30 FPS line
+ addBGSquare(-0.45, fpsToY(30), 0.45, fpsToY(32), 0.015, 0.5, 0.0, 0.5);
+
+ // 60 FPS line
+ addBGSquare(-0.45, fpsToY(60), 0.45, fpsToY(62), 0.015, 0.2, 0.0, 0.75);
+
+ this._fpsVertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(fpsVerts), gl.DYNAMIC_DRAW);
+ let fpsIndexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(fpsIndices));
+
+ let fpsAttribs = [
+ new PrimitiveAttribute('POSITION', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 0),
+ new PrimitiveAttribute('COLOR_0', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 12),
+ ];
+
+ let fpsPrimitive = new Primitive(fpsAttribs, fpsIndices.length);
+ fpsPrimitive.setIndexBuffer(fpsIndexBuffer);
+ fpsPrimitive.setBounds([-0.5, -0.5, 0.0], [0.5, 0.5, 0.015]);
+
+ this._fpsRenderPrimitive = renderer.createRenderPrimitive(fpsPrimitive, new StatsMaterial());
+ this._fpsNode = new Node();
+ this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive);
+
+ this.addNode(this._fpsNode);
+ this.addNode(this._sevenSegmentNode);
+ }
+
+ get performanceMonitoring() {
+ return this._performanceMonitoring;
+ }
+
+ set performanceMonitoring(value) {
+ this._performanceMonitoring = value;
+ this._fpsStep = value ? 1000 : 250;
+ }
+
+ begin() {
+ this._startTime = now();
+ }
+
+ end() {
+ let time = now();
+
+ let frameFps = 1000 / (time - this._prevFrameTime);
+ this._prevFrameTime = time;
+ this._fpsMin = this._frames ? Math.min(this._fpsMin, frameFps) : frameFps;
+ this._frames++;
+
+ if (time > this._prevGraphUpdateTime + this._fpsStep) {
+ let intervalTime = time - this._prevGraphUpdateTime;
+ this._fpsAverage = Math.round(1000 / (intervalTime / this._frames));
+
+ // Draw both average and minimum FPS for this period
+ // so that dropped frames are more clearly visible.
+ this._updateGraph(this._fpsMin, this._fpsAverage);
+ if (this._performanceMonitoring) {
+ console.log(`Average FPS: ${this._fpsAverage} Min FPS: ${this._fpsMin}`);
+ }
+
+ this._prevGraphUpdateTime = time;
+ this._frames = 0;
+ this._fpsMin = 0;
+ }
+ }
+
+ _updateGraph(valueLow, valueHigh) {
+ let color = fpsToRGB(valueLow);
+ // Draw a range from the low to high value. Artificially widen the
+ // range a bit to ensure that near-equal values still remain
+ // visible - the logic here should match that used by the
+ // "60 FPS line" setup below. Hitting 60fps consistently will
+ // keep the top half of the 60fps background line visible.
+ let y0 = fpsToY(valueLow - 1);
+ let y1 = fpsToY(valueHigh + 1);
+
+ // Update the current segment with the new FPS value
+ let updateVerts = [
+ segmentToX(this._lastSegment), y1, 0.02, color.r, color.g, color.b,
+ segmentToX(this._lastSegment+1), y1, 0.02, color.r, color.g, color.b,
+ segmentToX(this._lastSegment), y0, 0.02, color.r, color.g, color.b,
+ segmentToX(this._lastSegment+1), y0, 0.02, color.r, color.g, color.b,
+ ];
+
+ // Re-shape the next segment into the green "progress" line
+ color.r = 0.2;
+ color.g = 1.0;
+ color.b = 0.2;
+
+ if (this._lastSegment == SEGMENTS - 1) {
+ // If we're updating the last segment we need to do two bufferSubDatas
+ // to update the segment and turn the first segment into the progress line.
+ this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),
+ this._lastSegment * 24 * 4);
+ updateVerts = [
+ segmentToX(0), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,
+ segmentToX(.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,
+ segmentToX(0), fpsToY(0), 0.02, color.r, color.g, color.b,
+ segmentToX(.25), fpsToY(0), 0.02, color.r, color.g, color.b,
+ ];
+ this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts), 0);
+ } else {
+ updateVerts.push(
+ segmentToX(this._lastSegment+1), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,
+ segmentToX(this._lastSegment+1.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,
+ segmentToX(this._lastSegment+1), fpsToY(0), 0.02, color.r, color.g, color.b,
+ segmentToX(this._lastSegment+1.25), fpsToY(0), 0.02, color.r, color.g, color.b
+ );
+ this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),
+ this._lastSegment * 24 * 4);
+ }
+
+ this._lastSegment = (this._lastSegment+1) % SEGMENTS;
+
+ this._sevenSegmentNode.text = `${this._fpsAverage} FP5`;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/video.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/video.js
new file mode 100644
index 00000000000..50ed9d91250
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/video.js
@@ -0,0 +1,145 @@
+// 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.
+
+/*
+Node for displaying 2D or stereo videos on a quad.
+*/
+
+import {Material} from '../core/material.js';
+import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
+import {Node} from '../core/node.js';
+import {VideoTexture} from '../core/texture.js';
+
+const GL = WebGLRenderingContext; // For enums
+
+class VideoMaterial extends Material {
+ constructor() {
+ super();
+
+ this.image = this.defineSampler('diffuse');
+
+ this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',
+ [1.0, 1.0, 0.0, 0.0,
+ 1.0, 1.0, 0.0, 0.0], 4);
+ }
+
+ get materialName() {
+ return 'VIDEO_PLAYER';
+ }
+
+ get vertexSource() {
+ return `
+ uniform int EYE_INDEX;
+ uniform vec4 texCoordScaleOffset[2];
+ attribute vec3 POSITION;
+ attribute vec2 TEXCOORD_0;
+ varying vec2 vTexCoord;
+
+ vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
+ vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];
+ vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;
+ vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);
+ return out_vec;
+ }`;
+ }
+
+ get fragmentSource() {
+ return `
+ uniform sampler2D diffuse;
+ varying vec2 vTexCoord;
+
+ vec4 fragment_main() {
+ return texture2D(diffuse, vTexCoord);
+ }`;
+ }
+}
+
+export class VideoNode extends Node {
+ constructor(options) {
+ super();
+
+ this._video = options.video;
+ this._displayMode = options.displayMode || 'mono';
+
+ this._video_texture = new VideoTexture(this._video);
+ }
+
+ get aspectRatio() {
+ let width = this._video.videoWidth;
+ let height = this._video.videoHeight;
+
+ switch (this._displayMode) {
+ case 'stereoTopBottom': height *= 0.5; break;
+ case 'stereoLeftRight': width *= 0.5; break;
+ }
+
+ if (!height || !width) {
+ return 1;
+ }
+
+ return width / height;
+ }
+
+ onRendererChanged(renderer) {
+ let vertices = [
+ -1.0, 1.0, 0.0, 0.0, 0.0,
+ 1.0, 1.0, 0.0, 1.0, 0.0,
+ 1.0, -1.0, 0.0, 1.0, 1.0,
+ -1.0, -1.0, 0.0, 0.0, 1.0,
+ ];
+ let indices = [
+ 0, 2, 1,
+ 0, 3, 2,
+ ];
+
+ let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));
+ let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
+
+ let attribs = [
+ new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),
+ new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),
+ ];
+
+ let primitive = new Primitive(attribs, indices.length);
+ primitive.setIndexBuffer(indexBuffer);
+ primitive.setBounds([-1.0, -1.0, 0.0], [1.0, 1.0, 0.015]);
+
+ let material = new VideoMaterial();
+ material.image.texture = this._video_texture;
+
+ switch (this._displayMode) {
+ case 'mono':
+ material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,
+ 1.0, 1.0, 0.0, 0.0];
+ break;
+ case 'stereoTopBottom':
+ material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,
+ 1.0, 0.5, 0.0, 0.5];
+ break;
+ case 'stereoLeftRight':
+ material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,
+ 0.5, 1.0, 0.5, 0.0];
+ break;
+ }
+
+ let renderPrimitive = renderer.createRenderPrimitive(primitive, material);
+ this.addRenderPrimitive(renderPrimitive);
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js
new file mode 100644
index 00000000000..ba60b82b1f0
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js
@@ -0,0 +1,304 @@
+// 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.
+
+import {RenderView} from '../core/renderer.js';
+import {InputRenderer} from '../nodes/input-renderer.js';
+import {StatsViewer} from '../nodes/stats-viewer.js';
+import {Node} from '../core/node.js';
+import {vec3, quat} from '../math/gl-matrix.js';
+
+export class WebXRView extends RenderView {
+ constructor(view, layer) {
+ super(
+ view ? view.projectionMatrix : null,
+ view ? view.viewMatrix : null,
+ (layer && view) ? layer.getViewport(view) : null,
+ view ? view.eye : 'left'
+ );
+ }
+}
+
+export class Scene extends Node {
+ constructor() {
+ super();
+
+ this._timestamp = -1;
+ this._frameDelta = 0;
+ this._statsStanding = false;
+ this._stats = null;
+ this._statsEnabled = false;
+ this.enableStats(true); // Ensure the stats are added correctly by default.
+
+ this._inputRenderer = null;
+ this._resetInputEndFrame = true;
+
+ this._lastTimestamp = 0;
+
+ this._hoverFrame = 0;
+ this._hoveredNodes = [];
+
+ this.clear = true;
+ }
+
+ setRenderer(renderer) {
+ this._setRenderer(renderer);
+ }
+
+ loseRenderer() {
+ if (this._renderer) {
+ this._stats = null;
+ this._renderer = null;
+ this._inputRenderer = null;
+ }
+ }
+
+ get inputRenderer() {
+ if (!this._inputRenderer) {
+ this._inputRenderer = new InputRenderer();
+ this.addNode(this._inputRenderer);
+ }
+ return this._inputRenderer;
+ }
+
+ // Helper function that automatically adds the appropriate visual elements for
+ // all input sources.
+ updateInputSources(frame, frameOfRef) {
+ // FIXME: Check for the existence of the API first. This check should be
+ // removed once the input API is part of the official spec.
+ if (!frame.session.getInputSources) {
+ return;
+ }
+
+ let inputSources = frame.session.getInputSources();
+
+ let newHoveredNodes = [];
+ let lastHoverFrame = this._hoverFrame;
+ this._hoverFrame++;
+
+ for (let inputSource of inputSources) {
+ let inputPose = frame.getInputPose(inputSource, frameOfRef);
+
+ if (!inputPose) {
+ continue;
+ }
+
+ // Any time that we have a grip matrix, we'll render a controller.
+ if (inputPose.gripMatrix) {
+ this.inputRenderer.addController(inputPose.gripMatrix);
+ }
+
+ if (inputPose.targetRay) {
+ if (inputSource.targetRayMode == 'tracked-pointer') {
+ // If we have a pointer matrix and the pointer origin is the users
+ // hand (as opposed to their head or the screen) use it to render
+ // a ray coming out of the input device to indicate the pointer
+ // direction.
+ this.inputRenderer.addLaserPointer(inputPose.targetRay);
+ }
+
+ // If we have a pointer matrix we can also use it to render a cursor
+ // for both handheld and gaze-based input sources.
+
+ // Check and see if the pointer is pointing at any selectable objects.
+ let hitResult = this.hitTest(inputPose.targetRay);
+
+ if (hitResult) {
+ // Render a cursor at the intersection point.
+ this.inputRenderer.addCursor(hitResult.intersection);
+
+ if (hitResult.node._hoverFrameId != lastHoverFrame) {
+ hitResult.node.onHoverStart();
+ }
+ hitResult.node._hoverFrameId = this._hoverFrame;
+ newHoveredNodes.push(hitResult.node);
+ } else {
+ // Statically render the cursor 1 meters down the ray since we didn't
+ // hit anything selectable.
+ let cursorDistance = 1.0;
+ let cursorPos = vec3.fromValues(
+ inputPose.targetRay.origin.x,
+ inputPose.targetRay.origin.y,
+ inputPose.targetRay.origin.z
+ );
+ vec3.add(cursorPos, cursorPos, [
+ inputPose.targetRay.direction.x * cursorDistance,
+ inputPose.targetRay.direction.y * cursorDistance,
+ inputPose.targetRay.direction.z * cursorDistance,
+ ]);
+ // let cursorPos = vec3.fromValues(0, 0, -1.0);
+ // vec3.transformMat4(cursorPos, cursorPos, inputPose.targetRay);
+ this.inputRenderer.addCursor(cursorPos);
+ }
+ }
+ }
+
+ for (let hoverNode of this._hoveredNodes) {
+ if (hoverNode._hoverFrameId != this._hoverFrame) {
+ hoverNode.onHoverEnd();
+ }
+ }
+
+ this._hoveredNodes = newHoveredNodes;
+ }
+
+ handleSelect(inputSource, frame, frameOfRef) {
+ let inputPose = frame.getInputPose(inputSource, frameOfRef);
+
+ if (!inputPose) {
+ return;
+ }
+
+ this.handleSelectPointer(inputPose.targetRay);
+ }
+
+ handleSelectPointer(targetRay) {
+ if (targetRay) {
+ // Check and see if the pointer is pointing at any selectable objects.
+ let hitResult = this.hitTest(targetRay);
+
+ if (hitResult) {
+ // Render a cursor at the intersection point.
+ hitResult.node.handleSelect();
+ }
+ }
+ }
+
+ enableStats(enable) {
+ if (enable == this._statsEnabled) {
+ return;
+ }
+
+ this._statsEnabled = enable;
+
+ if (enable) {
+ this._stats = new StatsViewer();
+ this._stats.selectable = true;
+ this.addNode(this._stats);
+
+ if (this._statsStanding) {
+ this._stats.translation = [0, 1.4, -0.75];
+ } else {
+ this._stats.translation = [0, -0.3, -0.5];
+ }
+ this._stats.scale = [0.3, 0.3, 0.3];
+ quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);
+ } else if (!enable) {
+ if (this._stats) {
+ this.removeNode(this._stats);
+ this._stats = null;
+ }
+ }
+ }
+
+ standingStats(enable) {
+ this._statsStanding = enable;
+ if (this._stats) {
+ if (this._statsStanding) {
+ this._stats.translation = [0, 1.4, -0.75];
+ } else {
+ this._stats.translation = [0, -0.3, -0.5];
+ }
+ this._stats.scale = [0.3, 0.3, 0.3];
+ quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);
+ }
+ }
+
+ draw(projectionMatrix, viewMatrix, eye) {
+ let view = new RenderView();
+ view.projectionMatrix = projectionMatrix;
+ view.viewMatrix = viewMatrix;
+ if (eye) {
+ view.eye = eye;
+ }
+
+ this.drawViewArray([view]);
+ }
+
+ /** Draws the scene into the base layer of the XRFrame's session */
+ drawXRFrame(xrFrame, pose) {
+ if (!this._renderer || !pose) {
+ return;
+ }
+
+ let gl = this._renderer.gl;
+ let session = xrFrame.session;
+ // Assumed to be a XRWebGLLayer for now.
+ let layer = session.baseLayer;
+
+ if (!gl) {
+ return;
+ }
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
+
+ if (this.clear) {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ }
+
+ let views = [];
+ for (let view of pose.views) {
+ views.push(new WebXRView(view, layer));
+ }
+
+ this.drawViewArray(views);
+ }
+
+ drawViewArray(views) {
+ // Don't draw when we don't have a valid context
+ if (!this._renderer) {
+ return;
+ }
+
+ this._renderer.drawViews(views, this);
+ }
+
+ startFrame() {
+ let prevTimestamp = this._timestamp;
+ this._timestamp = performance.now();
+ if (this._stats) {
+ this._stats.begin();
+ }
+
+ if (prevTimestamp >= 0) {
+ this._frameDelta = this._timestamp - prevTimestamp;
+ } else {
+ this._frameDelta = 0;
+ }
+
+ this._update(this._timestamp, this._frameDelta);
+
+ return this._frameDelta;
+ }
+
+ endFrame() {
+ if (this._inputRenderer && this._resetInputEndFrame) {
+ this._inputRenderer.reset();
+ }
+
+ if (this._stats) {
+ this._stats.end();
+ }
+ }
+
+ // Override to load scene resources on construction or context restore.
+ onLoadScene(renderer) {
+ return Promise.resolve();
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/fallback-helper.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/fallback-helper.js
new file mode 100644
index 00000000000..e5668a1776a
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/fallback-helper.js
@@ -0,0 +1,144 @@
+// 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.
+
+import {mat4} from '../math/gl-matrix.js';
+
+const LOOK_SPEED = 0.0025;
+
+export class FallbackHelper {
+ constructor(scene, gl) {
+ this.scene = scene;
+ this.gl = gl;
+ this._emulateStage = false;
+
+ this.lookYaw = 0;
+ this.lookPitch = 0;
+
+ this.viewMatrix = mat4.create();
+
+ let projectionMatrix = mat4.create();
+ this.projectionMatrix = projectionMatrix;
+
+ // Using a simple identity matrix for the view.
+ mat4.identity(this.viewMatrix);
+
+ // We need to track the canvas size in order to resize the WebGL
+ // backbuffer width and height, as well as update the projection matrix
+ // and adjust the viewport.
+ function onResize() {
+ gl.canvas.width = gl.canvas.offsetWidth * window.devicePixelRatio;
+ gl.canvas.height = gl.canvas.offsetHeight * window.devicePixelRatio;
+ mat4.perspective(projectionMatrix, Math.PI*0.4,
+ gl.canvas.width/gl.canvas.height,
+ 0.1, 1000.0);
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ }
+ window.addEventListener('resize', onResize);
+ onResize();
+
+ // Upding the view matrix with touch or mouse events.
+ let canvas = gl.canvas;
+ let lastTouchX = 0;
+ let lastTouchY = 0;
+ canvas.addEventListener('touchstart', (ev) => {
+ if (ev.touches.length == 2) {
+ lastTouchX = ev.touches[1].pageX;
+ lastTouchY = ev.touches[1].pageY;
+ }
+ });
+ canvas.addEventListener('touchmove', (ev) => {
+ // Rotate the view when two fingers are being used.
+ if (ev.touches.length == 2) {
+ this.onLook(ev.touches[1].pageX - lastTouchX, ev.touches[1].pageY - lastTouchY);
+ lastTouchX = ev.touches[1].pageX;
+ lastTouchY = ev.touches[1].pageY;
+ }
+ });
+ canvas.addEventListener('mousemove', (ev) => {
+ // Only rotate when the right button is pressed.
+ if (ev.buttons & 2) {
+ this.onLook(ev.movementX, ev.movementY);
+ }
+ });
+ canvas.addEventListener('contextmenu', (ev) => {
+ // Prevent context menus on the canvas so that we can use right click to rotate.
+ ev.preventDefault();
+ });
+
+ this.boundOnFrame = this.onFrame.bind(this);
+ window.requestAnimationFrame(this.boundOnFrame);
+ }
+
+ onLook(yaw, pitch) {
+ this.lookYaw += yaw * LOOK_SPEED;
+ this.lookPitch += pitch * LOOK_SPEED;
+
+ // Clamp pitch rotation beyond looking straight up or down.
+ if (this.lookPitch < -Math.PI*0.5) {
+ this.lookPitch = -Math.PI*0.5;
+ }
+ if (this.lookPitch > Math.PI*0.5) {
+ this.lookPitch = Math.PI*0.5;
+ }
+
+ this.updateView();
+ }
+
+ onFrame(t) {
+ let gl = this.gl;
+ window.requestAnimationFrame(this.boundOnFrame);
+
+ this.scene.startFrame();
+
+ // We can skip setting the framebuffer and viewport every frame, because
+ // it won't change from frame to frame and we're updating the viewport
+ // only when we resize for efficency.
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // We're drawing with our own projection and view matrix now, and we
+ // don't have a list of view to loop through, but otherwise all of the
+ // WebGL drawing logic is exactly the same.
+ this.scene.draw(this.projectionMatrix, this.viewMatrix);
+
+ this.scene.endFrame();
+ }
+
+ get emulateStage() {
+ return this._emulateStage;
+ }
+
+ set emulateStage(value) {
+ this._emulateStage = value;
+ this.updateView();
+ }
+
+ updateView() {
+ mat4.identity(this.viewMatrix);
+
+ mat4.rotateX(this.viewMatrix, this.viewMatrix, -this.lookPitch);
+ mat4.rotateY(this.viewMatrix, this.viewMatrix, -this.lookYaw);
+
+ // If we're emulating a stage frame of reference we'll need to move the view
+ // matrix roughly a meter and a half up in the air.
+ if (this._emulateStage) {
+ mat4.translate(this.viewMatrix, this.viewMatrix, [0, -1.6, 0]);
+ }
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/query-args.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/query-args.js
new file mode 100644
index 00000000000..e80a6b23d99
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/util/query-args.js
@@ -0,0 +1,87 @@
+// 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.
+
+/*
+Provides a simple way to get values from the query string if they're present
+and use a default value if not. Not strictly a "WebGL" utility, but I use it
+frequently enough for debugging that I wanted to include it here.
+
+Example:
+For the URL http://example.com/index.html?particleCount=1000
+
+QueryArgs.getInt("particleCount", 100); // URL overrides, returns 1000
+QueryArgs.getInt("particleSize", 10); // Not in URL, returns default of 10
+*/
+
+let urlArgs = null;
+window.onhashchange = function() {
+ // Force re-parsing on next access
+ urlArgs = null;
+};
+
+function ensureArgsCached() {
+ if (!urlArgs) {
+ urlArgs = {};
+ let query = window.location.search.substring(1) || window.location.hash.substring(1);
+ let vars = query.split('&');
+ for (let i = 0; i < vars.length; i++) {
+ let pair = vars[i].split('=');
+ urlArgs[pair[0].toLowerCase()] = decodeURIComponent(pair[1]);
+ }
+ }
+}
+
+export class QueryArgs {
+ static getString(name, defaultValue) {
+ ensureArgsCached();
+ let lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return urlArgs[lcaseName];
+ }
+ return defaultValue;
+ }
+
+ static getInt(name, defaultValue) {
+ ensureArgsCached();
+ let lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return parseInt(urlArgs[lcaseName], 10);
+ }
+ return defaultValue;
+ }
+
+ static getFloat(name, defaultValue) {
+ ensureArgsCached();
+ let lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return parseFloat(urlArgs[lcaseName]);
+ }
+ return defaultValue;
+ }
+
+ static getBool(name, defaultValue) {
+ ensureArgsCached();
+ let lcaseName = name.toLowerCase();
+ if (lcaseName in urlArgs) {
+ return parseInt(urlArgs[lcaseName], 10) != 0;
+ }
+ return defaultValue;
+ }
+}
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.debug.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.debug.js
new file mode 100644
index 00000000000..6adb055549b
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.debug.js
@@ -0,0 +1,54 @@
+// 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.
+
+'use strict';
+
+let fs = require('fs');
+let path = require('path');
+let webpack = require('webpack');
+
+// Read the LICENSE file to append to the generated file.
+let header = fs.readFileSync('LICENSE.md', { encoding: 'utf8' });
+
+module.exports = {
+ entry: './src/cottontail.js',
+ output: {
+ path: path.join(__dirname, 'build'),
+ filename: 'cottontail.debug.js',
+ libraryTarget: 'umd'
+ },
+ devtool: 'source-map',
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ use: {
+ loader: 'babel-loader'
+ }
+ }
+ ]
+ },
+ plugins: [
+ new webpack.BannerPlugin({ banner: header, entryOnly: true }),
+ ],
+ mode: "development"
+};
+
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.js
new file mode 100644
index 00000000000..8268697e62d
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/cottontail/webpack.config.js
@@ -0,0 +1,53 @@
+// 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.
+
+'use strict';
+
+let fs = require('fs');
+let path = require('path');
+let webpack = require('webpack');
+
+// Read the LICENSE file to append to the generated file.
+let header = fs.readFileSync('LICENSE.md', { encoding: 'utf8' });
+
+module.exports = {
+ entry: './src/cottontail.js',
+ output: {
+ path: path.join(__dirname, 'build'),
+ filename: 'cottontail.js',
+ libraryTarget: 'umd'
+ },
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ use: {
+ loader: 'babel-loader'
+ }
+ }
+ ]
+ },
+ plugins: [
+ new webpack.BannerPlugin({ banner: header, entryOnly: true }),
+ ],
+ mode: "production"
+};
+
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/third-party/dat.gui.min.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/third-party/dat.gui.min.js
new file mode 100644
index 00000000000..6de153f1728
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/third-party/dat.gui.min.js
@@ -0,0 +1,13 @@
+/**
+ * dat-gui JavaScript Controller Library
+ * http://code.google.com/p/dat-gui
+ *
+ * Copyright 2011 Data Arts Team, Google Creative Lab
+ *
+ * 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
+ */
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.dat=t()}(this,function(){"use strict";function e(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),s=e.a,a=Math.round(e.h),l=e.s.toFixed(1),d=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var c=e.hex.toString(16);c.length<6;)c="0"+c;return"#"+c}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+s+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+s+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+s+"}":"HSV_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+"}":"HSVA_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+",a:"+s+"}":"unknown format"}function t(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(V.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(V.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function n(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(V.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(V.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}function o(e){if("0"===e||k.isUndefined(e))return 0;var t=e.match(G);return k.isNull(t)?0:parseFloat(t[1])}function i(e){var t=e.toString();return t.indexOf(".")>-1?t.length-t.indexOf(".")-1:0}function r(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}function s(e,t,n,o,i){return o+(e-t)/(n-t)*(i-o)}function a(e,t,n,o){e.style.background="",k.each($,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function l(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}function d(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function c(e){U.unbind(window,"resize",e.__resizeHandler),e.saveToLocalStorageIfPossible&&U.unbind(window,"unload",e.saveToLocalStorageIfPossible)}function u(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];n.innerHTML=t?n.value+"*":n.value}function _(e,t,n){if(n.__li=t,n.__gui=e,k.extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),p(e,n.object,n.property,{before:o,factoryArgs:[k.toArray(arguments)]})}if(k.isArray(t)||k.isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),p(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){return n.__gui.remove(n),n}}),n instanceof Q){var o=new W(n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});k.each(["updateDisplay","onChange","onFinishChange","step"],function(e){var t=n[e],i=o[e];n[e]=o[e]=function(){var e=Array.prototype.slice.call(arguments);return i.apply(o,e),t.apply(n,e)}}),U.addClass(t,"has-slider"),n.domElement.insertBefore(o.domElement,n.domElement.firstElementChild)}else if(n instanceof W){var i=function(t){if(k.isNumber(n.__min)&&k.isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=p(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=k.compose(i,n.min),n.max=k.compose(i,n.max)}else n instanceof X?(U.bind(t,"click",function(){U.fakeEvent(n.__checkbox,"click")}),U.bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof q?(U.bind(t,"click",function(){U.fakeEvent(n.__button,"click")}),U.bind(t,"mouseover",function(){U.addClass(n.__button,"hover")}),U.bind(t,"mouseout",function(){U.removeClass(n.__button,"hover")})):n instanceof Z&&(U.addClass(t,"color"),n.updateDisplay=k.compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=k.compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&u(e.getRoot(),!0),t},n.setValue)}function h(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(-1!==o){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,s=void 0;if(r[e.preset])s=r[e.preset];else{if(!r[re])return;s=r[re]}if(s[o]&&void 0!==s[o][t.property]){var a=s[o][t.property];t.initialValue=a,t.setValue(a)}}}}function p(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var i=void 0;if(o.color)i=new Z(t,n);else{var r=[t,n].concat(o.factoryArgs);i=te.apply(e,r)}o.before instanceof I&&(o.before=o.before.__li),h(e,i),U.addClass(i.domElement,"c");var s=document.createElement("span");U.addClass(s,"property-name"),s.innerHTML=i.property;var a=document.createElement("div");a.appendChild(s),a.appendChild(i.domElement);var l=d(e,a,o.before);return U.addClass(l,_e.CLASS_CONTROLLER_ROW),i instanceof Z?U.addClass(l,"color"):U.addClass(l,N(i.getValue())),_(e,l,i),e.__controllers.push(i),i}function f(e,t){return document.location.href+"."+t}function m(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function g(e,t){t.style.display=e.useLocalStorage?"block":"none"}function b(e){var t=e.__save_row=document.createElement("li");U.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),U.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML="&nbsp;",U.addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",U.addClass(o,"button"),U.addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",U.addClass(i,"button"),U.addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",U.addClass(r,"button"),U.addClass(r,"revert");var s=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?k.each(e.load.remembered,function(t,n){m(e,n,n===e.preset)}):m(e,re,!1),U.bind(s,"change",function(){for(var t=0;t<e.__preset_select.length;t++)e.__preset_select[t].innerHTML=e.__preset_select[t].value;e.preset=this.value}),t.appendChild(s),t.appendChild(n),t.appendChild(o),t.appendChild(i),t.appendChild(r),se){var a=document.getElementById("dg-local-explain"),l=document.getElementById("dg-local-storage");document.getElementById("dg-save-locally").style.display="block","true"===localStorage.getItem(f(e,"isLocal"))&&l.setAttribute("checked","checked"),g(e,a),U.bind(l,"change",function(){e.useLocalStorage=!e.useLocalStorage,g(e,a)})}var d=document.getElementById("dg-new-constructor");U.bind(d,"keydown",function(e){!e.metaKey||67!==e.which&&67!==e.keyCode||ae.hide()}),U.bind(n,"click",function(){d.innerHTML=JSON.stringify(e.getSaveObject(),void 0,2),ae.show(),d.focus(),d.select()}),U.bind(o,"click",function(){e.save()}),U.bind(i,"click",function(){var t=prompt("Enter a new preset name.");t&&e.saveAs(t)}),U.bind(r,"click",function(){e.revert()})}function v(e){function t(t){return t.preventDefault(),e.width+=i-t.clientX,e.onResize(),i=t.clientX,!1}function n(){U.removeClass(e.__closeButton,_e.CLASS_DRAG),U.unbind(window,"mousemove",t),U.unbind(window,"mouseup",n)}function o(o){return o.preventDefault(),i=o.clientX,U.addClass(e.__closeButton,_e.CLASS_DRAG),U.bind(window,"mousemove",t),U.bind(window,"mouseup",n),!1}var i=void 0;e.__resize_handle=document.createElement("div"),k.extend(e.__resize_handle.style,{width:"6px",marginLeft:"-3px",height:"200px",cursor:"ew-resize",position:"absolute"}),U.bind(e.__resize_handle,"mousedown",o),U.bind(e.__closeButton,"mousedown",o),e.domElement.insertBefore(e.__resize_handle,e.domElement.firstElementChild)}function y(e,t){e.domElement.style.width=t+"px",e.__save_row&&e.autoPlace&&(e.__save_row.style.width=t+"px"),e.__closeButton&&(e.__closeButton.style.width=t+"px")}function w(e,t){var n={};return k.each(e.__rememberedObjects,function(o,i){var r={},s=e.__rememberedObjectIndecesToControllers[i];k.each(s,function(e,n){r[n]=t?e.initialValue:e.getValue()}),n[i]=r}),n}function x(e){for(var t=0;t<e.__preset_select.length;t++)e.__preset_select[t].value===e.preset&&(e.__preset_select.selectedIndex=t)}function E(e){0!==e.length&&ne.call(window,function(){E(e)}),k.each(e,function(e){e.updateDisplay()})}var C=Array.prototype.forEach,A=Array.prototype.slice,k={BREAK:{},extend:function(e){return this.each(A.call(arguments,1),function(t){(this.isObject(t)?Object.keys(t):[]).forEach(function(n){this.isUndefined(t[n])||(e[n]=t[n])}.bind(this))},this),e},defaults:function(e){return this.each(A.call(arguments,1),function(t){(this.isObject(t)?Object.keys(t):[]).forEach(function(n){this.isUndefined(e[n])&&(e[n]=t[n])}.bind(this))},this),e},compose:function(){var e=A.call(arguments);return function(){for(var t=A.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,n){if(e)if(C&&e.forEach&&e.forEach===C)e.forEach(t,n);else if(e.length===e.length+0){var o=void 0,i=void 0;for(o=0,i=e.length;o<i;o++)if(o in e&&t.call(n,e[o],o)===this.BREAK)return}else for(var r in e)if(t.call(n,e[r],r)===this.BREAK)return},defer:function(e){setTimeout(e,0)},debounce:function(e,t,n){var o=void 0;return function(){var i=this,r=arguments,s=n||!o;clearTimeout(o),o=setTimeout(function(){o=null,n||e.apply(i,r)},t),s&&e.apply(i,r)}},toArray:function(e){return e.toArray?e.toArray():A.call(e)},isUndefined:function(e){return void 0===e},isNull:function(e){return null===e},isNaN:function(e){function t(t){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}(function(e){return isNaN(e)}),isArray:Array.isArray||function(e){return e.constructor===Array},isObject:function(e){return e===Object(e)},isNumber:function(e){return e===e+0},isString:function(e){return e===e+""},isBoolean:function(e){return!1===e||!0===e},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)}},S=[{litmus:k.isString,conversions:{THREE_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString()+t[1].toString()+t[2].toString()+t[2].toString()+t[3].toString()+t[3].toString(),0)}},write:e},SIX_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9]{6})$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString(),0)}},write:e},CSS_RGB:{read:function(e){var t=e.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3])}},write:e},CSS_RGBA:{read:function(e){var t=e.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3]),a:parseFloat(t[4])}},write:e}}},{litmus:k.isNumber,conversions:{HEX:{read:function(e){return{space:"HEX",hex:e,conversionName:"HEX"}},write:function(e){return e.hex}}}},{litmus:k.isArray,conversions:{RGB_ARRAY:{read:function(e){return 3===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2]}},write:function(e){return[e.r,e.g,e.b]}},RGBA_ARRAY:{read:function(e){return 4===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2],a:e[3]}},write:function(e){return[e.r,e.g,e.b,e.a]}}}},{litmus:k.isObject,conversions:{RGBA_OBJ:{read:function(e){return!!(k.isNumber(e.r)&&k.isNumber(e.g)&&k.isNumber(e.b)&&k.isNumber(e.a))&&{space:"RGB",r:e.r,g:e.g,b:e.b,a:e.a}},write:function(e){return{r:e.r,g:e.g,b:e.b,a:e.a}}},RGB_OBJ:{read:function(e){return!!(k.isNumber(e.r)&&k.isNumber(e.g)&&k.isNumber(e.b))&&{space:"RGB",r:e.r,g:e.g,b:e.b}},write:function(e){return{r:e.r,g:e.g,b:e.b}}},HSVA_OBJ:{read:function(e){return!!(k.isNumber(e.h)&&k.isNumber(e.s)&&k.isNumber(e.v)&&k.isNumber(e.a))&&{space:"HSV",h:e.h,s:e.s,v:e.v,a:e.a}},write:function(e){return{h:e.h,s:e.s,v:e.v,a:e.a}}},HSV_OBJ:{read:function(e){return!!(k.isNumber(e.h)&&k.isNumber(e.s)&&k.isNumber(e.v))&&{space:"HSV",h:e.h,s:e.s,v:e.v}},write:function(e){return{h:e.h,s:e.s,v:e.v}}}}}],O=void 0,T=void 0,R=function(){T=!1;var e=arguments.length>1?k.toArray(arguments):arguments[0];return k.each(S,function(t){if(t.litmus(e))return k.each(t.conversions,function(t,n){if(O=t.read(e),!1===T&&!1!==O)return T=O,O.conversionName=n,O.conversion=t,k.BREAK}),k.BREAK}),T},L=void 0,B={hsv_to_rgb:function(e,t,n){var o=Math.floor(e/60)%6,i=e/60-Math.floor(e/60),r=n*(1-t),s=n*(1-i*t),a=n*(1-(1-i)*t),l=[[n,a,r],[s,n,r],[r,n,a],[r,s,n],[a,r,n],[n,r,s]][o];return{r:255*l[0],g:255*l[1],b:255*l[2]}},rgb_to_hsv:function(e,t,n){var o=Math.min(e,t,n),i=Math.max(e,t,n),r=i-o,s=void 0,a=void 0;return 0===i?{h:NaN,s:0,v:0}:(a=r/i,s=e===i?(t-n)/r:t===i?2+(n-e)/r:4+(e-t)/r,(s/=6)<0&&(s+=1),{h:360*s,s:a,v:i/255})},rgb_to_hex:function(e,t,n){var o=this.hex_with_component(0,2,e);return o=this.hex_with_component(o,1,t),o=this.hex_with_component(o,0,n)},component_from_hex:function(e,t){return e>>8*t&255},hex_with_component:function(e,t,n){return n<<(L=8*t)|e&~(255<<L)}},N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},H=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},F=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),P=function e(t,n,o){null===t&&(t=Function.prototype);var i=Object.getOwnPropertyDescriptor(t,n);if(void 0===i){var r=Object.getPrototypeOf(t);return null===r?void 0:e(r,n,o)}if("value"in i)return i.value;var s=i.get;if(void 0!==s)return s.call(o)},j=function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)},D=function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t},V=function(){function t(){if(H(this,t),this.__state=R.apply(this,arguments),!1===this.__state)throw new Error("Failed to interpret color arguments");this.__state.a=this.__state.a||1}return F(t,[{key:"toString",value:function(){return e(this)}},{key:"toHexString",value:function(){return e(this,!0)}},{key:"toOriginal",value:function(){return this.__state.conversion.write(this)}}]),t}();V.recalculateRGB=function(e,t,n){if("HEX"===e.__state.space)e.__state[t]=B.component_from_hex(e.__state.hex,n);else{if("HSV"!==e.__state.space)throw new Error("Corrupted color state");k.extend(e.__state,B.hsv_to_rgb(e.__state.h,e.__state.s,e.__state.v))}},V.recalculateHSV=function(e){var t=B.rgb_to_hsv(e.r,e.g,e.b);k.extend(e.__state,{s:t.s,v:t.v}),k.isNaN(t.h)?k.isUndefined(e.__state.h)&&(e.__state.h=0):e.__state.h=t.h},V.COMPONENTS=["r","g","b","h","s","v","hex","a"],t(V.prototype,"r",2),t(V.prototype,"g",1),t(V.prototype,"b",0),n(V.prototype,"h"),n(V.prototype,"s"),n(V.prototype,"v"),Object.defineProperty(V.prototype,"a",{get:function(){return this.__state.a},set:function(e){this.__state.a=e}}),Object.defineProperty(V.prototype,"hex",{get:function(){return"HEX"!==!this.__state.space&&(this.__state.hex=B.rgb_to_hex(this.r,this.g,this.b)),this.__state.hex},set:function(e){this.__state.space="HEX",this.__state.hex=e}});var I=function(){function e(t,n){H(this,e),this.initialValue=t[n],this.domElement=document.createElement("div"),this.object=t,this.property=n,this.__onChange=void 0,this.__onFinishChange=void 0}return F(e,[{key:"onChange",value:function(e){return this.__onChange=e,this}},{key:"onFinishChange",value:function(e){return this.__onFinishChange=e,this}},{key:"setValue",value:function(e){return this.object[this.property]=e,this.__onChange&&this.__onChange.call(this,e),this.updateDisplay(),this}},{key:"getValue",value:function(){return this.object[this.property]}},{key:"updateDisplay",value:function(){return this}},{key:"isModified",value:function(){return this.initialValue!==this.getValue()}}]),e}(),z={HTMLEvents:["change"],MouseEvents:["click","mousemove","mousedown","mouseup","mouseover"],KeyboardEvents:["keydown"]},M={};k.each(z,function(e,t){k.each(e,function(e){M[e]=t})});var G=/(\d+(\.\d+)?)px/,U={makeSelectable:function(e,t){void 0!==e&&void 0!==e.style&&(e.onselectstart=t?function(){return!1}:function(){},e.style.MozUserSelect=t?"auto":"none",e.style.KhtmlUserSelect=t?"auto":"none",e.unselectable=t?"on":"off")},makeFullscreen:function(e,t,n){var o=n,i=t;k.isUndefined(i)&&(i=!0),k.isUndefined(o)&&(o=!0),e.style.position="absolute",i&&(e.style.left=0,e.style.right=0),o&&(e.style.top=0,e.style.bottom=0)},fakeEvent:function(e,t,n,o){var i=n||{},r=M[t];if(!r)throw new Error("Event type "+t+" not supported.");var s=document.createEvent(r);switch(r){case"MouseEvents":var a=i.x||i.clientX||0,l=i.y||i.clientY||0;s.initMouseEvent(t,i.bubbles||!1,i.cancelable||!0,window,i.clickCount||1,0,0,a,l,!1,!1,!1,!1,0,null);break;case"KeyboardEvents":var d=s.initKeyboardEvent||s.initKeyEvent;k.defaults(i,{cancelable:!0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,keyCode:void 0,charCode:void 0}),d(t,i.bubbles||!1,i.cancelable,window,i.ctrlKey,i.altKey,i.shiftKey,i.metaKey,i.keyCode,i.charCode);break;default:s.initEvent(t,i.bubbles||!1,i.cancelable||!0)}k.defaults(s,o),e.dispatchEvent(s)},bind:function(e,t,n,o){var i=o||!1;return e.addEventListener?e.addEventListener(t,n,i):e.attachEvent&&e.attachEvent("on"+t,n),U},unbind:function(e,t,n,o){var i=o||!1;return e.removeEventListener?e.removeEventListener(t,n,i):e.detachEvent&&e.detachEvent("on"+t,n),U},addClass:function(e,t){if(void 0===e.className)e.className=t;else if(e.className!==t){var n=e.className.split(/ +/);-1===n.indexOf(t)&&(n.push(t),e.className=n.join(" ").replace(/^\s+/,"").replace(/\s+$/,""))}return U},removeClass:function(e,t){if(t)if(e.className===t)e.removeAttribute("class");else{var n=e.className.split(/ +/),o=n.indexOf(t);-1!==o&&(n.splice(o,1),e.className=n.join(" "))}else e.className=void 0;return U},hasClass:function(e,t){return new RegExp("(?:^|\\s+)"+t+"(?:\\s+|$)").test(e.className)||!1},getWidth:function(e){var t=getComputedStyle(e);return o(t["border-left-width"])+o(t["border-right-width"])+o(t["padding-left"])+o(t["padding-right"])+o(t.width)},getHeight:function(e){var t=getComputedStyle(e);return o(t["border-top-width"])+o(t["border-bottom-width"])+o(t["padding-top"])+o(t["padding-bottom"])+o(t.height)},getOffset:function(e){var t=e,n={left:0,top:0};if(t.offsetParent)do{n.left+=t.offsetLeft,n.top+=t.offsetTop,t=t.offsetParent}while(t);return n},isActive:function(e){return e===document.activeElement&&(e.type||e.href)}},X=function(e){function t(e,n){H(this,t);var o=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),i=o;return o.__prev=o.getValue(),o.__checkbox=document.createElement("input"),o.__checkbox.setAttribute("type","checkbox"),U.bind(o.__checkbox,"change",function(){i.setValue(!i.__prev)},!1),o.domElement.appendChild(o.__checkbox),o.updateDisplay(),o}return j(t,I),F(t,[{key:"setValue",value:function(e){var n=P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,e);return this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue()),this.__prev=this.getValue(),n}},{key:"updateDisplay",value:function(){return!0===this.getValue()?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=!0,this.__prev=!0):(this.__checkbox.checked=!1,this.__prev=!1),P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),K=function(e){function t(e,n,o){H(this,t);var i=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=o,s=i;if(i.__select=document.createElement("select"),k.isArray(r)){var a={};k.each(r,function(e){a[e]=e}),r=a}return k.each(r,function(e,t){var n=document.createElement("option");n.innerHTML=t,n.setAttribute("value",e),s.__select.appendChild(n)}),i.updateDisplay(),U.bind(i.__select,"change",function(){var e=this.options[this.selectedIndex].value;s.setValue(e)}),i.domElement.appendChild(i.__select),i}return j(t,I),F(t,[{key:"setValue",value:function(e){var n=P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,e);return this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue()),n}},{key:"updateDisplay",value:function(){return U.isActive(this.__select)?this:(this.__select.value=this.getValue(),P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this))}}]),t}(),Y=function(e){function t(e,n){function o(){r.setValue(r.__input.value)}H(this,t);var i=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=i;return i.__input=document.createElement("input"),i.__input.setAttribute("type","text"),U.bind(i.__input,"keyup",o),U.bind(i.__input,"change",o),U.bind(i.__input,"blur",function(){r.__onFinishChange&&r.__onFinishChange.call(r,r.getValue())}),U.bind(i.__input,"keydown",function(e){13===e.keyCode&&this.blur()}),i.updateDisplay(),i.domElement.appendChild(i.__input),i}return j(t,I),F(t,[{key:"updateDisplay",value:function(){return U.isActive(this.__input)||(this.__input.value=this.getValue()),P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),J=function(e){function t(e,n,o){H(this,t);var r=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),s=o||{};return r.__min=s.min,r.__max=s.max,r.__step=s.step,k.isUndefined(r.__step)?0===r.initialValue?r.__impliedStep=1:r.__impliedStep=Math.pow(10,Math.floor(Math.log(Math.abs(r.initialValue))/Math.LN10))/10:r.__impliedStep=r.__step,r.__precision=i(r.__impliedStep),r}return j(t,I),F(t,[{key:"setValue",value:function(e){var n=e;return void 0!==this.__min&&n<this.__min?n=this.__min:void 0!==this.__max&&n>this.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!=0&&(n=Math.round(n/this.__step)*this.__step),P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,n)}},{key:"min",value:function(e){return this.__min=e,this}},{key:"max",value:function(e){return this.__max=e,this}},{key:"step",value:function(e){return this.__step=e,this.__impliedStep=e,this.__precision=i(e),this}}]),t}(),W=function(e){function t(e,n,o){function i(){l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())}function r(e){var t=d-e.clientY;l.setValue(l.getValue()+t*l.__impliedStep),d=e.clientY}function s(){U.unbind(window,"mousemove",r),U.unbind(window,"mouseup",s),i()}H(this,t);var a=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,o));a.__truncationSuspended=!1;var l=a,d=void 0;return a.__input=document.createElement("input"),a.__input.setAttribute("type","text"),U.bind(a.__input,"change",function(){var e=parseFloat(l.__input.value);k.isNaN(e)||l.setValue(e)}),U.bind(a.__input,"blur",function(){i()}),U.bind(a.__input,"mousedown",function(e){U.bind(window,"mousemove",r),U.bind(window,"mouseup",s),d=e.clientY}),U.bind(a.__input,"keydown",function(e){13===e.keyCode&&(l.__truncationSuspended=!0,this.blur(),l.__truncationSuspended=!1,i())}),a.updateDisplay(),a.domElement.appendChild(a.__input),a}return j(t,J),F(t,[{key:"updateDisplay",value:function(){return this.__input.value=this.__truncationSuspended?this.getValue():r(this.getValue(),this.__precision),P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),Q=function(e){function t(e,n,o,i,r){function a(e){e.preventDefault();var t=_.__background.getBoundingClientRect();return _.setValue(s(e.clientX,t.left,t.right,_.__min,_.__max)),!1}function l(){U.unbind(window,"mousemove",a),U.unbind(window,"mouseup",l),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}function d(e){var t=e.touches[0].clientX,n=_.__background.getBoundingClientRect();_.setValue(s(t,n.left,n.right,_.__min,_.__max))}function c(){U.unbind(window,"touchmove",d),U.unbind(window,"touchend",c),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}H(this,t);var u=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,{min:o,max:i,step:r})),_=u;return u.__background=document.createElement("div"),u.__foreground=document.createElement("div"),U.bind(u.__background,"mousedown",function(e){document.activeElement.blur(),U.bind(window,"mousemove",a),U.bind(window,"mouseup",l),a(e)}),U.bind(u.__background,"touchstart",function(e){1===e.touches.length&&(U.bind(window,"touchmove",d),U.bind(window,"touchend",c),d(e))}),U.addClass(u.__background,"slider"),U.addClass(u.__foreground,"slider-fg"),u.updateDisplay(),u.__background.appendChild(u.__foreground),u.domElement.appendChild(u.__background),u}return j(t,J),F(t,[{key:"updateDisplay",value:function(){var e=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*e+"%",P(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),q=function(e){function t(e,n,o){H(this,t);var i=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=i;return i.__button=document.createElement("div"),i.__button.innerHTML=void 0===o?"Fire":o,U.bind(i.__button,"click",function(e){return e.preventDefault(),r.fire(),!1}),U.addClass(i.__button,"button"),i.domElement.appendChild(i.__button),i}return j(t,I),F(t,[{key:"fire",value:function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}}]),t}(),Z=function(e){function t(e,n){function o(e){u(e),U.bind(window,"mousemove",u),U.bind(window,"touchmove",u),U.bind(window,"mouseup",r),U.bind(window,"touchend",r)}function i(e){_(e),U.bind(window,"mousemove",_),U.bind(window,"touchmove",_),U.bind(window,"mouseup",s),U.bind(window,"touchend",s)}function r(){U.unbind(window,"mousemove",u),U.unbind(window,"touchmove",u),U.unbind(window,"mouseup",r),U.unbind(window,"touchend",r),c()}function s(){U.unbind(window,"mousemove",_),U.unbind(window,"touchmove",_),U.unbind(window,"mouseup",s),U.unbind(window,"touchend",s),c()}function d(){var e=R(this.value);!1!==e?(p.__color.__state=e,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}function c(){p.__onFinishChange&&p.__onFinishChange.call(p,p.__color.toOriginal())}function u(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__saturation_field.getBoundingClientRect(),n=e.touches&&e.touches[0]||e,o=n.clientX,i=n.clientY,r=(o-t.left)/(t.right-t.left),s=1-(i-t.top)/(t.bottom-t.top);return s>1?s=1:s<0&&(s=0),r>1?r=1:r<0&&(r=0),p.__color.v=s,p.__color.s=r,p.setValue(p.__color.toOriginal()),!1}function _(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__hue_field.getBoundingClientRect(),n=1-((e.touches&&e.touches[0]||e).clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),p.__color.h=360*n,p.setValue(p.__color.toOriginal()),!1}H(this,t);var h=D(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n));h.__color=new V(h.getValue()),h.__temp=new V(0);var p=h;h.domElement=document.createElement("div"),U.makeSelectable(h.domElement,!1),h.__selector=document.createElement("div"),h.__selector.className="selector",h.__saturation_field=document.createElement("div"),h.__saturation_field.className="saturation-field",h.__field_knob=document.createElement("div"),h.__field_knob.className="field-knob",h.__field_knob_border="2px solid ",h.__hue_knob=document.createElement("div"),h.__hue_knob.className="hue-knob",h.__hue_field=document.createElement("div"),h.__hue_field.className="hue-field",h.__input=document.createElement("input"),h.__input.type="text",h.__input_textShadow="0 1px 1px ",U.bind(h.__input,"keydown",function(e){13===e.keyCode&&d.call(this)}),U.bind(h.__input,"blur",d),U.bind(h.__selector,"mousedown",function(){U.addClass(this,"drag").bind(window,"mouseup",function(){U.removeClass(p.__selector,"drag")})}),U.bind(h.__selector,"touchstart",function(){U.addClass(this,"drag").bind(window,"touchend",function(){U.removeClass(p.__selector,"drag")})});var f=document.createElement("div");return k.extend(h.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),k.extend(h.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:h.__field_knob_border+(h.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),k.extend(h.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),k.extend(h.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),k.extend(f.style,{width:"100%",height:"100%",background:"none"}),a(f,"top","rgba(0,0,0,0)","#000"),k.extend(h.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),l(h.__hue_field),k.extend(h.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:h.__input_textShadow+"rgba(0,0,0,0.7)"}),U.bind(h.__saturation_field,"mousedown",o),U.bind(h.__saturation_field,"touchstart",o),U.bind(h.__field_knob,"mousedown",o),U.bind(h.__field_knob,"touchstart",o),U.bind(h.__hue_field,"mousedown",i),U.bind(h.__hue_field,"touchstart",i),h.__saturation_field.appendChild(f),h.__selector.appendChild(h.__field_knob),h.__selector.appendChild(h.__saturation_field),h.__selector.appendChild(h.__hue_field),h.__hue_field.appendChild(h.__hue_knob),h.domElement.appendChild(h.__input),h.domElement.appendChild(h.__selector),h.updateDisplay(),h}return j(t,I),F(t,[{key:"updateDisplay",value:function(){var e=R(this.getValue());if(!1!==e){var t=!1;k.each(V.COMPONENTS,function(n){if(!k.isUndefined(e[n])&&!k.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&k.extend(this.__color.__state,e)}k.extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;k.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,a(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),k.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})}}]),t}(),$=["-moz-","-o-","-webkit-","-ms-",""],ee={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(e){}}},te=function(e,t){var n=e[t];return k.isArray(arguments[2])||k.isObject(arguments[2])?new K(e,t,arguments[2]):k.isNumber(n)?k.isNumber(arguments[2])&&k.isNumber(arguments[3])?k.isNumber(arguments[4])?new Q(e,t,arguments[2],arguments[3],arguments[4]):new Q(e,t,arguments[2],arguments[3]):k.isNumber(arguments[4])?new W(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new W(e,t,{min:arguments[2],max:arguments[3]}):k.isString(n)?new Y(e,t):k.isFunction(n)?new q(e,t,""):k.isBoolean(n)?new X(e,t):null},ne=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)},oe=function(){function e(){H(this,e),this.backgroundElement=document.createElement("div"),k.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),U.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),k.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;U.bind(this.backgroundElement,"click",function(){t.hide()})}return F(e,[{key:"show",value:function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),k.defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})}},{key:"hide",value:function(){var e=this,t=function t(){e.domElement.style.display="none",e.backgroundElement.style.display="none",U.unbind(e.domElement,"webkitTransitionEnd",t),U.unbind(e.domElement,"transitionend",t),U.unbind(e.domElement,"oTransitionEnd",t)};U.bind(this.domElement,"webkitTransitionEnd",t),U.bind(this.domElement,"transitionend",t),U.bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"}},{key:"layout",value:function(){this.domElement.style.left=window.innerWidth/2-U.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-U.getHeight(this.domElement)/2+"px"}}]),e}(),ie=function(e){if(e&&"undefined"!=typeof window){var t=document.createElement("style");return t.setAttribute("type","text/css"),t.innerHTML=e,document.head.appendChild(t),e}}(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid transparent}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n");ee.inject(ie);var re="Default",se=function(){try{return"localStorage"in window&&null!==window.localStorage}catch(e){return!1}}(),ae=void 0,le=!0,de=void 0,ce=!1,ue=[],_e=function e(t){var n=this,o=t||{};this.domElement=document.createElement("div"),this.__ul=document.createElement("ul"),this.domElement.appendChild(this.__ul),U.addClass(this.domElement,"dg"),this.__folders={},this.__controllers=[],this.__rememberedObjects=[],this.__rememberedObjectIndecesToControllers=[],this.__listening=[],o=k.defaults(o,{closeOnTop:!1,autoPlace:!0,width:e.DEFAULT_WIDTH}),o=k.defaults(o,{resizable:o.autoPlace,hideable:o.autoPlace}),k.isUndefined(o.load)?o.load={preset:re}:o.preset&&(o.load.preset=o.preset),k.isUndefined(o.parent)&&o.hideable&&ue.push(this),o.resizable=k.isUndefined(o.parent)&&o.resizable,o.autoPlace&&k.isUndefined(o.scrollable)&&(o.scrollable=!0);var i=se&&"true"===localStorage.getItem(f(this,"isLocal")),r=void 0;if(Object.defineProperties(this,{parent:{get:function(){return o.parent}},scrollable:{get:function(){return o.scrollable}},autoPlace:{get:function(){return o.autoPlace}},closeOnTop:{get:function(){return o.closeOnTop}},preset:{get:function(){return n.parent?n.getRoot().preset:o.load.preset},set:function(e){n.parent?n.getRoot().preset=e:o.load.preset=e,x(this),n.revert()}},width:{get:function(){return o.width},set:function(e){o.width=e,y(n,e)}},name:{get:function(){return o.name},set:function(e){o.name=e,titleRowName&&(titleRowName.innerHTML=o.name)}},closed:{get:function(){return o.closed},set:function(t){o.closed=t,o.closed?U.addClass(n.__ul,e.CLASS_CLOSED):U.removeClass(n.__ul,e.CLASS_CLOSED),this.onResize(),n.__closeButton&&(n.__closeButton.innerHTML=t?e.TEXT_OPEN:e.TEXT_CLOSED)}},load:{get:function(){return o.load}},useLocalStorage:{get:function(){return i},set:function(e){se&&(i=e,e?U.bind(window,"unload",r):U.unbind(window,"unload",r),localStorage.setItem(f(n,"isLocal"),e))}}}),k.isUndefined(o.parent)){if(o.closed=!1,U.addClass(this.domElement,e.CLASS_MAIN),U.makeSelectable(this.domElement,!1),se&&i){n.useLocalStorage=!0;var s=localStorage.getItem(f(this,"gui"));s&&(o.load=JSON.parse(s))}this.__closeButton=document.createElement("div"),this.__closeButton.innerHTML=e.TEXT_CLOSED,U.addClass(this.__closeButton,e.CLASS_CLOSE_BUTTON),o.closeOnTop?(U.addClass(this.__closeButton,e.CLASS_CLOSE_TOP),this.domElement.insertBefore(this.__closeButton,this.domElement.childNodes[0])):(U.addClass(this.__closeButton,e.CLASS_CLOSE_BOTTOM),this.domElement.appendChild(this.__closeButton)),U.bind(this.__closeButton,"click",function(){n.closed=!n.closed})}else{void 0===o.closed&&(o.closed=!0);var a=document.createTextNode(o.name);U.addClass(a,"controller-name");var l=d(n,a);U.addClass(this.__ul,e.CLASS_CLOSED),U.addClass(l,"title"),U.bind(l,"click",function(e){return e.preventDefault(),n.closed=!n.closed,!1}),o.closed||(this.closed=!1)}o.autoPlace&&(k.isUndefined(o.parent)&&(le&&(de=document.createElement("div"),U.addClass(de,"dg"),U.addClass(de,e.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(de),le=!1),de.appendChild(this.domElement),U.addClass(this.domElement,e.CLASS_AUTO_PLACE)),this.parent||y(n,o.width)),this.__resizeHandler=function(){n.onResizeDebounced()},U.bind(window,"resize",this.__resizeHandler),U.bind(this.__ul,"webkitTransitionEnd",this.__resizeHandler),U.bind(this.__ul,"transitionend",this.__resizeHandler),U.bind(this.__ul,"oTransitionEnd",this.__resizeHandler),this.onResize(),o.resizable&&v(this),r=function(){se&&"true"===localStorage.getItem(f(n,"isLocal"))&&localStorage.setItem(f(n,"gui"),JSON.stringify(n.getSaveObject()))},this.saveToLocalStorageIfPossible=r,o.parent||function(){var e=n.getRoot();e.width+=1,k.defer(function(){e.width-=1})}()};return _e.toggleHide=function(){ce=!ce,k.each(ue,function(e){e.domElement.style.display=ce?"none":""})},_e.CLASS_AUTO_PLACE="a",_e.CLASS_AUTO_PLACE_CONTAINER="ac",_e.CLASS_MAIN="main",_e.CLASS_CONTROLLER_ROW="cr",_e.CLASS_TOO_TALL="taller-than-window",_e.CLASS_CLOSED="closed",_e.CLASS_CLOSE_BUTTON="close-button",_e.CLASS_CLOSE_TOP="close-top",_e.CLASS_CLOSE_BOTTOM="close-bottom",_e.CLASS_DRAG="drag",_e.DEFAULT_WIDTH=245,_e.TEXT_CLOSED="Close Controls",_e.TEXT_OPEN="Open Controls",_e._keydownHandler=function(e){"text"===document.activeElement.type||72!==e.which&&72!==e.keyCode||_e.toggleHide()},U.bind(window,"keydown",_e._keydownHandler,!1),k.extend(_e.prototype,{add:function(e,t){return p(this,e,t,{factoryArgs:Array.prototype.slice.call(arguments,2)})},addColor:function(e,t){return p(this,e,t,{color:!0})},remove:function(e){this.__ul.removeChild(e.__li),this.__controllers.splice(this.__controllers.indexOf(e),1);var t=this;k.defer(function(){t.onResize()})},destroy:function(){if(this.parent)throw new Error("Only the root GUI should be removed with .destroy(). For subfolders, use gui.removeFolder(folder) instead.");this.autoPlace&&de.removeChild(this.domElement);var e=this;k.each(this.__folders,function(t){e.removeFolder(t)}),U.unbind(window,"keydown",_e._keydownHandler,!1),c(this)},addFolder:function(e){if(void 0!==this.__folders[e])throw new Error('You already have a folder in this GUI by the name "'+e+'"');var t={name:e,parent:this};t.autoPlace=this.autoPlace,this.load&&this.load.folders&&this.load.folders[e]&&(t.closed=this.load.folders[e].closed,t.load=this.load.folders[e]);var n=new _e(t);this.__folders[e]=n;var o=d(this,n.domElement);return U.addClass(o,"folder"),n},removeFolder:function(e){this.__ul.removeChild(e.domElement.parentElement),delete this.__folders[e.name],this.load&&this.load.folders&&this.load.folders[e.name]&&delete this.load.folders[e.name],c(e);var t=this;k.each(e.__folders,function(t){e.removeFolder(t)}),k.defer(function(){t.onResize()})},open:function(){this.closed=!1},close:function(){this.closed=!0},onResize:function(){var e=this.getRoot();if(e.scrollable){var t=U.getOffset(e.__ul).top,n=0;k.each(e.__ul.childNodes,function(t){e.autoPlace&&t===e.__save_row||(n+=U.getHeight(t))}),window.innerHeight-t-20<n?(U.addClass(e.domElement,_e.CLASS_TOO_TALL),e.__ul.style.height=window.innerHeight-t-20+"px"):(U.removeClass(e.domElement,_e.CLASS_TOO_TALL),e.__ul.style.height="auto")}e.__resize_handle&&k.defer(function(){e.__resize_handle.style.height=e.__ul.offsetHeight+"px"}),e.__closeButton&&(e.__closeButton.style.width=e.width+"px")},onResizeDebounced:k.debounce(function(){this.onResize()},50),remember:function(){if(k.isUndefined(ae)&&((ae=new oe).domElement.innerHTML='<div id="dg-save" class="dg dialogue">\n\n Here\'s the new load parameter for your <code>GUI</code>\'s constructor:\n\n <textarea id="dg-new-constructor"></textarea>\n\n <div id="dg-save-locally">\n\n <input id="dg-local-storage" type="checkbox"/> Automatically save\n values to <code>localStorage</code> on exit.\n\n <div id="dg-local-explain">The values saved to <code>localStorage</code> will\n override those passed to <code>dat.GUI</code>\'s constructor. This makes it\n easier to work incrementally, but <code>localStorage</code> is fragile,\n and your friends may not see the same values you do.\n\n </div>\n\n </div>\n\n</div>'),this.parent)throw new Error("You can only call remember on a top level GUI.");var e=this;k.each(Array.prototype.slice.call(arguments),function(t){0===e.__rememberedObjects.length&&b(e),-1===e.__rememberedObjects.indexOf(t)&&e.__rememberedObjects.push(t)}),this.autoPlace&&y(this,this.width)},getRoot:function(){for(var e=this;e.parent;)e=e.parent;return e},getSaveObject:function(){var e=this.load;return e.closed=this.closed,this.__rememberedObjects.length>0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=w(this)),e.folders={},k.each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=w(this),u(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[re]=w(this,!0)),this.load.remembered[e]=w(this),this.preset=e,m(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){k.each(this.__controllers,function(t){this.getRoot().load.remembered?h(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),k.each(this.__folders,function(e){e.revert(e)}),e||u(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&E(this.__listening)},updateDisplay:function(){k.each(this.__controllers,function(e){e.updateDisplay()}),k.each(this.__folders,function(e){e.updateDisplay()})}}),{color:{Color:V,math:B,interpret:R},controllers:{Controller:I,BooleanController:X,OptionController:K,StringController:Y,NumberController:J,NumberControllerBox:W,NumberControllerSlider:Q,FunctionController:q,ColorController:Z},dom:{dom:U},gui:{GUI:_e},GUI:_e}});
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
new file mode 100644
index 00000000000..1028a5b9ada
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
@@ -0,0 +1,488 @@
+// Copyright 2016 Google Inc.
+//
+// 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.
+
+// This is a stripped down and specialized version of WebVR-UI
+// (https://github.com/googlevr/webvr-ui) that takes out most of the state
+// management in favor of providing a simple way of listing available devices
+// for the needs of the sample pages. Functionality like beginning sessions
+// is intentionally left out so that the sample pages can demonstrate them more
+// clearly.
+
+window.XRDeviceButton = (function () {
+
+//
+// State consts
+//
+
+// Not yet presenting, but ready to present
+const READY_TO_PRESENT = 'ready';
+
+// In presentation mode
+const PRESENTING = 'presenting';
+const PRESENTING_FULLSCREEN = 'presenting-fullscreen';
+
+// Checking device availability
+const PREPARING = 'preparing';
+
+// Errors
+const ERROR_NO_PRESENTABLE_DISPLAYS = 'error-no-presentable-displays';
+const ERROR_BROWSER_NOT_SUPPORTED = 'error-browser-not-supported';
+const ERROR_REQUEST_TO_PRESENT_REJECTED = 'error-request-to-present-rejected';
+const ERROR_EXIT_PRESENT_REJECTED = 'error-exit-present-rejected';
+const ERROR_REQUEST_STATE_CHANGE_REJECTED = 'error-request-state-change-rejected';
+const ERROR_UNKOWN = 'error-unkown';
+
+//
+// DOM element
+//
+
+const _LOGO_SCALE = 0.8;
+let _WEBXR_UI_CSS_INJECTED = {};
+
+/**
+ * Generate the innerHTML for the button
+ *
+ * @return {string} html of the button as string
+ * @param {string} cssPrefix
+ * @param {Number} height
+ * @private
+ */
+const generateInnerHTML = (cssPrefix, height)=> {
+ const logoHeight = height*_LOGO_SCALE;
+ const svgString = generateXRIconString(cssPrefix, logoHeight) + generateNoXRIconString(cssPrefix, logoHeight);
+
+ return `<button class="${cssPrefix}-button">
+ <div class="${cssPrefix}-title"></div>
+ <div class="${cssPrefix}-logo" >${svgString}</div>
+ </button>`;
+};
+
+/**
+ * Inject the CSS string to the head of the document
+ *
+ * @param {string} cssText the css to inject
+ */
+const injectCSS = (cssText)=> {
+ // Create the css
+ const style = document.createElement('style');
+ style.innerHTML = cssText;
+
+ let head = document.getElementsByTagName('head')[0];
+ head.insertBefore(style, head.firstChild);
+};
+
+/**
+ * Generate DOM element view for button
+ *
+ * @return {HTMLElement}
+ * @param {Object} options
+ */
+const createDefaultView = (options)=> {
+ const fontSize = options.height / 3;
+ if (options.injectCSS) {
+ // Check that css isnt already injected
+ if (!_WEBXR_UI_CSS_INJECTED[options.cssprefix]) {
+ injectCSS(generateCSS(options, fontSize));
+ _WEBXR_UI_CSS_INJECTED[options.cssprefix] = true;
+ }
+ }
+
+ const el = document.createElement('div');
+ el.innerHTML = generateInnerHTML(options.cssprefix, fontSize);
+ return el.firstChild;
+};
+
+
+const createXRIcon = (cssPrefix, height)=>{
+ const el = document.createElement('div');
+ el.innerHTML = generateXRIconString(cssPrefix, height);
+ return el.firstChild;
+};
+
+const createNoXRIcon = (cssPrefix, height)=>{
+ const el = document.createElement('div');
+ el.innerHTML = generateNoXRIconString(cssPrefix, height);
+ return el.firstChild;
+};
+
+const generateXRIconString = (cssPrefix, height)=> {
+ let aspect = 28 / 18;
+ return `<svg class="${cssPrefix}-svg" version="1.1" x="0px" y="0px"
+ width="${aspect * height}px" height="${height}px" viewBox="0 0 28 18" xml:space="preserve">
+ <path d="M26.8,1.1C26.1,0.4,25.1,0,24.2,0H3.4c-1,0-1.7,0.4-2.4,1.1C0.3,1.7,0,2.7,0,3.6v10.7
+ c0,1,0.3,1.9,0.9,2.6C1.6,17.6,2.4,18,3.4,18h5c0.7,0,1.3-0.2,1.8-0.5c0.6-0.3,1-0.8,1.3-1.4l
+ 1.5-2.6C13.2,13.1,13,13,14,13v0h-0.2 h0c0.3,0,0.7,0.1,0.8,0.5l1.4,2.6c0.3,0.6,0.8,1.1,1.3,
+ 1.4c0.6,0.3,1.2,0.5,1.8,0.5h5c1,0,2-0.4,2.7-1.1c0.7-0.7,1.2-1.6,1.2-2.6 V3.6C28,2.7,27.5,
+ 1.7,26.8,1.1z M7.4,11.8c-1.6,0-2.8-1.3-2.8-2.8c0-1.6,1.3-2.8,2.8-2.8c1.6,0,2.8,1.3,2.8,2.8
+ C10.2,10.5,8.9,11.8,7.4,11.8z M20.1,11.8c-1.6,0-2.8-1.3-2.8-2.8c0-1.6,1.3-2.8,2.8-2.8C21.7
+ ,6.2,23,7.4,23,9 C23,10.5,21.7,11.8,20.1,11.8z"/>
+ </svg>`;
+};
+
+const generateNoXRIconString = (cssPrefix, height)=>{
+ let aspect = 28 / 18;
+ return `<svg class="${cssPrefix}-svg-error" x="0px" y="0px"
+ width="${aspect * height}px" height="${aspect * height}px" viewBox="0 0 28 28" xml:space="preserve">
+ <path d="M17.6,13.4c0-0.2-0.1-0.4-0.1-0.6c0-1.6,1.3-2.8,2.8-2.8s2.8,1.3,2.8,2.8s-1.3,2.8-2.8,2.8
+ c-0.2,0-0.4,0-0.6-0.1l5.9,5.9c0.5-0.2,0.9-0.4,1.3-0.8
+ c0.7-0.7,1.1-1.6,1.1-2.5V7.4c0-1-0.4-1.9-1.1-2.5c-0.7-0.7-1.6-1-2.5-1
+ H8.1 L17.6,13.4z"/>
+ <path d="M10.1,14.2c-0.5,0.9-1.4,1.4-2.4,1.4c-1.6,0-2.8-1.3-2.8-2.8c0-1.1,0.6-2,1.4-2.5
+ L0.9,5.1 C0.3,5.7,0,6.6,0,7.5v10.7c0,1,0.4,1.8,1.1,2.5c0.7,0.7,1.6,1,2.5,1
+ h5c0.7,0,1.3-0.1,1.8-0.5c0.6-0.3,1-0.8,1.3-1.4l1.3-2.6 L10.1,14.2z"/>
+ <path d="M25.5,27.5l-25-25C-0.1,2-0.1,1,0.5,0.4l0,0C1-0.1,2-0.1,2.6,0.4l25,25c0.6,0.6,0.6,1.5
+ ,0,2.1l0,0 C27,28.1,26,28.1,25.5,27.5z"/>
+ </svg>`;
+};
+
+/**
+ * Generate the CSS string to inject
+ *
+ * @param {Object} options
+ * @param {Number} [fontSize=18]
+ * @return {string}
+ */
+const generateCSS = (options, fontSize=18)=> {
+ const height = options.height;
+ const borderWidth = 2;
+ const borderColor = options.background ? options.background : options.color;
+ const cssPrefix = options.cssprefix;
+
+ let borderRadius;
+ if (options.corners == 'round') {
+ borderRadius = options.height / 2;
+ } else if (options.corners == 'square') {
+ borderRadius = 2;
+ } else {
+ borderRadius = options.corners;
+ }
+
+ return (`
+ @font-face {
+ font-family: 'Karla';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Karla'), local('Karla-Regular'),
+ url(https://fonts.gstatic.com/s/karla/v5/31P4mP32i98D9CEnGyeX9Q.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
+ }
+ @font-face {
+ font-family: 'Karla';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Karla'), local('Karla-Regular'),
+ url(https://fonts.gstatic.com/s/karla/v5/Zi_e6rBgGqv33BWF8WTq8g.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074,
+ U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
+ }
+
+ button.${cssPrefix}-button {
+ font-family: 'Karla', sans-serif;
+
+ border: ${borderColor} ${borderWidth}px solid;
+ border-radius: ${borderRadius}px;
+ box-sizing: border-box;
+ background: ${options.background ? options.background : 'none'};
+
+ height: ${height}px;
+ min-width: ${fontSize * 9.6}px;
+ display: inline-block;
+ position: relative;
+
+ cursor: pointer;
+ }
+
+ button.${cssPrefix}-button:focus {
+ outline: none;
+ }
+
+ /*
+ * Logo
+ */
+
+ .${cssPrefix}-logo {
+ width: ${height}px;
+ height: ${height}px;
+ position: absolute;
+ top:0px;
+ left:0px;
+ width: ${height - 4}px;
+ height: ${height - 4}px;
+ }
+ .${cssPrefix}-svg {
+ fill: ${options.color};
+ margin-top: ${(height - fontSize * _LOGO_SCALE) / 2 - 2}px;
+ margin-left: ${height / 3 }px;
+ }
+ .${cssPrefix}-svg-error {
+ fill: ${options.color};
+ display:none;
+ margin-top: ${(height - 28 / 18 * fontSize * _LOGO_SCALE) / 2 - 2}px;
+ margin-left: ${height / 3 }px;
+ }
+
+
+ /*
+ * Title
+ */
+
+ .${cssPrefix}-title {
+ color: ${options.color};
+ position: relative;
+ font-size: ${fontSize}px;
+ padding-left: ${height * 1.05}px;
+ padding-right: ${(borderRadius - 10 < 5) ? height / 3 : borderRadius - 10}px;
+ }
+
+ /*
+ * disabled
+ */
+
+ button.${cssPrefix}-button[disabled=true] {
+ opacity: ${options.disabledOpacity};
+ }
+
+ button.${cssPrefix}-button[disabled=true] > .${cssPrefix}-logo > .${cssPrefix}-svg {
+ display:none;
+ }
+
+ button.${cssPrefix}-button[disabled=true] > .${cssPrefix}-logo > .${cssPrefix}-svg-error {
+ display:initial;
+ }
+ `);
+};
+
+//
+// Button class
+//
+
+class EnterXRButton {
+ /**
+ * Construct a new Enter XR Button
+ * @constructor
+ * @param {HTMLCanvasElement} sourceCanvas the canvas that you want to present with WebXR
+ * @param {Object} [options] optional parameters
+ * @param {HTMLElement} [options.domElement] provide your own domElement to bind to
+ * @param {Boolean} [options.injectCSS=true] set to false if you want to write your own styles
+ * @param {Function} [options.beforeEnter] should return a promise, opportunity to intercept request to enter
+ * @param {Function} [options.beforeExit] should return a promise, opportunity to intercept request to exit
+ * @param {Function} [options.onRequestStateChange] set to a function returning false to prevent default state changes
+ * @param {string} [options.textEnterXRTitle] set the text for Enter XR
+ * @param {string} [options.textXRNotFoundTitle] set the text for when a XR display is not found
+ * @param {string} [options.textExitXRTitle] set the text for exiting XR
+ * @param {string} [options.color] text and icon color
+ * @param {string} [options.background] set to false for no brackground or a color
+ * @param {string} [options.corners] set to 'round', 'square' or pixel value representing the corner radius
+ * @param {string} [options.disabledOpacity] set opacity of button dom when disabled
+ * @param {string} [options.cssprefix] set to change the css prefix from default 'webvr-ui'
+ */
+ constructor(options) {
+ options = options || {};
+
+ options.color = options.color || 'rgb(80,168,252)';
+ options.background = options.background || false;
+ options.disabledOpacity = options.disabledOpacity || 0.5;
+ options.height = options.height || 55;
+ options.corners = options.corners || 'square';
+ options.cssprefix = options.cssprefix || 'webvr-ui';
+
+ // This reads VR as none of the samples are designed for other formats as of yet.
+ options.textEnterXRTitle = options.textEnterXRTitle || 'ENTER VR';
+ options.textXRNotFoundTitle = options.textXRNotFoundTitle || 'VR NOT FOUND';
+ options.textExitXRTitle = options.textExitXRTitle || 'EXIT VR';
+
+ options.onRequestSession = options.onRequestSession || (function() {});
+ options.onEndSession = options.onEndSession || (function() {});
+
+ options.injectCSS = options.injectCSS !== false;
+
+ this.options = options;
+
+ this.device = null;
+ this.session = null;
+
+ // Pass in your own domElement if you really dont want to use ours
+ this.domElement = options.domElement || createDefaultView(options);
+ this.__defaultDisplayStyle = this.domElement.style.display || 'initial';
+
+ // Bind button click events to __onClick
+ this.domElement.addEventListener('click', ()=> this.__onXRButtonClick());
+
+ this.__forceDisabled = false;
+ this.__setDisabledAttribute(true);
+ this.setTitle(this.options.textXRNotFoundTitle);
+ }
+
+ /**
+ * Sets the XRDevice this button is associated with.
+ * @param {XRDevice} device
+ * @return {EnterXRButton}
+ */
+ setDevice(device) {
+ this.device = device;
+ this.__updateButtonState();
+ return this;
+ }
+
+ /**
+ * Indicate that there's an active XRSession. Switches the button to "Exit XR"
+ * state if not null, or "Enter XR" state if null.
+ * @param {XRSession} session
+ * @return {EnterXRButton}
+ */
+ setSession(session) {
+ this.session = session;
+ this.__updateButtonState();
+ return this;
+ }
+
+ /**
+ * Set the title of the button
+ * @param {string} text
+ * @return {EnterXRButton}
+ */
+ setTitle(text) {
+ this.domElement.title = text;
+ ifChild(this.domElement, this.options.cssprefix, 'title', (title)=> {
+ if (!text) {
+ title.style.display = 'none';
+ } else {
+ title.innerText = text;
+ title.style.display = 'initial';
+ }
+ });
+
+ return this;
+ }
+
+ /**
+ * Set the tooltip of the button
+ * @param {string} tooltip
+ * @return {EnterXRButton}
+ */
+ setTooltip(tooltip) {
+ this.domElement.title = tooltip;
+ return this;
+ }
+
+ /**
+ * Show the button
+ * @return {EnterXRButton}
+ */
+ show() {
+ this.domElement.style.display = this.__defaultDisplayStyle;
+ return this;
+ }
+
+ /**
+ * Hide the button
+ * @return {EnterXRButton}
+ */
+ hide() {
+ this.domElement.style.display = 'none';
+ return this;
+ }
+
+ /**
+ * Enable the button
+ * @return {EnterXRButton}
+ */
+ enable() {
+ this.__setDisabledAttribute(false);
+ this.__forceDisabled = false;
+ return this;
+ }
+
+ /**
+ * Disable the button from being clicked
+ * @return {EnterXRButton}
+ */
+ disable() {
+ this.__setDisabledAttribute(true);
+ this.__forceDisabled = true;
+ return this;
+ }
+
+ /**
+ * clean up object for garbage collection
+ */
+ remove() {
+ if (this.domElement.parentElement) {
+ this.domElement.parentElement.removeChild(this.domElement);
+ }
+ }
+
+ /**
+ * Set the disabled attribute
+ * @param {boolean} disabled
+ * @private
+ */
+ __setDisabledAttribute(disabled) {
+ if (disabled || this.__forceDisabled) {
+ this.domElement.setAttribute('disabled', 'true');
+ } else {
+ this.domElement.removeAttribute('disabled');
+ }
+ }
+
+ /**
+ * Handling click event from button
+ * @private
+ */
+ __onXRButtonClick() {
+ if (this.session) {
+ this.options.onEndSession(this.session);
+ } else if (this.device) {
+ this.options.onRequestSession(this.device);
+ }
+ }
+
+ /**
+ * Updates the display of the button based on it's current state
+ * @private
+ */
+ __updateButtonState() {
+ if (this.session) {
+ this.setTitle(this.options.textExitXRTitle);
+ this.setTooltip('Exit XR presentation');
+ this.__setDisabledAttribute(false);
+ } else if (this.device) {
+ this.setTitle(this.options.textEnterXRTitle);
+ this.setTooltip('Enter XR');
+ this.__setDisabledAttribute(false);
+ } else {
+ this.setTitle(this.options.textXRNotFoundTitle);
+ this.setTooltip('No XR headset found.');
+ this.__setDisabledAttribute(true);
+ }
+ }
+}
+
+/**
+ * Function checking if a specific css class exists as child of element.
+ *
+ * @param {HTMLElement} el element to find child in
+ * @param {string} cssPrefix css prefix of button
+ * @param {string} suffix class name
+ * @param {function} fn function to call if child is found
+ * @private
+ */
+const ifChild = (el, cssPrefix, suffix, fn)=> {
+ const c = el.querySelector('.' + cssPrefix + '-' + suffix);
+ c && fn(c);
+};
+
+return EnterXRButton;
+
+})();
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
new file mode 100644
index 00000000000..047e689bd52
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
@@ -0,0 +1,6196 @@
+/**
+ * @license
+ * webxr-polyfill
+ * Copyright (c) 2017 Google
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @license
+ * cardboard-vr-display
+ * Copyright (c) 2015-2017 Google
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @license
+ * webvr-polyfill-dpdb
+ * Copyright (c) 2017 Google
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @license
+ * wglu-preserve-state
+ * Copyright (c) 2016, Brandon Jones.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @license
+ * nosleep.js
+ * Copyright (c) 2017, Rich Tibbett
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global.WebXRPolyfill = factory());
+}(this, (function () { 'use strict';
+
+var _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");
+ }
+};
+
+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 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
+ }
+ });
+ 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()
+ };
+ }
+ 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);
+ }
+ }, {
+ 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();
+ }
+ }
+ }
+ }, {
+ 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 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));
+ }
+ }]);
+ return XR;
+}(EventTarget);
+
+var now = void 0;
+if ('performance' in _global === false) {
+ var startTime = Date.now();
+ now = function now() {
+ return Date.now() - startTime;
+ };
+} else {
+ now = function now() {
+ return 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);
+ }
+ createClass(XRPresentationContext, [{
+ key: 'canvas',
+ get: function get$$1() {
+ return this[PRIVATE$2].canvas;
+ }
+ }]);
+ return XRPresentationContext;
+}();
+
+var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+
+
+var degree = Math.PI / 180;
+
+function create() {
+ var out = new ARRAY_TYPE(16);
+ 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 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) {
+ 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;
+ 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) {
+ 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;
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+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;
+ 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) {
+ var trace = mat[0] + mat[5] + mat[10];
+ var 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) {
+ var f = 1.0 / Math.tan(fovy / 2);
+ var nf = 1 / (near - far);
+ 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[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 2 * far * near * nf;
+ out[15] = 0;
+ 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))
+ };
+ }
+ 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;
+}();
+
+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;
+}();
+
+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
+ };
+ }
+ 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;
+}();
+
+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
+ };
+ }
+ createClass(XRFrame, [{
+ key: 'getDevicePose',
+ value: function getDevicePose(coordinateSystem) {
+ this[PRIVATE$6].devicePose.updateFromFrameOfReference(coordinateSystem);
+ return this[PRIVATE$6].devicePose;
+ }
+ }, {
+ key: 'getInputPose',
+ value: function getInputPose(inputSource, coordinateSystem) {
+ return this[PRIVATE$6].polyfill.getInputPose(inputSource, coordinateSystem);
+ }
+ }, {
+ key: 'session',
+ get: function get$$1() {
+ return this[PRIVATE$6].session;
+ }
+ }, {
+ key: 'views',
+ get: function get$$1() {
+ return this[PRIVATE$6].views;
+ }
+ }]);
+ return XRFrame;
+}();
+
+var PRIVATE$7 = Symbol('@@webxr-polyfill/XRStageBoundsPoint');
+var XRStageBoundsPoint = function () {
+ function XRStageBoundsPoint(x, z) {
+ classCallCheck(this, XRStageBoundsPoint);
+ this[PRIVATE$7] = { x: x, z: z };
+ }
+ 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;
+}();
+
+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 };
+ }
+ createClass(XRStageBounds, [{
+ key: 'geometry',
+ get: function get$$1() {
+ return this[PRIVATE$8].geometry;
+ }
+ }]);
+ return XRStageBounds;
+}();
+
+var XRCoordinateSystem = function () {
+ function XRCoordinateSystem() {
+ classCallCheck(this, XRCoordinateSystem);
+ }
+ createClass(XRCoordinateSystem, [{
+ key: 'getTransformTo',
+ value: function getTransformTo(other) {
+ throw new Error('Not yet supported');
+ }
+ }]);
+ return XRCoordinateSystem;
+}();
+
+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;
+ }
+ }, {
+ key: 'bounds',
+ get: function get$$1() {
+ return this[PRIVATE$9].bounds;
+ }
+ }, {
+ key: 'emulatedHeight',
+ get: function get$$1() {
+ return this[PRIVATE$9].emulatedHeight;
+ }
+ }, {
+ key: 'type',
+ get: function get$$1() {
+ return this[PRIVATE$9].type;
+ }
+ }]);
+ return XRFrameOfReference;
+}(XRCoordinateSystem);
+
+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;
+ }
+ if (outputContext !== undefined && !(outputContext instanceof XRPresentationContext)) {
+ return false;
+ }
+ 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);
+ }
+ }]);
+ 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()
+ };
+ _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);
+ 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
+ };
+ } 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;
+ }
+ }]);
+ return DOMPointReadOnly;
+ }();
+}
+var DOMPointReadOnly$1 = domPointROExport;
+
+var XRRay =
+function XRRay() {
+ var origin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new DOMPointReadOnly$1(0, 0, 0, 1);
+ var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new DOMPointReadOnly$1(0, 0, -1, 0);
+ var transformMatrix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new Float32Array(16);
+ classCallCheck(this, XRRay);
+ if (!(origin instanceof DOMPointReadOnly$1)) {
+ throw new Error('origin must be a DOMPointReadOnly');
+ }
+ if (!(direction instanceof DOMPointReadOnly$1)) {
+ throw new Error('direction must be a DOMPointReadOnly');
+ }
+ if (!(transformMatrix instanceof Float32Array)) {
+ throw new Error('transformMatrix must be a Float32Array');
+ }
+ Object.defineProperties(this, {
+ origin: {
+ value: origin,
+ writable: false
+ },
+ direction: {
+ value: direction,
+ writable: false
+ },
+ transformMatrix: {
+ value: transformMatrix,
+ writable: false
+ }
+ });
+};
+
+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
+ };
+ }
+ 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;
+ }
+ }]);
+ 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);
+ }
+ 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');
+
+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');
+ }
+ }
+ 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
+ };
+ 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,
+ XRRay: XRRay
+};
+
+var extendContextCompatibleXRDevice = function extendContextCompatibleXRDevice(Context) {
+ if (typeof Context.prototype.setCompatibleXRDevice === 'function') {
+ return false;
+ }
+ 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;
+ }
+ return ctx;
+ };
+};
+
+function create$1() {
+ var out = new ARRAY_TYPE(3);
+ 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) {
+ 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);
+ 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;
+}
+
+
+
+
+
+
+
+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) {
+ 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(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+function cross(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;
+}
+
+
+
+
+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;
+ 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;
+ 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;
+ } else {
+ return Math.acos(cosine);
+ }
+}
+
+
+
+var sub$1 = subtract$1;
+
+
+
+
+var len = length;
+
+var forEach = function () {
+ var vec = create$1();
+ 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;
+ };
+}();
+
+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) {
+ 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;
+};
+var applyCanvasStylesForMinimalRendering = function 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 base64 = function base64(mimeType, _base) {
+ return 'data:' + mimeType + ';base64,' + _base;
+};
+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-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 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.matchRule_(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.matchRule_ = function (rule, ua, screenWidth, screenHeight) {
+ if (!rule.ua && !rule.res) return false;
+ 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 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));
+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._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, [{
+ key: 'init',
+ value: function init() {
+ var sensor = null;
+ try {
+ sensor = new RelativeOrientationSensor({ frequency: SENSOR_FREQUENCY });
+ 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();
+ }
+ window.addEventListener('orientationchange', this._onOrientationChange);
+ }
+ }, {
+ 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);
+ out.multiply(this._worldToScreenQ);
+ 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() {}
+ }, {
+ 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+';
+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 = base64('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 ? 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/AAj5IQAD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';
+ })
+ ]);
+});
+});
+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);
+
+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;
+ }
+ 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);
+ }
+ };
+}();
+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;
+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;
+ }
+}
+var OrientationArmModel = function () {
+ function OrientationArmModel() {
+ classCallCheck(this, OrientationArmModel);
+ 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();
+ }
+ 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));
+ } else {
+ copy$4(this.rootQ, headYawQ);
+ }
+ 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;
+ }
+ }, {
+ 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;
+ }
+ }, {
+ key: 'clamp_',
+ value: function clamp_(value, min$$1, max$$1) {
+ return Math.min(Math.max(value, min$$1), max$$1);
+ }
+ }, {
+ 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);
+ }
+ }]);
+ return OrientationArmModel;
+}();
+
+var GamepadXRInputSource = function () {
+ function GamepadXRInputSource(polyfill) {
+ var primaryButtonIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+ classCallCheck(this, GamepadXRInputSource);
+ this.polyfill = polyfill;
+ this.gamepad = null;
+ this.inputSource = new XRInputSource(this);
+ this.lastPosition = create$1();
+ this.emulatedPosition = false;
+ this.basePoseMatrix = create();
+ this.inputPoses = new WeakMap();
+ this.primaryButtonIndex = primaryButtonIndex;
+ this.primaryActionPressed = false;
+ this.handedness = '';
+ 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;
+ }
+ }
+ }, {
+ 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;
+ }
+ } 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;
+ }
+ }, {
+ 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 GamepadXRInputSource;
+}();
+
+var EXTRA_PRESENTATION_ATTRIBUTES = {
+ highRefreshRate: true
+};
+var 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([{
+ 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;
+ }
+ }
+ }, {
+ 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;
+ }
+ }, {
+ 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));
+ }
+ }, {
+ key: 'requestAnimationFrame',
+ value: function requestAnimationFrame(callback) {
+ return this.display.requestAnimationFrame(callback);
+ }
+ }, {
+ 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;
+ }
+ }
+ return Math.min(primaryButton, gamepad.buttons.length - 1);
+ }
+ }, {
+ 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;
+ }
+ }
+ }
+ }
+ 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;
+ }
+ if (canvas.height != oHeight) {
+ canvas.height = oHeight;
+ }
+ 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();
+ }
+ }
+ }, {
+ key: 'cancelAnimationFrame',
+ value: function cancelAnimationFrame(handle) {
+ this.display.cancelAnimationFrame(handle);
+ }
+ }, {
+ 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());
+ } else {
+ session.ended = true;
+ }
+ 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));
+ }
+ }, {
+ 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\'');
+ }
+ }
+ }, {
+ 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;
+ 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);
+ 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\'');
+ }
+ }
+ }, {
+ key: 'getInputSources',
+ value: function getInputSources() {
+ var inputSources = [];
+ for (var i in this.gamepadInputSources) {
+ inputSources.push(this.gamepadInputSources[i].inputSource);
+ }
+ return inputSources;
+ }
+ }, {
+ 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);
+ }
+ }
+ 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);
+ }
+ });
+ }
+ }
+ }, {
+ 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 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 = {
+ rightViewMatrix: new Float32Array(16),
+ leftViewMatrix: new Float32Array(16),
+ rightProjectionMatrix: new Float32Array(16),
+ leftProjectionMatrix: new Float32Array(16),
+ pose: 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);
+ }
+ }
+ function $If_4() {
+ return $return(device);
+ }
+ return $If_4.call(this);
+ }.bind(this));
+};
+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));
+};
+
+var CONFIG_DEFAULTS = {
+ 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;
+ this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config));
+ 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();
+ }
+ }
+ 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);
+ }
+ 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;
+ }
+ }
+ }
+ {
+ var polyfilledCtx = extendContextCompatibleXRDevice(global.WebGLRenderingContext);
+ if (polyfilledCtx) {
+ extendGetContext(global.HTMLCanvasElement);
+ if (global.WebGL2RenderingContext) {
+ extendContextCompatibleXRDevice(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;
+}();
+
+return WebXRPolyfill;
+
+})));
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js
new file mode 100644
index 00000000000..359fd08c6b2
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js
@@ -0,0 +1,220 @@
+// 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.
+
+// This file contains various patches to adjust for differences in outdated browser
+// implementations of the WebXR API and allow the samples to be coded exclusively
+// against the most recent version.
+
+class XRRayShim {
+ constructor(rayMatrix) {
+ this._transformMatrix = rayMatrix;
+
+ // TODO: Don't rely on these types for the shim.
+ // Some browsers don't support them yet.
+ let o = new DOMPointReadOnly(0, 0, 0, 1);
+ let d = new DOMPointReadOnly(0, 0, -1, 0);
+ let t = new DOMMatrix(rayMatrix);
+
+ this._origin = DOMPointReadOnly.fromPoint(t.transformPoint(o));
+ this._direction = DOMPointReadOnly.fromPoint(t.transformPoint(d));
+ }
+
+ get origin() {
+ return this._origin;
+ }
+
+ get direction() {
+ return this._direction;
+ }
+
+ get transformMatrix() {
+ return this._transformMatrix;
+ }
+}
+
+class WebXRVersionShim {
+ constructor() {
+ if (this._shouldApplyPatch()) {
+ this._applyPatch();
+ }
+ }
+
+ _isMobile() {
+ return /Android/i.test(navigator.userAgent) ||
+ /iPhone|iPad|iPod/i.test(navigator.userAgent);s
+ }
+
+ _shouldApplyPatch() {
+ // Don't apply the patch with WebXR isn't available.
+ if (!('xr' in navigator)) {
+ return false;
+ }
+
+ // Allow for universally disabling the version shim with a URL arg, which will
+ // make it easier to test updates to native implementations.
+ let query = window.location.search.substring(1) || window.location.hash.substring(1);
+ let vars = query.split('&');
+ for (let i = 0; i < vars.length; i++) {
+ let pair = vars[i].split('=');
+ if (pair[0].toLowerCase() == 'nowebxrversionshim') {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ _applyPatch() {
+ //===========================
+ // Chrome 67/68
+ //===========================
+
+ // Map 'immersive' to the old 'exclusive' verbiage if needed.
+ if ('exclusive' in XRSession.prototype) {
+ const NATIVE_SUPPORTS_SESSION = XRDevice.prototype.supportsSession;
+ XRDevice.prototype.supportsSession = function(options) {
+ options.exclusive = !!options.immersive;
+ return NATIVE_SUPPORTS_SESSION.call(this, options);
+ };
+
+ const NATIVE_REQUEST_SESSION = XRDevice.prototype.requestSession;
+ XRDevice.prototype.requestSession = function(options) {
+ options.exclusive = !!options.immersive;
+ return NATIVE_REQUEST_SESSION.call(this, options);
+ };
+
+ Object.defineProperty(XRSession.prototype, 'immersive', {
+ enumerable: true, configurable: false, writeable: false,
+ get: function() { return this.exclusive; }
+ });
+ }
+
+ // We can't test for the existence of the enums in question directly, so this code
+ // will just try to create the requested type and fall back if it fails.
+ const NATIVE_REQUEST_FRAME_OF_REFERENCE = XRSession.prototype.requestReferenceSpace;
+ XRSession.prototype.requestFrameOfReference = function(type, options_original) {
+ let session = this;
+ let options = options_original || {};
+ options["type"] = "stationary";
+ options["subtype"] = type;
+ // Try the current type.
+ return NATIVE_REQUEST_FRAME_OF_REFERENCE.call(session, options).catch((error)=>{
+ // FIXME: Should be checking for TypeError specifically. Requires a polyfill update.
+ if(error instanceof Error) {
+ // If the current type fails, switch to the other version.
+ switch(type) {
+ case 'eye-level':
+ options["subtype"] = 'eyeLevel';
+ break;
+ case 'head-model':
+ options["subtype"] = 'headModel';
+ break;
+ default:
+ return Promise.reject(error);
+ }
+ return Promise.resolve(NATIVE_REQUEST_FRAME_OF_REFERENCE.call(session, options));
+ } else {
+ return Promise.reject(error);
+ }
+ });
+ };
+
+ // Make sure that requestAnimationFrame is always supplied with a timestamp
+ const NATIVE_REQUEST_ANIMATION_FRAME = XRSession.prototype.requestAnimationFrame;
+ XRSession.prototype.requestAnimationFrame = function(callback) {
+ return NATIVE_REQUEST_ANIMATION_FRAME.call(this, (timestamp, frame) => {
+ callback(timestamp ? timestamp : performance.now(), frame);
+ });
+ };
+
+ if (!('getNativeFramebufferScaleFactor' in XRWebGLLayer)) {
+ if (this._isMobile()) {
+ const NATIVE_WEBGL_LAYER = XRWebGLLayer;
+ const NATIVE_WEBGL_LAYER_PROTOTYPE = XRWebGLLayer.prototype;
+ XRWebGLLayer = function(session, gl, options) {
+ if (options && options.framebufferScaleFactor) {
+ // On Chrome 67/68 mobile the default framebuffer returned is 0.7 of full res.
+ options.framebufferScaleFactor = 0.7 * options.framebufferScaleFactor;
+ }
+
+ return new NATIVE_WEBGL_LAYER(session, gl, options);
+ };
+
+ XRWebGLLayer.prototype = NATIVE_WEBGL_LAYER_PROTOTYPE;
+
+ Object.defineProperty(XRWebGLLayer, 'getNativeFramebufferScaleFactor', {
+ enumerable: true, configurable: false, writeable: false,
+ value: function(session) {
+ if (!session) {
+ throw new TypeError('No XRSession specified');
+ }
+ if (isMobile()) {
+ // On Chrome 67/68 mobile the default framebuffer returned is 0.7 of full res.
+ return 1.42857;
+ } else {
+ // On Chrome 67/68 desktop the full res buffer is already returned.
+ return 1.0;
+ }
+ }
+ });
+ }
+ }
+
+ // If the environmentBlendMode isn't available report it as 'opaque', since any
+ // implementations lacking this property only really worked on VR headsets.
+ if (!('environmentBlendMode' in XRSession.prototype)) {
+ Object.defineProperty(XRSession.prototype, 'environmentBlendMode', {
+ enumerable: true, configurable: false, writeable: false,
+ get: function() { return 'opaque'; }
+ });
+ }
+
+ if (!('targetRayMode' in XRInputSource.prototype)) {
+ Object.defineProperty(XRInputSource.prototype, 'targetRayMode', {
+ enumerable: true, configurable: false, writeable: false,
+ get: function() {
+ switch (this.pointerOrigin) {
+ case 'head': return 'gaze';
+ case 'hand': return 'tracked-pointer';
+ case 'screen': return 'screen';
+
+ default: throw new ValueError('Unrecognized pointerOrigin: ' + this.pointerOrigin);
+ }
+ }
+ });
+ }
+
+ if (!('targetRay' in XRInputPose.prototype)) {
+ Object.defineProperty(XRInputPose.prototype, 'targetRay', {
+ enumerable: true, configurable: false, writeable: false,
+ get: function() {
+ if (!this._targetRay) {
+ if (this.targetRayMatrix) {
+ this._targetRay = new XRRayShim(this.targetRayMatrix);
+ } else if (this.pointerMatrix) {
+ this._targetRay = new XRRayShim(this.pointerMatrix);
+ }
+ }
+ return this._targetRay || null;
+ }
+ });
+ }
+ }
+}
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
new file mode 100644
index 00000000000..3baa4c9185d
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/magic-window.html
@@ -0,0 +1,216 @@
+<!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, 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>Magic Window</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Magic Window</summary>
+ <p>
+ This sample demonstrates use of a non-immersive XRSession to present
+ 'Magic Window' content prior to entering XR presentation with an
+ immersive session.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // Shh! Nothing to see here, move along.
+ let arMode = QueryArgs.getBool('arMode', false);
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ let solarSystem = new Gltf2Node({url: 'media/gltf/space/space.gltf'});
+ scene.addNode(solarSystem);
+
+ if (arMode) {
+ solarSystem.scale = [0.2, 0.2, 0.2];
+ } else {
+ scene.addNode(new SkyboxNode({url: 'media/textures/milky-way-4k.png'}));
+ }
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ // In order for a non-immersive session to be used we must provide
+ // an outputContext, which indicates the canvas that will contain
+ // results of the session's rendering.
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ // Pick an arbitrary device for the magic window content and start
+ // up a non-immersive session if possible.
+ device.requestSession({outputContext: ctx})
+ .then((session) => {
+ // Add the canvas to the document once we know that it will be
+ // rendered to.
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ });
+ }
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({immersive: true, outputContext: ctx}).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ if (!gl) {
+ gl = createWebGLContext({
+ compatibleXRDevice: session.device
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ }
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ // Since we're dealing with multple sessions now we need to track
+ // which XRFrameOfReference is associated with which XRSession.
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ // Only reset the button when the immersive session ends.
+ if (event.session.immersive) {
+ // Remove the mirroring canvas.
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ // 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 frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ if (pose) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
+ if (!arMode) {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ }
+
+ for (let view of frame.views) {
+ let viewport = session.baseLayer.getViewport(view);
+ gl.viewport(viewport.x, viewport.y,
+ viewport.width, viewport.height);
+
+ scene.draw(view.projectionMatrix, pose.getViewMatrix(view));
+ }
+ }
+
+ scene.endFrame();
+ }
+
+ // Start the XR application.
+ initXR();
+ })();
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/mirroring.html b/chromium/third_party/webxr_test_pages/webxr-samples/mirroring.html
new file mode 100644
index 00000000000..d552693cc72
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/mirroring.html
@@ -0,0 +1,198 @@
+<!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, 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>Mirroring</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Mirroring</summary>
+ <p>
+ This sample demonstrates how to present a simple WebGL scene to a
+ XRDevice while mirroring to a context. The scene is not rendered to
+ the page prior to XR presentation. Mirroring has no effect on mobile
+ or standalone devices.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <main style='text-align: center;'>
+ <p>Click 'Enter XR' to see content</p>
+ </main>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new Gltf2Node({url: 'media/gltf/space/space.gltf'}));
+ scene.addNode(new SkyboxNode({url: 'media/textures/milky-way-4k.png'}));
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+ });
+ }
+ }
+
+ function onRequestSession(device) {
+ // In order to mirror an exclusive session, we must provide
+ // an XRPresentationContext, which indicates the canvas that will
+ // contain results of the session's rendering.
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+
+ // Add the canvas to the document.
+ document.body.appendChild(mirrorCanvas);
+
+ // Providing an outputContext when requesting an exclusive session
+ // indicates that it should be used as the mirror destination.
+ device.requestSession({
+ immersive: true,
+ outputContext: ctx
+ }).then(onSessionStarted);
+ }
+
+ function onSessionStarted(session) {
+ xrButton.setSession(session);
+
+ session.addEventListener('end', onSessionEnded);
+
+ if (!gl) {
+ gl = createWebGLContext({
+ compatibleXRDevice: session.device
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ }
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ // Set the mirroring context to be the same size as one eye on the
+ // layer context.
+ let outputCanvas = document.querySelector('#mirror-canvas');
+ outputCanvas.width = session.baseLayer.framebufferWidth / 2;
+ outputCanvas.height = session.baseLayer.framebufferHeight;
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ xrFrameOfRef = frameOfRef;
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ xrButton.setSession(null);
+
+ gl = null;
+
+ // Remove the injected mirroring canvas from the DOM.
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ let pose = frame.getDevicePose(xrFrameOfRef);
+
+ if (pose) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ for (let view of frame.views) {
+ let viewport = session.baseLayer.getViewport(view);
+ gl.viewport(viewport.x, viewport.y,
+ viewport.width, viewport.height);
+
+ scene.draw(view.projectionMatrix, pose.getViewMatrix(view));
+ }
+ }
+
+ // Per-frame scene teardown. Nothing WebXR specific here.
+ scene.endFrame();
+ }
+
+ // Start the XR application.
+ initXR();
+ })();
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/module-tester.html b/chromium/third_party/webxr_test_pages/webxr-samples/module-tester.html
new file mode 100644
index 00000000000..5d3de9e27c1
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/module-tester.html
@@ -0,0 +1,301 @@
+<!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, 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>Scene tester</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <style>
+ #scene-select {
+ position: absolute;
+ z-index: 2;
+ }
+ </style>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Module Tester</summary>
+ <p>
+ Just a simple test page to allow developers to test sample scenes
+ without a headset.<br/>
+ WASD + Mouse Click/Drag to move.
+ </p>
+ <select id='scene-select'>
+ <option value='void' selected>Void</option>
+ <option value='cube-sea'>Cube Sea</option>
+ <option value='space'>Space (glTF)</option>
+ <option value='camp'>Camp (glTF)</option>
+ <option value='cave'>Cave (glTF)</option>
+ <option value='garage'>Garage (glTF)</option>
+ <option value='cube-room'>Cube Room (glTF)</option>
+ <option value='home-theater'>Home Theater (glTF)</option>
+ </select>
+ </details>
+ </header>
+
+ <script type="module">
+ import {Scene} from './js/cottontail/src/scenes/scene.js';
+ import {Renderer, createWebGLContext} from './js/cottontail/src/core/renderer.js';
+ import {UrlTexture} from './js/cottontail/src/core/texture.js';
+
+ import {BoxBuilder} from './js/cottontail/src/geometry/box-builder.js';
+ import {PbrMaterial} from './js/cottontail/src/materials/pbr.js';
+
+ import {ButtonNode} from './js/cottontail/src/nodes/button.js';
+ import {CubeSeaNode} from './js/cottontail/src/nodes/cube-sea.js';
+ import {Gltf2Node} from './js/cottontail/src/nodes/gltf2.js';
+
+ const IDENTITY_MATRIX = new Float32Array([1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 1.6, 0, 1]);
+
+ let projectionMat = mat4.create();
+ let viewMat = mat4.create();
+
+ let scene = null;
+ let gl = createWebGLContext({antialias: false});
+ document.body.appendChild(gl.canvas);
+
+ let renderer = new Renderer(gl);
+
+ let boxNodes = [];
+
+ function setScene(newScene) {
+ scene = newScene;
+ scene.standingStats(true);
+ scene.addNode(new SkyboxNode({url: 'media/textures/milky-way-4k.png'}));
+
+ let stereo = new Gltf2Node({url: 'media/gltf/stereo/stereo.gltf'});
+ stereo.selectable = true;
+ boxNodes.push(stereo);
+ scene.addNode(stereo);
+
+ scene.setRenderer(renderer);
+
+ let boxBuilder = new BoxBuilder();
+
+ function addBox(x, y, z) {
+ boxBuilder.pushCube([x, y, z], 0.3);
+ let boxPrimitve = boxBuilder.primitiveStream.finishPrimitive(renderer);
+
+ let boxMaterial = new PbrMaterial();
+ boxMaterial.baseColorFactor.value = [0.0, 0.3, 1.0, 1.0];
+
+ let node = renderer.createMesh(boxPrimitve, boxMaterial);
+ node.selectable = true;
+ scene.addNode(node);
+ boxNodes.push(node);
+ boxBuilder.clear();
+ }
+
+ /*addBox(0, 0, -1.0);
+ addBox(-0.7, 0, -1.0);
+ addBox(0.7, 0, -1.0);
+ addBox(0, -0.7, -1.0);
+ addBox(0, 0.7, -1.0);
+ addBox(-0.7, -0.7, -1.0);
+ addBox(0.7, -0.7, -1.0);
+ addBox(-0.7, 0.7, -1.0);
+ addBox(0.7, 0.7, -1.0);*/
+
+ let button = new ButtonNode(new UrlTexture('media/textures/play-button.png'), () => {
+ // Do something?
+ button.iconTexture = new UrlTexture('media/textures/pause-button.png');
+ console.log("Button clicked");
+ });
+ scene.addNode(button);
+ }
+
+ function onResize () {
+ gl.canvas.width = gl.canvas.offsetWidth * window.devicePixelRatio;
+ gl.canvas.height = gl.canvas.offsetHeight * window.devicePixelRatio;
+
+ gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
+ mat4.perspective(projectionMat, Math.PI*0.4,
+ gl.canvas.width/gl.canvas.height,
+ 0.1, 1000.0);
+ }
+ window.addEventListener('resize', onResize);
+ onResize();
+
+ // Simple flight controls
+ let pressedKeys = new Array(256);
+ let selectStarted = false;
+ let selectPending = false;
+ let lookYaw = 0;
+ let lookPitch = 0;
+ let lookPos = [0, 0, 0];
+ const lookSpeed = 0.0025;
+ const moveSpeed = 0.0025;
+ window.addEventListener('keydown', (ev) => pressedKeys[ev.keyCode] = true);
+ window.addEventListener('keyup', (ev) => pressedKeys[ev.keyCode] = false);
+ window.addEventListener('mousemove', (ev) => {
+ // Only rotate when the left button is pressed
+ if (ev.buttons && 1) {
+ lookYaw += ev.movementX * lookSpeed;
+
+ lookPitch += ev.movementY * lookSpeed;
+ if (lookPitch < -Math.PI*0.5)
+ lookPitch = -Math.PI*0.5;
+ if (lookPitch > Math.PI*0.5)
+ lookPitch = Math.PI*0.5;
+ }
+ });
+
+ function updateView(delta) {
+ if (pressedKeys[' '.charCodeAt(0)]) {
+ selectStarted = true;
+ } else if (selectStarted) {
+ selectStarted = false;
+ selectPending = true;
+ }
+
+ let moveDir = [0, 0, 0];
+
+ if(pressedKeys['W'.charCodeAt(0)]) {
+ moveDir[2] += 1;
+ }
+ if(pressedKeys['S'.charCodeAt(0)]) {
+ moveDir[2] -= 1;
+ }
+ if(pressedKeys['A'.charCodeAt(0)]) {
+ moveDir[0] += 1;
+ }
+ if(pressedKeys['D'.charCodeAt(0)]) {
+ moveDir[0] -= 1;
+ }
+
+ vec3.normalize(moveDir, moveDir);
+ vec3.scale(moveDir, moveDir, delta * moveSpeed);
+
+ mat4.identity(viewMat);
+ mat4.rotateY(viewMat, viewMat, -lookYaw);
+ mat4.rotateX(viewMat, viewMat, -lookPitch);
+
+ vec3.transformMat4(moveDir, moveDir, viewMat);
+ vec3.add(lookPos, lookPos, moveDir);
+
+ mat4.identity(viewMat);
+ mat4.rotateX(viewMat, viewMat, lookPitch);
+ mat4.rotateY(viewMat, viewMat, lookYaw);
+ mat4.translate(viewMat, viewMat, lookPos);
+ };
+
+ let selectedNode = null;
+
+ function checkRay(targetRay) {
+ if (selectedNode) {
+ //selectedNode.visible = true;
+ }
+ let hitResult = scene.hitTest(targetRay);
+ if (hitResult) {
+ selectedNode = hitResult.node;
+ //selectedNode.visible = false;
+ scene.inputRenderer.addCursor(hitResult.intersection);
+ } else {
+ selectedNode = null;
+ }
+ }
+
+ let targetRayMatrix = mat4.create();
+ function onGLFrame(t) {
+ window.requestAnimationFrame(onGLFrame);
+
+ if (!scene)
+ return;
+
+ let frameDelta = scene.startFrame();
+ updateView(frameDelta);
+
+ let cursorPos = vec3.fromValues(0, 0, -2.0);
+ mat4.invert(targetRayMatrix, viewMat);
+ vec3.transformMat4(cursorPos, cursorPos, targetRayMatrix);
+
+ scene.inputRenderer.addCursor(cursorPos);
+
+ let mat = mat4.create();
+ mat4.identity(mat);
+ mat4.translate(mat, mat, [Math.sin(t / 1000), 0, Math.cos(t / 1000)]);
+ mat4.rotateY(mat, mat, t / 1000);
+
+ for (let boxNode of boxNodes) {
+ boxNode.matrix = mat;
+ }
+
+ checkRay(targetRayMatrix);
+
+ if (selectPending) {
+ selectPending = false;
+ scene.handleSelectPointer(targetRayMatrix);
+ }
+
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+
+ scene.draw(projectionMat, viewMat);
+
+ scene.endFrame();
+ }
+ window.requestAnimationFrame(onGLFrame);
+
+ let sceneSelect = document.getElementById('scene-select');
+ function onSceneSelected() {
+ let scene = new Scene();
+ switch(sceneSelect.value) {
+ case 'void':
+ break;
+ case 'cube-sea':
+ scene.addNode(new CubeSeaNode());
+ break;
+ default:
+ scene.addNode(new Gltf2Node({url: `media/gltf/${sceneSelect.value}/${sceneSelect.value}.gltf`}));
+ break;
+ }
+ setScene(scene);
+ }
+ sceneSelect.addEventListener('change', onSceneSelected);
+ onSceneSelected();
+ </script>
+ </body>
+</html>
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
new file mode 100644
index 00000000000..0b9b72b0aee
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/positional-audio.html
@@ -0,0 +1,484 @@
+<!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, 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>Positional Audio</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src="https://cdn.jsdelivr.net/npm/resonance-audio/build/resonance-audio.min.js"></script>
+
+ <script src='js/cottontail/build/cottontail.debug.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Positional Audio</summary>
+ <p>
+ This sample demonstrates playing audio that sounds as if it originates
+ at a specific point in the space. Audio will begin playing when you
+ enter XR.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // Temporary
+ let hideStats = QueryArgs.getBool('hideStats', false);
+
+ const DEFAULT_HEIGHT = 1.5;
+ const ANALYSER_FFT_SIZE = 1024;
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = 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/garage/garage.gltf'}));
+ scene.standingStats(true);
+
+ let playButton = null;
+ let playTexture = new UrlTexture('media/textures/play-button.png');
+ let pauseTexture = new UrlTexture('media/textures/pause-button.png');
+ let stereo = new Gltf2Node({url: 'media/gltf/stereo/stereo.gltf'});
+ // FIXME: Temporary fix to initialize for cloning.
+ stereo.visible = false;
+ scene.addNode(stereo);
+
+ // Audio scene globals
+ let audioContext = new AudioContext();
+ let resonance = new ResonanceAudio(audioContext);
+ resonance.output.connect(audioContext.destination);
+
+ audioContext.suspend();
+
+ // TODO: This is crashing in recent versions of Resonance for me, and I'm
+ // not sure why. It does run succesfully without it, though.
+ // Rough room dimensions in meters (estimated from model in Blender.)
+ /*let roomDimensions = {
+ width : 6,
+ height : 3,
+ depth : 6
+ };
+
+ // Simplified view of the materials that make up the scene.
+ let roomMaterials = {
+ left : 'plywood-panel', // Garage walls
+ right : 'plywood-panel',
+ front : 'plywood-panel',
+ back : 'metal', // To account for the garage door
+ down : 'polished-concrete-or-tile', // garage floor
+ up : 'wood-ceiling'
+ };
+ resonance.setRoomProperties(roomDimensions, roomMaterials);*/
+
+ function createAudioSource(options) {
+ // Create a Resonance source and set its position in space.
+ let source = resonance.createSource();
+ let pos = options.position;
+ source.setPosition(pos[0], pos[1], pos[2]);
+
+ // Connect an analyser. This is only for visualization of the audio, and
+ // in most cases you won't want it.
+ let analyser = audioContext.createAnalyser();
+ analyser.fftSize = ANALYSER_FFT_SIZE;
+ analyser.lastRMSdB = 0;
+
+ return fetch(options.url)
+ .then((response) => response.arrayBuffer())
+ .then((buffer) => audioContext.decodeAudioData(buffer))
+ .then((decodedBuffer) => {
+ let bufferSource = createBufferSource(
+ source, decodedBuffer, analyser);
+
+ return {
+ buffer: decodedBuffer,
+ bufferSource: bufferSource,
+ source: source,
+ analyser: analyser,
+ position: pos,
+ rotateY: options.rotateY,
+ node: null
+ };
+ });
+ }
+
+ function createBufferSource(source, buffer, analyser) {
+ // Create a buffer source. This will need to be recreated every time
+ // we wish to start the audio, see
+ // https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode
+ let bufferSource = audioContext.createBufferSource();
+ bufferSource.loop = true;
+ bufferSource.connect(source.input);
+
+ bufferSource.connect(analyser);
+
+ bufferSource.buffer = buffer;
+
+ return bufferSource;
+ }
+
+ /**
+ * Returns a floating point value that represents the loudness of the audio
+ * stream, appropriate for scaling an object with.
+ * @return {Number} loudness scalar.
+ */
+ let fftBuffer = new Float32Array(ANALYSER_FFT_SIZE);
+ function getLoudnessScale(analyser) {
+ analyser.getFloatTimeDomainData(fftBuffer);
+ let sum = 0;
+ for (let i = 0; i < fftBuffer.length; ++i)
+ sum += fftBuffer[i] * fftBuffer[i];
+
+ // Calculate RMS and convert it to DB for perceptual loudness.
+ let rms = Math.sqrt(sum / fftBuffer.length);
+ let db = 30 + 10 / Math.LN10 * Math.log(rms <= 0 ? 0.0001 : rms);
+
+ // Moving average with the alpha of 0.525. Experimentally determined.
+ analyser.lastRMSdB += 0.525 * ((db < 0 ? 0 : db) - analyser.lastRMSdB);
+
+ // Scaling by 1/30 is also experimentally determined. Max is to present
+ // objects from disappearing entirely.
+ return Math.max(0.3, analyser.lastRMSdB / 30.0);
+ }
+
+ let audioSources = [];
+
+ function updateAudioNodes() {
+ if (!stereo)
+ return;
+
+ for (let source of audioSources) {
+ if (!source.node) {
+ source.node = stereo.clone();
+ source.node.visible = true;
+ source.node.selectable = true;
+ scene.addNode(source.node);
+ }
+
+ let node = source.node;
+ let matrix = node.matrix;
+
+ // Move the node to the right location.
+ mat4.identity(matrix);
+ mat4.translate(matrix, matrix, source.position);
+ mat4.rotateY(matrix, matrix, source.rotateY);
+
+ // Scale it based on loudness of the audio channel
+ let scale = getLoudnessScale(source.analyser);
+ mat4.scale(matrix, matrix, [scale, scale, scale]);
+ }
+ }
+
+ function playAudio() {
+ if (audioContext.state == 'running')
+ return;
+
+ audioContext.resume();
+
+ for (let source of audioSources) {
+ source.bufferSource.start(0);
+ }
+
+ if (playButton) {
+ playButton.iconTexture = pauseTexture;
+ }
+ }
+
+ function pauseAudio() {
+ if (audioContext.state == 'suspended')
+ return;
+
+ for (let source of audioSources) {
+ source.bufferSource.stop(0);
+ source.bufferSource = createBufferSource(
+ source.source, source.buffer, source.analyser);
+ }
+
+ audioContext.suspend();
+
+ if (playButton) {
+ playButton.iconTexture = playTexture;
+ }
+ }
+
+ window.addEventListener('blur', () => {
+ // As a general rule you should mute any sounds your page is playing
+ // whenever the page loses focus.
+ pauseAudio();
+ });
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ // Load multiple audio sources.
+ Promise.all([
+ createAudioSource({
+ url: 'media/sound/guitar.ogg',
+ position: [0, DEFAULT_HEIGHT, -1],
+ rotateY: 0
+ }),
+ createAudioSource({
+ url: 'media/sound/drums.ogg',
+ position: [-1, DEFAULT_HEIGHT, 0],
+ rotateY: Math.PI * 0.5
+ }),
+ createAudioSource({
+ url: 'media/sound/perc.ogg',
+ position: [1, DEFAULT_HEIGHT, 0],
+ rotateY: Math.PI * -0.5
+ }),
+ ]).then((sources) => {
+ audioSources = sources;
+
+ // Once the audio is loaded, create a button that toggles the
+ // audio state when clicked.
+ playButton = new ButtonNode(playTexture, () => {
+ if (audioContext.state == 'running') {
+ pauseAudio();
+ } else {
+ playAudio();
+ }
+ });
+ playButton.translation = [0, 1.2, -0.65];
+ scene.addNode(playButton);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ fallbackHelper.emulateStage = true;
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ session.addEventListener('selectstart', onSelectStart);
+ session.addEventListener('selectend', onSelectEnd);
+ session.addEventListener('select', (ev) => {
+ let frameOfRef = ev.frame.session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ scene.handleSelect(ev.inputSource, ev.frame, frameOfRef);
+ });
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('stage').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+
+ // Stop the audio playback when we exit XR.
+ pauseAudio();
+ }
+ }
+
+ let draggingSource = null;
+ let draggingInput = null;
+ let draggingTransform = mat4.create();
+
+ function hitTest(inputSource, frame, frameOfRef) {
+ let inputPose = frame.getInputPose(inputSource, frameOfRef);
+ if (!inputPose) {
+ return;
+ }
+
+ if (inputPose.targetRay) {
+ let hitResult = scene.hitTest(inputPose.targetRay)
+ if (hitResult) {
+ for (let source of audioSources) {
+ if (hitResult.node == source.node) {
+ draggingSource = source;
+ draggingInput = inputSource;
+ mat4.invert(draggingTransform, inputPose.targetRay.transformMatrix);
+ mat4.multiply(draggingTransform, draggingTransform, source.node.matrix);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ function onSelectStart(ev) {
+ let frameOfRef = ev.frame.session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ hitTest(ev.inputSource, ev.frame, frameOfRef);
+ }
+
+ function onSelectEnd(ev) {
+ draggingSource = null;
+ draggingInput = null;
+ }
+
+ let tmpMatrix = mat4.create();
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ scene.updateInputSources(frame, frameOfRef);
+
+ if (draggingSource) {
+ let draggingPose = frame.getInputPose(draggingInput, frameOfRef);
+ if (draggingPose) {
+ let pos = draggingSource.position;
+ mat4.multiply(tmpMatrix, draggingPose.targetRay.transformMatrix, draggingTransform);
+ vec3.transformMat4(pos, [0, 0, 0], tmpMatrix);
+ draggingSource.source.setPosition(pos[0], pos[1], pos[2]);
+ }
+ }
+
+ updateAudioNodes();
+
+ scene.drawXRFrame(frame, pose);
+
+ if (pose) {
+ resonance.setListenerFromMatrix({ elements: pose.poseModelMatrix });
+ }
+
+ scene.endFrame();
+ }
+
+ // Start the XR application.
+ initXR();
+ })();
+ </script>
+ </body>
+</html>
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
new file mode 100644
index 00000000000..41310ae4841
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/index.html
@@ -0,0 +1,172 @@
+<!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 - Proposals</title>
+ </head>
+ <body>
+
+ <div class='container' id='container'>
+ <header class='header'>
+ <div id='nav'>
+ <a href='../'>Samples</a>
+ <a href='./' class='selected'>Proposals</a>
+ <a href='../tests/'>Test Pages</a>
+ </div>
+
+ <h1><a href='' class='wordmark'><span>WebXR</span></a></h1>
+ <h2 class='tagline'>Proposals</h2>
+ </header>
+
+ <main class='main' id='main'>
+ <p>These pages test features which have been proposed and are in development but have
+ not yet been adopted into the core WebXR Device API. They may have varying support
+ across WebXR-compatible browsers, and the APIs presented here are assumed to be
+ in flux.<br/>
+
+ <script>
+ let pages = [
+ { title: 'Phone AR', category: 'Phone AR',
+ path: 'phone-ar.html',
+ description: 'Demonstrates basic support for passthrough AR on a mobile device.' },
+
+ { title: 'AR Hit Test', category: 'Phone AR',
+ path: 'phone-ar-hit-test.html',
+ description: 'Demonstrates using the Hit Test API to place virtual objects on real-world surfaces.' },
+ ];
+
+ let mainElement = document.getElementById("main");
+
+ // Append an element for every item in the pages list.
+ for (var i = 0; i < pages.length; ++i) {
+ var page = pages[i];
+
+ let article = document.createElement('article');
+
+ let title = document.createElement('h3');
+ title.setAttribute('data-index', i + 1);
+
+ 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);
+
+ let sourceLink = document.createElement('a');
+ sourceLink.href = 'https://github.com/immersive-web/webxr-samples/blob/master/proposals/' + page.path;
+ sourceLink.innerHTML = 'Source';
+ links.appendChild(sourceLink);
+
+ article.appendChild(links);
+
+ mainElement.appendChild(article);
+ }
+ </script>
+ </main>
+
+ <br/>
+
+ <h3><a class='github-link' href='https://github.com/immersive-web/webxr-samples'>View source on GitHub</a></h3>
+
+ <footer class='footer'>
+ </footer>
+ </div>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html
new file mode 100644
index 00000000000..201501a14a0
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html
@@ -0,0 +1,272 @@
+<!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, 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>
+
+ <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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='../js/webxr-version-shim.js'></script>
+
+ <script src='../js/cottontail/build/cottontail.js'></script>
+
+ <script src='../js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>AR Hit Test</summary>
+ <p>
+ This sample demonstrates use of hit testing to place AR objects on real-world surfaces.
+ <a class="back" href="./">Back</a>
+ <br/>
+ <hr/>
+ <input id="useReticle" type="checkbox" checked>
+ <label for="useReticle">Use reticle for placement</label>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ let useReticle = document.getElementById('useReticle');
+
+ // XR globals.
+ let xrButton = null;
+ let xrFrameOfRef = null;
+
+ let outputCanvas = document.createElement('canvas');
+ outputCanvas.setAttribute('id', 'output-canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.enableStats(false);
+
+ let arObject = new Node();
+ arObject.visible = false;
+ scene.addNode(arObject);
+
+ let flower = new Gltf2Node({url: '../media/gltf/sunflower/sunflower.gltf'});
+ arObject.addNode(flower);
+
+ // Having a really simple drop shadow underneath an object helps ground
+ // it in the world without adding much complexity.
+ let shadow = new DropShadowNode();
+ vec3.set(shadow.scale, 0.15, 0.15, 0.15);
+ arObject.addNode(shadow);
+
+ const MAX_FLOWERS = 30;
+ let flowers = [];
+
+ // Ensure the background is transparent for AR.
+ scene.clear = false;
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession,
+ textEnterXRTitle: "START AR",
+ textXRNotFoundTitle: "AR NOT FOUND",
+ textExitXRTitle: "EXIT AR",
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({ environmentIntegration: true, outputContext: ctx }).then(() => {
+ xrButton.setDevice(device);
+ });
+ });
+ }
+ }
+
+ function onRequestSession(device) {
+ device.requestSession({ environmentIntegration: true, outputContext: ctx })
+ .then((session) => {
+ // Add the canvas to the document once we know that it will be
+ // rendered to.
+ document.body.appendChild(outputCanvas);
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+ session.addEventListener('select', onSelect);
+
+ if (!gl) {
+ gl = createWebGLContext({
+ compatibleXRDevice: session.device,
+ xrCompatible : true,
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ }
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ xrFrameOfRef = frameOfRef;
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ // Remove the injected output canvas from the DOM.
+ document.body.removeChild(document.querySelector('#output-canvas'));
+ }
+
+ function onSessionEnded(event) {
+ xrButton.setSession(null);
+ }
+
+ // Adds a new object to the scene at the
+ // specificed transform.
+ function addARObjectAt(matrix) {
+ let newFlower = arObject.clone();
+ newFlower.visible = true;
+ newFlower.matrix = matrix;
+ scene.addNode(newFlower);
+
+ flowers.push(newFlower);
+
+ // For performance reasons if we add too many objects start
+ // removing the oldest ones to keep the scene complexity
+ // from growing too much.
+ if (flowers.length > MAX_FLOWERS) {
+ let oldFlower = flowers.shift();
+ scene.removeNode(oldFlower);
+ }
+ }
+
+ let rayOrigin = vec3.create();
+ let rayDirection = vec3.create();
+ function onSelect(event) {
+ if (useReticle.checked && arObject.visible) {
+ // If we're using the reticle then we've already got a mesh positioned
+ // at the latest hit point and we should just use it's matrix to save
+ // an unnecessary requestHitTest call.
+ addARObjectAt(arObject.matrix);
+ } else {
+ // Otherwise we'll use the target ray from the input source that generated
+ // this event to fire off a new hit test.
+ let inputPose = event.frame.getInputPose(event.inputSource, xrFrameOfRef);
+ if (!inputPose) {
+ return;
+ }
+
+ if (inputPose.targetRay) {
+ vec3.set(rayOrigin,
+ inputPose.targetRay.origin.x,
+ inputPose.targetRay.origin.y,
+ inputPose.targetRay.origin.z);
+ vec3.set(rayDirection,
+ inputPose.targetRay.direction.x,
+ inputPose.targetRay.direction.y,
+ inputPose.targetRay.direction.z);
+ event.frame.session.requestHitTest(rayOrigin, rayDirection, xrFrameOfRef).then((results) => {
+ if (results.length) {
+ addARObjectAt(results[0].hitMatrix);
+ }
+ });
+ }
+ }
+ }
+
+ // Called every time a XRSession requests that a new frame be drawn.
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let pose = frame.getViewerPose(xrFrameOfRef);
+
+ // 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
+ // as the "reticle".
+ if (useReticle.checked && pose && pose.poseModelMatrix) {
+ vec3.set(rayOrigin, 0, 0, 0);
+ vec3.transformMat4(rayOrigin, rayOrigin, pose.poseModelMatrix);
+
+ vec3.set(rayDirection, 0, 0, -1);
+ vec3.transformMat4(rayDirection, rayDirection, pose.poseModelMatrix);
+ vec3.sub(rayDirection, rayDirection, rayOrigin);
+ vec3.normalize(rayDirection, rayDirection);
+
+ session.requestHitTest(rayOrigin, rayDirection, xrFrameOfRef).then((results) => {
+ // When the hit test returns use it to place our proxy object.
+ if (results.length) {
+ let hitResult = results[0];
+ arObject.visible = true;
+ arObject.matrix = hitResult.hitMatrix;
+ } else {
+ arObject.visible = false;
+ }
+ });
+ } else {
+ arObject.visible = false;
+ }
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ 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/proposals/phone-ar.html b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
new file mode 100644
index 00000000000..69c502d4440
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
@@ -0,0 +1,188 @@
+<!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, 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>Phone AR</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='../js/webxr-version-shim.js'></script>
+
+ <script src='../js/cottontail/build/cottontail.js'></script>
+
+ <script src='../js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Phone AR</summary>
+ <p>
+ This sample demonstrates use of a non-exclusive XRSession to present
+ Augmented Reality content.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrFrameOfRef = null;
+
+ // AR sessions must have an outputContext, just like magic window
+ // sessions.
+ let outputCanvas = document.createElement('canvas');
+ outputCanvas.setAttribute('id', 'output-canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ let solarSystem = new Gltf2Node({url: '../media/gltf/space/space.gltf'});
+ // The solar system is big (citation needed). Scale it down so that users can
+ // move around the planets more easily.
+ solarSystem.scale = [0.1, 0.1, 0.1];
+ scene.addNode(solarSystem);
+
+ // No skybox is added to this scene, and we're not clearing the background to
+ // black because we want the real world to show through.
+ scene.clear = false;
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession,
+ textEnterXRTitle: "START AR",
+ textXRNotFoundTitle: "AR NOT FOUND",
+ textExitXRTitle: "EXIT AR",
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ // Checks to ensure that environment integration (AR) is available,
+ // and only enables the button if so.
+ device.supportsSession({ environmentIntegration: true, outputContext: ctx }).then(() => {
+ xrButton.setDevice(device);
+ });
+ });
+ }
+ }
+
+ function onRequestSession(device) {
+ // Requests an inline (non-immersive) session with environment integration
+ // to get AR via video passthrough.
+
+ // 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.
+ device.requestSession({ environmentIntegration: true, outputContext: ctx })
+ .then((session) => {
+ // Add the canvas to the document once we know that it will be
+ // rendered to.
+ document.body.appendChild(outputCanvas);
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ if (!gl) {
+ gl = createWebGLContext({
+ compatibleXRDevice: session.device,
+ xrCompatible : true,
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ }
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ xrFrameOfRef = frameOfRef;
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ // Remove the injected output canvas from the DOM.
+ document.body.removeChild(document.querySelector('#output-canvas'));
+ }
+
+ function onSessionEnded(event) {
+ xrButton.setSession(null);
+ }
+
+ // Called every time a XRSession requests that a new frame be drawn.
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let pose = frame.getViewerPose(xrFrameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ 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/reduced-bind-rendering.html b/chromium/third_party/webxr_test_pages/webxr-samples/reduced-bind-rendering.html
new file mode 100644
index 00000000000..585e6df4cea
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/reduced-bind-rendering.html
@@ -0,0 +1,267 @@
+<!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, 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>Reduced Bind Rendering</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Reduced Bind Rendering</summary>
+ <p>
+ This sample demonstrates a simple technique to reduce the number of
+ state changes an application needs to make while rendering, potentially
+ enabling better performance.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new CubeSeaNode());
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ // This kicks off a really simple fallback rendering loop so that we don't
+ // have to clutter up the sample code with fallback rendering logic. This
+ // variant also has the benefit of including simple support for looking
+ // around via clicking and dragging with the right mouse button or a two-
+ // finger drag.
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+ // Set up a non-black clear color so that we can see if something renders wrong.
+ gl.clearColor(0.1, 0.2, 0.3, 1.0);
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ if (pose) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // This is a different rendering pattern than the previous samples
+ // used, but it should be more efficent. It's very common for apps
+ // being ported to XR to take existing 2D rendering code and call the
+ // top-level "drawScene" function once per XR view, effectively
+ // drawing a single eye at a time. However, this causes many state
+ // changes to be duplicated, which adds to the render loop's overhead.
+ // By providing the matrices and viewports as an array to the drawing
+ // function it can do all the necessary binding once and then call the
+ // actual draw commands in a tighter loop, only changing the matrices
+ // and viewport each time. This does mean that the viewport is changed
+ // much more frequently (N times per object instead of N times per
+ // scene) but it's typically a pretty cheap thing to change and will
+ // almost always be easily outweighed by the savings from not
+ // redundantly binding everything else.
+
+ // For example, a traditional draw loop would do this:
+
+ // Draw(views):
+ // for each view in views:
+ // setViewport();
+ // for each object in scene:
+ // bindProgram();
+ // bindMatrices();
+ // bindUniforms();
+ // bindBuffers();
+ // bindTextures();
+ // draw();
+
+ // While this method results in a loop more like this:
+
+ // Draw(views):
+ // for each object in scene:
+ // bindProgram();
+ // bindUniforms();
+ // bindBuffers();
+ // bindTextures();
+ // for each view in views:
+ // setViewport();
+ // bindMatrices();
+ // draw();
+
+ // Note that for the complexity of the scene in this samples this
+ // won't make much visible performance difference, but we're using the
+ // more efficient pattern anyway as a way of promoting best practices.
+
+ let views = [];
+ for (let view of frame.views) {
+ // Gather all the values needed for one view and push it into the
+ // array of views to be drawn. WebXRView is a utility class that
+ // holds all the necessary values for drawing a single view.
+ let renderView = new WebXRView();
+
+ // In future samples we'll hide this part away as well by using the
+ // scene.drawXRViews() function, which handles gathering these
+ // values internally.
+ renderView.projectionMatrix = view.projectionMatrix;
+ renderView.viewMatrix = pose.getViewMatrix(view);
+ renderView.viewport = session.baseLayer.getViewport(view);
+ views.push(renderView);
+ }
+
+ scene.drawViewArray(views);
+ }
+
+ scene.endFrame();
+ }
+
+ initXR();
+ })();
+ </script>
+ </body>
+</html>
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
new file mode 100644
index 00000000000..2096d5e7a59
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/room-scale.html
@@ -0,0 +1,212 @@
+<!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, 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>Room Scale</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Room Scale</summary>
+ <p>
+ This sample demonstrates using a 'stage' frame of reference to provide
+ room scale tracking. If stage bounds are provided by the XRDevice, they
+ will be represented as a green ground plane.
+ <a class="back" href="./">Back</a>
+ </p>
+ </summary>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new Gltf2Node({url: 'media/gltf/camp/camp.gltf'}));
+ scene.addNode(new SkyboxNode({url: 'media/textures/eilenriede-park-2k.png'}));
+ scene.standingStats(true);
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ fallbackHelper.emulateStage = true;
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ // Get a stage frame of reference, which will align the user's physical
+ // floor with Y=0 and can provide boundaries that indicate where the
+ // user can safely walk. If the system can't natively provide stage
+ // coordinates (for example, with a 3DoF device) then it will return an
+ // emulated stage, where the view is translated up by a static height so
+ // that the scene still renders in approximately the right place.
+ session.requestFrameOfReference('stage').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ let boundsRenderer = new BoundsRenderer();
+ boundsRenderer.stageBounds = frameOfRef.bounds;
+ scene.addNode(boundsRenderer);
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ // Every XR frame uses basically the same render loop, so for the sake
+ // of keeping the sample code focused on the interesting bits most
+ // samples after this one will start using this helper function to hide
+ // away the majority of the rendering logic.
+ 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/spectator-mode.html b/chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html
new file mode 100644
index 00000000000..92fb937dc89
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/spectator-mode.html
@@ -0,0 +1,315 @@
+<!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, 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>Spectator Mode</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Spectator Mode</summary>
+ <p>
+ This sample demonstrates how to render a separate, 3rd person view of
+ the scene to an external monitor if one is available. This sample is
+ not applicable to mobile or standalone devices.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <main style='text-align: center;'>
+ </main>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let outputCanvas = null;
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new Gltf2Node({url: 'media/gltf/garage/garage.gltf'}));
+ scene.standingStats(true);
+
+ // Indicates if we are currently presenting a spectator view of the
+ // scene to an external display.
+ let spectatorMode = false;
+ let spectatorButton = null;
+ let spectatorProjectionMatrix = mat4.create();
+ let spectatorViewMatrix = mat4.create();
+ let headset = null;
+
+ let mainElement = document.querySelector('main');
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ fallbackHelper.emulateStage = true;
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+
+ // Because we may be rendering to the gl context's backbuffer now we
+ // need to start monitoring resize events to manage it's size.
+ window.addEventListener('resize', onResize);
+ }
+
+ function onRequestSession(device) {
+ device.requestSession({ immersive: true }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+
+ // When the exclusive session starts, add a button to the page that
+ // users can click to start the spectator mode. It's important to not
+ // begin presenting spectator mode right away, because on some devices
+ // that may mean doing additional work that the user can't see. By
+ // requiring a button click first you're ensuring that the user CAN
+ // still access the 2D page somehow.
+ spectatorButton = document.createElement('button');
+ spectatorButton.innerHTML = 'Enable spectator mode';
+ spectatorButton.addEventListener('click', onEnableSpectatorMode);
+ mainElement.appendChild(spectatorButton);
+
+ // Hide the non-exclusive session's output canvas so that we can see
+ // the button.
+ outputCanvas.style.display = 'none';
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('stage').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ xrButton.setSession(null);
+
+ // When we exit the exclusive session, stop presenting the spectator
+ // view and remove the WebGL canvas from the document.
+ if (spectatorMode) {
+ spectatorMode = false;
+ document.body.removeChild(gl.canvas);
+ }
+
+ // Remove the spectator button if needed.
+ if (spectatorButton) {
+ mainElement.removeChild(spectatorButton);
+ spectatorButton = null;
+ }
+
+ // Show the non-exclusive session's output canvas again.
+ outputCanvas.style.display = '';
+ }
+ }
+
+ // Called when the user clicks the button to enable spectator mode.
+ function onEnableSpectatorMode() {
+ spectatorMode = true;
+
+ // Append the WebGL context's canvas to the page so that we can render
+ // directly to it.
+ document.body.appendChild(gl.canvas);
+ onResize();
+
+ // Remove the spectator button, since it's no longer needed. You could
+ // alternately change the button's function to disable spectator mode.
+ if (spectatorButton) {
+ mainElement.removeChild(spectatorButton);
+ spectatorButton = null;
+ }
+
+ // Load up a mesh that we can use to visualize the headset's pose.
+ if (!headset) {
+ headset = new Gltf2Node({url: 'media/gltf/headset/headset.gltf'});
+ scene.addNode(headset);
+ }
+ }
+
+ function onResize () {
+ if (spectatorMode) {
+ // The spectator view does take time to render, and can impact the
+ // performance of the in-headset view. To help mitigate that, we'll
+ // draw the spectator view at half the native resolution.
+ gl.canvas.width = (gl.canvas.offsetWidth * window.devicePixelRatio) / 2.0;
+ gl.canvas.height = (gl.canvas.offsetHeight * window.devicePixelRatio) / 2.0;
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ scene.updateInputSources(frame, frameOfRef);
+
+ scene.drawXRFrame(frame, pose);
+
+ // If spectator mode is active, draw a 3rd person view of the scene to
+ // the WebGL context's default backbuffer.
+ if (spectatorMode) {
+ // Bind the WebGL context's default framebuffer, so that the rendered
+ // content shows up in the canvas element.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ // Clear the framebuffer
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // Set the viewport to the whole canvas
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+
+ // Set up a sensible projection matrix for the canvas
+ mat4.perspective(spectatorProjectionMatrix, Math.PI*0.4, gl.drawingBufferWidth / gl.drawingBufferHeight, session.depthNear, session.depthFar);
+
+ // Set up a view matrix that gives us a 3rd-person view of the scene.
+ // In this case it's positioned in a corner of the garage scene near
+ // near the ceiling and looking down at the user.
+ mat4.identity(spectatorViewMatrix);
+ mat4.translate(spectatorViewMatrix, spectatorViewMatrix, [-1.75, 2.0, 1.75]);
+ mat4.rotateY(spectatorViewMatrix, spectatorViewMatrix, Math.PI * -0.25);
+ mat4.rotateX(spectatorViewMatrix, spectatorViewMatrix, Math.PI * -0.15);
+ mat4.invert(spectatorViewMatrix, spectatorViewMatrix);
+
+ // Update the headset's pose to match the user's and make it visible
+ // for this draw.
+ if (headset) {
+ headset.visible = true;
+ headset.matrix = pose.poseModelMatrix;
+ }
+
+ // Draw the spectator view of the scene.
+ scene.draw(spectatorProjectionMatrix, spectatorViewMatrix);
+
+ // Ensure the headset isn't visible in the VR view.
+ if (headset) {
+ headset.visible = false;
+ }
+ }
+
+ scene.endFrame();
+ }
+
+ // Start the XR application.
+ initXR();
+ })();
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/stereo-video.html b/chromium/third_party/webxr_test_pages/webxr-samples/stereo-video.html
new file mode 100644
index 00000000000..be332d83953
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/stereo-video.html
@@ -0,0 +1,259 @@
+<!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, 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>Stereo Video Player</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Stereo Video Player</summary>
+ <p>
+ This sample demonstrates how to play a stereo 3D video. (Stereo part not yet working.)
+ <a class="back" href="./">Back</a>
+ </p>
+ </summary>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new Gltf2Node({url: 'media/gltf/home-theater/home-theater.gltf'}));
+ scene.enableStats(false);
+
+ let video = document.createElement('video');
+ video.loop = true;
+ video.src = 'media/video/bbb-sunflower-540p2-1min.webm';
+
+ let videoNode = new VideoNode({
+ video: video,
+ displayMode: 'stereoTopBottom'
+ });
+
+ // When the video is clicked we'll pause it if it's playing.
+ videoNode.onSelect(() => {
+ if (!video.paused) {
+ playButton.visible = true;
+ video.pause();
+ }
+ });
+ videoNode.selectable = true;
+
+ // Move back to the position of the in-room screen and size to cover it.
+ // Values determined experimentally and with many refreshes.
+ videoNode.translation = [0.025, 0.275, -4.4];
+ videoNode.scale = [2.1, 1.1, 1.0];
+ scene.addNode(videoNode);
+
+ video.addEventListener('loadeddata', () => {
+ // Once the video has loaded up adjust the aspect ratio of the "screen"
+ // to fit the video's native shape.
+ let aspect = videoNode.aspectRatio;
+ if (aspect < 2.0) {
+ videoNode.scale = [aspect * 1.1, 1.1, 1.0];
+ } else {
+ videoNode.scale = [2.1, 2.1 / aspect, 1.0];
+ }
+ });
+
+ // Add a button to the scene to play/pause the movie.
+ let playTexture = new UrlTexture('media/textures/play-button.png');
+
+ // Create a button that plays the video when clicked.
+ let playButton = new ButtonNode(playTexture, () => {
+ // Play the video and hide the button.
+ if (video.paused) {
+ playButton.visible = false;
+ video.play();
+ }
+ });
+ // Move the play button to the center of the screen and make it much
+ // bigger.
+ playButton.translation = [0.025, 0.275, -4.3];
+ playButton.scale = [5.0, 5.0, 5.0];
+ scene.addNode(playButton);
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({ outputContext: ctx })
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ renderer = new Renderer(gl);
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+ session.addEventListener('select', (ev) => {
+ let frameOfRef = ev.frame.session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ scene.handleSelect(ev.inputSource, ev.frame, frameOfRef);
+ });
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ // In this case we're going to use an eye-level frame of reference
+ // because we want to users head to appear in the right place relative
+ // to the center chair, as if they're sitting in it, rather than
+ // somewhere in the room relative to the floor.
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ session.requestAnimationFrame(onXRFrame);
+
+ scene.updateInputSources(frame, frameOfRef);
+
+ 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/viewport-scaling.html b/chromium/third_party/webxr_test_pages/webxr-samples/viewport-scaling.html
new file mode 100644
index 00000000000..351c5ac62e8
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/viewport-scaling.html
@@ -0,0 +1,230 @@
+<!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, 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>Viewport Scaling</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Viewport Scaling</summary>
+ <p>
+ This sample demonstrates scaling the viewports used for a WebXR layer
+ at runtime to dynamically adjust the fillrate required and improve
+ performance or quality as needed.
+
+ Viewport scaling should be used to make a performance/quality tradeoff
+ in response to realtime performance monitoring.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrImmersiveFrameOfRef = null;
+ let xrNonImmersiveFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new CubeSeaNode());
+
+ let resolutionMultiplier = 1.0;
+ let lastAdjustment = Date.now()-1000;
+
+ // Called in the render loop.
+ function adjustViewportScale(session) {
+ // Update the viewport scale every tenth of a second.
+ let t = Date.now();
+ if (t - lastAdjustment < 100)
+ return;
+ lastAdjustment = t;
+
+ // Modify the scale over time on a sin wave. In the real world this
+ // would probably be based on scene complexity.
+ // Oscillates between 1.0 to 0.5.
+ resolutionMultiplier = (Math.sin(t / 1000) * 0.25) + 0.75;
+
+ // This is the only new XRSession call in this sample. It sets a
+ // requested scale to be applied to the viewports reported for each
+ // XRView. The UA is allowed to ignore the request or adjust it as
+ // needed. If the scaling request is honored it will take effect on the
+ // *next* frame, not the current one.
+ session.baseLayer.requestViewportScaling(resolutionMultiplier);
+ }
+
+ function initXR() {
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ if (navigator.xr) {
+ navigator.xr.requestDevice().then((device) => {
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+
+ let outputCanvas = document.createElement('canvas');
+ let ctx = outputCanvas.getContext('xrpresent');
+
+ device.requestSession({outputContext: ctx})
+ .then((session) => {
+ document.body.appendChild(outputCanvas);
+ onSessionStarted(session);
+ });
+ }).catch(() => {
+ initFallback();
+ });
+ } else {
+ initFallback();
+ }
+ }
+
+ function initFallback() {
+ initGL();
+ document.body.appendChild(gl.canvas);
+ let fallbackHelper = new FallbackHelper(scene, gl);
+ }
+
+ function initGL(compatibleDevice) {
+ if (gl)
+ return;
+
+ gl = createWebGLContext({
+ compatibleXRDevice: compatibleDevice
+ });
+
+ gl.clearColor(0.1, 0.2, 0.3, 1.0);
+
+ renderer = new Renderer(gl);
+
+ scene.setRenderer(renderer);
+ scene.inputRenderer.setControllerMesh(new Gltf2Node({url: 'media/gltf/controller/controller.gltf'}));
+ }
+
+ function onRequestSession(device) {
+ // Set up a mirror canvas
+ let mirrorCanvas = document.createElement('canvas');
+ let ctx = mirrorCanvas.getContext('xrpresent');
+ mirrorCanvas.setAttribute('id', 'mirror-canvas');
+ document.body.appendChild(mirrorCanvas);
+
+ device.requestSession({ immersive: true, outputContext: ctx }).then((session) => {
+ xrButton.setSession(session);
+ onSessionStarted(session);
+ });
+ }
+
+ function onSessionStarted(session) {
+ session.addEventListener('end', onSessionEnded);
+
+ initGL(session.device);
+
+ session.baseLayer = new XRWebGLLayer(session, gl);
+
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ if (session.immersive) {
+ xrImmersiveFrameOfRef = frameOfRef;
+ } else {
+ xrNonImmersiveFrameOfRef = frameOfRef;
+ }
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ function onEndSession(session) {
+ session.end();
+ }
+
+ function onSessionEnded(event) {
+ if (event.session.immersive) {
+ document.body.removeChild(document.querySelector('#mirror-canvas'));
+ xrButton.setSession(null);
+ }
+ }
+
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+ let frameOfRef = session.immersive ?
+ xrImmersiveFrameOfRef :
+ xrNonImmersiveFrameOfRef;
+ let pose = frame.getDevicePose(frameOfRef);
+
+ scene.startFrame();
+
+ // Adjust the viewports if needed.
+ adjustViewportScale(session);
+
+ session.requestAnimationFrame(onXRFrame);
+
+ scene.updateInputSources(frame, frameOfRef);
+
+ 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/xr-barebones.html b/chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
new file mode 100644
index 00000000000..a462ce85a45
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
@@ -0,0 +1,206 @@
+<!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, 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>Barebones WebXR</title>
+
+ <link href='css/common.css' rel='stylesheet'></link>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>Barebones WebXR</summary>
+ <p>
+ This sample demonstrates extremely simple use of WebXR with no library
+ dependencies. It doesn't render anything exciting, just clears your
+ headset's display to a slowly changing color to prove it's working.
+ <a class="back" href="./">Back</a>
+ </p>
+ <button id="xr-button" disabled>XR not found</button>
+ </details>
+ </header>
+ <main style='text-align: center;'>
+ <p>Click 'Enter XR' to see content</p>
+ </main>
+ <script>
+ (function () {
+ 'use strict';
+
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = document.getElementById('xr-button');
+ let xrDevice = null;
+ let xrSession = null;
+ let xrFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+
+ // 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.
+ function initXR() {
+ // Is WebXR available on this UA?
+ if (navigator.xr) {
+ // Request an XRDevice connected to the system.
+ navigator.xr.requestDevice().then((device) => {
+ xrDevice = device;
+ // If the device allows creation of exclusive sessions set it as the
+ // target of the 'Enter XR' button.
+ device.supportsSession({immersive: true}).then(() => {
+ // Updates the button to start an XR session when clicked.
+ xrButton.addEventListener('click', onButtonClicked);
+ xrButton.innerHTML = 'Enter XR';
+ xrButton.disabled = false;
+ });
+ });
+ }
+ }
+
+ // Called when the user clicks the button to enter XR. If we don't have a
+ // session already we'll request one, and if we do we'll end it.
+ function onButtonClicked() {
+ if (!xrSession) {
+ xrDevice.requestSession({immersive: true}).then(onSessionStarted);
+ } else {
+ xrSession.end();
+ }
+ }
+
+ // 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) {
+ xrSession = session;
+ xrButton.innerHTML = 'Exit XR';
+
+ // Listen for the sessions 'end' event so we can respond if the user
+ // or UA ends the session for any reason.
+ session.addEventListener('end', onSessionEnded);
+
+ // Create a WebGL context to render with, initialized to be compatible
+ // with the XRDisplay we're presenting to.
+ let canvas = document.createElement('canvas');
+ gl = canvas.getContext('webgl', {
+ compatibleXRDevice: session.device
+ });
+
+ // 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.
+ session.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.
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ xrFrameOfRef = frameOfRef;
+
+ // Inform the session that we're ready to begin drawing.
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ // Called when the user clicks the 'Exit XR' button. In response we end
+ // the session.
+ function onEndSession(session) {
+ session.end();
+ }
+
+ // Called either when the user has explicitly ended the session (like in
+ // onEndSession()) or when the UA has ended the session for any reason.
+ // At this point the session object is no longer usable and should be
+ // discarded.
+ function onSessionEnded(event) {
+ xrSession = null;
+ xrButton.innerHTML = 'Enter VR';
+
+ // In this simple case discard the WebGL context too, since we're not
+ // rendering anything else to the screen with it.
+ gl = null;
+ }
+
+ // Called every time the XRSession requests that a new frame be drawn.
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+
+ // Inform the session that we're ready for the next frame.
+ session.requestAnimationFrame(onXRFrame);
+
+ // Get the XRDevice pose relative to the Frame of Reference we created
+ // earlier.
+ let pose = frame.getDevicePose(xrFrameOfRef);
+
+ // 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
+ // framebuffer cleared, so tracking loss means the scene will simply
+ // dissapear.
+ 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
+ // rendered.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
+
+ // Update the clear color so that we can observe the color in the
+ // headset changing over time.
+ let time = Date.now();
+ gl.clearColor(Math.cos(time / 2000), Math.cos(time / 4000), Math.cos(time / 6000), 1.0);
+
+ // Clear the framebuffer
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // Normally you'd loop through each of the views reported by the frame
+ // and draw them into the corresponding viewport here, but we're
+ // keeping this sample slim so we're not bothering to draw any
+ // geometry.
+ /*for (let view of frame.views) {
+ let viewport = session.baseLayer.getViewport(view);
+ gl.viewport(viewport.x, viewport.y,
+ viewport.width, viewport.height);
+
+ // Draw something.
+ }*/
+ }
+ }
+
+ // Start the XR application.
+ initXR();
+
+ })();
+ </script>
+ </body>
+</html>
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/xr-presentation.html b/chromium/third_party/webxr_test_pages/webxr-samples/xr-presentation.html
new file mode 100644
index 00000000000..c1edb0028b5
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/xr-presentation.html
@@ -0,0 +1,244 @@
+<!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, 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>XR Presentation</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/webxr-polyfill.js'></script>
+
+ <!--This script patches up around implementation differences in past browser versions
+ so that the samples can always be written against the most recent spec changes.
+ It won't be necessary after the API has been officially shipped for a bit.-->
+ <script src='js/webxr-version-shim.js'></script>
+
+ <script src='js/cottontail/build/cottontail.js'></script>
+
+ <script src='js/webxr-button.js'></script>
+ </head>
+ <body>
+ <header>
+ <details open>
+ <summary>XR Presentation</summary>
+ <p>
+ This sample demonstrates how to present a simple WebGL scene to a
+ XRDevice. The scene is not rendered to the page prior to XR
+ presentation, nor is it mirrored during presentation.
+ <a class="back" href="./">Back</a>
+ </p>
+ </details>
+ </header>
+ <main style='text-align: center;'>
+ <p>Click 'Enter XR' to see content</p>
+ </main>
+ <script>
+ (function () {
+ 'use strict';
+
+ // If requested, initialize the WebXR polyfill
+ if (QueryArgs.getBool('allowPolyfill', false)) {
+ var polyfill = new WebXRPolyfill();
+ }
+ // Apply the version shim after the polyfill is instantiated, to ensure
+ // that the polyfill also gets patched if necessary.
+ var versionShim = new WebXRVersionShim();
+
+ // XR globals.
+ let xrButton = null;
+ let xrFrameOfRef = null;
+
+ // WebGL scene globals.
+ let gl = null;
+ let renderer = null;
+ let scene = new Scene();
+ scene.addNode(new Gltf2Node({url: 'media/gltf/space/space.gltf'}));
+ scene.addNode(new SkyboxNode({url: 'media/textures/milky-way-4k.png'}));
+
+ // Checks to see if WebXR is available and, if so, queries a list of
+ // XRDevices that are connected to the system.
+ function initXR() {
+ // Adds a helper button to the page that indicates if any XRDevices are
+ // available and let's the user pick between them if there's multiple.
+ xrButton = new XRDeviceButton({
+ onRequestSession: onRequestSession,
+ onEndSession: onEndSession
+ });
+ document.querySelector('header').appendChild(xrButton.domElement);
+
+ // Is WebXR available on this UA?
+ if (navigator.xr) {
+ // Request an XRDevice connected to the system.
+ navigator.xr.requestDevice().then((device) => {
+ // If the device allows creation of exclusive sessions set it as the
+ // target of the 'Enter XR' button.
+ device.supportsSession({immersive: true}).then(() => {
+ xrButton.setDevice(device);
+ });
+ });
+ }
+ }
+
+ // Called when the user selects a device to present to. In response we
+ // will request an exclusive session from that device.
+ function onRequestSession(device) {
+ device.requestSession({immersive: true}).then(onSessionStarted);
+ }
+
+ // 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) {
+ // This informs the 'Enter XR' button that the session has started and
+ // that it should display 'Exit XR' instead.
+ xrButton.setSession(session);
+
+ // Listen for the sessions 'end' event so we can respond if the user
+ // or UA ends the session for any reason.
+ session.addEventListener('end', onSessionEnded);
+
+ // Create a WebGL context to render with, initialized to be compatible
+ // with the XRDisplay we're presenting to.
+ gl = createWebGLContext({
+ compatibleXRDevice: session.device
+ });
+
+ // Create a renderer with that GL context (this is just for the samples
+ // framework and has nothing to do with WebXR specifically.)
+ renderer = new Renderer(gl);
+
+ // Set the scene's renderer, which creates the necessary GPU resources.
+ scene.setRenderer(renderer);
+
+ // 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.
+ session.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.
+ session.requestFrameOfReference('eye-level').then((frameOfRef) => {
+ xrFrameOfRef = frameOfRef;
+
+ // Inform the session that we're ready to begin drawing.
+ session.requestAnimationFrame(onXRFrame);
+ });
+ }
+
+ // Called when the user clicks the 'Exit XR' button. In response we end
+ // the session.
+ function onEndSession(session) {
+ session.end();
+ }
+
+ // Called either when the user has explicitly ended the session (like in
+ // onEndSession()) or when the UA has ended the session for any reason.
+ // At this point the session object is no longer usable and should be
+ // discarded.
+ function onSessionEnded(event) {
+ xrButton.setSession(null);
+
+ // In this simple case discard the WebGL context too, since we're not
+ // rendering anything else to the screen with it.
+ renderer = null;
+ }
+
+ // Called every time the XRSession requests that a new frame be drawn.
+ function onXRFrame(t, frame) {
+ let session = frame.session;
+
+ // Per-frame scene setup. Nothing WebXR specific here.
+ scene.startFrame();
+
+ // Inform the session that we're ready for the next frame.
+ session.requestAnimationFrame(onXRFrame);
+
+ // Get the XRDevice pose relative to the Frame of Reference we created
+ // earlier.
+ let pose = frame.getDevicePose(xrFrameOfRef);
+
+ // 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
+ // framebuffer cleared, so tracking loss means the scene will simply
+ // dissapear.
+ 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
+ // rendered.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
+
+ // Clear the framebuffer
+ 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 frame.views) {
+ let viewport = session.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, pose.getViewMatrix(view));
+ }
+ } 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();
+ }
+
+ // Start the XR application.
+ initXR();
+ })();
+ </script>
+ </body>
+</html>