@shopware-ag/dive 1.16.24 → 1.16.26-beta.0

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.
Files changed (44) hide show
  1. package/build/dive.cjs +1652 -203
  2. package/build/dive.cjs.map +1 -1
  3. package/build/dive.d.cts +50 -8
  4. package/build/dive.d.ts +50 -8
  5. package/build/dive.js +1619 -159
  6. package/build/dive.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/ar/AR.ts +164 -0
  9. package/src/ar/arquicklook/ARQuickLook.ts +42 -0
  10. package/src/ar/webxr/WebXR.ts +176 -0
  11. package/src/ar/webxr/controller/WebXRController.ts +334 -0
  12. package/src/ar/webxr/crosshair/WebXRCrosshair.ts +35 -0
  13. package/src/ar/webxr/origin/WebXROrigin.ts +191 -0
  14. package/src/ar/webxr/overlay/Overlay.ts +50 -0
  15. package/src/ar/webxr/raycaster/WebXRRaycaster.ts +131 -0
  16. package/src/ar/webxr/raycaster/ar/WebXRRaycasterAR.ts +102 -0
  17. package/src/ar/webxr/raycaster/three/WebXRRaycasterTHREE.ts +49 -0
  18. package/src/ar/webxr/touchscreencontrols/WebXRTouchscreenControls.ts +356 -0
  19. package/src/axiscamera/AxisCamera.ts +4 -4
  20. package/src/axiscamera/__test__/AxisCamera.test.ts +4 -0
  21. package/src/com/Communication.ts +17 -0
  22. package/src/com/__test__/Communication.test.ts +1 -1
  23. package/src/com/actions/index.ts +2 -0
  24. package/src/dive.ts +51 -9
  25. package/src/events/EventExecutor.ts +35 -0
  26. package/src/helper/findSceneRecursive/findSceneRecursive.ts +2 -2
  27. package/src/info/Info.ts +37 -1
  28. package/src/info/__test__/Info.test.ts +45 -5
  29. package/src/mediacreator/MediaCreator.ts +4 -4
  30. package/src/mediacreator/__test__/MediaCreator.test.ts +7 -2
  31. package/src/renderer/Renderer.ts +21 -11
  32. package/src/renderer/__test__/Renderer.test.ts +19 -1
  33. package/src/scene/Scene.ts +35 -12
  34. package/src/scene/__test__/Scene.test.ts +39 -5
  35. package/src/scene/root/Root.ts +1 -0
  36. package/src/scene/xrroot/XRRoot.ts +56 -0
  37. package/src/scene/xrroot/xrlightroot/XRLightRoot.ts +80 -0
  38. package/src/toolbox/BaseTool.ts +9 -3
  39. package/src/toolbox/Toolbox.ts +1 -1
  40. package/src/toolbox/__test__/Toolbox.test.ts +1 -1
  41. package/src/toolbox/select/SelectTool.ts +1 -1
  42. package/src/toolbox/select/__test__/SelectTool.test.ts +1 -1
  43. package/src/toolbox/transform/TransformTool.ts +4 -4
  44. package/src/toolbox/transform/__test__/TransformTool.test.ts +2 -4
@@ -21,6 +21,7 @@ import { type DIVEMediaCreator } from '../mediacreator/MediaCreator.ts';
21
21
  import { type DIVERenderer } from '../renderer/Renderer.ts';
22
22
  import { type DIVESelectable } from '../interface/Selectable.ts';
23
23
  import { type DIVEIO } from '../io/IO.ts';
24
+ import { type DIVEAR } from '../ar/AR.ts';
24
25
 
25
26
  type EventListener<Action extends keyof Actions> = (
26
27
  payload: Actions[Action]['PAYLOAD'],
@@ -97,6 +98,16 @@ export class DIVECommunication {
97
98
  return this._io;
98
99
  }
99
100
 
101
+ private _ar: DIVEAR | null;
102
+ private get ar(): DIVEAR {
103
+ if (!this._ar) {
104
+ const DIVEAR = require('../ar/AR.ts')
105
+ .DIVEAR as typeof import('../ar/AR.ts').DIVEAR;
106
+ this._ar = new DIVEAR(this.renderer, this.scene, this.controller);
107
+ }
108
+ return this._ar;
109
+ }
110
+
100
111
  private registered: Map<string, COMEntity> = new Map();
101
112
 
102
113
  // private listeners: { [key: string]: EventListener[] } = {};
@@ -116,6 +127,7 @@ export class DIVECommunication {
116
127
  this.toolbox = toolbox;
117
128
  this._mediaGenerator = null;
118
129
  this._io = null;
130
+ this._ar = null;
119
131
 
120
132
  DIVECommunication.__instances.push(this);
121
133
  }
@@ -292,6 +304,11 @@ export class DIVECommunication {
292
304
  );
293
305
  break;
294
306
  }
307
+ case 'LAUNCH_AR': {
308
+ this.ar.Launch();
309
+ returnValue = true;
310
+ break;
311
+ }
295
312
  default: {
296
313
  console.warn(
297
314
  `DIVECommunication.PerformAction: has been executed with unknown Action type ${action}`,
@@ -21,7 +21,7 @@ import '../actions/scene/updatescene';
21
21
  import '../actions/toolbox/select/setgizmomode';
22
22
  import '../actions/toolbox/transform/setgizmovisible';
23
23
  import '../actions/camera/getcameratransform';
24
- import type { DIVEScene } from '../../scene/Scene';
24
+ import { type DIVEScene } from '../../scene/Scene';
25
25
  import type DIVEToolbox from '../../toolbox/Toolbox';
26
26
  import type DIVEOrbitControls from '../../controls/OrbitControls';
27
27
  import { type DIVERenderer } from '../../renderer/Renderer';
@@ -52,4 +52,6 @@ export interface Actions {
52
52
  GENERATE_MEDIA: GENERATE_MEDIA;
53
53
  SET_PARENT: SET_PARENT;
54
54
  EXPORT_SCENE: EXPORT_SCENE;
55
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
+ LAUNCH_AR: any;
55
57
  }
package/src/dive.ts CHANGED
@@ -17,7 +17,6 @@ import { DIVECommunication } from './com/Communication.ts';
17
17
  import { DIVEAnimationSystem } from './animation/AnimationSystem.ts';
18
18
  import DIVEAxisCamera from './axiscamera/AxisCamera.ts';
19
19
  import { getObjectDelta } from './helper/getObjectDelta/getObjectDelta.ts';
20
-
21
20
  import { generateUUID } from 'three/src/math/MathUtils';
22
21
  import { DIVEInfo } from './info/Info.ts';
23
22
  import pkgjson from '../package.json';
@@ -63,8 +62,11 @@ export const DIVEDefaultSettings: DIVESettings = {
63
62
 
64
63
  export default class DIVE {
65
64
  // static members
66
- public static QuickView(uri: string): DIVE {
67
- const dive = new DIVE();
65
+ public static QuickView(
66
+ uri: string,
67
+ settings?: Partial<DIVESettings>,
68
+ ): DIVE {
69
+ const dive = new DIVE(settings);
68
70
 
69
71
  dive.Communication.PerformAction('SET_CAMERA_TRANSFORM', {
70
72
  position: { x: 0, y: 2, z: 2 },
@@ -92,9 +94,22 @@ export default class DIVE {
92
94
  // add loaded listener
93
95
  dive.Communication.Subscribe('MODEL_LOADED', (data) => {
94
96
  if (data.id !== modelid) return;
95
- dive.Communication.PerformAction('PLACE_ON_FLOOR', {
96
- id: modelid,
97
- });
97
+
98
+ // console.log(
99
+ // dive.Communication.PerformAction('GET_OBJECTS', {
100
+ // ids: [modelid],
101
+ // })[0].position,
102
+ // );
103
+
104
+ // dive.Communication.PerformAction('PLACE_ON_FLOOR', {
105
+ // id: modelid,
106
+ // });
107
+
108
+ // console.log(
109
+ // dive.Communication.PerformAction('GET_OBJECTS', {
110
+ // ids: [modelid],
111
+ // }),
112
+ // );
98
113
 
99
114
  const transform = dive.Communication.PerformAction(
100
115
  'COMPUTE_ENCOMPASSING_VIEW',
@@ -277,9 +292,36 @@ export default class DIVE {
277
292
  },
278
293
  };
279
294
 
280
- console.log(
281
- `DIVE ${pkgjson.version} initialized ${process.env.DIVE_NODE_ENV === 'development' ? 'in development mode' : ''}`,
282
- );
295
+ console.log(`
296
+ @@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@
297
+ @@@@+-:::::::---------------------==------------------------------=#@@@@
298
+ @@%=::::.......::---------------------------------------------------------+@@
299
+ @@+:::...........::-----------------------------------------------------------#@@
300
+ @@=:::.........::::::--------------${' DIVE ' + pkgjson.version.padStart(7, ' ') + ' '}---------------------------------%@
301
+ @%:::.......:::::::-------------------${process.env.DIVE_NODE_ENV === 'development' ? ' DEV MODE ' : '--------------'}------------------------------------#@
302
+ @*:::.....:::::-----------------------------------------------------------------------*@
303
+ @%::::::.::::---------------------------------------------------------------------------@@
304
+ @@-:::::::::-----------------------------------------------------------------------------=@
305
+ @%::::::::--------------------------------------------------------------------------------%@
306
+ @+::::::::--------------------------------=@@@@@%-----------------------------------------%@
307
+ @=:::::::--------------------------------*@@ @@+---------------------------------------#@
308
+ @+:::::::-------------------------------*@ @*--------------------------------------%@
309
+ @#::::::::-----------------------------=@@ @@=-------------------------------------%@
310
+ @@-::::::::----------------------------@@ @@------------------------------------=@
311
+ @%:::::::::--------------------------*@ @*-----------------------------------@@
312
+ @*:::::::::-------------------------@@ @@----------------------------------%@
313
+ @#::::::::::----------------------%@ @%--------------------------------%@
314
+ @#:::::::::::-------------------=@@ @@=------------------------------%@
315
+ @@-::::::::::::----------------%@ @%----------------------------=@@
316
+ @@#::::::::::::::------------*@ @*--------------------------#@@
317
+ @@+::::::::::::::::--------@@ @@------------------------+@@
318
+ @@*:::::::::::::::::----@@ @@---------------------+@@
319
+ @@@-:::::::::::::::--#@ @#-----------------=%@@
320
+ @@%-::::::::::::-%@ @%-------------=%@@
321
+ @@@@+:::::::#@@ @@*-------*@@@@
322
+ @@@@@@@ @@@@@@
323
+
324
+ `);
283
325
  }
284
326
 
285
327
  public Dispose(): void {
@@ -0,0 +1,35 @@
1
+ export class DIVEEventExecutor<T> {
2
+ private _listeners: Map<keyof T, ((payload: T[keyof T]) => void)[]> =
3
+ new Map();
4
+
5
+ public Subscribe<S extends keyof T>(
6
+ type: S,
7
+ listener: (payload: T[S]) => void,
8
+ ): () => boolean {
9
+ if (!this._listeners.get(type)) this._listeners.set(type, []);
10
+
11
+ this._listeners
12
+ .get(type)!
13
+ .push(listener as (payload: T[keyof T]) => void);
14
+
15
+ return () => {
16
+ const listenerArray = this._listeners.get(type);
17
+ if (!listenerArray) return false;
18
+
19
+ const existingIndex = listenerArray.findIndex(
20
+ (entry) => entry === listener,
21
+ );
22
+ if (existingIndex === -1) return false;
23
+
24
+ listenerArray.splice(existingIndex, 1);
25
+ return true;
26
+ };
27
+ }
28
+
29
+ protected dispatch<S extends keyof T>(type: S, payload?: T[S]): void {
30
+ const listenerArray = this._listeners.get(type);
31
+ if (!listenerArray) return;
32
+
33
+ listenerArray.forEach((listener) => listener(payload as T[S]));
34
+ }
35
+ }
@@ -1,5 +1,5 @@
1
- import type { Object3D } from 'three';
2
- import type { DIVEScene } from '../../scene/Scene';
1
+ import { type Object3D } from 'three';
2
+ import { type DIVEScene } from '../../scene/Scene';
3
3
 
4
4
  /**
5
5
  * Find the scene object of an object.
package/src/info/Info.ts CHANGED
@@ -1,5 +1,14 @@
1
+ export enum WebXRUnsupportedReason {
2
+ 'UNKNWON_ERROR' = 0,
3
+ 'NO_HTTPS' = 1,
4
+ 'IMMERSIVE_AR_NOT_SUPPORTED_BY_DEVICE' = 2,
5
+ 'AR_SESSION_NOT_ALLOWED' = 3,
6
+ }
7
+
1
8
  export class DIVEInfo {
2
9
  private static _supportsWebXR: boolean | null = null;
10
+ private static _webXRUnsupportedReason: WebXRUnsupportedReason | null =
11
+ null;
3
12
 
4
13
  /**
5
14
  *
@@ -30,21 +39,48 @@ export class DIVEInfo {
30
39
  return this._supportsWebXR;
31
40
  }
32
41
 
42
+ // check if XRSystem is available && if https enabled
33
43
  if (!navigator.xr) {
34
44
  this._supportsWebXR = false;
45
+
46
+ if (window.isSecureContext === false) {
47
+ this._webXRUnsupportedReason = WebXRUnsupportedReason.NO_HTTPS;
48
+ } else {
49
+ this._webXRUnsupportedReason =
50
+ WebXRUnsupportedReason.UNKNWON_ERROR;
51
+ }
52
+
35
53
  return this._supportsWebXR;
36
54
  }
55
+
37
56
  // Check if immersive-vr session mode is supported
38
57
  try {
39
58
  const supported =
40
- await navigator.xr.isSessionSupported('immersive-ar');
59
+ await navigator.xr!.isSessionSupported('immersive-ar');
60
+ if (!supported) {
61
+ this._webXRUnsupportedReason =
62
+ WebXRUnsupportedReason.IMMERSIVE_AR_NOT_SUPPORTED_BY_DEVICE;
63
+ }
41
64
  this._supportsWebXR = supported;
42
65
  } catch (error) {
43
66
  this._supportsWebXR = false;
67
+ this._webXRUnsupportedReason =
68
+ WebXRUnsupportedReason.AR_SESSION_NOT_ALLOWED;
44
69
  }
45
70
  return this._supportsWebXR;
46
71
  }
47
72
 
73
+ /**
74
+ * @returns The reason why WebXR is not supported on the user's device. Returns null if WebXR is supported nor not has been checked yet.
75
+ */
76
+ public static GetWebXRUnsupportedReason(): WebXRUnsupportedReason | null {
77
+ if (this._supportsWebXR === null) {
78
+ console.log('WebXR support has not been checked yet.');
79
+ return null;
80
+ }
81
+ return this._webXRUnsupportedReason;
82
+ }
83
+
48
84
  /**
49
85
  * @returns A boolean indicating whether the user's device supports AR Quick Look.
50
86
  */
@@ -1,4 +1,4 @@
1
- import { DIVEInfo } from '../Info';
1
+ import { DIVEInfo, WebXRUnsupportedReason } from '../Info';
2
2
 
3
3
  const mockNavigator = (navigator: any) => {
4
4
  Object.defineProperty(global, 'navigator', {
@@ -60,7 +60,6 @@ describe('dive/info/DIVEInfo', () => {
60
60
  });
61
61
 
62
62
  it('should support webXR', async () => {
63
- DIVEInfo['_supportsWebXR'] = null;
64
63
  mockNavigator({
65
64
  xr: {
66
65
  isSessionSupported: jest.fn().mockResolvedValue(true),
@@ -71,16 +70,50 @@ describe('dive/info/DIVEInfo', () => {
71
70
  });
72
71
 
73
72
  it('should not support webXR (xr undefined)', async () => {
74
- DIVEInfo['_supportsWebXR'] = null;
75
73
  mockNavigator({
76
74
  xr: undefined,
77
75
  });
78
76
  const supports = await DIVEInfo.GetSupportsWebXR();
79
77
  expect(supports).toBe(false);
78
+
79
+ const reason = DIVEInfo.GetWebXRUnsupportedReason();
80
+ expect(reason).toBe(WebXRUnsupportedReason.UNKNWON_ERROR);
81
+ });
82
+
83
+ it('should not support webXR (xr undefined & isSecureContext false)', async () => {
84
+ window.isSecureContext = false;
85
+ mockNavigator({
86
+ xr: undefined,
87
+ });
88
+ const supports = await DIVEInfo.GetSupportsWebXR();
89
+ expect(supports).toBe(false);
90
+
91
+ const reason = DIVEInfo.GetWebXRUnsupportedReason();
92
+ expect(reason).toBe(WebXRUnsupportedReason.NO_HTTPS);
93
+ });
94
+
95
+ it('should get empty reason (not checked)', async () => {
96
+ mockNavigator({
97
+ xr: {
98
+ isSessionSupported: jest.fn().mockResolvedValue(true),
99
+ },
100
+ });
101
+ console.log = jest.fn();
102
+ const reason = DIVEInfo.GetWebXRUnsupportedReason();
103
+ expect(reason).toBe(null);
104
+ });
105
+
106
+ it('should get empty reason (webXR supported)', async () => {
107
+ mockNavigator({
108
+ xr: {
109
+ isSessionSupported: jest.fn().mockResolvedValue(true),
110
+ },
111
+ });
112
+ const reason = DIVEInfo.GetWebXRUnsupportedReason();
113
+ expect(reason).toBe(null);
80
114
  });
81
115
 
82
116
  it('should not support webXR', async () => {
83
- DIVEInfo['_supportsWebXR'] = null;
84
117
  mockNavigator({
85
118
  xr: {
86
119
  isSessionSupported: jest.fn().mockResolvedValue(false),
@@ -88,10 +121,14 @@ describe('dive/info/DIVEInfo', () => {
88
121
  });
89
122
  const supports = await DIVEInfo.GetSupportsWebXR();
90
123
  expect(supports).toBe(false);
124
+
125
+ const reason = DIVEInfo.GetWebXRUnsupportedReason();
126
+ expect(reason).toBe(
127
+ WebXRUnsupportedReason.IMMERSIVE_AR_NOT_SUPPORTED_BY_DEVICE,
128
+ );
91
129
  });
92
130
 
93
131
  it('should not support webXR on error', async () => {
94
- DIVEInfo['_supportsWebXR'] = null;
95
132
  mockNavigator({
96
133
  xr: {
97
134
  isSessionSupported: jest.fn().mockRejectedValue('error'),
@@ -99,6 +136,9 @@ describe('dive/info/DIVEInfo', () => {
99
136
  });
100
137
  const supports = await DIVEInfo.GetSupportsWebXR();
101
138
  expect(supports).toBe(false);
139
+
140
+ const reason = DIVEInfo.GetWebXRUnsupportedReason();
141
+ expect(reason).toBe(WebXRUnsupportedReason.AR_SESSION_NOT_ALLOWED);
102
142
  });
103
143
 
104
144
  it('should return cached value', async () => {
@@ -1,8 +1,8 @@
1
1
  import DIVEPerspectiveCamera from '../camera/PerspectiveCamera.ts';
2
- import { DIVEScene } from '../scene/Scene.ts';
3
- import { DIVERenderer } from '../renderer/Renderer.ts';
4
- import DIVEOrbitControls from '../controls/OrbitControls.ts';
5
- import { Vector3Like } from 'three';
2
+ import { type DIVEScene } from '../scene/Scene.ts';
3
+ import { type DIVERenderer } from '../renderer/Renderer.ts';
4
+ import type DIVEOrbitControls from '../controls/OrbitControls.ts';
5
+ import { type Vector3Like } from 'three';
6
6
 
7
7
  /**
8
8
  * Creates renderings of the current scene
@@ -17,8 +17,13 @@ const mock_toDataURL = jest.fn();
17
17
 
18
18
  jest.mock('../../scene/Scene', () => {
19
19
  return {
20
- DIVEScene: jest.fn(() => {
21
- return {};
20
+ DIVEScene: jest.fn(function () {
21
+ this.add = jest.fn();
22
+ this.children = [];
23
+ this.Root = {
24
+ children: [],
25
+ };
26
+ return this;
22
27
  }),
23
28
  };
24
29
  });
@@ -29,6 +29,11 @@ export const DIVERendererDefaultSettings: DIVERendererSettings = {
29
29
  canvas: undefined,
30
30
  };
31
31
 
32
+ export type DIVERenderCallback = (
33
+ time: DOMHighResTimeStamp,
34
+ frame: XRFrame,
35
+ ) => void;
36
+
32
37
  /**
33
38
  * A changed version of the WebGLRenderer.
34
39
  *
@@ -44,13 +49,13 @@ export class DIVERenderer extends WebGLRenderer {
44
49
  private force: boolean = false;
45
50
 
46
51
  // pre- and post-render callbacks
47
- private preRenderCallbacks: Map<string, () => void> = new Map<
52
+ private preRenderCallbacks: Map<string, DIVERenderCallback> = new Map<
48
53
  string,
49
- () => void
54
+ DIVERenderCallback
50
55
  >();
51
- private postRenderCallbacks: Map<string, () => void> = new Map<
56
+ private postRenderCallbacks: Map<string, DIVERenderCallback> = new Map<
52
57
  string,
53
- () => void
58
+ DIVERenderCallback
54
59
  >();
55
60
 
56
61
  constructor(
@@ -88,8 +93,8 @@ export class DIVERenderer extends WebGLRenderer {
88
93
 
89
94
  // Starts the renderer with the given scene and camera.
90
95
  public StartRenderer(scene: Scene, cam: Camera): void {
91
- this.setAnimationLoop(() => {
92
- this.internal_render(scene, cam);
96
+ this.setAnimationLoop((time: DOMHighResTimeStamp, frame: XRFrame) => {
97
+ this.internal_render(scene, cam, time, frame);
93
98
  });
94
99
  this.running = true;
95
100
  }
@@ -120,7 +125,7 @@ export class DIVERenderer extends WebGLRenderer {
120
125
  * @param callback Executed before rendering.
121
126
  * @returns uuid to remove the callback.
122
127
  */
123
- public AddPreRenderCallback(callback: () => void): string {
128
+ public AddPreRenderCallback(callback: DIVERenderCallback): string {
124
129
  // add callback to renderloop
125
130
  const newUUID = MathUtils.generateUUID();
126
131
  this.preRenderCallbacks.set(newUUID, callback);
@@ -148,7 +153,7 @@ export class DIVERenderer extends WebGLRenderer {
148
153
  * @param callback Executed after rendering.
149
154
  * @returns uuid to remove the callback.
150
155
  */
151
- public AddPostRenderCallback(callback: () => void): string {
156
+ public AddPostRenderCallback(callback: DIVERenderCallback): string {
152
157
  // add callback to renderloop
153
158
  const newUUID = MathUtils.generateUUID();
154
159
  this.postRenderCallbacks.set(newUUID, callback);
@@ -185,19 +190,24 @@ export class DIVERenderer extends WebGLRenderer {
185
190
  * @param scene Scene to render.
186
191
  * @param cam Camera to render with.
187
192
  */
188
- private internal_render(scene: Scene, cam: Camera): void {
193
+ private internal_render(
194
+ scene: Scene,
195
+ cam: Camera,
196
+ time: DOMHighResTimeStamp,
197
+ frame: XRFrame,
198
+ ): void {
189
199
  // execute background render loop callbacks
190
200
  if ((this.paused || !this.running) && !this.force) return;
191
201
 
192
202
  // execute render loop callbacks
193
203
  this.preRenderCallbacks.forEach((callback) => {
194
- callback();
204
+ callback(time, frame);
195
205
  });
196
206
 
197
207
  this.render(scene, cam);
198
208
 
199
209
  this.postRenderCallbacks.forEach((callback) => {
200
- callback();
210
+ callback(time, frame);
201
211
  });
202
212
 
203
213
  this.force = false;
@@ -1,5 +1,5 @@
1
1
  import type DIVEPerspectiveCamera from '../../camera/PerspectiveCamera';
2
- import type { DIVEScene } from '../../scene/Scene';
2
+ import { type DIVEScene } from '../../scene/Scene';
3
3
  import { DIVERenderer, DIVERendererDefaultSettings } from '../Renderer';
4
4
 
5
5
  /**
@@ -123,6 +123,8 @@ describe('dive/renderer/DIVERenderer', () => {
123
123
  renderer['internal_render'](
124
124
  {} as DIVEScene,
125
125
  {} as DIVEPerspectiveCamera,
126
+ 0.016,
127
+ {} as XRFrame,
126
128
  );
127
129
  }).not.toThrow();
128
130
  expect(mock_render).toHaveBeenCalledTimes(1);
@@ -139,6 +141,8 @@ describe('dive/renderer/DIVERenderer', () => {
139
141
  renderer['internal_render'](
140
142
  {} as DIVEScene,
141
143
  {} as DIVEPerspectiveCamera,
144
+ 0.016,
145
+ {} as XRFrame,
142
146
  );
143
147
  expect(mock_render).toHaveBeenCalledTimes(0);
144
148
  });
@@ -148,6 +152,8 @@ describe('dive/renderer/DIVERenderer', () => {
148
152
  renderer['internal_render'](
149
153
  {} as DIVEScene,
150
154
  {} as DIVEPerspectiveCamera,
155
+ 0.016,
156
+ {} as XRFrame,
151
157
  );
152
158
  expect(mock_render).toHaveBeenCalledTimes(1);
153
159
 
@@ -155,6 +161,8 @@ describe('dive/renderer/DIVERenderer', () => {
155
161
  renderer['internal_render'](
156
162
  {} as DIVEScene,
157
163
  {} as DIVEPerspectiveCamera,
164
+ 0.016,
165
+ {} as XRFrame,
158
166
  );
159
167
  expect(mock_render).toHaveBeenCalledTimes(1);
160
168
  });
@@ -164,6 +172,8 @@ describe('dive/renderer/DIVERenderer', () => {
164
172
  renderer['internal_render'](
165
173
  {} as DIVEScene,
166
174
  {} as DIVEPerspectiveCamera,
175
+ 0.016,
176
+ {} as XRFrame,
167
177
  );
168
178
  expect(mock_render).toHaveBeenCalledTimes(1);
169
179
 
@@ -171,6 +181,8 @@ describe('dive/renderer/DIVERenderer', () => {
171
181
  renderer['internal_render'](
172
182
  {} as DIVEScene,
173
183
  {} as DIVEPerspectiveCamera,
184
+ 0.016,
185
+ {} as XRFrame,
174
186
  );
175
187
  expect(mock_render).toHaveBeenCalledTimes(1);
176
188
  });
@@ -181,6 +193,8 @@ describe('dive/renderer/DIVERenderer', () => {
181
193
  renderer['internal_render'](
182
194
  {} as DIVEScene,
183
195
  {} as DIVEPerspectiveCamera,
196
+ 0.016,
197
+ {} as XRFrame,
184
198
  );
185
199
  expect(mock_render).toHaveBeenCalledTimes(0);
186
200
 
@@ -188,6 +202,8 @@ describe('dive/renderer/DIVERenderer', () => {
188
202
  renderer['internal_render'](
189
203
  {} as DIVEScene,
190
204
  {} as DIVEPerspectiveCamera,
205
+ 0.016,
206
+ {} as XRFrame,
191
207
  );
192
208
  expect(mock_render).toHaveBeenCalledTimes(1);
193
209
  });
@@ -233,6 +249,8 @@ describe('dive/renderer/DIVERenderer', () => {
233
249
  renderer['internal_render'](
234
250
  {} as DIVEScene,
235
251
  {} as DIVEPerspectiveCamera,
252
+ 0.016,
253
+ {} as XRFrame,
236
254
  );
237
255
  expect(precallback).toHaveBeenCalledTimes(1);
238
256
  expect(postcallback).toHaveBeenCalledTimes(1);
@@ -4,6 +4,8 @@ import { DIVERoot } from './root/Root';
4
4
  import { DIVEGrid } from '../grid/Grid';
5
5
  import { DIVEFloor } from '../primitive/floor/Floor';
6
6
  import { type DIVESceneObject } from '../types';
7
+ import { DIVEXRRoot } from './xrroot/XRRoot';
8
+ import { type DIVERenderer } from '../renderer/Renderer';
7
9
 
8
10
  /**
9
11
  * A basic scene class.
@@ -14,20 +16,25 @@ import { type DIVESceneObject } from '../types';
14
16
  */
15
17
 
16
18
  export class DIVEScene extends Scene {
17
- private root: DIVERoot;
18
- private floor: DIVEFloor;
19
- private grid: DIVEGrid;
19
+ private _root: DIVERoot;
20
+ private _floor: DIVEFloor;
21
+ private _grid: DIVEGrid;
20
22
 
21
23
  public get Root(): DIVERoot {
22
- return this.root;
24
+ return this._root;
25
+ }
26
+
27
+ private _xrRoot: DIVEXRRoot;
28
+ public get XRRoot(): DIVEXRRoot {
29
+ return this._xrRoot;
23
30
  }
24
31
 
25
32
  public get Floor(): DIVEFloor {
26
- return this.floor;
33
+ return this._floor;
27
34
  }
28
35
 
29
36
  public get Grid(): DIVEGrid {
30
- return this.grid;
37
+ return this._grid;
31
38
  }
32
39
 
33
40
  constructor() {
@@ -35,14 +42,30 @@ export class DIVEScene extends Scene {
35
42
 
36
43
  this.background = new Color(0xffffff);
37
44
 
38
- this.root = new DIVERoot();
39
- this.add(this.root);
45
+ this._root = new DIVERoot();
46
+ this.add(this._root);
47
+
48
+ this._floor = new DIVEFloor();
49
+ this.add(this._floor);
50
+
51
+ this._grid = new DIVEGrid();
52
+ this.add(this._grid);
40
53
 
41
- this.floor = new DIVEFloor();
42
- this.add(this.floor);
54
+ this._xrRoot = new DIVEXRRoot(this);
55
+ this._xrRoot.visible = false;
56
+ this.add(this._xrRoot);
57
+ }
58
+
59
+ public InitXR(renderer: DIVERenderer): void {
60
+ this._root.visible = false;
61
+ this._xrRoot.visible = true;
62
+ this._xrRoot.InitLightEstimation(renderer);
63
+ }
43
64
 
44
- this.grid = new DIVEGrid();
45
- this.add(this.grid);
65
+ public DisposeXR(): void {
66
+ this._root.visible = true;
67
+ this._xrRoot.visible = false;
68
+ this._xrRoot.DisposeLightEstimation();
46
69
  }
47
70
 
48
71
  public SetBackground(color: ColorRepresentation): void {