@configura/babylon-view 1.6.2 → 2.0.0-alpha.10

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 (134) hide show
  1. package/.eslintrc.json +18 -18
  2. package/LICENSE +201 -201
  3. package/README.md +1 -1
  4. package/dist/animation/AnimatableObject.d.ts +8 -8
  5. package/dist/animation/AnimatableObject.js +3 -3
  6. package/dist/animation/animator/Animator.d.ts +33 -33
  7. package/dist/animation/animator/Animator.js +58 -58
  8. package/dist/animation/animator/AnimatorEasing.d.ts +16 -16
  9. package/dist/animation/animator/AnimatorEasing.js +31 -31
  10. package/dist/animation/animator/AnimatorEasingMatrix.d.ts +14 -14
  11. package/dist/animation/animator/AnimatorEasingMatrix.js +16 -16
  12. package/dist/animation/animator/AnimatorHighlight.d.ts +16 -16
  13. package/dist/animation/animator/AnimatorHighlight.js +32 -32
  14. package/dist/animation/animator/AnimatorPointToPoint.d.ts +8 -8
  15. package/dist/animation/animator/AnimatorPointToPoint.js +14 -14
  16. package/dist/animation/animator/AnimatorQueue.d.ts +13 -13
  17. package/dist/animation/animator/AnimatorQueue.js +57 -57
  18. package/dist/animation/animator/AnimatorScale.d.ts +8 -8
  19. package/dist/animation/animator/AnimatorScale.js +13 -13
  20. package/dist/animation/animator/AnimatorSpin.d.ts +10 -10
  21. package/dist/animation/animator/AnimatorSpin.js +13 -13
  22. package/dist/animation/animator/EasingFunctions.d.ts +35 -35
  23. package/dist/animation/animator/EasingFunctions.js +137 -137
  24. package/dist/animation/coordinator/Coordinator.d.ts +28 -28
  25. package/dist/animation/coordinator/Coordinator.js +53 -53
  26. package/dist/animation/coordinator/CoordinatorDropAndSpin.d.ts +22 -22
  27. package/dist/animation/coordinator/CoordinatorDropAndSpin.js +138 -138
  28. package/dist/animation/coordinator/CoordinatorIdentity.d.ts +11 -11
  29. package/dist/animation/coordinator/CoordinatorIdentity.js +14 -14
  30. package/dist/animation/coordinator/CoordinatorNodeQueues.d.ts +18 -18
  31. package/dist/animation/coordinator/CoordinatorNodeQueues.js +50 -50
  32. package/dist/animation/coordinator/CoordinatorPulse.d.ts +21 -21
  33. package/dist/animation/coordinator/CoordinatorPulse.js +47 -47
  34. package/dist/animation/coordinator/CoordinatorPulseBounce.d.ts +14 -14
  35. package/dist/animation/coordinator/CoordinatorPulseBounce.js +35 -35
  36. package/dist/animation/coordinator/CoordinatorPulseHighlight.d.ts +13 -13
  37. package/dist/animation/coordinator/CoordinatorPulseHighlight.js +29 -29
  38. package/dist/animation/coordinator/CoordinatorPulseInflate.d.ts +14 -14
  39. package/dist/animation/coordinator/CoordinatorPulseInflate.js +23 -23
  40. package/dist/camera/CameraCreator.d.ts +5 -5
  41. package/dist/camera/CameraCreator.js +4 -4
  42. package/dist/camera/CfgArcRotateCameraPointersInput.d.ts +26 -26
  43. package/dist/camera/CfgArcRotateCameraPointersInput.js +266 -266
  44. package/dist/camera/CfgOrbitalCamera.d.ts +76 -68
  45. package/dist/camera/CfgOrbitalCamera.js +276 -250
  46. package/dist/camera/CfgOrbitalCameraControlProps.d.ts +12 -6
  47. package/dist/camera/CfgOrbitalCameraControlProps.js +7 -3
  48. package/dist/camera/GradingApplier.d.ts +3 -3
  49. package/dist/camera/GradingApplier.js +48 -48
  50. package/dist/engine/EngineCreator.d.ts +3 -3
  51. package/dist/engine/EngineCreator.js +10 -10
  52. package/dist/geometry/CfgGeometry.d.ts +29 -29
  53. package/dist/geometry/CfgGeometry.js +146 -146
  54. package/dist/geometry/CfgMesh.d.ts +10 -10
  55. package/dist/geometry/CfgMesh.js +38 -38
  56. package/dist/geometry/geoSplitter.d.ts +8 -8
  57. package/dist/geometry/geoSplitter.js +192 -192
  58. package/dist/geometry/stretch/CfgMorphTarget.d.ts +15 -15
  59. package/dist/geometry/stretch/CfgMorphTarget.js +65 -65
  60. package/dist/geometry/stretch/CfgStretchData.d.ts +116 -116
  61. package/dist/geometry/stretch/CfgStretchData.js +350 -350
  62. package/dist/geometry/stretch/CfgStretchMorphGeometry.d.ts +16 -16
  63. package/dist/geometry/stretch/CfgStretchMorphGeometry.js +95 -95
  64. package/dist/index.d.ts +16 -13
  65. package/dist/index.js +16 -13
  66. package/dist/io/CfgHistoryToCameraConfConnector.d.ts +30 -0
  67. package/dist/io/CfgHistoryToCameraConfConnector.js +80 -0
  68. package/dist/io/CfgIOCameraConfConnector.d.ts +36 -0
  69. package/dist/io/CfgIOCameraConfConnector.js +81 -0
  70. package/dist/io/CfgObservableStateToCameraConfConnector.d.ts +11 -0
  71. package/dist/io/CfgObservableStateToCameraConfConnector.js +11 -0
  72. package/dist/io/CfgWindowMessageToCameraConfConnector.d.ts +11 -0
  73. package/dist/io/CfgWindowMessageToCameraConfConnector.js +11 -0
  74. package/dist/light/CfgDirectionalLight.d.ts +8 -8
  75. package/dist/light/CfgDirectionalLight.js +18 -18
  76. package/dist/light/CfgHemisphericLight.d.ts +7 -7
  77. package/dist/light/CfgHemisphericLight.js +17 -17
  78. package/dist/light/CfgPointLight.d.ts +8 -8
  79. package/dist/light/CfgPointLight.js +18 -18
  80. package/dist/light/DefaultLightRig.d.ts +19 -19
  81. package/dist/light/DefaultLightRig.js +77 -77
  82. package/dist/light/LightRigCreator.d.ts +9 -9
  83. package/dist/light/LightRigCreator.js +3 -3
  84. package/dist/material/CfgMaterial.d.ts +68 -68
  85. package/dist/material/CfgMaterial.js +482 -482
  86. package/dist/material/DummyMaterialCreator.d.ts +4 -4
  87. package/dist/material/DummyMaterialCreator.js +15 -15
  88. package/dist/material/material.d.ts +18 -18
  89. package/dist/material/material.js +128 -128
  90. package/dist/material/texture.d.ts +14 -14
  91. package/dist/material/texture.js +306 -306
  92. package/dist/nodes/CfgContentRootNode.d.ts +19 -19
  93. package/dist/nodes/CfgContentRootNode.js +75 -75
  94. package/dist/nodes/CfgDeferredMeshNode.d.ts +55 -55
  95. package/dist/nodes/CfgDeferredMeshNode.js +378 -378
  96. package/dist/nodes/CfgProductNode.d.ts +127 -127
  97. package/dist/nodes/CfgProductNode.js +598 -598
  98. package/dist/nodes/CfgSymNode.d.ts +50 -50
  99. package/dist/nodes/CfgSymNode.js +249 -249
  100. package/dist/nodes/CfgSymRootNode.d.ts +45 -45
  101. package/dist/nodes/CfgSymRootNode.js +229 -229
  102. package/dist/nodes/CfgTransformNode.d.ts +33 -33
  103. package/dist/nodes/CfgTransformNode.js +83 -83
  104. package/dist/scene/SceneCreator.d.ts +6 -6
  105. package/dist/scene/SceneCreator.js +22 -22
  106. package/dist/utilities/CfgBoundingBox.d.ts +21 -21
  107. package/dist/utilities/CfgBoundingBox.js +81 -81
  108. package/dist/utilities/anchor/anchor.d.ts +50 -50
  109. package/dist/utilities/anchor/anchor.js +133 -133
  110. package/dist/utilities/anchor/anchorMap.d.ts +20 -20
  111. package/dist/utilities/anchor/anchorMap.js +111 -111
  112. package/dist/utilities/utilities3D.d.ts +70 -70
  113. package/dist/utilities/utilities3D.js +265 -265
  114. package/dist/utilities/utilitiesColor.d.ts +18 -18
  115. package/dist/utilities/utilitiesColor.js +50 -50
  116. package/dist/utilities/utilitiesImage.d.ts +6 -6
  117. package/dist/utilities/utilitiesImage.js +107 -107
  118. package/dist/utilities/utilitiesSymRootIdentifier.d.ts +7 -7
  119. package/dist/utilities/utilitiesSymRootIdentifier.js +26 -26
  120. package/dist/view/BaseView.d.ts +78 -78
  121. package/dist/view/BaseView.js +303 -303
  122. package/dist/view/BaseViewConfiguration.d.ts +32 -32
  123. package/dist/view/BaseViewConfiguration.js +10 -10
  124. package/dist/view/RenderEnv.d.ts +43 -43
  125. package/dist/view/RenderEnv.js +7 -7
  126. package/dist/view/SingleProductDefaultCameraView.d.ts +37 -34
  127. package/dist/view/SingleProductDefaultCameraView.js +145 -141
  128. package/dist/view/SingleProductDefaultCameraViewConfiguration.d.ts +42 -46
  129. package/dist/view/SingleProductDefaultCameraViewConfiguration.js +11 -11
  130. package/dist/view/SingleProductView.d.ts +44 -42
  131. package/dist/view/SingleProductView.js +212 -207
  132. package/dist/view/SingleProductViewConfiguration.d.ts +32 -32
  133. package/dist/view/SingleProductViewConfiguration.js +19 -19
  134. package/package.json +5 -5
@@ -1,598 +1,598 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { Matrix } from "@babylonjs/core/Maths/math.vector.js";
11
- import { InspectableType } from "@babylonjs/core/Misc/iInspectable.js";
12
- import { aggregateAllMaterialApplications, CfgMtrlApplication, CfgMtrlApplicationSource, logMaterialMappingToConsole, } from "@configura/web-api";
13
- import { LogObservable, readFileToArrayBuffer } from "@configura/web-utilities";
14
- import { CfgAnchorRef, getAnchorTargetPriorityComparer, updatedStretchedAnchorPointMatrix, } from "../utilities/anchor/anchor.js";
15
- import { makeAnchoredToAnchorMap } from "../utilities/anchor/anchorMap.js";
16
- import { CfgBoundingBox } from "../utilities/CfgBoundingBox.js";
17
- import { modelTransformToSymTransform, symTransformToMatrix } from "../utilities/utilities3D.js";
18
- import { isSameRootNodeSource } from "../utilities/utilitiesSymRootIdentifier.js";
19
- import { CfgSymRootNode, isSymRootNode } from "./CfgSymRootNode.js";
20
- import { CfgTransformNode } from "./CfgTransformNode.js";
21
- export function isProductNode(value) {
22
- return value instanceof CfgProductNode;
23
- }
24
- export function isCfgSymRootNode(value) {
25
- return value instanceof CfgSymRootNode;
26
- }
27
- export function isCfgAnchorableNode(value) {
28
- return isProductNode(value) || isCfgSymRootNode(value);
29
- }
30
- export class CfgProductNode extends CfgTransformNode {
31
- constructor(renderEnvironment, _product) {
32
- super(renderEnvironment, `(Product) ${_product.sku}`);
33
- this._product = _product;
34
- this.logger = new LogObservable();
35
- this._destroyed = false;
36
- this._applicationAreas = [];
37
- this._mtrlApplications = [];
38
- this._debugMtrlApplications = [];
39
- this._scheduledForRemoval = [];
40
- this._anchoredToAnchors = new Map();
41
- this._symRootLoadings = [];
42
- /**
43
- * The passed function is recursively applied on every descendant CfgProductNode in the tree.
44
- * This node is included. Destroyed products are not included.
45
- */
46
- this._applyOnDescendantProductNodes = (fn) => {
47
- const result = [];
48
- result.push(fn(this));
49
- for (const additionalProduct of this._getAdditionalProductNodes()) {
50
- result.push(...additionalProduct._applyOnDescendantProductNodes(fn));
51
- }
52
- return result;
53
- };
54
- this.key = _product.key;
55
- /* eslint-disable */
56
- // Useful debug tool:
57
- if (false) {
58
- window.product = this;
59
- window[this.key] = this;
60
- console.log(`Use "window.product" or 'window["${this.key}"]' to access "${this.key}" product node.`);
61
- }
62
- /* eslint-enable */
63
- this._refreshTransformAndAnchoring();
64
- }
65
- static make(renderEnvironment, product) {
66
- return new this(renderEnvironment, product);
67
- }
68
- get cfgClassName() {
69
- return "CfgProductNode";
70
- }
71
- destroy() {
72
- this._destroyed = true;
73
- this._symRootLoadings.length = 0;
74
- for (const symRoot of this._getSymRootChildren().filter((c) => !c.isForDebug)) {
75
- this.scheduleForRemoval(symRoot);
76
- }
77
- }
78
- get product() {
79
- return this._product;
80
- }
81
- /**
82
- * We want to be able to animate nodes that are on the way out.
83
- * So we do not immediately remove them from the tree.
84
- */
85
- scheduleForRemoval(node) {
86
- node.destroy();
87
- this._scheduledForRemoval.push(node);
88
- }
89
- isDestroyed() {
90
- return this._destroyed;
91
- }
92
- _refreshTransformAndAnchoring() {
93
- const product = this._product._internal;
94
- const modelTransform = product.transform;
95
- if (modelTransform !== undefined) {
96
- const modelSymTransform = modelTransformToSymTransform(modelTransform);
97
- this._modelMatrix = symTransformToMatrix(modelSymTransform.transform());
98
- }
99
- this.anchorRef = CfgAnchorRef.make(product.anchor);
100
- this.refreshTransform();
101
- }
102
- /**
103
- * This function will apply either of tree passed functions on the additional products/ in the
104
- * passed CfgProduct and the additional products in the CfgProductNode.
105
- * It is not applied recursively.
106
- */
107
- _syncAdditionalProductNodes(parentProduct, fn) {
108
- const { both, productNodeButNoProduct, productButNoProductNode } = fn;
109
- const additionalProducts = parentProduct.additionalProducts.filter((c) => c.selected);
110
- const additionalProductNodes = this._getAdditionalProductNodes();
111
- for (const additionalProductNode of additionalProductNodes) {
112
- const index = additionalProducts.findIndex((p) => additionalProductNode.product.isBackedBySame(p));
113
- if (index === -1) {
114
- if (productNodeButNoProduct === undefined) {
115
- throw Error(`ProductNode ${additionalProductNode.key} exist, but no data for it. There is no handler for this.`);
116
- }
117
- productNodeButNoProduct(additionalProductNode);
118
- }
119
- else {
120
- const additionalProduct = additionalProducts.splice(index, 1)[0];
121
- if (both === undefined) {
122
- throw Error(`ProductNode ${additionalProductNode.key} and data ${additionalProduct.key} exists. There is no handler for this.`);
123
- }
124
- both(additionalProduct, additionalProductNode);
125
- }
126
- }
127
- for (const additionalProduct of additionalProducts) {
128
- if (productButNoProductNode === undefined) {
129
- throw Error(`Data ${additionalProduct.key} exists, but no ProductNode for it. There is no handler for this.`);
130
- }
131
- productButNoProductNode(additionalProduct);
132
- }
133
- }
134
- /**
135
- * Application areas are essentially catalogue level material mappings.
136
- * This function is recursively applied on additional products.
137
- */
138
- setApplicationAreas(applicationAreas) {
139
- this._applyOnDescendantProductNodes((p) => {
140
- p._applicationAreas = applicationAreas;
141
- });
142
- }
143
- /**
144
- * Start loading the geometry, but do not yet show it.
145
- * This function is recursively applied on additional products.
146
- */
147
- loadGeo(coordinatorWithMeta) {
148
- return __awaiter(this, void 0, void 0, function* () {
149
- const product = this._product;
150
- const rootNodeSources = product._internal.rootNodeSources || [];
151
- // Duplicate filter
152
- const updateRootNodeSources = rootNodeSources.reduce((a, c) => {
153
- if (a.every((s) => !isSameRootNodeSource(s, c))) {
154
- a.push(c);
155
- }
156
- return a;
157
- }, []);
158
- const allSymRootLoadings = this._symRootLoadings;
159
- let i = allSymRootLoadings.length;
160
- while (i--) {
161
- const symRootLoading = allSymRootLoadings[i];
162
- const updateIndex = updateRootNodeSources.findIndex((rootNodeSource) => isSameRootNodeSource(rootNodeSource, symRootLoading.rootNodeSource));
163
- if (updateIndex === -1) {
164
- // We remove the inProgress, because the thing which is in progress will not be
165
- // wanted when it arrives.
166
- allSymRootLoadings.splice(i, 1);
167
- }
168
- }
169
- for (const symRootChild of this._getSymRootChildren().filter((c) => !c.isForDebug)) {
170
- const updateIndex = updateRootNodeSources.findIndex((m) => symRootChild.isSameIdentifierTransformAndAnchor(m));
171
- if (updateIndex === -1) {
172
- // Not found, remove
173
- this.scheduleForRemoval(symRootChild);
174
- }
175
- else {
176
- // Found, no need to change anything
177
- updateRootNodeSources.splice(updateIndex, 1);
178
- }
179
- }
180
- const batchSymRootLoadings = updateRootNodeSources.map((rootNodeSource) => {
181
- let symRootLoading = allSymRootLoadings.find((s) => isSameRootNodeSource(rootNodeSource, s.rootNodeSource));
182
- if (symRootLoading === undefined) {
183
- symRootLoading = {
184
- rootNodeSource,
185
- rootNodePromise: CfgSymRootNode.makeCfgSymRootFromRootNodeSource(this.logger, false, this._renderEnvironment, this, rootNodeSource),
186
- };
187
- allSymRootLoadings.push(symRootLoading);
188
- }
189
- return symRootLoading;
190
- });
191
- yield Promise.all([
192
- ...batchSymRootLoadings.map((s) => s.rootNodePromise),
193
- this._loadAdditionalProducts(coordinatorWithMeta),
194
- ]);
195
- const addedSymRoots = (yield Promise.all(batchSymRootLoadings.map((s) => s.rootNodePromise)))
196
- .filter((symRoot) => symRoot !== undefined)
197
- .filter((symRoot) => {
198
- const loadInProgressIndex = allSymRootLoadings.findIndex((symRootLoadInProgress) => symRoot.isSameIdentifierTransformAndAnchor(symRootLoadInProgress.rootNodeSource));
199
- if (loadInProgressIndex === -1) {
200
- // This node no longer needs to be added...
201
- if (!symRoot.parent) {
202
- // ...and was never added as a child
203
- symRoot.destroy();
204
- symRoot.dispose();
205
- }
206
- return false;
207
- }
208
- // We'll add this, so it moves from "loading" to being a proper child
209
- allSymRootLoadings.splice(loadInProgressIndex, 1);
210
- this.add(symRoot);
211
- return true;
212
- });
213
- // Updated symRootChildren
214
- const anchorableChildren = this._getAnchorableNodes();
215
- // Make a map of who is anchored to who
216
- const anchoredToAnchors = makeAnchoredToAnchorMap(anchorableChildren, getAnchorTargetPriorityComparer(this.product._internal.measureDefinitions));
217
- this._anchoredToAnchors = anchoredToAnchors;
218
- for (const child of anchorableChildren) {
219
- child.setAnchorTarget(anchoredToAnchors.get(child));
220
- }
221
- this.refreshStretch();
222
- for (const symRoot of addedSymRoots) {
223
- if (coordinatorWithMeta === undefined) {
224
- continue;
225
- }
226
- const c = coordinatorWithMeta.coordinator;
227
- yield c.prepareForEnter.bind(c)(symRoot, coordinatorWithMeta.isNewProduct);
228
- }
229
- });
230
- }
231
- _loadAdditionalProducts(coordinatorWithMeta) {
232
- return __awaiter(this, void 0, void 0, function* () {
233
- const additionalProductLoadPromises = [];
234
- this._syncAdditionalProductNodes(this._product, {
235
- productNodeButNoProduct: (additionalProductNode) => {
236
- this.scheduleForRemoval(additionalProductNode);
237
- },
238
- productButNoProductNode: (additionalProduct) => {
239
- const additionalProductNode = CfgProductNode.make(this._renderEnvironment, additionalProduct);
240
- this.add(additionalProductNode);
241
- additionalProductLoadPromises.push(additionalProductNode.loadGeo(coordinatorWithMeta));
242
- },
243
- both: (_additionalProduct, additionalProductNode) => {
244
- additionalProductNode._refreshTransformAndAnchoring();
245
- additionalProductLoadPromises.push(additionalProductNode.loadGeo(coordinatorWithMeta));
246
- },
247
- });
248
- yield Promise.all(additionalProductLoadPromises);
249
- });
250
- }
251
- /**
252
- * Run any animations and then permanently removes the nodes from the tree
253
- * This function is recursively applied on additional products.
254
- */
255
- flushScheduledForRemove(animationCoordinator) {
256
- return __awaiter(this, void 0, void 0, function* () {
257
- const thisBatch = this._scheduledForRemoval.slice();
258
- this._scheduledForRemoval.length = 0;
259
- yield Promise.all(this._getAdditionalProductNodes(true).map((additionalProductNode) => additionalProductNode.flushScheduledForRemove(animationCoordinator)));
260
- yield Promise.all(thisBatch.map((node) => (() => __awaiter(this, void 0, void 0, function* () {
261
- if (node instanceof CfgSymRootNode) {
262
- if (animationCoordinator !== undefined) {
263
- const c = animationCoordinator.coordinator;
264
- yield c.prepareForExit.bind(c)(node);
265
- }
266
- }
267
- this.remove(true, node);
268
- }))()));
269
- });
270
- }
271
- /**
272
- * Are all materials currently needed loaded and ready to be applied?
273
- * This function does not take additional products into account.
274
- */
275
- _isAllMeshMaterialsReady() {
276
- return this._getSymRootChildren().reduce((a, c) => a && c.isAllMeshMaterialsReady(), true);
277
- }
278
- /**
279
- * Resolves when all materials currently needed have been loaded and are ready to be applied.
280
- * This function does not take additional products into account.
281
- */
282
- _awaitAllMeshMaterialsReady() {
283
- return __awaiter(this, void 0, void 0, function* () {
284
- return new Promise((resolve, reject) => {
285
- let maxTries = 60 * 60; // Assuming 60 fps this gives a minute, which is absurdly long
286
- const frame = () => {
287
- if (this._isAllMeshMaterialsReady()) {
288
- resolve();
289
- return;
290
- }
291
- if (maxTries === 0) {
292
- reject("Materials not ready in time");
293
- return;
294
- }
295
- window.requestAnimationFrame(frame);
296
- maxTries--;
297
- };
298
- frame();
299
- });
300
- });
301
- }
302
- /**
303
- * Loads the materials needed.
304
- * This function is recursively applied on additional products.
305
- */
306
- loadMaterials(animationCoordinator) {
307
- return __awaiter(this, void 0, void 0, function* () {
308
- const product = this._product;
309
- const productMtrlApplications = (product._internal.mtrlApplications || []).map((m) => CfgMtrlApplication.fromMtrlLikeApplication(CfgMtrlApplicationSource.Product, m));
310
- this._mtrlApplications = productMtrlApplications;
311
- this._configuration = product.configuration;
312
- yield Promise.all([
313
- this._aggregateMaterialsPushToChildrenAndLoad(animationCoordinator),
314
- ...this._getAdditionalProductNodes().map((additionalProductNode) => additionalProductNode.loadMaterials(animationCoordinator)),
315
- ]);
316
- });
317
- }
318
- /**
319
- * Update the tag (area) to material mapping and gives them to sym children
320
- * This function does not take additional products into account.
321
- */
322
- _aggregateMaterialsPushToChildrenAndLoad(animationCoordinator) {
323
- return __awaiter(this, void 0, void 0, function* () {
324
- if (this._applicationAreas === undefined || this._configuration === undefined) {
325
- return;
326
- }
327
- const areasToMaterials = aggregateAllMaterialApplications(this._applicationAreas, this._mtrlApplications, this._configuration, this._debugMtrlApplications);
328
- this._areasToMaterials = areasToMaterials;
329
- yield this._pushMaterialToSymRootChildrenAndLoad(animationCoordinator);
330
- });
331
- }
332
- /**
333
- * Starts loading the materials on the sym children (but does not apply)
334
- * This function does not take additional products into account.
335
- */
336
- _pushMaterialToSymRootChildrenAndLoad(animationCoordinator) {
337
- return __awaiter(this, void 0, void 0, function* () {
338
- const areasToMaterials = this._areasToMaterials;
339
- if (areasToMaterials === undefined) {
340
- return;
341
- }
342
- yield Promise.all(this._getSymRootChildren().map((child) => child.setMaterialsAndLoad(areasToMaterials, animationCoordinator)));
343
- });
344
- }
345
- _getSymRootChildren() {
346
- return this.getChildren()
347
- .filter(isSymRootNode)
348
- .filter((c) => !c.isDestroyed());
349
- }
350
- _getAdditionalProductNodes(includeDestroyed = false) {
351
- return this.getChildren()
352
- .filter(isProductNode)
353
- .filter((c) => includeDestroyed || !c.isDestroyed());
354
- }
355
- _getAnchorableNodes() {
356
- return this.getChildren()
357
- .filter(isCfgAnchorableNode)
358
- .filter((c) => !c.isDestroyed());
359
- }
360
- /**
361
- * Applies and thereby shows the geometry. Finally flushes scheduled for remove.
362
- * This function is recursively applied on additional products.
363
- */
364
- applyGeo(animationCoordinator) {
365
- return __awaiter(this, void 0, void 0, function* () {
366
- yield Promise.all(this._applyOnDescendantProductNodes((p) => (() => __awaiter(this, void 0, void 0, function* () {
367
- p._getSymRootChildren().forEach((child) => {
368
- child.applyGeo();
369
- });
370
- // Wait until materials have been loaded so that we don't get any blinking.
371
- // It might seem wrong that this is done after we apply, but the material
372
- // will not be ready unless it is applied. So we wait after applying.
373
- yield p._awaitAllMeshMaterialsReady();
374
- }))()));
375
- // Not blocking on this
376
- void this.flushScheduledForRemove(animationCoordinator);
377
- });
378
- }
379
- /**
380
- * Applies and thereby shows the right materials.
381
- * This function is recursively applied on additional products.
382
- */
383
- applyMaterials() {
384
- return __awaiter(this, void 0, void 0, function* () {
385
- yield Promise.all(this._applyOnDescendantProductNodes((p) => (() => __awaiter(this, void 0, void 0, function* () {
386
- p._getSymRootChildren().forEach((child) => {
387
- child.applyMaterial();
388
- });
389
- // Wait until materials have been loaded so that we don't get any blinking.
390
- // It might seem wrong that this is done after we apply, but the material
391
- // will not be ready unless it is applied. So we wait after applying.
392
- yield p._awaitAllMeshMaterialsReady();
393
- }))()));
394
- });
395
- }
396
- setAnchorTarget(anchorTarget) {
397
- this._anchorTarget = anchorTarget;
398
- }
399
- refreshStretch() {
400
- const updated = updatedStretchedAnchorPointMatrix(this.anchorRef, this._anchorTarget, this._stretchedAnchorPointMatrix);
401
- if (updated !== undefined) {
402
- this._stretchedAnchorPointMatrix = updated;
403
- this.refreshTransform();
404
- }
405
- // anchoredToAnchors is sorted so that anchors always are before what
406
- // is anchored to them. That way we know that if we refreshStretch on
407
- // them first anchor-on-anchor will work correctly.
408
- const anchorableChildren = this._getAnchorableNodes().slice();
409
- for (const anchor of this._anchoredToAnchors.values()) {
410
- const i = anchorableChildren.indexOf(anchor);
411
- if (i === -1) {
412
- // As multiple anchors can anchor to the same anchor this will happen
413
- continue;
414
- }
415
- anchor.refreshStretch();
416
- anchorableChildren.splice(i, 1);
417
- }
418
- // Refresh for the un-anchored
419
- for (const child of anchorableChildren) {
420
- child.refreshStretch();
421
- }
422
- }
423
- get originalMatrix() {
424
- var _a;
425
- if (this._originalMatrixWithModelTransform === undefined) {
426
- let originalMatrix = (_a = this._modelMatrix) !== null && _a !== void 0 ? _a : Matrix.Identity();
427
- const stretchedAnchorPointMatrix = this._stretchedAnchorPointMatrix;
428
- if (stretchedAnchorPointMatrix !== undefined) {
429
- originalMatrix = originalMatrix.multiply(stretchedAnchorPointMatrix);
430
- }
431
- this._originalMatrixWithModelTransform = originalMatrix;
432
- }
433
- return this._originalMatrixWithModelTransform;
434
- }
435
- refreshTransform() {
436
- this._originalMatrixWithModelTransform = undefined; // Reset the matrix
437
- this.setPreTransformMatrix(this.originalMatrix);
438
- }
439
- _applyDebugSymRoots(symRootPromises) {
440
- return __awaiter(this, void 0, void 0, function* () {
441
- const allSymRoots = yield Promise.all(symRootPromises);
442
- allSymRoots.forEach((symRoot) => {
443
- if (symRoot === undefined) {
444
- return;
445
- }
446
- this.add(symRoot);
447
- });
448
- yield this.applyGeo();
449
- yield this._pushMaterialToSymRootChildrenAndLoad();
450
- yield this.applyMaterials();
451
- this._renderEnvironment.scheduleRerender();
452
- });
453
- }
454
- _addDebugMtrlApplication(debugMtrlApplication) {
455
- return __awaiter(this, void 0, void 0, function* () {
456
- this._debugMtrlApplications.push(debugMtrlApplication);
457
- yield this._aggregateMaterialsPushToChildrenAndLoad();
458
- yield this.applyMaterials();
459
- this._renderEnvironment.scheduleRerender();
460
- });
461
- }
462
- get boundingBox() {
463
- const bb = [...this._getSymRootChildren(), ...this._getAdditionalProductNodes()].reduce((a, m) => {
464
- a.expand(m.boundingBox);
465
- return a;
466
- }, new CfgBoundingBox());
467
- bb.applyMatrix(this.originalMatrix);
468
- return bb;
469
- }
470
- addInspectorProperties() {
471
- super.addInspectorProperties();
472
- this.addInspectableCustomProperty({
473
- label: "Log materialMappings",
474
- propertyName: "_inspectorLogMaterialMappings",
475
- type: InspectableType.Checkbox,
476
- });
477
- this.addInspectableCustomProperty({
478
- label: "Add material to mapping from File",
479
- propertyName: "_inspectorAddMaterialToMaterialMappingFromFile",
480
- type: InspectableType.Checkbox,
481
- });
482
- this.addInspectableCustomProperty({
483
- label: "Add material to mapping from Url",
484
- propertyName: "_inspectorAddMaterialToMaterialMappingFromUrl",
485
- type: InspectableType.Checkbox,
486
- });
487
- this.addInspectableCustomProperty({
488
- label: "Add CmSym from File",
489
- propertyName: "_inspectorAddCmSymFile",
490
- type: InspectableType.Checkbox,
491
- });
492
- this.addInspectableCustomProperty({
493
- label: "Add CmSym from Url",
494
- propertyName: "_inspectorAddCmSymUrl",
495
- type: InspectableType.Checkbox,
496
- });
497
- }
498
- get _inspectorLogMaterialMappings() {
499
- return this._areasToMaterials === undefined;
500
- }
501
- set _inspectorLogMaterialMappings(x) {
502
- if (this._areasToMaterials === undefined) {
503
- return;
504
- }
505
- logMaterialMappingToConsole(this._areasToMaterials);
506
- }
507
- get _inspectorAddMaterialToMaterialMappingFromFile() {
508
- return this._areasToMaterials === undefined;
509
- }
510
- set _inspectorAddMaterialToMaterialMappingFromFile(x) {
511
- if (this._areasToMaterials === undefined) {
512
- return;
513
- }
514
- const tag = window.prompt("Please provide a Tag for the mapping");
515
- if (tag === null || tag.trim().length === 0) {
516
- alert("You must provide a tag for the mapping");
517
- return;
518
- }
519
- const fileUpload = document.createElement("input");
520
- fileUpload.type = "file";
521
- fileUpload.style.display = "none";
522
- const body = document.getElementsByTagName("body")[0];
523
- body.appendChild(fileUpload);
524
- fileUpload.addEventListener("change", (event) => {
525
- void (() => __awaiter(this, void 0, void 0, function* () {
526
- const files = fileUpload.files;
527
- if (files !== null) {
528
- const mtrlApplications = yield Promise.all(Array.from(files)
529
- .map(readFileToArrayBuffer)
530
- .map((bufferAndNamePromise) => __awaiter(this, void 0, void 0, function* () {
531
- const bufferAndName = yield bufferAndNamePromise;
532
- return CfgMtrlApplication.fromBufferForDebug([tag], bufferAndName.fileName, bufferAndName.buffer);
533
- })));
534
- mtrlApplications.forEach((mtrlApplication) => {
535
- this._addDebugMtrlApplication(mtrlApplication);
536
- });
537
- }
538
- body.removeChild(fileUpload);
539
- }))();
540
- });
541
- fileUpload.click();
542
- }
543
- get _inspectorAddMaterialToMaterialMappingFromUrl() {
544
- return this._areasToMaterials === undefined;
545
- }
546
- set _inspectorAddMaterialToMaterialMappingFromUrl(x) {
547
- if (this._areasToMaterials === undefined) {
548
- return;
549
- }
550
- const tag = window.prompt("Please provide a Tag for the mapping");
551
- if (tag === null || tag.trim().length === 0) {
552
- alert("You must provide a tag for the mapping");
553
- return;
554
- }
555
- const url = window.prompt("Please provide a material-url");
556
- if (url === null || url.trim().length === 0) {
557
- alert("You must provide an URL to a material-file");
558
- return;
559
- }
560
- const mtrlApplication = CfgMtrlApplication.fromUrlForDebug([tag], url);
561
- this._addDebugMtrlApplication(mtrlApplication);
562
- }
563
- get _inspectorAddCmSymFile() {
564
- return false;
565
- }
566
- set _inspectorAddCmSymFile(x) {
567
- const fileUpload = document.createElement("input");
568
- fileUpload.type = "file";
569
- fileUpload.style.display = "none";
570
- const body = document.getElementsByTagName("body")[0];
571
- body.appendChild(fileUpload);
572
- const logger = this.logger;
573
- const renderEnvironment = this._renderEnvironment;
574
- fileUpload.addEventListener("change", (event) => {
575
- const files = fileUpload.files;
576
- if (files !== null) {
577
- const symRootPromises = Array.from(files).map((file) => {
578
- return CfgSymRootNode.makeCfgSymRootFromFile(logger, true, renderEnvironment, this, file);
579
- });
580
- this._applyDebugSymRoots(symRootPromises);
581
- }
582
- body.removeChild(fileUpload);
583
- });
584
- fileUpload.click();
585
- }
586
- get _inspectorAddCmSymUrl() {
587
- return false;
588
- }
589
- set _inspectorAddCmSymUrl(x) {
590
- const url = window.prompt("Please provide a CmSym-url");
591
- if (url === null || url.trim().length === 0) {
592
- alert("You must provide an URL to a CmSym-file");
593
- return;
594
- }
595
- const symRootNode = CfgSymRootNode.makeCfgSymRootFromUrl(this.logger, true, this._renderEnvironment, this, url, undefined, undefined);
596
- this._applyDebugSymRoots([symRootNode]);
597
- }
598
- }
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Matrix } from "@babylonjs/core/Maths/math.vector.js";
11
+ import { InspectableType } from "@babylonjs/core/Misc/iInspectable.js";
12
+ import { aggregateAllMaterialApplications, CfgMtrlApplication, CfgMtrlApplicationSource, logMaterialMappingToConsole, } from "@configura/web-api";
13
+ import { LogObservable, readFileToArrayBuffer } from "@configura/web-utilities";
14
+ import { CfgAnchorRef, getAnchorTargetPriorityComparer, updatedStretchedAnchorPointMatrix, } from "../utilities/anchor/anchor.js";
15
+ import { makeAnchoredToAnchorMap } from "../utilities/anchor/anchorMap.js";
16
+ import { CfgBoundingBox } from "../utilities/CfgBoundingBox.js";
17
+ import { modelTransformToSymTransform, symTransformToMatrix } from "../utilities/utilities3D.js";
18
+ import { isSameRootNodeSource } from "../utilities/utilitiesSymRootIdentifier.js";
19
+ import { CfgSymRootNode, isSymRootNode } from "./CfgSymRootNode.js";
20
+ import { CfgTransformNode } from "./CfgTransformNode.js";
21
+ export function isProductNode(value) {
22
+ return value instanceof CfgProductNode;
23
+ }
24
+ export function isCfgSymRootNode(value) {
25
+ return value instanceof CfgSymRootNode;
26
+ }
27
+ export function isCfgAnchorableNode(value) {
28
+ return isProductNode(value) || isCfgSymRootNode(value);
29
+ }
30
+ export class CfgProductNode extends CfgTransformNode {
31
+ constructor(renderEnvironment, _product) {
32
+ super(renderEnvironment, `(Product) ${_product.sku}`);
33
+ this._product = _product;
34
+ this.logger = new LogObservable();
35
+ this._destroyed = false;
36
+ this._applicationAreas = [];
37
+ this._mtrlApplications = [];
38
+ this._debugMtrlApplications = [];
39
+ this._scheduledForRemoval = [];
40
+ this._anchoredToAnchors = new Map();
41
+ this._symRootLoadings = [];
42
+ /**
43
+ * The passed function is recursively applied on every descendant CfgProductNode in the tree.
44
+ * This node is included. Destroyed products are not included.
45
+ */
46
+ this._applyOnDescendantProductNodes = (fn) => {
47
+ const result = [];
48
+ result.push(fn(this));
49
+ for (const additionalProduct of this._getAdditionalProductNodes()) {
50
+ result.push(...additionalProduct._applyOnDescendantProductNodes(fn));
51
+ }
52
+ return result;
53
+ };
54
+ this.key = _product.key;
55
+ /* eslint-disable */
56
+ // Useful debug tool:
57
+ if (false) {
58
+ window.product = this;
59
+ window[this.key] = this;
60
+ console.log(`Use "window.product" or 'window["${this.key}"]' to access "${this.key}" product node.`);
61
+ }
62
+ /* eslint-enable */
63
+ this._refreshTransformAndAnchoring();
64
+ }
65
+ static make(renderEnvironment, product) {
66
+ return new this(renderEnvironment, product);
67
+ }
68
+ get cfgClassName() {
69
+ return "CfgProductNode";
70
+ }
71
+ destroy() {
72
+ this._destroyed = true;
73
+ this._symRootLoadings.length = 0;
74
+ for (const symRoot of this._getSymRootChildren().filter((c) => !c.isForDebug)) {
75
+ this.scheduleForRemoval(symRoot);
76
+ }
77
+ }
78
+ get product() {
79
+ return this._product;
80
+ }
81
+ /**
82
+ * We want to be able to animate nodes that are on the way out.
83
+ * So we do not immediately remove them from the tree.
84
+ */
85
+ scheduleForRemoval(node) {
86
+ node.destroy();
87
+ this._scheduledForRemoval.push(node);
88
+ }
89
+ isDestroyed() {
90
+ return this._destroyed;
91
+ }
92
+ _refreshTransformAndAnchoring() {
93
+ const product = this._product._internal;
94
+ const modelTransform = product.transform;
95
+ if (modelTransform !== undefined) {
96
+ const modelSymTransform = modelTransformToSymTransform(modelTransform);
97
+ this._modelMatrix = symTransformToMatrix(modelSymTransform.transform());
98
+ }
99
+ this.anchorRef = CfgAnchorRef.make(product.anchor);
100
+ this.refreshTransform();
101
+ }
102
+ /**
103
+ * This function will apply either of tree passed functions on the additional products/ in the
104
+ * passed CfgProduct and the additional products in the CfgProductNode.
105
+ * It is not applied recursively.
106
+ */
107
+ _syncAdditionalProductNodes(parentProduct, fn) {
108
+ const { both, productNodeButNoProduct, productButNoProductNode } = fn;
109
+ const additionalProducts = parentProduct.additionalProducts.filter((c) => c.selected);
110
+ const additionalProductNodes = this._getAdditionalProductNodes();
111
+ for (const additionalProductNode of additionalProductNodes) {
112
+ const index = additionalProducts.findIndex((p) => additionalProductNode.product.isBackedBySame(p));
113
+ if (index === -1) {
114
+ if (productNodeButNoProduct === undefined) {
115
+ throw Error(`ProductNode ${additionalProductNode.key} exist, but no data for it. There is no handler for this.`);
116
+ }
117
+ productNodeButNoProduct(additionalProductNode);
118
+ }
119
+ else {
120
+ const additionalProduct = additionalProducts.splice(index, 1)[0];
121
+ if (both === undefined) {
122
+ throw Error(`ProductNode ${additionalProductNode.key} and data ${additionalProduct.key} exists. There is no handler for this.`);
123
+ }
124
+ both(additionalProduct, additionalProductNode);
125
+ }
126
+ }
127
+ for (const additionalProduct of additionalProducts) {
128
+ if (productButNoProductNode === undefined) {
129
+ throw Error(`Data ${additionalProduct.key} exists, but no ProductNode for it. There is no handler for this.`);
130
+ }
131
+ productButNoProductNode(additionalProduct);
132
+ }
133
+ }
134
+ /**
135
+ * Application areas are essentially catalogue level material mappings.
136
+ * This function is recursively applied on additional products.
137
+ */
138
+ setApplicationAreas(applicationAreas) {
139
+ this._applyOnDescendantProductNodes((p) => {
140
+ p._applicationAreas = applicationAreas;
141
+ });
142
+ }
143
+ /**
144
+ * Start loading the geometry, but do not yet show it.
145
+ * This function is recursively applied on additional products.
146
+ */
147
+ loadGeo(coordinatorWithMeta) {
148
+ return __awaiter(this, void 0, void 0, function* () {
149
+ const product = this._product;
150
+ const rootNodeSources = product._internal.rootNodeSources || [];
151
+ // Duplicate filter
152
+ const updateRootNodeSources = rootNodeSources.reduce((a, c) => {
153
+ if (a.every((s) => !isSameRootNodeSource(s, c))) {
154
+ a.push(c);
155
+ }
156
+ return a;
157
+ }, []);
158
+ const allSymRootLoadings = this._symRootLoadings;
159
+ let i = allSymRootLoadings.length;
160
+ while (i--) {
161
+ const symRootLoading = allSymRootLoadings[i];
162
+ const updateIndex = updateRootNodeSources.findIndex((rootNodeSource) => isSameRootNodeSource(rootNodeSource, symRootLoading.rootNodeSource));
163
+ if (updateIndex === -1) {
164
+ // We remove the inProgress, because the thing which is in progress will not be
165
+ // wanted when it arrives.
166
+ allSymRootLoadings.splice(i, 1);
167
+ }
168
+ }
169
+ for (const symRootChild of this._getSymRootChildren().filter((c) => !c.isForDebug)) {
170
+ const updateIndex = updateRootNodeSources.findIndex((m) => symRootChild.isSameIdentifierTransformAndAnchor(m));
171
+ if (updateIndex === -1) {
172
+ // Not found, remove
173
+ this.scheduleForRemoval(symRootChild);
174
+ }
175
+ else {
176
+ // Found, no need to change anything
177
+ updateRootNodeSources.splice(updateIndex, 1);
178
+ }
179
+ }
180
+ const batchSymRootLoadings = updateRootNodeSources.map((rootNodeSource) => {
181
+ let symRootLoading = allSymRootLoadings.find((s) => isSameRootNodeSource(rootNodeSource, s.rootNodeSource));
182
+ if (symRootLoading === undefined) {
183
+ symRootLoading = {
184
+ rootNodeSource,
185
+ rootNodePromise: CfgSymRootNode.makeCfgSymRootFromRootNodeSource(this.logger, false, this._renderEnvironment, this, rootNodeSource),
186
+ };
187
+ allSymRootLoadings.push(symRootLoading);
188
+ }
189
+ return symRootLoading;
190
+ });
191
+ yield Promise.all([
192
+ ...batchSymRootLoadings.map((s) => s.rootNodePromise),
193
+ this._loadAdditionalProducts(coordinatorWithMeta),
194
+ ]);
195
+ const addedSymRoots = (yield Promise.all(batchSymRootLoadings.map((s) => s.rootNodePromise)))
196
+ .filter((symRoot) => symRoot !== undefined)
197
+ .filter((symRoot) => {
198
+ const loadInProgressIndex = allSymRootLoadings.findIndex((symRootLoadInProgress) => symRoot.isSameIdentifierTransformAndAnchor(symRootLoadInProgress.rootNodeSource));
199
+ if (loadInProgressIndex === -1) {
200
+ // This node no longer needs to be added...
201
+ if (!symRoot.parent) {
202
+ // ...and was never added as a child
203
+ symRoot.destroy();
204
+ symRoot.dispose();
205
+ }
206
+ return false;
207
+ }
208
+ // We'll add this, so it moves from "loading" to being a proper child
209
+ allSymRootLoadings.splice(loadInProgressIndex, 1);
210
+ this.add(symRoot);
211
+ return true;
212
+ });
213
+ // Updated symRootChildren
214
+ const anchorableChildren = this._getAnchorableNodes();
215
+ // Make a map of who is anchored to who
216
+ const anchoredToAnchors = makeAnchoredToAnchorMap(anchorableChildren, getAnchorTargetPriorityComparer(this.product._internal.measureDefinitions));
217
+ this._anchoredToAnchors = anchoredToAnchors;
218
+ for (const child of anchorableChildren) {
219
+ child.setAnchorTarget(anchoredToAnchors.get(child));
220
+ }
221
+ this.refreshStretch();
222
+ for (const symRoot of addedSymRoots) {
223
+ if (coordinatorWithMeta === undefined) {
224
+ continue;
225
+ }
226
+ const c = coordinatorWithMeta.coordinator;
227
+ yield c.prepareForEnter.bind(c)(symRoot, coordinatorWithMeta.isNewProduct);
228
+ }
229
+ });
230
+ }
231
+ _loadAdditionalProducts(coordinatorWithMeta) {
232
+ return __awaiter(this, void 0, void 0, function* () {
233
+ const additionalProductLoadPromises = [];
234
+ this._syncAdditionalProductNodes(this._product, {
235
+ productNodeButNoProduct: (additionalProductNode) => {
236
+ this.scheduleForRemoval(additionalProductNode);
237
+ },
238
+ productButNoProductNode: (additionalProduct) => {
239
+ const additionalProductNode = CfgProductNode.make(this._renderEnvironment, additionalProduct);
240
+ this.add(additionalProductNode);
241
+ additionalProductLoadPromises.push(additionalProductNode.loadGeo(coordinatorWithMeta));
242
+ },
243
+ both: (_additionalProduct, additionalProductNode) => {
244
+ additionalProductNode._refreshTransformAndAnchoring();
245
+ additionalProductLoadPromises.push(additionalProductNode.loadGeo(coordinatorWithMeta));
246
+ },
247
+ });
248
+ yield Promise.all(additionalProductLoadPromises);
249
+ });
250
+ }
251
+ /**
252
+ * Run any animations and then permanently removes the nodes from the tree
253
+ * This function is recursively applied on additional products.
254
+ */
255
+ flushScheduledForRemove(animationCoordinator) {
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ const thisBatch = this._scheduledForRemoval.slice();
258
+ this._scheduledForRemoval.length = 0;
259
+ yield Promise.all(this._getAdditionalProductNodes(true).map((additionalProductNode) => additionalProductNode.flushScheduledForRemove(animationCoordinator)));
260
+ yield Promise.all(thisBatch.map((node) => (() => __awaiter(this, void 0, void 0, function* () {
261
+ if (node instanceof CfgSymRootNode) {
262
+ if (animationCoordinator !== undefined) {
263
+ const c = animationCoordinator.coordinator;
264
+ yield c.prepareForExit.bind(c)(node);
265
+ }
266
+ }
267
+ this.remove(true, node);
268
+ }))()));
269
+ });
270
+ }
271
+ /**
272
+ * Are all materials currently needed loaded and ready to be applied?
273
+ * This function does not take additional products into account.
274
+ */
275
+ _isAllMeshMaterialsReady() {
276
+ return this._getSymRootChildren().reduce((a, c) => a && c.isAllMeshMaterialsReady(), true);
277
+ }
278
+ /**
279
+ * Resolves when all materials currently needed have been loaded and are ready to be applied.
280
+ * This function does not take additional products into account.
281
+ */
282
+ _awaitAllMeshMaterialsReady() {
283
+ return __awaiter(this, void 0, void 0, function* () {
284
+ return new Promise((resolve, reject) => {
285
+ let maxTries = 60 * 60; // Assuming 60 fps this gives a minute, which is absurdly long
286
+ const frame = () => {
287
+ if (this._isAllMeshMaterialsReady()) {
288
+ resolve();
289
+ return;
290
+ }
291
+ if (maxTries === 0) {
292
+ reject("Materials not ready in time");
293
+ return;
294
+ }
295
+ window.requestAnimationFrame(frame);
296
+ maxTries--;
297
+ };
298
+ frame();
299
+ });
300
+ });
301
+ }
302
+ /**
303
+ * Loads the materials needed.
304
+ * This function is recursively applied on additional products.
305
+ */
306
+ loadMaterials(animationCoordinator) {
307
+ return __awaiter(this, void 0, void 0, function* () {
308
+ const product = this._product;
309
+ const productMtrlApplications = (product._internal.mtrlApplications || []).map((m) => CfgMtrlApplication.fromMtrlLikeApplication(CfgMtrlApplicationSource.Product, m));
310
+ this._mtrlApplications = productMtrlApplications;
311
+ this._configuration = product.configuration;
312
+ yield Promise.all([
313
+ this._aggregateMaterialsPushToChildrenAndLoad(animationCoordinator),
314
+ ...this._getAdditionalProductNodes().map((additionalProductNode) => additionalProductNode.loadMaterials(animationCoordinator)),
315
+ ]);
316
+ });
317
+ }
318
+ /**
319
+ * Update the tag (area) to material mapping and gives them to sym children
320
+ * This function does not take additional products into account.
321
+ */
322
+ _aggregateMaterialsPushToChildrenAndLoad(animationCoordinator) {
323
+ return __awaiter(this, void 0, void 0, function* () {
324
+ if (this._applicationAreas === undefined || this._configuration === undefined) {
325
+ return;
326
+ }
327
+ const areasToMaterials = aggregateAllMaterialApplications(this._applicationAreas, this._mtrlApplications, this._configuration, this._debugMtrlApplications);
328
+ this._areasToMaterials = areasToMaterials;
329
+ yield this._pushMaterialToSymRootChildrenAndLoad(animationCoordinator);
330
+ });
331
+ }
332
+ /**
333
+ * Starts loading the materials on the sym children (but does not apply)
334
+ * This function does not take additional products into account.
335
+ */
336
+ _pushMaterialToSymRootChildrenAndLoad(animationCoordinator) {
337
+ return __awaiter(this, void 0, void 0, function* () {
338
+ const areasToMaterials = this._areasToMaterials;
339
+ if (areasToMaterials === undefined) {
340
+ return;
341
+ }
342
+ yield Promise.all(this._getSymRootChildren().map((child) => child.setMaterialsAndLoad(areasToMaterials, animationCoordinator)));
343
+ });
344
+ }
345
+ _getSymRootChildren() {
346
+ return this.getChildren()
347
+ .filter(isSymRootNode)
348
+ .filter((c) => !c.isDestroyed());
349
+ }
350
+ _getAdditionalProductNodes(includeDestroyed = false) {
351
+ return this.getChildren()
352
+ .filter(isProductNode)
353
+ .filter((c) => includeDestroyed || !c.isDestroyed());
354
+ }
355
+ _getAnchorableNodes() {
356
+ return this.getChildren()
357
+ .filter(isCfgAnchorableNode)
358
+ .filter((c) => !c.isDestroyed());
359
+ }
360
+ /**
361
+ * Applies and thereby shows the geometry. Finally flushes scheduled for remove.
362
+ * This function is recursively applied on additional products.
363
+ */
364
+ applyGeo(animationCoordinator) {
365
+ return __awaiter(this, void 0, void 0, function* () {
366
+ yield Promise.all(this._applyOnDescendantProductNodes((p) => (() => __awaiter(this, void 0, void 0, function* () {
367
+ p._getSymRootChildren().forEach((child) => {
368
+ child.applyGeo();
369
+ });
370
+ // Wait until materials have been loaded so that we don't get any blinking.
371
+ // It might seem wrong that this is done after we apply, but the material
372
+ // will not be ready unless it is applied. So we wait after applying.
373
+ yield p._awaitAllMeshMaterialsReady();
374
+ }))()));
375
+ // Not blocking on this
376
+ void this.flushScheduledForRemove(animationCoordinator);
377
+ });
378
+ }
379
+ /**
380
+ * Applies and thereby shows the right materials.
381
+ * This function is recursively applied on additional products.
382
+ */
383
+ applyMaterials() {
384
+ return __awaiter(this, void 0, void 0, function* () {
385
+ yield Promise.all(this._applyOnDescendantProductNodes((p) => (() => __awaiter(this, void 0, void 0, function* () {
386
+ p._getSymRootChildren().forEach((child) => {
387
+ child.applyMaterial();
388
+ });
389
+ // Wait until materials have been loaded so that we don't get any blinking.
390
+ // It might seem wrong that this is done after we apply, but the material
391
+ // will not be ready unless it is applied. So we wait after applying.
392
+ yield p._awaitAllMeshMaterialsReady();
393
+ }))()));
394
+ });
395
+ }
396
+ setAnchorTarget(anchorTarget) {
397
+ this._anchorTarget = anchorTarget;
398
+ }
399
+ refreshStretch() {
400
+ const updated = updatedStretchedAnchorPointMatrix(this.anchorRef, this._anchorTarget, this._stretchedAnchorPointMatrix);
401
+ if (updated !== undefined) {
402
+ this._stretchedAnchorPointMatrix = updated;
403
+ this.refreshTransform();
404
+ }
405
+ // anchoredToAnchors is sorted so that anchors always are before what
406
+ // is anchored to them. That way we know that if we refreshStretch on
407
+ // them first anchor-on-anchor will work correctly.
408
+ const anchorableChildren = this._getAnchorableNodes().slice();
409
+ for (const anchor of this._anchoredToAnchors.values()) {
410
+ const i = anchorableChildren.indexOf(anchor);
411
+ if (i === -1) {
412
+ // As multiple anchors can anchor to the same anchor this will happen
413
+ continue;
414
+ }
415
+ anchor.refreshStretch();
416
+ anchorableChildren.splice(i, 1);
417
+ }
418
+ // Refresh for the un-anchored
419
+ for (const child of anchorableChildren) {
420
+ child.refreshStretch();
421
+ }
422
+ }
423
+ get originalMatrix() {
424
+ var _a;
425
+ if (this._originalMatrixWithModelTransform === undefined) {
426
+ let originalMatrix = (_a = this._modelMatrix) !== null && _a !== void 0 ? _a : Matrix.Identity();
427
+ const stretchedAnchorPointMatrix = this._stretchedAnchorPointMatrix;
428
+ if (stretchedAnchorPointMatrix !== undefined) {
429
+ originalMatrix = originalMatrix.multiply(stretchedAnchorPointMatrix);
430
+ }
431
+ this._originalMatrixWithModelTransform = originalMatrix;
432
+ }
433
+ return this._originalMatrixWithModelTransform;
434
+ }
435
+ refreshTransform() {
436
+ this._originalMatrixWithModelTransform = undefined; // Reset the matrix
437
+ this.setPreTransformMatrix(this.originalMatrix);
438
+ }
439
+ _applyDebugSymRoots(symRootPromises) {
440
+ return __awaiter(this, void 0, void 0, function* () {
441
+ const allSymRoots = yield Promise.all(symRootPromises);
442
+ allSymRoots.forEach((symRoot) => {
443
+ if (symRoot === undefined) {
444
+ return;
445
+ }
446
+ this.add(symRoot);
447
+ });
448
+ yield this.applyGeo();
449
+ yield this._pushMaterialToSymRootChildrenAndLoad();
450
+ yield this.applyMaterials();
451
+ this._renderEnvironment.scheduleRerender();
452
+ });
453
+ }
454
+ _addDebugMtrlApplication(debugMtrlApplication) {
455
+ return __awaiter(this, void 0, void 0, function* () {
456
+ this._debugMtrlApplications.push(debugMtrlApplication);
457
+ yield this._aggregateMaterialsPushToChildrenAndLoad();
458
+ yield this.applyMaterials();
459
+ this._renderEnvironment.scheduleRerender();
460
+ });
461
+ }
462
+ get boundingBox() {
463
+ const bb = [...this._getSymRootChildren(), ...this._getAdditionalProductNodes()].reduce((a, m) => {
464
+ a.expand(m.boundingBox);
465
+ return a;
466
+ }, new CfgBoundingBox());
467
+ bb.applyMatrix(this.originalMatrix);
468
+ return bb;
469
+ }
470
+ addInspectorProperties() {
471
+ super.addInspectorProperties();
472
+ this.addInspectableCustomProperty({
473
+ label: "Log materialMappings",
474
+ propertyName: "_inspectorLogMaterialMappings",
475
+ type: InspectableType.Checkbox,
476
+ });
477
+ this.addInspectableCustomProperty({
478
+ label: "Add material to mapping from File",
479
+ propertyName: "_inspectorAddMaterialToMaterialMappingFromFile",
480
+ type: InspectableType.Checkbox,
481
+ });
482
+ this.addInspectableCustomProperty({
483
+ label: "Add material to mapping from Url",
484
+ propertyName: "_inspectorAddMaterialToMaterialMappingFromUrl",
485
+ type: InspectableType.Checkbox,
486
+ });
487
+ this.addInspectableCustomProperty({
488
+ label: "Add CmSym from File",
489
+ propertyName: "_inspectorAddCmSymFile",
490
+ type: InspectableType.Checkbox,
491
+ });
492
+ this.addInspectableCustomProperty({
493
+ label: "Add CmSym from Url",
494
+ propertyName: "_inspectorAddCmSymUrl",
495
+ type: InspectableType.Checkbox,
496
+ });
497
+ }
498
+ get _inspectorLogMaterialMappings() {
499
+ return this._areasToMaterials === undefined;
500
+ }
501
+ set _inspectorLogMaterialMappings(x) {
502
+ if (this._areasToMaterials === undefined) {
503
+ return;
504
+ }
505
+ logMaterialMappingToConsole(this._areasToMaterials);
506
+ }
507
+ get _inspectorAddMaterialToMaterialMappingFromFile() {
508
+ return this._areasToMaterials === undefined;
509
+ }
510
+ set _inspectorAddMaterialToMaterialMappingFromFile(x) {
511
+ if (this._areasToMaterials === undefined) {
512
+ return;
513
+ }
514
+ const tag = window.prompt("Please provide a Tag for the mapping");
515
+ if (tag === null || tag.trim().length === 0) {
516
+ alert("You must provide a tag for the mapping");
517
+ return;
518
+ }
519
+ const fileUpload = document.createElement("input");
520
+ fileUpload.type = "file";
521
+ fileUpload.style.display = "none";
522
+ const body = document.getElementsByTagName("body")[0];
523
+ body.appendChild(fileUpload);
524
+ fileUpload.addEventListener("change", (event) => {
525
+ void (() => __awaiter(this, void 0, void 0, function* () {
526
+ const files = fileUpload.files;
527
+ if (files !== null) {
528
+ const mtrlApplications = yield Promise.all(Array.from(files)
529
+ .map(readFileToArrayBuffer)
530
+ .map((bufferAndNamePromise) => __awaiter(this, void 0, void 0, function* () {
531
+ const bufferAndName = yield bufferAndNamePromise;
532
+ return CfgMtrlApplication.fromBufferForDebug([tag], bufferAndName.fileName, bufferAndName.buffer);
533
+ })));
534
+ mtrlApplications.forEach((mtrlApplication) => {
535
+ this._addDebugMtrlApplication(mtrlApplication);
536
+ });
537
+ }
538
+ body.removeChild(fileUpload);
539
+ }))();
540
+ });
541
+ fileUpload.click();
542
+ }
543
+ get _inspectorAddMaterialToMaterialMappingFromUrl() {
544
+ return this._areasToMaterials === undefined;
545
+ }
546
+ set _inspectorAddMaterialToMaterialMappingFromUrl(x) {
547
+ if (this._areasToMaterials === undefined) {
548
+ return;
549
+ }
550
+ const tag = window.prompt("Please provide a Tag for the mapping");
551
+ if (tag === null || tag.trim().length === 0) {
552
+ alert("You must provide a tag for the mapping");
553
+ return;
554
+ }
555
+ const url = window.prompt("Please provide a material-url");
556
+ if (url === null || url.trim().length === 0) {
557
+ alert("You must provide an URL to a material-file");
558
+ return;
559
+ }
560
+ const mtrlApplication = CfgMtrlApplication.fromUrlForDebug([tag], url);
561
+ this._addDebugMtrlApplication(mtrlApplication);
562
+ }
563
+ get _inspectorAddCmSymFile() {
564
+ return false;
565
+ }
566
+ set _inspectorAddCmSymFile(x) {
567
+ const fileUpload = document.createElement("input");
568
+ fileUpload.type = "file";
569
+ fileUpload.style.display = "none";
570
+ const body = document.getElementsByTagName("body")[0];
571
+ body.appendChild(fileUpload);
572
+ const logger = this.logger;
573
+ const renderEnvironment = this._renderEnvironment;
574
+ fileUpload.addEventListener("change", (event) => {
575
+ const files = fileUpload.files;
576
+ if (files !== null) {
577
+ const symRootPromises = Array.from(files).map((file) => {
578
+ return CfgSymRootNode.makeCfgSymRootFromFile(logger, true, renderEnvironment, this, file);
579
+ });
580
+ this._applyDebugSymRoots(symRootPromises);
581
+ }
582
+ body.removeChild(fileUpload);
583
+ });
584
+ fileUpload.click();
585
+ }
586
+ get _inspectorAddCmSymUrl() {
587
+ return false;
588
+ }
589
+ set _inspectorAddCmSymUrl(x) {
590
+ const url = window.prompt("Please provide a CmSym-url");
591
+ if (url === null || url.trim().length === 0) {
592
+ alert("You must provide an URL to a CmSym-file");
593
+ return;
594
+ }
595
+ const symRootNode = CfgSymRootNode.makeCfgSymRootFromUrl(this.logger, true, this._renderEnvironment, this, url, undefined, undefined);
596
+ this._applyDebugSymRoots([symRootNode]);
597
+ }
598
+ }