@combeenation/3d-viewer 8.0.0 → 8.1.0-alpha1
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/dist/lib-cjs/api/classes/parameter.d.ts +27 -0
- package/dist/lib-cjs/api/classes/parameter.js +27 -0
- package/dist/lib-cjs/api/classes/parameter.js.map +1 -1
- package/dist/lib-cjs/api/classes/variant.d.ts +8 -0
- package/dist/lib-cjs/api/classes/variant.js +12 -0
- package/dist/lib-cjs/api/classes/variant.js.map +1 -1
- package/dist/lib-cjs/api/classes/viewer.d.ts +2 -2
- package/dist/lib-cjs/api/classes/viewer.js +9 -8
- package/dist/lib-cjs/api/classes/viewer.js.map +1 -1
- package/dist/lib-cjs/api/manager/gltfExportManager.d.ts +1 -0
- package/dist/lib-cjs/api/manager/gltfExportManager.js +7 -2
- package/dist/lib-cjs/api/manager/gltfExportManager.js.map +1 -1
- package/dist/lib-cjs/api/manager/tagManager.d.ts +25 -23
- package/dist/lib-cjs/api/manager/tagManager.js +153 -89
- package/dist/lib-cjs/api/manager/tagManager.js.map +1 -1
- package/dist/lib-cjs/api/manager/variantInstanceManager.d.ts +1 -1
- package/dist/lib-cjs/api/manager/variantInstanceManager.js +5 -7
- package/dist/lib-cjs/api/manager/variantInstanceManager.js.map +1 -1
- package/dist/lib-cjs/api/util/globalTypes.d.ts +16 -4
- package/dist/lib-cjs/api/util/structureHelper.d.ts +6 -6
- package/dist/lib-cjs/api/util/structureHelper.js +31 -28
- package/dist/lib-cjs/api/util/structureHelper.js.map +1 -1
- package/dist/lib-cjs/buildinfo.json +1 -1
- package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/api/classes/parameter.ts +30 -0
- package/src/api/classes/variant.ts +14 -0
- package/src/api/classes/viewer.ts +12 -14
- package/src/api/manager/gltfExportManager.ts +8 -3
- package/src/api/manager/tagManager.ts +178 -119
- package/src/api/manager/variantInstanceManager.ts +5 -8
- package/src/api/util/globalTypes.ts +20 -4
- package/src/api/util/structureHelper.ts +29 -27
|
@@ -2,20 +2,10 @@ import { Event, emitter } from '../classes/event';
|
|
|
2
2
|
import { FuzzyMap } from '../classes/fuzzyMap';
|
|
3
3
|
import { Parameter } from '../classes/parameter';
|
|
4
4
|
import { Viewer } from '../classes/viewer';
|
|
5
|
-
import {
|
|
6
|
-
assertMeshCapability,
|
|
7
|
-
cloneTransformNodeMaterial,
|
|
8
|
-
injectNodeMetadata,
|
|
9
|
-
mapTags,
|
|
10
|
-
setMaterial,
|
|
11
|
-
setMaterialColor,
|
|
12
|
-
setMaterialMetallness,
|
|
13
|
-
setMaterialRoughness,
|
|
14
|
-
} from '../util/babylonHelper';
|
|
15
|
-
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
|
|
5
|
+
import { assertMeshCapability, mapTags, setMaterial } from '../util/babylonHelper';
|
|
16
6
|
import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
17
7
|
import { Tags } from '@babylonjs/core/Misc/tags';
|
|
18
|
-
import { clone, get,
|
|
8
|
+
import { clone, get, merge, uniq } from 'lodash-es';
|
|
19
9
|
|
|
20
10
|
export class TagManager {
|
|
21
11
|
public readonly parameters: TagManagerParameterBag = new FuzzyMap();
|
|
@@ -37,7 +27,7 @@ export class TagManager {
|
|
|
37
27
|
tagName: string,
|
|
38
28
|
parameterName: string,
|
|
39
29
|
value: ParameterValue
|
|
40
|
-
): Promise<
|
|
30
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
41
31
|
return await this.handleParameter({ tagName: tagName }, parameterName, value);
|
|
42
32
|
}
|
|
43
33
|
|
|
@@ -49,22 +39,35 @@ export class TagManager {
|
|
|
49
39
|
nodeName: string,
|
|
50
40
|
parameterName: string,
|
|
51
41
|
value: ParameterValue
|
|
52
|
-
): Promise<
|
|
42
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
53
43
|
return await this.handleParameter({ nodeName: nodeName }, parameterName, value);
|
|
54
44
|
}
|
|
55
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Calls the {@link ParameterObserver} for given {@link Parameter} and applies the {@link ParameterValue} on all
|
|
48
|
+
* materials with given materialName.
|
|
49
|
+
*/
|
|
50
|
+
public async setMaterialParameterValue(
|
|
51
|
+
materialName: string,
|
|
52
|
+
parameterName: string,
|
|
53
|
+
value: ParameterValue
|
|
54
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
55
|
+
return await this.handleParameter({ materialName: materialName }, parameterName, value);
|
|
56
|
+
}
|
|
57
|
+
|
|
56
58
|
/**
|
|
57
59
|
* Splits the passed {@link TagManagerParameterValue}s into individual values and calls all {@link ParameterObserver}s
|
|
58
60
|
* of all {@link Parameter}s with the respective {@link TagManagerSubject} and {@link ParameterValue}. The result is a
|
|
59
|
-
* map of passed {@link TagManagerParameterValue}s and the associated {@link
|
|
61
|
+
* map of passed {@link TagManagerParameterValue}s and the associated {@link TagManagerParameterObserverResult} of the
|
|
60
62
|
* {@link ParameterObserver}.
|
|
61
63
|
*/
|
|
62
64
|
public async setParameterValues(
|
|
63
65
|
values: TagManagerParameterValue[]
|
|
64
|
-
): Promise<Map<TagManagerParameterValue,
|
|
65
|
-
const observerResultMap: Map<TagManagerParameterValue,
|
|
66
|
-
const tagPromises: Promise<
|
|
67
|
-
const nodePromises: Promise<
|
|
66
|
+
): Promise<Map<TagManagerParameterValue, TagManagerParameterObserverResultBag>> {
|
|
67
|
+
const observerResultMap: Map<TagManagerParameterValue, TagManagerParameterObserverResultBag> = new Map();
|
|
68
|
+
const tagPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
69
|
+
const nodePromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
70
|
+
const materialPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
68
71
|
for (const value of values) {
|
|
69
72
|
const subject: TagManagerSubject = {};
|
|
70
73
|
if (value.tagName) {
|
|
@@ -73,6 +76,9 @@ export class TagManager {
|
|
|
73
76
|
if (value.nodeName) {
|
|
74
77
|
subject.nodeName = value.nodeName;
|
|
75
78
|
}
|
|
79
|
+
if (value.materialName) {
|
|
80
|
+
subject.materialName = value.materialName;
|
|
81
|
+
}
|
|
76
82
|
const observerResultPromise = this.handleParameter(subject, value.parameterName, value.value);
|
|
77
83
|
observerResultPromise.then(result => observerResultMap.set(value, result));
|
|
78
84
|
if (value.tagName) {
|
|
@@ -81,32 +87,37 @@ export class TagManager {
|
|
|
81
87
|
if (value.nodeName) {
|
|
82
88
|
nodePromises.push(observerResultPromise);
|
|
83
89
|
}
|
|
90
|
+
if (value.materialName) {
|
|
91
|
+
materialPromises.push(observerResultPromise);
|
|
92
|
+
}
|
|
84
93
|
}
|
|
85
94
|
await Promise.all(tagPromises);
|
|
86
95
|
await Promise.all(nodePromises);
|
|
96
|
+
await Promise.all(materialPromises);
|
|
87
97
|
return observerResultMap;
|
|
88
98
|
}
|
|
89
99
|
|
|
90
100
|
/**
|
|
91
101
|
* Gets a list of {@link TagManagerSubject}s that are present in both the state of the {@link TagManager}'s
|
|
92
|
-
* {@link parameters} and the given
|
|
102
|
+
* {@link parameters} and the given object.
|
|
93
103
|
*/
|
|
94
|
-
public getSubjectsFor(
|
|
104
|
+
public getSubjectsFor(object: TransformNode | Material): TagManagerSubject[] {
|
|
95
105
|
return [...this.parameters.keys()].filter(
|
|
96
106
|
subject =>
|
|
97
|
-
(subject.tagName && Tags.MatchesQuery(
|
|
98
|
-
(subject.nodeName &&
|
|
107
|
+
(subject.tagName && Tags.MatchesQuery(object, subject.tagName)) ||
|
|
108
|
+
(subject.nodeName && object.name === subject.nodeName) ||
|
|
109
|
+
(subject.materialName && object.name === subject.materialName)
|
|
99
110
|
);
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
/**
|
|
103
114
|
* Gets a list of {@link TagManagerSubject}s that are present in both the state of the {@link TagManager}'s
|
|
104
|
-
* {@link parameters} and the given
|
|
115
|
+
* {@link parameters} and the given objects.
|
|
105
116
|
*/
|
|
106
|
-
public getApplicableSubjectsFor(
|
|
117
|
+
public getApplicableSubjectsFor(objects: (TransformNode | Material)[]): TagManagerSubject[] {
|
|
107
118
|
let applicableSubjects: TagManagerSubject[] = [];
|
|
108
|
-
for (const
|
|
109
|
-
const subjects = this.getSubjectsFor(
|
|
119
|
+
for (const object of objects) {
|
|
120
|
+
const subjects = this.getSubjectsFor(object);
|
|
110
121
|
applicableSubjects = [...applicableSubjects, ...subjects];
|
|
111
122
|
}
|
|
112
123
|
return uniq(applicableSubjects);
|
|
@@ -117,12 +128,12 @@ export class TagManager {
|
|
|
117
128
|
*/
|
|
118
129
|
public async applyExistingParameterValuesFor(
|
|
119
130
|
subjects: TagManagerSubject[]
|
|
120
|
-
): Promise<Map<TagManagerSubject,
|
|
121
|
-
const observerResultMap: Map<TagManagerSubject,
|
|
122
|
-
let tagPromises: Promise<
|
|
123
|
-
let nodePromises: Promise<
|
|
131
|
+
): Promise<Map<TagManagerSubject, TagManagerParameterObserverResultBag>> {
|
|
132
|
+
const observerResultMap: Map<TagManagerSubject, TagManagerParameterObserverResultBag> = new Map();
|
|
133
|
+
let tagPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
134
|
+
let nodePromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
135
|
+
let materialPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
124
136
|
for (const subject of subjects) {
|
|
125
|
-
this.clearAppliedNodeMetadataParameters(this.getNodesBySubject(subject));
|
|
126
137
|
const observerResultPromises = this.handleParameterBag(subject, this.parameters.get(subject)!);
|
|
127
138
|
for (const observerResultPromise of observerResultPromises) {
|
|
128
139
|
observerResultPromise.then(result => observerResultMap.set(subject, result));
|
|
@@ -133,9 +144,13 @@ export class TagManager {
|
|
|
133
144
|
if (subject.nodeName) {
|
|
134
145
|
nodePromises = [...nodePromises, ...observerResultPromises];
|
|
135
146
|
}
|
|
147
|
+
if (subject.materialName) {
|
|
148
|
+
materialPromises = [...materialPromises, ...observerResultPromises];
|
|
149
|
+
}
|
|
136
150
|
}
|
|
137
151
|
await Promise.all(tagPromises);
|
|
138
152
|
await Promise.all(nodePromises);
|
|
153
|
+
await Promise.all(materialPromises);
|
|
139
154
|
return observerResultMap;
|
|
140
155
|
}
|
|
141
156
|
|
|
@@ -144,15 +159,15 @@ export class TagManager {
|
|
|
144
159
|
* {@link TagManager}'s {@link parameters} are applied to all given nodes.
|
|
145
160
|
*/
|
|
146
161
|
public async applyExistingParameterValuesTo(
|
|
147
|
-
|
|
148
|
-
): Promise<Map<TagManagerSubject,
|
|
149
|
-
return this.applyExistingParameterValuesFor(this.getApplicableSubjectsFor(
|
|
162
|
+
objects: (TransformNode | Material)[]
|
|
163
|
+
): Promise<Map<TagManagerSubject, TagManagerParameterObserverResultBag>> {
|
|
164
|
+
return this.applyExistingParameterValuesFor(this.getApplicableSubjectsFor(objects));
|
|
150
165
|
}
|
|
151
166
|
|
|
152
167
|
/**
|
|
153
168
|
* Applies all existing states of the {@link TagManager}'s {@link parameters} for all {@link TagManagerSubject}s.
|
|
154
169
|
*/
|
|
155
|
-
public async applyExistingParameterValues(): Promise<Map<TagManagerSubject,
|
|
170
|
+
public async applyExistingParameterValues(): Promise<Map<TagManagerSubject, TagManagerParameterObserverResultBag>> {
|
|
156
171
|
return this.applyExistingParameterValuesFor([...this.parameters.keys()]);
|
|
157
172
|
}
|
|
158
173
|
|
|
@@ -248,18 +263,46 @@ export class TagManager {
|
|
|
248
263
|
}
|
|
249
264
|
|
|
250
265
|
/**
|
|
251
|
-
*
|
|
252
|
-
|
|
266
|
+
* Gets all materials for given {@link TagManagerSubject} on the Babylon.js scene.
|
|
267
|
+
*/
|
|
268
|
+
public getMaterialsBySubject(subject: TagManagerSubject, predicate?: (material: Material) => boolean): Material[] {
|
|
269
|
+
let materials: Material[] = [];
|
|
270
|
+
if (subject.tagName) {
|
|
271
|
+
materials = [...materials, ...this.viewer.scene.getMaterialByTags(subject.tagName, predicate)];
|
|
272
|
+
}
|
|
273
|
+
if (subject.materialName) {
|
|
274
|
+
materials = [...materials, this.viewer.scene.getMaterialByName(subject.materialName)].filter(
|
|
275
|
+
t => !!t && (!predicate || predicate(t))
|
|
276
|
+
) as Material[];
|
|
277
|
+
}
|
|
278
|
+
return materials;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Registers observers that are called on every new object added to the Babylon.js scene.
|
|
283
|
+
* The observers ensure that each new object gets the state of the {@link TagManager}'s {@link parameters} applied.
|
|
253
284
|
*/
|
|
254
|
-
public
|
|
285
|
+
public registerNewObjectObservers(scene: Scene) {
|
|
286
|
+
// nodes and meshes
|
|
255
287
|
const onNewTransformNodeAdded = (node: TransformNode) => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
288
|
+
/* NOTE:
|
|
289
|
+
Removed the check for created instances here since it is not guaranteed that all instances
|
|
290
|
+
created means that there is no scenario where new nodes should get TagManager parameters applied.
|
|
291
|
+
Instead, we check for the state to be enabled via the `onEnabledStateChangedObservable` below.
|
|
292
|
+
*/
|
|
293
|
+
//if (node.name === Viewer.BOUNDING_BOX_NAME || !this.viewer.variantInstances.areAllDefinitionsCreated) {
|
|
294
|
+
if (node.name === Viewer.BOUNDING_BOX_NAME) {
|
|
260
295
|
return;
|
|
261
296
|
}
|
|
262
|
-
|
|
297
|
+
const onEnabledStateChangedObserver = node.onEnabledStateChangedObservable.add(async state => {
|
|
298
|
+
if (!state) {
|
|
299
|
+
// if the node is disabled, means ignoring also "ghost nodes"
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
await this.applyExistingParameterValuesTo([node]);
|
|
303
|
+
node.onEnabledStateChangedObservable.remove(onEnabledStateChangedObserver);
|
|
304
|
+
});
|
|
305
|
+
node.onEnabledStateChangedObservable.makeObserverBottomPriority(onEnabledStateChangedObserver!);
|
|
263
306
|
};
|
|
264
307
|
scene.onNewTransformNodeAddedObservable.makeObserverBottomPriority(
|
|
265
308
|
scene.onNewTransformNodeAddedObservable.add(onNewTransformNodeAdded)!
|
|
@@ -267,6 +310,21 @@ export class TagManager {
|
|
|
267
310
|
scene.onNewMeshAddedObservable.makeObserverBottomPriority(
|
|
268
311
|
scene.onNewMeshAddedObservable.add(onNewTransformNodeAdded)!
|
|
269
312
|
);
|
|
313
|
+
// materials
|
|
314
|
+
const onNewMaterialAdded = (material: Material) => {
|
|
315
|
+
/* NOTE:
|
|
316
|
+
We have to wait until a material is bound to a Mesh. In all other scenarios, the material
|
|
317
|
+
is not "fully ready" or even empty (without working attributes/properties).
|
|
318
|
+
*/
|
|
319
|
+
const onMaterialBindObserver = material.onBindObservable.add(async abstractMesh => {
|
|
320
|
+
await this.applyExistingParameterValuesTo([material]);
|
|
321
|
+
material.onBindObservable.remove(onMaterialBindObserver);
|
|
322
|
+
});
|
|
323
|
+
material.onBindObservable.makeObserverBottomPriority(onMaterialBindObserver!);
|
|
324
|
+
};
|
|
325
|
+
scene.onNewMaterialAddedObservable.makeObserverBottomPriority(
|
|
326
|
+
scene.onNewMaterialAddedObservable.add(onNewMaterialAdded)!
|
|
327
|
+
);
|
|
270
328
|
}
|
|
271
329
|
|
|
272
330
|
/**
|
|
@@ -317,54 +375,51 @@ export class TagManager {
|
|
|
317
375
|
}
|
|
318
376
|
return true;
|
|
319
377
|
});
|
|
320
|
-
this.parameterObservers.set(Parameter.
|
|
321
|
-
const
|
|
322
|
-
for (const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
378
|
+
this.parameterObservers.set(Parameter.COLOR, async payload => {
|
|
379
|
+
const color = Parameter.parseColor(payload.newValue);
|
|
380
|
+
for (const material of payload.materials) {
|
|
381
|
+
const materialCls = material.getClassName();
|
|
382
|
+
switch (materialCls) {
|
|
383
|
+
case 'PBRMaterial':
|
|
384
|
+
(material as PBRMaterial).albedoColor = color.toLinearSpace();
|
|
385
|
+
break;
|
|
386
|
+
case 'StandardMaterial':
|
|
387
|
+
(material as StandardMaterial).diffuseColor = color;
|
|
388
|
+
break;
|
|
389
|
+
default:
|
|
390
|
+
throw new Error(`Setting color for material of instance "${materialCls}" not implemented (yet).`);
|
|
332
391
|
}
|
|
333
|
-
setMaterialColor(node, parsedValue, false);
|
|
334
392
|
}
|
|
335
393
|
return true;
|
|
336
394
|
});
|
|
337
|
-
this.parameterObservers.set(Parameter.
|
|
338
|
-
const
|
|
339
|
-
for (const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
395
|
+
this.parameterObservers.set(Parameter.ROUGHNESS, async payload => {
|
|
396
|
+
const roughness = Parameter.parseNumber(payload.newValue);
|
|
397
|
+
for (const material of payload.materials) {
|
|
398
|
+
const materialCls = material.getClassName();
|
|
399
|
+
switch (materialCls) {
|
|
400
|
+
case 'PBRMaterial':
|
|
401
|
+
(material as PBRMaterial).roughness = roughness;
|
|
402
|
+
break;
|
|
403
|
+
case 'StandardMaterial':
|
|
404
|
+
(material as StandardMaterial).roughness = roughness;
|
|
405
|
+
break;
|
|
406
|
+
default:
|
|
407
|
+
throw new Error(`Setting roughness for material of instance "${materialCls}" not implemented (yet).`);
|
|
349
408
|
}
|
|
350
|
-
setMaterialRoughness(node, parsedValue, false);
|
|
351
409
|
}
|
|
352
410
|
return true;
|
|
353
411
|
});
|
|
354
|
-
this.parameterObservers.set(Parameter.
|
|
355
|
-
const
|
|
356
|
-
for (const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
injectNodeMetadata(node, { dirty: { material: { color: payload.oldValue } } }, false);
|
|
365
|
-
}
|
|
412
|
+
this.parameterObservers.set(Parameter.METALLNESS, async payload => {
|
|
413
|
+
const metallness = Parameter.parseNumber(payload.newValue);
|
|
414
|
+
for (const material of payload.materials) {
|
|
415
|
+
const materialCls = material.getClassName();
|
|
416
|
+
switch (materialCls) {
|
|
417
|
+
case 'PBRMaterial':
|
|
418
|
+
(material as PBRMaterial).metallic = metallness;
|
|
419
|
+
break;
|
|
420
|
+
default:
|
|
421
|
+
throw new Error(`Setting metallness for material of instance "${materialCls}" not implemented (yet).`);
|
|
366
422
|
}
|
|
367
|
-
setMaterialMetallness(node, parsedValue, false);
|
|
368
423
|
}
|
|
369
424
|
return true;
|
|
370
425
|
});
|
|
@@ -379,8 +434,8 @@ export class TagManager {
|
|
|
379
434
|
protected handleParameterBag(
|
|
380
435
|
subject: TagManagerSubject,
|
|
381
436
|
parameters: ParameterBag
|
|
382
|
-
): Promise<
|
|
383
|
-
const observerPromises: Promise<
|
|
437
|
+
): Promise<TagManagerParameterObserverResultBag>[] {
|
|
438
|
+
const observerPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
384
439
|
for (const parameter in parameters) {
|
|
385
440
|
observerPromises.push(this.handleParameter(subject, parameter, parameters[parameter]));
|
|
386
441
|
}
|
|
@@ -397,36 +452,58 @@ export class TagManager {
|
|
|
397
452
|
subject: TagManagerSubject,
|
|
398
453
|
parameter: string,
|
|
399
454
|
parameterValue: ParameterValue
|
|
400
|
-
): Promise<
|
|
455
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
401
456
|
Parameter.assertParameter(Parameter.declarations, parameter, parameterValue);
|
|
402
|
-
if (!this.parameterObservers.has(parameter)) {
|
|
403
|
-
return Promise.resolve(false);
|
|
404
|
-
}
|
|
405
457
|
const parameterBag = this.parameters.get(subject) || {};
|
|
406
458
|
const oldValue = parameterBag[parameter];
|
|
459
|
+
const parameterObserverResultBag: TagManagerParameterObserverResultBag = {
|
|
460
|
+
subject: subject,
|
|
461
|
+
parameter: parameter,
|
|
462
|
+
nodes: [],
|
|
463
|
+
materials: [],
|
|
464
|
+
oldValue: oldValue,
|
|
465
|
+
newValue: parameterValue,
|
|
466
|
+
parameterObserverResult: false,
|
|
467
|
+
};
|
|
468
|
+
if (!this.parameterObservers.has(parameter)) {
|
|
469
|
+
return Promise.resolve(parameterObserverResultBag);
|
|
470
|
+
}
|
|
407
471
|
if (oldValue === parameterValue) {
|
|
408
|
-
|
|
472
|
+
/* NOTE:
|
|
473
|
+
The following is wrong in different scenarios. If a node enters life and the subject/parameter
|
|
474
|
+
applied in the past, the new node will not be altered by the subsequent observers, because of
|
|
475
|
+
the return on the next line. If we want to tackle that problem and do an early return to not
|
|
476
|
+
trigger observers twice, we have to hold a state for every node/material and the applied
|
|
477
|
+
parameter value. This could be highly cost sensitive, so I would just avoid that check
|
|
478
|
+
at all. Babylon will not trigger changes if the value on a node/material does not change
|
|
479
|
+
anyway.
|
|
480
|
+
*/
|
|
481
|
+
//return Promise.resolve(parameterObserverResultBag);
|
|
409
482
|
}
|
|
410
483
|
this.parameters.set(subject, parameterBag);
|
|
411
484
|
this.parameters.get(subject)![parameter] = parameterValue;
|
|
412
485
|
const nodes = this.getNodesBySubject(subject);
|
|
413
|
-
|
|
414
|
-
|
|
486
|
+
const materials = this.getMaterialsBySubject(subject);
|
|
487
|
+
if (nodes.length === 0 && materials.length === 0) {
|
|
488
|
+
return Promise.resolve(parameterObserverResultBag);
|
|
415
489
|
}
|
|
416
490
|
const observer = this.parameterObservers.get(parameter)!;
|
|
417
|
-
const result = await observer({
|
|
418
|
-
if (result === false) {
|
|
419
|
-
// reset to old value if observer was not successful
|
|
420
|
-
this.parameters.get(subject)![parameter] = oldValue;
|
|
421
|
-
}
|
|
422
|
-
emitter.emit(Event.TAG_MANAGER_PARAMETER_COMMITTED, {
|
|
491
|
+
const result = await observer({
|
|
423
492
|
subject: subject,
|
|
424
|
-
parameter: parameter,
|
|
425
493
|
nodes: nodes,
|
|
426
|
-
|
|
494
|
+
materials: materials,
|
|
427
495
|
newValue: parameterValue,
|
|
428
|
-
|
|
496
|
+
oldValue: oldValue,
|
|
429
497
|
});
|
|
498
|
+
if (result === false) {
|
|
499
|
+
// reset to old value if observer was not successful
|
|
500
|
+
this.parameters.get(subject)![parameter] = oldValue;
|
|
501
|
+
}
|
|
502
|
+
parameterObserverResultBag.nodes = nodes;
|
|
503
|
+
parameterObserverResultBag.materials = materials;
|
|
504
|
+
parameterObserverResultBag.parameterObserverResult = result;
|
|
505
|
+
emitter.emit(Event.TAG_MANAGER_PARAMETER_COMMITTED, parameterObserverResultBag);
|
|
506
|
+
return parameterObserverResultBag;
|
|
430
507
|
}
|
|
431
508
|
|
|
432
509
|
/**
|
|
@@ -441,17 +518,14 @@ export class TagManager {
|
|
|
441
518
|
if (oldNode) {
|
|
442
519
|
accNodeMapping[oldNode.name] = curNode.name;
|
|
443
520
|
}
|
|
444
|
-
|
|
445
521
|
return accNodeMapping;
|
|
446
522
|
}, {} as TagMapping);
|
|
447
|
-
|
|
448
523
|
for (const subject of this.parameters.keys()) {
|
|
449
524
|
const isNode = subject.nodeName;
|
|
450
525
|
const newName = isNode ? nodeMapping[subject.nodeName] : tagMapping[subject.tagName];
|
|
451
526
|
if (!newName) {
|
|
452
527
|
continue;
|
|
453
528
|
}
|
|
454
|
-
|
|
455
529
|
const newSubject = clone(subject);
|
|
456
530
|
newSubject[isNode ? 'nodeName' : 'tagName'] = newName;
|
|
457
531
|
const parameterBag = clone(this.parameters.get(subject)!);
|
|
@@ -459,19 +533,4 @@ export class TagManager {
|
|
|
459
533
|
this.parameters.set(newSubject, parameterBag);
|
|
460
534
|
}
|
|
461
535
|
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Clears the applied {@link ParameterBag} state of the node's metadata to ensure that observers trigger (once again).
|
|
465
|
-
* This is necessary e.g. after mapping tags when a nodeName subject shall override the parameterValue of a mapped
|
|
466
|
-
* tag.
|
|
467
|
-
* @protected
|
|
468
|
-
*/
|
|
469
|
-
protected clearAppliedNodeMetadataParameters(nodes: TransformNode[]): void {
|
|
470
|
-
for (const node of nodes) {
|
|
471
|
-
if (!node.metadata?.tagManager?.parameters) {
|
|
472
|
-
continue;
|
|
473
|
-
}
|
|
474
|
-
node.metadata.tagManager.parameters = {};
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
536
|
}
|
|
@@ -120,15 +120,13 @@ export class VariantInstanceManager extends EventBroadcaster {
|
|
|
120
120
|
public async create(
|
|
121
121
|
dottedPath: DottedPathArgument,
|
|
122
122
|
name?: string,
|
|
123
|
-
parameters?: ParameterBag
|
|
124
|
-
tagManagerParameterValues?: TagManagerParameterValue[]
|
|
123
|
+
parameters?: ParameterBag
|
|
125
124
|
): Promise<VariantInstance> {
|
|
126
125
|
const variant = DottedPath.create(dottedPath).path;
|
|
127
126
|
const definition = {
|
|
128
127
|
name: this.ensureUniqueName(name ? name : variant),
|
|
129
128
|
variant: variant,
|
|
130
129
|
parameters: parameters,
|
|
131
|
-
tagManagerParameterValues: tagManagerParameterValues,
|
|
132
130
|
};
|
|
133
131
|
return await this.createFromDefinition(definition);
|
|
134
132
|
}
|
|
@@ -246,7 +244,10 @@ export class VariantInstanceManager extends EventBroadcaster {
|
|
|
246
244
|
this.variantInstances.set(definition.name, variantInstanceClone);
|
|
247
245
|
reportDuplicateNodeNames(duplicateNodeNames(this.viewer.scene.getNodes(), n => n instanceof TransformNode));
|
|
248
246
|
this.viewer.tagManager.mapNodesAndTags(variantInstanceClone.variant.elementNodesFlat, tagMapping ?? {});
|
|
249
|
-
await this.viewer.tagManager.applyExistingParameterValuesTo(
|
|
247
|
+
await this.viewer.tagManager.applyExistingParameterValuesTo([
|
|
248
|
+
...variantInstanceClone.variant.elementNodesFlat,
|
|
249
|
+
...variantInstanceClone.variant.elementAbstractMeshesFlat.map(n => n.material!).filter(m => !!m),
|
|
250
|
+
]);
|
|
250
251
|
variantInstance.broadcastEvent(Event.VARIANT_INSTANCE_CLONED, variantInstanceClone);
|
|
251
252
|
return variantInstanceClone;
|
|
252
253
|
}
|
|
@@ -285,10 +286,6 @@ export class VariantInstanceManager extends EventBroadcaster {
|
|
|
285
286
|
const variant = await this.rootVariant.getDescendant(definition.variant);
|
|
286
287
|
const variantInstance = await VariantInstance.createLiving(variant, definition.name, definition.parameters);
|
|
287
288
|
this.variantInstances.set(definition.name, variantInstance);
|
|
288
|
-
// set tag manager parameter values if all definitions has been created.
|
|
289
|
-
if (definition.tagManagerParameterValues && this.areAllDefinitionsCreated) {
|
|
290
|
-
await this.viewer.tagManager.setParameterValues(definition.tagManagerParameterValues);
|
|
291
|
-
}
|
|
292
289
|
this.broadcastEvent(Event.VARIANT_INSTANCE_CREATED, variantInstance);
|
|
293
290
|
return variantInstance;
|
|
294
291
|
}
|
|
@@ -280,7 +280,7 @@ type ScreenshotSettings = {
|
|
|
280
280
|
/**
|
|
281
281
|
* Use this to define geometry to be excluded from autofocus, GLB export, etc.
|
|
282
282
|
*/
|
|
283
|
-
type ExcludedGeometry =
|
|
283
|
+
type ExcludedGeometry = TransformNode | VariantInstance | Variant | VariantElement | TagManagerSubject;
|
|
284
284
|
type ExcludedGeometryList = ExcludedGeometry[];
|
|
285
285
|
|
|
286
286
|
type AutofocusSettings = {
|
|
@@ -370,7 +370,6 @@ type VariantInstanceDefinition = {
|
|
|
370
370
|
name?: string;
|
|
371
371
|
variant: DottedPathArgument;
|
|
372
372
|
parameters?: ParameterBag;
|
|
373
|
-
tagManagerParameterValues?: TagManagerParameterValue[];
|
|
374
373
|
lazy?: boolean;
|
|
375
374
|
};
|
|
376
375
|
|
|
@@ -403,7 +402,7 @@ type DottedPathArgument = string | string[] | DottedPath;
|
|
|
403
402
|
type ParameterObserverResult = boolean | void;
|
|
404
403
|
|
|
405
404
|
type ParameterObserver = (
|
|
406
|
-
|
|
405
|
+
object: any,
|
|
407
406
|
oldValue: Undefinable<ParameterValue>,
|
|
408
407
|
newValue: ParameterValue
|
|
409
408
|
) => Promise<ParameterObserverResult>;
|
|
@@ -487,13 +486,18 @@ type TagMapping = {
|
|
|
487
486
|
type TagManagerSubject = {
|
|
488
487
|
tagName?: string;
|
|
489
488
|
nodeName?: string;
|
|
489
|
+
materialName?: string;
|
|
490
490
|
};
|
|
491
491
|
|
|
492
|
+
type TagManagerParameterObserverResult = ParameterObserverResult;
|
|
493
|
+
|
|
492
494
|
/**
|
|
493
495
|
* The observer should return `false` in cases where the given value was not actually applied. E.g. when wanting to
|
|
494
496
|
* apply a property on the given `node`s material which doesn't exist at the time the observer is called etc.
|
|
495
497
|
*/
|
|
496
|
-
type TagManagerParameterObserver = (
|
|
498
|
+
type TagManagerParameterObserver = (
|
|
499
|
+
payload: TagManagerParameterObserverPayload
|
|
500
|
+
) => Promise<TagManagerParameterObserverResult>;
|
|
497
501
|
|
|
498
502
|
type TagManagerParameterBag = FuzzyMap<TagManagerSubject, ParameterBag>;
|
|
499
503
|
|
|
@@ -502,6 +506,7 @@ type TagManagerParameterObserverBag = Map<string, TagManagerParameterObserver>;
|
|
|
502
506
|
type TagManagerParameterObserverPayload = {
|
|
503
507
|
subject: TagManagerSubject;
|
|
504
508
|
nodes: TransformNode[];
|
|
509
|
+
materials: Material[];
|
|
505
510
|
newValue: ParameterValue;
|
|
506
511
|
oldValue: Undefinable<ParameterValue>;
|
|
507
512
|
};
|
|
@@ -509,10 +514,21 @@ type TagManagerParameterObserverPayload = {
|
|
|
509
514
|
type TagManagerParameterValue = {
|
|
510
515
|
tagName?: string;
|
|
511
516
|
nodeName?: string;
|
|
517
|
+
materialName?: string;
|
|
512
518
|
parameterName: string;
|
|
513
519
|
value: ParameterValue;
|
|
514
520
|
};
|
|
515
521
|
|
|
522
|
+
type TagManagerParameterObserverResultBag = {
|
|
523
|
+
subject: TagManagerSubject;
|
|
524
|
+
parameter: string;
|
|
525
|
+
nodes: TransformNode[];
|
|
526
|
+
materials: Material[];
|
|
527
|
+
oldValue: ParameterValue;
|
|
528
|
+
newValue: ParameterValue;
|
|
529
|
+
parameterObserverResult: TagManagerParameterObserverResult;
|
|
530
|
+
};
|
|
531
|
+
|
|
516
532
|
type NodeNamingStrategyPayload = {
|
|
517
533
|
variantInstance: VariantInstance;
|
|
518
534
|
variant: Variant;
|