@configura/babylon-view 2.0.0-alpha.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +5 -18
- package/LICENSE +201 -201
- package/README.md +1 -1
- package/dist/animation/AnimatableObject.d.ts +8 -8
- package/dist/animation/AnimatableObject.js +3 -3
- package/dist/animation/animator/Animator.d.ts +33 -33
- package/dist/animation/animator/Animator.js +58 -58
- package/dist/animation/animator/AnimatorEasing.d.ts +16 -16
- package/dist/animation/animator/AnimatorEasing.js +31 -31
- package/dist/animation/animator/AnimatorEasingMatrix.d.ts +14 -14
- package/dist/animation/animator/AnimatorEasingMatrix.js +16 -16
- package/dist/animation/animator/AnimatorHighlight.d.ts +16 -16
- package/dist/animation/animator/AnimatorHighlight.js +32 -32
- package/dist/animation/animator/AnimatorPointToPoint.d.ts +8 -8
- package/dist/animation/animator/AnimatorPointToPoint.js +14 -14
- package/dist/animation/animator/AnimatorQueue.d.ts +13 -13
- package/dist/animation/animator/AnimatorQueue.js +57 -57
- package/dist/animation/animator/AnimatorScale.d.ts +8 -8
- package/dist/animation/animator/AnimatorScale.js +13 -13
- package/dist/animation/animator/AnimatorSpin.d.ts +10 -10
- package/dist/animation/animator/AnimatorSpin.js +13 -13
- package/dist/animation/animator/EasingFunctions.d.ts +35 -35
- package/dist/animation/animator/EasingFunctions.js +137 -137
- package/dist/animation/coordinator/Coordinator.d.ts +28 -28
- package/dist/animation/coordinator/Coordinator.js +53 -53
- package/dist/animation/coordinator/CoordinatorDropAndSpin.d.ts +22 -22
- package/dist/animation/coordinator/CoordinatorDropAndSpin.js +138 -138
- package/dist/animation/coordinator/CoordinatorIdentity.d.ts +11 -11
- package/dist/animation/coordinator/CoordinatorIdentity.js +14 -14
- package/dist/animation/coordinator/CoordinatorNodeQueues.d.ts +18 -18
- package/dist/animation/coordinator/CoordinatorNodeQueues.js +50 -50
- package/dist/animation/coordinator/CoordinatorPulse.d.ts +21 -21
- package/dist/animation/coordinator/CoordinatorPulse.js +47 -47
- package/dist/animation/coordinator/CoordinatorPulseBounce.d.ts +14 -14
- package/dist/animation/coordinator/CoordinatorPulseBounce.js +35 -35
- package/dist/animation/coordinator/CoordinatorPulseHighlight.d.ts +13 -13
- package/dist/animation/coordinator/CoordinatorPulseHighlight.js +29 -29
- package/dist/animation/coordinator/CoordinatorPulseInflate.d.ts +14 -14
- package/dist/animation/coordinator/CoordinatorPulseInflate.js +23 -23
- package/dist/camera/CameraCreator.d.ts +5 -5
- package/dist/camera/CameraCreator.js +4 -4
- package/dist/camera/CfgArcRotateCameraPointersInput.d.ts +26 -26
- package/dist/camera/CfgArcRotateCameraPointersInput.js +266 -266
- package/dist/camera/CfgOrbitalCamera.d.ts +76 -73
- package/dist/camera/CfgOrbitalCamera.js +281 -260
- package/dist/camera/CfgOrbitalCameraControlProps.d.ts +14 -11
- package/dist/camera/CfgOrbitalCameraControlProps.js +7 -6
- package/dist/camera/GradingApplier.d.ts +3 -3
- package/dist/camera/GradingApplier.js +48 -48
- package/dist/engine/EngineCreator.d.ts +3 -3
- package/dist/engine/EngineCreator.js +10 -10
- package/dist/geometry/CfgGeometry.d.ts +29 -29
- package/dist/geometry/CfgGeometry.js +146 -146
- package/dist/geometry/CfgMesh.d.ts +10 -10
- package/dist/geometry/CfgMesh.js +38 -38
- package/dist/geometry/geoSplitter.d.ts +8 -8
- package/dist/geometry/geoSplitter.js +192 -192
- package/dist/geometry/stretch/CfgMorphTarget.d.ts +15 -15
- package/dist/geometry/stretch/CfgMorphTarget.js +65 -65
- package/dist/geometry/stretch/CfgStretchData.d.ts +116 -116
- package/dist/geometry/stretch/CfgStretchData.js +350 -350
- package/dist/geometry/stretch/CfgStretchMorphGeometry.d.ts +16 -16
- package/dist/geometry/stretch/CfgStretchMorphGeometry.js +95 -95
- package/dist/index.d.ts +16 -16
- package/dist/index.js +16 -16
- package/dist/io/CfgHistoryToCameraConfConnector.d.ts +31 -29
- package/dist/io/CfgHistoryToCameraConfConnector.js +90 -80
- package/dist/io/CfgIOCameraConfConnector.d.ts +35 -35
- package/dist/io/CfgIOCameraConfConnector.js +81 -80
- package/dist/io/CfgObservableStateToCameraConfConnector.d.ts +10 -10
- package/dist/io/CfgObservableStateToCameraConfConnector.js +11 -11
- package/dist/io/CfgWindowMessageToCameraConfConnector.d.ts +10 -10
- package/dist/io/CfgWindowMessageToCameraConfConnector.js +11 -11
- package/dist/light/CfgDirectionalLight.d.ts +8 -8
- package/dist/light/CfgDirectionalLight.js +18 -18
- package/dist/light/CfgHemisphericLight.d.ts +7 -7
- package/dist/light/CfgHemisphericLight.js +17 -17
- package/dist/light/CfgPointLight.d.ts +8 -8
- package/dist/light/CfgPointLight.js +18 -18
- package/dist/light/DefaultLightRig.d.ts +19 -19
- package/dist/light/DefaultLightRig.js +77 -77
- package/dist/light/LightRigCreator.d.ts +9 -9
- package/dist/light/LightRigCreator.js +3 -3
- package/dist/material/CfgMaterial.d.ts +68 -68
- package/dist/material/CfgMaterial.js +482 -482
- package/dist/material/DummyMaterialCreator.d.ts +4 -4
- package/dist/material/DummyMaterialCreator.js +15 -15
- package/dist/material/material.d.ts +18 -18
- package/dist/material/material.js +128 -128
- package/dist/material/texture.d.ts +14 -14
- package/dist/material/texture.js +306 -306
- package/dist/nodes/CfgContentRootNode.d.ts +19 -19
- package/dist/nodes/CfgContentRootNode.js +75 -75
- package/dist/nodes/CfgDeferredMeshNode.d.ts +55 -55
- package/dist/nodes/CfgDeferredMeshNode.js +378 -378
- package/dist/nodes/CfgProductNode.d.ts +127 -127
- package/dist/nodes/CfgProductNode.js +598 -598
- package/dist/nodes/CfgSymNode.d.ts +50 -50
- package/dist/nodes/CfgSymNode.js +249 -249
- package/dist/nodes/CfgSymRootNode.d.ts +45 -45
- package/dist/nodes/CfgSymRootNode.js +229 -229
- package/dist/nodes/CfgTransformNode.d.ts +33 -33
- package/dist/nodes/CfgTransformNode.js +83 -83
- package/dist/scene/SceneCreator.d.ts +6 -6
- package/dist/scene/SceneCreator.js +22 -22
- package/dist/utilities/CfgBoundingBox.d.ts +21 -21
- package/dist/utilities/CfgBoundingBox.js +81 -81
- package/dist/utilities/anchor/anchor.d.ts +50 -50
- package/dist/utilities/anchor/anchor.js +133 -133
- package/dist/utilities/anchor/anchorMap.d.ts +20 -20
- package/dist/utilities/anchor/anchorMap.js +111 -111
- package/dist/utilities/utilities3D.d.ts +70 -70
- package/dist/utilities/utilities3D.js +265 -265
- package/dist/utilities/utilitiesColor.d.ts +18 -18
- package/dist/utilities/utilitiesColor.js +50 -50
- package/dist/utilities/utilitiesImage.d.ts +6 -6
- package/dist/utilities/utilitiesImage.js +107 -107
- package/dist/utilities/utilitiesSymRootIdentifier.d.ts +7 -7
- package/dist/utilities/utilitiesSymRootIdentifier.js +26 -26
- package/dist/view/BaseView.d.ts +78 -78
- package/dist/view/BaseView.js +303 -303
- package/dist/view/BaseViewConfiguration.d.ts +32 -32
- package/dist/view/BaseViewConfiguration.js +10 -10
- package/dist/view/RenderEnv.d.ts +43 -43
- package/dist/view/RenderEnv.js +7 -7
- package/dist/view/SingleProductDefaultCameraView.d.ts +38 -37
- package/dist/view/SingleProductDefaultCameraView.js +149 -145
- package/dist/view/SingleProductDefaultCameraViewConfiguration.d.ts +44 -42
- package/dist/view/SingleProductDefaultCameraViewConfiguration.js +11 -11
- package/dist/view/SingleProductView.d.ts +44 -44
- package/dist/view/SingleProductView.js +212 -212
- package/dist/view/SingleProductViewConfiguration.d.ts +32 -32
- package/dist/view/SingleProductViewConfiguration.js +19 -19
- package/package.json +5 -5
package/dist/view/BaseView.js
CHANGED
|
@@ -1,303 +1,303 @@
|
|
|
1
|
-
import "@babylonjs/core/Debug/debugLayer.js";
|
|
2
|
-
import { Matrix } from "@babylonjs/core/Maths/math.vector.js";
|
|
3
|
-
import { AssetsManager } from "@babylonjs/core/Misc/assetsManager.js";
|
|
4
|
-
import { SymGetMeshEnv } from "@configura/web-core/dist/cm/format/cmsym/components/SymGetMeshEnv.js";
|
|
5
|
-
import { DexManager } from "@configura/web-core/dist/cm/format/dex/DexManager.js";
|
|
6
|
-
import { AggregatedLoadingObservable, isAbortError, Observable, PromiseCache, toError, } from "@configura/web-utilities";
|
|
7
|
-
import { getDefaultGradingApplier } from "../camera/GradingApplier.js";
|
|
8
|
-
import { getDefaultEngine } from "../engine/EngineCreator.js";
|
|
9
|
-
import { getDefaultLightRigCreator } from "../light/DefaultLightRig.js";
|
|
10
|
-
import { defaultDummyMaterialCreator, } from "../material/DummyMaterialCreator.js";
|
|
11
|
-
import { CfgContentRootNode } from "../nodes/CfgContentRootNode.js";
|
|
12
|
-
import { getDefaultScene } from "../scene/SceneCreator.js";
|
|
13
|
-
import { CfgBoundingBox } from "../utilities/CfgBoundingBox.js";
|
|
14
|
-
import { cameraConfigurationPropsEquals, DetailLevel, } from "./BaseViewConfiguration.js";
|
|
15
|
-
// CET coordinate system is Z-up, Babylon is Y-up, both are right handed
|
|
16
|
-
// CET coordinates are used in the CfgProductNode and all its children.
|
|
17
|
-
export const CET_TO_BABYLON_MATRIX = Matrix.RotationX(-Math.PI / 2);
|
|
18
|
-
export const BABYLON_TO_CET_MATRIX = Matrix.RotationX(Math.PI / 2);
|
|
19
|
-
const ENABLE_CONTINUOUS_RENDER = false;
|
|
20
|
-
const CULL_EMPTY_NODES = true;
|
|
21
|
-
/**
|
|
22
|
-
* Load the highest quality meshes by default.
|
|
23
|
-
*
|
|
24
|
-
* @remarks We only use "base" as a last fallback. The reason is that even though this LOD level
|
|
25
|
-
* could theoretically include a better version than "super" it is not normally included in CmSym
|
|
26
|
-
* files and never used by CET, which makes it unpredictable. See WRD-387 for a case where it
|
|
27
|
-
* caused problems when it was the first choice.
|
|
28
|
-
*/
|
|
29
|
-
export const DEFAULT_DETAIL_LEVELS = [
|
|
30
|
-
DetailLevel.super,
|
|
31
|
-
DetailLevel.high,
|
|
32
|
-
DetailLevel.medium,
|
|
33
|
-
DetailLevel.low,
|
|
34
|
-
DetailLevel.base,
|
|
35
|
-
];
|
|
36
|
-
/**
|
|
37
|
-
* @remarks As this cache contains items read from a another resource undefined is an acceptable
|
|
38
|
-
* cache value representing a value that will not be anything but undefined no mather how many
|
|
39
|
-
* times you try.
|
|
40
|
-
*/
|
|
41
|
-
const geometryCache = new PromiseCache((i1, i2) => i1.component === i2.component &&
|
|
42
|
-
i1.stretchDatasHash === i2.stretchDatasHash &&
|
|
43
|
-
i1.uvMapperHash === i2.uvMapperHash);
|
|
44
|
-
const symNodeCache = new PromiseCache();
|
|
45
|
-
const materialCache = new PromiseCache();
|
|
46
|
-
const textureImageCache = new PromiseCache();
|
|
47
|
-
const derivedNormalMapCache = new PromiseCache();
|
|
48
|
-
// Singletons
|
|
49
|
-
const SYM_MESH_ENV = new SymGetMeshEnv();
|
|
50
|
-
const DEX_MANAGER = new DexManager("BabylonCanvas");
|
|
51
|
-
function getAssetManager(scene) {
|
|
52
|
-
const assetsManager = new AssetsManager(scene);
|
|
53
|
-
assetsManager.useDefaultLoadingScreen = false;
|
|
54
|
-
return assetsManager;
|
|
55
|
-
}
|
|
56
|
-
export class BaseView {
|
|
57
|
-
constructor(options) {
|
|
58
|
-
this._destroyed = false;
|
|
59
|
-
this._inspectorActive = false;
|
|
60
|
-
this._needsRenderFrame = false;
|
|
61
|
-
this._dumpNextFrameToImage = [];
|
|
62
|
-
this._enginePauseSemaphore = 0;
|
|
63
|
-
this._errorObservable = new Observable();
|
|
64
|
-
this._loadingObservable = new AggregatedLoadingObservable();
|
|
65
|
-
this._renderEnvironmentObservable = new Observable();
|
|
66
|
-
// To be able to add/remove event listeners without binding them
|
|
67
|
-
this._boundNotifyCameraListeners = () => {
|
|
68
|
-
this.notifyCameraListeners();
|
|
69
|
-
this.scheduleRerender();
|
|
70
|
-
};
|
|
71
|
-
this.notifyError = (e) => {
|
|
72
|
-
if (isAbortError(e)) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
this._errorObservable.notifyAll(toError(e));
|
|
76
|
-
};
|
|
77
|
-
const { canvas, cameraCreator, engineCreator, lightRigCreator, sceneCreator, gradingApplier, dummyMaterialCreator, } = options;
|
|
78
|
-
this._canvas = canvas;
|
|
79
|
-
// This workaround prevents canvas long taps to select text near the canvas on iOS
|
|
80
|
-
for (const eventName of [
|
|
81
|
-
"click",
|
|
82
|
-
"dblclick",
|
|
83
|
-
"mousedown",
|
|
84
|
-
"mouseup",
|
|
85
|
-
"mousemove",
|
|
86
|
-
"touchstart",
|
|
87
|
-
"touchend",
|
|
88
|
-
"touchmove",
|
|
89
|
-
]) {
|
|
90
|
-
canvas.addEventListener(eventName, (event) => {
|
|
91
|
-
event.preventDefault();
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
const { width, height } = canvas.getBoundingClientRect();
|
|
95
|
-
this._viewportSize = [width, height];
|
|
96
|
-
const engine = (engineCreator || getDefaultEngine)(canvas, width, height);
|
|
97
|
-
const scene = (sceneCreator || getDefaultScene)(engine);
|
|
98
|
-
scene.useRightHandedSystem = true;
|
|
99
|
-
const camera = cameraCreator(scene, canvas);
|
|
100
|
-
(gradingApplier || getDefaultGradingApplier())(camera);
|
|
101
|
-
this._scene = scene;
|
|
102
|
-
this._engine = engine;
|
|
103
|
-
this._camera = camera;
|
|
104
|
-
const lightRig = (lightRigCreator || getDefaultLightRigCreator(true))(scene, camera);
|
|
105
|
-
this._lightRig = lightRig;
|
|
106
|
-
this._dummyMaterialCreator = dummyMaterialCreator || defaultDummyMaterialCreator;
|
|
107
|
-
this._renderEnvironment = {
|
|
108
|
-
scene,
|
|
109
|
-
assetsManager: getAssetManager(scene),
|
|
110
|
-
geometryCache,
|
|
111
|
-
symNodeCache,
|
|
112
|
-
materialCache,
|
|
113
|
-
textureImageCache,
|
|
114
|
-
derivedNormalMapCache,
|
|
115
|
-
lightRig,
|
|
116
|
-
dummyMaterial: this._dummyMaterialCreator(scene, lightRig.lightCount),
|
|
117
|
-
scheduleRerender: this.scheduleRerender.bind(this),
|
|
118
|
-
notifyError: this.notifyError.bind(this),
|
|
119
|
-
symMeshEnv: SYM_MESH_ENV,
|
|
120
|
-
dexManager: DEX_MANAGER,
|
|
121
|
-
cullEmptyNodes: CULL_EMPTY_NODES,
|
|
122
|
-
allowedDetailLevels: DEFAULT_DETAIL_LEVELS,
|
|
123
|
-
};
|
|
124
|
-
this._contentRoot = new CfgContentRootNode(this._renderEnvironment);
|
|
125
|
-
this.setConfiguration({}); // Init the RenderEnv
|
|
126
|
-
requestAnimationFrame(this.browserTick.bind(this));
|
|
127
|
-
// NOTE: As of now we mix view and projection-related properties when we notify, so let's subscribe to both
|
|
128
|
-
this._camera.onViewMatrixChangedObservable.add(this._boundNotifyCameraListeners);
|
|
129
|
-
this._camera.onProjectionMatrixChangedObservable.add(this._boundNotifyCameraListeners);
|
|
130
|
-
}
|
|
131
|
-
destroy() {
|
|
132
|
-
this._destroyed = true;
|
|
133
|
-
this._camera.onViewMatrixChangedObservable.removeCallback(this._boundNotifyCameraListeners);
|
|
134
|
-
this._camera.onProjectionMatrixChangedObservable.removeCallback(this._boundNotifyCameraListeners);
|
|
135
|
-
this._hideInspector();
|
|
136
|
-
this._camera.dispose();
|
|
137
|
-
geometryCache.clear();
|
|
138
|
-
materialCache.clear();
|
|
139
|
-
}
|
|
140
|
-
pauseRendering() {
|
|
141
|
-
this._enginePauseSemaphore += 1;
|
|
142
|
-
}
|
|
143
|
-
resumeRendering() {
|
|
144
|
-
this._enginePauseSemaphore = Math.max(0, this._enginePauseSemaphore - 1);
|
|
145
|
-
}
|
|
146
|
-
_hideInspector() {
|
|
147
|
-
// The debugLayer getter initializes the backing field _debugLayer, but if we do that before
|
|
148
|
-
// "@babylonjs/inspector" is loaded it will not work properly.
|
|
149
|
-
if (this._scene._debugLayer === undefined) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
this._scene.debugLayer.hide();
|
|
153
|
-
}
|
|
154
|
-
showInspector(target) {
|
|
155
|
-
if (target === undefined) {
|
|
156
|
-
this._hideInspector();
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
|
-
if (!this._scene.debugLayer.BJSINSPECTOR) {
|
|
161
|
-
console.warn("@babylonjs/inspector has to be loaded before the Inspector can be shown.");
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
void this._scene.debugLayer.show({
|
|
165
|
-
globalRoot: target,
|
|
166
|
-
enableClose: false,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
this._inspectorActive = target !== undefined;
|
|
170
|
-
}
|
|
171
|
-
setConfiguration(configuration) {
|
|
172
|
-
if (configuration.allowedDetailLevels !== undefined) {
|
|
173
|
-
this._renderEnvironment.allowedDetailLevels = configuration.allowedDetailLevels;
|
|
174
|
-
}
|
|
175
|
-
this._renderEnvironmentObservable.notifyAll(this._renderEnvironment);
|
|
176
|
-
}
|
|
177
|
-
get cameraConfiguration() {
|
|
178
|
-
return {
|
|
179
|
-
nearClipping: this._camera.minZ,
|
|
180
|
-
farClipping: this._camera.maxZ,
|
|
181
|
-
position: this._camera.position.clone(),
|
|
182
|
-
contentPosition: this.contentCenter,
|
|
183
|
-
fov: this._camera.fov,
|
|
184
|
-
aspect: this._engine.getScreenAspectRatio(),
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
get contentCenter() {
|
|
188
|
-
const { min, max } = this._contentRoot.getHierarchyBoundingVectors();
|
|
189
|
-
return new CfgBoundingBox(min, max).center;
|
|
190
|
-
}
|
|
191
|
-
notifyCameraListeners() {
|
|
192
|
-
if (this._cameraConfigurationObservable === undefined) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
const cameraConf = this.cameraConfiguration;
|
|
196
|
-
if (this._previousCameraConf !== undefined &&
|
|
197
|
-
cameraConfigurationPropsEquals(this._previousCameraConf, cameraConf)) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
this._cameraConfigurationObservable.notifyAll(cameraConf, this._cameraConfigurationObservable);
|
|
201
|
-
this._previousCameraConf = cameraConf;
|
|
202
|
-
}
|
|
203
|
-
addEventListener(event, listener) {
|
|
204
|
-
switch (event) {
|
|
205
|
-
case "cameraConfiguration":
|
|
206
|
-
if (this._cameraConfigurationObservable === undefined) {
|
|
207
|
-
this._cameraConfigurationObservable =
|
|
208
|
-
new Observable();
|
|
209
|
-
}
|
|
210
|
-
this._cameraConfigurationObservable.listen(listener);
|
|
211
|
-
break;
|
|
212
|
-
case "renderEnv": {
|
|
213
|
-
const l = listener;
|
|
214
|
-
this._renderEnvironmentObservable.listen(l);
|
|
215
|
-
l(this._renderEnvironment);
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
case "error":
|
|
219
|
-
this._errorObservable.listen(listener);
|
|
220
|
-
break;
|
|
221
|
-
case "loading":
|
|
222
|
-
this._loadingObservable.listen(listener);
|
|
223
|
-
break;
|
|
224
|
-
default:
|
|
225
|
-
throw Error(`Unknown event-type ${event.toString()}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
removeEventListener(event, listener) {
|
|
229
|
-
switch (event) {
|
|
230
|
-
case "cameraConfiguration":
|
|
231
|
-
if (this._cameraConfigurationObservable === undefined) {
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
this._cameraConfigurationObservable.stopListen(listener);
|
|
235
|
-
break;
|
|
236
|
-
case "renderEnv":
|
|
237
|
-
this._renderEnvironmentObservable.stopListen(listener);
|
|
238
|
-
break;
|
|
239
|
-
case "error":
|
|
240
|
-
this._errorObservable.stopListen(listener);
|
|
241
|
-
break;
|
|
242
|
-
case "loading":
|
|
243
|
-
this._loadingObservable.stopListen(listener);
|
|
244
|
-
break;
|
|
245
|
-
default:
|
|
246
|
-
throw Error(`Unknown event-type ${event.toString()}`);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
scheduleRerender(dumpNextFrameToImage) {
|
|
250
|
-
this._needsRenderFrame = true;
|
|
251
|
-
if (dumpNextFrameToImage !== undefined) {
|
|
252
|
-
this._dumpNextFrameToImage.push(dumpNextFrameToImage);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
isContinuousRender() {
|
|
256
|
-
return ENABLE_CONTINUOUS_RENDER || this._inspectorActive;
|
|
257
|
-
}
|
|
258
|
-
getNeededFrameRender(time) {
|
|
259
|
-
return this._needsRenderFrame || this.isContinuousRender();
|
|
260
|
-
}
|
|
261
|
-
browserTick(time) {
|
|
262
|
-
if (this._destroyed) {
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
this._camera.update();
|
|
266
|
-
if (this._enginePauseSemaphore === 0 && this.getNeededFrameRender(time)) {
|
|
267
|
-
this.renderFrame(time);
|
|
268
|
-
}
|
|
269
|
-
requestAnimationFrame(this.browserTick.bind(this));
|
|
270
|
-
}
|
|
271
|
-
renderFrame(time) {
|
|
272
|
-
if (this._viewportSize === undefined) {
|
|
273
|
-
console.warn("Size not inited");
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
this._needsRenderFrame = false;
|
|
277
|
-
this.refreshCameraNearFar();
|
|
278
|
-
this._engine.beginFrame();
|
|
279
|
-
this._scene.render();
|
|
280
|
-
this._engine.endFrame();
|
|
281
|
-
if (0 < this._dumpNextFrameToImage.length) {
|
|
282
|
-
const dataUrl = this._canvas.toDataURL("image/png");
|
|
283
|
-
this._dumpNextFrameToImage.forEach((c) => c(dataUrl));
|
|
284
|
-
this._dumpNextFrameToImage.length = 0;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
resizeViewport(width, height) {
|
|
288
|
-
this._viewportSize = [width, height];
|
|
289
|
-
this._canvas.style.width = `${Math.floor(width)}px`;
|
|
290
|
-
this._canvas.style.height = `${Math.floor(height)}px`;
|
|
291
|
-
this._engine.resize();
|
|
292
|
-
this.handleSizing(false);
|
|
293
|
-
this.scheduleRerender();
|
|
294
|
-
}
|
|
295
|
-
// Exists to be overridden
|
|
296
|
-
handleSizing(_force) {
|
|
297
|
-
// Do nothing
|
|
298
|
-
}
|
|
299
|
-
// Exists to be overridden
|
|
300
|
-
refreshCameraNearFar() {
|
|
301
|
-
// Do nothing
|
|
302
|
-
}
|
|
303
|
-
}
|
|
1
|
+
import "@babylonjs/core/Debug/debugLayer.js";
|
|
2
|
+
import { Matrix } from "@babylonjs/core/Maths/math.vector.js";
|
|
3
|
+
import { AssetsManager } from "@babylonjs/core/Misc/assetsManager.js";
|
|
4
|
+
import { SymGetMeshEnv } from "@configura/web-core/dist/cm/format/cmsym/components/SymGetMeshEnv.js";
|
|
5
|
+
import { DexManager } from "@configura/web-core/dist/cm/format/dex/DexManager.js";
|
|
6
|
+
import { AggregatedLoadingObservable, isAbortError, Observable, PromiseCache, toError, } from "@configura/web-utilities";
|
|
7
|
+
import { getDefaultGradingApplier } from "../camera/GradingApplier.js";
|
|
8
|
+
import { getDefaultEngine } from "../engine/EngineCreator.js";
|
|
9
|
+
import { getDefaultLightRigCreator } from "../light/DefaultLightRig.js";
|
|
10
|
+
import { defaultDummyMaterialCreator, } from "../material/DummyMaterialCreator.js";
|
|
11
|
+
import { CfgContentRootNode } from "../nodes/CfgContentRootNode.js";
|
|
12
|
+
import { getDefaultScene } from "../scene/SceneCreator.js";
|
|
13
|
+
import { CfgBoundingBox } from "../utilities/CfgBoundingBox.js";
|
|
14
|
+
import { cameraConfigurationPropsEquals, DetailLevel, } from "./BaseViewConfiguration.js";
|
|
15
|
+
// CET coordinate system is Z-up, Babylon is Y-up, both are right handed
|
|
16
|
+
// CET coordinates are used in the CfgProductNode and all its children.
|
|
17
|
+
export const CET_TO_BABYLON_MATRIX = Matrix.RotationX(-Math.PI / 2);
|
|
18
|
+
export const BABYLON_TO_CET_MATRIX = Matrix.RotationX(Math.PI / 2);
|
|
19
|
+
const ENABLE_CONTINUOUS_RENDER = false;
|
|
20
|
+
const CULL_EMPTY_NODES = true;
|
|
21
|
+
/**
|
|
22
|
+
* Load the highest quality meshes by default.
|
|
23
|
+
*
|
|
24
|
+
* @remarks We only use "base" as a last fallback. The reason is that even though this LOD level
|
|
25
|
+
* could theoretically include a better version than "super" it is not normally included in CmSym
|
|
26
|
+
* files and never used by CET, which makes it unpredictable. See WRD-387 for a case where it
|
|
27
|
+
* caused problems when it was the first choice.
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_DETAIL_LEVELS = [
|
|
30
|
+
DetailLevel.super,
|
|
31
|
+
DetailLevel.high,
|
|
32
|
+
DetailLevel.medium,
|
|
33
|
+
DetailLevel.low,
|
|
34
|
+
DetailLevel.base,
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* @remarks As this cache contains items read from a another resource undefined is an acceptable
|
|
38
|
+
* cache value representing a value that will not be anything but undefined no mather how many
|
|
39
|
+
* times you try.
|
|
40
|
+
*/
|
|
41
|
+
const geometryCache = new PromiseCache((i1, i2) => i1.component === i2.component &&
|
|
42
|
+
i1.stretchDatasHash === i2.stretchDatasHash &&
|
|
43
|
+
i1.uvMapperHash === i2.uvMapperHash);
|
|
44
|
+
const symNodeCache = new PromiseCache();
|
|
45
|
+
const materialCache = new PromiseCache();
|
|
46
|
+
const textureImageCache = new PromiseCache();
|
|
47
|
+
const derivedNormalMapCache = new PromiseCache();
|
|
48
|
+
// Singletons
|
|
49
|
+
const SYM_MESH_ENV = new SymGetMeshEnv();
|
|
50
|
+
const DEX_MANAGER = new DexManager("BabylonCanvas");
|
|
51
|
+
function getAssetManager(scene) {
|
|
52
|
+
const assetsManager = new AssetsManager(scene);
|
|
53
|
+
assetsManager.useDefaultLoadingScreen = false;
|
|
54
|
+
return assetsManager;
|
|
55
|
+
}
|
|
56
|
+
export class BaseView {
|
|
57
|
+
constructor(options) {
|
|
58
|
+
this._destroyed = false;
|
|
59
|
+
this._inspectorActive = false;
|
|
60
|
+
this._needsRenderFrame = false;
|
|
61
|
+
this._dumpNextFrameToImage = [];
|
|
62
|
+
this._enginePauseSemaphore = 0;
|
|
63
|
+
this._errorObservable = new Observable();
|
|
64
|
+
this._loadingObservable = new AggregatedLoadingObservable();
|
|
65
|
+
this._renderEnvironmentObservable = new Observable();
|
|
66
|
+
// To be able to add/remove event listeners without binding them
|
|
67
|
+
this._boundNotifyCameraListeners = () => {
|
|
68
|
+
this.notifyCameraListeners();
|
|
69
|
+
this.scheduleRerender();
|
|
70
|
+
};
|
|
71
|
+
this.notifyError = (e) => {
|
|
72
|
+
if (isAbortError(e)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this._errorObservable.notifyAll(toError(e));
|
|
76
|
+
};
|
|
77
|
+
const { canvas, cameraCreator, engineCreator, lightRigCreator, sceneCreator, gradingApplier, dummyMaterialCreator, } = options;
|
|
78
|
+
this._canvas = canvas;
|
|
79
|
+
// This workaround prevents canvas long taps to select text near the canvas on iOS
|
|
80
|
+
for (const eventName of [
|
|
81
|
+
"click",
|
|
82
|
+
"dblclick",
|
|
83
|
+
"mousedown",
|
|
84
|
+
"mouseup",
|
|
85
|
+
"mousemove",
|
|
86
|
+
"touchstart",
|
|
87
|
+
"touchend",
|
|
88
|
+
"touchmove",
|
|
89
|
+
]) {
|
|
90
|
+
canvas.addEventListener(eventName, (event) => {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const { width, height } = canvas.getBoundingClientRect();
|
|
95
|
+
this._viewportSize = [width, height];
|
|
96
|
+
const engine = (engineCreator || getDefaultEngine)(canvas, width, height);
|
|
97
|
+
const scene = (sceneCreator || getDefaultScene)(engine);
|
|
98
|
+
scene.useRightHandedSystem = true;
|
|
99
|
+
const camera = cameraCreator(scene, canvas);
|
|
100
|
+
(gradingApplier || getDefaultGradingApplier())(camera);
|
|
101
|
+
this._scene = scene;
|
|
102
|
+
this._engine = engine;
|
|
103
|
+
this._camera = camera;
|
|
104
|
+
const lightRig = (lightRigCreator || getDefaultLightRigCreator(true))(scene, camera);
|
|
105
|
+
this._lightRig = lightRig;
|
|
106
|
+
this._dummyMaterialCreator = dummyMaterialCreator || defaultDummyMaterialCreator;
|
|
107
|
+
this._renderEnvironment = {
|
|
108
|
+
scene,
|
|
109
|
+
assetsManager: getAssetManager(scene),
|
|
110
|
+
geometryCache,
|
|
111
|
+
symNodeCache,
|
|
112
|
+
materialCache,
|
|
113
|
+
textureImageCache,
|
|
114
|
+
derivedNormalMapCache,
|
|
115
|
+
lightRig,
|
|
116
|
+
dummyMaterial: this._dummyMaterialCreator(scene, lightRig.lightCount),
|
|
117
|
+
scheduleRerender: this.scheduleRerender.bind(this),
|
|
118
|
+
notifyError: this.notifyError.bind(this),
|
|
119
|
+
symMeshEnv: SYM_MESH_ENV,
|
|
120
|
+
dexManager: DEX_MANAGER,
|
|
121
|
+
cullEmptyNodes: CULL_EMPTY_NODES,
|
|
122
|
+
allowedDetailLevels: DEFAULT_DETAIL_LEVELS,
|
|
123
|
+
};
|
|
124
|
+
this._contentRoot = new CfgContentRootNode(this._renderEnvironment);
|
|
125
|
+
this.setConfiguration({}); // Init the RenderEnv
|
|
126
|
+
requestAnimationFrame(this.browserTick.bind(this));
|
|
127
|
+
// NOTE: As of now we mix view and projection-related properties when we notify, so let's subscribe to both
|
|
128
|
+
this._camera.onViewMatrixChangedObservable.add(this._boundNotifyCameraListeners);
|
|
129
|
+
this._camera.onProjectionMatrixChangedObservable.add(this._boundNotifyCameraListeners);
|
|
130
|
+
}
|
|
131
|
+
destroy() {
|
|
132
|
+
this._destroyed = true;
|
|
133
|
+
this._camera.onViewMatrixChangedObservable.removeCallback(this._boundNotifyCameraListeners);
|
|
134
|
+
this._camera.onProjectionMatrixChangedObservable.removeCallback(this._boundNotifyCameraListeners);
|
|
135
|
+
this._hideInspector();
|
|
136
|
+
this._camera.dispose();
|
|
137
|
+
geometryCache.clear();
|
|
138
|
+
materialCache.clear();
|
|
139
|
+
}
|
|
140
|
+
pauseRendering() {
|
|
141
|
+
this._enginePauseSemaphore += 1;
|
|
142
|
+
}
|
|
143
|
+
resumeRendering() {
|
|
144
|
+
this._enginePauseSemaphore = Math.max(0, this._enginePauseSemaphore - 1);
|
|
145
|
+
}
|
|
146
|
+
_hideInspector() {
|
|
147
|
+
// The debugLayer getter initializes the backing field _debugLayer, but if we do that before
|
|
148
|
+
// "@babylonjs/inspector" is loaded it will not work properly.
|
|
149
|
+
if (this._scene._debugLayer === undefined) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this._scene.debugLayer.hide();
|
|
153
|
+
}
|
|
154
|
+
showInspector(target) {
|
|
155
|
+
if (target === undefined) {
|
|
156
|
+
this._hideInspector();
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
|
+
if (!this._scene.debugLayer.BJSINSPECTOR) {
|
|
161
|
+
console.warn("@babylonjs/inspector has to be loaded before the Inspector can be shown.");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
void this._scene.debugLayer.show({
|
|
165
|
+
globalRoot: target,
|
|
166
|
+
enableClose: false,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
this._inspectorActive = target !== undefined;
|
|
170
|
+
}
|
|
171
|
+
setConfiguration(configuration) {
|
|
172
|
+
if (configuration.allowedDetailLevels !== undefined) {
|
|
173
|
+
this._renderEnvironment.allowedDetailLevels = configuration.allowedDetailLevels;
|
|
174
|
+
}
|
|
175
|
+
this._renderEnvironmentObservable.notifyAll(this._renderEnvironment);
|
|
176
|
+
}
|
|
177
|
+
get cameraConfiguration() {
|
|
178
|
+
return {
|
|
179
|
+
nearClipping: this._camera.minZ,
|
|
180
|
+
farClipping: this._camera.maxZ,
|
|
181
|
+
position: this._camera.position.clone(),
|
|
182
|
+
contentPosition: this.contentCenter,
|
|
183
|
+
fov: this._camera.fov,
|
|
184
|
+
aspect: this._engine.getScreenAspectRatio(),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
get contentCenter() {
|
|
188
|
+
const { min, max } = this._contentRoot.getHierarchyBoundingVectors();
|
|
189
|
+
return new CfgBoundingBox(min, max).center;
|
|
190
|
+
}
|
|
191
|
+
notifyCameraListeners() {
|
|
192
|
+
if (this._cameraConfigurationObservable === undefined) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const cameraConf = this.cameraConfiguration;
|
|
196
|
+
if (this._previousCameraConf !== undefined &&
|
|
197
|
+
cameraConfigurationPropsEquals(this._previousCameraConf, cameraConf)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this._cameraConfigurationObservable.notifyAll(cameraConf, this._cameraConfigurationObservable);
|
|
201
|
+
this._previousCameraConf = cameraConf;
|
|
202
|
+
}
|
|
203
|
+
addEventListener(event, listener) {
|
|
204
|
+
switch (event) {
|
|
205
|
+
case "cameraConfiguration":
|
|
206
|
+
if (this._cameraConfigurationObservable === undefined) {
|
|
207
|
+
this._cameraConfigurationObservable =
|
|
208
|
+
new Observable();
|
|
209
|
+
}
|
|
210
|
+
this._cameraConfigurationObservable.listen(listener);
|
|
211
|
+
break;
|
|
212
|
+
case "renderEnv": {
|
|
213
|
+
const l = listener;
|
|
214
|
+
this._renderEnvironmentObservable.listen(l);
|
|
215
|
+
l(this._renderEnvironment);
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case "error":
|
|
219
|
+
this._errorObservable.listen(listener);
|
|
220
|
+
break;
|
|
221
|
+
case "loading":
|
|
222
|
+
this._loadingObservable.listen(listener);
|
|
223
|
+
break;
|
|
224
|
+
default:
|
|
225
|
+
throw Error(`Unknown event-type ${event.toString()}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
removeEventListener(event, listener) {
|
|
229
|
+
switch (event) {
|
|
230
|
+
case "cameraConfiguration":
|
|
231
|
+
if (this._cameraConfigurationObservable === undefined) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
this._cameraConfigurationObservable.stopListen(listener);
|
|
235
|
+
break;
|
|
236
|
+
case "renderEnv":
|
|
237
|
+
this._renderEnvironmentObservable.stopListen(listener);
|
|
238
|
+
break;
|
|
239
|
+
case "error":
|
|
240
|
+
this._errorObservable.stopListen(listener);
|
|
241
|
+
break;
|
|
242
|
+
case "loading":
|
|
243
|
+
this._loadingObservable.stopListen(listener);
|
|
244
|
+
break;
|
|
245
|
+
default:
|
|
246
|
+
throw Error(`Unknown event-type ${event.toString()}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
scheduleRerender(dumpNextFrameToImage) {
|
|
250
|
+
this._needsRenderFrame = true;
|
|
251
|
+
if (dumpNextFrameToImage !== undefined) {
|
|
252
|
+
this._dumpNextFrameToImage.push(dumpNextFrameToImage);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
isContinuousRender() {
|
|
256
|
+
return ENABLE_CONTINUOUS_RENDER || this._inspectorActive;
|
|
257
|
+
}
|
|
258
|
+
getNeededFrameRender(time) {
|
|
259
|
+
return this._needsRenderFrame || this.isContinuousRender();
|
|
260
|
+
}
|
|
261
|
+
browserTick(time) {
|
|
262
|
+
if (this._destroyed) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
this._camera.update();
|
|
266
|
+
if (this._enginePauseSemaphore === 0 && this.getNeededFrameRender(time)) {
|
|
267
|
+
this.renderFrame(time);
|
|
268
|
+
}
|
|
269
|
+
requestAnimationFrame(this.browserTick.bind(this));
|
|
270
|
+
}
|
|
271
|
+
renderFrame(time) {
|
|
272
|
+
if (this._viewportSize === undefined) {
|
|
273
|
+
console.warn("Size not inited");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
this._needsRenderFrame = false;
|
|
277
|
+
this.refreshCameraNearFar();
|
|
278
|
+
this._engine.beginFrame();
|
|
279
|
+
this._scene.render();
|
|
280
|
+
this._engine.endFrame();
|
|
281
|
+
if (0 < this._dumpNextFrameToImage.length) {
|
|
282
|
+
const dataUrl = this._canvas.toDataURL("image/png");
|
|
283
|
+
this._dumpNextFrameToImage.forEach((c) => c(dataUrl));
|
|
284
|
+
this._dumpNextFrameToImage.length = 0;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
resizeViewport(width, height) {
|
|
288
|
+
this._viewportSize = [width, height];
|
|
289
|
+
this._canvas.style.width = `${Math.floor(width)}px`;
|
|
290
|
+
this._canvas.style.height = `${Math.floor(height)}px`;
|
|
291
|
+
this._engine.resize();
|
|
292
|
+
this.handleSizing(false);
|
|
293
|
+
this.scheduleRerender();
|
|
294
|
+
}
|
|
295
|
+
// Exists to be overridden
|
|
296
|
+
handleSizing(_force) {
|
|
297
|
+
// Do nothing
|
|
298
|
+
}
|
|
299
|
+
// Exists to be overridden
|
|
300
|
+
refreshCameraNearFar() {
|
|
301
|
+
// Do nothing
|
|
302
|
+
}
|
|
303
|
+
}
|