@@ -57,6 +57,8 @@
|
|
57
57
|
*/
|
58
58
|
export const needlePlugins = async (command, config, userSettings) => {
|
59
59
|
|
60
|
+
if(!config) config = {}
|
61
|
+
|
60
62
|
// ensure we have user settings initialized with defaults
|
61
63
|
userSettings = { ...defaultUserSettings, ...userSettings }
|
62
64
|
const array = [
|
@@ -453,7 +453,7 @@
|
|
453
453
|
|
454
454
|
|
455
455
|
/** Optional callback, you can implement this to only get callbacks for VR or AR sessions if necessary.
|
456
|
-
* @returns true if the mode is supported (if false the mode is not supported by this
|
456
|
+
* @returns true if the mode is supported (if false the mode is not supported by this component and it will not receive XR callbacks for this mode)
|
457
457
|
*/
|
458
458
|
supportsXR?(mode: XRSessionMode): boolean;
|
459
459
|
/** Called before the XR session is requested. Use this callback if you want to modify the session init features */
|
@@ -150,70 +150,74 @@
|
|
150
150
|
instance[$isDontDestroy] = value;
|
151
151
|
}
|
152
152
|
|
153
|
+
const destroyed_components: Array<IComponent> = [];
|
154
|
+
const destroyed_objects: Array<Object3D> = [];
|
153
155
|
export function destroy(instance: Object3D | Component, recursive: boolean = true, dispose: boolean = false) {
|
154
|
-
|
155
|
-
|
156
|
-
|
156
|
+
destroyed_components.length = 0;
|
157
|
+
destroyed_objects.length = 0;
|
158
|
+
internalDestroy(instance, recursive, dispose, true);
|
159
|
+
for (const comp of destroyed_components) {
|
157
160
|
comp.gameObject = null!;
|
158
161
|
//@ts-ignore
|
159
162
|
comp.context = null;
|
160
163
|
}
|
164
|
+
// dipose resources and remove references
|
165
|
+
for (const obj of destroyed_objects) {
|
166
|
+
setDestroyed(obj, true);
|
167
|
+
if (dispose) {
|
168
|
+
disposeObjectResources(obj);
|
169
|
+
}
|
170
|
+
// This needs to be called after disposing because it removes the references to resources
|
171
|
+
__internalRemoveReferences(obj);
|
172
|
+
}
|
173
|
+
destroyed_objects.length = 0;
|
174
|
+
destroyed_components.length = 0;
|
161
175
|
}
|
162
176
|
|
163
|
-
function internalDestroy(instance: Object3D | Component, recursive: boolean = true, dispose: boolean = false, isRoot: boolean = true
|
177
|
+
function internalDestroy(instance: Object3D | Component, recursive: boolean = true, dispose: boolean = false, isRoot: boolean = true) {
|
164
178
|
if (instance === null || instance === undefined)
|
165
179
|
return;
|
166
180
|
|
167
181
|
const comp = instance as Component;
|
168
182
|
if (comp.isComponent) {
|
183
|
+
// Handle Component
|
169
184
|
if (comp[$isDontDestroy]) return;
|
170
|
-
|
185
|
+
destroyed_components.push(comp);
|
171
186
|
const go = comp.gameObject;
|
172
187
|
comp.__internalDisable();
|
173
188
|
comp.__internalDestroy();
|
174
189
|
comp.gameObject = go;
|
175
190
|
return;
|
176
191
|
}
|
192
|
+
|
193
|
+
// handle Object3D
|
177
194
|
if (instance[$isDontDestroy]) return;
|
178
195
|
|
179
|
-
|
180
196
|
const obj = instance as GameObject;
|
181
|
-
setDestroyed(obj, true);
|
182
|
-
if (dispose) {
|
183
|
-
disposeObjectResources(obj);
|
184
|
-
}
|
185
|
-
// This needs to be called after disposing because it removes the references to resources
|
186
|
-
__internalRemoveReferences(obj);
|
187
|
-
|
188
197
|
if (debug) console.log(obj);
|
198
|
+
destroyed_objects.push(obj);
|
189
199
|
|
190
|
-
|
191
|
-
for (const ch of obj.children) {
|
192
|
-
internalDestroy(ch, recursive, dispose, false, allComponents);
|
193
|
-
}
|
194
|
-
}
|
195
|
-
|
200
|
+
// first disable and call onDestroy on components
|
196
201
|
const components = obj.userData.components;
|
197
202
|
if (components) {
|
198
203
|
let lastLength = components.length;
|
199
204
|
for (let i = 0; i < components.length; i++) {
|
200
205
|
const comp: Component = components[i];
|
201
|
-
|
202
|
-
|
203
|
-
comp.__internalDisable();
|
204
|
-
comp.__internalDestroy();
|
205
|
-
comp.gameObject = go;
|
206
|
-
// if (comp.destroy) {
|
207
|
-
// if (debug) console.log("destroying", comp);
|
208
|
-
// comp.destroy();
|
209
|
-
// }
|
210
|
-
// components will be removed from componentlist in destroy
|
206
|
+
internalDestroy(comp, recursive, dispose, false);
|
207
|
+
// components will be removed from componentlist in destroy
|
211
208
|
if (components.length < lastLength) {
|
212
209
|
lastLength = components.length;
|
213
210
|
i--;
|
214
211
|
}
|
215
212
|
}
|
216
213
|
}
|
214
|
+
// then continue in children of the passed in object
|
215
|
+
if (recursive && obj.children) {
|
216
|
+
for (const ch of obj.children) {
|
217
|
+
internalDestroy(ch, recursive, dispose, false);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
217
221
|
if (isRoot)
|
218
222
|
obj.removeFromParent();
|
219
223
|
}
|
@@ -84,11 +84,12 @@
|
|
84
84
|
*/
|
85
85
|
emitEvents = true;
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
/** Is the controller still connected? */
|
88
|
+
get connected() {
|
89
|
+
return this._connected;
|
90
|
+
}
|
91
|
+
private _connected: boolean = true;
|
92
|
+
|
92
93
|
get isTracking() { return this._isTracking; }
|
93
94
|
private _isTracking: boolean = false;
|
94
95
|
/** the input source gamepad giving raw access to the gamepad values
|
@@ -379,6 +380,7 @@
|
|
379
380
|
|
380
381
|
/** Called when the input source disconnects */
|
381
382
|
onDisconnected() {
|
383
|
+
this._connected = false;
|
382
384
|
if (debug) console.warn("Controller disconnected", this.index);
|
383
385
|
// move all attached objects into the scene
|
384
386
|
for (const child of this._object.children) {
|
@@ -606,8 +608,6 @@
|
|
606
608
|
// we should probably do both but then we need to ignore the primary index in the following function (to not raise an event for the same button twice)
|
607
609
|
// and start with index = 1
|
608
610
|
private updateInputEvents() {
|
609
|
-
if (!this._layout) return;
|
610
|
-
|
611
611
|
// https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-heading
|
612
612
|
if (this.gamepad?.buttons) {
|
613
613
|
for (let k = 0; k < this.gamepad.buttons.length; k++) {
|
@@ -383,8 +383,7 @@
|
|
383
383
|
return obj;
|
384
384
|
}
|
385
385
|
|
386
|
-
|
387
|
-
|
386
|
+
private static invertForwardMatrix = new Matrix4().makeRotationY(Math.PI);
|
388
387
|
private applyWebARSessionRoot() {
|
389
388
|
if (!this.objectToExport) return;
|
390
389
|
|
@@ -408,9 +407,14 @@
|
|
408
407
|
const scale = 1 / sessionRoot!.arScale;
|
409
408
|
if (debug) console.log("AR Session Root scale", scale, target);
|
410
409
|
target.matrix.makeScale(scale, scale, scale);
|
411
|
-
if (sessionRoot.invertForward
|
412
|
-
target.matrix.multiply(
|
410
|
+
if (sessionRoot.invertForward) {
|
411
|
+
target.matrix.multiply(USDZExporter.invertForwardMatrix);
|
413
412
|
}
|
413
|
+
|
414
|
+
// TODO we should refactor this and use one common method in WebARSessionRoot to place an object –
|
415
|
+
// basically the inverted effect of WebARSessionRoot.onApplyPose()
|
416
|
+
|
417
|
+
// TODO why are we not reverting this transformation after the export?
|
414
418
|
}
|
415
419
|
|
416
420
|
|
@@ -53,7 +53,7 @@
|
|
53
53
|
childModel.matrix.copy(child.matrix);
|
54
54
|
|
55
55
|
const childParent = child.parent;
|
56
|
-
const isText = childParent && typeof childParent["textContent"] === "string" && childParent["textContent"].length;
|
56
|
+
const isText = !!childParent && typeof childParent["textContent"] === "string" && childParent["textContent"].length > 0;
|
57
57
|
let hierarchyOpacity = opacityMap.get(childParent!) || 1;
|
58
58
|
|
59
59
|
// TODO CanvasGroup doesn't render something but modifies opacity
|
@@ -65,8 +65,11 @@
|
|
65
65
|
|
66
66
|
if (child instanceof Mesh && isText) {
|
67
67
|
// get shadoDomOwner so we can export Text from the text extension directly
|
68
|
-
const shadowDomOwner = child[$shadowDomOwner]
|
69
|
-
|
68
|
+
const shadowDomOwner = child[$shadowDomOwner];
|
69
|
+
if (!shadowDomOwner)
|
70
|
+
console.error("Error when exporting UI: shadow component owner not found. This is likely a bug.", child);
|
71
|
+
else
|
72
|
+
textExt.exportText(shadowDomOwner.gameObject, childModel, _context);
|
70
73
|
}
|
71
74
|
|
72
75
|
if (child instanceof Mesh && !isText)
|
@@ -270,13 +270,16 @@
|
|
270
270
|
private onPlaceScene = (evt: NEPointerEvent) => {
|
271
271
|
if (this._isPlacing == false) return;
|
272
272
|
|
273
|
-
let reticle = this._reticle[0];
|
273
|
+
let reticle: IGameObject | undefined = this._reticle[0];
|
274
274
|
let hit = this._hits[0];
|
275
275
|
|
276
276
|
if (evt.origin instanceof NeedleXRController) {
|
277
277
|
// until we can use hit testing for both controllers and have multple reticles we only allow placement with the first controller
|
278
|
-
|
279
|
-
|
278
|
+
const controllerReticle = this._reticle[evt.origin.index];
|
279
|
+
if (controllerReticle) {
|
280
|
+
reticle = controllerReticle;
|
281
|
+
hit = this._hits[evt.origin.index];
|
282
|
+
}
|
280
283
|
}
|
281
284
|
|
282
285
|
if (!reticle) {
|
@@ -315,6 +318,7 @@
|
|
315
318
|
|
316
319
|
private onRevertSceneChanges() {
|
317
320
|
for (const ret of this._reticle) {
|
321
|
+
if (!ret) continue;
|
318
322
|
ret.visible = false;
|
319
323
|
ret?.removeFromParent();
|
320
324
|
}
|
@@ -368,8 +372,7 @@
|
|
368
372
|
reticle.attach(rigObject);
|
369
373
|
reticle.removeFromParent();
|
370
374
|
|
371
|
-
|
372
|
-
// move rig now relative tot he reticle
|
375
|
+
// move rig now relative to the reticle
|
373
376
|
// apply scale
|
374
377
|
rigObject.scale.set(this.arScale, this.arScale, this.arScale);
|
375
378
|
rigObject.position.multiplyScalar(this.arScale);
|
@@ -377,7 +380,7 @@
|
|
377
380
|
rigObject.updateMatrix();
|
378
381
|
// if invert forward is disabled we need to invert the forward rotation
|
379
382
|
// we want to look into positive Z direction (if invertForward is enabled we look into negative Z direction)
|
380
|
-
if (this.invertForward
|
383
|
+
if (this.invertForward)
|
381
384
|
rigObject.matrix.premultiply(invertForwardMatrix);
|
382
385
|
rigObject.matrix.premultiply(this._startOffset);
|
383
386
|
|
@@ -386,205 +389,6 @@
|
|
386
389
|
previousParent.add(rigObject);
|
387
390
|
}
|
388
391
|
}
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
/*
|
394
|
-
|
395
|
-
webAR: WebAR | null = null;
|
396
|
-
|
397
|
-
get rig(): Object3D | undefined {
|
398
|
-
return this.webAR?.webxr.Rig;
|
399
|
-
}
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
private readonly _initalMatrix = new Matrix4();
|
404
|
-
private readonly _selectStartFn = this.onSelectStart.bind(this);
|
405
|
-
private readonly _selectEndFn = this.onSelectEnd.bind(this);
|
406
|
-
|
407
|
-
start() {
|
408
|
-
const xr = GameObject.findObjectOfType(WebXR);
|
409
|
-
if (xr) {
|
410
|
-
xr.Rig.updateMatrix();
|
411
|
-
this._initalMatrix.copy(xr.Rig.matrix);
|
412
|
-
}
|
413
|
-
}
|
414
|
-
|
415
|
-
private _rig: Object3D | null = null;
|
416
|
-
private _startPose: Matrix4 | null = null;
|
417
|
-
private _placementPose: Matrix4 | null = null;
|
418
|
-
private _isTouching: boolean = false;
|
419
|
-
private _rigStartPose: Matrix4 | undefined | null = null;
|
420
|
-
private _gotFirstHitTestResult: boolean = false;
|
421
|
-
private _anchor: XRAnchor | null = null;
|
422
|
-
|
423
|
-
onBegin(session: XRSession) {
|
424
|
-
|
425
|
-
this._placementPose = null;
|
426
|
-
this.gameObject.visible = false;
|
427
|
-
this.gameObject.matrixAutoUpdate = false;
|
428
|
-
this._startPose = this.gameObject.matrix.clone();
|
429
|
-
this._rigStartPose = this.rig?.matrix.clone();
|
430
|
-
this._gotFirstHitTestResult = false;
|
431
|
-
this._anchor = null;
|
432
|
-
session.addEventListener('selectstart', this._selectStartFn);
|
433
|
-
session.addEventListener('selectend', this._selectEndFn);
|
434
|
-
// setTimeout(() => this.gameObject.visible = false, 1000); // TODO test on phone AR and Hololens if this was still needed
|
435
|
-
|
436
|
-
// console.log(this.rig?.position, this.rig?.quaternion, this.rig?.scale);
|
437
|
-
this.gameObject.visible = false;
|
438
|
-
|
439
|
-
if (this.rig) {
|
440
|
-
// reset rig to initial pose, this is helping the mix of immersive AR and immersive VR that we now have on quest
|
441
|
-
// where the rig can be moved and scaled by the user in VR mode and we use the rig position when entering
|
442
|
-
// immersive Ar right now to place the user/offset the session
|
443
|
-
this.rig.matrixAutoUpdate = true;
|
444
|
-
this._initalMatrix.decompose(this.rig.position, this.rig.quaternion, this.rig.scale);
|
445
|
-
}
|
446
|
-
|
447
|
-
// TODO this is duplicate to WebXR events AND engine events, would be better in one place
|
448
|
-
this.dispatchEvent(new CustomEvent('onBeginSession'));
|
449
|
-
}
|
450
|
-
|
451
|
-
onUpdate(rig: Object3D | null, _session: XRSession, hit: XRHitTestResult | null, pose: XRPose | null | undefined): boolean {
|
452
|
-
|
453
|
-
if (pose && !this._placementPose) {
|
454
|
-
if (!this._gotFirstHitTestResult) {
|
455
|
-
this._gotFirstHitTestResult = true;
|
456
|
-
this.dispatchEvent(new CustomEvent('canPlaceSession', { detail: { pose: pose } }));
|
457
|
-
}
|
458
|
-
|
459
|
-
if (this._isTouching) {
|
460
|
-
// callbacks
|
461
|
-
const poseMatrix = new Matrix4().fromArray(pose.transform.matrix).invert();
|
462
|
-
this.dispatchEvent(new CustomEvent('placedSession', { detail: { pose, poseMatrix } }));
|
463
|
-
|
464
|
-
if (this.webAR) this.webAR.setReticleActive(false);
|
465
|
-
this.placeAt(rig, poseMatrix);
|
466
|
-
if (hit && pose && !isQuest()) // TODO anchors seem to behave differently with an XRRig
|
467
|
-
this.onCreatePlacementAnchor(hit, pose);
|
468
|
-
|
469
|
-
return true;
|
470
|
-
}
|
471
|
-
}
|
472
|
-
return false;
|
473
|
-
}
|
474
|
-
|
475
|
-
private onCreatePlacementAnchor(hit: XRHitTestResult, pose: XRPose) {
|
476
|
-
this._anchor = null;
|
477
|
-
hit?.createAnchor?.call(hit, pose.transform)?.then(anchor => {
|
478
|
-
if (this.context.isInAR)
|
479
|
-
this._anchor = anchor;
|
480
|
-
}).catch(ex => {
|
481
|
-
console.warn("Failed to create anchor", ex);
|
482
|
-
});
|
483
|
-
}
|
484
|
-
|
485
|
-
private _anchorMatrix: Matrix4 = new Matrix4();
|
486
|
-
|
487
|
-
onBeforeRender(frame: XRFrame | null): void {
|
488
|
-
if (frame && this._rig) {
|
489
|
-
if (this._anchor) {
|
490
|
-
const referenceSpace = this.context.renderer.xr.getReferenceSpace();
|
491
|
-
if (referenceSpace) {
|
492
|
-
const pose = frame.getPose(this._anchor.anchorSpace, referenceSpace);
|
493
|
-
if (pose) {
|
494
|
-
const poseMatrix = this._anchorMatrix.fromArray(pose.transform.matrix).invert();
|
495
|
-
this.placeAt(this._rig, poseMatrix);
|
496
|
-
return;
|
497
|
-
}
|
498
|
-
}
|
499
|
-
}
|
500
|
-
else if (this._placementPose) {
|
501
|
-
this.placeAt(this._rig, this._placementPose!);
|
502
|
-
}
|
503
|
-
}
|
504
|
-
}
|
505
|
-
|
506
|
-
private _invertedSessionRootMatrix: Matrix4 = new Matrix4();
|
507
|
-
private _invertForwardMatrix: Matrix4 = new Matrix4().makeRotationY(Math.PI);
|
508
|
-
|
509
|
-
placeAt(rig: Object3D | null, mat: Matrix4) {
|
510
|
-
if (!this._placementPose) this._placementPose = new Matrix4();
|
511
|
-
this._placementPose.copy(mat);
|
512
|
-
|
513
|
-
// apply session root offset
|
514
|
-
const invertedSessionRoot = this._invertedSessionRootMatrix.copy(this.gameObject.matrixWorld).invert();
|
515
|
-
this._placementPose.premultiply(invertedSessionRoot);
|
516
|
-
if (rig) {
|
517
|
-
if (this.invertForward) {
|
518
|
-
this._placementPose.premultiply(this._invertForwardMatrix);
|
519
|
-
}
|
520
|
-
|
521
|
-
if (!this.userInput) this.userInput = new WebXRSessionRootUserInput(this.context);
|
522
|
-
this.userInput.enable();
|
523
|
-
|
524
|
-
this._rig = rig;
|
525
|
-
this.setScale(this.arScale);
|
526
|
-
}
|
527
|
-
else this._rig = null;
|
528
|
-
this.gameObject.visible = true;
|
529
|
-
}
|
530
|
-
|
531
|
-
onEnd(rig: Object3D | null, _session: XRSession) {
|
532
|
-
this.userInput?.disable();
|
533
|
-
this.userInput?.reset();
|
534
|
-
|
535
|
-
this._placementPose = null;
|
536
|
-
this.gameObject.visible = false;
|
537
|
-
this.gameObject.matrixAutoUpdate = false;
|
538
|
-
this._anchor = null;
|
539
|
-
if (this._startPose) {
|
540
|
-
this.gameObject.matrix.copy(this._startPose);
|
541
|
-
}
|
542
|
-
if (rig) {
|
543
|
-
rig.matrixAutoUpdate = true;
|
544
|
-
if (this._rigStartPose) {
|
545
|
-
this._rigStartPose.decompose(rig.position, rig.quaternion, rig.scale);
|
546
|
-
// console.log(rig.position, rig.quaternion, rig.scale);
|
547
|
-
}
|
548
|
-
}
|
549
|
-
InstancingUtil.markDirty(this.gameObject, true);
|
550
|
-
// HACK to fix physics being not in correct place after exiting AR
|
551
|
-
setTimeout(() => {
|
552
|
-
if (!this.gameObject) return;
|
553
|
-
this.gameObject.matrixAutoUpdate = true;
|
554
|
-
this.gameObject.visible = true;
|
555
|
-
}, 100);
|
556
|
-
}
|
557
|
-
|
558
|
-
|
559
|
-
private onSelectStart() {
|
560
|
-
this._isTouching = true;
|
561
|
-
}
|
562
|
-
|
563
|
-
private onSelectEnd() {
|
564
|
-
this._isTouching = false;
|
565
|
-
}
|
566
|
-
|
567
|
-
private setScale(scale) {
|
568
|
-
const rig = this._rig;
|
569
|
-
if (!rig || !this._placementPose) {
|
570
|
-
return;
|
571
|
-
}
|
572
|
-
// Capture the rig position before the first time we move it during a session
|
573
|
-
if (!this._rigStartPose) {
|
574
|
-
this._rigStartPose = rig.matrix.clone();
|
575
|
-
}
|
576
|
-
// we apply the transform to the rig because we want to move the user's position for easy networking
|
577
|
-
rig.matrixAutoUpdate = false;
|
578
|
-
if (this.arTouchTransform && this.userInput) {
|
579
|
-
this.userInput.applyMatrixTo(this._placementPose);
|
580
|
-
// rig.matrix.premultiply(this.userInput.offset);
|
581
|
-
}
|
582
|
-
rig.matrix.multiplyMatrices(tempMatrix.makeScale(scale, scale, scale), this._placementPose);
|
583
|
-
rig.matrix.decompose(rig.position, rig.quaternion, rig.scale);
|
584
|
-
rig.updateMatrixWorld();
|
585
|
-
}
|
586
|
-
|
587
|
-
*/
|
588
392
|
}
|
589
393
|
|
590
394
|
|
@@ -148,6 +148,7 @@
|
|
148
148
|
console.warn("No USDZExporter component found in the scene");
|
149
149
|
}
|
150
150
|
});
|
151
|
+
this.hideElementDuringXRSession(button);
|
151
152
|
this.root?.appendChild(button);
|
152
153
|
return button;
|
153
154
|
}
|
@@ -173,9 +174,10 @@
|
|
173
174
|
button.addEventListener("click", () => NeedleXRSession.start(mode, init));
|
174
175
|
this.updateSessionSupported(button, mode);
|
175
176
|
this.listenToXRSessionState(button, mode);
|
177
|
+
this.hideElementDuringXRSession(button);
|
176
178
|
this.root?.appendChild(button);
|
177
179
|
|
178
|
-
if(!this.isSecureConnection) {
|
180
|
+
if (!this.isSecureConnection) {
|
179
181
|
button.disabled = true;
|
180
182
|
button.title = "WebXR requires a secure connection (HTTPS)";
|
181
183
|
}
|
@@ -207,9 +209,10 @@
|
|
207
209
|
button.addEventListener("click", () => NeedleXRSession.start(mode, init));
|
208
210
|
this.updateSessionSupported(button, mode);
|
209
211
|
this.listenToXRSessionState(button, mode);
|
212
|
+
this.hideElementDuringXRSession(button);
|
210
213
|
this.root?.appendChild(button);
|
211
214
|
|
212
|
-
if(!this.isSecureConnection) {
|
215
|
+
if (!this.isSecureConnection) {
|
213
216
|
button.disabled = true;
|
214
217
|
button.title = "WebXR requires a secure connection (HTTPS)";
|
215
218
|
}
|
@@ -238,6 +241,8 @@
|
|
238
241
|
const urlParameter = encodeURIComponent(window.location.href);
|
239
242
|
window.open(baseUrl + urlParameter);
|
240
243
|
});
|
244
|
+
this.listenToXRSessionState(button);
|
245
|
+
this.hideElementDuringXRSession(button);
|
241
246
|
// make sure to hide the button when we have VR support directly on the device
|
242
247
|
if (!isMozillaXR()) { // WebXR Viewer can't attach events before session start
|
243
248
|
navigator.xr?.addEventListener("devicechange", () => {
|
@@ -257,6 +262,7 @@
|
|
257
262
|
const wrapper = document.createElement("div");
|
258
263
|
wrapper.style.position = "relative";
|
259
264
|
wrapper.style.display = "inline-block";
|
265
|
+
this.hideElementDuringXRSession(wrapper);
|
260
266
|
|
261
267
|
const qrCodeContainer = document.createElement("div");
|
262
268
|
qrCodeContainer.classList.add("qr-code-container");
|
@@ -301,35 +307,41 @@
|
|
301
307
|
});
|
302
308
|
}
|
303
309
|
|
304
|
-
private
|
305
|
-
NeedleXRSession.onSessionRequestStart(args => {
|
306
|
-
if (args.mode === mode) {
|
307
|
-
button.classList.add("this-mode-is-requested");
|
308
|
-
// button["original-text"] = button.innerText;
|
309
|
-
// let modeText = mode === "immersive-vr" ? "VR" : "AR";
|
310
|
-
// button.innerText = "Starting " + modeText + "...";
|
311
|
-
}
|
312
|
-
else {
|
313
|
-
button["was-disabled"] = button.disabled;
|
314
|
-
button.disabled = true;
|
315
|
-
button.classList.add("other-mode-is-requested");
|
316
|
-
}
|
317
|
-
});
|
318
|
-
NeedleXRSession.onSessionRequestEnd(_ => {
|
319
|
-
button.classList.remove("this-mode-is-requested");
|
320
|
-
button.classList.remove("other-mode-is-requested");
|
321
|
-
button.disabled = button["was-disabled"];
|
322
|
-
// button.innerText = button["original-text"];
|
323
|
-
});
|
310
|
+
private hideElementDuringXRSession(element: HTMLElement) {
|
324
311
|
NeedleXRSession.onXRSessionStart(_ => {
|
325
|
-
|
326
|
-
|
312
|
+
element["previous-display"] = element.style.display;
|
313
|
+
element.style.display = "none";
|
327
314
|
});
|
328
315
|
NeedleXRSession.onXRSessionEnd(_ => {
|
329
|
-
if (
|
330
|
-
|
316
|
+
if (element["previous-display"] != undefined)
|
317
|
+
element.style.display = element["previous-display"];
|
331
318
|
});
|
332
319
|
}
|
320
|
+
|
321
|
+
private listenToXRSessionState(button: HTMLButtonElement, mode?: XRSessionMode) {
|
322
|
+
|
323
|
+
if (mode) {
|
324
|
+
NeedleXRSession.onSessionRequestStart(args => {
|
325
|
+
if (args.mode === mode) {
|
326
|
+
button.classList.add("this-mode-is-requested");
|
327
|
+
// button["original-text"] = button.innerText;
|
328
|
+
// let modeText = mode === "immersive-vr" ? "VR" : "AR";
|
329
|
+
// button.innerText = "Starting " + modeText + "...";
|
330
|
+
}
|
331
|
+
else {
|
332
|
+
button["was-disabled"] = button.disabled;
|
333
|
+
button.disabled = true;
|
334
|
+
button.classList.add("other-mode-is-requested");
|
335
|
+
}
|
336
|
+
});
|
337
|
+
NeedleXRSession.onSessionRequestEnd(_ => {
|
338
|
+
button.classList.remove("this-mode-is-requested");
|
339
|
+
button.classList.remove("other-mode-is-requested");
|
340
|
+
button.disabled = button["was-disabled"];
|
341
|
+
// button.innerText = button["original-text"];
|
342
|
+
});
|
343
|
+
}
|
344
|
+
}
|
333
345
|
}
|
334
346
|
|
335
347
|
if (!customElements.get(webXRElementName))
|