@shopware-ag/dive 1.0.7 → 1.0.9

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 (97) hide show
  1. package/package.json +6 -3
  2. package/src/__test__/DIVE.test.ts +244 -0
  3. package/src/animation/AnimationSystem.ts +14 -0
  4. package/src/animation/__test__/AnimationSystem.test.ts +19 -0
  5. package/src/axiscamera/AxisCamera.ts +50 -0
  6. package/src/axiscamera/__test__/AxisCamera.test.ts +41 -0
  7. package/src/camera/PerspectiveCamera.ts +43 -0
  8. package/src/camera/__test__/PerspectiveCamera.test.ts +27 -0
  9. package/src/com/Communication.ts +382 -0
  10. package/src/com/__test__/Communication.test.ts +612 -0
  11. package/src/com/actions/camera/getcameratransform.ts +9 -0
  12. package/src/com/actions/camera/movecamera.ts +15 -0
  13. package/src/com/actions/camera/resetcamera.ts +4 -0
  14. package/src/com/actions/camera/setcameralayer.ts +4 -0
  15. package/src/com/actions/camera/setcameratransform.ts +9 -0
  16. package/src/com/actions/camera/zoomcamera.ts +4 -0
  17. package/src/com/actions/index.ts +41 -0
  18. package/src/com/actions/media/generatemedia.ts +15 -0
  19. package/src/com/actions/object/addobject.ts +6 -0
  20. package/src/com/actions/object/deleteobject.ts +6 -0
  21. package/src/com/actions/object/getallobjects.ts +6 -0
  22. package/src/com/actions/object/getobjects.ts +6 -0
  23. package/src/com/actions/object/model/modelloaded.ts +4 -0
  24. package/src/com/actions/object/model/placeonfloor.ts +4 -0
  25. package/src/com/actions/object/selectobject.ts +6 -0
  26. package/src/com/actions/object/updateobject.ts +6 -0
  27. package/src/com/actions/scene/getallscenedata.ts +23 -0
  28. package/src/com/actions/scene/setbackground.ts +4 -0
  29. package/src/com/actions/scene/updatescene.ts +9 -0
  30. package/src/com/actions/toolbox/select/setgizmomode.ts +4 -0
  31. package/src/com/index.ts +4 -0
  32. package/src/com/types.ts +30 -0
  33. package/src/constant/AxisHelperColors.ts +7 -0
  34. package/src/constant/GridColors.ts +2 -0
  35. package/src/constant/VisibilityLayerMask.ts +5 -0
  36. package/src/controls/OrbitControls.ts +145 -0
  37. package/src/controls/__test__/OrbitControls.test.ts +181 -0
  38. package/src/grid/Grid.ts +22 -0
  39. package/src/grid/__test__/Grid.test.ts +19 -0
  40. package/src/helper/applyMixins/__test__/applyMixins.test.ts +27 -0
  41. package/src/helper/applyMixins/applyMixins.ts +15 -0
  42. package/src/helper/getObjectDelta/__test__/getObjectDelta.spec.ts +152 -0
  43. package/src/helper/getObjectDelta/getObjectDelta.ts +101 -0
  44. package/src/interface/Moveable.ts +13 -0
  45. package/src/interface/Rotatable.ts +10 -0
  46. package/src/interface/Scalable.ts +10 -0
  47. package/src/interface/Selectable.ts +11 -0
  48. package/src/interface/__test__/Interfaces.test.ts +13 -0
  49. package/src/light/AmbientLight.ts +29 -0
  50. package/src/light/PointLight.ts +63 -0
  51. package/src/light/SceneLight.ts +60 -0
  52. package/src/light/__test__/AmbientLight.test.ts +44 -0
  53. package/src/light/__test__/PointLight.test.ts +98 -0
  54. package/src/light/__test__/SceneLight.test.ts +122 -0
  55. package/src/loadingmanager/LoadingManager.ts +44 -0
  56. package/src/loadingmanager/__test__/LoadingManager.test.ts +52 -0
  57. package/src/math/__test__/DIVEMath.test.ts +12 -0
  58. package/src/math/ceil/__test__/ceilExp.test.ts +12 -0
  59. package/src/math/ceil/ceilExp.ts +6 -0
  60. package/src/math/floor/__test__/floorExp.test.ts +14 -0
  61. package/src/math/floor/floorExp.ts +6 -0
  62. package/src/math/helper/__test__/shift.test.ts +12 -0
  63. package/src/math/helper/shift.ts +4 -0
  64. package/src/math/index.ts +19 -0
  65. package/src/math/round/__test__/roundExp.test.ts +14 -0
  66. package/src/math/round/roundExp.ts +7 -0
  67. package/src/math/toFixed/__test__/toFixedExp.test.ts +14 -0
  68. package/src/math/toFixed/toFixedExp.ts +6 -0
  69. package/src/math/truncate/__test__/truncateExp.test.ts +14 -0
  70. package/src/math/truncate/truncateExp.ts +6 -0
  71. package/src/mediacreator/MediaCreator.ts +65 -0
  72. package/src/mediacreator/__test__/MediaCreator.test.ts +113 -0
  73. package/src/model/Model.ts +72 -0
  74. package/src/model/__test__/Model.test.ts +163 -0
  75. package/src/primitive/floor/Floor.ts +34 -0
  76. package/src/primitive/floor/__test__/Floor.test.ts +21 -0
  77. package/src/renderer/Renderer.ts +165 -0
  78. package/src/renderer/__test__/Renderer.test.ts +169 -0
  79. package/src/scene/Scene.ts +49 -0
  80. package/src/scene/__test__/Scene.test.ts +70 -0
  81. package/src/scene/root/Root.ts +107 -0
  82. package/src/scene/root/__test__/Root.test.ts +129 -0
  83. package/src/scene/root/lightroot/LightRoot.ts +84 -0
  84. package/src/scene/root/lightroot/__test__/LightRoot.test.ts +137 -0
  85. package/src/scene/root/modelroot/ModelRoot.ts +82 -0
  86. package/src/scene/root/modelroot/__test__/ModelRoot.test.ts +185 -0
  87. package/src/toolbox/BaseTool.ts +18 -0
  88. package/src/toolbox/Toolbox.ts +76 -0
  89. package/src/toolbox/__test__/Toolbox.test.ts +109 -0
  90. package/src/toolbox/select/SelectTool.ts +123 -0
  91. package/src/toolbox/select/__test__/SelectTool.test.ts +190 -0
  92. package/build/dive.cjs +0 -1551
  93. package/build/dive.cjs.map +0 -1
  94. package/build/dive.d.cts +0 -558
  95. package/build/dive.d.ts +0 -558
  96. package/build/dive.js +0 -1516
  97. package/build/dive.js.map +0 -1
@@ -0,0 +1,163 @@
1
+ import Model from '../Model';
2
+ import DIVECommunication from '../../com/Communication';
3
+ import { GLTF } from 'three/examples/jsm/Addons';
4
+
5
+ jest.mock('three', () => {
6
+ return {
7
+ Vector3: jest.fn(function (x: number, y: number, z: number) {
8
+ return { x, y, z };
9
+ }),
10
+ Object3D: jest.fn(function () {
11
+ this.clear = jest.fn();
12
+ this.color = {};
13
+ this.intensity = 0;
14
+ this.layers = {
15
+ mask: 0,
16
+ };
17
+ this.shadow = {
18
+ radius: 0,
19
+ mapSize: { width: 0, height: 0 },
20
+ bias: 0,
21
+ camera: {
22
+ near: 0,
23
+ far: 0,
24
+ fov: 0,
25
+ },
26
+ }
27
+ this.add = jest.fn();
28
+ this.children = [{
29
+ material: {
30
+ color: {},
31
+ },
32
+ }];
33
+ this.userData = {};
34
+ this.position = {
35
+ x: 0,
36
+ y: 0,
37
+ z: 0,
38
+ set: jest.fn(),
39
+ };
40
+ this.rotation = {
41
+ x: 0,
42
+ y: 0,
43
+ z: 0,
44
+ setFromVector3: jest.fn(),
45
+ };
46
+ this.scale = {
47
+ x: 1,
48
+ y: 1,
49
+ z: 1,
50
+ set: jest.fn(),
51
+ };
52
+ return this;
53
+ }),
54
+ Box3: jest.fn(function () {
55
+ this.min = { x: 0, y: 0, z: 0 };
56
+ this.expandByObject = jest.fn();
57
+ return this;
58
+ }),
59
+ }
60
+ });
61
+
62
+ jest.mock('../../com/Communication.ts', () => {
63
+ return {
64
+ get: jest.fn(() => {
65
+ return {
66
+ PerformAction: jest.fn(),
67
+ }
68
+ }),
69
+ }
70
+ });
71
+
72
+ const gltf = {
73
+ scene: {
74
+ isObject3D: true,
75
+ parent: null,
76
+ dispatchEvent: jest.fn(),
77
+ layers: {
78
+ mask: 0,
79
+ },
80
+ updateWorldMatrix: jest.fn(),
81
+ children: [
82
+ {
83
+ castShadow: false,
84
+ receiveShadow: false,
85
+ layers: {
86
+ mask: 0,
87
+ },
88
+ children: [],
89
+ updateWorldMatrix: jest.fn(),
90
+ },
91
+ ],
92
+ traverse: function (callback: (object: object) => void) {
93
+ callback(this);
94
+ },
95
+ removeFromParent: jest.fn(),
96
+ },
97
+ } as unknown as GLTF;
98
+
99
+ jest.spyOn(DIVECommunication, 'get').mockReturnValue({ PerformAction: jest.fn() } as unknown as DIVECommunication);
100
+
101
+ describe('dive/model/DIVEModel', () => {
102
+ afterEach(() => {
103
+ jest.clearAllMocks();
104
+ });
105
+
106
+ it('should instantiate', () => {
107
+ const model = new Model();
108
+ expect(model).toBeDefined();
109
+ });
110
+
111
+ it('should set model', () => {
112
+ const model = new Model();
113
+ expect(() => model.SetModel(gltf)).not.toThrow();
114
+ });
115
+
116
+ it('should set position', () => {
117
+ const model = new Model();
118
+ expect(() => model.SetPosition({ x: 0, y: 0, z: 0 })).not.toThrow();
119
+ });
120
+
121
+ it('should set rotation', () => {
122
+ const model = new Model();
123
+ expect(() => model.SetRotation({ x: 0, y: 0, z: 0 })).not.toThrow();
124
+ });
125
+
126
+ it('should set scale', () => {
127
+ const model = new Model();
128
+ expect(() => model.SetScale({ x: 1, y: 1, z: 1 })).not.toThrow();
129
+ });
130
+
131
+ it('should set to world origin', () => {
132
+ const model = new Model();
133
+ model.userData.id = 'something';
134
+
135
+ expect(() => model.SetToWorldOrigin()).not.toThrow();
136
+ expect(model.position.x).toBe(0);
137
+ expect(model.position.y).toBe(0);
138
+ expect(model.position.z).toBe(0);
139
+
140
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
141
+ expect(() => model.SetToWorldOrigin()).not.toThrow();
142
+ });
143
+
144
+ it('should place on floor', () => {
145
+ const model = new Model();
146
+ model.userData.id = 'something';
147
+
148
+ expect(() => model.PlaceOnFloor()).not.toThrow();
149
+
150
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
151
+ expect(() => model.PlaceOnFloor()).not.toThrow();
152
+ });
153
+
154
+ it('should onMove', () => {
155
+ const model = new Model();
156
+ model.userData.id = 'something';
157
+
158
+ expect(() => model.onMove()).not.toThrow();
159
+
160
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
161
+ expect(() => model.onMove()).not.toThrow();
162
+ });
163
+ });
@@ -0,0 +1,34 @@
1
+ import { Color, ColorRepresentation, Mesh, MeshStandardMaterial, PlaneGeometry } from "three";
2
+ import { PRODUCT_LAYER_MASK } from "../../constant/VisibilityLayerMask.ts";
3
+
4
+ /**
5
+ * A basic floor geometry.
6
+ *
7
+ * Can change the color and visibility of the floor.
8
+ *
9
+ * @module
10
+ */
11
+
12
+ export default class DIVEFloor extends Mesh {
13
+ public isFloor: true = true;
14
+
15
+ constructor() {
16
+ super(new PlaneGeometry(10000, 10000), new MeshStandardMaterial({ color: new Color(150 / 255, 150 / 255, 150 / 255) }));
17
+
18
+ this.name = 'Floor';
19
+
20
+ this.layers.mask = PRODUCT_LAYER_MASK;
21
+
22
+ this.receiveShadow = true;
23
+
24
+ this.rotateX(-Math.PI / 2);
25
+ }
26
+
27
+ public SetVisibility(visible: boolean): void {
28
+ this.visible = visible;
29
+ }
30
+
31
+ public SetColor(color: ColorRepresentation): void {
32
+ (this.material as MeshStandardMaterial).color = new Color(color);
33
+ }
34
+ }
@@ -0,0 +1,21 @@
1
+ import { MeshStandardMaterial } from 'three';
2
+ import DIVEFloor from '../Floor';
3
+
4
+ describe('dive/primitive/floor/DIVEFloor', () => {
5
+ it('should instantiate', () => {
6
+ const floor = new DIVEFloor();
7
+ expect(floor).toBeDefined();
8
+ });
9
+
10
+ it('should set visibility', () => {
11
+ const floor = new DIVEFloor();
12
+ expect(() => { floor.SetVisibility(false) }).not.toThrow();
13
+ expect(floor.visible).toBe(false);
14
+ });
15
+
16
+ it('should set color', () => {
17
+ const floor = new DIVEFloor();
18
+ expect(() => { floor.SetColor('#ff00ff') }).not.toThrow();
19
+ expect('#' + (floor.material as MeshStandardMaterial).color.getHexString()).toBe('#ff00ff');
20
+ });
21
+ });
@@ -0,0 +1,165 @@
1
+ import { Camera, MathUtils, NoToneMapping, PCFSoftShadowMap, Scene, ShadowMapType, ToneMapping, WebGLRenderer } from "three";
2
+
3
+ export type DIVERendererSettings = {
4
+ antialias: boolean;
5
+ alpha: boolean;
6
+ stencil: boolean;
7
+ shadowMapEnabled: boolean;
8
+ shadowMapType: ShadowMapType;
9
+ toneMapping: ToneMapping;
10
+ }
11
+
12
+ export const DIVERendererDefaultSettings: DIVERendererSettings = {
13
+ antialias: true,
14
+ alpha: true,
15
+ stencil: false,
16
+ shadowMapEnabled: true,
17
+ shadowMapType: PCFSoftShadowMap,
18
+ toneMapping: NoToneMapping,
19
+ }
20
+
21
+ /**
22
+ * A changed version of the WebGLRenderer.
23
+ *
24
+ * Has to be started manually by calling StartRenderer().
25
+ *
26
+ * @module
27
+ */
28
+
29
+ export default class DIVERenderer extends WebGLRenderer {
30
+ // basic functionality members
31
+ private paused: boolean = false;
32
+ private running: boolean = false;
33
+ private force: boolean = false;
34
+
35
+ // pre- and post-render callbacks
36
+ private preRenderCallbacks: Map<string, () => void> = new Map<string, () => void>();
37
+ private postRenderCallbacks: Map<string, () => void> = new Map<string, () => void>();
38
+
39
+ constructor(rendererSettings: DIVERendererSettings = DIVERendererDefaultSettings) {
40
+ super({
41
+ antialias: rendererSettings.antialias,
42
+ alpha: rendererSettings.alpha,
43
+ preserveDrawingBuffer: true
44
+ });
45
+ this.setPixelRatio(window.devicePixelRatio);
46
+
47
+ this.shadowMap.enabled = rendererSettings.shadowMapEnabled;
48
+ this.shadowMap.type = rendererSettings.shadowMapType;
49
+
50
+ this.toneMapping = rendererSettings.toneMapping;
51
+
52
+ this.debug.checkShaderErrors = false;
53
+ }
54
+
55
+ // Starts the renderer with the given scene and camera.
56
+ public StartRenderer(scene: Scene, cam: Camera): void {
57
+ this.setAnimationLoop(() => { this.internal_render(scene, cam) });
58
+ this.running = true;
59
+ }
60
+
61
+ // Pauses the renderer.
62
+ public PauseRenderer(): void {
63
+ this.paused = true;
64
+ }
65
+
66
+ // Resumes the renderer after pausing.
67
+ public ResumeRenderer(): void {
68
+ this.paused = false;
69
+ }
70
+
71
+ // Stops the renderer completely. Has to be started again with StartRenderer().
72
+ public StopRenderer(): void {
73
+ this.setAnimationLoop(null);
74
+ this.running = false;
75
+ }
76
+
77
+ // Resizes the renderer to the given width and height.
78
+ public OnResize(width: number, height: number): void {
79
+ this.setSize(width, height);
80
+ }
81
+
82
+ /**
83
+ * Adds a callback to the render loop before actual render call.
84
+ * @param callback Executed before rendering.
85
+ * @returns uuid to remove the callback.
86
+ */
87
+ public AddPreRenderCallback(callback: () => void): string {
88
+ // add callback to renderloop
89
+ const newUUID = MathUtils.generateUUID();
90
+ this.preRenderCallbacks.set(newUUID, callback);
91
+
92
+ return newUUID;
93
+ }
94
+
95
+ /**
96
+ * Removes a callback from the render loop before actual render call.
97
+ * @param uuid of callback to remove.
98
+ * @returns if removing was successful.
99
+ */
100
+ public RemovePreRenderCallback(uuid: string): boolean {
101
+ // check if callback exists
102
+ if (!this.preRenderCallbacks.has(uuid)) return false;
103
+
104
+ // remove callback from renderloop
105
+ this.preRenderCallbacks.delete(uuid);
106
+
107
+ return true;
108
+ }
109
+
110
+ /**
111
+ * Adds a callback to the render loop after actual render call.
112
+ * @param callback Executed after rendering.
113
+ * @returns uuid to remove the callback.
114
+ */
115
+ public AddPostRenderCallback(callback: () => void): string {
116
+ // add callback to renderloop
117
+ const newUUID = MathUtils.generateUUID();
118
+ this.postRenderCallbacks.set(newUUID, callback);
119
+
120
+ return newUUID;
121
+ }
122
+
123
+ /**
124
+ * Removes a callback from the render loop after actual render call.
125
+ * @param uuid of callback to remove.
126
+ * @returns if removing was successful.
127
+ */
128
+ public RemovePostRenderCallback(uuid: string): boolean {
129
+ // check if callback exists
130
+ if (!this.postRenderCallbacks.has(uuid)) return false;
131
+
132
+ // remove callback from renderloop
133
+ this.postRenderCallbacks.delete(uuid);
134
+
135
+ return true;
136
+ }
137
+
138
+ /**
139
+ * Forces the renderer to render the next frame.
140
+ */
141
+ public ForceRendering(): void {
142
+ this.force = true;
143
+ }
144
+
145
+ /**
146
+ * Internal render loop.
147
+ *
148
+ * To control renderloop you can add callbacks via AddPreRenderCallback() and AddPostRenderCallback().
149
+ * @param scene Scene to render.
150
+ * @param cam Camera to render with.
151
+ */
152
+ private internal_render(scene: Scene, cam: Camera): void {
153
+ // execute background render loop callbacks
154
+ if ((this.paused || !this.running) && !this.force) return;
155
+
156
+ // execute render loop callbacks
157
+ this.preRenderCallbacks.forEach((callback) => { callback(); });
158
+
159
+ this.render(scene, cam);
160
+
161
+ this.postRenderCallbacks.forEach((callback) => { callback(); });
162
+
163
+ this.force = false;
164
+ }
165
+ }
@@ -0,0 +1,169 @@
1
+ import DIVEPerspectiveCamera from '../../camera/PerspectiveCamera';
2
+ import DIVEScene from '../../scene/Scene';
3
+ import DIVERenderer, { DIVERendererDefaultSettings } from '../Renderer';
4
+
5
+ /**
6
+ * @jest-environment jsdom
7
+ */
8
+
9
+ const test_uuid = 'test-uuid';
10
+
11
+ const mock_render = jest.fn();
12
+ const mock_setSize = jest.fn();
13
+ const mock_setAnimationLoop = jest.fn();
14
+
15
+ jest.mock('three', () => {
16
+ return {
17
+ WebGLRenderer: jest.fn(function () {
18
+ this.domElement = {
19
+ style: {
20
+ position: 'absolute',
21
+ },
22
+ };
23
+ this.debug = {
24
+ checkShaderErrors: true,
25
+ };
26
+ this.setSize = mock_setSize;
27
+ this.setPixelRatio = jest.fn();
28
+ this.render = mock_render;
29
+ this.setAnimationLoop = mock_setAnimationLoop;
30
+ this.shadowMap = {
31
+ enabled: false,
32
+ };
33
+ return this;
34
+ }),
35
+ MathUtils: {
36
+ generateUUID: () => { return test_uuid; },
37
+ },
38
+ }
39
+ });
40
+
41
+ let renderer: DIVERenderer;
42
+
43
+ describe('dive/renderer/DIVERenderer', () => {
44
+ beforeEach(() => {
45
+ jest.clearAllMocks();
46
+ renderer = new DIVERenderer(DIVERendererDefaultSettings);
47
+ });
48
+
49
+ it('should instantiate', () => {
50
+ expect(renderer).toBeDefined();
51
+ renderer = new DIVERenderer();
52
+ });
53
+
54
+ it('should start render', () => {
55
+ expect(() => { renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera) }).not.toThrow();
56
+ expect(renderer['running']).toBe(true);
57
+ });
58
+
59
+ it('should pause render', () => {
60
+ renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera);
61
+ expect(() => { renderer.PauseRenderer() }).not.toThrow();
62
+ expect(renderer['paused']).toBe(true);
63
+ });
64
+
65
+ it('should resume render', () => {
66
+ renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera);
67
+ renderer.PauseRenderer();
68
+ expect(() => { renderer.ResumeRenderer() }).not.toThrow();
69
+ expect(renderer['paused']).toBe(false);
70
+ });
71
+
72
+ it('should stop render', () => {
73
+ expect(() => { renderer.StopRenderer() }).not.toThrow();
74
+ expect(renderer['running']).toBe(false);
75
+ });
76
+
77
+ it('should resize renderer', () => {
78
+ expect(() => { renderer.OnResize(500, 500) }).not.toThrow();
79
+ expect(mock_setSize).toHaveBeenCalledTimes(1);
80
+ });
81
+
82
+ it('should render', () => {
83
+ expect(mock_render).toHaveBeenCalledTimes(0);
84
+
85
+ renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera);
86
+ expect(() => { renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera) }).not.toThrow();
87
+ expect(mock_render).toHaveBeenCalledTimes(1);
88
+ });
89
+
90
+ it('should force render', () => {
91
+ expect(() => { renderer.ForceRendering() }).not.toThrow();
92
+ });
93
+
94
+ it('should not render when not started', () => {
95
+ expect(mock_render).toHaveBeenCalledTimes(0);
96
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
97
+ expect(mock_render).toHaveBeenCalledTimes(0);
98
+ });
99
+
100
+ it('should not render when stopped', () => {
101
+ renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera);
102
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
103
+ expect(mock_render).toHaveBeenCalledTimes(1);
104
+
105
+ renderer.StopRenderer();
106
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
107
+ expect(mock_render).toHaveBeenCalledTimes(1);
108
+ });
109
+
110
+ it('should not render when paused', () => {
111
+ renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera);
112
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
113
+ expect(mock_render).toHaveBeenCalledTimes(1);
114
+
115
+ renderer.PauseRenderer();
116
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
117
+ expect(mock_render).toHaveBeenCalledTimes(1);
118
+ });
119
+
120
+ it('should resume render when running', () => {
121
+ renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera);
122
+ renderer.PauseRenderer();
123
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
124
+ expect(mock_render).toHaveBeenCalledTimes(0);
125
+
126
+ renderer.ResumeRenderer();
127
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
128
+ expect(mock_render).toHaveBeenCalledTimes(1);
129
+ });
130
+
131
+ it('should add pre render callback', () => {
132
+ expect(renderer.AddPreRenderCallback(() => { })).toBe(test_uuid);
133
+ expect(renderer['preRenderCallbacks'].size).toBe(1);
134
+ });
135
+
136
+ it('should remove pre render callback', () => {
137
+ const uuid = renderer.AddPreRenderCallback(() => { });
138
+ expect(renderer.RemovePreRenderCallback(uuid)).toBe(true);
139
+ });
140
+
141
+ it('should not crash while removing non-existing pre render callback', () => {
142
+ expect(() => { renderer.RemovePreRenderCallback(test_uuid) }).not.toThrow();
143
+ });
144
+
145
+ it('should add post render callback', () => {
146
+ expect(renderer.AddPostRenderCallback(() => { })).toBe(test_uuid);
147
+ expect(renderer['postRenderCallbacks'].size).toBe(1);
148
+ });
149
+
150
+ it('should remove post render callback', () => {
151
+ const uuid = renderer.AddPostRenderCallback(() => { });
152
+ expect(renderer.RemovePostRenderCallback(uuid)).toBe(true);
153
+ });
154
+
155
+ it('should not crash while removing non-existing post render callback', () => {
156
+ expect(() => { renderer.RemovePostRenderCallback(test_uuid) }).not.toThrow();
157
+ });
158
+
159
+ it('should execute pre and post render callbacks', () => {
160
+ renderer.StartRenderer({} as DIVEScene, {} as DIVEPerspectiveCamera);
161
+ const precallback = jest.fn();
162
+ const postcallback = jest.fn();
163
+ renderer.AddPreRenderCallback(precallback);
164
+ renderer.AddPostRenderCallback(postcallback);
165
+ renderer['internal_render']({} as DIVEScene, {} as DIVEPerspectiveCamera);
166
+ expect(precallback).toHaveBeenCalledTimes(1);
167
+ expect(postcallback).toHaveBeenCalledTimes(1);
168
+ });
169
+ });
@@ -0,0 +1,49 @@
1
+ import { Color, ColorRepresentation, Object3D, Scene } from 'three';
2
+ import { COMModel, COMEntity } from '../com/types';
3
+ import DIVERoot from './root/Root';
4
+
5
+ /**
6
+ * A basic scene class.
7
+ *
8
+ * Comes with a root object that contains all the scene objects.
9
+ *
10
+ * @module
11
+ */
12
+
13
+ export default class DIVEScene extends Scene {
14
+ private root: DIVERoot;
15
+ public get Root(): DIVERoot {
16
+ return this.root;
17
+ }
18
+
19
+ constructor() {
20
+ super();
21
+
22
+ this.root = new DIVERoot();
23
+ this.add(this.root);
24
+ }
25
+
26
+ public SetBackground(color: ColorRepresentation): void {
27
+ this.background = new Color(color);
28
+ }
29
+
30
+ public GetSceneObject(object: Partial<COMEntity>): Object3D | undefined {
31
+ return this.Root.GetSceneObject(object);
32
+ }
33
+
34
+ public AddSceneObject(object: COMEntity): void {
35
+ this.Root.UpdateSceneObject(object);
36
+ }
37
+
38
+ public UpdateSceneObject(object: Partial<COMEntity>): void {
39
+ this.Root.UpdateSceneObject(object);
40
+ }
41
+
42
+ public DeleteSceneObject(object: Partial<COMEntity>): void {
43
+ this.Root.DeleteSceneObject(object);
44
+ }
45
+
46
+ public PlaceOnFloor(object: Partial<COMModel>): void {
47
+ this.Root.PlaceOnFloor(object);
48
+ }
49
+ }
@@ -0,0 +1,70 @@
1
+ import { Color } from 'three';
2
+ import DIVEScene from '../Scene';
3
+ import { COMEntity } from '../../com';
4
+
5
+ const mock_UpdateSceneObject = jest.fn();
6
+ const mock_DeleteSceneObject = jest.fn();
7
+ const mock_PlaceOnFloor = jest.fn();
8
+ const mock_GetSceneObject = jest.fn();
9
+
10
+ jest.mock('../root/Root', () => {
11
+ return jest.fn(function () {
12
+ this.isObject3D = true;
13
+ this.parent = null;
14
+ this.dispatchEvent = jest.fn();
15
+ this.UpdateSceneObject = mock_UpdateSceneObject;
16
+ this.DeleteSceneObject = mock_DeleteSceneObject;
17
+ this.PlaceOnFloor = mock_PlaceOnFloor;
18
+ this.GetSceneObject = mock_GetSceneObject;
19
+ this.removeFromParent = jest.fn();
20
+ return this;
21
+ });
22
+ });
23
+
24
+ describe('dive/scene/DIVEScene', () => {
25
+ afterEach(() => {
26
+ jest.clearAllMocks();
27
+ });
28
+
29
+ it('should instantiate', () => {
30
+ const scene = new DIVEScene();
31
+ expect(scene).toBeDefined();
32
+ expect(scene.children).toHaveLength(1);
33
+ });
34
+
35
+ it('should set background color', () => {
36
+ const scene = new DIVEScene();
37
+ scene.SetBackground(0x123456);
38
+ expect((scene.background as Color).getHex()).toBe(0x123456);
39
+ });
40
+
41
+ it('should add object', () => {
42
+ const scene = new DIVEScene();
43
+ scene.AddSceneObject({} as COMEntity);
44
+ expect(mock_UpdateSceneObject).toHaveBeenCalledTimes(1);
45
+ });
46
+
47
+ it('should update object', () => {
48
+ const scene = new DIVEScene();
49
+ scene.UpdateSceneObject({});
50
+ expect(mock_UpdateSceneObject).toHaveBeenCalledTimes(1);
51
+ });
52
+
53
+ it('should remove object', () => {
54
+ const scene = new DIVEScene();
55
+ scene.DeleteSceneObject({});
56
+ expect(mock_DeleteSceneObject).toHaveBeenCalledTimes(1);
57
+ });
58
+
59
+ it('should place object on floor', () => {
60
+ const scene = new DIVEScene();
61
+ scene.PlaceOnFloor({});
62
+ expect(mock_PlaceOnFloor).toHaveBeenCalledTimes(1);
63
+ });
64
+
65
+ it('should get scene object', () => {
66
+ const scene = new DIVEScene();
67
+ scene.GetSceneObject({});
68
+ expect(mock_GetSceneObject).toHaveBeenCalledTimes(1);
69
+ });
70
+ });