@shopware-ag/dive 1.5.0 → 1.6.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.
- package/README.md +38 -25
- package/build/dive.cjs +717 -500
- package/build/dive.cjs.map +1 -1
- package/build/dive.d.cts +174 -113
- package/build/dive.d.ts +174 -113
- package/build/dive.js +716 -486
- package/build/dive.js.map +1 -1
- package/package.json +1 -1
- package/src/__test__/DIVE.test.ts +66 -22
- package/src/animation/AnimationSystem.ts +16 -0
- package/src/animation/__test__/AnimationSystem.test.ts +23 -2
- package/src/axiscamera/AxisCamera.ts +40 -2
- package/src/axiscamera/__test__/AxisCamera.test.ts +178 -5
- package/src/com/Communication.ts +50 -16
- package/src/com/__test__/Communication.test.ts +73 -24
- package/src/com/actions/camera/computeencompassingview.ts +9 -0
- package/src/com/actions/index.ts +2 -0
- package/src/com/actions/scene/updatescene.ts +1 -0
- package/src/controls/OrbitControls.ts +14 -2
- package/src/controls/__test__/OrbitControls.test.ts +31 -4
- package/src/dive.ts +93 -33
- package/src/grid/Grid.ts +4 -0
- package/src/grid/__test__/Grid.test.ts +7 -0
- package/src/interface/Selectable.ts +17 -0
- package/src/interface/__test__/Interfaces.test.ts +18 -0
- package/src/mediacreator/MediaCreator.ts +2 -2
- package/src/mediacreator/__test__/MediaCreator.test.ts +12 -10
- package/src/renderer/Renderer.ts +7 -1
- package/src/renderer/__test__/Renderer.test.ts +14 -5
- package/src/scene/Scene.ts +8 -2
- package/src/scene/__test__/Scene.test.ts +6 -0
- package/src/scene/root/Root.ts +11 -1
- package/src/scene/root/__test__/Root.test.ts +68 -2
- package/src/toolbox/BaseTool.ts +1 -1
- package/src/toolbox/Toolbox.ts +53 -37
- package/src/toolbox/__test__/BaseTool.test.ts +43 -7
- package/src/toolbox/__test__/Toolbox.test.ts +39 -44
- package/src/toolbox/select/SelectTool.ts +17 -28
- package/src/toolbox/select/__test__/SelectTool.test.ts +21 -12
- package/src/toolbox/transform/TransformTool.ts +7 -1
- package/src/toolbox/transform/__test__/TransformTool.test.ts +22 -5
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import DIVECommunication from '../Communication';
|
|
2
|
-
import DIVEScene from '../../scene/Scene';
|
|
3
|
-
import DIVEToolbox from '../../toolbox/Toolbox';
|
|
4
|
-
import DIVEMediaCreator from '../../mediacreator/MediaCreator';
|
|
5
2
|
import '..';
|
|
6
3
|
import '../types';
|
|
7
4
|
import '../actions';
|
|
@@ -25,9 +22,13 @@ import '../actions/scene/updatescene';
|
|
|
25
22
|
import '../actions/toolbox/select/setgizmomode';
|
|
26
23
|
import '../actions/toolbox/transform/setgizmovisible';
|
|
27
24
|
import '../actions/camera/getcameratransform';
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import
|
|
25
|
+
import type DIVEScene from '../../scene/Scene';
|
|
26
|
+
import type DIVEToolbox from '../../toolbox/Toolbox';
|
|
27
|
+
import type DIVEOrbitControls from '../../controls/OrbitControls';
|
|
28
|
+
import { type DIVERenderer } from '../../renderer/Renderer';
|
|
29
|
+
import { type COMLight, type COMModel, type COMPov } from '../types';
|
|
30
|
+
import { type Object3D } from 'three';
|
|
31
|
+
import { DIVESelectTool, isSelectTool } from '../../toolbox/select/SelectTool';
|
|
31
32
|
|
|
32
33
|
jest.mock('three/src/math/MathUtils', () => {
|
|
33
34
|
return {
|
|
@@ -35,6 +36,33 @@ jest.mock('three/src/math/MathUtils', () => {
|
|
|
35
36
|
}
|
|
36
37
|
});
|
|
37
38
|
|
|
39
|
+
jest.mock('../../mediacreator/MediaCreator', () => {
|
|
40
|
+
return {
|
|
41
|
+
default: jest.fn(function () {
|
|
42
|
+
this.GenerateMedia = jest.fn();
|
|
43
|
+
|
|
44
|
+
return this;
|
|
45
|
+
}),
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
jest.mock('../../toolbox/select/SelectTool', () => {
|
|
50
|
+
return {
|
|
51
|
+
isSelectTool: jest.fn().mockReturnValue(true),
|
|
52
|
+
DIVESelectTool: jest.fn().mockImplementation(() => {
|
|
53
|
+
return {
|
|
54
|
+
AttachGizmo: jest.fn(),
|
|
55
|
+
DetachGizmo: jest.fn(),
|
|
56
|
+
};
|
|
57
|
+
}),
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const mockRenderer = {
|
|
62
|
+
render: jest.fn(),
|
|
63
|
+
OnResize: jest.fn(),
|
|
64
|
+
} as unknown as DIVERenderer;
|
|
65
|
+
|
|
38
66
|
const mockScene = {
|
|
39
67
|
SetBackground: jest.fn(),
|
|
40
68
|
AddSceneObject: jest.fn(),
|
|
@@ -56,8 +84,12 @@ const mockScene = {
|
|
|
56
84
|
},
|
|
57
85
|
SetVisibility: jest.fn(),
|
|
58
86
|
SetColor: jest.fn(),
|
|
59
|
-
}
|
|
87
|
+
},
|
|
88
|
+
Grid: {
|
|
89
|
+
SetVisibility: jest.fn(),
|
|
90
|
+
},
|
|
60
91
|
},
|
|
92
|
+
ComputeSceneBB: jest.fn(),
|
|
61
93
|
} as unknown as DIVEScene;
|
|
62
94
|
|
|
63
95
|
const mockController = {
|
|
@@ -108,33 +140,44 @@ const mockController = {
|
|
|
108
140
|
clone: jest.fn().mockReturnValue({ x: 1, y: 2, z: 3 }),
|
|
109
141
|
copy: jest.fn(),
|
|
110
142
|
},
|
|
143
|
+
quaternion: {
|
|
144
|
+
x: 1,
|
|
145
|
+
y: 2,
|
|
146
|
+
z: 3,
|
|
147
|
+
w: 4,
|
|
148
|
+
clone: jest.fn().mockReturnValue({ x: 1, y: 2, z: 3, w: 4 }),
|
|
149
|
+
copy: jest.fn(),
|
|
150
|
+
},
|
|
111
151
|
SetCameraLayer: jest.fn(),
|
|
152
|
+
OnResize: jest.fn(),
|
|
153
|
+
layers: {
|
|
154
|
+
mask: 1,
|
|
155
|
+
},
|
|
112
156
|
},
|
|
113
157
|
MoveTo: jest.fn(),
|
|
114
158
|
RevertLast: jest.fn(),
|
|
159
|
+
ComputeEncompassingView: jest.fn().mockReturnValue({
|
|
160
|
+
position: { x: 1, y: 2, z: 3 },
|
|
161
|
+
target: { x: 4, y: 5, z: 6 }
|
|
162
|
+
}),
|
|
115
163
|
} as unknown as DIVEOrbitControls;
|
|
116
164
|
|
|
117
|
-
const mockAttach = jest.fn();
|
|
118
|
-
const mockDetach = jest.fn();
|
|
119
165
|
const mockToolBox = {
|
|
120
166
|
UseTool: jest.fn(),
|
|
121
167
|
GetActiveTool: jest.fn().mockReturnValue({
|
|
122
|
-
AttachGizmo:
|
|
123
|
-
DetachGizmo:
|
|
168
|
+
AttachGizmo: jest.fn(),
|
|
169
|
+
DetachGizmo: jest.fn(),
|
|
124
170
|
}),
|
|
125
171
|
SetGizmoMode: jest.fn(),
|
|
126
172
|
SetGizmoVisibility: jest.fn(),
|
|
127
173
|
} as unknown as DIVEToolbox;
|
|
128
174
|
|
|
129
|
-
const mockMediaCreator = {
|
|
130
|
-
GenerateMedia: jest.fn(),
|
|
131
|
-
} as unknown as DIVEMediaCreator;
|
|
132
175
|
let testCom: DIVECommunication;
|
|
133
176
|
|
|
134
177
|
|
|
135
178
|
describe('dive/communication/DIVECommunication', () => {
|
|
136
179
|
beforeEach(() => {
|
|
137
|
-
testCom = new DIVECommunication(mockScene, mockController, mockToolBox
|
|
180
|
+
testCom = new DIVECommunication(mockRenderer, mockScene, mockController, mockToolBox);
|
|
138
181
|
});
|
|
139
182
|
|
|
140
183
|
afterEach(() => {
|
|
@@ -193,13 +236,6 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
193
236
|
expect(() => testCom.PerformAction('ADD_OBJECT', payload)).not.toThrow();
|
|
194
237
|
});
|
|
195
238
|
|
|
196
|
-
// it('should not dispatch with invalid action type', () => {
|
|
197
|
-
// const listener = jest.fn();
|
|
198
|
-
// testCom.Subscribe('GET_ALL_OBJECTS', listener);
|
|
199
|
-
// testCom.dispatch('INVALID_ACTION_TYPE', {});
|
|
200
|
-
// expect(listener).toHaveBeenCalledTimes(0);
|
|
201
|
-
// });
|
|
202
|
-
|
|
203
239
|
it('should perform action ADD_OBJECT', () => {
|
|
204
240
|
const payload = {
|
|
205
241
|
entityType: "light",
|
|
@@ -434,6 +470,19 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
434
470
|
expect(successSet).toBe(true);
|
|
435
471
|
});
|
|
436
472
|
|
|
473
|
+
it('should perform action COMPUTE_ENCOMPASSING_VIEW', () => {
|
|
474
|
+
const payload = {};
|
|
475
|
+
const transform = testCom.PerformAction('COMPUTE_ENCOMPASSING_VIEW', payload);
|
|
476
|
+
expect(transform).toStrictEqual({
|
|
477
|
+
position: { x: 1, y: 2, z: 3 },
|
|
478
|
+
target: { x: 4, y: 5, z: 6 }
|
|
479
|
+
});
|
|
480
|
+
expect(payload).toStrictEqual({
|
|
481
|
+
position: { x: 1, y: 2, z: 3 },
|
|
482
|
+
target: { x: 4, y: 5, z: 6 }
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
|
|
437
486
|
it('should perform action GET_ALL_SCENE_DATA', () => {
|
|
438
487
|
testCom.PerformAction('ADD_OBJECT', {
|
|
439
488
|
entityType: "pov",
|
|
@@ -544,7 +593,6 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
544
593
|
jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true } as unknown as Object3D);
|
|
545
594
|
const success3 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0' });
|
|
546
595
|
expect(success3).toBe(true);
|
|
547
|
-
expect(mockAttach).toHaveBeenCalledTimes(1);
|
|
548
596
|
});
|
|
549
597
|
|
|
550
598
|
it('should perform action DESELECT_OBJECT', () => {
|
|
@@ -570,7 +618,6 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
570
618
|
jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true } as unknown as Object3D);
|
|
571
619
|
const success3 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0' });
|
|
572
620
|
expect(success3).toBe(true);
|
|
573
|
-
expect(mockDetach).toHaveBeenCalledTimes(1);
|
|
574
621
|
});
|
|
575
622
|
|
|
576
623
|
it('should perform action SET_CAMERA_TRANSFORM', () => {
|
|
@@ -647,6 +694,7 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
647
694
|
backgroundColor: 'ffffff',
|
|
648
695
|
floorEnabled: true,
|
|
649
696
|
floorColor: 'ffffff',
|
|
697
|
+
gridEnabled: true,
|
|
650
698
|
});
|
|
651
699
|
expect(success0).toBe(true);
|
|
652
700
|
|
|
@@ -655,6 +703,7 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
655
703
|
backgroundColor: undefined,
|
|
656
704
|
floorEnabled: undefined,
|
|
657
705
|
floorColor: undefined,
|
|
706
|
+
gridEnabled: undefined,
|
|
658
707
|
});
|
|
659
708
|
expect(success1).toBe(true);
|
|
660
709
|
});
|
package/src/com/actions/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import DESELECT_OBJECT from "./object/deselectobject.ts";
|
|
|
20
20
|
import GET_CAMERA_TRANSFORM from "./camera/getcameratransform.ts";
|
|
21
21
|
import DROP_IT from "./object/model/dropit.ts";
|
|
22
22
|
import SET_GIZMO_VISIBILITY from "./toolbox/transform/setgizmovisible.js";
|
|
23
|
+
import COMPUTE_ENCOMPASSING_VIEW from "./camera/computeencompassingview.ts";
|
|
23
24
|
|
|
24
25
|
export type Actions = {
|
|
25
26
|
GET_ALL_SCENE_DATA: GET_ALL_SCENE_DATA,
|
|
@@ -37,6 +38,7 @@ export type Actions = {
|
|
|
37
38
|
GET_CAMERA_TRANSFORM: GET_CAMERA_TRANSFORM,
|
|
38
39
|
MOVE_CAMERA: MOVE_CAMERA,
|
|
39
40
|
RESET_CAMERA: RESET_CAMERA,
|
|
41
|
+
COMPUTE_ENCOMPASSING_VIEW: COMPUTE_ENCOMPASSING_VIEW,
|
|
40
42
|
SET_CAMERA_LAYER: SET_CAMERA_LAYER,
|
|
41
43
|
ZOOM_CAMERA: ZOOM_CAMERA,
|
|
42
44
|
SET_GIZMO_MODE: SET_GIZMO_MODE,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OrbitControls } from "three/examples/jsm/Addons.js";
|
|
2
2
|
import DIVEPerspectiveCamera from "../camera/PerspectiveCamera.ts";
|
|
3
|
-
import DIVERenderer from "../renderer/Renderer.ts";
|
|
4
|
-
import { MathUtils, Vector3Like } from "three";
|
|
3
|
+
import { DIVERenderer } from "../renderer/Renderer.ts";
|
|
4
|
+
import { type Box3, MathUtils, Vector3, Vector3Like } from "three";
|
|
5
5
|
import { Easing, Tween } from "@tweenjs/tween.js";
|
|
6
6
|
|
|
7
7
|
export type DIVEOrbitControlsSettings = {
|
|
@@ -49,6 +49,18 @@ export default class DIVEOrbitControls extends OrbitControls {
|
|
|
49
49
|
this.dampingFactor = settings.dampingFactor;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
public ComputeEncompassingView(bb: Box3): { position: Vector3Like, target: Vector3Like } {
|
|
53
|
+
const center = bb.getCenter(new Vector3());
|
|
54
|
+
const size = bb.getSize(new Vector3());
|
|
55
|
+
const distance = Math.max(size.x, size.y, size.z) * 1.25;
|
|
56
|
+
const direction = this.object.position.clone().normalize();
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
position: direction.multiplyScalar(distance),
|
|
60
|
+
target: center,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
public ZoomIn(by?: number): void {
|
|
53
65
|
const zoomBy = by || DIVEOrbitControls.DEFAULT_ZOOM_FACTOR;
|
|
54
66
|
const { minDistance, maxDistance } = this;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import DIVEOrbitControls from '../OrbitControls';
|
|
2
|
-
import DIVEPerspectiveCamera from '../../camera/PerspectiveCamera';
|
|
3
|
-
import
|
|
2
|
+
import type DIVEPerspectiveCamera from '../../camera/PerspectiveCamera';
|
|
3
|
+
import { DIVERenderer } from '../../renderer/Renderer';
|
|
4
|
+
import { Box3 } from 'three';
|
|
4
5
|
|
|
5
6
|
jest.mock('three/examples/jsm/Addons.js', () => {
|
|
6
7
|
return {
|
|
@@ -88,11 +89,32 @@ const moveToDuration = 1000;
|
|
|
88
89
|
|
|
89
90
|
const mockCamera = {
|
|
90
91
|
position: {
|
|
91
|
-
clone: jest.fn()
|
|
92
|
+
clone: jest.fn(() => {
|
|
93
|
+
return mockCamera.position;
|
|
94
|
+
}),
|
|
95
|
+
normalize: jest.fn(() => {
|
|
96
|
+
return mockCamera.position;
|
|
97
|
+
}),
|
|
98
|
+
multiplyScalar: jest.fn(() => {
|
|
99
|
+
return mockCamera.position;
|
|
100
|
+
}),
|
|
92
101
|
},
|
|
93
102
|
lookAt: jest.fn(),
|
|
94
103
|
} as unknown as DIVEPerspectiveCamera;
|
|
95
|
-
const mockRenderer
|
|
104
|
+
const mockRenderer = {
|
|
105
|
+
render: jest.fn(),
|
|
106
|
+
OnResize: jest.fn(),
|
|
107
|
+
getViewport: jest.fn(),
|
|
108
|
+
setViewport: jest.fn(),
|
|
109
|
+
AddPreRenderCallback: jest.fn((callback) => {
|
|
110
|
+
callback();
|
|
111
|
+
}),
|
|
112
|
+
AddPostRenderCallback: jest.fn((callback) => {
|
|
113
|
+
callback();
|
|
114
|
+
}),
|
|
115
|
+
RemovePreRenderCallback: jest.fn(),
|
|
116
|
+
RemovePostRenderCallback: jest.fn(),
|
|
117
|
+
} as unknown as DIVERenderer;
|
|
96
118
|
|
|
97
119
|
describe('dive/controls/DIVEOrbitControls', () => {
|
|
98
120
|
afterEach(() => {
|
|
@@ -104,6 +126,11 @@ describe('dive/controls/DIVEOrbitControls', () => {
|
|
|
104
126
|
expect(controller).toBeDefined();
|
|
105
127
|
});
|
|
106
128
|
|
|
129
|
+
it('should compute encompassing view', () => {
|
|
130
|
+
const controller = new DIVEOrbitControls(mockCamera, mockRenderer);
|
|
131
|
+
expect(() => controller.ComputeEncompassingView(new Box3())).not.toThrow();
|
|
132
|
+
});
|
|
133
|
+
|
|
107
134
|
it('should zoom in with default value', () => {
|
|
108
135
|
const controller = new DIVEOrbitControls(mockCamera, mockRenderer);
|
|
109
136
|
expect(() => controller.ZoomIn()).not.toThrow();
|
package/src/dive.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import DIVERenderer, { DIVERendererDefaultSettings, DIVERendererSettings } from "./renderer/Renderer.ts";
|
|
1
|
+
import { DIVERenderer, DIVERendererDefaultSettings, DIVERendererSettings } from "./renderer/Renderer.ts";
|
|
3
2
|
import DIVEScene from "./scene/Scene.ts";
|
|
4
3
|
import DIVEPerspectiveCamera, { DIVEPerspectiveCameraDefaultSettings, DIVEPerspectiveCameraSettings } from "./camera/PerspectiveCamera.ts";
|
|
5
4
|
import DIVEOrbitControls, { DIVEOrbitControlsDefaultSettings, DIVEOrbitControlsSettings } from "./controls/OrbitControls.ts";
|
|
6
|
-
import DIVEMediaCreator from "./mediacreator/MediaCreator.ts";
|
|
7
5
|
import DIVEToolbox from "./toolbox/Toolbox.ts";
|
|
8
6
|
import DIVECommunication from "./com/Communication.ts";
|
|
9
7
|
import DIVEAnimationSystem from "./animation/AnimationSystem.ts";
|
|
@@ -13,9 +11,11 @@ import { getObjectDelta } from "./helper/getObjectDelta/getObjectDelta.ts";
|
|
|
13
11
|
import type { Actions } from './com/actions/index.ts';
|
|
14
12
|
import type { COMPov, COMLight, COMModel, COMEntity } from './com/types.ts';
|
|
15
13
|
import { DIVEMath } from './math/index.ts';
|
|
14
|
+
import { generateUUID } from "three/src/math/MathUtils";
|
|
16
15
|
|
|
17
16
|
export type DIVESettings = {
|
|
18
17
|
autoResize: boolean;
|
|
18
|
+
displayAxes: boolean;
|
|
19
19
|
renderer: DIVERendererSettings;
|
|
20
20
|
perspectiveCamera: DIVEPerspectiveCameraSettings;
|
|
21
21
|
orbitControls: DIVEOrbitControlsSettings;
|
|
@@ -23,6 +23,7 @@ export type DIVESettings = {
|
|
|
23
23
|
|
|
24
24
|
export const DIVEDefaultSettings: DIVESettings = {
|
|
25
25
|
autoResize: true,
|
|
26
|
+
displayAxes: false,
|
|
26
27
|
renderer: DIVERendererDefaultSettings,
|
|
27
28
|
perspectiveCamera: DIVEPerspectiveCameraDefaultSettings,
|
|
28
29
|
orbitControls: DIVEOrbitControlsDefaultSettings,
|
|
@@ -52,6 +53,71 @@ export const DIVEDefaultSettings: DIVESettings = {
|
|
|
52
53
|
*/
|
|
53
54
|
|
|
54
55
|
export default class DIVE {
|
|
56
|
+
// static members
|
|
57
|
+
public static QuickView(uri: string): DIVE {
|
|
58
|
+
const dive = new DIVE();
|
|
59
|
+
|
|
60
|
+
dive.Communication.PerformAction('SET_CAMERA_TRANSFORM', {
|
|
61
|
+
position: { x: 0, y: 2, z: 2 },
|
|
62
|
+
target: { x: 0, y: 0.5, z: 0 },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// generate scene light id
|
|
66
|
+
const lightid = generateUUID();
|
|
67
|
+
|
|
68
|
+
// add scene light
|
|
69
|
+
dive.Communication.PerformAction('ADD_OBJECT', {
|
|
70
|
+
entityType: 'light',
|
|
71
|
+
type: 'scene',
|
|
72
|
+
name: 'light',
|
|
73
|
+
id: lightid,
|
|
74
|
+
enabled: true,
|
|
75
|
+
visible: true,
|
|
76
|
+
intensity: 1,
|
|
77
|
+
color: 0xffffff,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// generate model id
|
|
81
|
+
const modelid = generateUUID();
|
|
82
|
+
|
|
83
|
+
// add loaded listener
|
|
84
|
+
dive.Communication.Subscribe('MODEL_LOADED', (data) => {
|
|
85
|
+
if (data.id !== modelid) return;
|
|
86
|
+
dive.Communication.PerformAction('PLACE_ON_FLOOR', {
|
|
87
|
+
id: modelid,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const transform = dive.Communication.PerformAction('COMPUTE_ENCOMPASSING_VIEW', {});
|
|
91
|
+
|
|
92
|
+
dive.Communication.PerformAction('SET_CAMERA_TRANSFORM', {
|
|
93
|
+
position: transform.position,
|
|
94
|
+
target: transform.target,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// instantiate model
|
|
99
|
+
dive.Communication.PerformAction('ADD_OBJECT', {
|
|
100
|
+
entityType: 'model',
|
|
101
|
+
name: 'object',
|
|
102
|
+
id: modelid,
|
|
103
|
+
position: { x: 0, y: 0, z: 0 },
|
|
104
|
+
rotation: { x: 0, y: 0, z: 0 },
|
|
105
|
+
scale: { x: 1, y: 1, z: 1 },
|
|
106
|
+
uri: uri,
|
|
107
|
+
visible: true,
|
|
108
|
+
loaded: false,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// set scene properties
|
|
112
|
+
dive.Communication.PerformAction('UPDATE_SCENE', {
|
|
113
|
+
backgroundColor: 0xffffff,
|
|
114
|
+
gridEnabled: false,
|
|
115
|
+
floorColor: 0xffffff,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return dive;
|
|
119
|
+
}
|
|
120
|
+
|
|
55
121
|
// descriptive members
|
|
56
122
|
private _settings: DIVESettings;
|
|
57
123
|
private _resizeObserverId: string;
|
|
@@ -63,13 +129,12 @@ export default class DIVE {
|
|
|
63
129
|
private scene: DIVEScene;
|
|
64
130
|
private perspectiveCamera: DIVEPerspectiveCamera;
|
|
65
131
|
private orbitControls: DIVEOrbitControls;
|
|
66
|
-
private mediaCreator: DIVEMediaCreator;
|
|
67
132
|
private toolbox: DIVEToolbox;
|
|
68
133
|
private communication: DIVECommunication;
|
|
69
134
|
|
|
70
135
|
// additional components
|
|
71
|
-
private animationSystem: DIVEAnimationSystem;
|
|
72
|
-
private axisCamera: DIVEAxisCamera;
|
|
136
|
+
private animationSystem: DIVEAnimationSystem | null;
|
|
137
|
+
private axisCamera: DIVEAxisCamera | null;
|
|
73
138
|
|
|
74
139
|
// getters
|
|
75
140
|
public get Communication(): DIVECommunication {
|
|
@@ -108,6 +173,13 @@ export default class DIVE {
|
|
|
108
173
|
}
|
|
109
174
|
}
|
|
110
175
|
|
|
176
|
+
if (settingsDelta.displayAxes) {
|
|
177
|
+
this.axisCamera = new DIVEAxisCamera(this.renderer, this.scene, this.orbitControls);
|
|
178
|
+
} else {
|
|
179
|
+
this.axisCamera?.Dispose();
|
|
180
|
+
this.axisCamera = null;
|
|
181
|
+
}
|
|
182
|
+
|
|
111
183
|
Object.assign(this._settings, settings);
|
|
112
184
|
}
|
|
113
185
|
|
|
@@ -123,38 +195,18 @@ export default class DIVE {
|
|
|
123
195
|
this.scene = new DIVEScene();
|
|
124
196
|
this.perspectiveCamera = new DIVEPerspectiveCamera(this._settings.perspectiveCamera);
|
|
125
197
|
this.orbitControls = new DIVEOrbitControls(this.perspectiveCamera, this.renderer, this._settings.orbitControls);
|
|
126
|
-
this.mediaCreator = new DIVEMediaCreator(this.renderer, this.scene, this.orbitControls);
|
|
127
198
|
this.toolbox = new DIVEToolbox(this.scene, this.orbitControls);
|
|
128
|
-
this.communication = new DIVECommunication(this.
|
|
199
|
+
this.communication = new DIVECommunication(this.renderer, this.scene, this.orbitControls, this.toolbox);
|
|
129
200
|
|
|
130
201
|
// initialize animation system
|
|
131
|
-
this.animationSystem =
|
|
132
|
-
this.renderer.AddPreRenderCallback(() => {
|
|
133
|
-
this.animationSystem.update();
|
|
134
|
-
})
|
|
202
|
+
this.animationSystem = null;
|
|
135
203
|
|
|
136
204
|
// initialize axis camera
|
|
137
|
-
this.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const restoreBackground = this.scene.background;
|
|
143
|
-
this.scene.background = null;
|
|
144
|
-
|
|
145
|
-
this.renderer.getViewport(restoreViewport);
|
|
146
|
-
this.renderer.setViewport(0, 0, 150, 150);
|
|
147
|
-
this.renderer.autoClear = false;
|
|
148
|
-
|
|
149
|
-
this.axisCamera.SetFromCameraMatrix(this.perspectiveCamera.matrix);
|
|
150
|
-
|
|
151
|
-
this.renderer.render(this.scene, this.axisCamera);
|
|
152
|
-
|
|
153
|
-
this.renderer.setViewport(restoreViewport);
|
|
154
|
-
this.renderer.autoClear = true;
|
|
155
|
-
|
|
156
|
-
this.scene.background = restoreBackground;
|
|
157
|
-
});
|
|
205
|
+
if (this._settings.displayAxes) {
|
|
206
|
+
this.axisCamera = new DIVEAxisCamera(this.renderer, this.scene, this.orbitControls);
|
|
207
|
+
} else {
|
|
208
|
+
this.axisCamera = null;
|
|
209
|
+
}
|
|
158
210
|
|
|
159
211
|
// add resize observer if autoResize is enabled
|
|
160
212
|
if (this._settings.autoResize) {
|
|
@@ -172,6 +224,14 @@ export default class DIVE {
|
|
|
172
224
|
}
|
|
173
225
|
}
|
|
174
226
|
|
|
227
|
+
public Dispose(): void {
|
|
228
|
+
this.removeResizeObserver();
|
|
229
|
+
this.renderer.Dispose();
|
|
230
|
+
this.axisCamera?.Dispose();
|
|
231
|
+
this.toolbox.Dispose();
|
|
232
|
+
this.communication.DestroyInstance();
|
|
233
|
+
}
|
|
234
|
+
|
|
175
235
|
// methods
|
|
176
236
|
public OnResize(width: number, height: number): void {
|
|
177
237
|
// resize renderer
|
package/src/grid/Grid.ts
CHANGED
|
@@ -16,4 +16,11 @@ describe('dive/grid/DIVEGrid', () => {
|
|
|
16
16
|
expect((grid.children[0] as GridHelper).material.depthTest).toBe(false);
|
|
17
17
|
expect((grid.children[0] as GridHelper).layers.mask).toBe(HELPER_LAYER_MASK);
|
|
18
18
|
});
|
|
19
|
+
|
|
20
|
+
it('should set visibility', () => {
|
|
21
|
+
grid.SetVisibility(false);
|
|
22
|
+
expect(grid.visible).toBe(false);
|
|
23
|
+
grid.SetVisibility(true);
|
|
24
|
+
expect(grid.visible).toBe(true);
|
|
25
|
+
});
|
|
19
26
|
});
|
|
@@ -14,4 +14,21 @@ export interface DIVESelectable {
|
|
|
14
14
|
|
|
15
15
|
export function isSelectable(object: Object3D): object is Object3D & DIVESelectable {
|
|
16
16
|
return 'isSelectable' in object;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function findSelectableInterface(child: Object3D): (Object3D & DIVESelectable) | undefined {
|
|
20
|
+
if (child === undefined) return undefined;
|
|
21
|
+
|
|
22
|
+
if (child.parent === null) {
|
|
23
|
+
// in this case it is the scene itself
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isSelectable(child)) {
|
|
28
|
+
// in this case it is the Selectable
|
|
29
|
+
return child;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// search recursively in parent
|
|
33
|
+
return findSelectableInterface(child.parent);
|
|
17
34
|
}
|
|
@@ -21,6 +21,24 @@ describe('interfaces', () => {
|
|
|
21
21
|
expect(Selectable_DEF.isSelectable(Selectable as unknown as Object3D)).toBe(true);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
it('should find Selectable', () => {
|
|
25
|
+
let Selectable = {
|
|
26
|
+
isSelectable: true,
|
|
27
|
+
} as unknown as Object3D & Selectable_DEF.DIVESelectable;
|
|
28
|
+
expect(Selectable_DEF.findSelectableInterface(Selectable as unknown as Object3D)).toBe(Selectable);
|
|
29
|
+
|
|
30
|
+
let parent = {
|
|
31
|
+
isSelectable: true,
|
|
32
|
+
}
|
|
33
|
+
Selectable = {
|
|
34
|
+
parent: parent,
|
|
35
|
+
} as unknown as Object3D & Selectable_DEF.DIVESelectable;
|
|
36
|
+
expect(Selectable_DEF.findSelectableInterface(Selectable as unknown as Object3D)).toBe(parent);
|
|
37
|
+
|
|
38
|
+
Selectable = { isSelectable: true, parent: null } as unknown as Object3D & Selectable_DEF.DIVESelectable;
|
|
39
|
+
expect(Selectable_DEF.findSelectableInterface(Selectable as unknown as Object3D)).toBe(undefined);
|
|
40
|
+
});
|
|
41
|
+
|
|
24
42
|
it('should identify Draggable', () => {
|
|
25
43
|
const Draggable = { isDraggable: true };
|
|
26
44
|
expect(Draggable_DEF.isDraggable(Draggable as unknown as Object3D)).toBe(true);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import DIVEPerspectiveCamera from "../camera/PerspectiveCamera.ts";
|
|
2
2
|
import DIVEScene from "../scene/Scene.ts";
|
|
3
|
-
import DIVERenderer from "../renderer/Renderer.ts";
|
|
3
|
+
import { DIVERenderer } from "../renderer/Renderer.ts";
|
|
4
4
|
import DIVEOrbitControls from "../controls/OrbitControls.ts";
|
|
5
5
|
import { Vector3Like } from "three";
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ import { Vector3Like } from "three";
|
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
export
|
|
13
|
+
export class DIVEMediaCreator {
|
|
14
14
|
private renderer: DIVERenderer;
|
|
15
15
|
private scene: DIVEScene;
|
|
16
16
|
private controller: DIVEOrbitControls;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import DIVEMediaCreator from '../MediaCreator';
|
|
2
|
-
import DIVERenderer from '../../renderer/Renderer';
|
|
1
|
+
import { DIVEMediaCreator } from '../MediaCreator';
|
|
2
|
+
import { DIVERenderer } from '../../renderer/Renderer';
|
|
3
3
|
import DIVEScene from '../../scene/Scene';
|
|
4
4
|
import DIVEPerspectiveCamera, { DIVEPerspectiveCameraDefaultSettings } from '../../camera/PerspectiveCamera';
|
|
5
5
|
import { COMPov } from '../../com';
|
|
@@ -71,14 +71,16 @@ jest.mock('../../controls/OrbitControls', () => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
jest.mock('../../renderer/Renderer', () => {
|
|
74
|
-
return
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
return {
|
|
75
|
+
DIVERenderer: jest.fn(function () {
|
|
76
|
+
this.domElement = {
|
|
77
|
+
toDataURL: mock_toDataURL,
|
|
78
|
+
}
|
|
79
|
+
this.render = mock_render;
|
|
80
|
+
this.OnResize = jest.fn();
|
|
81
|
+
return this;
|
|
82
|
+
})
|
|
83
|
+
}
|
|
82
84
|
});
|
|
83
85
|
|
|
84
86
|
let mediaCreator: DIVEMediaCreator;
|
package/src/renderer/Renderer.ts
CHANGED
|
@@ -26,7 +26,7 @@ export const DIVERendererDefaultSettings: DIVERendererSettings = {
|
|
|
26
26
|
* @module
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
export
|
|
29
|
+
export class DIVERenderer extends WebGLRenderer {
|
|
30
30
|
// basic functionality members
|
|
31
31
|
private paused: boolean = false;
|
|
32
32
|
private running: boolean = false;
|
|
@@ -52,6 +52,12 @@ export default class DIVERenderer extends WebGLRenderer {
|
|
|
52
52
|
this.debug.checkShaderErrors = false;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
// Stops renderings and disposes the renderer.
|
|
56
|
+
public Dispose(): void {
|
|
57
|
+
this.StopRenderer();
|
|
58
|
+
this.dispose();
|
|
59
|
+
}
|
|
60
|
+
|
|
55
61
|
// Starts the renderer with the given scene and camera.
|
|
56
62
|
public StartRenderer(scene: Scene, cam: Camera): void {
|
|
57
63
|
this.setAnimationLoop(() => { this.internal_render(scene, cam) });
|