@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,122 @@
1
+ import DIVESceneLight from '../SceneLight';
2
+ import DIVECommunication from '../../com/Communication';
3
+ import { Color } from 'three';
4
+
5
+ jest.mock('../../com/Communication.ts', () => {
6
+ return {
7
+ get: jest.fn(() => {
8
+ return {
9
+ PerformAction: jest.fn(),
10
+ }
11
+ }),
12
+ }
13
+ });
14
+
15
+ const mockAdd = jest.fn();
16
+
17
+ jest.mock('three', () => {
18
+ return {
19
+ Color: jest.fn(function () {
20
+ return {};
21
+ }),
22
+ PointLight: jest.fn(function () {
23
+ this.color = {};
24
+ this.intensity = 0;
25
+ this.layers = {
26
+ mask: 0,
27
+ };
28
+ this.shadow = {
29
+ radius: 0,
30
+ mapSize: { width: 0, height: 0 },
31
+ bias: 0,
32
+ camera: {
33
+ near: 0,
34
+ far: 0,
35
+ fov: 0,
36
+ },
37
+ }
38
+ this.add = mockAdd;
39
+ this.children = [{
40
+ material: {
41
+ color: {},
42
+ },
43
+ }];
44
+ this.userData = {};
45
+ return this;
46
+ }),
47
+ SphereGeometry: jest.fn(function () {
48
+ return this;
49
+ }),
50
+ MeshBasicMaterial: jest.fn(function () {
51
+ return this;
52
+ }),
53
+ Mesh: jest.fn(function () {
54
+ this.layers = {
55
+ mask: 0,
56
+ };
57
+ return this;
58
+ }),
59
+ Object3D: jest.fn(function () {
60
+ this.add = mockAdd;
61
+ return this;
62
+ }),
63
+ HemisphereLight: jest.fn(function () {
64
+ this.layers = {
65
+ mask: 0,
66
+ };
67
+ this.position = {
68
+ set: jest.fn(),
69
+ };
70
+ this.removeFromParent = mockAdd;
71
+ return this;
72
+ }),
73
+ DirectionalLight: jest.fn(function () {
74
+ this.layers = {
75
+ mask: 0,
76
+ };
77
+ this.position = {
78
+ set: jest.fn(),
79
+ multiplyScalar: jest.fn(),
80
+ };
81
+ this.shadow = {
82
+ radius: 0,
83
+ mapSize: { width: 0, height: 0 },
84
+ bias: 0,
85
+ camera: {
86
+ near: 0,
87
+ far: 0,
88
+ fov: 0,
89
+ },
90
+ }
91
+ this.removeFromParent = mockAdd;
92
+ return this;
93
+ }),
94
+ }
95
+ });
96
+
97
+ jest.spyOn(DIVECommunication, 'get').mockReturnValue({ PerformAction: jest.fn() } as unknown as DIVECommunication);
98
+
99
+ describe('dive/light/DIVESceneLight', () => {
100
+ it('should instantiate', () => {
101
+ const testLight = new DIVESceneLight();
102
+ expect(testLight).toBeDefined();
103
+ expect(mockAdd).toHaveBeenCalledTimes(2);
104
+ });
105
+
106
+ it('should set intensity', () => {
107
+ const testLight = new DIVESceneLight();
108
+ expect(() => testLight.SetIntensity(1.0)).not.toThrow();
109
+ expect(() => testLight.SetIntensity(0.6)).not.toThrow();
110
+ });
111
+
112
+ it('should set color', () => {
113
+ const testLight = new DIVESceneLight();
114
+ expect(() => testLight.SetColor({ test: true } as unknown as Color)).not.toThrow();
115
+ });
116
+
117
+ it('should set enabled', () => {
118
+ const testLight = new DIVESceneLight();
119
+ testLight.SetEnabled(false);
120
+ expect(testLight.visible).toBe(false);
121
+ });
122
+ });
@@ -0,0 +1,44 @@
1
+ import { DRACOLoader, GLTF, GLTFLoader } from "three/examples/jsm/Addons.js";
2
+
3
+ /**
4
+ * A basic loading manager.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ export default class DIVELoadingManager {
10
+ private gltfloader: GLTFLoader;
11
+ private dracoloader: DRACOLoader;
12
+ // ... maybe extend with other loaders later
13
+
14
+ constructor() {
15
+ this.gltfloader = new GLTFLoader();
16
+ this.dracoloader = new DRACOLoader();
17
+ this.dracoloader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
18
+ this.gltfloader.setDRACOLoader(this.dracoloader);
19
+ }
20
+
21
+ private progress: Map<string, number> = new Map<string, number>();
22
+
23
+ public async LoadGLTF(uri: string): Promise<GLTF> {
24
+ const progEvent = (p: ProgressEvent<EventTarget>): void => {
25
+ this.progress.set(uri, p.loaded / p.total);
26
+ }
27
+
28
+ this.progress.set(uri, 0);
29
+
30
+ return new Promise<GLTF>((resolve, reject) => {
31
+ this.gltfloader.loadAsync(uri, progEvent).then(resolve).catch(reject);
32
+ })
33
+ }
34
+
35
+ public PollProgress(): number {
36
+ let total = 0;
37
+ this.progress.forEach((progress: number) => {
38
+ total += progress;
39
+ });
40
+
41
+ if (this.progress.size === 0) return 1;
42
+ return total / this.progress.size;
43
+ }
44
+ }
@@ -0,0 +1,52 @@
1
+ import DIVELoadingManager from '../LoadingManager';
2
+
3
+ const mock_setDRACOLoader = jest.fn();
4
+ const mock_setDecoderPath = jest.fn();
5
+
6
+ jest.mock('three/examples/jsm/Addons.js', () => {
7
+ return {
8
+ GLTFLoader: jest.fn(function () {
9
+
10
+ this.loadAsync = (uri: string, progEvent: (p: ProgressEvent<EventTarget>) => void) => new Promise<void>((resolve) => {
11
+ progEvent({ loaded: 0, total: 1 } as ProgressEvent<EventTarget>);
12
+ resolve();
13
+ });
14
+ this.setDRACOLoader = mock_setDRACOLoader;
15
+ return this;
16
+ }),
17
+ DRACOLoader: jest.fn(() => {
18
+ return {
19
+ setDecoderPath: mock_setDecoderPath,
20
+ }
21
+ }),
22
+ }
23
+ });
24
+
25
+ describe('dive/loadingmanager/DIVELoadingManager', () => {
26
+ it('should instantiate', () => {
27
+ const testLight = new DIVELoadingManager();
28
+ expect(testLight).toBeDefined();
29
+ expect(mock_setDecoderPath).toHaveBeenCalledTimes(1);
30
+ expect(mock_setDRACOLoader).toHaveBeenCalledTimes(1);
31
+ });
32
+
33
+ it('should return GLTF promise', () => {
34
+ const testLight = new DIVELoadingManager();
35
+ const promise = testLight.LoadGLTF('test.gltf');
36
+ expect(promise).toBeDefined();
37
+ });
38
+
39
+ it('should return progress', () => {
40
+ const testLight = new DIVELoadingManager();
41
+ testLight.LoadGLTF('test.gltf');
42
+ const progress = testLight.PollProgress();
43
+ expect(progress).toBe(0);
44
+ });
45
+
46
+ it('should return done progress without load', () => {
47
+ const testLight = new DIVELoadingManager();
48
+ const progress = testLight.PollProgress();
49
+ expect(progress).toBe(1);
50
+ });
51
+
52
+ });
@@ -0,0 +1,12 @@
1
+ import { DIVEMath } from '../index';
2
+
3
+ describe('dive/math', () => {
4
+ it('should be defined', () => {
5
+ expect(DIVEMath).toBeDefined();
6
+ expect(DIVEMath.ceilExp).toBeDefined();
7
+ expect(DIVEMath.floorExp).toBeDefined();
8
+ expect(DIVEMath.roundExp).toBeDefined();
9
+ expect(DIVEMath.toFixedExp).toBeDefined();
10
+ expect(DIVEMath.truncateExp).toBeDefined();
11
+ });
12
+ });
@@ -0,0 +1,12 @@
1
+ import ceilExp from '../ceilExp';
2
+
3
+ describe('dive/math/ceil/ceilExp', () => {
4
+ it('should ceilExp', () => {
5
+ expect(ceilExp(-0.5)).toBe(0);
6
+ expect(ceilExp(0.5)).toBe(1);
7
+ expect(ceilExp(0.55)).toBe(1);
8
+ expect(ceilExp(0.49)).toBe(1);
9
+ expect(ceilExp(0.49, 2)).toBe(0.49);
10
+ expect(ceilExp(-1.49, 2)).toBe(-1.49);
11
+ });
12
+ });
@@ -0,0 +1,6 @@
1
+ import shift from "../helper/shift.ts";
2
+
3
+ export default function ceilExp(number: number, decimals: number = 0): number {
4
+ const n = shift(number, +decimals);
5
+ return shift(Math.ceil(n), -decimals);
6
+ }
@@ -0,0 +1,14 @@
1
+ import floorExp from '../floorExp';
2
+
3
+ describe('dive/math/floor/floorExp', () => {
4
+ it('should floorExp', () => {
5
+ expect(floorExp(-0.5)).toBe(-1);
6
+ expect(floorExp(0.5)).toBe(0);
7
+ expect(floorExp(0.55)).toBe(0);
8
+ expect(floorExp(0.49)).toBe(0);
9
+ expect(floorExp(1.49)).toBe(1);
10
+ expect(floorExp(0.49, 2)).toBe(0.49);
11
+ expect(floorExp(1.49, 2)).toBe(1.49);
12
+ expect(floorExp(-1.49, 2)).toBe(-1.49);
13
+ });
14
+ });
@@ -0,0 +1,6 @@
1
+ import shift from "../helper/shift.ts";
2
+
3
+ export default function floorExp(number: number, decimals: number = 0): number {
4
+ const n = shift(number, +decimals);
5
+ return shift(Math.floor(n), -decimals);
6
+ }
@@ -0,0 +1,12 @@
1
+ import shift from '../shift';
2
+
3
+ describe('dive/math/helper/shift', () => {
4
+ it('should shift', () => {
5
+ expect(shift(0.5, 2)).toBe(50);
6
+ expect(shift(0.55, 2)).toBe(55);
7
+ expect(shift(0.49, 2)).toBe(49);
8
+ expect(shift(1.49, 2)).toBe(149);
9
+ expect(shift(0.49, 2)).toBe(49);
10
+ expect(shift(1.49, 2)).toBe(149);
11
+ });
12
+ });
@@ -0,0 +1,4 @@
1
+ export default function shift(value: number, exponent: number): number {
2
+ const subvalues = (value + 'e').split('e');
3
+ return +(subvalues[0] + 'e' + (+subvalues[1] + (exponent || 0)));
4
+ }
@@ -0,0 +1,19 @@
1
+ import ceilExp from "./ceil/ceilExp.ts";
2
+ import floorExp from "./floor/floorExp.ts";
3
+ import roundExp from "./round/roundExp.ts";
4
+ import toFixedExp from "./toFixed/toFixedExp.ts";
5
+ import truncateExp from "./truncate/truncateExp.ts";
6
+
7
+ export const DIVEMath: {
8
+ ceilExp: typeof ceilExp;
9
+ floorExp: typeof floorExp;
10
+ roundExp: typeof roundExp;
11
+ toFixedExp: typeof toFixedExp;
12
+ truncateExp: typeof truncateExp;
13
+ } = {
14
+ ceilExp,
15
+ floorExp,
16
+ roundExp,
17
+ toFixedExp,
18
+ truncateExp,
19
+ }
@@ -0,0 +1,14 @@
1
+ import roundExp from '../roundExp';
2
+
3
+ describe('dive/math/round/roundExp', () => {
4
+ it('should roundExp', () => {
5
+ expect(roundExp(-0.5)).toBe(-1);
6
+ expect(roundExp(0.5)).toBe(1);
7
+ expect(roundExp(0.55)).toBe(1);
8
+ expect(roundExp(0.49)).toBe(0);
9
+ expect(roundExp(1.49)).toBe(1);
10
+ expect(roundExp(0.49, 2)).toBe(0.49);
11
+ expect(roundExp(1.49, 2)).toBe(1.49);
12
+ expect(roundExp(-1.49, 2)).toBe(-1.49);
13
+ });
14
+ });
@@ -0,0 +1,7 @@
1
+ import shift from "../helper/shift.ts";
2
+
3
+ export default function roundExponential(number: number, decimals: number = 0): number {
4
+ if (number < 0) return -roundExponential(-number, decimals);
5
+ const n = shift(number, +decimals);
6
+ return shift(Math.round(n), -decimals);
7
+ };
@@ -0,0 +1,14 @@
1
+ import toFixedExp from '../toFixedExp';
2
+
3
+ describe('dive/math/toFixed/toFixedExp', () => {
4
+ it('should toFixedExp', () => {
5
+ expect(toFixedExp(-0.5)).toBe("0");
6
+ expect(toFixedExp(0.5)).toBe("1");
7
+ expect(toFixedExp(0.55)).toBe("1");
8
+ expect(toFixedExp(0.49)).toBe("0");
9
+ expect(toFixedExp(1.49)).toBe("1");
10
+ expect(toFixedExp(0.49, 2)).toBe("0.49");
11
+ expect(toFixedExp(1.49, 2)).toBe("1.49");
12
+ expect(toFixedExp(-1.49, 2)).toBe("-1.49");
13
+ });
14
+ });
@@ -0,0 +1,6 @@
1
+ import shift from "../helper/shift.ts";
2
+
3
+ export default function toFixedExp(number: number, decimals: number = 0): string {
4
+ const n = shift(number, +decimals);
5
+ return shift(Math.round(n), -decimals).toFixed(decimals);
6
+ }
@@ -0,0 +1,14 @@
1
+ import truncateExp from '../truncateExp';
2
+
3
+ describe('dive/math/truncate/truncateExp', () => {
4
+ it('should truncateExp', () => {
5
+ expect(truncateExp(-0.5)).toBe(0);
6
+ expect(truncateExp(0.5)).toBe(0);
7
+ expect(truncateExp(0.55)).toBe(0);
8
+ expect(truncateExp(0.49)).toBe(0);
9
+ expect(truncateExp(1.49)).toBe(1);
10
+ expect(truncateExp(0.49, 2)).toBe(0.49);
11
+ expect(truncateExp(1.49, 2)).toBe(1.49);
12
+ expect(truncateExp(-1.49, 2)).toBe(-1.49);
13
+ });
14
+ });
@@ -0,0 +1,6 @@
1
+ import shift from "../helper/shift.ts";
2
+
3
+ export default function truncateExp(number: number, decimals: number = 0): number {
4
+ const n = shift(number, +decimals);
5
+ return shift(Math.trunc(n), -decimals);
6
+ }
@@ -0,0 +1,65 @@
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";
6
+
7
+ /**
8
+ * Creates renderings of the current scene
9
+ *
10
+ * @module
11
+ */
12
+
13
+ export default class DIVEMediaCreator {
14
+ private renderer: DIVERenderer;
15
+ private scene: DIVEScene;
16
+ private controller: DIVEOrbitControls;
17
+
18
+ constructor(renderer: DIVERenderer, scene: DIVEScene, controller: DIVEOrbitControls) {
19
+ this.renderer = renderer;
20
+ this.scene = scene;
21
+ this.controller = controller;
22
+ }
23
+
24
+ public GenerateMedia(position: Vector3Like, target: Vector3Like, width: number, height: number): string {
25
+ const resetPosition = this.controller.object.position.clone();
26
+ const resetRotation = this.controller.object.quaternion.clone();
27
+
28
+ this.renderer.OnResize(width, height);
29
+ this.controller.object.OnResize(width, height);
30
+
31
+ this.controller.object.position.copy(position);
32
+ this.controller.target.copy(target);
33
+ this.controller.update();
34
+
35
+
36
+ const dataUri = this.DrawCanvas().toDataURL();
37
+
38
+ this.controller.object.position.copy(resetPosition);
39
+ this.controller.object.quaternion.copy(resetRotation);
40
+
41
+ return dataUri;
42
+ }
43
+
44
+ public DrawCanvas(canvasElement?: HTMLCanvasElement): HTMLCanvasElement {
45
+ // save current canvas
46
+ const restore = this.renderer.domElement;
47
+ if (canvasElement) {
48
+ this.renderer.domElement = canvasElement;
49
+ }
50
+
51
+ // draw canvas
52
+ this.controller.object.layers.mask = DIVEPerspectiveCamera.LIVE_VIEW_LAYER_MASK;
53
+ this.renderer.render(this.scene, this.controller.object);
54
+ this.controller.object.layers.mask = DIVEPerspectiveCamera.EDITOR_VIEW_LAYER_MASK;
55
+
56
+ const returnCanvas = this.renderer.domElement;
57
+
58
+ // restore canvas
59
+ if (canvasElement) {
60
+ this.renderer.domElement = restore;
61
+ }
62
+
63
+ return returnCanvas;
64
+ }
65
+ }
@@ -0,0 +1,113 @@
1
+ import DIVEMediaCreator from '../MediaCreator';
2
+ import DIVERenderer from '../../renderer/Renderer';
3
+ import DIVEScene from '../../scene/Scene';
4
+ import DIVEPerspectiveCamera, { DIVEPerspectiveCameraDefaultSettings } from '../../camera/PerspectiveCamera';
5
+ import { COMPov } from '../../com';
6
+ import DIVEOrbitControls from '../../controls/OrbitControls';
7
+
8
+ /**
9
+ * @jest-environment jsdom
10
+ */
11
+
12
+ const mock_render = jest.fn();
13
+ const mock_toDataURL = jest.fn();
14
+
15
+ jest.mock('../../scene/Scene', () => {
16
+ return jest.fn(() => {
17
+ return {};
18
+ });
19
+ });
20
+
21
+ jest.mock('../../camera/PerspectiveCamera', () => {
22
+ return jest.fn(function () {
23
+ this.position = {
24
+ clone: jest.fn(),
25
+ copy: jest.fn(),
26
+ };
27
+ this.quaternion = {
28
+ clone: jest.fn(),
29
+ copy: jest.fn(),
30
+ };
31
+ this.orbitControls = {
32
+ target: {
33
+ clone: jest.fn(),
34
+ copy: jest.fn(),
35
+ },
36
+ update: jest.fn(),
37
+ };
38
+ this.layers = {
39
+ mask: 0,
40
+ }
41
+ return this;
42
+ });
43
+ });
44
+
45
+ jest.mock('../../controls/OrbitControls', () => {
46
+ return jest.fn(function () {
47
+ this.object = {
48
+ position: {
49
+ clone: jest.fn(),
50
+ copy: jest.fn(),
51
+ },
52
+ quaternion: {
53
+ clone: jest.fn(),
54
+ copy: jest.fn(),
55
+ },
56
+ layers: {
57
+ mask: 0,
58
+ },
59
+ OnResize: jest.fn(),
60
+ };
61
+
62
+ this.target = {
63
+ clone: jest.fn(),
64
+ copy: jest.fn(),
65
+ };
66
+
67
+ this.update = jest.fn();
68
+
69
+ return this;
70
+ });
71
+ });
72
+
73
+ jest.mock('../../renderer/Renderer', () => {
74
+ return jest.fn(function () {
75
+ this.domElement = {
76
+ toDataURL: mock_toDataURL,
77
+ }
78
+ this.render = mock_render;
79
+ this.OnResize = jest.fn();
80
+ return this;
81
+ });
82
+ });
83
+
84
+ let mediaCreator: DIVEMediaCreator;
85
+
86
+ describe('dive/mediacreator/DIVEMediaCreator', () => {
87
+ beforeEach(() => {
88
+ jest.clearAllMocks();
89
+ mediaCreator = new DIVEMediaCreator(new DIVERenderer(), new DIVEScene(), new DIVEOrbitControls(new DIVEPerspectiveCamera(DIVEPerspectiveCameraDefaultSettings), new DIVERenderer()));
90
+ });
91
+
92
+ it('should instantiate', () => {
93
+ expect(mediaCreator).toBeDefined();
94
+ });
95
+
96
+ it('should generate media', () => {
97
+ const mock_POV = {
98
+ position: { x: 0, y: 0, z: 0 },
99
+ target: { x: 0, y: 0, z: 0 }
100
+ } as COMPov;
101
+ expect(() => {
102
+ mediaCreator.GenerateMedia(mock_POV.position, mock_POV.target, 800, 600)
103
+ }).not.toThrow();
104
+ expect(mock_render).toHaveBeenCalledTimes(1);
105
+ expect(mock_toDataURL).toHaveBeenCalledTimes(1);
106
+ });
107
+
108
+ it('should draw canvas with custom canvas', () => {
109
+ const canvas = document.createElement('canvas');
110
+ mediaCreator.DrawCanvas(canvas);
111
+ expect(mock_render).toHaveBeenCalledTimes(1);
112
+ });
113
+ });
@@ -0,0 +1,72 @@
1
+ import { Box3, Object3D, Vector3, Vector3Like } from 'three';
2
+ import { DIVESelectable } from '../interface/Selectable';
3
+ import { PRODUCT_LAYER_MASK } from '../constant/VisibilityLayerMask';
4
+ import { DIVEMoveable } from '../interface/Moveable';
5
+ import DIVECommunication from '../com/Communication';
6
+ import type { GLTF, TransformControls } from 'three/examples/jsm/Addons.js';
7
+
8
+ /**
9
+ * A basic model class.
10
+ *
11
+ * It does calculate it's own bounding box which is used for positioning on the floor.
12
+ *
13
+ * Can be moved and selected.
14
+ *
15
+ * @module
16
+ */
17
+
18
+ export default class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable {
19
+ public isSelectable: true = true;
20
+ public isMoveable: true = true;
21
+ public gizmo: TransformControls | null = null;
22
+
23
+ private boundingBox: Box3;
24
+
25
+ constructor() {
26
+ super();
27
+
28
+ this.layers.mask = PRODUCT_LAYER_MASK;
29
+
30
+ this.boundingBox = new Box3();
31
+ }
32
+
33
+ public SetModel(gltf: GLTF): void {
34
+ this.clear();
35
+
36
+ gltf.scene.traverse((child) => {
37
+ child.castShadow = true;
38
+ child.receiveShadow = true;
39
+
40
+ child.layers.mask = this.layers.mask;
41
+ this.boundingBox.expandByObject(child);
42
+ });
43
+
44
+ this.add(gltf.scene);
45
+ }
46
+
47
+ public SetPosition(position: Vector3Like): void {
48
+ this.position.set(position.x, position.y, position.z);
49
+ }
50
+
51
+ public SetRotation(rotation: Vector3Like): void {
52
+ this.rotation.setFromVector3(new Vector3(rotation.x, rotation.y, rotation.z));
53
+ }
54
+
55
+ public SetScale(scale: Vector3Like): void {
56
+ this.scale.set(scale.x, scale.y, scale.z);
57
+ }
58
+
59
+ public SetToWorldOrigin(): void {
60
+ this.position.set(0, 0, 0);
61
+ DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
62
+ }
63
+
64
+ public PlaceOnFloor(): void {
65
+ this.position.y = -this.boundingBox.min.y * this.scale.y;
66
+ DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
67
+ }
68
+
69
+ public onMove(): void {
70
+ DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
71
+ }
72
+ }