@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.
- package/package.json +6 -3
- package/src/__test__/DIVE.test.ts +244 -0
- package/src/animation/AnimationSystem.ts +14 -0
- package/src/animation/__test__/AnimationSystem.test.ts +19 -0
- package/src/axiscamera/AxisCamera.ts +50 -0
- package/src/axiscamera/__test__/AxisCamera.test.ts +41 -0
- package/src/camera/PerspectiveCamera.ts +43 -0
- package/src/camera/__test__/PerspectiveCamera.test.ts +27 -0
- package/src/com/Communication.ts +382 -0
- package/src/com/__test__/Communication.test.ts +612 -0
- package/src/com/actions/camera/getcameratransform.ts +9 -0
- package/src/com/actions/camera/movecamera.ts +15 -0
- package/src/com/actions/camera/resetcamera.ts +4 -0
- package/src/com/actions/camera/setcameralayer.ts +4 -0
- package/src/com/actions/camera/setcameratransform.ts +9 -0
- package/src/com/actions/camera/zoomcamera.ts +4 -0
- package/src/com/actions/index.ts +41 -0
- package/src/com/actions/media/generatemedia.ts +15 -0
- package/src/com/actions/object/addobject.ts +6 -0
- package/src/com/actions/object/deleteobject.ts +6 -0
- package/src/com/actions/object/getallobjects.ts +6 -0
- package/src/com/actions/object/getobjects.ts +6 -0
- package/src/com/actions/object/model/modelloaded.ts +4 -0
- package/src/com/actions/object/model/placeonfloor.ts +4 -0
- package/src/com/actions/object/selectobject.ts +6 -0
- package/src/com/actions/object/updateobject.ts +6 -0
- package/src/com/actions/scene/getallscenedata.ts +23 -0
- package/src/com/actions/scene/setbackground.ts +4 -0
- package/src/com/actions/scene/updatescene.ts +9 -0
- package/src/com/actions/toolbox/select/setgizmomode.ts +4 -0
- package/src/com/index.ts +4 -0
- package/src/com/types.ts +30 -0
- package/src/constant/AxisHelperColors.ts +7 -0
- package/src/constant/GridColors.ts +2 -0
- package/src/constant/VisibilityLayerMask.ts +5 -0
- package/src/controls/OrbitControls.ts +145 -0
- package/src/controls/__test__/OrbitControls.test.ts +181 -0
- package/src/grid/Grid.ts +22 -0
- package/src/grid/__test__/Grid.test.ts +19 -0
- package/src/helper/applyMixins/__test__/applyMixins.test.ts +27 -0
- package/src/helper/applyMixins/applyMixins.ts +15 -0
- package/src/helper/getObjectDelta/__test__/getObjectDelta.spec.ts +152 -0
- package/src/helper/getObjectDelta/getObjectDelta.ts +101 -0
- package/src/interface/Moveable.ts +13 -0
- package/src/interface/Rotatable.ts +10 -0
- package/src/interface/Scalable.ts +10 -0
- package/src/interface/Selectable.ts +11 -0
- package/src/interface/__test__/Interfaces.test.ts +13 -0
- package/src/light/AmbientLight.ts +29 -0
- package/src/light/PointLight.ts +63 -0
- package/src/light/SceneLight.ts +60 -0
- package/src/light/__test__/AmbientLight.test.ts +44 -0
- package/src/light/__test__/PointLight.test.ts +98 -0
- package/src/light/__test__/SceneLight.test.ts +122 -0
- package/src/loadingmanager/LoadingManager.ts +44 -0
- package/src/loadingmanager/__test__/LoadingManager.test.ts +52 -0
- package/src/math/__test__/DIVEMath.test.ts +12 -0
- package/src/math/ceil/__test__/ceilExp.test.ts +12 -0
- package/src/math/ceil/ceilExp.ts +6 -0
- package/src/math/floor/__test__/floorExp.test.ts +14 -0
- package/src/math/floor/floorExp.ts +6 -0
- package/src/math/helper/__test__/shift.test.ts +12 -0
- package/src/math/helper/shift.ts +4 -0
- package/src/math/index.ts +19 -0
- package/src/math/round/__test__/roundExp.test.ts +14 -0
- package/src/math/round/roundExp.ts +7 -0
- package/src/math/toFixed/__test__/toFixedExp.test.ts +14 -0
- package/src/math/toFixed/toFixedExp.ts +6 -0
- package/src/math/truncate/__test__/truncateExp.test.ts +14 -0
- package/src/math/truncate/truncateExp.ts +6 -0
- package/src/mediacreator/MediaCreator.ts +65 -0
- package/src/mediacreator/__test__/MediaCreator.test.ts +113 -0
- package/src/model/Model.ts +72 -0
- package/src/model/__test__/Model.test.ts +163 -0
- package/src/primitive/floor/Floor.ts +34 -0
- package/src/primitive/floor/__test__/Floor.test.ts +21 -0
- package/src/renderer/Renderer.ts +165 -0
- package/src/renderer/__test__/Renderer.test.ts +169 -0
- package/src/scene/Scene.ts +49 -0
- package/src/scene/__test__/Scene.test.ts +70 -0
- package/src/scene/root/Root.ts +107 -0
- package/src/scene/root/__test__/Root.test.ts +129 -0
- package/src/scene/root/lightroot/LightRoot.ts +84 -0
- package/src/scene/root/lightroot/__test__/LightRoot.test.ts +137 -0
- package/src/scene/root/modelroot/ModelRoot.ts +82 -0
- package/src/scene/root/modelroot/__test__/ModelRoot.test.ts +185 -0
- package/src/toolbox/BaseTool.ts +18 -0
- package/src/toolbox/Toolbox.ts +76 -0
- package/src/toolbox/__test__/Toolbox.test.ts +109 -0
- package/src/toolbox/select/SelectTool.ts +123 -0
- package/src/toolbox/select/__test__/SelectTool.test.ts +190 -0
- package/build/dive.cjs +0 -1551
- package/build/dive.cjs.map +0 -1
- package/build/dive.d.cts +0 -558
- package/build/dive.d.ts +0 -558
- package/build/dive.js +0 -1516
- 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,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,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,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,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,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
|
+
}
|