elation-engine 0.9.113 → 0.9.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/systems/render.css +5 -1
- package/package.json +1 -1
- package/scripts/assets.js +103 -20
- package/scripts/assetworker.js +18 -1
- package/scripts/external/holoplay.js +1494 -0
- package/scripts/external/octree.js +0 -0
- package/scripts/external/three/CSS3DRenderer.js +46 -43
- package/scripts/external/three/CubemapToEquirectangular.js +1 -1
- package/scripts/external/three/three-extras.js +1553 -392
- package/scripts/external/three/three-icosa.js +2575 -0
- package/scripts/external/three/three-loaders.js +925 -133
- package/scripts/external/three/three-postprocessing.js +3 -3
- package/scripts/external/three/three-r116dev.js +50930 -0
- package/scripts/external/three/three-spotlighttextures.js +50953 -0
- package/scripts/external/three/three-vrm.js +2 -2
- package/scripts/external/three/three-working.js +35968 -0
- package/scripts/external/three/three.js +38532 -24087
- package/scripts/external/three-mesh-bvh.js +5370 -0
- package/scripts/external/three-old/BVHLoader.js +406 -0
- package/scripts/external/three-old/ColladaLoader.js +5519 -0
- package/scripts/external/three-old/ColladaLoader2.js +1694 -0
- package/scripts/external/three-old/CubemapToEquirectangular.js +188 -0
- package/scripts/external/three-old/DDSLoader.js +269 -0
- package/scripts/external/three-old/FBXLoader-mine.js +5063 -0
- package/scripts/external/three-old/FBXLoader.js +5112 -0
- package/scripts/external/three-old/FlyControls.js +295 -0
- package/scripts/external/three-old/GLTF2Loader.js +2950 -0
- package/scripts/external/three-old/GLTFLoader.js +2213 -0
- package/scripts/external/three-old/JSONLoader.js +435 -0
- package/scripts/external/three-old/MTLLoader.js +533 -0
- package/scripts/external/three-old/OBJLoader-experimental.js +874 -0
- package/scripts/external/three-old/OBJLoader-working.js +727 -0
- package/scripts/external/three-old/OBJLoader.js +723 -0
- package/scripts/external/three-old/OBJMTLLoader.js +440 -0
- package/scripts/external/three-old/OrbitControls.js +592 -0
- package/scripts/external/three-old/PLYLoader.js +517 -0
- package/scripts/external/three-old/TransformControls.js +1100 -0
- package/scripts/external/three-old/VRMLLoader.js +1021 -0
- package/scripts/external/three-old/glTFLoader-combined.js +2513 -0
- package/scripts/external/three-old/nodethree.js +44018 -0
- package/scripts/external/three-old/render/BleachBypassShader.js +64 -0
- package/scripts/external/three-old/render/BloomPass.js +116 -0
- package/scripts/external/three-old/render/CSS3DRenderer.js +310 -0
- package/scripts/external/three-old/render/ClearPass.js +44 -0
- package/scripts/external/three-old/render/ConvolutionShader.js +101 -0
- package/scripts/external/three-old/render/CopyShader.js +46 -0
- package/scripts/external/three-old/render/EffectComposer.js +211 -0
- package/scripts/external/three-old/render/FXAAShader.js +88 -0
- package/scripts/external/three-old/render/FilmPass.js +60 -0
- package/scripts/external/three-old/render/FilmShader.js +104 -0
- package/scripts/external/three-old/render/ManualMSAARenderPass.js +168 -0
- package/scripts/external/three-old/render/MaskPass.js +97 -0
- package/scripts/external/three-old/render/OculusRenderPass.js +84 -0
- package/scripts/external/three-old/render/OculusRiftEffect.js +240 -0
- package/scripts/external/three-old/render/PortalRenderPass.js +166 -0
- package/scripts/external/three-old/render/RecordingPass.js +208 -0
- package/scripts/external/three-old/render/RenderPass.js +57 -0
- package/scripts/external/three-old/render/SSAOShader.js +259 -0
- package/scripts/external/three-old/render/SepiaShader.js +54 -0
- package/scripts/external/three-old/render/ShaderPass.js +66 -0
- package/scripts/external/three-old/render/VREffect.js +482 -0
- package/scripts/external/three-old/shimthree.js +23 -0
- package/scripts/external/three-old/stats.js +6 -0
- package/scripts/external/three-old/three-88dev.js +45004 -0
- package/scripts/external/three-old/three-backgroundoptimization.js +44432 -0
- package/scripts/external/three-old/three-updates.js +44735 -0
- package/scripts/external/three-old/three-working.js +44719 -0
- package/scripts/external/three-old/three.js +44431 -0
- package/scripts/external/three-old/threex.rendererstats.js +66 -0
- package/scripts/external/three-old/tween.js +13 -0
- package/scripts/external/webvr-polyfill-new.js +3497 -0
- package/scripts/external/webvr-polyfill-newest.js +3491 -0
- package/scripts/external/webvr-polyfill-old.js +6337 -0
- package/scripts/geometries.js +2 -2
- package/scripts/math.js +6 -6
- package/scripts/systems/admin.js +1 -1
- package/scripts/systems/controls.js +6 -4
- package/scripts/systems/physics.js +10 -10
- package/scripts/systems/render.js +58 -20
- package/scripts/systems/render2.js +38 -0
- package/scripts/things/camera.js +6 -1
- package/scripts/things/generic-trackedvectors.js +1875 -0
- package/scripts/things/generic.js +3 -4
- package/scripts/things/label2d.js +1 -1
- package/scripts/things/leapmotion.js +6 -6
- package/scripts/things/menu.js +1 -1
- package/scripts/things/player-bak.js +638 -0
- package/scripts/things/player.js +28 -10
- package/scripts/things/skysphere.js +1 -1
- package/scripts/things/terrain.js +1 -1
- package/scripts/things/text.js +1 -1
|
@@ -0,0 +1,3491 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* webvr-polyfill
|
|
4
|
+
* Copyright (c) 2015-2017 Google
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @license
|
|
20
|
+
* cardboard-vr-display
|
|
21
|
+
* Copyright (c) 2015-2017 Google
|
|
22
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
23
|
+
* you may not use this file except in compliance with the License.
|
|
24
|
+
* You may obtain a copy of the License at
|
|
25
|
+
*
|
|
26
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
27
|
+
*
|
|
28
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
29
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
30
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
31
|
+
* See the License for the specific language governing permissions and
|
|
32
|
+
* limitations under the License.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @license
|
|
37
|
+
* webvr-polyfill-dpdb
|
|
38
|
+
* Copyright (c) 2017 Google
|
|
39
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
40
|
+
* you may not use this file except in compliance with the License.
|
|
41
|
+
* You may obtain a copy of the License at
|
|
42
|
+
*
|
|
43
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
44
|
+
*
|
|
45
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
46
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
47
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
48
|
+
* See the License for the specific language governing permissions and
|
|
49
|
+
* limitations under the License.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @license
|
|
54
|
+
* wglu-preserve-state
|
|
55
|
+
* Copyright (c) 2016, Brandon Jones.
|
|
56
|
+
*
|
|
57
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
58
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
59
|
+
* in the Software without restriction, including without limitation the rights
|
|
60
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
61
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
62
|
+
* furnished to do so, subject to the following conditions:
|
|
63
|
+
*
|
|
64
|
+
* The above copyright notice and this permission notice shall be included in
|
|
65
|
+
* all copies or substantial portions of the Software.
|
|
66
|
+
*
|
|
67
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
68
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
69
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
70
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
71
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
72
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
73
|
+
* THE SOFTWARE.
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @license
|
|
78
|
+
* nosleep.js
|
|
79
|
+
* Copyright (c) 2017, Rich Tibbett
|
|
80
|
+
*
|
|
81
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
82
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
83
|
+
* in the Software without restriction, including without limitation the rights
|
|
84
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
85
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
86
|
+
* furnished to do so, subject to the following conditions:
|
|
87
|
+
*
|
|
88
|
+
* The above copyright notice and this permission notice shall be included in
|
|
89
|
+
* all copies or substantial portions of the Software.
|
|
90
|
+
*
|
|
91
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
92
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
93
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
94
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
95
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
96
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
97
|
+
* THE SOFTWARE.
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
(function (global, factory) {
|
|
101
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
102
|
+
typeof define === 'function' && define.amd ? define(factory) :
|
|
103
|
+
(global.WebVRPolyfill = factory());
|
|
104
|
+
}(this, (function () { 'use strict';
|
|
105
|
+
|
|
106
|
+
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
function unwrapExports (x) {
|
|
111
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function createCommonjsModule(fn, module) {
|
|
115
|
+
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
var race = function race(promises) {
|
|
119
|
+
if (Promise.race) {
|
|
120
|
+
return Promise.race(promises);
|
|
121
|
+
}
|
|
122
|
+
return new Promise(function (resolve, reject) {
|
|
123
|
+
for (var i = 0; i < promises.length; i++) {
|
|
124
|
+
promises[i].then(resolve, reject);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
var isMobile = function isMobile() {
|
|
130
|
+
return (/Android/i.test(navigator.userAgent) || /iPhone|iPad|iPod/i.test(navigator.userAgent)
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
var copyArray = function copyArray(source, dest) {
|
|
134
|
+
for (var i = 0, n = source.length; i < n; i++) {
|
|
135
|
+
dest[i] = source[i];
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
var extend = function extend(dest, src) {
|
|
139
|
+
for (var key in src) {
|
|
140
|
+
if (src.hasOwnProperty(key)) {
|
|
141
|
+
dest[key] = src[key];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return dest;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
var cardboardVrDisplay = createCommonjsModule(function (module, exports) {
|
|
148
|
+
/**
|
|
149
|
+
* @license
|
|
150
|
+
* cardboard-vr-display
|
|
151
|
+
* Copyright (c) 2015-2017 Google
|
|
152
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
153
|
+
* you may not use this file except in compliance with the License.
|
|
154
|
+
* You may obtain a copy of the License at
|
|
155
|
+
*
|
|
156
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
157
|
+
*
|
|
158
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
159
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
160
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
161
|
+
* See the License for the specific language governing permissions and
|
|
162
|
+
* limitations under the License.
|
|
163
|
+
*/
|
|
164
|
+
/**
|
|
165
|
+
* @license
|
|
166
|
+
* gl-preserve-state
|
|
167
|
+
* Copyright (c) 2016, Brandon Jones.
|
|
168
|
+
*
|
|
169
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
170
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
171
|
+
* in the Software without restriction, including without limitation the rights
|
|
172
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
173
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
174
|
+
* furnished to do so, subject to the following conditions:
|
|
175
|
+
*
|
|
176
|
+
* The above copyright notice and this permission notice shall be included in
|
|
177
|
+
* all copies or substantial portions of the Software.
|
|
178
|
+
*
|
|
179
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
180
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
181
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
182
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
183
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
184
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
185
|
+
* THE SOFTWARE.
|
|
186
|
+
*/
|
|
187
|
+
/**
|
|
188
|
+
* @license
|
|
189
|
+
* webvr-polyfill-dpdb
|
|
190
|
+
* Copyright (c) 2015-2017 Google
|
|
191
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
* you may not use this file except in compliance with the License.
|
|
193
|
+
* You may obtain a copy of the License at
|
|
194
|
+
*
|
|
195
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
*
|
|
197
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
* See the License for the specific language governing permissions and
|
|
201
|
+
* limitations under the License.
|
|
202
|
+
*/
|
|
203
|
+
/**
|
|
204
|
+
* @license
|
|
205
|
+
* nosleep.js
|
|
206
|
+
* Copyright (c) 2017, Rich Tibbett
|
|
207
|
+
*
|
|
208
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
209
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
210
|
+
* in the Software without restriction, including without limitation the rights
|
|
211
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
212
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
213
|
+
* furnished to do so, subject to the following conditions:
|
|
214
|
+
*
|
|
215
|
+
* The above copyright notice and this permission notice shall be included in
|
|
216
|
+
* all copies or substantial portions of the Software.
|
|
217
|
+
*
|
|
218
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
219
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
220
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
221
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
222
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
223
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
224
|
+
* THE SOFTWARE.
|
|
225
|
+
*/
|
|
226
|
+
(function (global, factory) {
|
|
227
|
+
module.exports = factory();
|
|
228
|
+
}(commonjsGlobal, (function () { var classCallCheck = function (instance, Constructor) {
|
|
229
|
+
if (!(instance instanceof Constructor)) {
|
|
230
|
+
throw new TypeError("Cannot call a class as a function");
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
var createClass = function () {
|
|
234
|
+
function defineProperties(target, props) {
|
|
235
|
+
for (var i = 0; i < props.length; i++) {
|
|
236
|
+
var descriptor = props[i];
|
|
237
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
238
|
+
descriptor.configurable = true;
|
|
239
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
240
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return function (Constructor, protoProps, staticProps) {
|
|
244
|
+
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
245
|
+
if (staticProps) defineProperties(Constructor, staticProps);
|
|
246
|
+
return Constructor;
|
|
247
|
+
};
|
|
248
|
+
}();
|
|
249
|
+
var slicedToArray = function () {
|
|
250
|
+
function sliceIterator(arr, i) {
|
|
251
|
+
var _arr = [];
|
|
252
|
+
var _n = true;
|
|
253
|
+
var _d = false;
|
|
254
|
+
var _e = undefined;
|
|
255
|
+
try {
|
|
256
|
+
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
|
257
|
+
_arr.push(_s.value);
|
|
258
|
+
if (i && _arr.length === i) break;
|
|
259
|
+
}
|
|
260
|
+
} catch (err) {
|
|
261
|
+
_d = true;
|
|
262
|
+
_e = err;
|
|
263
|
+
} finally {
|
|
264
|
+
try {
|
|
265
|
+
if (!_n && _i["return"]) _i["return"]();
|
|
266
|
+
} finally {
|
|
267
|
+
if (_d) throw _e;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return _arr;
|
|
271
|
+
}
|
|
272
|
+
return function (arr, i) {
|
|
273
|
+
if (Array.isArray(arr)) {
|
|
274
|
+
return arr;
|
|
275
|
+
} else if (Symbol.iterator in Object(arr)) {
|
|
276
|
+
return sliceIterator(arr, i);
|
|
277
|
+
} else {
|
|
278
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
}();
|
|
282
|
+
var MIN_TIMESTEP = 0.001;
|
|
283
|
+
var MAX_TIMESTEP = 1;
|
|
284
|
+
var base64 = function base64(mimeType, _base) {
|
|
285
|
+
return 'data:' + mimeType + ';base64,' + _base;
|
|
286
|
+
};
|
|
287
|
+
var lerp = function lerp(a, b, t) {
|
|
288
|
+
return a + (b - a) * t;
|
|
289
|
+
};
|
|
290
|
+
var isIOS = function () {
|
|
291
|
+
var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);
|
|
292
|
+
return function () {
|
|
293
|
+
return isIOS;
|
|
294
|
+
};
|
|
295
|
+
}();
|
|
296
|
+
var isWebViewAndroid = function () {
|
|
297
|
+
var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1;
|
|
298
|
+
return function () {
|
|
299
|
+
return isWebViewAndroid;
|
|
300
|
+
};
|
|
301
|
+
}();
|
|
302
|
+
var isSafari = function () {
|
|
303
|
+
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
304
|
+
return function () {
|
|
305
|
+
return isSafari;
|
|
306
|
+
};
|
|
307
|
+
}();
|
|
308
|
+
var isFirefoxAndroid = function () {
|
|
309
|
+
var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1;
|
|
310
|
+
return function () {
|
|
311
|
+
return isFirefoxAndroid;
|
|
312
|
+
};
|
|
313
|
+
}();
|
|
314
|
+
var getChromeVersion = function () {
|
|
315
|
+
var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/);
|
|
316
|
+
var value = match ? parseInt(match[1], 10) : null;
|
|
317
|
+
return function () {
|
|
318
|
+
return value;
|
|
319
|
+
};
|
|
320
|
+
}();
|
|
321
|
+
var isChromeWithoutDeviceMotion = function () {
|
|
322
|
+
var value = false;
|
|
323
|
+
if (getChromeVersion() === 65) {
|
|
324
|
+
var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/);
|
|
325
|
+
if (match) {
|
|
326
|
+
var _match$1$split = match[1].split('.'),
|
|
327
|
+
_match$1$split2 = slicedToArray(_match$1$split, 4),
|
|
328
|
+
major = _match$1$split2[0],
|
|
329
|
+
minor = _match$1$split2[1],
|
|
330
|
+
branch = _match$1$split2[2],
|
|
331
|
+
build = _match$1$split2[3];
|
|
332
|
+
value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return function () {
|
|
336
|
+
return value;
|
|
337
|
+
};
|
|
338
|
+
}();
|
|
339
|
+
var isR7 = function () {
|
|
340
|
+
var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1;
|
|
341
|
+
return function () {
|
|
342
|
+
return isR7;
|
|
343
|
+
};
|
|
344
|
+
}();
|
|
345
|
+
var isLandscapeMode = function isLandscapeMode() {
|
|
346
|
+
var rtn = window.orientation == 90 || window.orientation == -90;
|
|
347
|
+
return isR7() ? !rtn : rtn;
|
|
348
|
+
};
|
|
349
|
+
var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) {
|
|
350
|
+
if (isNaN(timestampDeltaS)) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
if (timestampDeltaS <= MIN_TIMESTEP) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
if (timestampDeltaS > MAX_TIMESTEP) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
return true;
|
|
360
|
+
};
|
|
361
|
+
var getScreenWidth = function getScreenWidth() {
|
|
362
|
+
return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio;
|
|
363
|
+
};
|
|
364
|
+
var getScreenHeight = function getScreenHeight() {
|
|
365
|
+
return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio;
|
|
366
|
+
};
|
|
367
|
+
var requestFullscreen = function requestFullscreen(element) {
|
|
368
|
+
if (isWebViewAndroid()) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
if (element.requestFullscreen) {
|
|
372
|
+
element.requestFullscreen();
|
|
373
|
+
} else if (element.webkitRequestFullscreen) {
|
|
374
|
+
element.webkitRequestFullscreen();
|
|
375
|
+
} else if (element.mozRequestFullScreen) {
|
|
376
|
+
element.mozRequestFullScreen();
|
|
377
|
+
} else if (element.msRequestFullscreen) {
|
|
378
|
+
element.msRequestFullscreen();
|
|
379
|
+
} else {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
return true;
|
|
383
|
+
};
|
|
384
|
+
var exitFullscreen = function exitFullscreen() {
|
|
385
|
+
if (document.exitFullscreen) {
|
|
386
|
+
document.exitFullscreen();
|
|
387
|
+
} else if (document.webkitExitFullscreen) {
|
|
388
|
+
document.webkitExitFullscreen();
|
|
389
|
+
} else if (document.mozCancelFullScreen) {
|
|
390
|
+
document.mozCancelFullScreen();
|
|
391
|
+
} else if (document.msExitFullscreen) {
|
|
392
|
+
document.msExitFullscreen();
|
|
393
|
+
} else {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
return true;
|
|
397
|
+
};
|
|
398
|
+
var getFullscreenElement = function getFullscreenElement() {
|
|
399
|
+
return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
|
|
400
|
+
};
|
|
401
|
+
var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) {
|
|
402
|
+
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
403
|
+
gl.shaderSource(vertexShader, vertexSource);
|
|
404
|
+
gl.compileShader(vertexShader);
|
|
405
|
+
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
406
|
+
gl.shaderSource(fragmentShader, fragmentSource);
|
|
407
|
+
gl.compileShader(fragmentShader);
|
|
408
|
+
var program = gl.createProgram();
|
|
409
|
+
gl.attachShader(program, vertexShader);
|
|
410
|
+
gl.attachShader(program, fragmentShader);
|
|
411
|
+
for (var attribName in attribLocationMap) {
|
|
412
|
+
gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);
|
|
413
|
+
}gl.linkProgram(program);
|
|
414
|
+
gl.deleteShader(vertexShader);
|
|
415
|
+
gl.deleteShader(fragmentShader);
|
|
416
|
+
return program;
|
|
417
|
+
};
|
|
418
|
+
var getProgramUniforms = function getProgramUniforms(gl, program) {
|
|
419
|
+
var uniforms = {};
|
|
420
|
+
var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
|
|
421
|
+
var uniformName = '';
|
|
422
|
+
for (var i = 0; i < uniformCount; i++) {
|
|
423
|
+
var uniformInfo = gl.getActiveUniform(program, i);
|
|
424
|
+
uniformName = uniformInfo.name.replace('[0]', '');
|
|
425
|
+
uniforms[uniformName] = gl.getUniformLocation(program, uniformName);
|
|
426
|
+
}
|
|
427
|
+
return uniforms;
|
|
428
|
+
};
|
|
429
|
+
var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) {
|
|
430
|
+
var lr = 1 / (left - right),
|
|
431
|
+
bt = 1 / (bottom - top),
|
|
432
|
+
nf = 1 / (near - far);
|
|
433
|
+
out[0] = -2 * lr;
|
|
434
|
+
out[1] = 0;
|
|
435
|
+
out[2] = 0;
|
|
436
|
+
out[3] = 0;
|
|
437
|
+
out[4] = 0;
|
|
438
|
+
out[5] = -2 * bt;
|
|
439
|
+
out[6] = 0;
|
|
440
|
+
out[7] = 0;
|
|
441
|
+
out[8] = 0;
|
|
442
|
+
out[9] = 0;
|
|
443
|
+
out[10] = 2 * nf;
|
|
444
|
+
out[11] = 0;
|
|
445
|
+
out[12] = (left + right) * lr;
|
|
446
|
+
out[13] = (top + bottom) * bt;
|
|
447
|
+
out[14] = (far + near) * nf;
|
|
448
|
+
out[15] = 1;
|
|
449
|
+
return out;
|
|
450
|
+
};
|
|
451
|
+
var isMobile = function isMobile() {
|
|
452
|
+
var check = false;
|
|
453
|
+
(function (a) {
|
|
454
|
+
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;
|
|
455
|
+
})(navigator.userAgent || navigator.vendor || window.opera);
|
|
456
|
+
return check;
|
|
457
|
+
};
|
|
458
|
+
var extend = function extend(dest, src) {
|
|
459
|
+
for (var key in src) {
|
|
460
|
+
if (src.hasOwnProperty(key)) {
|
|
461
|
+
dest[key] = src[key];
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return dest;
|
|
465
|
+
};
|
|
466
|
+
var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) {
|
|
467
|
+
if (isIOS()) {
|
|
468
|
+
var width = canvas.style.width;
|
|
469
|
+
var height = canvas.style.height;
|
|
470
|
+
canvas.style.width = parseInt(width) + 1 + 'px';
|
|
471
|
+
canvas.style.height = parseInt(height) + 'px';
|
|
472
|
+
setTimeout(function () {
|
|
473
|
+
canvas.style.width = width;
|
|
474
|
+
canvas.style.height = height;
|
|
475
|
+
}, 100);
|
|
476
|
+
}
|
|
477
|
+
window.canvas = canvas;
|
|
478
|
+
};
|
|
479
|
+
var frameDataFromPose = function () {
|
|
480
|
+
var piOver180 = Math.PI / 180.0;
|
|
481
|
+
var rad45 = Math.PI * 0.25;
|
|
482
|
+
function mat4_perspectiveFromFieldOfView(out, fov, near, far) {
|
|
483
|
+
var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45),
|
|
484
|
+
downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45),
|
|
485
|
+
leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45),
|
|
486
|
+
rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45),
|
|
487
|
+
xScale = 2.0 / (leftTan + rightTan),
|
|
488
|
+
yScale = 2.0 / (upTan + downTan);
|
|
489
|
+
out[0] = xScale;
|
|
490
|
+
out[1] = 0.0;
|
|
491
|
+
out[2] = 0.0;
|
|
492
|
+
out[3] = 0.0;
|
|
493
|
+
out[4] = 0.0;
|
|
494
|
+
out[5] = yScale;
|
|
495
|
+
out[6] = 0.0;
|
|
496
|
+
out[7] = 0.0;
|
|
497
|
+
out[8] = -((leftTan - rightTan) * xScale * 0.5);
|
|
498
|
+
out[9] = (upTan - downTan) * yScale * 0.5;
|
|
499
|
+
out[10] = far / (near - far);
|
|
500
|
+
out[11] = -1.0;
|
|
501
|
+
out[12] = 0.0;
|
|
502
|
+
out[13] = 0.0;
|
|
503
|
+
out[14] = far * near / (near - far);
|
|
504
|
+
out[15] = 0.0;
|
|
505
|
+
return out;
|
|
506
|
+
}
|
|
507
|
+
function mat4_fromRotationTranslation(out, q, v) {
|
|
508
|
+
var x = q[0],
|
|
509
|
+
y = q[1],
|
|
510
|
+
z = q[2],
|
|
511
|
+
w = q[3],
|
|
512
|
+
x2 = x + x,
|
|
513
|
+
y2 = y + y,
|
|
514
|
+
z2 = z + z,
|
|
515
|
+
xx = x * x2,
|
|
516
|
+
xy = x * y2,
|
|
517
|
+
xz = x * z2,
|
|
518
|
+
yy = y * y2,
|
|
519
|
+
yz = y * z2,
|
|
520
|
+
zz = z * z2,
|
|
521
|
+
wx = w * x2,
|
|
522
|
+
wy = w * y2,
|
|
523
|
+
wz = w * z2;
|
|
524
|
+
out[0] = 1 - (yy + zz);
|
|
525
|
+
out[1] = xy + wz;
|
|
526
|
+
out[2] = xz - wy;
|
|
527
|
+
out[3] = 0;
|
|
528
|
+
out[4] = xy - wz;
|
|
529
|
+
out[5] = 1 - (xx + zz);
|
|
530
|
+
out[6] = yz + wx;
|
|
531
|
+
out[7] = 0;
|
|
532
|
+
out[8] = xz + wy;
|
|
533
|
+
out[9] = yz - wx;
|
|
534
|
+
out[10] = 1 - (xx + yy);
|
|
535
|
+
out[11] = 0;
|
|
536
|
+
out[12] = v[0];
|
|
537
|
+
out[13] = v[1];
|
|
538
|
+
out[14] = v[2];
|
|
539
|
+
out[15] = 1;
|
|
540
|
+
return out;
|
|
541
|
+
}
|
|
542
|
+
function mat4_translate(out, a, v) {
|
|
543
|
+
var x = v[0],
|
|
544
|
+
y = v[1],
|
|
545
|
+
z = v[2],
|
|
546
|
+
a00,
|
|
547
|
+
a01,
|
|
548
|
+
a02,
|
|
549
|
+
a03,
|
|
550
|
+
a10,
|
|
551
|
+
a11,
|
|
552
|
+
a12,
|
|
553
|
+
a13,
|
|
554
|
+
a20,
|
|
555
|
+
a21,
|
|
556
|
+
a22,
|
|
557
|
+
a23;
|
|
558
|
+
if (a === out) {
|
|
559
|
+
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
|
|
560
|
+
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
|
|
561
|
+
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
|
|
562
|
+
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
|
|
563
|
+
} else {
|
|
564
|
+
a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
|
|
565
|
+
a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
|
|
566
|
+
a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
|
|
567
|
+
out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
|
|
568
|
+
out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
|
|
569
|
+
out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
|
|
570
|
+
out[12] = a00 * x + a10 * y + a20 * z + a[12];
|
|
571
|
+
out[13] = a01 * x + a11 * y + a21 * z + a[13];
|
|
572
|
+
out[14] = a02 * x + a12 * y + a22 * z + a[14];
|
|
573
|
+
out[15] = a03 * x + a13 * y + a23 * z + a[15];
|
|
574
|
+
}
|
|
575
|
+
return out;
|
|
576
|
+
}
|
|
577
|
+
function mat4_invert(out, a) {
|
|
578
|
+
var a00 = a[0],
|
|
579
|
+
a01 = a[1],
|
|
580
|
+
a02 = a[2],
|
|
581
|
+
a03 = a[3],
|
|
582
|
+
a10 = a[4],
|
|
583
|
+
a11 = a[5],
|
|
584
|
+
a12 = a[6],
|
|
585
|
+
a13 = a[7],
|
|
586
|
+
a20 = a[8],
|
|
587
|
+
a21 = a[9],
|
|
588
|
+
a22 = a[10],
|
|
589
|
+
a23 = a[11],
|
|
590
|
+
a30 = a[12],
|
|
591
|
+
a31 = a[13],
|
|
592
|
+
a32 = a[14],
|
|
593
|
+
a33 = a[15],
|
|
594
|
+
b00 = a00 * a11 - a01 * a10,
|
|
595
|
+
b01 = a00 * a12 - a02 * a10,
|
|
596
|
+
b02 = a00 * a13 - a03 * a10,
|
|
597
|
+
b03 = a01 * a12 - a02 * a11,
|
|
598
|
+
b04 = a01 * a13 - a03 * a11,
|
|
599
|
+
b05 = a02 * a13 - a03 * a12,
|
|
600
|
+
b06 = a20 * a31 - a21 * a30,
|
|
601
|
+
b07 = a20 * a32 - a22 * a30,
|
|
602
|
+
b08 = a20 * a33 - a23 * a30,
|
|
603
|
+
b09 = a21 * a32 - a22 * a31,
|
|
604
|
+
b10 = a21 * a33 - a23 * a31,
|
|
605
|
+
b11 = a22 * a33 - a23 * a32,
|
|
606
|
+
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
|
607
|
+
if (!det) {
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
det = 1.0 / det;
|
|
611
|
+
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
|
|
612
|
+
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
|
|
613
|
+
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
|
|
614
|
+
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
|
|
615
|
+
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
|
|
616
|
+
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
|
|
617
|
+
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
|
|
618
|
+
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
|
|
619
|
+
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
|
|
620
|
+
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
|
|
621
|
+
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
|
|
622
|
+
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
|
|
623
|
+
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
|
|
624
|
+
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
|
|
625
|
+
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
|
|
626
|
+
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
|
|
627
|
+
return out;
|
|
628
|
+
}
|
|
629
|
+
var defaultOrientation = new Float32Array([0, 0, 0, 1]);
|
|
630
|
+
var defaultPosition = new Float32Array([0, 0, 0]);
|
|
631
|
+
function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) {
|
|
632
|
+
mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar);
|
|
633
|
+
var orientation = pose.orientation || defaultOrientation;
|
|
634
|
+
var position = pose.position || defaultPosition;
|
|
635
|
+
mat4_fromRotationTranslation(view, orientation, position);
|
|
636
|
+
if (offset) mat4_translate(view, view, offset);
|
|
637
|
+
mat4_invert(view, view);
|
|
638
|
+
}
|
|
639
|
+
return function (frameData, pose, vrDisplay) {
|
|
640
|
+
if (!frameData || !pose) return false;
|
|
641
|
+
frameData.pose = pose;
|
|
642
|
+
frameData.timestamp = pose.timestamp;
|
|
643
|
+
updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay);
|
|
644
|
+
updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay);
|
|
645
|
+
return true;
|
|
646
|
+
};
|
|
647
|
+
}();
|
|
648
|
+
var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() {
|
|
649
|
+
var isFramed = window.self !== window.top;
|
|
650
|
+
var refOrigin = getOriginFromUrl(document.referrer);
|
|
651
|
+
var thisOrigin = getOriginFromUrl(window.location.href);
|
|
652
|
+
return isFramed && refOrigin !== thisOrigin;
|
|
653
|
+
};
|
|
654
|
+
var getOriginFromUrl = function getOriginFromUrl(url) {
|
|
655
|
+
var domainIdx;
|
|
656
|
+
var protoSepIdx = url.indexOf("://");
|
|
657
|
+
if (protoSepIdx !== -1) {
|
|
658
|
+
domainIdx = protoSepIdx + 3;
|
|
659
|
+
} else {
|
|
660
|
+
domainIdx = 0;
|
|
661
|
+
}
|
|
662
|
+
var domainEndIdx = url.indexOf('/', domainIdx);
|
|
663
|
+
if (domainEndIdx === -1) {
|
|
664
|
+
domainEndIdx = url.length;
|
|
665
|
+
}
|
|
666
|
+
return url.substring(0, domainEndIdx);
|
|
667
|
+
};
|
|
668
|
+
var getQuaternionAngle = function getQuaternionAngle(quat) {
|
|
669
|
+
if (quat.w > 1) {
|
|
670
|
+
console.warn('getQuaternionAngle: w > 1');
|
|
671
|
+
return 0;
|
|
672
|
+
}
|
|
673
|
+
var angle = 2 * Math.acos(quat.w);
|
|
674
|
+
return angle;
|
|
675
|
+
};
|
|
676
|
+
var warnOnce = function () {
|
|
677
|
+
var observedWarnings = {};
|
|
678
|
+
return function (key, message) {
|
|
679
|
+
if (observedWarnings[key] === undefined) {
|
|
680
|
+
console.warn('webvr-polyfill: ' + message);
|
|
681
|
+
observedWarnings[key] = true;
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
}();
|
|
685
|
+
var deprecateWarning = function deprecateWarning(deprecated, suggested) {
|
|
686
|
+
var alternative = suggested ? 'Please use ' + suggested + ' instead.' : '';
|
|
687
|
+
warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative);
|
|
688
|
+
};
|
|
689
|
+
function WGLUPreserveGLState(gl, bindings, callback) {
|
|
690
|
+
if (!bindings) {
|
|
691
|
+
callback(gl);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
var boundValues = [];
|
|
695
|
+
var activeTexture = null;
|
|
696
|
+
for (var i = 0; i < bindings.length; ++i) {
|
|
697
|
+
var binding = bindings[i];
|
|
698
|
+
switch (binding) {
|
|
699
|
+
case gl.TEXTURE_BINDING_2D:
|
|
700
|
+
case gl.TEXTURE_BINDING_CUBE_MAP:
|
|
701
|
+
var textureUnit = bindings[++i];
|
|
702
|
+
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {
|
|
703
|
+
console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit");
|
|
704
|
+
boundValues.push(null, null);
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
if (!activeTexture) {
|
|
708
|
+
activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
|
|
709
|
+
}
|
|
710
|
+
gl.activeTexture(textureUnit);
|
|
711
|
+
boundValues.push(gl.getParameter(binding), null);
|
|
712
|
+
break;
|
|
713
|
+
case gl.ACTIVE_TEXTURE:
|
|
714
|
+
activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
|
|
715
|
+
boundValues.push(null);
|
|
716
|
+
break;
|
|
717
|
+
default:
|
|
718
|
+
boundValues.push(gl.getParameter(binding));
|
|
719
|
+
break;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
callback(gl);
|
|
723
|
+
for (var i = 0; i < bindings.length; ++i) {
|
|
724
|
+
var binding = bindings[i];
|
|
725
|
+
var boundValue = boundValues[i];
|
|
726
|
+
switch (binding) {
|
|
727
|
+
case gl.ACTIVE_TEXTURE:
|
|
728
|
+
break;
|
|
729
|
+
case gl.ARRAY_BUFFER_BINDING:
|
|
730
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);
|
|
731
|
+
break;
|
|
732
|
+
case gl.COLOR_CLEAR_VALUE:
|
|
733
|
+
gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
|
|
734
|
+
break;
|
|
735
|
+
case gl.COLOR_WRITEMASK:
|
|
736
|
+
gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
|
|
737
|
+
break;
|
|
738
|
+
case gl.CURRENT_PROGRAM:
|
|
739
|
+
gl.useProgram(boundValue);
|
|
740
|
+
break;
|
|
741
|
+
case gl.ELEMENT_ARRAY_BUFFER_BINDING:
|
|
742
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);
|
|
743
|
+
break;
|
|
744
|
+
case gl.FRAMEBUFFER_BINDING:
|
|
745
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);
|
|
746
|
+
break;
|
|
747
|
+
case gl.RENDERBUFFER_BINDING:
|
|
748
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);
|
|
749
|
+
break;
|
|
750
|
+
case gl.TEXTURE_BINDING_2D:
|
|
751
|
+
var textureUnit = bindings[++i];
|
|
752
|
+
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
|
|
753
|
+
break;
|
|
754
|
+
gl.activeTexture(textureUnit);
|
|
755
|
+
gl.bindTexture(gl.TEXTURE_2D, boundValue);
|
|
756
|
+
break;
|
|
757
|
+
case gl.TEXTURE_BINDING_CUBE_MAP:
|
|
758
|
+
var textureUnit = bindings[++i];
|
|
759
|
+
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
|
|
760
|
+
break;
|
|
761
|
+
gl.activeTexture(textureUnit);
|
|
762
|
+
gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);
|
|
763
|
+
break;
|
|
764
|
+
case gl.VIEWPORT:
|
|
765
|
+
gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
|
|
766
|
+
break;
|
|
767
|
+
case gl.BLEND:
|
|
768
|
+
case gl.CULL_FACE:
|
|
769
|
+
case gl.DEPTH_TEST:
|
|
770
|
+
case gl.SCISSOR_TEST:
|
|
771
|
+
case gl.STENCIL_TEST:
|
|
772
|
+
if (boundValue) {
|
|
773
|
+
gl.enable(binding);
|
|
774
|
+
} else {
|
|
775
|
+
gl.disable(binding);
|
|
776
|
+
}
|
|
777
|
+
break;
|
|
778
|
+
default:
|
|
779
|
+
console.log("No GL restore behavior for 0x" + binding.toString(16));
|
|
780
|
+
break;
|
|
781
|
+
}
|
|
782
|
+
if (activeTexture) {
|
|
783
|
+
gl.activeTexture(activeTexture);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
var glPreserveState = WGLUPreserveGLState;
|
|
788
|
+
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');
|
|
789
|
+
var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n');
|
|
790
|
+
function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) {
|
|
791
|
+
this.gl = gl;
|
|
792
|
+
this.cardboardUI = cardboardUI;
|
|
793
|
+
this.bufferScale = bufferScale;
|
|
794
|
+
this.dirtySubmitFrameBindings = dirtySubmitFrameBindings;
|
|
795
|
+
this.ctxAttribs = gl.getContextAttributes();
|
|
796
|
+
this.meshWidth = 20;
|
|
797
|
+
this.meshHeight = 20;
|
|
798
|
+
this.bufferWidth = gl.drawingBufferWidth;
|
|
799
|
+
this.bufferHeight = gl.drawingBufferHeight;
|
|
800
|
+
this.realBindFramebuffer = gl.bindFramebuffer;
|
|
801
|
+
this.realEnable = gl.enable;
|
|
802
|
+
this.realDisable = gl.disable;
|
|
803
|
+
this.realColorMask = gl.colorMask;
|
|
804
|
+
this.realClearColor = gl.clearColor;
|
|
805
|
+
this.realViewport = gl.viewport;
|
|
806
|
+
if (!isIOS()) {
|
|
807
|
+
this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');
|
|
808
|
+
this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');
|
|
809
|
+
}
|
|
810
|
+
this.isPatched = false;
|
|
811
|
+
this.lastBoundFramebuffer = null;
|
|
812
|
+
this.cullFace = false;
|
|
813
|
+
this.depthTest = false;
|
|
814
|
+
this.blend = false;
|
|
815
|
+
this.scissorTest = false;
|
|
816
|
+
this.stencilTest = false;
|
|
817
|
+
this.viewport = [0, 0, 0, 0];
|
|
818
|
+
this.colorMask = [true, true, true, true];
|
|
819
|
+
this.clearColor = [0, 0, 0, 0];
|
|
820
|
+
this.attribs = {
|
|
821
|
+
position: 0,
|
|
822
|
+
texCoord: 1
|
|
823
|
+
};
|
|
824
|
+
this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs);
|
|
825
|
+
this.uniforms = getProgramUniforms(gl, this.program);
|
|
826
|
+
this.viewportOffsetScale = new Float32Array(8);
|
|
827
|
+
this.setTextureBounds();
|
|
828
|
+
this.vertexBuffer = gl.createBuffer();
|
|
829
|
+
this.indexBuffer = gl.createBuffer();
|
|
830
|
+
this.indexCount = 0;
|
|
831
|
+
this.renderTarget = gl.createTexture();
|
|
832
|
+
this.framebuffer = gl.createFramebuffer();
|
|
833
|
+
this.depthStencilBuffer = null;
|
|
834
|
+
this.depthBuffer = null;
|
|
835
|
+
this.stencilBuffer = null;
|
|
836
|
+
if (this.ctxAttribs.depth && this.ctxAttribs.stencil) {
|
|
837
|
+
this.depthStencilBuffer = gl.createRenderbuffer();
|
|
838
|
+
} else if (this.ctxAttribs.depth) {
|
|
839
|
+
this.depthBuffer = gl.createRenderbuffer();
|
|
840
|
+
} else if (this.ctxAttribs.stencil) {
|
|
841
|
+
this.stencilBuffer = gl.createRenderbuffer();
|
|
842
|
+
}
|
|
843
|
+
this.patch();
|
|
844
|
+
this.onResize();
|
|
845
|
+
}
|
|
846
|
+
CardboardDistorter.prototype.destroy = function () {
|
|
847
|
+
var gl = this.gl;
|
|
848
|
+
this.unpatch();
|
|
849
|
+
gl.deleteProgram(this.program);
|
|
850
|
+
gl.deleteBuffer(this.vertexBuffer);
|
|
851
|
+
gl.deleteBuffer(this.indexBuffer);
|
|
852
|
+
gl.deleteTexture(this.renderTarget);
|
|
853
|
+
gl.deleteFramebuffer(this.framebuffer);
|
|
854
|
+
if (this.depthStencilBuffer) {
|
|
855
|
+
gl.deleteRenderbuffer(this.depthStencilBuffer);
|
|
856
|
+
}
|
|
857
|
+
if (this.depthBuffer) {
|
|
858
|
+
gl.deleteRenderbuffer(this.depthBuffer);
|
|
859
|
+
}
|
|
860
|
+
if (this.stencilBuffer) {
|
|
861
|
+
gl.deleteRenderbuffer(this.stencilBuffer);
|
|
862
|
+
}
|
|
863
|
+
if (this.cardboardUI) {
|
|
864
|
+
this.cardboardUI.destroy();
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
CardboardDistorter.prototype.onResize = function () {
|
|
868
|
+
var gl = this.gl;
|
|
869
|
+
var self = this;
|
|
870
|
+
var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0];
|
|
871
|
+
glPreserveState(gl, glState, function (gl) {
|
|
872
|
+
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
|
|
873
|
+
if (self.scissorTest) {
|
|
874
|
+
self.realDisable.call(gl, gl.SCISSOR_TEST);
|
|
875
|
+
}
|
|
876
|
+
self.realColorMask.call(gl, true, true, true, true);
|
|
877
|
+
self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
878
|
+
self.realClearColor.call(gl, 0, 0, 0, 1);
|
|
879
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
880
|
+
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer);
|
|
881
|
+
gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
|
|
882
|
+
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);
|
|
883
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
884
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
885
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
886
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
887
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0);
|
|
888
|
+
if (self.ctxAttribs.depth && self.ctxAttribs.stencil) {
|
|
889
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer);
|
|
890
|
+
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight);
|
|
891
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer);
|
|
892
|
+
} else if (self.ctxAttribs.depth) {
|
|
893
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer);
|
|
894
|
+
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight);
|
|
895
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer);
|
|
896
|
+
} else if (self.ctxAttribs.stencil) {
|
|
897
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer);
|
|
898
|
+
gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight);
|
|
899
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer);
|
|
900
|
+
}
|
|
901
|
+
if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
|
|
902
|
+
console.error('Framebuffer incomplete!');
|
|
903
|
+
}
|
|
904
|
+
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
|
|
905
|
+
if (self.scissorTest) {
|
|
906
|
+
self.realEnable.call(gl, gl.SCISSOR_TEST);
|
|
907
|
+
}
|
|
908
|
+
self.realColorMask.apply(gl, self.colorMask);
|
|
909
|
+
self.realViewport.apply(gl, self.viewport);
|
|
910
|
+
self.realClearColor.apply(gl, self.clearColor);
|
|
911
|
+
});
|
|
912
|
+
if (this.cardboardUI) {
|
|
913
|
+
this.cardboardUI.onResize();
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
CardboardDistorter.prototype.patch = function () {
|
|
917
|
+
if (this.isPatched) {
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
var self = this;
|
|
921
|
+
var canvas = this.gl.canvas;
|
|
922
|
+
var gl = this.gl;
|
|
923
|
+
if (!isIOS()) {
|
|
924
|
+
canvas.width = getScreenWidth() * this.bufferScale;
|
|
925
|
+
canvas.height = getScreenHeight() * this.bufferScale;
|
|
926
|
+
Object.defineProperty(canvas, 'width', {
|
|
927
|
+
configurable: true,
|
|
928
|
+
enumerable: true,
|
|
929
|
+
get: function get() {
|
|
930
|
+
return self.bufferWidth;
|
|
931
|
+
},
|
|
932
|
+
set: function set(value) {
|
|
933
|
+
self.bufferWidth = value;
|
|
934
|
+
self.realCanvasWidth.set.call(canvas, value);
|
|
935
|
+
self.onResize();
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
Object.defineProperty(canvas, 'height', {
|
|
939
|
+
configurable: true,
|
|
940
|
+
enumerable: true,
|
|
941
|
+
get: function get() {
|
|
942
|
+
return self.bufferHeight;
|
|
943
|
+
},
|
|
944
|
+
set: function set(value) {
|
|
945
|
+
self.bufferHeight = value;
|
|
946
|
+
self.realCanvasHeight.set.call(canvas, value);
|
|
947
|
+
self.onResize();
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
|
|
952
|
+
if (this.lastBoundFramebuffer == null) {
|
|
953
|
+
this.lastBoundFramebuffer = this.framebuffer;
|
|
954
|
+
this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
|
|
955
|
+
}
|
|
956
|
+
this.gl.bindFramebuffer = function (target, framebuffer) {
|
|
957
|
+
self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer;
|
|
958
|
+
self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer);
|
|
959
|
+
};
|
|
960
|
+
this.cullFace = gl.getParameter(gl.CULL_FACE);
|
|
961
|
+
this.depthTest = gl.getParameter(gl.DEPTH_TEST);
|
|
962
|
+
this.blend = gl.getParameter(gl.BLEND);
|
|
963
|
+
this.scissorTest = gl.getParameter(gl.SCISSOR_TEST);
|
|
964
|
+
this.stencilTest = gl.getParameter(gl.STENCIL_TEST);
|
|
965
|
+
gl.enable = function (pname) {
|
|
966
|
+
switch (pname) {
|
|
967
|
+
case gl.CULL_FACE:
|
|
968
|
+
self.cullFace = true;break;
|
|
969
|
+
case gl.DEPTH_TEST:
|
|
970
|
+
self.depthTest = true;break;
|
|
971
|
+
case gl.BLEND:
|
|
972
|
+
self.blend = true;break;
|
|
973
|
+
case gl.SCISSOR_TEST:
|
|
974
|
+
self.scissorTest = true;break;
|
|
975
|
+
case gl.STENCIL_TEST:
|
|
976
|
+
self.stencilTest = true;break;
|
|
977
|
+
}
|
|
978
|
+
self.realEnable.call(gl, pname);
|
|
979
|
+
};
|
|
980
|
+
gl.disable = function (pname) {
|
|
981
|
+
switch (pname) {
|
|
982
|
+
case gl.CULL_FACE:
|
|
983
|
+
self.cullFace = false;break;
|
|
984
|
+
case gl.DEPTH_TEST:
|
|
985
|
+
self.depthTest = false;break;
|
|
986
|
+
case gl.BLEND:
|
|
987
|
+
self.blend = false;break;
|
|
988
|
+
case gl.SCISSOR_TEST:
|
|
989
|
+
self.scissorTest = false;break;
|
|
990
|
+
case gl.STENCIL_TEST:
|
|
991
|
+
self.stencilTest = false;break;
|
|
992
|
+
}
|
|
993
|
+
self.realDisable.call(gl, pname);
|
|
994
|
+
};
|
|
995
|
+
this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK);
|
|
996
|
+
gl.colorMask = function (r, g, b, a) {
|
|
997
|
+
self.colorMask[0] = r;
|
|
998
|
+
self.colorMask[1] = g;
|
|
999
|
+
self.colorMask[2] = b;
|
|
1000
|
+
self.colorMask[3] = a;
|
|
1001
|
+
self.realColorMask.call(gl, r, g, b, a);
|
|
1002
|
+
};
|
|
1003
|
+
this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
|
|
1004
|
+
gl.clearColor = function (r, g, b, a) {
|
|
1005
|
+
self.clearColor[0] = r;
|
|
1006
|
+
self.clearColor[1] = g;
|
|
1007
|
+
self.clearColor[2] = b;
|
|
1008
|
+
self.clearColor[3] = a;
|
|
1009
|
+
self.realClearColor.call(gl, r, g, b, a);
|
|
1010
|
+
};
|
|
1011
|
+
this.viewport = gl.getParameter(gl.VIEWPORT);
|
|
1012
|
+
gl.viewport = function (x, y, w, h) {
|
|
1013
|
+
self.viewport[0] = x;
|
|
1014
|
+
self.viewport[1] = y;
|
|
1015
|
+
self.viewport[2] = w;
|
|
1016
|
+
self.viewport[3] = h;
|
|
1017
|
+
self.realViewport.call(gl, x, y, w, h);
|
|
1018
|
+
};
|
|
1019
|
+
this.isPatched = true;
|
|
1020
|
+
safariCssSizeWorkaround(canvas);
|
|
1021
|
+
};
|
|
1022
|
+
CardboardDistorter.prototype.unpatch = function () {
|
|
1023
|
+
if (!this.isPatched) {
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
var gl = this.gl;
|
|
1027
|
+
var canvas = this.gl.canvas;
|
|
1028
|
+
if (!isIOS()) {
|
|
1029
|
+
Object.defineProperty(canvas, 'width', this.realCanvasWidth);
|
|
1030
|
+
Object.defineProperty(canvas, 'height', this.realCanvasHeight);
|
|
1031
|
+
}
|
|
1032
|
+
canvas.width = this.bufferWidth;
|
|
1033
|
+
canvas.height = this.bufferHeight;
|
|
1034
|
+
gl.bindFramebuffer = this.realBindFramebuffer;
|
|
1035
|
+
gl.enable = this.realEnable;
|
|
1036
|
+
gl.disable = this.realDisable;
|
|
1037
|
+
gl.colorMask = this.realColorMask;
|
|
1038
|
+
gl.clearColor = this.realClearColor;
|
|
1039
|
+
gl.viewport = this.realViewport;
|
|
1040
|
+
if (this.lastBoundFramebuffer == this.framebuffer) {
|
|
1041
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
1042
|
+
}
|
|
1043
|
+
this.isPatched = false;
|
|
1044
|
+
setTimeout(function () {
|
|
1045
|
+
safariCssSizeWorkaround(canvas);
|
|
1046
|
+
}, 1);
|
|
1047
|
+
};
|
|
1048
|
+
CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) {
|
|
1049
|
+
if (!leftBounds) {
|
|
1050
|
+
leftBounds = [0, 0, 0.5, 1];
|
|
1051
|
+
}
|
|
1052
|
+
if (!rightBounds) {
|
|
1053
|
+
rightBounds = [0.5, 0, 0.5, 1];
|
|
1054
|
+
}
|
|
1055
|
+
this.viewportOffsetScale[0] = leftBounds[0];
|
|
1056
|
+
this.viewportOffsetScale[1] = leftBounds[1];
|
|
1057
|
+
this.viewportOffsetScale[2] = leftBounds[2];
|
|
1058
|
+
this.viewportOffsetScale[3] = leftBounds[3];
|
|
1059
|
+
this.viewportOffsetScale[4] = rightBounds[0];
|
|
1060
|
+
this.viewportOffsetScale[5] = rightBounds[1];
|
|
1061
|
+
this.viewportOffsetScale[6] = rightBounds[2];
|
|
1062
|
+
this.viewportOffsetScale[7] = rightBounds[3];
|
|
1063
|
+
};
|
|
1064
|
+
CardboardDistorter.prototype.submitFrame = function () {
|
|
1065
|
+
var gl = this.gl;
|
|
1066
|
+
var self = this;
|
|
1067
|
+
var glState = [];
|
|
1068
|
+
if (!this.dirtySubmitFrameBindings) {
|
|
1069
|
+
glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0);
|
|
1070
|
+
}
|
|
1071
|
+
glPreserveState(gl, glState, function (gl) {
|
|
1072
|
+
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
|
|
1073
|
+
if (self.cullFace) {
|
|
1074
|
+
self.realDisable.call(gl, gl.CULL_FACE);
|
|
1075
|
+
}
|
|
1076
|
+
if (self.depthTest) {
|
|
1077
|
+
self.realDisable.call(gl, gl.DEPTH_TEST);
|
|
1078
|
+
}
|
|
1079
|
+
if (self.blend) {
|
|
1080
|
+
self.realDisable.call(gl, gl.BLEND);
|
|
1081
|
+
}
|
|
1082
|
+
if (self.scissorTest) {
|
|
1083
|
+
self.realDisable.call(gl, gl.SCISSOR_TEST);
|
|
1084
|
+
}
|
|
1085
|
+
if (self.stencilTest) {
|
|
1086
|
+
self.realDisable.call(gl, gl.STENCIL_TEST);
|
|
1087
|
+
}
|
|
1088
|
+
self.realColorMask.call(gl, true, true, true, true);
|
|
1089
|
+
self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1090
|
+
if (self.ctxAttribs.alpha || isIOS()) {
|
|
1091
|
+
self.realClearColor.call(gl, 0, 0, 0, 1);
|
|
1092
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
1093
|
+
}
|
|
1094
|
+
gl.useProgram(self.program);
|
|
1095
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
|
|
1096
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
|
|
1097
|
+
gl.enableVertexAttribArray(self.attribs.position);
|
|
1098
|
+
gl.enableVertexAttribArray(self.attribs.texCoord);
|
|
1099
|
+
gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0);
|
|
1100
|
+
gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8);
|
|
1101
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
1102
|
+
gl.uniform1i(self.uniforms.diffuse, 0);
|
|
1103
|
+
gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
|
|
1104
|
+
gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale);
|
|
1105
|
+
gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);
|
|
1106
|
+
if (self.cardboardUI) {
|
|
1107
|
+
self.cardboardUI.renderNoState();
|
|
1108
|
+
}
|
|
1109
|
+
self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);
|
|
1110
|
+
if (!self.ctxAttribs.preserveDrawingBuffer) {
|
|
1111
|
+
self.realClearColor.call(gl, 0, 0, 0, 0);
|
|
1112
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
1113
|
+
}
|
|
1114
|
+
if (!self.dirtySubmitFrameBindings) {
|
|
1115
|
+
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
|
|
1116
|
+
}
|
|
1117
|
+
if (self.cullFace) {
|
|
1118
|
+
self.realEnable.call(gl, gl.CULL_FACE);
|
|
1119
|
+
}
|
|
1120
|
+
if (self.depthTest) {
|
|
1121
|
+
self.realEnable.call(gl, gl.DEPTH_TEST);
|
|
1122
|
+
}
|
|
1123
|
+
if (self.blend) {
|
|
1124
|
+
self.realEnable.call(gl, gl.BLEND);
|
|
1125
|
+
}
|
|
1126
|
+
if (self.scissorTest) {
|
|
1127
|
+
self.realEnable.call(gl, gl.SCISSOR_TEST);
|
|
1128
|
+
}
|
|
1129
|
+
if (self.stencilTest) {
|
|
1130
|
+
self.realEnable.call(gl, gl.STENCIL_TEST);
|
|
1131
|
+
}
|
|
1132
|
+
self.realColorMask.apply(gl, self.colorMask);
|
|
1133
|
+
self.realViewport.apply(gl, self.viewport);
|
|
1134
|
+
if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) {
|
|
1135
|
+
self.realClearColor.apply(gl, self.clearColor);
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
if (isIOS()) {
|
|
1139
|
+
var canvas = gl.canvas;
|
|
1140
|
+
if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) {
|
|
1141
|
+
self.bufferWidth = canvas.width;
|
|
1142
|
+
self.bufferHeight = canvas.height;
|
|
1143
|
+
self.onResize();
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) {
|
|
1148
|
+
var gl = this.gl;
|
|
1149
|
+
var self = this;
|
|
1150
|
+
var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];
|
|
1151
|
+
glPreserveState(gl, glState, function (gl) {
|
|
1152
|
+
var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo);
|
|
1153
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
|
|
1154
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
1155
|
+
if (!self.indexCount) {
|
|
1156
|
+
var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight);
|
|
1157
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
|
|
1158
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
|
|
1159
|
+
self.indexCount = indices.length;
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
};
|
|
1163
|
+
CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) {
|
|
1164
|
+
var vertices = new Float32Array(2 * width * height * 5);
|
|
1165
|
+
var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();
|
|
1166
|
+
var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();
|
|
1167
|
+
var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);
|
|
1168
|
+
var vidx = 0;
|
|
1169
|
+
for (var e = 0; e < 2; e++) {
|
|
1170
|
+
for (var j = 0; j < height; j++) {
|
|
1171
|
+
for (var i = 0; i < width; i++, vidx++) {
|
|
1172
|
+
var u = i / (width - 1);
|
|
1173
|
+
var v = j / (height - 1);
|
|
1174
|
+
var s = u;
|
|
1175
|
+
var t = v;
|
|
1176
|
+
var x = lerp(lensFrustum[0], lensFrustum[2], u);
|
|
1177
|
+
var y = lerp(lensFrustum[3], lensFrustum[1], v);
|
|
1178
|
+
var d = Math.sqrt(x * x + y * y);
|
|
1179
|
+
var r = deviceInfo.distortion.distortInverse(d);
|
|
1180
|
+
var p = x * r / d;
|
|
1181
|
+
var q = y * r / d;
|
|
1182
|
+
u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]);
|
|
1183
|
+
v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]);
|
|
1184
|
+
u = (viewport.x + u * viewport.width - 0.5) * 2.0;
|
|
1185
|
+
v = (viewport.y + v * viewport.height - 0.5) * 2.0;
|
|
1186
|
+
vertices[vidx * 5 + 0] = u;
|
|
1187
|
+
vertices[vidx * 5 + 1] = v;
|
|
1188
|
+
vertices[vidx * 5 + 2] = s;
|
|
1189
|
+
vertices[vidx * 5 + 3] = t;
|
|
1190
|
+
vertices[vidx * 5 + 4] = e;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
var w = lensFrustum[2] - lensFrustum[0];
|
|
1194
|
+
lensFrustum[0] = -(w + lensFrustum[0]);
|
|
1195
|
+
lensFrustum[2] = w - lensFrustum[2];
|
|
1196
|
+
w = noLensFrustum[2] - noLensFrustum[0];
|
|
1197
|
+
noLensFrustum[0] = -(w + noLensFrustum[0]);
|
|
1198
|
+
noLensFrustum[2] = w - noLensFrustum[2];
|
|
1199
|
+
viewport.x = 1 - (viewport.x + viewport.width);
|
|
1200
|
+
}
|
|
1201
|
+
return vertices;
|
|
1202
|
+
};
|
|
1203
|
+
CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) {
|
|
1204
|
+
var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6);
|
|
1205
|
+
var halfwidth = width / 2;
|
|
1206
|
+
var halfheight = height / 2;
|
|
1207
|
+
var vidx = 0;
|
|
1208
|
+
var iidx = 0;
|
|
1209
|
+
for (var e = 0; e < 2; e++) {
|
|
1210
|
+
for (var j = 0; j < height; j++) {
|
|
1211
|
+
for (var i = 0; i < width; i++, vidx++) {
|
|
1212
|
+
if (i == 0 || j == 0) continue;
|
|
1213
|
+
if (i <= halfwidth == j <= halfheight) {
|
|
1214
|
+
indices[iidx++] = vidx;
|
|
1215
|
+
indices[iidx++] = vidx - width - 1;
|
|
1216
|
+
indices[iidx++] = vidx - width;
|
|
1217
|
+
indices[iidx++] = vidx - width - 1;
|
|
1218
|
+
indices[iidx++] = vidx;
|
|
1219
|
+
indices[iidx++] = vidx - 1;
|
|
1220
|
+
} else {
|
|
1221
|
+
indices[iidx++] = vidx - 1;
|
|
1222
|
+
indices[iidx++] = vidx - width;
|
|
1223
|
+
indices[iidx++] = vidx;
|
|
1224
|
+
indices[iidx++] = vidx - width;
|
|
1225
|
+
indices[iidx++] = vidx - 1;
|
|
1226
|
+
indices[iidx++] = vidx - width - 1;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return indices;
|
|
1232
|
+
};
|
|
1233
|
+
CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) {
|
|
1234
|
+
var descriptor = Object.getOwnPropertyDescriptor(proto, attrName);
|
|
1235
|
+
if (descriptor.get === undefined || descriptor.set === undefined) {
|
|
1236
|
+
descriptor.configurable = true;
|
|
1237
|
+
descriptor.enumerable = true;
|
|
1238
|
+
descriptor.get = function () {
|
|
1239
|
+
return this.getAttribute(attrName);
|
|
1240
|
+
};
|
|
1241
|
+
descriptor.set = function (val) {
|
|
1242
|
+
this.setAttribute(attrName, val);
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
return descriptor;
|
|
1246
|
+
};
|
|
1247
|
+
var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n');
|
|
1248
|
+
var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n');
|
|
1249
|
+
var DEG2RAD = Math.PI / 180.0;
|
|
1250
|
+
var kAnglePerGearSection = 60;
|
|
1251
|
+
var kOuterRimEndAngle = 12;
|
|
1252
|
+
var kInnerRimBeginAngle = 20;
|
|
1253
|
+
var kOuterRadius = 1;
|
|
1254
|
+
var kMiddleRadius = 0.75;
|
|
1255
|
+
var kInnerRadius = 0.3125;
|
|
1256
|
+
var kCenterLineThicknessDp = 4;
|
|
1257
|
+
var kButtonWidthDp = 28;
|
|
1258
|
+
var kTouchSlopFactor = 1.5;
|
|
1259
|
+
function CardboardUI(gl) {
|
|
1260
|
+
this.gl = gl;
|
|
1261
|
+
this.attribs = {
|
|
1262
|
+
position: 0
|
|
1263
|
+
};
|
|
1264
|
+
this.program = linkProgram(gl, uiVS, uiFS, this.attribs);
|
|
1265
|
+
this.uniforms = getProgramUniforms(gl, this.program);
|
|
1266
|
+
this.vertexBuffer = gl.createBuffer();
|
|
1267
|
+
this.gearOffset = 0;
|
|
1268
|
+
this.gearVertexCount = 0;
|
|
1269
|
+
this.arrowOffset = 0;
|
|
1270
|
+
this.arrowVertexCount = 0;
|
|
1271
|
+
this.projMat = new Float32Array(16);
|
|
1272
|
+
this.listener = null;
|
|
1273
|
+
this.onResize();
|
|
1274
|
+
}
|
|
1275
|
+
CardboardUI.prototype.destroy = function () {
|
|
1276
|
+
var gl = this.gl;
|
|
1277
|
+
if (this.listener) {
|
|
1278
|
+
gl.canvas.removeEventListener('click', this.listener, false);
|
|
1279
|
+
}
|
|
1280
|
+
gl.deleteProgram(this.program);
|
|
1281
|
+
gl.deleteBuffer(this.vertexBuffer);
|
|
1282
|
+
};
|
|
1283
|
+
CardboardUI.prototype.listen = function (optionsCallback, backCallback) {
|
|
1284
|
+
var canvas = this.gl.canvas;
|
|
1285
|
+
this.listener = function (event) {
|
|
1286
|
+
var midline = canvas.clientWidth / 2;
|
|
1287
|
+
var buttonSize = kButtonWidthDp * kTouchSlopFactor;
|
|
1288
|
+
if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) {
|
|
1289
|
+
optionsCallback(event);
|
|
1290
|
+
}
|
|
1291
|
+
else if (event.clientX < buttonSize && event.clientY < buttonSize) {
|
|
1292
|
+
backCallback(event);
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
canvas.addEventListener('click', this.listener, false);
|
|
1296
|
+
};
|
|
1297
|
+
CardboardUI.prototype.onResize = function () {
|
|
1298
|
+
var gl = this.gl;
|
|
1299
|
+
var self = this;
|
|
1300
|
+
var glState = [gl.ARRAY_BUFFER_BINDING];
|
|
1301
|
+
glPreserveState(gl, glState, function (gl) {
|
|
1302
|
+
var vertices = [];
|
|
1303
|
+
var midline = gl.drawingBufferWidth / 2;
|
|
1304
|
+
var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;
|
|
1305
|
+
var scalingRatio = gl.drawingBufferWidth / physicalPixels;
|
|
1306
|
+
var dps = scalingRatio * window.devicePixelRatio;
|
|
1307
|
+
var lineWidth = kCenterLineThicknessDp * dps / 2;
|
|
1308
|
+
var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps;
|
|
1309
|
+
var buttonScale = kButtonWidthDp * dps / 2;
|
|
1310
|
+
var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps;
|
|
1311
|
+
vertices.push(midline - lineWidth, buttonSize);
|
|
1312
|
+
vertices.push(midline - lineWidth, gl.drawingBufferHeight);
|
|
1313
|
+
vertices.push(midline + lineWidth, buttonSize);
|
|
1314
|
+
vertices.push(midline + lineWidth, gl.drawingBufferHeight);
|
|
1315
|
+
self.gearOffset = vertices.length / 2;
|
|
1316
|
+
function addGearSegment(theta, r) {
|
|
1317
|
+
var angle = (90 - theta) * DEG2RAD;
|
|
1318
|
+
var x = Math.cos(angle);
|
|
1319
|
+
var y = Math.sin(angle);
|
|
1320
|
+
vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale);
|
|
1321
|
+
vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale);
|
|
1322
|
+
}
|
|
1323
|
+
for (var i = 0; i <= 6; i++) {
|
|
1324
|
+
var segmentTheta = i * kAnglePerGearSection;
|
|
1325
|
+
addGearSegment(segmentTheta, kOuterRadius);
|
|
1326
|
+
addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius);
|
|
1327
|
+
addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius);
|
|
1328
|
+
addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius);
|
|
1329
|
+
addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius);
|
|
1330
|
+
}
|
|
1331
|
+
self.gearVertexCount = vertices.length / 2 - self.gearOffset;
|
|
1332
|
+
self.arrowOffset = vertices.length / 2;
|
|
1333
|
+
function addArrowVertex(x, y) {
|
|
1334
|
+
vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);
|
|
1335
|
+
}
|
|
1336
|
+
var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);
|
|
1337
|
+
addArrowVertex(0, buttonScale);
|
|
1338
|
+
addArrowVertex(buttonScale, 0);
|
|
1339
|
+
addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);
|
|
1340
|
+
addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);
|
|
1341
|
+
addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
|
|
1342
|
+
addArrowVertex(0, buttonScale);
|
|
1343
|
+
addArrowVertex(buttonScale, buttonScale * 2);
|
|
1344
|
+
addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth);
|
|
1345
|
+
addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
|
|
1346
|
+
addArrowVertex(0, buttonScale);
|
|
1347
|
+
addArrowVertex(angledLineWidth, buttonScale - lineWidth);
|
|
1348
|
+
addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);
|
|
1349
|
+
addArrowVertex(angledLineWidth, buttonScale + lineWidth);
|
|
1350
|
+
addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);
|
|
1351
|
+
self.arrowVertexCount = vertices.length / 2 - self.arrowOffset;
|
|
1352
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
|
|
1353
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
|
|
1354
|
+
});
|
|
1355
|
+
};
|
|
1356
|
+
CardboardUI.prototype.render = function () {
|
|
1357
|
+
var gl = this.gl;
|
|
1358
|
+
var self = this;
|
|
1359
|
+
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];
|
|
1360
|
+
glPreserveState(gl, glState, function (gl) {
|
|
1361
|
+
gl.disable(gl.CULL_FACE);
|
|
1362
|
+
gl.disable(gl.DEPTH_TEST);
|
|
1363
|
+
gl.disable(gl.BLEND);
|
|
1364
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
1365
|
+
gl.disable(gl.STENCIL_TEST);
|
|
1366
|
+
gl.colorMask(true, true, true, true);
|
|
1367
|
+
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1368
|
+
self.renderNoState();
|
|
1369
|
+
});
|
|
1370
|
+
};
|
|
1371
|
+
CardboardUI.prototype.renderNoState = function () {
|
|
1372
|
+
var gl = this.gl;
|
|
1373
|
+
gl.useProgram(this.program);
|
|
1374
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
1375
|
+
gl.enableVertexAttribArray(this.attribs.position);
|
|
1376
|
+
gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0);
|
|
1377
|
+
gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);
|
|
1378
|
+
orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);
|
|
1379
|
+
gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);
|
|
1380
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
1381
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount);
|
|
1382
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount);
|
|
1383
|
+
};
|
|
1384
|
+
function Distortion(coefficients) {
|
|
1385
|
+
this.coefficients = coefficients;
|
|
1386
|
+
}
|
|
1387
|
+
Distortion.prototype.distortInverse = function (radius) {
|
|
1388
|
+
var r0 = 0;
|
|
1389
|
+
var r1 = 1;
|
|
1390
|
+
var dr0 = radius - this.distort(r0);
|
|
1391
|
+
while (Math.abs(r1 - r0) > 0.0001 ) {
|
|
1392
|
+
var dr1 = radius - this.distort(r1);
|
|
1393
|
+
var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));
|
|
1394
|
+
r0 = r1;
|
|
1395
|
+
r1 = r2;
|
|
1396
|
+
dr0 = dr1;
|
|
1397
|
+
}
|
|
1398
|
+
return r1;
|
|
1399
|
+
};
|
|
1400
|
+
Distortion.prototype.distort = function (radius) {
|
|
1401
|
+
var r2 = radius * radius;
|
|
1402
|
+
var ret = 0;
|
|
1403
|
+
for (var i = 0; i < this.coefficients.length; i++) {
|
|
1404
|
+
ret = r2 * (ret + this.coefficients[i]);
|
|
1405
|
+
}
|
|
1406
|
+
return (ret + 1) * radius;
|
|
1407
|
+
};
|
|
1408
|
+
var degToRad = Math.PI / 180;
|
|
1409
|
+
var radToDeg = 180 / Math.PI;
|
|
1410
|
+
var Vector3 = function Vector3(x, y, z) {
|
|
1411
|
+
this.x = x || 0;
|
|
1412
|
+
this.y = y || 0;
|
|
1413
|
+
this.z = z || 0;
|
|
1414
|
+
};
|
|
1415
|
+
Vector3.prototype = {
|
|
1416
|
+
constructor: Vector3,
|
|
1417
|
+
set: function set(x, y, z) {
|
|
1418
|
+
this.x = x;
|
|
1419
|
+
this.y = y;
|
|
1420
|
+
this.z = z;
|
|
1421
|
+
return this;
|
|
1422
|
+
},
|
|
1423
|
+
copy: function copy(v) {
|
|
1424
|
+
this.x = v.x;
|
|
1425
|
+
this.y = v.y;
|
|
1426
|
+
this.z = v.z;
|
|
1427
|
+
return this;
|
|
1428
|
+
},
|
|
1429
|
+
length: function length() {
|
|
1430
|
+
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
|
1431
|
+
},
|
|
1432
|
+
normalize: function normalize() {
|
|
1433
|
+
var scalar = this.length();
|
|
1434
|
+
if (scalar !== 0) {
|
|
1435
|
+
var invScalar = 1 / scalar;
|
|
1436
|
+
this.multiplyScalar(invScalar);
|
|
1437
|
+
} else {
|
|
1438
|
+
this.x = 0;
|
|
1439
|
+
this.y = 0;
|
|
1440
|
+
this.z = 0;
|
|
1441
|
+
}
|
|
1442
|
+
return this;
|
|
1443
|
+
},
|
|
1444
|
+
multiplyScalar: function multiplyScalar(scalar) {
|
|
1445
|
+
this.x *= scalar;
|
|
1446
|
+
this.y *= scalar;
|
|
1447
|
+
this.z *= scalar;
|
|
1448
|
+
},
|
|
1449
|
+
applyQuaternion: function applyQuaternion(q) {
|
|
1450
|
+
var x = this.x;
|
|
1451
|
+
var y = this.y;
|
|
1452
|
+
var z = this.z;
|
|
1453
|
+
var qx = q.x;
|
|
1454
|
+
var qy = q.y;
|
|
1455
|
+
var qz = q.z;
|
|
1456
|
+
var qw = q.w;
|
|
1457
|
+
var ix = qw * x + qy * z - qz * y;
|
|
1458
|
+
var iy = qw * y + qz * x - qx * z;
|
|
1459
|
+
var iz = qw * z + qx * y - qy * x;
|
|
1460
|
+
var iw = -qx * x - qy * y - qz * z;
|
|
1461
|
+
this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
|
|
1462
|
+
this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
|
|
1463
|
+
this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
|
|
1464
|
+
return this;
|
|
1465
|
+
},
|
|
1466
|
+
dot: function dot(v) {
|
|
1467
|
+
return this.x * v.x + this.y * v.y + this.z * v.z;
|
|
1468
|
+
},
|
|
1469
|
+
crossVectors: function crossVectors(a, b) {
|
|
1470
|
+
var ax = a.x,
|
|
1471
|
+
ay = a.y,
|
|
1472
|
+
az = a.z;
|
|
1473
|
+
var bx = b.x,
|
|
1474
|
+
by = b.y,
|
|
1475
|
+
bz = b.z;
|
|
1476
|
+
this.x = ay * bz - az * by;
|
|
1477
|
+
this.y = az * bx - ax * bz;
|
|
1478
|
+
this.z = ax * by - ay * bx;
|
|
1479
|
+
return this;
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
var Quaternion = function Quaternion(x, y, z, w) {
|
|
1483
|
+
this.x = x || 0;
|
|
1484
|
+
this.y = y || 0;
|
|
1485
|
+
this.z = z || 0;
|
|
1486
|
+
this.w = w !== undefined ? w : 1;
|
|
1487
|
+
};
|
|
1488
|
+
Quaternion.prototype = {
|
|
1489
|
+
constructor: Quaternion,
|
|
1490
|
+
set: function set(x, y, z, w) {
|
|
1491
|
+
this.x = x;
|
|
1492
|
+
this.y = y;
|
|
1493
|
+
this.z = z;
|
|
1494
|
+
this.w = w;
|
|
1495
|
+
return this;
|
|
1496
|
+
},
|
|
1497
|
+
copy: function copy(quaternion) {
|
|
1498
|
+
this.x = quaternion.x;
|
|
1499
|
+
this.y = quaternion.y;
|
|
1500
|
+
this.z = quaternion.z;
|
|
1501
|
+
this.w = quaternion.w;
|
|
1502
|
+
return this;
|
|
1503
|
+
},
|
|
1504
|
+
setFromEulerXYZ: function setFromEulerXYZ(x, y, z) {
|
|
1505
|
+
var c1 = Math.cos(x / 2);
|
|
1506
|
+
var c2 = Math.cos(y / 2);
|
|
1507
|
+
var c3 = Math.cos(z / 2);
|
|
1508
|
+
var s1 = Math.sin(x / 2);
|
|
1509
|
+
var s2 = Math.sin(y / 2);
|
|
1510
|
+
var s3 = Math.sin(z / 2);
|
|
1511
|
+
this.x = s1 * c2 * c3 + c1 * s2 * s3;
|
|
1512
|
+
this.y = c1 * s2 * c3 - s1 * c2 * s3;
|
|
1513
|
+
this.z = c1 * c2 * s3 + s1 * s2 * c3;
|
|
1514
|
+
this.w = c1 * c2 * c3 - s1 * s2 * s3;
|
|
1515
|
+
return this;
|
|
1516
|
+
},
|
|
1517
|
+
setFromEulerYXZ: function setFromEulerYXZ(x, y, z) {
|
|
1518
|
+
var c1 = Math.cos(x / 2);
|
|
1519
|
+
var c2 = Math.cos(y / 2);
|
|
1520
|
+
var c3 = Math.cos(z / 2);
|
|
1521
|
+
var s1 = Math.sin(x / 2);
|
|
1522
|
+
var s2 = Math.sin(y / 2);
|
|
1523
|
+
var s3 = Math.sin(z / 2);
|
|
1524
|
+
this.x = s1 * c2 * c3 + c1 * s2 * s3;
|
|
1525
|
+
this.y = c1 * s2 * c3 - s1 * c2 * s3;
|
|
1526
|
+
this.z = c1 * c2 * s3 - s1 * s2 * c3;
|
|
1527
|
+
this.w = c1 * c2 * c3 + s1 * s2 * s3;
|
|
1528
|
+
return this;
|
|
1529
|
+
},
|
|
1530
|
+
setFromAxisAngle: function setFromAxisAngle(axis, angle) {
|
|
1531
|
+
var halfAngle = angle / 2,
|
|
1532
|
+
s = Math.sin(halfAngle);
|
|
1533
|
+
this.x = axis.x * s;
|
|
1534
|
+
this.y = axis.y * s;
|
|
1535
|
+
this.z = axis.z * s;
|
|
1536
|
+
this.w = Math.cos(halfAngle);
|
|
1537
|
+
return this;
|
|
1538
|
+
},
|
|
1539
|
+
multiply: function multiply(q) {
|
|
1540
|
+
return this.multiplyQuaternions(this, q);
|
|
1541
|
+
},
|
|
1542
|
+
multiplyQuaternions: function multiplyQuaternions(a, b) {
|
|
1543
|
+
var qax = a.x,
|
|
1544
|
+
qay = a.y,
|
|
1545
|
+
qaz = a.z,
|
|
1546
|
+
qaw = a.w;
|
|
1547
|
+
var qbx = b.x,
|
|
1548
|
+
qby = b.y,
|
|
1549
|
+
qbz = b.z,
|
|
1550
|
+
qbw = b.w;
|
|
1551
|
+
this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
|
|
1552
|
+
this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
|
|
1553
|
+
this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
|
|
1554
|
+
this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
|
|
1555
|
+
return this;
|
|
1556
|
+
},
|
|
1557
|
+
inverse: function inverse() {
|
|
1558
|
+
this.x *= -1;
|
|
1559
|
+
this.y *= -1;
|
|
1560
|
+
this.z *= -1;
|
|
1561
|
+
this.normalize();
|
|
1562
|
+
return this;
|
|
1563
|
+
},
|
|
1564
|
+
normalize: function normalize() {
|
|
1565
|
+
var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
|
|
1566
|
+
if (l === 0) {
|
|
1567
|
+
this.x = 0;
|
|
1568
|
+
this.y = 0;
|
|
1569
|
+
this.z = 0;
|
|
1570
|
+
this.w = 1;
|
|
1571
|
+
} else {
|
|
1572
|
+
l = 1 / l;
|
|
1573
|
+
this.x = this.x * l;
|
|
1574
|
+
this.y = this.y * l;
|
|
1575
|
+
this.z = this.z * l;
|
|
1576
|
+
this.w = this.w * l;
|
|
1577
|
+
}
|
|
1578
|
+
return this;
|
|
1579
|
+
},
|
|
1580
|
+
slerp: function slerp(qb, t) {
|
|
1581
|
+
if (t === 0) return this;
|
|
1582
|
+
if (t === 1) return this.copy(qb);
|
|
1583
|
+
var x = this.x,
|
|
1584
|
+
y = this.y,
|
|
1585
|
+
z = this.z,
|
|
1586
|
+
w = this.w;
|
|
1587
|
+
var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
|
|
1588
|
+
if (cosHalfTheta < 0) {
|
|
1589
|
+
this.w = -qb.w;
|
|
1590
|
+
this.x = -qb.x;
|
|
1591
|
+
this.y = -qb.y;
|
|
1592
|
+
this.z = -qb.z;
|
|
1593
|
+
cosHalfTheta = -cosHalfTheta;
|
|
1594
|
+
} else {
|
|
1595
|
+
this.copy(qb);
|
|
1596
|
+
}
|
|
1597
|
+
if (cosHalfTheta >= 1.0) {
|
|
1598
|
+
this.w = w;
|
|
1599
|
+
this.x = x;
|
|
1600
|
+
this.y = y;
|
|
1601
|
+
this.z = z;
|
|
1602
|
+
return this;
|
|
1603
|
+
}
|
|
1604
|
+
var halfTheta = Math.acos(cosHalfTheta);
|
|
1605
|
+
var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
|
|
1606
|
+
if (Math.abs(sinHalfTheta) < 0.001) {
|
|
1607
|
+
this.w = 0.5 * (w + this.w);
|
|
1608
|
+
this.x = 0.5 * (x + this.x);
|
|
1609
|
+
this.y = 0.5 * (y + this.y);
|
|
1610
|
+
this.z = 0.5 * (z + this.z);
|
|
1611
|
+
return this;
|
|
1612
|
+
}
|
|
1613
|
+
var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
|
|
1614
|
+
ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
|
|
1615
|
+
this.w = w * ratioA + this.w * ratioB;
|
|
1616
|
+
this.x = x * ratioA + this.x * ratioB;
|
|
1617
|
+
this.y = y * ratioA + this.y * ratioB;
|
|
1618
|
+
this.z = z * ratioA + this.z * ratioB;
|
|
1619
|
+
return this;
|
|
1620
|
+
},
|
|
1621
|
+
setFromUnitVectors: function () {
|
|
1622
|
+
var v1, r;
|
|
1623
|
+
var EPS = 0.000001;
|
|
1624
|
+
return function (vFrom, vTo) {
|
|
1625
|
+
if (v1 === undefined) v1 = new Vector3();
|
|
1626
|
+
r = vFrom.dot(vTo) + 1;
|
|
1627
|
+
if (r < EPS) {
|
|
1628
|
+
r = 0;
|
|
1629
|
+
if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
|
|
1630
|
+
v1.set(-vFrom.y, vFrom.x, 0);
|
|
1631
|
+
} else {
|
|
1632
|
+
v1.set(0, -vFrom.z, vFrom.y);
|
|
1633
|
+
}
|
|
1634
|
+
} else {
|
|
1635
|
+
v1.crossVectors(vFrom, vTo);
|
|
1636
|
+
}
|
|
1637
|
+
this.x = v1.x;
|
|
1638
|
+
this.y = v1.y;
|
|
1639
|
+
this.z = v1.z;
|
|
1640
|
+
this.w = r;
|
|
1641
|
+
this.normalize();
|
|
1642
|
+
return this;
|
|
1643
|
+
};
|
|
1644
|
+
}()
|
|
1645
|
+
};
|
|
1646
|
+
function Device(params) {
|
|
1647
|
+
this.width = params.width || getScreenWidth();
|
|
1648
|
+
this.height = params.height || getScreenHeight();
|
|
1649
|
+
this.widthMeters = params.widthMeters;
|
|
1650
|
+
this.heightMeters = params.heightMeters;
|
|
1651
|
+
this.bevelMeters = params.bevelMeters;
|
|
1652
|
+
}
|
|
1653
|
+
var DEFAULT_ANDROID = new Device({
|
|
1654
|
+
widthMeters: 0.110,
|
|
1655
|
+
heightMeters: 0.062,
|
|
1656
|
+
bevelMeters: 0.004
|
|
1657
|
+
});
|
|
1658
|
+
var DEFAULT_IOS = new Device({
|
|
1659
|
+
widthMeters: 0.1038,
|
|
1660
|
+
heightMeters: 0.0584,
|
|
1661
|
+
bevelMeters: 0.004
|
|
1662
|
+
});
|
|
1663
|
+
var Viewers = {
|
|
1664
|
+
CardboardV1: new CardboardViewer({
|
|
1665
|
+
id: 'CardboardV1',
|
|
1666
|
+
label: 'Cardboard I/O 2014',
|
|
1667
|
+
fov: 40,
|
|
1668
|
+
interLensDistance: 0.060,
|
|
1669
|
+
baselineLensDistance: 0.035,
|
|
1670
|
+
screenLensDistance: 0.042,
|
|
1671
|
+
distortionCoefficients: [0.441, 0.156],
|
|
1672
|
+
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]
|
|
1673
|
+
}),
|
|
1674
|
+
CardboardV2: new CardboardViewer({
|
|
1675
|
+
id: 'CardboardV2',
|
|
1676
|
+
label: 'Cardboard I/O 2015',
|
|
1677
|
+
fov: 60,
|
|
1678
|
+
interLensDistance: 0.064,
|
|
1679
|
+
baselineLensDistance: 0.035,
|
|
1680
|
+
screenLensDistance: 0.039,
|
|
1681
|
+
distortionCoefficients: [0.34, 0.55],
|
|
1682
|
+
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]
|
|
1683
|
+
})
|
|
1684
|
+
};
|
|
1685
|
+
function DeviceInfo(deviceParams, additionalViewers) {
|
|
1686
|
+
this.viewer = Viewers.CardboardV2;
|
|
1687
|
+
this.updateDeviceParams(deviceParams);
|
|
1688
|
+
this.distortion = new Distortion(this.viewer.distortionCoefficients);
|
|
1689
|
+
for (var i = 0; i < additionalViewers.length; i++) {
|
|
1690
|
+
var viewer = additionalViewers[i];
|
|
1691
|
+
Viewers[viewer.id] = new CardboardViewer(viewer);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
DeviceInfo.prototype.updateDeviceParams = function (deviceParams) {
|
|
1695
|
+
this.device = this.determineDevice_(deviceParams) || this.device;
|
|
1696
|
+
};
|
|
1697
|
+
DeviceInfo.prototype.getDevice = function () {
|
|
1698
|
+
return this.device;
|
|
1699
|
+
};
|
|
1700
|
+
DeviceInfo.prototype.setViewer = function (viewer) {
|
|
1701
|
+
this.viewer = viewer;
|
|
1702
|
+
this.distortion = new Distortion(this.viewer.distortionCoefficients);
|
|
1703
|
+
};
|
|
1704
|
+
DeviceInfo.prototype.determineDevice_ = function (deviceParams) {
|
|
1705
|
+
if (!deviceParams) {
|
|
1706
|
+
if (isIOS()) {
|
|
1707
|
+
console.warn('Using fallback iOS device measurements.');
|
|
1708
|
+
return DEFAULT_IOS;
|
|
1709
|
+
} else {
|
|
1710
|
+
console.warn('Using fallback Android device measurements.');
|
|
1711
|
+
return DEFAULT_ANDROID;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
var METERS_PER_INCH = 0.0254;
|
|
1715
|
+
var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi;
|
|
1716
|
+
var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi;
|
|
1717
|
+
var width = getScreenWidth();
|
|
1718
|
+
var height = getScreenHeight();
|
|
1719
|
+
return new Device({
|
|
1720
|
+
widthMeters: metersPerPixelX * width,
|
|
1721
|
+
heightMeters: metersPerPixelY * height,
|
|
1722
|
+
bevelMeters: deviceParams.bevelMm * 0.001
|
|
1723
|
+
});
|
|
1724
|
+
};
|
|
1725
|
+
DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () {
|
|
1726
|
+
var viewer = this.viewer;
|
|
1727
|
+
var device = this.device;
|
|
1728
|
+
var distortion = this.distortion;
|
|
1729
|
+
var eyeToScreenDistance = viewer.screenLensDistance;
|
|
1730
|
+
var outerDist = (device.widthMeters - viewer.interLensDistance) / 2;
|
|
1731
|
+
var innerDist = viewer.interLensDistance / 2;
|
|
1732
|
+
var bottomDist = viewer.baselineLensDistance - device.bevelMeters;
|
|
1733
|
+
var topDist = device.heightMeters - bottomDist;
|
|
1734
|
+
var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance));
|
|
1735
|
+
var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance));
|
|
1736
|
+
var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance));
|
|
1737
|
+
var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance));
|
|
1738
|
+
return {
|
|
1739
|
+
leftDegrees: Math.min(outerAngle, viewer.fov),
|
|
1740
|
+
rightDegrees: Math.min(innerAngle, viewer.fov),
|
|
1741
|
+
downDegrees: Math.min(bottomAngle, viewer.fov),
|
|
1742
|
+
upDegrees: Math.min(topAngle, viewer.fov)
|
|
1743
|
+
};
|
|
1744
|
+
};
|
|
1745
|
+
DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () {
|
|
1746
|
+
var viewer = this.viewer;
|
|
1747
|
+
var device = this.device;
|
|
1748
|
+
var distortion = this.distortion;
|
|
1749
|
+
var fovLeft = Math.tan(-degToRad * viewer.fov);
|
|
1750
|
+
var fovTop = Math.tan(degToRad * viewer.fov);
|
|
1751
|
+
var fovRight = Math.tan(degToRad * viewer.fov);
|
|
1752
|
+
var fovBottom = Math.tan(-degToRad * viewer.fov);
|
|
1753
|
+
var halfWidth = device.widthMeters / 4;
|
|
1754
|
+
var halfHeight = device.heightMeters / 2;
|
|
1755
|
+
var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
|
|
1756
|
+
var centerX = viewer.interLensDistance / 2 - halfWidth;
|
|
1757
|
+
var centerY = -verticalLensOffset;
|
|
1758
|
+
var centerZ = viewer.screenLensDistance;
|
|
1759
|
+
var screenLeft = distortion.distort((centerX - halfWidth) / centerZ);
|
|
1760
|
+
var screenTop = distortion.distort((centerY + halfHeight) / centerZ);
|
|
1761
|
+
var screenRight = distortion.distort((centerX + halfWidth) / centerZ);
|
|
1762
|
+
var screenBottom = distortion.distort((centerY - halfHeight) / centerZ);
|
|
1763
|
+
var result = new Float32Array(4);
|
|
1764
|
+
result[0] = Math.max(fovLeft, screenLeft);
|
|
1765
|
+
result[1] = Math.min(fovTop, screenTop);
|
|
1766
|
+
result[2] = Math.min(fovRight, screenRight);
|
|
1767
|
+
result[3] = Math.max(fovBottom, screenBottom);
|
|
1768
|
+
return result;
|
|
1769
|
+
};
|
|
1770
|
+
DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () {
|
|
1771
|
+
var viewer = this.viewer;
|
|
1772
|
+
var device = this.device;
|
|
1773
|
+
var distortion = this.distortion;
|
|
1774
|
+
var result = new Float32Array(4);
|
|
1775
|
+
var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
|
|
1776
|
+
var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
|
|
1777
|
+
var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
|
|
1778
|
+
var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
|
|
1779
|
+
var halfWidth = device.widthMeters / 4;
|
|
1780
|
+
var halfHeight = device.heightMeters / 2;
|
|
1781
|
+
var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
|
|
1782
|
+
var centerX = viewer.interLensDistance / 2 - halfWidth;
|
|
1783
|
+
var centerY = -verticalLensOffset;
|
|
1784
|
+
var centerZ = viewer.screenLensDistance;
|
|
1785
|
+
var screenLeft = (centerX - halfWidth) / centerZ;
|
|
1786
|
+
var screenTop = (centerY + halfHeight) / centerZ;
|
|
1787
|
+
var screenRight = (centerX + halfWidth) / centerZ;
|
|
1788
|
+
var screenBottom = (centerY - halfHeight) / centerZ;
|
|
1789
|
+
result[0] = Math.max(fovLeft, screenLeft);
|
|
1790
|
+
result[1] = Math.min(fovTop, screenTop);
|
|
1791
|
+
result[2] = Math.min(fovRight, screenRight);
|
|
1792
|
+
result[3] = Math.max(fovBottom, screenBottom);
|
|
1793
|
+
return result;
|
|
1794
|
+
};
|
|
1795
|
+
DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) {
|
|
1796
|
+
var viewer = this.viewer;
|
|
1797
|
+
var device = this.device;
|
|
1798
|
+
var dist = viewer.screenLensDistance;
|
|
1799
|
+
var eyeX = (device.widthMeters - viewer.interLensDistance) / 2;
|
|
1800
|
+
var eyeY = viewer.baselineLensDistance - device.bevelMeters;
|
|
1801
|
+
var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters;
|
|
1802
|
+
var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters;
|
|
1803
|
+
var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters;
|
|
1804
|
+
var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters;
|
|
1805
|
+
return {
|
|
1806
|
+
x: left,
|
|
1807
|
+
y: bottom,
|
|
1808
|
+
width: right - left,
|
|
1809
|
+
height: top - bottom
|
|
1810
|
+
};
|
|
1811
|
+
};
|
|
1812
|
+
DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) {
|
|
1813
|
+
return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye();
|
|
1814
|
+
};
|
|
1815
|
+
DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) {
|
|
1816
|
+
var fov = this.getFieldOfViewLeftEye(opt_isUndistorted);
|
|
1817
|
+
return {
|
|
1818
|
+
leftDegrees: fov.rightDegrees,
|
|
1819
|
+
rightDegrees: fov.leftDegrees,
|
|
1820
|
+
upDegrees: fov.upDegrees,
|
|
1821
|
+
downDegrees: fov.downDegrees
|
|
1822
|
+
};
|
|
1823
|
+
};
|
|
1824
|
+
DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () {
|
|
1825
|
+
var p = this.getUndistortedParams_();
|
|
1826
|
+
return {
|
|
1827
|
+
leftDegrees: radToDeg * Math.atan(p.outerDist),
|
|
1828
|
+
rightDegrees: radToDeg * Math.atan(p.innerDist),
|
|
1829
|
+
downDegrees: radToDeg * Math.atan(p.bottomDist),
|
|
1830
|
+
upDegrees: radToDeg * Math.atan(p.topDist)
|
|
1831
|
+
};
|
|
1832
|
+
};
|
|
1833
|
+
DeviceInfo.prototype.getUndistortedViewportLeftEye = function () {
|
|
1834
|
+
var p = this.getUndistortedParams_();
|
|
1835
|
+
var viewer = this.viewer;
|
|
1836
|
+
var device = this.device;
|
|
1837
|
+
var eyeToScreenDistance = viewer.screenLensDistance;
|
|
1838
|
+
var screenWidth = device.widthMeters / eyeToScreenDistance;
|
|
1839
|
+
var screenHeight = device.heightMeters / eyeToScreenDistance;
|
|
1840
|
+
var xPxPerTanAngle = device.width / screenWidth;
|
|
1841
|
+
var yPxPerTanAngle = device.height / screenHeight;
|
|
1842
|
+
var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle);
|
|
1843
|
+
var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle);
|
|
1844
|
+
return {
|
|
1845
|
+
x: x,
|
|
1846
|
+
y: y,
|
|
1847
|
+
width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x,
|
|
1848
|
+
height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y
|
|
1849
|
+
};
|
|
1850
|
+
};
|
|
1851
|
+
DeviceInfo.prototype.getUndistortedParams_ = function () {
|
|
1852
|
+
var viewer = this.viewer;
|
|
1853
|
+
var device = this.device;
|
|
1854
|
+
var distortion = this.distortion;
|
|
1855
|
+
var eyeToScreenDistance = viewer.screenLensDistance;
|
|
1856
|
+
var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance;
|
|
1857
|
+
var screenWidth = device.widthMeters / eyeToScreenDistance;
|
|
1858
|
+
var screenHeight = device.heightMeters / eyeToScreenDistance;
|
|
1859
|
+
var eyePosX = screenWidth / 2 - halfLensDistance;
|
|
1860
|
+
var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance;
|
|
1861
|
+
var maxFov = viewer.fov;
|
|
1862
|
+
var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov));
|
|
1863
|
+
var outerDist = Math.min(eyePosX, viewerMax);
|
|
1864
|
+
var innerDist = Math.min(halfLensDistance, viewerMax);
|
|
1865
|
+
var bottomDist = Math.min(eyePosY, viewerMax);
|
|
1866
|
+
var topDist = Math.min(screenHeight - eyePosY, viewerMax);
|
|
1867
|
+
return {
|
|
1868
|
+
outerDist: outerDist,
|
|
1869
|
+
innerDist: innerDist,
|
|
1870
|
+
topDist: topDist,
|
|
1871
|
+
bottomDist: bottomDist,
|
|
1872
|
+
eyePosX: eyePosX,
|
|
1873
|
+
eyePosY: eyePosY
|
|
1874
|
+
};
|
|
1875
|
+
};
|
|
1876
|
+
function CardboardViewer(params) {
|
|
1877
|
+
this.id = params.id;
|
|
1878
|
+
this.label = params.label;
|
|
1879
|
+
this.fov = params.fov;
|
|
1880
|
+
this.interLensDistance = params.interLensDistance;
|
|
1881
|
+
this.baselineLensDistance = params.baselineLensDistance;
|
|
1882
|
+
this.screenLensDistance = params.screenLensDistance;
|
|
1883
|
+
this.distortionCoefficients = params.distortionCoefficients;
|
|
1884
|
+
this.inverseCoefficients = params.inverseCoefficients;
|
|
1885
|
+
}
|
|
1886
|
+
DeviceInfo.Viewers = Viewers;
|
|
1887
|
+
var format = 1;
|
|
1888
|
+
var last_updated = "2018-02-20T22:55:10Z";
|
|
1889
|
+
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}];
|
|
1890
|
+
var DPDB_CACHE = {
|
|
1891
|
+
format: format,
|
|
1892
|
+
last_updated: last_updated,
|
|
1893
|
+
devices: devices
|
|
1894
|
+
};
|
|
1895
|
+
function Dpdb(url, onDeviceParamsUpdated) {
|
|
1896
|
+
this.dpdb = DPDB_CACHE;
|
|
1897
|
+
this.recalculateDeviceParams_();
|
|
1898
|
+
if (url) {
|
|
1899
|
+
this.onDeviceParamsUpdated = onDeviceParamsUpdated;
|
|
1900
|
+
var xhr = new XMLHttpRequest();
|
|
1901
|
+
var obj = this;
|
|
1902
|
+
xhr.open('GET', url, true);
|
|
1903
|
+
xhr.addEventListener('load', function () {
|
|
1904
|
+
obj.loading = false;
|
|
1905
|
+
if (xhr.status >= 200 && xhr.status <= 299) {
|
|
1906
|
+
obj.dpdb = JSON.parse(xhr.response);
|
|
1907
|
+
obj.recalculateDeviceParams_();
|
|
1908
|
+
} else {
|
|
1909
|
+
console.error('Error loading online DPDB!');
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
xhr.send();
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
Dpdb.prototype.getDeviceParams = function () {
|
|
1916
|
+
return this.deviceParams;
|
|
1917
|
+
};
|
|
1918
|
+
Dpdb.prototype.recalculateDeviceParams_ = function () {
|
|
1919
|
+
var newDeviceParams = this.calcDeviceParams_();
|
|
1920
|
+
if (newDeviceParams) {
|
|
1921
|
+
this.deviceParams = newDeviceParams;
|
|
1922
|
+
if (this.onDeviceParamsUpdated) {
|
|
1923
|
+
this.onDeviceParamsUpdated(this.deviceParams);
|
|
1924
|
+
}
|
|
1925
|
+
} else {
|
|
1926
|
+
console.error('Failed to recalculate device parameters.');
|
|
1927
|
+
}
|
|
1928
|
+
};
|
|
1929
|
+
Dpdb.prototype.calcDeviceParams_ = function () {
|
|
1930
|
+
var db = this.dpdb;
|
|
1931
|
+
if (!db) {
|
|
1932
|
+
console.error('DPDB not available.');
|
|
1933
|
+
return null;
|
|
1934
|
+
}
|
|
1935
|
+
if (db.format != 1) {
|
|
1936
|
+
console.error('DPDB has unexpected format version.');
|
|
1937
|
+
return null;
|
|
1938
|
+
}
|
|
1939
|
+
if (!db.devices || !db.devices.length) {
|
|
1940
|
+
console.error('DPDB does not have a devices section.');
|
|
1941
|
+
return null;
|
|
1942
|
+
}
|
|
1943
|
+
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
1944
|
+
var width = getScreenWidth();
|
|
1945
|
+
var height = getScreenHeight();
|
|
1946
|
+
if (!db.devices) {
|
|
1947
|
+
console.error('DPDB has no devices section.');
|
|
1948
|
+
return null;
|
|
1949
|
+
}
|
|
1950
|
+
for (var i = 0; i < db.devices.length; i++) {
|
|
1951
|
+
var device = db.devices[i];
|
|
1952
|
+
if (!device.rules) {
|
|
1953
|
+
console.warn('Device[' + i + '] has no rules section.');
|
|
1954
|
+
continue;
|
|
1955
|
+
}
|
|
1956
|
+
if (device.type != 'ios' && device.type != 'android') {
|
|
1957
|
+
console.warn('Device[' + i + '] has invalid type.');
|
|
1958
|
+
continue;
|
|
1959
|
+
}
|
|
1960
|
+
if (isIOS() != (device.type == 'ios')) continue;
|
|
1961
|
+
var matched = false;
|
|
1962
|
+
for (var j = 0; j < device.rules.length; j++) {
|
|
1963
|
+
var rule = device.rules[j];
|
|
1964
|
+
if (this.matchRule_(rule, userAgent, width, height)) {
|
|
1965
|
+
matched = true;
|
|
1966
|
+
break;
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
if (!matched) continue;
|
|
1970
|
+
var xdpi = device.dpi[0] || device.dpi;
|
|
1971
|
+
var ydpi = device.dpi[1] || device.dpi;
|
|
1972
|
+
return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw });
|
|
1973
|
+
}
|
|
1974
|
+
console.warn('No DPDB device match.');
|
|
1975
|
+
return null;
|
|
1976
|
+
};
|
|
1977
|
+
Dpdb.prototype.matchRule_ = function (rule, ua, screenWidth, screenHeight) {
|
|
1978
|
+
if (!rule.ua && !rule.res) return false;
|
|
1979
|
+
if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
|
|
1980
|
+
if (rule.res) {
|
|
1981
|
+
if (!rule.res[0] || !rule.res[1]) return false;
|
|
1982
|
+
var resX = rule.res[0];
|
|
1983
|
+
var resY = rule.res[1];
|
|
1984
|
+
if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) {
|
|
1985
|
+
return false;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
return true;
|
|
1989
|
+
};
|
|
1990
|
+
function DeviceParams(params) {
|
|
1991
|
+
this.xdpi = params.xdpi;
|
|
1992
|
+
this.ydpi = params.ydpi;
|
|
1993
|
+
this.bevelMm = params.bevelMm;
|
|
1994
|
+
}
|
|
1995
|
+
function SensorSample(sample, timestampS) {
|
|
1996
|
+
this.set(sample, timestampS);
|
|
1997
|
+
}
|
|
1998
|
+
SensorSample.prototype.set = function (sample, timestampS) {
|
|
1999
|
+
this.sample = sample;
|
|
2000
|
+
this.timestampS = timestampS;
|
|
2001
|
+
};
|
|
2002
|
+
SensorSample.prototype.copy = function (sensorSample) {
|
|
2003
|
+
this.set(sensorSample.sample, sensorSample.timestampS);
|
|
2004
|
+
};
|
|
2005
|
+
function ComplementaryFilter(kFilter, isDebug) {
|
|
2006
|
+
this.kFilter = kFilter;
|
|
2007
|
+
this.isDebug = isDebug;
|
|
2008
|
+
this.currentAccelMeasurement = new SensorSample();
|
|
2009
|
+
this.currentGyroMeasurement = new SensorSample();
|
|
2010
|
+
this.previousGyroMeasurement = new SensorSample();
|
|
2011
|
+
if (isIOS()) {
|
|
2012
|
+
this.filterQ = new Quaternion(-1, 0, 0, 1);
|
|
2013
|
+
} else {
|
|
2014
|
+
this.filterQ = new Quaternion(1, 0, 0, 1);
|
|
2015
|
+
}
|
|
2016
|
+
this.previousFilterQ = new Quaternion();
|
|
2017
|
+
this.previousFilterQ.copy(this.filterQ);
|
|
2018
|
+
this.accelQ = new Quaternion();
|
|
2019
|
+
this.isOrientationInitialized = false;
|
|
2020
|
+
this.estimatedGravity = new Vector3();
|
|
2021
|
+
this.measuredGravity = new Vector3();
|
|
2022
|
+
this.gyroIntegralQ = new Quaternion();
|
|
2023
|
+
}
|
|
2024
|
+
ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) {
|
|
2025
|
+
this.currentAccelMeasurement.set(vector, timestampS);
|
|
2026
|
+
};
|
|
2027
|
+
ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) {
|
|
2028
|
+
this.currentGyroMeasurement.set(vector, timestampS);
|
|
2029
|
+
var deltaT = timestampS - this.previousGyroMeasurement.timestampS;
|
|
2030
|
+
if (isTimestampDeltaValid(deltaT)) {
|
|
2031
|
+
this.run_();
|
|
2032
|
+
}
|
|
2033
|
+
this.previousGyroMeasurement.copy(this.currentGyroMeasurement);
|
|
2034
|
+
};
|
|
2035
|
+
ComplementaryFilter.prototype.run_ = function () {
|
|
2036
|
+
if (!this.isOrientationInitialized) {
|
|
2037
|
+
this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample);
|
|
2038
|
+
this.previousFilterQ.copy(this.accelQ);
|
|
2039
|
+
this.isOrientationInitialized = true;
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS;
|
|
2043
|
+
var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);
|
|
2044
|
+
this.gyroIntegralQ.multiply(gyroDeltaQ);
|
|
2045
|
+
this.filterQ.copy(this.previousFilterQ);
|
|
2046
|
+
this.filterQ.multiply(gyroDeltaQ);
|
|
2047
|
+
var invFilterQ = new Quaternion();
|
|
2048
|
+
invFilterQ.copy(this.filterQ);
|
|
2049
|
+
invFilterQ.inverse();
|
|
2050
|
+
this.estimatedGravity.set(0, 0, -1);
|
|
2051
|
+
this.estimatedGravity.applyQuaternion(invFilterQ);
|
|
2052
|
+
this.estimatedGravity.normalize();
|
|
2053
|
+
this.measuredGravity.copy(this.currentAccelMeasurement.sample);
|
|
2054
|
+
this.measuredGravity.normalize();
|
|
2055
|
+
var deltaQ = new Quaternion();
|
|
2056
|
+
deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);
|
|
2057
|
+
deltaQ.inverse();
|
|
2058
|
+
if (this.isDebug) {
|
|
2059
|
+
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));
|
|
2060
|
+
}
|
|
2061
|
+
var targetQ = new Quaternion();
|
|
2062
|
+
targetQ.copy(this.filterQ);
|
|
2063
|
+
targetQ.multiply(deltaQ);
|
|
2064
|
+
this.filterQ.slerp(targetQ, 1 - this.kFilter);
|
|
2065
|
+
this.previousFilterQ.copy(this.filterQ);
|
|
2066
|
+
};
|
|
2067
|
+
ComplementaryFilter.prototype.getOrientation = function () {
|
|
2068
|
+
return this.filterQ;
|
|
2069
|
+
};
|
|
2070
|
+
ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) {
|
|
2071
|
+
var normAccel = new Vector3();
|
|
2072
|
+
normAccel.copy(accel);
|
|
2073
|
+
normAccel.normalize();
|
|
2074
|
+
var quat = new Quaternion();
|
|
2075
|
+
quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel);
|
|
2076
|
+
quat.inverse();
|
|
2077
|
+
return quat;
|
|
2078
|
+
};
|
|
2079
|
+
ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) {
|
|
2080
|
+
var quat = new Quaternion();
|
|
2081
|
+
var axis = new Vector3();
|
|
2082
|
+
axis.copy(gyro);
|
|
2083
|
+
axis.normalize();
|
|
2084
|
+
quat.setFromAxisAngle(axis, gyro.length() * dt);
|
|
2085
|
+
return quat;
|
|
2086
|
+
};
|
|
2087
|
+
function PosePredictor(predictionTimeS, isDebug) {
|
|
2088
|
+
this.predictionTimeS = predictionTimeS;
|
|
2089
|
+
this.isDebug = isDebug;
|
|
2090
|
+
this.previousQ = new Quaternion();
|
|
2091
|
+
this.previousTimestampS = null;
|
|
2092
|
+
this.deltaQ = new Quaternion();
|
|
2093
|
+
this.outQ = new Quaternion();
|
|
2094
|
+
}
|
|
2095
|
+
PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) {
|
|
2096
|
+
if (!this.previousTimestampS) {
|
|
2097
|
+
this.previousQ.copy(currentQ);
|
|
2098
|
+
this.previousTimestampS = timestampS;
|
|
2099
|
+
return currentQ;
|
|
2100
|
+
}
|
|
2101
|
+
var axis = new Vector3();
|
|
2102
|
+
axis.copy(gyro);
|
|
2103
|
+
axis.normalize();
|
|
2104
|
+
var angularSpeed = gyro.length();
|
|
2105
|
+
if (angularSpeed < degToRad * 20) {
|
|
2106
|
+
if (this.isDebug) {
|
|
2107
|
+
console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1));
|
|
2108
|
+
}
|
|
2109
|
+
this.outQ.copy(currentQ);
|
|
2110
|
+
this.previousQ.copy(currentQ);
|
|
2111
|
+
return this.outQ;
|
|
2112
|
+
}
|
|
2113
|
+
var predictAngle = angularSpeed * this.predictionTimeS;
|
|
2114
|
+
this.deltaQ.setFromAxisAngle(axis, predictAngle);
|
|
2115
|
+
this.outQ.copy(this.previousQ);
|
|
2116
|
+
this.outQ.multiply(this.deltaQ);
|
|
2117
|
+
this.previousQ.copy(currentQ);
|
|
2118
|
+
this.previousTimestampS = timestampS;
|
|
2119
|
+
return this.outQ;
|
|
2120
|
+
};
|
|
2121
|
+
function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) {
|
|
2122
|
+
this.yawOnly = yawOnly;
|
|
2123
|
+
this.accelerometer = new Vector3();
|
|
2124
|
+
this.gyroscope = new Vector3();
|
|
2125
|
+
this.filter = new ComplementaryFilter(kFilter, isDebug);
|
|
2126
|
+
this.posePredictor = new PosePredictor(predictionTime, isDebug);
|
|
2127
|
+
this.isFirefoxAndroid = isFirefoxAndroid();
|
|
2128
|
+
this.isIOS = isIOS();
|
|
2129
|
+
var chromeVersion = getChromeVersion();
|
|
2130
|
+
this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66;
|
|
2131
|
+
this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion();
|
|
2132
|
+
this.filterToWorldQ = new Quaternion();
|
|
2133
|
+
if (isIOS()) {
|
|
2134
|
+
this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);
|
|
2135
|
+
} else {
|
|
2136
|
+
this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
|
|
2137
|
+
}
|
|
2138
|
+
this.inverseWorldToScreenQ = new Quaternion();
|
|
2139
|
+
this.worldToScreenQ = new Quaternion();
|
|
2140
|
+
this.originalPoseAdjustQ = new Quaternion();
|
|
2141
|
+
this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180);
|
|
2142
|
+
this.setScreenTransform_();
|
|
2143
|
+
if (isLandscapeMode()) {
|
|
2144
|
+
this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);
|
|
2145
|
+
}
|
|
2146
|
+
this.resetQ = new Quaternion();
|
|
2147
|
+
this.orientationOut_ = new Float32Array(4);
|
|
2148
|
+
this.start();
|
|
2149
|
+
}
|
|
2150
|
+
FusionPoseSensor.prototype.getPosition = function () {
|
|
2151
|
+
return null;
|
|
2152
|
+
};
|
|
2153
|
+
FusionPoseSensor.prototype.getOrientation = function () {
|
|
2154
|
+
var orientation = void 0;
|
|
2155
|
+
if (this.isWithoutDeviceMotion && this._deviceOrientationQ) {
|
|
2156
|
+
this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () {
|
|
2157
|
+
var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0);
|
|
2158
|
+
var y = new Quaternion();
|
|
2159
|
+
if (window.orientation === -90) {
|
|
2160
|
+
y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2);
|
|
2161
|
+
} else {
|
|
2162
|
+
y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2);
|
|
2163
|
+
}
|
|
2164
|
+
return z.multiply(y);
|
|
2165
|
+
}();
|
|
2166
|
+
this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () {
|
|
2167
|
+
var q = new Quaternion();
|
|
2168
|
+
q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
|
|
2169
|
+
return q;
|
|
2170
|
+
}();
|
|
2171
|
+
orientation = this._deviceOrientationQ;
|
|
2172
|
+
var out = new Quaternion();
|
|
2173
|
+
out.copy(orientation);
|
|
2174
|
+
out.multiply(this.deviceOrientationFilterToWorldQ);
|
|
2175
|
+
out.multiply(this.resetQ);
|
|
2176
|
+
out.multiply(this.worldToScreenQ);
|
|
2177
|
+
out.multiplyQuaternions(this.deviceOrientationFixQ, out);
|
|
2178
|
+
if (this.yawOnly) {
|
|
2179
|
+
out.x = 0;
|
|
2180
|
+
out.z = 0;
|
|
2181
|
+
out.normalize();
|
|
2182
|
+
}
|
|
2183
|
+
this.orientationOut_[0] = out.x;
|
|
2184
|
+
this.orientationOut_[1] = out.y;
|
|
2185
|
+
this.orientationOut_[2] = out.z;
|
|
2186
|
+
this.orientationOut_[3] = out.w;
|
|
2187
|
+
return this.orientationOut_;
|
|
2188
|
+
} else {
|
|
2189
|
+
var filterOrientation = this.filter.getOrientation();
|
|
2190
|
+
orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS);
|
|
2191
|
+
}
|
|
2192
|
+
var out = new Quaternion();
|
|
2193
|
+
out.copy(this.filterToWorldQ);
|
|
2194
|
+
out.multiply(this.resetQ);
|
|
2195
|
+
out.multiply(orientation);
|
|
2196
|
+
out.multiply(this.worldToScreenQ);
|
|
2197
|
+
if (this.yawOnly) {
|
|
2198
|
+
out.x = 0;
|
|
2199
|
+
out.z = 0;
|
|
2200
|
+
out.normalize();
|
|
2201
|
+
}
|
|
2202
|
+
this.orientationOut_[0] = out.x;
|
|
2203
|
+
this.orientationOut_[1] = out.y;
|
|
2204
|
+
this.orientationOut_[2] = out.z;
|
|
2205
|
+
this.orientationOut_[3] = out.w;
|
|
2206
|
+
return this.orientationOut_;
|
|
2207
|
+
};
|
|
2208
|
+
FusionPoseSensor.prototype.resetPose = function () {
|
|
2209
|
+
this.resetQ.copy(this.filter.getOrientation());
|
|
2210
|
+
this.resetQ.x = 0;
|
|
2211
|
+
this.resetQ.y = 0;
|
|
2212
|
+
this.resetQ.z *= -1;
|
|
2213
|
+
this.resetQ.normalize();
|
|
2214
|
+
if (isLandscapeMode()) {
|
|
2215
|
+
this.resetQ.multiply(this.inverseWorldToScreenQ);
|
|
2216
|
+
}
|
|
2217
|
+
this.resetQ.multiply(this.originalPoseAdjustQ);
|
|
2218
|
+
};
|
|
2219
|
+
FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) {
|
|
2220
|
+
this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion();
|
|
2221
|
+
var alpha = e.alpha,
|
|
2222
|
+
beta = e.beta,
|
|
2223
|
+
gamma = e.gamma;
|
|
2224
|
+
alpha = (alpha || 0) * Math.PI / 180;
|
|
2225
|
+
beta = (beta || 0) * Math.PI / 180;
|
|
2226
|
+
gamma = (gamma || 0) * Math.PI / 180;
|
|
2227
|
+
this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma);
|
|
2228
|
+
};
|
|
2229
|
+
FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) {
|
|
2230
|
+
this.updateDeviceMotion_(deviceMotion);
|
|
2231
|
+
};
|
|
2232
|
+
FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) {
|
|
2233
|
+
var accGravity = deviceMotion.accelerationIncludingGravity;
|
|
2234
|
+
var rotRate = deviceMotion.rotationRate;
|
|
2235
|
+
var timestampS = deviceMotion.timeStamp / 1000;
|
|
2236
|
+
var deltaS = timestampS - this.previousTimestampS;
|
|
2237
|
+
if (deltaS < 0) {
|
|
2238
|
+
warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion');
|
|
2239
|
+
this.previousTimestampS = timestampS;
|
|
2240
|
+
return;
|
|
2241
|
+
} else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) {
|
|
2242
|
+
warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.');
|
|
2243
|
+
this.previousTimestampS = timestampS;
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
|
|
2247
|
+
if (isR7()) {
|
|
2248
|
+
this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma);
|
|
2249
|
+
} else {
|
|
2250
|
+
this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);
|
|
2251
|
+
}
|
|
2252
|
+
if (!this.isDeviceMotionInRadians) {
|
|
2253
|
+
this.gyroscope.multiplyScalar(Math.PI / 180);
|
|
2254
|
+
}
|
|
2255
|
+
this.filter.addAccelMeasurement(this.accelerometer, timestampS);
|
|
2256
|
+
this.filter.addGyroMeasurement(this.gyroscope, timestampS);
|
|
2257
|
+
this.previousTimestampS = timestampS;
|
|
2258
|
+
};
|
|
2259
|
+
FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) {
|
|
2260
|
+
this.setScreenTransform_();
|
|
2261
|
+
};
|
|
2262
|
+
FusionPoseSensor.prototype.onMessage_ = function (event) {
|
|
2263
|
+
var message = event.data;
|
|
2264
|
+
if (!message || !message.type) {
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
var type = message.type.toLowerCase();
|
|
2268
|
+
if (type !== 'devicemotion') {
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2271
|
+
this.updateDeviceMotion_(message.deviceMotionEvent);
|
|
2272
|
+
};
|
|
2273
|
+
FusionPoseSensor.prototype.setScreenTransform_ = function () {
|
|
2274
|
+
this.worldToScreenQ.set(0, 0, 0, 1);
|
|
2275
|
+
switch (window.orientation) {
|
|
2276
|
+
case 0:
|
|
2277
|
+
break;
|
|
2278
|
+
case 90:
|
|
2279
|
+
this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2);
|
|
2280
|
+
break;
|
|
2281
|
+
case -90:
|
|
2282
|
+
this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2);
|
|
2283
|
+
break;
|
|
2284
|
+
case 180:
|
|
2285
|
+
break;
|
|
2286
|
+
}
|
|
2287
|
+
this.inverseWorldToScreenQ.copy(this.worldToScreenQ);
|
|
2288
|
+
this.inverseWorldToScreenQ.inverse();
|
|
2289
|
+
};
|
|
2290
|
+
FusionPoseSensor.prototype.start = function () {
|
|
2291
|
+
this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this);
|
|
2292
|
+
this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this);
|
|
2293
|
+
this.onMessageCallback_ = this.onMessage_.bind(this);
|
|
2294
|
+
this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this);
|
|
2295
|
+
if (isIOS() && isInsideCrossOriginIFrame()) {
|
|
2296
|
+
window.addEventListener('message', this.onMessageCallback_);
|
|
2297
|
+
}
|
|
2298
|
+
window.addEventListener('orientationchange', this.onOrientationChangeCallback_);
|
|
2299
|
+
if (this.isWithoutDeviceMotion) {
|
|
2300
|
+
window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_);
|
|
2301
|
+
} else {
|
|
2302
|
+
window.addEventListener('devicemotion', this.onDeviceMotionCallback_);
|
|
2303
|
+
}
|
|
2304
|
+
};
|
|
2305
|
+
FusionPoseSensor.prototype.stop = function () {
|
|
2306
|
+
window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);
|
|
2307
|
+
window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_);
|
|
2308
|
+
window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);
|
|
2309
|
+
window.removeEventListener('message', this.onMessageCallback_);
|
|
2310
|
+
};
|
|
2311
|
+
var SENSOR_FREQUENCY = 60;
|
|
2312
|
+
var X_AXIS = new Vector3(1, 0, 0);
|
|
2313
|
+
var Z_AXIS = new Vector3(0, 0, 1);
|
|
2314
|
+
var SENSOR_TO_VR = new Quaternion();
|
|
2315
|
+
SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2);
|
|
2316
|
+
SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2));
|
|
2317
|
+
var PoseSensor = function () {
|
|
2318
|
+
function PoseSensor(config) {
|
|
2319
|
+
classCallCheck(this, PoseSensor);
|
|
2320
|
+
this.config = config;
|
|
2321
|
+
this.sensor = null;
|
|
2322
|
+
this.fusionSensor = null;
|
|
2323
|
+
this._out = new Float32Array(4);
|
|
2324
|
+
this.api = null;
|
|
2325
|
+
this.errors = [];
|
|
2326
|
+
this._sensorQ = new Quaternion();
|
|
2327
|
+
this._outQ = new Quaternion();
|
|
2328
|
+
this._onSensorRead = this._onSensorRead.bind(this);
|
|
2329
|
+
this._onSensorError = this._onSensorError.bind(this);
|
|
2330
|
+
this.init();
|
|
2331
|
+
}
|
|
2332
|
+
createClass(PoseSensor, [{
|
|
2333
|
+
key: 'init',
|
|
2334
|
+
value: function init() {
|
|
2335
|
+
var sensor = null;
|
|
2336
|
+
try {
|
|
2337
|
+
sensor = new RelativeOrientationSensor({
|
|
2338
|
+
frequency: SENSOR_FREQUENCY,
|
|
2339
|
+
referenceFrame: 'screen'
|
|
2340
|
+
});
|
|
2341
|
+
sensor.addEventListener('error', this._onSensorError);
|
|
2342
|
+
} catch (error) {
|
|
2343
|
+
this.errors.push(error);
|
|
2344
|
+
if (error.name === 'SecurityError') {
|
|
2345
|
+
console.error('Cannot construct sensors due to the Feature Policy');
|
|
2346
|
+
console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.');
|
|
2347
|
+
this.useDeviceMotion();
|
|
2348
|
+
} else if (error.name === 'ReferenceError') {
|
|
2349
|
+
this.useDeviceMotion();
|
|
2350
|
+
} else {
|
|
2351
|
+
console.error(error);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
if (sensor) {
|
|
2355
|
+
this.api = 'sensor';
|
|
2356
|
+
this.sensor = sensor;
|
|
2357
|
+
this.sensor.addEventListener('reading', this._onSensorRead);
|
|
2358
|
+
this.sensor.start();
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
}, {
|
|
2362
|
+
key: 'useDeviceMotion',
|
|
2363
|
+
value: function useDeviceMotion() {
|
|
2364
|
+
this.api = 'devicemotion';
|
|
2365
|
+
this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG);
|
|
2366
|
+
if (this.sensor) {
|
|
2367
|
+
this.sensor.removeEventListener('reading', this._onSensorRead);
|
|
2368
|
+
this.sensor.removeEventListener('error', this._onSensorError);
|
|
2369
|
+
this.sensor = null;
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
}, {
|
|
2373
|
+
key: 'getOrientation',
|
|
2374
|
+
value: function getOrientation() {
|
|
2375
|
+
if (this.fusionSensor) {
|
|
2376
|
+
return this.fusionSensor.getOrientation();
|
|
2377
|
+
}
|
|
2378
|
+
if (!this.sensor || !this.sensor.quaternion) {
|
|
2379
|
+
this._out[0] = this._out[1] = this._out[2] = 0;
|
|
2380
|
+
this._out[3] = 1;
|
|
2381
|
+
return this._out;
|
|
2382
|
+
}
|
|
2383
|
+
var q = this.sensor.quaternion;
|
|
2384
|
+
this._sensorQ.set(q[0], q[1], q[2], q[3]);
|
|
2385
|
+
var out = this._outQ;
|
|
2386
|
+
out.copy(SENSOR_TO_VR);
|
|
2387
|
+
out.multiply(this._sensorQ);
|
|
2388
|
+
if (this.config.YAW_ONLY) {
|
|
2389
|
+
out.x = out.z = 0;
|
|
2390
|
+
out.normalize();
|
|
2391
|
+
}
|
|
2392
|
+
this._out[0] = out.x;
|
|
2393
|
+
this._out[1] = out.y;
|
|
2394
|
+
this._out[2] = out.z;
|
|
2395
|
+
this._out[3] = out.w;
|
|
2396
|
+
return this._out;
|
|
2397
|
+
}
|
|
2398
|
+
}, {
|
|
2399
|
+
key: '_onSensorError',
|
|
2400
|
+
value: function _onSensorError(event) {
|
|
2401
|
+
this.errors.push(event.error);
|
|
2402
|
+
if (event.error.name === 'NotAllowedError') {
|
|
2403
|
+
console.error('Permission to access sensor was denied');
|
|
2404
|
+
} else if (event.error.name === 'NotReadableError') {
|
|
2405
|
+
console.error('Sensor could not be read');
|
|
2406
|
+
} else {
|
|
2407
|
+
console.error(event.error);
|
|
2408
|
+
}
|
|
2409
|
+
this.useDeviceMotion();
|
|
2410
|
+
}
|
|
2411
|
+
}, {
|
|
2412
|
+
key: '_onSensorRead',
|
|
2413
|
+
value: function _onSensorRead() {}
|
|
2414
|
+
}]);
|
|
2415
|
+
return PoseSensor;
|
|
2416
|
+
}();
|
|
2417
|
+
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+';
|
|
2418
|
+
function RotateInstructions() {
|
|
2419
|
+
this.loadIcon_();
|
|
2420
|
+
var overlay = document.createElement('div');
|
|
2421
|
+
var s = overlay.style;
|
|
2422
|
+
s.position = 'fixed';
|
|
2423
|
+
s.top = 0;
|
|
2424
|
+
s.right = 0;
|
|
2425
|
+
s.bottom = 0;
|
|
2426
|
+
s.left = 0;
|
|
2427
|
+
s.backgroundColor = 'gray';
|
|
2428
|
+
s.fontFamily = 'sans-serif';
|
|
2429
|
+
s.zIndex = 1000000;
|
|
2430
|
+
var img = document.createElement('img');
|
|
2431
|
+
img.src = this.icon;
|
|
2432
|
+
var s = img.style;
|
|
2433
|
+
s.marginLeft = '25%';
|
|
2434
|
+
s.marginTop = '25%';
|
|
2435
|
+
s.width = '50%';
|
|
2436
|
+
overlay.appendChild(img);
|
|
2437
|
+
var text = document.createElement('div');
|
|
2438
|
+
var s = text.style;
|
|
2439
|
+
s.textAlign = 'center';
|
|
2440
|
+
s.fontSize = '16px';
|
|
2441
|
+
s.lineHeight = '24px';
|
|
2442
|
+
s.margin = '24px 25%';
|
|
2443
|
+
s.width = '50%';
|
|
2444
|
+
text.innerHTML = 'Place your phone into your Cardboard viewer.';
|
|
2445
|
+
overlay.appendChild(text);
|
|
2446
|
+
var snackbar = document.createElement('div');
|
|
2447
|
+
var s = snackbar.style;
|
|
2448
|
+
s.backgroundColor = '#CFD8DC';
|
|
2449
|
+
s.position = 'fixed';
|
|
2450
|
+
s.bottom = 0;
|
|
2451
|
+
s.width = '100%';
|
|
2452
|
+
s.height = '48px';
|
|
2453
|
+
s.padding = '14px 24px';
|
|
2454
|
+
s.boxSizing = 'border-box';
|
|
2455
|
+
s.color = '#656A6B';
|
|
2456
|
+
overlay.appendChild(snackbar);
|
|
2457
|
+
var snackbarText = document.createElement('div');
|
|
2458
|
+
snackbarText.style.float = 'left';
|
|
2459
|
+
snackbarText.innerHTML = 'No Cardboard viewer?';
|
|
2460
|
+
var snackbarButton = document.createElement('a');
|
|
2461
|
+
snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/';
|
|
2462
|
+
snackbarButton.innerHTML = 'get one';
|
|
2463
|
+
snackbarButton.target = '_blank';
|
|
2464
|
+
var s = snackbarButton.style;
|
|
2465
|
+
s.float = 'right';
|
|
2466
|
+
s.fontWeight = 600;
|
|
2467
|
+
s.textTransform = 'uppercase';
|
|
2468
|
+
s.borderLeft = '1px solid gray';
|
|
2469
|
+
s.paddingLeft = '24px';
|
|
2470
|
+
s.textDecoration = 'none';
|
|
2471
|
+
s.color = '#656A6B';
|
|
2472
|
+
snackbar.appendChild(snackbarText);
|
|
2473
|
+
snackbar.appendChild(snackbarButton);
|
|
2474
|
+
this.overlay = overlay;
|
|
2475
|
+
this.text = text;
|
|
2476
|
+
this.hide();
|
|
2477
|
+
}
|
|
2478
|
+
RotateInstructions.prototype.show = function (parent) {
|
|
2479
|
+
if (!parent && !this.overlay.parentElement) {
|
|
2480
|
+
document.body.appendChild(this.overlay);
|
|
2481
|
+
} else if (parent) {
|
|
2482
|
+
if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay);
|
|
2483
|
+
parent.appendChild(this.overlay);
|
|
2484
|
+
}
|
|
2485
|
+
this.overlay.style.display = 'block';
|
|
2486
|
+
var img = this.overlay.querySelector('img');
|
|
2487
|
+
var s = img.style;
|
|
2488
|
+
if (isLandscapeMode()) {
|
|
2489
|
+
s.width = '20%';
|
|
2490
|
+
s.marginLeft = '40%';
|
|
2491
|
+
s.marginTop = '3%';
|
|
2492
|
+
} else {
|
|
2493
|
+
s.width = '50%';
|
|
2494
|
+
s.marginLeft = '25%';
|
|
2495
|
+
s.marginTop = '25%';
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
RotateInstructions.prototype.hide = function () {
|
|
2499
|
+
this.overlay.style.display = 'none';
|
|
2500
|
+
};
|
|
2501
|
+
RotateInstructions.prototype.showTemporarily = function (ms, parent) {
|
|
2502
|
+
this.show(parent);
|
|
2503
|
+
this.timer = setTimeout(this.hide.bind(this), ms);
|
|
2504
|
+
};
|
|
2505
|
+
RotateInstructions.prototype.disableShowTemporarily = function () {
|
|
2506
|
+
clearTimeout(this.timer);
|
|
2507
|
+
};
|
|
2508
|
+
RotateInstructions.prototype.update = function () {
|
|
2509
|
+
this.disableShowTemporarily();
|
|
2510
|
+
if (!isLandscapeMode() && isMobile()) {
|
|
2511
|
+
this.show();
|
|
2512
|
+
} else {
|
|
2513
|
+
this.hide();
|
|
2514
|
+
}
|
|
2515
|
+
};
|
|
2516
|
+
RotateInstructions.prototype.loadIcon_ = function () {
|
|
2517
|
+
this.icon = base64('image/svg+xml', rotateInstructionsAsset);
|
|
2518
|
+
};
|
|
2519
|
+
var DEFAULT_VIEWER = 'CardboardV1';
|
|
2520
|
+
var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';
|
|
2521
|
+
var CLASS_NAME = 'webvr-polyfill-viewer-selector';
|
|
2522
|
+
function ViewerSelector(defaultViewer) {
|
|
2523
|
+
try {
|
|
2524
|
+
this.selectedKey = localStorage.getItem(VIEWER_KEY);
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
console.error('Failed to load viewer profile: %s', error);
|
|
2527
|
+
}
|
|
2528
|
+
if (!this.selectedKey) {
|
|
2529
|
+
this.selectedKey = defaultViewer || DEFAULT_VIEWER;
|
|
2530
|
+
}
|
|
2531
|
+
this.dialog = this.createDialog_(DeviceInfo.Viewers);
|
|
2532
|
+
this.root = null;
|
|
2533
|
+
this.onChangeCallbacks_ = [];
|
|
2534
|
+
}
|
|
2535
|
+
ViewerSelector.prototype.show = function (root) {
|
|
2536
|
+
this.root = root;
|
|
2537
|
+
root.appendChild(this.dialog);
|
|
2538
|
+
var selected = this.dialog.querySelector('#' + this.selectedKey);
|
|
2539
|
+
selected.checked = true;
|
|
2540
|
+
this.dialog.style.display = 'block';
|
|
2541
|
+
};
|
|
2542
|
+
ViewerSelector.prototype.hide = function () {
|
|
2543
|
+
if (this.root && this.root.contains(this.dialog)) {
|
|
2544
|
+
this.root.removeChild(this.dialog);
|
|
2545
|
+
}
|
|
2546
|
+
this.dialog.style.display = 'none';
|
|
2547
|
+
};
|
|
2548
|
+
ViewerSelector.prototype.getCurrentViewer = function () {
|
|
2549
|
+
return DeviceInfo.Viewers[this.selectedKey];
|
|
2550
|
+
};
|
|
2551
|
+
ViewerSelector.prototype.getSelectedKey_ = function () {
|
|
2552
|
+
var input = this.dialog.querySelector('input[name=field]:checked');
|
|
2553
|
+
if (input) {
|
|
2554
|
+
return input.id;
|
|
2555
|
+
}
|
|
2556
|
+
return null;
|
|
2557
|
+
};
|
|
2558
|
+
ViewerSelector.prototype.onChange = function (cb) {
|
|
2559
|
+
this.onChangeCallbacks_.push(cb);
|
|
2560
|
+
};
|
|
2561
|
+
ViewerSelector.prototype.fireOnChange_ = function (viewer) {
|
|
2562
|
+
for (var i = 0; i < this.onChangeCallbacks_.length; i++) {
|
|
2563
|
+
this.onChangeCallbacks_[i](viewer);
|
|
2564
|
+
}
|
|
2565
|
+
};
|
|
2566
|
+
ViewerSelector.prototype.onSave_ = function () {
|
|
2567
|
+
this.selectedKey = this.getSelectedKey_();
|
|
2568
|
+
if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) {
|
|
2569
|
+
console.error('ViewerSelector.onSave_: this should never happen!');
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]);
|
|
2573
|
+
try {
|
|
2574
|
+
localStorage.setItem(VIEWER_KEY, this.selectedKey);
|
|
2575
|
+
} catch (error) {
|
|
2576
|
+
console.error('Failed to save viewer profile: %s', error);
|
|
2577
|
+
}
|
|
2578
|
+
this.hide();
|
|
2579
|
+
};
|
|
2580
|
+
ViewerSelector.prototype.createDialog_ = function (options) {
|
|
2581
|
+
var container = document.createElement('div');
|
|
2582
|
+
container.classList.add(CLASS_NAME);
|
|
2583
|
+
container.style.display = 'none';
|
|
2584
|
+
var overlay = document.createElement('div');
|
|
2585
|
+
var s = overlay.style;
|
|
2586
|
+
s.position = 'fixed';
|
|
2587
|
+
s.left = 0;
|
|
2588
|
+
s.top = 0;
|
|
2589
|
+
s.width = '100%';
|
|
2590
|
+
s.height = '100%';
|
|
2591
|
+
s.background = 'rgba(0, 0, 0, 0.3)';
|
|
2592
|
+
overlay.addEventListener('click', this.hide.bind(this));
|
|
2593
|
+
var width = 280;
|
|
2594
|
+
var dialog = document.createElement('div');
|
|
2595
|
+
var s = dialog.style;
|
|
2596
|
+
s.boxSizing = 'border-box';
|
|
2597
|
+
s.position = 'fixed';
|
|
2598
|
+
s.top = '24px';
|
|
2599
|
+
s.left = '50%';
|
|
2600
|
+
s.marginLeft = -width / 2 + 'px';
|
|
2601
|
+
s.width = width + 'px';
|
|
2602
|
+
s.padding = '24px';
|
|
2603
|
+
s.overflow = 'hidden';
|
|
2604
|
+
s.background = '#fafafa';
|
|
2605
|
+
s.fontFamily = "'Roboto', sans-serif";
|
|
2606
|
+
s.boxShadow = '0px 5px 20px #666';
|
|
2607
|
+
dialog.appendChild(this.createH1_('Select your viewer'));
|
|
2608
|
+
for (var id in options) {
|
|
2609
|
+
dialog.appendChild(this.createChoice_(id, options[id].label));
|
|
2610
|
+
}
|
|
2611
|
+
dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this)));
|
|
2612
|
+
container.appendChild(overlay);
|
|
2613
|
+
container.appendChild(dialog);
|
|
2614
|
+
return container;
|
|
2615
|
+
};
|
|
2616
|
+
ViewerSelector.prototype.createH1_ = function (name) {
|
|
2617
|
+
var h1 = document.createElement('h1');
|
|
2618
|
+
var s = h1.style;
|
|
2619
|
+
s.color = 'black';
|
|
2620
|
+
s.fontSize = '20px';
|
|
2621
|
+
s.fontWeight = 'bold';
|
|
2622
|
+
s.marginTop = 0;
|
|
2623
|
+
s.marginBottom = '24px';
|
|
2624
|
+
h1.innerHTML = name;
|
|
2625
|
+
return h1;
|
|
2626
|
+
};
|
|
2627
|
+
ViewerSelector.prototype.createChoice_ = function (id, name) {
|
|
2628
|
+
var div = document.createElement('div');
|
|
2629
|
+
div.style.marginTop = '8px';
|
|
2630
|
+
div.style.color = 'black';
|
|
2631
|
+
var input = document.createElement('input');
|
|
2632
|
+
input.style.fontSize = '30px';
|
|
2633
|
+
input.setAttribute('id', id);
|
|
2634
|
+
input.setAttribute('type', 'radio');
|
|
2635
|
+
input.setAttribute('value', id);
|
|
2636
|
+
input.setAttribute('name', 'field');
|
|
2637
|
+
var label = document.createElement('label');
|
|
2638
|
+
label.style.marginLeft = '4px';
|
|
2639
|
+
label.setAttribute('for', id);
|
|
2640
|
+
label.innerHTML = name;
|
|
2641
|
+
div.appendChild(input);
|
|
2642
|
+
div.appendChild(label);
|
|
2643
|
+
return div;
|
|
2644
|
+
};
|
|
2645
|
+
ViewerSelector.prototype.createButton_ = function (label, onclick) {
|
|
2646
|
+
var button = document.createElement('button');
|
|
2647
|
+
button.innerHTML = label;
|
|
2648
|
+
var s = button.style;
|
|
2649
|
+
s.float = 'right';
|
|
2650
|
+
s.textTransform = 'uppercase';
|
|
2651
|
+
s.color = '#1094f7';
|
|
2652
|
+
s.fontSize = '14px';
|
|
2653
|
+
s.letterSpacing = 0;
|
|
2654
|
+
s.border = 0;
|
|
2655
|
+
s.background = 'none';
|
|
2656
|
+
s.marginTop = '16px';
|
|
2657
|
+
button.addEventListener('click', onclick);
|
|
2658
|
+
return button;
|
|
2659
|
+
};
|
|
2660
|
+
var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
|
|
2661
|
+
function unwrapExports$$1 (x) {
|
|
2662
|
+
return x && x.__esModule ? x['default'] : x;
|
|
2663
|
+
}
|
|
2664
|
+
function createCommonjsModule$$1(fn, module) {
|
|
2665
|
+
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
|
2666
|
+
}
|
|
2667
|
+
var NoSleep = createCommonjsModule$$1(function (module, exports) {
|
|
2668
|
+
(function webpackUniversalModuleDefinition(root, factory) {
|
|
2669
|
+
module.exports = factory();
|
|
2670
|
+
})(commonjsGlobal$$1, function() {
|
|
2671
|
+
return (function(modules) {
|
|
2672
|
+
var installedModules = {};
|
|
2673
|
+
function __webpack_require__(moduleId) {
|
|
2674
|
+
if(installedModules[moduleId]) {
|
|
2675
|
+
return installedModules[moduleId].exports;
|
|
2676
|
+
}
|
|
2677
|
+
var module = installedModules[moduleId] = {
|
|
2678
|
+
i: moduleId,
|
|
2679
|
+
l: false,
|
|
2680
|
+
exports: {}
|
|
2681
|
+
};
|
|
2682
|
+
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
2683
|
+
module.l = true;
|
|
2684
|
+
return module.exports;
|
|
2685
|
+
}
|
|
2686
|
+
__webpack_require__.m = modules;
|
|
2687
|
+
__webpack_require__.c = installedModules;
|
|
2688
|
+
__webpack_require__.d = function(exports, name, getter) {
|
|
2689
|
+
if(!__webpack_require__.o(exports, name)) {
|
|
2690
|
+
Object.defineProperty(exports, name, {
|
|
2691
|
+
configurable: false,
|
|
2692
|
+
enumerable: true,
|
|
2693
|
+
get: getter
|
|
2694
|
+
});
|
|
2695
|
+
}
|
|
2696
|
+
};
|
|
2697
|
+
__webpack_require__.n = function(module) {
|
|
2698
|
+
var getter = module && module.__esModule ?
|
|
2699
|
+
function getDefault() { return module['default']; } :
|
|
2700
|
+
function getModuleExports() { return module; };
|
|
2701
|
+
__webpack_require__.d(getter, 'a', getter);
|
|
2702
|
+
return getter;
|
|
2703
|
+
};
|
|
2704
|
+
__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
2705
|
+
__webpack_require__.p = "";
|
|
2706
|
+
return __webpack_require__(__webpack_require__.s = 0);
|
|
2707
|
+
})
|
|
2708
|
+
([
|
|
2709
|
+
(function(module, exports, __webpack_require__) {
|
|
2710
|
+
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; }; }();
|
|
2711
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
2712
|
+
var mediaFile = __webpack_require__(1);
|
|
2713
|
+
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;
|
|
2714
|
+
var NoSleep = function () {
|
|
2715
|
+
function NoSleep() {
|
|
2716
|
+
_classCallCheck(this, NoSleep);
|
|
2717
|
+
if (oldIOS) {
|
|
2718
|
+
this.noSleepTimer = null;
|
|
2719
|
+
} else {
|
|
2720
|
+
this.noSleepVideo = document.createElement('video');
|
|
2721
|
+
this.noSleepVideo.setAttribute('playsinline', '');
|
|
2722
|
+
this.noSleepVideo.setAttribute('src', mediaFile);
|
|
2723
|
+
this.noSleepVideo.addEventListener('timeupdate', function (e) {
|
|
2724
|
+
if (this.noSleepVideo.currentTime > 0.5) {
|
|
2725
|
+
this.noSleepVideo.currentTime = Math.random();
|
|
2726
|
+
}
|
|
2727
|
+
}.bind(this));
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
_createClass(NoSleep, [{
|
|
2731
|
+
key: 'enable',
|
|
2732
|
+
value: function enable() {
|
|
2733
|
+
if (oldIOS) {
|
|
2734
|
+
this.disable();
|
|
2735
|
+
this.noSleepTimer = window.setInterval(function () {
|
|
2736
|
+
window.location.href = '/';
|
|
2737
|
+
window.setTimeout(window.stop, 0);
|
|
2738
|
+
}, 15000);
|
|
2739
|
+
} else {
|
|
2740
|
+
this.noSleepVideo.play();
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
}, {
|
|
2744
|
+
key: 'disable',
|
|
2745
|
+
value: function disable() {
|
|
2746
|
+
if (oldIOS) {
|
|
2747
|
+
if (this.noSleepTimer) {
|
|
2748
|
+
window.clearInterval(this.noSleepTimer);
|
|
2749
|
+
this.noSleepTimer = null;
|
|
2750
|
+
}
|
|
2751
|
+
} else {
|
|
2752
|
+
this.noSleepVideo.pause();
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}]);
|
|
2756
|
+
return NoSleep;
|
|
2757
|
+
}();
|
|
2758
|
+
module.exports = NoSleep;
|
|
2759
|
+
}),
|
|
2760
|
+
(function(module, exports, __webpack_require__) {
|
|
2761
|
+
module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=';
|
|
2762
|
+
})
|
|
2763
|
+
]);
|
|
2764
|
+
});
|
|
2765
|
+
});
|
|
2766
|
+
var NoSleep$1 = unwrapExports$$1(NoSleep);
|
|
2767
|
+
var nextDisplayId = 1000;
|
|
2768
|
+
var defaultLeftBounds = [0, 0, 0.5, 1];
|
|
2769
|
+
var defaultRightBounds = [0.5, 0, 0.5, 1];
|
|
2770
|
+
var raf = window.requestAnimationFrame;
|
|
2771
|
+
var caf = window.cancelAnimationFrame;
|
|
2772
|
+
function VRFrameData() {
|
|
2773
|
+
this.leftProjectionMatrix = new Float32Array(16);
|
|
2774
|
+
this.leftViewMatrix = new Float32Array(16);
|
|
2775
|
+
this.rightProjectionMatrix = new Float32Array(16);
|
|
2776
|
+
this.rightViewMatrix = new Float32Array(16);
|
|
2777
|
+
this.pose = null;
|
|
2778
|
+
}
|
|
2779
|
+
function VRDisplayCapabilities(config) {
|
|
2780
|
+
Object.defineProperties(this, {
|
|
2781
|
+
hasPosition: {
|
|
2782
|
+
writable: false, enumerable: true, value: config.hasPosition
|
|
2783
|
+
},
|
|
2784
|
+
hasExternalDisplay: {
|
|
2785
|
+
writable: false, enumerable: true, value: config.hasExternalDisplay
|
|
2786
|
+
},
|
|
2787
|
+
canPresent: {
|
|
2788
|
+
writable: false, enumerable: true, value: config.canPresent
|
|
2789
|
+
},
|
|
2790
|
+
maxLayers: {
|
|
2791
|
+
writable: false, enumerable: true, value: config.maxLayers
|
|
2792
|
+
},
|
|
2793
|
+
hasOrientation: {
|
|
2794
|
+
enumerable: true, get: function get() {
|
|
2795
|
+
deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData');
|
|
2796
|
+
return config.hasOrientation;
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
});
|
|
2800
|
+
}
|
|
2801
|
+
function VRDisplay(config) {
|
|
2802
|
+
config = config || {};
|
|
2803
|
+
var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true;
|
|
2804
|
+
this.isPolyfilled = true;
|
|
2805
|
+
this.displayId = nextDisplayId++;
|
|
2806
|
+
this.displayName = '';
|
|
2807
|
+
this.depthNear = 0.01;
|
|
2808
|
+
this.depthFar = 10000.0;
|
|
2809
|
+
this.isPresenting = false;
|
|
2810
|
+
Object.defineProperty(this, 'isConnected', {
|
|
2811
|
+
get: function get() {
|
|
2812
|
+
deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay');
|
|
2813
|
+
return false;
|
|
2814
|
+
}
|
|
2815
|
+
});
|
|
2816
|
+
this.capabilities = new VRDisplayCapabilities({
|
|
2817
|
+
hasPosition: false,
|
|
2818
|
+
hasOrientation: false,
|
|
2819
|
+
hasExternalDisplay: false,
|
|
2820
|
+
canPresent: false,
|
|
2821
|
+
maxLayers: 1
|
|
2822
|
+
});
|
|
2823
|
+
this.stageParameters = null;
|
|
2824
|
+
this.waitingForPresent_ = false;
|
|
2825
|
+
this.layer_ = null;
|
|
2826
|
+
this.originalParent_ = null;
|
|
2827
|
+
this.fullscreenElement_ = null;
|
|
2828
|
+
this.fullscreenWrapper_ = null;
|
|
2829
|
+
this.fullscreenElementCachedStyle_ = null;
|
|
2830
|
+
this.fullscreenEventTarget_ = null;
|
|
2831
|
+
this.fullscreenChangeHandler_ = null;
|
|
2832
|
+
this.fullscreenErrorHandler_ = null;
|
|
2833
|
+
if (USE_WAKELOCK && isMobile()) {
|
|
2834
|
+
this.wakelock_ = new NoSleep$1();
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
VRDisplay.prototype.getFrameData = function (frameData) {
|
|
2838
|
+
return frameDataFromPose(frameData, this._getPose(), this);
|
|
2839
|
+
};
|
|
2840
|
+
VRDisplay.prototype.getPose = function () {
|
|
2841
|
+
deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData');
|
|
2842
|
+
return this._getPose();
|
|
2843
|
+
};
|
|
2844
|
+
VRDisplay.prototype.resetPose = function () {
|
|
2845
|
+
deprecateWarning('VRDisplay.prototype.resetPose');
|
|
2846
|
+
return this._resetPose();
|
|
2847
|
+
};
|
|
2848
|
+
VRDisplay.prototype.getImmediatePose = function () {
|
|
2849
|
+
deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData');
|
|
2850
|
+
return this._getPose();
|
|
2851
|
+
};
|
|
2852
|
+
VRDisplay.prototype.requestAnimationFrame = function (callback) {
|
|
2853
|
+
return raf(callback);
|
|
2854
|
+
};
|
|
2855
|
+
VRDisplay.prototype.cancelAnimationFrame = function (id) {
|
|
2856
|
+
return caf(id);
|
|
2857
|
+
};
|
|
2858
|
+
VRDisplay.prototype.wrapForFullscreen = function (element) {
|
|
2859
|
+
if (isIOS()) {
|
|
2860
|
+
return element;
|
|
2861
|
+
}
|
|
2862
|
+
if (!this.fullscreenWrapper_) {
|
|
2863
|
+
this.fullscreenWrapper_ = document.createElement('div');
|
|
2864
|
+
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'];
|
|
2865
|
+
this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');
|
|
2866
|
+
this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');
|
|
2867
|
+
}
|
|
2868
|
+
if (this.fullscreenElement_ == element) {
|
|
2869
|
+
return this.fullscreenWrapper_;
|
|
2870
|
+
}
|
|
2871
|
+
if (this.fullscreenElement_) {
|
|
2872
|
+
if (this.originalParent_) {
|
|
2873
|
+
this.originalParent_.appendChild(this.fullscreenElement_);
|
|
2874
|
+
} else {
|
|
2875
|
+
this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
this.fullscreenElement_ = element;
|
|
2879
|
+
this.originalParent_ = element.parentElement;
|
|
2880
|
+
if (!this.originalParent_) {
|
|
2881
|
+
document.body.appendChild(element);
|
|
2882
|
+
}
|
|
2883
|
+
if (!this.fullscreenWrapper_.parentElement) {
|
|
2884
|
+
var parent = this.fullscreenElement_.parentElement;
|
|
2885
|
+
parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);
|
|
2886
|
+
parent.removeChild(this.fullscreenElement_);
|
|
2887
|
+
}
|
|
2888
|
+
this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);
|
|
2889
|
+
this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');
|
|
2890
|
+
var self = this;
|
|
2891
|
+
function applyFullscreenElementStyle() {
|
|
2892
|
+
if (!self.fullscreenElement_) {
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2895
|
+
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'];
|
|
2896
|
+
self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');
|
|
2897
|
+
}
|
|
2898
|
+
applyFullscreenElementStyle();
|
|
2899
|
+
return this.fullscreenWrapper_;
|
|
2900
|
+
};
|
|
2901
|
+
VRDisplay.prototype.removeFullscreenWrapper = function () {
|
|
2902
|
+
if (!this.fullscreenElement_) {
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
var element = this.fullscreenElement_;
|
|
2906
|
+
if (this.fullscreenElementCachedStyle_) {
|
|
2907
|
+
element.setAttribute('style', this.fullscreenElementCachedStyle_);
|
|
2908
|
+
} else {
|
|
2909
|
+
element.removeAttribute('style');
|
|
2910
|
+
}
|
|
2911
|
+
this.fullscreenElement_ = null;
|
|
2912
|
+
this.fullscreenElementCachedStyle_ = null;
|
|
2913
|
+
var parent = this.fullscreenWrapper_.parentElement;
|
|
2914
|
+
this.fullscreenWrapper_.removeChild(element);
|
|
2915
|
+
if (this.originalParent_ === parent) {
|
|
2916
|
+
parent.insertBefore(element, this.fullscreenWrapper_);
|
|
2917
|
+
}
|
|
2918
|
+
else if (this.originalParent_) {
|
|
2919
|
+
this.originalParent_.appendChild(element);
|
|
2920
|
+
}
|
|
2921
|
+
parent.removeChild(this.fullscreenWrapper_);
|
|
2922
|
+
return element;
|
|
2923
|
+
};
|
|
2924
|
+
VRDisplay.prototype.requestPresent = function (layers) {
|
|
2925
|
+
var wasPresenting = this.isPresenting;
|
|
2926
|
+
var self = this;
|
|
2927
|
+
if (!(layers instanceof Array)) {
|
|
2928
|
+
deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument');
|
|
2929
|
+
layers = [layers];
|
|
2930
|
+
}
|
|
2931
|
+
return new Promise(function (resolve, reject) {
|
|
2932
|
+
if (!self.capabilities.canPresent) {
|
|
2933
|
+
reject(new Error('VRDisplay is not capable of presenting.'));
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {
|
|
2937
|
+
reject(new Error('Invalid number of layers.'));
|
|
2938
|
+
return;
|
|
2939
|
+
}
|
|
2940
|
+
var incomingLayer = layers[0];
|
|
2941
|
+
if (!incomingLayer.source) {
|
|
2942
|
+
resolve();
|
|
2943
|
+
return;
|
|
2944
|
+
}
|
|
2945
|
+
var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
|
|
2946
|
+
var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
|
|
2947
|
+
if (wasPresenting) {
|
|
2948
|
+
var layer = self.layer_;
|
|
2949
|
+
if (layer.source !== incomingLayer.source) {
|
|
2950
|
+
layer.source = incomingLayer.source;
|
|
2951
|
+
}
|
|
2952
|
+
for (var i = 0; i < 4; i++) {
|
|
2953
|
+
layer.leftBounds[i] = leftBounds[i];
|
|
2954
|
+
layer.rightBounds[i] = rightBounds[i];
|
|
2955
|
+
}
|
|
2956
|
+
self.wrapForFullscreen(self.layer_.source);
|
|
2957
|
+
self.updatePresent_();
|
|
2958
|
+
resolve();
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2961
|
+
self.layer_ = {
|
|
2962
|
+
predistorted: incomingLayer.predistorted,
|
|
2963
|
+
source: incomingLayer.source,
|
|
2964
|
+
leftBounds: leftBounds.slice(0),
|
|
2965
|
+
rightBounds: rightBounds.slice(0)
|
|
2966
|
+
};
|
|
2967
|
+
self.waitingForPresent_ = false;
|
|
2968
|
+
if (self.layer_ && self.layer_.source) {
|
|
2969
|
+
var fullscreenElement = self.wrapForFullscreen(self.layer_.source);
|
|
2970
|
+
var onFullscreenChange = function onFullscreenChange() {
|
|
2971
|
+
var actualFullscreenElement = getFullscreenElement();
|
|
2972
|
+
self.isPresenting = fullscreenElement === actualFullscreenElement;
|
|
2973
|
+
if (self.isPresenting) {
|
|
2974
|
+
if (screen.orientation && screen.orientation.lock) {
|
|
2975
|
+
screen.orientation.lock('landscape-primary').catch(function (error) {
|
|
2976
|
+
console.error('screen.orientation.lock() failed due to', error.message);
|
|
2977
|
+
});
|
|
2978
|
+
}
|
|
2979
|
+
self.waitingForPresent_ = false;
|
|
2980
|
+
self.beginPresent_();
|
|
2981
|
+
resolve();
|
|
2982
|
+
} else {
|
|
2983
|
+
if (screen.orientation && screen.orientation.unlock) {
|
|
2984
|
+
screen.orientation.unlock();
|
|
2985
|
+
}
|
|
2986
|
+
self.removeFullscreenWrapper();
|
|
2987
|
+
self.disableWakeLock();
|
|
2988
|
+
self.endPresent_();
|
|
2989
|
+
self.removeFullscreenListeners_();
|
|
2990
|
+
}
|
|
2991
|
+
self.fireVRDisplayPresentChange_();
|
|
2992
|
+
};
|
|
2993
|
+
var onFullscreenError = function onFullscreenError() {
|
|
2994
|
+
if (!self.waitingForPresent_) {
|
|
2995
|
+
return;
|
|
2996
|
+
}
|
|
2997
|
+
self.removeFullscreenWrapper();
|
|
2998
|
+
self.removeFullscreenListeners_();
|
|
2999
|
+
self.disableWakeLock();
|
|
3000
|
+
self.waitingForPresent_ = false;
|
|
3001
|
+
self.isPresenting = false;
|
|
3002
|
+
reject(new Error('Unable to present.'));
|
|
3003
|
+
};
|
|
3004
|
+
self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError);
|
|
3005
|
+
if (requestFullscreen(fullscreenElement)) {
|
|
3006
|
+
self.enableWakeLock();
|
|
3007
|
+
self.waitingForPresent_ = true;
|
|
3008
|
+
} else if (isIOS() || isWebViewAndroid()) {
|
|
3009
|
+
self.enableWakeLock();
|
|
3010
|
+
self.isPresenting = true;
|
|
3011
|
+
self.beginPresent_();
|
|
3012
|
+
self.fireVRDisplayPresentChange_();
|
|
3013
|
+
resolve();
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
if (!self.waitingForPresent_ && !isIOS()) {
|
|
3017
|
+
exitFullscreen();
|
|
3018
|
+
reject(new Error('Unable to present.'));
|
|
3019
|
+
}
|
|
3020
|
+
});
|
|
3021
|
+
};
|
|
3022
|
+
VRDisplay.prototype.exitPresent = function () {
|
|
3023
|
+
var wasPresenting = this.isPresenting;
|
|
3024
|
+
var self = this;
|
|
3025
|
+
this.isPresenting = false;
|
|
3026
|
+
this.layer_ = null;
|
|
3027
|
+
this.disableWakeLock();
|
|
3028
|
+
return new Promise(function (resolve, reject) {
|
|
3029
|
+
if (wasPresenting) {
|
|
3030
|
+
if (!exitFullscreen() && isIOS()) {
|
|
3031
|
+
self.endPresent_();
|
|
3032
|
+
self.fireVRDisplayPresentChange_();
|
|
3033
|
+
}
|
|
3034
|
+
if (isWebViewAndroid()) {
|
|
3035
|
+
self.removeFullscreenWrapper();
|
|
3036
|
+
self.removeFullscreenListeners_();
|
|
3037
|
+
self.endPresent_();
|
|
3038
|
+
self.fireVRDisplayPresentChange_();
|
|
3039
|
+
}
|
|
3040
|
+
resolve();
|
|
3041
|
+
} else {
|
|
3042
|
+
reject(new Error('Was not presenting to VRDisplay.'));
|
|
3043
|
+
}
|
|
3044
|
+
});
|
|
3045
|
+
};
|
|
3046
|
+
VRDisplay.prototype.getLayers = function () {
|
|
3047
|
+
if (this.layer_) {
|
|
3048
|
+
return [this.layer_];
|
|
3049
|
+
}
|
|
3050
|
+
return [];
|
|
3051
|
+
};
|
|
3052
|
+
VRDisplay.prototype.fireVRDisplayPresentChange_ = function () {
|
|
3053
|
+
var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } });
|
|
3054
|
+
window.dispatchEvent(event);
|
|
3055
|
+
};
|
|
3056
|
+
VRDisplay.prototype.fireVRDisplayConnect_ = function () {
|
|
3057
|
+
var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } });
|
|
3058
|
+
window.dispatchEvent(event);
|
|
3059
|
+
};
|
|
3060
|
+
VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) {
|
|
3061
|
+
this.removeFullscreenListeners_();
|
|
3062
|
+
this.fullscreenEventTarget_ = element;
|
|
3063
|
+
this.fullscreenChangeHandler_ = changeHandler;
|
|
3064
|
+
this.fullscreenErrorHandler_ = errorHandler;
|
|
3065
|
+
if (changeHandler) {
|
|
3066
|
+
if (document.fullscreenEnabled) {
|
|
3067
|
+
element.addEventListener('fullscreenchange', changeHandler, false);
|
|
3068
|
+
} else if (document.webkitFullscreenEnabled) {
|
|
3069
|
+
element.addEventListener('webkitfullscreenchange', changeHandler, false);
|
|
3070
|
+
} else if (document.mozFullScreenEnabled) {
|
|
3071
|
+
document.addEventListener('mozfullscreenchange', changeHandler, false);
|
|
3072
|
+
} else if (document.msFullscreenEnabled) {
|
|
3073
|
+
element.addEventListener('msfullscreenchange', changeHandler, false);
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
if (errorHandler) {
|
|
3077
|
+
if (document.fullscreenEnabled) {
|
|
3078
|
+
element.addEventListener('fullscreenerror', errorHandler, false);
|
|
3079
|
+
} else if (document.webkitFullscreenEnabled) {
|
|
3080
|
+
element.addEventListener('webkitfullscreenerror', errorHandler, false);
|
|
3081
|
+
} else if (document.mozFullScreenEnabled) {
|
|
3082
|
+
document.addEventListener('mozfullscreenerror', errorHandler, false);
|
|
3083
|
+
} else if (document.msFullscreenEnabled) {
|
|
3084
|
+
element.addEventListener('msfullscreenerror', errorHandler, false);
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
};
|
|
3088
|
+
VRDisplay.prototype.removeFullscreenListeners_ = function () {
|
|
3089
|
+
if (!this.fullscreenEventTarget_) return;
|
|
3090
|
+
var element = this.fullscreenEventTarget_;
|
|
3091
|
+
if (this.fullscreenChangeHandler_) {
|
|
3092
|
+
var changeHandler = this.fullscreenChangeHandler_;
|
|
3093
|
+
element.removeEventListener('fullscreenchange', changeHandler, false);
|
|
3094
|
+
element.removeEventListener('webkitfullscreenchange', changeHandler, false);
|
|
3095
|
+
document.removeEventListener('mozfullscreenchange', changeHandler, false);
|
|
3096
|
+
element.removeEventListener('msfullscreenchange', changeHandler, false);
|
|
3097
|
+
}
|
|
3098
|
+
if (this.fullscreenErrorHandler_) {
|
|
3099
|
+
var errorHandler = this.fullscreenErrorHandler_;
|
|
3100
|
+
element.removeEventListener('fullscreenerror', errorHandler, false);
|
|
3101
|
+
element.removeEventListener('webkitfullscreenerror', errorHandler, false);
|
|
3102
|
+
document.removeEventListener('mozfullscreenerror', errorHandler, false);
|
|
3103
|
+
element.removeEventListener('msfullscreenerror', errorHandler, false);
|
|
3104
|
+
}
|
|
3105
|
+
this.fullscreenEventTarget_ = null;
|
|
3106
|
+
this.fullscreenChangeHandler_ = null;
|
|
3107
|
+
this.fullscreenErrorHandler_ = null;
|
|
3108
|
+
};
|
|
3109
|
+
VRDisplay.prototype.enableWakeLock = function () {
|
|
3110
|
+
if (this.wakelock_) {
|
|
3111
|
+
this.wakelock_.enable();
|
|
3112
|
+
}
|
|
3113
|
+
};
|
|
3114
|
+
VRDisplay.prototype.disableWakeLock = function () {
|
|
3115
|
+
if (this.wakelock_) {
|
|
3116
|
+
this.wakelock_.disable();
|
|
3117
|
+
}
|
|
3118
|
+
};
|
|
3119
|
+
VRDisplay.prototype.beginPresent_ = function () {
|
|
3120
|
+
};
|
|
3121
|
+
VRDisplay.prototype.endPresent_ = function () {
|
|
3122
|
+
};
|
|
3123
|
+
VRDisplay.prototype.submitFrame = function (pose) {
|
|
3124
|
+
};
|
|
3125
|
+
VRDisplay.prototype.getEyeParameters = function (whichEye) {
|
|
3126
|
+
return null;
|
|
3127
|
+
};
|
|
3128
|
+
var config = {
|
|
3129
|
+
ADDITIONAL_VIEWERS: [],
|
|
3130
|
+
DEFAULT_VIEWER: '',
|
|
3131
|
+
MOBILE_WAKE_LOCK: true,
|
|
3132
|
+
DEBUG: false,
|
|
3133
|
+
DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
|
|
3134
|
+
K_FILTER: 0.98,
|
|
3135
|
+
PREDICTION_TIME_S: 0.040,
|
|
3136
|
+
CARDBOARD_UI_DISABLED: false,
|
|
3137
|
+
ROTATE_INSTRUCTIONS_DISABLED: false,
|
|
3138
|
+
YAW_ONLY: false,
|
|
3139
|
+
BUFFER_SCALE: 0.5,
|
|
3140
|
+
DIRTY_SUBMIT_FRAME_BINDINGS: false
|
|
3141
|
+
};
|
|
3142
|
+
var Eye = {
|
|
3143
|
+
LEFT: 'left',
|
|
3144
|
+
RIGHT: 'right'
|
|
3145
|
+
};
|
|
3146
|
+
function CardboardVRDisplay(config$$1) {
|
|
3147
|
+
var defaults = extend({}, config);
|
|
3148
|
+
config$$1 = extend(defaults, config$$1 || {});
|
|
3149
|
+
VRDisplay.call(this, {
|
|
3150
|
+
wakelock: config$$1.MOBILE_WAKE_LOCK
|
|
3151
|
+
});
|
|
3152
|
+
this.config = config$$1;
|
|
3153
|
+
this.displayName = 'Cardboard VRDisplay';
|
|
3154
|
+
this.capabilities = new VRDisplayCapabilities({
|
|
3155
|
+
hasPosition: false,
|
|
3156
|
+
hasOrientation: true,
|
|
3157
|
+
hasExternalDisplay: false,
|
|
3158
|
+
canPresent: true,
|
|
3159
|
+
maxLayers: 1
|
|
3160
|
+
});
|
|
3161
|
+
this.stageParameters = null;
|
|
3162
|
+
this.bufferScale_ = this.config.BUFFER_SCALE;
|
|
3163
|
+
this.poseSensor_ = new PoseSensor(this.config);
|
|
3164
|
+
this.distorter_ = null;
|
|
3165
|
+
this.cardboardUI_ = null;
|
|
3166
|
+
this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this));
|
|
3167
|
+
this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS);
|
|
3168
|
+
this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER);
|
|
3169
|
+
this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));
|
|
3170
|
+
this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());
|
|
3171
|
+
if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) {
|
|
3172
|
+
this.rotateInstructions_ = new RotateInstructions();
|
|
3173
|
+
}
|
|
3174
|
+
if (isIOS()) {
|
|
3175
|
+
window.addEventListener('resize', this.onResize_.bind(this));
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype);
|
|
3179
|
+
CardboardVRDisplay.prototype._getPose = function () {
|
|
3180
|
+
return {
|
|
3181
|
+
position: null,
|
|
3182
|
+
orientation: this.poseSensor_.getOrientation(),
|
|
3183
|
+
linearVelocity: null,
|
|
3184
|
+
linearAcceleration: null,
|
|
3185
|
+
angularVelocity: null,
|
|
3186
|
+
angularAcceleration: null
|
|
3187
|
+
};
|
|
3188
|
+
};
|
|
3189
|
+
CardboardVRDisplay.prototype._resetPose = function () {
|
|
3190
|
+
if (this.poseSensor_.resetPose) {
|
|
3191
|
+
this.poseSensor_.resetPose();
|
|
3192
|
+
}
|
|
3193
|
+
};
|
|
3194
|
+
CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) {
|
|
3195
|
+
var fieldOfView;
|
|
3196
|
+
if (whichEye == Eye.LEFT) {
|
|
3197
|
+
fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye();
|
|
3198
|
+
} else if (whichEye == Eye.RIGHT) {
|
|
3199
|
+
fieldOfView = this.deviceInfo_.getFieldOfViewRightEye();
|
|
3200
|
+
} else {
|
|
3201
|
+
console.error('Invalid eye provided: %s', whichEye);
|
|
3202
|
+
return null;
|
|
3203
|
+
}
|
|
3204
|
+
return fieldOfView;
|
|
3205
|
+
};
|
|
3206
|
+
CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) {
|
|
3207
|
+
var offset;
|
|
3208
|
+
if (whichEye == Eye.LEFT) {
|
|
3209
|
+
offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
|
|
3210
|
+
} else if (whichEye == Eye.RIGHT) {
|
|
3211
|
+
offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
|
|
3212
|
+
} else {
|
|
3213
|
+
console.error('Invalid eye provided: %s', whichEye);
|
|
3214
|
+
return null;
|
|
3215
|
+
}
|
|
3216
|
+
return offset;
|
|
3217
|
+
};
|
|
3218
|
+
CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) {
|
|
3219
|
+
var offset = this._getEyeOffset(whichEye);
|
|
3220
|
+
var fieldOfView = this._getFieldOfView(whichEye);
|
|
3221
|
+
var eyeParams = {
|
|
3222
|
+
offset: offset,
|
|
3223
|
+
renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,
|
|
3224
|
+
renderHeight: this.deviceInfo_.device.height * this.bufferScale_
|
|
3225
|
+
};
|
|
3226
|
+
Object.defineProperty(eyeParams, 'fieldOfView', {
|
|
3227
|
+
enumerable: true,
|
|
3228
|
+
get: function get() {
|
|
3229
|
+
deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices');
|
|
3230
|
+
return fieldOfView;
|
|
3231
|
+
}
|
|
3232
|
+
});
|
|
3233
|
+
return eyeParams;
|
|
3234
|
+
};
|
|
3235
|
+
CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) {
|
|
3236
|
+
if (this.config.DEBUG) {
|
|
3237
|
+
console.log('DPDB reported that device params were updated.');
|
|
3238
|
+
}
|
|
3239
|
+
this.deviceInfo_.updateDeviceParams(newParams);
|
|
3240
|
+
if (this.distorter_) {
|
|
3241
|
+
this.distorter_.updateDeviceInfo(this.deviceInfo_);
|
|
3242
|
+
}
|
|
3243
|
+
};
|
|
3244
|
+
CardboardVRDisplay.prototype.updateBounds_ = function () {
|
|
3245
|
+
if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) {
|
|
3246
|
+
this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds);
|
|
3247
|
+
}
|
|
3248
|
+
};
|
|
3249
|
+
CardboardVRDisplay.prototype.beginPresent_ = function () {
|
|
3250
|
+
var gl = this.layer_.source.getContext('webgl');
|
|
3251
|
+
if (!gl) gl = this.layer_.source.getContext('experimental-webgl');
|
|
3252
|
+
if (!gl) gl = this.layer_.source.getContext('webgl2');
|
|
3253
|
+
if (!gl) return;
|
|
3254
|
+
if (this.layer_.predistorted) {
|
|
3255
|
+
if (!this.config.CARDBOARD_UI_DISABLED) {
|
|
3256
|
+
gl.canvas.width = getScreenWidth() * this.bufferScale_;
|
|
3257
|
+
gl.canvas.height = getScreenHeight() * this.bufferScale_;
|
|
3258
|
+
this.cardboardUI_ = new CardboardUI(gl);
|
|
3259
|
+
}
|
|
3260
|
+
} else {
|
|
3261
|
+
if (!this.config.CARDBOARD_UI_DISABLED) {
|
|
3262
|
+
this.cardboardUI_ = new CardboardUI(gl);
|
|
3263
|
+
}
|
|
3264
|
+
this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS);
|
|
3265
|
+
this.distorter_.updateDeviceInfo(this.deviceInfo_);
|
|
3266
|
+
}
|
|
3267
|
+
if (this.cardboardUI_) {
|
|
3268
|
+
this.cardboardUI_.listen(function (e) {
|
|
3269
|
+
this.viewerSelector_.show(this.layer_.source.parentElement);
|
|
3270
|
+
e.stopPropagation();
|
|
3271
|
+
e.preventDefault();
|
|
3272
|
+
}.bind(this), function (e) {
|
|
3273
|
+
this.exitPresent();
|
|
3274
|
+
e.stopPropagation();
|
|
3275
|
+
e.preventDefault();
|
|
3276
|
+
}.bind(this));
|
|
3277
|
+
}
|
|
3278
|
+
if (this.rotateInstructions_) {
|
|
3279
|
+
if (isLandscapeMode() && isMobile()) {
|
|
3280
|
+
this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);
|
|
3281
|
+
} else {
|
|
3282
|
+
this.rotateInstructions_.update();
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
this.orientationHandler = this.onOrientationChange_.bind(this);
|
|
3286
|
+
window.addEventListener('orientationchange', this.orientationHandler);
|
|
3287
|
+
this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);
|
|
3288
|
+
window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
|
|
3289
|
+
this.fireVRDisplayDeviceParamsChange_();
|
|
3290
|
+
};
|
|
3291
|
+
CardboardVRDisplay.prototype.endPresent_ = function () {
|
|
3292
|
+
if (this.distorter_) {
|
|
3293
|
+
this.distorter_.destroy();
|
|
3294
|
+
this.distorter_ = null;
|
|
3295
|
+
}
|
|
3296
|
+
if (this.cardboardUI_) {
|
|
3297
|
+
this.cardboardUI_.destroy();
|
|
3298
|
+
this.cardboardUI_ = null;
|
|
3299
|
+
}
|
|
3300
|
+
if (this.rotateInstructions_) {
|
|
3301
|
+
this.rotateInstructions_.hide();
|
|
3302
|
+
}
|
|
3303
|
+
this.viewerSelector_.hide();
|
|
3304
|
+
window.removeEventListener('orientationchange', this.orientationHandler);
|
|
3305
|
+
window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
|
|
3306
|
+
};
|
|
3307
|
+
CardboardVRDisplay.prototype.updatePresent_ = function () {
|
|
3308
|
+
this.endPresent_();
|
|
3309
|
+
this.beginPresent_();
|
|
3310
|
+
};
|
|
3311
|
+
CardboardVRDisplay.prototype.submitFrame = function (pose) {
|
|
3312
|
+
if (this.distorter_) {
|
|
3313
|
+
this.updateBounds_();
|
|
3314
|
+
this.distorter_.submitFrame();
|
|
3315
|
+
} else if (this.cardboardUI_ && this.layer_) {
|
|
3316
|
+
var canvas = this.layer_.source.getContext('webgl').canvas;
|
|
3317
|
+
if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) {
|
|
3318
|
+
this.cardboardUI_.onResize();
|
|
3319
|
+
}
|
|
3320
|
+
this.lastWidth = canvas.width;
|
|
3321
|
+
this.lastHeight = canvas.height;
|
|
3322
|
+
this.cardboardUI_.render();
|
|
3323
|
+
}
|
|
3324
|
+
};
|
|
3325
|
+
CardboardVRDisplay.prototype.onOrientationChange_ = function (e) {
|
|
3326
|
+
this.viewerSelector_.hide();
|
|
3327
|
+
if (this.rotateInstructions_) {
|
|
3328
|
+
this.rotateInstructions_.update();
|
|
3329
|
+
}
|
|
3330
|
+
this.onResize_();
|
|
3331
|
+
};
|
|
3332
|
+
CardboardVRDisplay.prototype.onResize_ = function (e) {
|
|
3333
|
+
if (this.layer_) {
|
|
3334
|
+
var gl = this.layer_.source.getContext('webgl');
|
|
3335
|
+
var cssProperties = ['position: absolute', 'top: 0', 'left: 0',
|
|
3336
|
+
'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0',
|
|
3337
|
+
'padding: 0px', 'box-sizing: content-box'];
|
|
3338
|
+
gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');
|
|
3339
|
+
safariCssSizeWorkaround(gl.canvas);
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) {
|
|
3343
|
+
this.deviceInfo_.setViewer(viewer);
|
|
3344
|
+
if (this.distorter_) {
|
|
3345
|
+
this.distorter_.updateDeviceInfo(this.deviceInfo_);
|
|
3346
|
+
}
|
|
3347
|
+
this.fireVRDisplayDeviceParamsChange_();
|
|
3348
|
+
};
|
|
3349
|
+
CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () {
|
|
3350
|
+
var event = new CustomEvent('vrdisplaydeviceparamschange', {
|
|
3351
|
+
detail: {
|
|
3352
|
+
vrdisplay: this,
|
|
3353
|
+
deviceInfo: this.deviceInfo_
|
|
3354
|
+
}
|
|
3355
|
+
});
|
|
3356
|
+
window.dispatchEvent(event);
|
|
3357
|
+
};
|
|
3358
|
+
CardboardVRDisplay.VRFrameData = VRFrameData;
|
|
3359
|
+
CardboardVRDisplay.VRDisplay = VRDisplay;
|
|
3360
|
+
return CardboardVRDisplay;
|
|
3361
|
+
})));
|
|
3362
|
+
});
|
|
3363
|
+
var CardboardVRDisplay = unwrapExports(cardboardVrDisplay);
|
|
3364
|
+
|
|
3365
|
+
var version = "0.10.7";
|
|
3366
|
+
|
|
3367
|
+
var DefaultConfig = {
|
|
3368
|
+
ADDITIONAL_VIEWERS: [],
|
|
3369
|
+
DEFAULT_VIEWER: '',
|
|
3370
|
+
PROVIDE_MOBILE_VRDISPLAY: true,
|
|
3371
|
+
GET_VR_DISPLAYS_TIMEOUT: 1000,
|
|
3372
|
+
MOBILE_WAKE_LOCK: true,
|
|
3373
|
+
DEBUG: false,
|
|
3374
|
+
DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
|
|
3375
|
+
K_FILTER: 0.98,
|
|
3376
|
+
PREDICTION_TIME_S: 0.040,
|
|
3377
|
+
CARDBOARD_UI_DISABLED: false,
|
|
3378
|
+
ROTATE_INSTRUCTIONS_DISABLED: false,
|
|
3379
|
+
YAW_ONLY: false,
|
|
3380
|
+
BUFFER_SCALE: 0.5,
|
|
3381
|
+
DIRTY_SUBMIT_FRAME_BINDINGS: false
|
|
3382
|
+
};
|
|
3383
|
+
|
|
3384
|
+
function WebVRPolyfill(config) {
|
|
3385
|
+
this.config = extend(extend({}, DefaultConfig), config);
|
|
3386
|
+
this.polyfillDisplays = [];
|
|
3387
|
+
this.enabled = false;
|
|
3388
|
+
this.hasNative = 'getVRDisplays' in navigator;
|
|
3389
|
+
this.native = {};
|
|
3390
|
+
this.native.getVRDisplays = navigator.getVRDisplays;
|
|
3391
|
+
this.native.VRFrameData = window.VRFrameData;
|
|
3392
|
+
this.native.VRDisplay = window.VRDisplay;
|
|
3393
|
+
if (!this.hasNative || this.config.PROVIDE_MOBILE_VRDISPLAY && isMobile()) {
|
|
3394
|
+
this.enable();
|
|
3395
|
+
this.getVRDisplays().then(function (displays) {
|
|
3396
|
+
if (displays && displays[0] && displays[0].fireVRDisplayConnect_) {
|
|
3397
|
+
displays[0].fireVRDisplayConnect_();
|
|
3398
|
+
}
|
|
3399
|
+
});
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
WebVRPolyfill.prototype.getPolyfillDisplays = function () {
|
|
3403
|
+
if (this._polyfillDisplaysPopulated) {
|
|
3404
|
+
return this.polyfillDisplays;
|
|
3405
|
+
}
|
|
3406
|
+
if (isMobile()) {
|
|
3407
|
+
var vrDisplay = new CardboardVRDisplay({
|
|
3408
|
+
ADDITIONAL_VIEWERS: this.config.ADDITIONAL_VIEWERS,
|
|
3409
|
+
DEFAULT_VIEWER: this.config.DEFAULT_VIEWER,
|
|
3410
|
+
MOBILE_WAKE_LOCK: this.config.MOBILE_WAKE_LOCK,
|
|
3411
|
+
DEBUG: this.config.DEBUG,
|
|
3412
|
+
DPDB_URL: this.config.DPDB_URL,
|
|
3413
|
+
CARDBOARD_UI_DISABLED: this.config.CARDBOARD_UI_DISABLED,
|
|
3414
|
+
K_FILTER: this.config.K_FILTER,
|
|
3415
|
+
PREDICTION_TIME_S: this.config.PREDICTION_TIME_S,
|
|
3416
|
+
ROTATE_INSTRUCTIONS_DISABLED: this.config.ROTATE_INSTRUCTIONS_DISABLED,
|
|
3417
|
+
YAW_ONLY: this.config.YAW_ONLY,
|
|
3418
|
+
BUFFER_SCALE: this.config.BUFFER_SCALE,
|
|
3419
|
+
DIRTY_SUBMIT_FRAME_BINDINGS: this.config.DIRTY_SUBMIT_FRAME_BINDINGS
|
|
3420
|
+
});
|
|
3421
|
+
this.polyfillDisplays.push(vrDisplay);
|
|
3422
|
+
}
|
|
3423
|
+
this._polyfillDisplaysPopulated = true;
|
|
3424
|
+
return this.polyfillDisplays;
|
|
3425
|
+
};
|
|
3426
|
+
WebVRPolyfill.prototype.enable = function () {
|
|
3427
|
+
this.enabled = true;
|
|
3428
|
+
if (this.hasNative && this.native.VRFrameData) {
|
|
3429
|
+
var NativeVRFrameData = this.native.VRFrameData;
|
|
3430
|
+
var nativeFrameData = new this.native.VRFrameData();
|
|
3431
|
+
var nativeGetFrameData = this.native.VRDisplay.prototype.getFrameData;
|
|
3432
|
+
window.VRDisplay.prototype.getFrameData = function (frameData) {
|
|
3433
|
+
if (frameData instanceof NativeVRFrameData) {
|
|
3434
|
+
nativeGetFrameData.call(this, frameData);
|
|
3435
|
+
return;
|
|
3436
|
+
}
|
|
3437
|
+
nativeGetFrameData.call(this, nativeFrameData);
|
|
3438
|
+
frameData.pose = nativeFrameData.pose;
|
|
3439
|
+
copyArray(nativeFrameData.leftProjectionMatrix, frameData.leftProjectionMatrix);
|
|
3440
|
+
copyArray(nativeFrameData.rightProjectionMatrix, frameData.rightProjectionMatrix);
|
|
3441
|
+
copyArray(nativeFrameData.leftViewMatrix, frameData.leftViewMatrix);
|
|
3442
|
+
copyArray(nativeFrameData.rightViewMatrix, frameData.rightViewMatrix);
|
|
3443
|
+
};
|
|
3444
|
+
}
|
|
3445
|
+
navigator.getVRDisplays = this.getVRDisplays.bind(this);
|
|
3446
|
+
window.VRDisplay = CardboardVRDisplay.VRDisplay;
|
|
3447
|
+
window.VRFrameData = CardboardVRDisplay.VRFrameData;
|
|
3448
|
+
};
|
|
3449
|
+
WebVRPolyfill.prototype.getVRDisplays = function () {
|
|
3450
|
+
var _this = this;
|
|
3451
|
+
var config = this.config;
|
|
3452
|
+
if (!this.hasNative) {
|
|
3453
|
+
return Promise.resolve(this.getPolyfillDisplays());
|
|
3454
|
+
}
|
|
3455
|
+
var timeoutId;
|
|
3456
|
+
var vrDisplaysNative = this.native.getVRDisplays.call(navigator);
|
|
3457
|
+
var timeoutPromise = new Promise(function (resolve) {
|
|
3458
|
+
timeoutId = setTimeout(function () {
|
|
3459
|
+
console.warn('Native WebVR implementation detected, but `getVRDisplays()` failed to resolve. Falling back to polyfill.');
|
|
3460
|
+
resolve([]);
|
|
3461
|
+
}, config.GET_VR_DISPLAYS_TIMEOUT);
|
|
3462
|
+
});
|
|
3463
|
+
return race([vrDisplaysNative, timeoutPromise]).then(function (nativeDisplays) {
|
|
3464
|
+
clearTimeout(timeoutId);
|
|
3465
|
+
return nativeDisplays.length > 0 ? nativeDisplays : _this.getPolyfillDisplays();
|
|
3466
|
+
});
|
|
3467
|
+
};
|
|
3468
|
+
WebVRPolyfill.version = version;
|
|
3469
|
+
WebVRPolyfill.VRFrameData = CardboardVRDisplay.VRFrameData;
|
|
3470
|
+
WebVRPolyfill.VRDisplay = CardboardVRDisplay.VRDisplay;
|
|
3471
|
+
|
|
3472
|
+
|
|
3473
|
+
var webvrPolyfill = Object.freeze({
|
|
3474
|
+
default: WebVRPolyfill
|
|
3475
|
+
});
|
|
3476
|
+
|
|
3477
|
+
var require$$0 = ( webvrPolyfill && WebVRPolyfill ) || webvrPolyfill;
|
|
3478
|
+
|
|
3479
|
+
if (typeof commonjsGlobal !== 'undefined' && commonjsGlobal.window) {
|
|
3480
|
+
if (!commonjsGlobal.document) {
|
|
3481
|
+
commonjsGlobal.document = commonjsGlobal.window.document;
|
|
3482
|
+
}
|
|
3483
|
+
if (!commonjsGlobal.navigator) {
|
|
3484
|
+
commonjsGlobal.navigator = commonjsGlobal.window.navigator;
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
var src = require$$0;
|
|
3488
|
+
|
|
3489
|
+
return src;
|
|
3490
|
+
|
|
3491
|
+
})));
|