@shopware-ag/dive 1.12.1 → 1.14.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 (77) hide show
  1. package/build/dive.cjs +458 -405
  2. package/build/dive.cjs.map +1 -1
  3. package/build/dive.d.cts +314 -78
  4. package/build/dive.d.ts +314 -78
  5. package/build/dive.js +430 -377
  6. package/build/dive.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/__test__/DIVE.test.ts +33 -29
  9. package/src/axiscamera/AxisCamera.ts +1 -1
  10. package/src/axiscamera/__test__/AxisCamera.test.ts +1 -1
  11. package/src/com/Communication.ts +59 -14
  12. package/src/com/__test__/Communication.test.ts +111 -31
  13. package/src/com/actions/index.ts +2 -0
  14. package/src/com/actions/object/addobject.ts +1 -1
  15. package/src/com/actions/object/deleteobject.ts +1 -1
  16. package/src/com/actions/object/deselectobject.ts +1 -1
  17. package/src/com/actions/object/getallobjects.ts +1 -1
  18. package/src/com/actions/object/getobjects.ts +1 -1
  19. package/src/com/actions/object/selectobject.ts +1 -1
  20. package/src/com/actions/object/setparent.ts +9 -0
  21. package/src/com/actions/object/updateobject.ts +1 -1
  22. package/src/com/actions/scene/getallscenedata.ts +1 -1
  23. package/src/com/types/COMBaseEntity.ts +9 -0
  24. package/src/com/types/COMEntity.ts +7 -0
  25. package/src/com/types/COMEntityType.ts +1 -0
  26. package/src/com/types/COMGeometry.ts +6 -0
  27. package/src/com/types/COMGroup.ts +9 -0
  28. package/src/com/types/COMLight.ts +10 -0
  29. package/src/com/types/COMMaterial.ts +12 -0
  30. package/src/com/types/COMModel.ts +12 -0
  31. package/src/com/types/COMPov.ts +8 -0
  32. package/src/com/types/COMPrimitive.ts +12 -0
  33. package/src/com/types/index.ts +21 -0
  34. package/src/dive.ts +9 -16
  35. package/src/grid/Grid.ts +1 -1
  36. package/src/grid/__test__/Grid.test.ts +1 -1
  37. package/src/group/Group.ts +126 -0
  38. package/src/group/__test__/Group.test.ts +100 -0
  39. package/src/helper/findSceneRecursive/findSceneRecursive.ts +1 -1
  40. package/src/light/AmbientLight.ts +3 -0
  41. package/src/light/PointLight.ts +6 -3
  42. package/src/light/SceneLight.ts +2 -0
  43. package/src/light/__test__/PointLight.test.ts +8 -6
  44. package/src/light/__test__/SceneLight.test.ts +8 -6
  45. package/src/loadingmanager/LoadingManager.ts +1 -1
  46. package/src/loadingmanager/__test__/LoadingManager.test.ts +1 -1
  47. package/src/mediacreator/MediaCreator.ts +1 -1
  48. package/src/mediacreator/__test__/MediaCreator.test.ts +6 -4
  49. package/src/model/Model.ts +8 -7
  50. package/src/model/__test__/Model.test.ts +13 -10
  51. package/src/primitive/Primitive.ts +4 -3
  52. package/src/primitive/__test__/Primitive.test.ts +9 -7
  53. package/src/primitive/floor/Floor.ts +1 -1
  54. package/src/primitive/floor/__test__/Floor.test.ts +1 -1
  55. package/src/renderer/__test__/Renderer.test.ts +1 -1
  56. package/src/scene/Scene.ts +29 -9
  57. package/src/scene/__test__/Scene.test.ts +33 -19
  58. package/src/scene/root/Root.ts +239 -72
  59. package/src/scene/root/__test__/Root.test.ts +476 -114
  60. package/src/toolbox/BaseTool.ts +1 -1
  61. package/src/toolbox/Toolbox.ts +1 -1
  62. package/src/toolbox/__test__/BaseTool.test.ts +1 -1
  63. package/src/toolbox/__test__/Toolbox.test.ts +1 -1
  64. package/src/toolbox/select/SelectTool.ts +1 -1
  65. package/src/toolbox/select/__test__/SelectTool.test.ts +11 -9
  66. package/src/toolbox/transform/TransformTool.ts +1 -1
  67. package/src/toolbox/transform/__test__/TransformTool.test.ts +12 -10
  68. package/src/types/SceneObjects.ts +14 -0
  69. package/src/types/index.ts +5 -0
  70. package/src/com/index.ts +0 -3
  71. package/src/com/types.ts +0 -58
  72. package/src/scene/root/lightroot/LightRoot.ts +0 -99
  73. package/src/scene/root/lightroot/__test__/LightRoot.test.ts +0 -145
  74. package/src/scene/root/modelroot/ModelRoot.ts +0 -98
  75. package/src/scene/root/modelroot/__test__/ModelRoot.test.ts +0 -189
  76. package/src/scene/root/primitiveroot/PrimitiveRoot.ts +0 -88
  77. package/src/scene/root/primitiveroot/__test__/PrimitiveRoot.test.ts +0 -181
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware-ag/dive",
3
- "version": "1.12.1",
3
+ "version": "1.14.0",
4
4
  "description": "Shopware Spatial Framework",
5
5
  "type": "module",
6
6
  "main": "./build/dive.cjs",
@@ -37,19 +37,21 @@ jest.mock('three/src/math/MathUtils', () => {
37
37
  });
38
38
 
39
39
  jest.mock('../com/Communication.ts', () => {
40
- return jest.fn(function () {
41
- this.PerformAction = jest.fn().mockReturnValue({
42
- position: { x: 0, y: 0, z: 0 },
43
- target: { x: 0, y: 0, z: 0 },
44
- });
45
- this.Subscribe = jest.fn((action: string, callback: (data: { id: string }) => void) => {
46
- callback({ id: 'incorrect id' });
47
- callback({ id: 'test_uuid' });
48
- });
49
- this.DestroyInstance = jest.fn();
40
+ return {
41
+ DIVECommunication: jest.fn(function () {
42
+ this.PerformAction = jest.fn().mockReturnValue({
43
+ position: { x: 0, y: 0, z: 0 },
44
+ target: { x: 0, y: 0, z: 0 },
45
+ });
46
+ this.Subscribe = jest.fn((action: string, callback: (data: { id: string }) => void) => {
47
+ callback({ id: 'incorrect id' });
48
+ callback({ id: 'test_uuid' });
49
+ });
50
+ this.DestroyInstance = jest.fn();
50
51
 
51
- return this;
52
- });
52
+ return this;
53
+ })
54
+ };
53
55
  });
54
56
 
55
57
  jest.mock('../renderer/Renderer.ts', () => {
@@ -83,23 +85,25 @@ jest.mock('../renderer/Renderer.ts', () => {
83
85
  });
84
86
 
85
87
  jest.mock('../scene/Scene.ts', () => {
86
- return jest.fn(function () {
87
- this.add = jest.fn();
88
- this.isObject3D = true;
89
- this.parent = null;
90
- this.dispatchEvent = jest.fn();
91
- this.position = {
92
- set: jest.fn(),
93
- }
94
- this.SetIntensity = jest.fn();
95
- this.SetEnabled = jest.fn();
96
- this.SetColor = jest.fn();
97
- this.userData = {
98
- id: undefined,
99
- }
100
- this.removeFromParent = jest.fn();
101
- return this;
102
- });
88
+ return {
89
+ DIVEScene: jest.fn(function () {
90
+ this.add = jest.fn();
91
+ this.isObject3D = true;
92
+ this.parent = null;
93
+ this.dispatchEvent = jest.fn();
94
+ this.position = {
95
+ set: jest.fn(),
96
+ }
97
+ this.SetIntensity = jest.fn();
98
+ this.SetEnabled = jest.fn();
99
+ this.SetColor = jest.fn();
100
+ this.userData = {
101
+ id: undefined,
102
+ }
103
+ this.removeFromParent = jest.fn();
104
+ return this;
105
+ })
106
+ };
103
107
  });
104
108
 
105
109
  jest.mock('../camera/PerspectiveCamera.ts', () => {
@@ -3,7 +3,7 @@ import SpriteText from "three-spritetext";
3
3
  import { COORDINATE_LAYER_MASK } from "../constant/VisibilityLayerMask.ts";
4
4
  import { AxesColorRed, AxesColorGreen, AxesColorBlue, AxesColorRedLetter, AxesColorGreenLetter, AxesColorBlueLetter } from "../constant/AxisHelperColors.ts";
5
5
  import { DIVERenderer } from "../renderer/Renderer.ts";
6
- import DIVEScene from "../scene/Scene.ts";
6
+ import { DIVEScene } from "../scene/Scene.ts";
7
7
  import DIVEOrbitControls from "../controls/OrbitControls.ts";
8
8
 
9
9
  /**
@@ -1,7 +1,7 @@
1
1
  import { AxesHelper, Matrix4, OrthographicCamera, Vector4 } from 'three';
2
2
  import DIVEAxisCamera from '../AxisCamera';
3
3
  import { DIVERenderer } from '../../renderer/Renderer';
4
- import DIVEScene from '../../scene/Scene';
4
+ import { DIVEScene } from '../../scene/Scene';
5
5
  import DIVEOrbitControls from '../../controls/OrbitControls';
6
6
 
7
7
  jest.mock('three', () => {
@@ -1,17 +1,17 @@
1
1
  import { Actions } from "./actions/index.ts";
2
2
  import { generateUUID } from 'three/src/math/MathUtils';
3
+ import { isSelectTool } from "../toolbox/select/SelectTool.ts";
3
4
 
4
5
  // type imports
5
6
  import { type Color, type MeshStandardMaterial } from "three";
6
- import { type COMLight, type COMModel, type COMEntity, type COMPov } from "./types.ts";
7
- import type DIVEScene from "../scene/Scene.ts";
7
+ import { type COMLight, type COMModel, type COMEntity, type COMPov } from "./types";
8
+ import { type DIVEScene } from "../scene/Scene.ts";
8
9
  import type DIVEToolbox from "../toolbox/Toolbox.ts";
9
10
  import type DIVEOrbitControls from "../controls/OrbitControls.ts";
10
- import type DIVEModel from "../model/Model.ts";
11
+ import { type DIVEModel } from "../model/Model.ts";
11
12
  import { type DIVEMediaCreator } from "../mediacreator/MediaCreator.ts";
12
13
  import { type DIVERenderer } from "../renderer/Renderer.ts";
13
14
  import { type DIVESelectable } from "../interface/Selectable.ts";
14
- import { isSelectTool } from "../toolbox/select/SelectTool.ts";
15
15
 
16
16
  type EventListener<Action extends keyof Actions> = (payload: Actions[Action]['PAYLOAD']) => void;
17
17
 
@@ -37,7 +37,7 @@ type Unsubscribe = () => boolean;
37
37
  * @module
38
38
  */
39
39
 
40
- export default class DIVECommunication {
40
+ export class DIVECommunication {
41
41
  private static __instances: DIVECommunication[] = [];
42
42
 
43
43
  public static get(id: string): DIVECommunication | undefined {
@@ -188,6 +188,10 @@ export default class DIVECommunication {
188
188
  returnValue = this.generateMedia(payload as Actions['GENERATE_MEDIA']['PAYLOAD']);
189
189
  break;
190
190
  }
191
+ case 'SET_PARENT': {
192
+ returnValue = this.setParent(payload as Actions['SET_PARENT']['PAYLOAD']);
193
+ break;
194
+ }
191
195
  }
192
196
 
193
197
  this.dispatch(action, payload);
@@ -225,8 +229,8 @@ export default class DIVECommunication {
225
229
  name: this.scene.name,
226
230
  mediaItem: null,
227
231
  backgroundColor: '#' + (this.scene.background as Color).getHexString(),
228
- floorEnabled: this.scene.Root.Floor.visible,
229
- floorColor: '#' + (this.scene.Root.Floor.material as MeshStandardMaterial).color.getHexString(),
232
+ floorEnabled: this.scene.Floor.visible,
233
+ floorColor: '#' + (this.scene.Floor.material as MeshStandardMaterial).color.getHexString(),
230
234
  userCamera: {
231
235
  position: this.controller.object.position.clone(),
232
236
  target: this.controller.target.clone(),
@@ -260,6 +264,8 @@ export default class DIVECommunication {
260
264
  private addObject(payload: Actions['ADD_OBJECT']['PAYLOAD']): Actions['ADD_OBJECT']['RETURN'] {
261
265
  if (this.registered.get(payload.id)) return false;
262
266
 
267
+ if (payload.parent === undefined) payload.parent = null;
268
+
263
269
  this.registered.set(payload.id, payload);
264
270
 
265
271
  this.scene.AddSceneObject(payload);
@@ -274,7 +280,7 @@ export default class DIVECommunication {
274
280
  this.registered.set(payload.id, { ...objectToUpdate, ...payload });
275
281
 
276
282
  const updatedObject = this.registered.get(payload.id)!;
277
- this.scene.UpdateSceneObject(updatedObject);
283
+ this.scene.UpdateSceneObject({ ...payload, id: updatedObject.id, entityType: updatedObject.entityType });
278
284
 
279
285
  Object.assign(payload, updatedObject);
280
286
 
@@ -444,19 +450,19 @@ export default class DIVECommunication {
444
450
  if (payload.name !== undefined) this.scene.name = payload.name;
445
451
  if (payload.backgroundColor !== undefined) this.scene.SetBackground(payload.backgroundColor);
446
452
 
447
- if (payload.gridEnabled !== undefined) this.scene.Root.Grid.SetVisibility(payload.gridEnabled);
453
+ if (payload.gridEnabled !== undefined) this.scene.Grid.SetVisibility(payload.gridEnabled);
448
454
 
449
- if (payload.floorEnabled !== undefined) this.scene.Root.Floor.SetVisibility(payload.floorEnabled);
450
- if (payload.floorColor !== undefined) this.scene.Root.Floor.SetColor(payload.floorColor);
455
+ if (payload.floorEnabled !== undefined) this.scene.Floor.SetVisibility(payload.floorEnabled);
456
+ if (payload.floorColor !== undefined) this.scene.Floor.SetColor(payload.floorColor);
451
457
 
452
458
 
453
459
  // fill payload with current values
454
460
  // TODO optmize this
455
461
  payload.name = this.scene.name;
456
462
  payload.backgroundColor = '#' + (this.scene.background as Color).getHexString();
457
- payload.gridEnabled = this.scene.Root.Grid.visible;
458
- payload.floorEnabled = this.scene.Root.Floor.visible;
459
- payload.floorColor = '#' + (this.scene.Root.Floor.material as MeshStandardMaterial).color.getHexString();
463
+ payload.gridEnabled = this.scene.Grid.visible;
464
+ payload.floorEnabled = this.scene.Floor.visible;
465
+ payload.floorColor = '#' + (this.scene.Floor.material as MeshStandardMaterial).color.getHexString();
460
466
 
461
467
  return true;
462
468
  }
@@ -476,5 +482,44 @@ export default class DIVECommunication {
476
482
 
477
483
  return true;
478
484
  }
485
+
486
+ private setParent(payload: Actions['SET_PARENT']['PAYLOAD']): Actions['SET_PARENT']['RETURN'] {
487
+ const object = this.registered.get(payload.object.id);
488
+ if (!object) return false;
489
+
490
+ const sceneObject = this.scene.GetSceneObject(object);
491
+ if (!sceneObject) return false;
492
+
493
+ if (payload.parent === null) {
494
+ // detach from current parent
495
+ this.scene.Root.attach(sceneObject);
496
+ return true;
497
+ }
498
+
499
+ if (payload.object.id === payload.parent.id) {
500
+ // cannot attach object to itself
501
+ return false;
502
+ }
503
+
504
+ const parent = this.registered.get(payload.parent.id);
505
+ if (!parent) {
506
+ // detach from current parent
507
+ this.scene.Root.attach(sceneObject);
508
+ return true;
509
+ }
510
+
511
+ // attach to new parent
512
+ const parentObject = this.scene.GetSceneObject(parent);
513
+ if (!parentObject) {
514
+ // detach from current parent
515
+ this.scene.Root.attach(sceneObject);
516
+ return true;
517
+ }
518
+
519
+ // attach to new parent
520
+ parentObject.attach(sceneObject);
521
+ return true;
522
+ }
479
523
  }
480
524
 
525
+ export type { Actions } from './actions/index.ts';
@@ -1,5 +1,4 @@
1
- import DIVECommunication from '../Communication';
2
- import '..';
1
+ import { DIVECommunication } from '../Communication';
3
2
  import '../types';
4
3
  import '../actions';
5
4
  import '../actions/camera/movecamera';
@@ -22,12 +21,12 @@ import '../actions/scene/updatescene';
22
21
  import '../actions/toolbox/select/setgizmomode';
23
22
  import '../actions/toolbox/transform/setgizmovisible';
24
23
  import '../actions/camera/getcameratransform';
25
- import type DIVEScene from '../../scene/Scene';
24
+ import type { DIVEScene } from '../../scene/Scene';
26
25
  import type DIVEToolbox from '../../toolbox/Toolbox';
27
26
  import type DIVEOrbitControls from '../../controls/OrbitControls';
28
27
  import { type DIVERenderer } from '../../renderer/Renderer';
29
- import { type COMLight, type COMModel, type COMPov } from '../types';
30
- import { type Object3D } from 'three';
28
+ import { type COMEntity, type COMEntityType, type COMLight, type COMModel, type COMPov } from '../types';
29
+ import { type DIVESceneObject } from '../../types';
31
30
 
32
31
  jest.mock('three/src/math/MathUtils', () => {
33
32
  return {
@@ -68,25 +67,29 @@ const mockScene = {
68
67
  UpdateSceneObject: jest.fn(),
69
68
  DeleteSceneObject: jest.fn(),
70
69
  PlaceOnFloor: jest.fn(),
71
- GetSceneObject: jest.fn(),
70
+ GetSceneObject: jest.fn().mockReturnValue({
71
+ attach: jest.fn(),
72
+ DropIt: jest.fn(),
73
+ }),
72
74
  background: {
73
75
  getHexString: jest.fn().mockReturnValue('ffffff'),
74
76
  },
75
77
  Root: {
76
- Floor: {
77
- isFloor: true,
78
- visible: true,
79
- material: {
80
- color: {
81
- getHexString: jest.fn().mockReturnValue('ffffff'),
82
- },
78
+ attach: jest.fn(),
79
+ },
80
+ Floor: {
81
+ isFloor: true,
82
+ visible: true,
83
+ material: {
84
+ color: {
85
+ getHexString: jest.fn().mockReturnValue('ffffff'),
83
86
  },
84
- SetVisibility: jest.fn(),
85
- SetColor: jest.fn(),
86
- },
87
- Grid: {
88
- SetVisibility: jest.fn(),
89
87
  },
88
+ SetVisibility: jest.fn(),
89
+ SetColor: jest.fn(),
90
+ },
91
+ Grid: {
92
+ SetVisibility: jest.fn(),
90
93
  },
91
94
  ComputeSceneBB: jest.fn(),
92
95
  } as unknown as DIVEScene;
@@ -350,9 +353,7 @@ describe('dive/communication/DIVECommunication', () => {
350
353
 
351
354
  testCom.PerformAction('ADD_OBJECT', payload);
352
355
 
353
- const placeSpy = jest.spyOn(mockScene, 'GetSceneObject').mockReturnValue({
354
- DropIt: jest.fn(),
355
- } as unknown as Object3D);
356
+ const placeSpy = jest.spyOn(mockScene, 'GetSceneObject');
356
357
 
357
358
  const successPlace = testCom.PerformAction('DROP_IT', payload);
358
359
  expect(successPlace).toBe(true);
@@ -369,9 +370,7 @@ describe('dive/communication/DIVECommunication', () => {
369
370
 
370
371
  uri: "https://threejs.org/examples/models/gltf/LittlestTokyo.glb",
371
372
  };
372
- const placeSpy = jest.spyOn(mockScene, 'GetSceneObject').mockReturnValue({
373
- DropIt: jest.fn(),
374
- } as unknown as Object3D);
373
+ const placeSpy = jest.spyOn(mockScene, 'GetSceneObject');
375
374
 
376
375
  const successPlace = testCom.PerformAction('DROP_IT', payload);
377
376
  expect(successPlace).toBe(false);
@@ -400,7 +399,7 @@ describe('dive/communication/DIVECommunication', () => {
400
399
 
401
400
  it('should perform action PLACE_ON_FLOOR without existing model', () => {
402
401
  const payload = {
403
- entityType: "model",
402
+ entityType: "model" as COMEntityType,
404
403
  id: "model",
405
404
  position: { x: 0, y: 0, z: 0 },
406
405
  rotation: { x: 0, y: 0, z: 0 },
@@ -525,6 +524,7 @@ describe('dive/communication/DIVECommunication', () => {
525
524
  id: "pov",
526
525
  position: { x: 0, y: 0, z: 0 },
527
526
  target: { x: 0, y: 0, z: 0 },
527
+ parent: null,
528
528
  }],
529
529
  floorColor: "#ffffff",
530
530
  floorEnabled: true,
@@ -534,6 +534,7 @@ describe('dive/communication/DIVECommunication', () => {
534
534
  type: "ambient",
535
535
  intensity: 0.5,
536
536
  color: 'white',
537
+ parent: null,
537
538
  }],
538
539
  mediaItem: null,
539
540
  name: undefined,
@@ -543,7 +544,7 @@ describe('dive/communication/DIVECommunication', () => {
543
544
  position: { x: 0, y: 0, z: 0 },
544
545
  rotation: { x: 0, y: 0, z: 0 },
545
546
  scale: { x: 0.01, y: 0.01, z: 0.01 },
546
-
547
+ parent: null,
547
548
  uri: "https://threejs.org/examples/models/gltf/LittlestTokyo.glb",
548
549
  }],
549
550
  spotmarks: [],
@@ -575,7 +576,7 @@ describe('dive/communication/DIVECommunication', () => {
575
576
  expect(Array.from(successWithoutIds.values())).toStrictEqual([]);
576
577
 
577
578
  const successWithIds = testCom.PerformAction('GET_OBJECTS', { ids: ['test1'] });
578
- expect(Array.from(successWithIds.values())).toStrictEqual([{ entityType: "pov", id: "test1", position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 } }]);
579
+ expect(Array.from(successWithIds.values())).toStrictEqual([{ entityType: "pov", id: "test1", position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, parent: null }]);
579
580
  });
580
581
 
581
582
  it('should perform action SELECT_OBJECT', () => {
@@ -594,11 +595,11 @@ describe('dive/communication/DIVECommunication', () => {
594
595
  const success1 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0' });
595
596
  expect(success1).toBe(false);
596
597
 
597
- jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({} as unknown as Object3D);
598
+ jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({} as unknown as DIVESceneObject);
598
599
  const success2 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0' });
599
600
  expect(success2).toBe(false);
600
601
 
601
- jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true } as unknown as Object3D);
602
+ jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true } as unknown as DIVESceneObject);
602
603
  const success3 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0' });
603
604
  expect(success3).toBe(true);
604
605
  });
@@ -619,11 +620,11 @@ describe('dive/communication/DIVECommunication', () => {
619
620
  const success1 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0' });
620
621
  expect(success1).toBe(false);
621
622
 
622
- jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({} as unknown as Object3D);
623
+ jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({} as unknown as DIVESceneObject);
623
624
  const success2 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0' });
624
625
  expect(success2).toBe(false);
625
626
 
626
- jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true } as unknown as Object3D);
627
+ jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true } as unknown as DIVESceneObject);
627
628
  const success3 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0' });
628
629
  expect(success3).toBe(true);
629
630
  });
@@ -750,4 +751,83 @@ describe('dive/communication/DIVECommunication', () => {
750
751
  });
751
752
  expect(success1).toBe(true);
752
753
  });
754
+
755
+ it('should perform action SET_PARENT', () => {
756
+ const object = {
757
+ id: "object",
758
+ } as COMEntity;
759
+ testCom.PerformAction('ADD_OBJECT', object);
760
+
761
+ const objectNotRegistered = {
762
+ id: "objectNotRegistered",
763
+ } as COMEntity;
764
+
765
+ const parent0 = {
766
+ id: "parent0",
767
+ } as COMEntity;
768
+ testCom.PerformAction('ADD_OBJECT', parent0);
769
+
770
+ const parent1 = {
771
+ id: "parent1",
772
+ } as COMEntity;
773
+ testCom.PerformAction('ADD_OBJECT', parent1);
774
+
775
+ const parentNotRegistered = {
776
+ id: "parentNotRegistered",
777
+ } as COMEntity;
778
+
779
+ const attachNotRegisteredObject = testCom.PerformAction('SET_PARENT', {
780
+ object: objectNotRegistered,
781
+ parent: null,
782
+ });
783
+ expect(attachNotRegisteredObject).toBe(false);
784
+
785
+ jest.spyOn(mockScene, 'GetSceneObject').mockImplementationOnce(() => {
786
+ return undefined;
787
+ })
788
+ const attachNonSceneObject = testCom.PerformAction('SET_PARENT', {
789
+ object: object,
790
+ parent: null,
791
+ });
792
+ expect(attachNonSceneObject).toBe(false);
793
+
794
+ const attachToNull = testCom.PerformAction('SET_PARENT', {
795
+ object: object,
796
+ parent: null,
797
+ });
798
+ expect(attachToNull).toBe(true);
799
+
800
+ const attachToItself = testCom.PerformAction('SET_PARENT', {
801
+ object: object,
802
+ parent: object,
803
+ });
804
+ expect(attachToItself).toBe(false);
805
+
806
+ const attachToNotRegsiteredParent = testCom.PerformAction('SET_PARENT', {
807
+ object: object,
808
+ parent: parentNotRegistered,
809
+ });
810
+ expect(attachToNotRegsiteredParent).toBe(true);
811
+
812
+ jest.spyOn(mockScene, 'GetSceneObject').mockImplementationOnce(() => {
813
+ return {
814
+ DropIt: jest.fn(),
815
+ attach: jest.fn(),
816
+ } as unknown as DIVESceneObject;
817
+ }).mockImplementationOnce(() => {
818
+ return undefined;
819
+ });
820
+
821
+ const attachtoNonSceneParent = testCom.PerformAction('SET_PARENT', {
822
+ object: object,
823
+ parent: parent1,
824
+ });
825
+ expect(attachtoNonSceneParent).toBe(true);
826
+
827
+ const attachToValidParent = testCom.PerformAction('SET_PARENT', {
828
+ object: object,
829
+ parent: parent1,
830
+ });
831
+ expect(attachToValidParent).toBe(true);
832
+ });
753
833
  });
@@ -22,6 +22,7 @@ import DROP_IT from "./object/model/dropit.ts";
22
22
  import SET_GIZMO_VISIBILITY from "./toolbox/transform/setgizmovisible.js";
23
23
  import COMPUTE_ENCOMPASSING_VIEW from "./camera/computeencompassingview.ts";
24
24
  import USE_TOOL from "./toolbox/usetool.ts";
25
+ import SET_PARENT from "./object/setparent.ts";
25
26
 
26
27
  export type Actions = {
27
28
  GET_ALL_SCENE_DATA: GET_ALL_SCENE_DATA,
@@ -48,4 +49,5 @@ export type Actions = {
48
49
  MODEL_LOADED: MODEL_LOADED,
49
50
  UPDATE_SCENE: UPDATE_SCENE,
50
51
  GENERATE_MEDIA: GENERATE_MEDIA,
52
+ SET_PARENT: SET_PARENT,
51
53
  };
@@ -1,4 +1,4 @@
1
- import { COMEntity } from "../../types.ts";
1
+ import { COMEntity } from "../../types";
2
2
 
3
3
  export default interface ADD_OBJECT {
4
4
  'PAYLOAD': COMEntity,
@@ -1,4 +1,4 @@
1
- import { COMEntity } from "../../types.ts";
1
+ import { COMEntity } from "../../types";
2
2
 
3
3
  export default interface DELETE_OBJECT {
4
4
  'PAYLOAD': Partial<COMEntity> & { id: string },
@@ -1,4 +1,4 @@
1
- import { COMEntity } from "../../types.ts";
1
+ import { COMEntity } from "../../types";
2
2
 
3
3
  export default interface DESELECT_OBJECT {
4
4
  'PAYLOAD': Partial<COMEntity> & { id: string },
@@ -1,4 +1,4 @@
1
- import { COMEntity } from "../../types.ts";
1
+ import { COMEntity } from "../../types";
2
2
 
3
3
  export default interface GET_ALL_OBJECTS {
4
4
  'PAYLOAD': Map<string, COMEntity>,
@@ -1,4 +1,4 @@
1
- import { COMEntity } from "../../types.ts";
1
+ import { COMEntity } from "../../types";
2
2
 
3
3
  export default interface GET_OBJECTS {
4
4
  'PAYLOAD': { ids: string[] },
@@ -1,4 +1,4 @@
1
- import { COMEntity } from "../../types.ts";
1
+ import { COMEntity } from "../../types";
2
2
 
3
3
  export default interface SELECT_OBJECT {
4
4
  'PAYLOAD': Partial<COMEntity> & { id: string },
@@ -0,0 +1,9 @@
1
+ import { type COMEntity } from "../../types";
2
+
3
+ export default interface SET_PARENT {
4
+ 'PAYLOAD': {
5
+ object: Partial<COMEntity> & { id: string },
6
+ parent: Partial<COMEntity> & { id: string } | null,
7
+ },
8
+ 'RETURN': boolean,
9
+ };
@@ -1,4 +1,4 @@
1
- import { COMEntity } from "../../types.ts";
1
+ import { COMEntity } from "../../types";
2
2
 
3
3
  export default interface UPDATE_OBJECT {
4
4
  'PAYLOAD': Partial<COMEntity> & { id: string },
@@ -1,5 +1,5 @@
1
1
  import { Vector3Like } from "three";
2
- import { COMLight, COMModel, COMPov } from "../../types.ts";
2
+ import { COMLight, COMModel, COMPov } from "../../types";
3
3
 
4
4
  type SceneData = {
5
5
  name: string,
@@ -0,0 +1,9 @@
1
+ import { COMEntityType } from "./COMEntityType";
2
+
3
+ export type COMBaseEntity = {
4
+ id: string;
5
+ name: string;
6
+ entityType: COMEntityType;
7
+ visible: boolean;
8
+ parent?: Partial<COMBaseEntity> & { id: string } | null;
9
+ }
@@ -0,0 +1,7 @@
1
+ import { type COMPov } from "./COMPov";
2
+ import { type COMLight } from "./COMLight";
3
+ import { type COMModel } from "./COMModel";
4
+ import { type COMPrimitive } from "./COMPrimitive";
5
+ import { type COMGroup } from "./COMGroup";
6
+
7
+ export type COMEntity = COMPov | COMLight | COMModel | COMPrimitive | COMGroup;
@@ -0,0 +1 @@
1
+ export type COMEntityType = 'pov' | 'light' | 'model' | 'primitive' | 'group';
@@ -0,0 +1,6 @@
1
+ export type COMGeometry = {
2
+ name: string
3
+ width: number;
4
+ height: number;
5
+ depth: number;
6
+ }
@@ -0,0 +1,9 @@
1
+ import { type Vector3Like } from "three";
2
+ import { type COMBaseEntity } from "./COMBaseEntity";
3
+
4
+ export type COMGroup = COMBaseEntity & {
5
+ position: Vector3Like;
6
+ rotation: Vector3Like;
7
+ scale: Vector3Like;
8
+ bbVisible?: boolean;
9
+ }
@@ -0,0 +1,10 @@
1
+ import { type Vector3Like } from "three";
2
+ import { type COMBaseEntity } from "./COMBaseEntity";
3
+
4
+ export type COMLight = COMBaseEntity & {
5
+ type: 'ambient' | 'point' | 'scene';
6
+ intensity: number;
7
+ color: string | number;
8
+ enabled: boolean;
9
+ position?: Vector3Like;
10
+ };
@@ -0,0 +1,12 @@
1
+ import { type Texture } from "three";
2
+
3
+ export type COMMaterial = {
4
+ vertexColors: boolean;
5
+ color: string | number;
6
+ map: Texture | null;
7
+ normalMap: Texture | null;
8
+ roughness: number;
9
+ roughnessMap: Texture | null;
10
+ metalness: number;
11
+ metalnessMap: Texture | null;
12
+ }
@@ -0,0 +1,12 @@
1
+ import { type Vector3Like } from "three";
2
+ import { type COMMaterial } from "./COMMaterial";
3
+ import { type COMBaseEntity } from "./COMBaseEntity";
4
+
5
+ export type COMModel = COMBaseEntity & {
6
+ uri: string;
7
+ position: Vector3Like;
8
+ rotation: Vector3Like;
9
+ scale: Vector3Like;
10
+ loaded: boolean;
11
+ material?: Partial<COMMaterial>;
12
+ };
@@ -0,0 +1,8 @@
1
+ import { type Vector3Like } from "three";
2
+ import { type COMBaseEntity } from "./COMBaseEntity";
3
+
4
+ export type COMPov = COMBaseEntity & {
5
+ position: Vector3Like;
6
+ target: Vector3Like;
7
+ locked?: boolean;
8
+ };