@colijnit/configuratorcore 262.1.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.
|
@@ -0,0 +1,2941 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { Group, BufferGeometry, Float32BufferAttribute, Line, LineBasicMaterial, Vector3, CylinderGeometry, Mesh, MeshBasicMaterial, Object3D, EquirectangularReflectionMapping, Vector2, Material as Material$1, Texture, Source, Camera, Box3, LinearSRGBColorSpace, SRGBColorSpace, Color, MaterialLoader, MeshPhongMaterial, NearestFilter, DoubleSide, MeshPhysicalMaterial, MeshStandardMaterial, Euler, Quaternion } from 'three';
|
|
3
|
+
import { Subject, BehaviorSubject } from 'rxjs';
|
|
4
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
5
|
+
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
6
|
+
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
|
|
7
|
+
import { BusinessObjectFactory } from '@colijnit/ioneconnector/build/service/business-object-factory.js';
|
|
8
|
+
import { DecoNodeType } from '@colijnit/configuratorapi/build/enum/deco-node-type.enum.js';
|
|
9
|
+
import JSZip from 'jszip';
|
|
10
|
+
import axios from 'axios';
|
|
11
|
+
import { DecoNode } from '@colijnit/configuratorapi/build/model/deco-node.js';
|
|
12
|
+
import { Answer } from '@colijnit/configuratorapi/build/model/answer.js';
|
|
13
|
+
import { SelectorStructure } from '@colijnit/configuratorapi/build/model/selector-structure.bo.js';
|
|
14
|
+
import { NodeType } from '@colijnit/configuratorapi/build/enum/node-type.enum.js';
|
|
15
|
+
import { DecoNodeKind } from '@colijnit/configuratorapi/build/enum/deco-node-kind.enum.js';
|
|
16
|
+
import { Selection } from '@colijnit/configuratorapi/build/model/selection.js';
|
|
17
|
+
import { HdecoPositioning } from '@colijnit/configuratorapi/build/enum/hdeco-positioning.enum.js';
|
|
18
|
+
|
|
19
|
+
class ObjectUtils {
|
|
20
|
+
static materialProps = ['map', 'lightMap', 'bumpMap', 'normalMap', 'specularMap', 'envMap', 'aoMap', 'roughnessMap', 'metalnessMap'];
|
|
21
|
+
static CreateArrow(name, color, length, direction, headLength, headWidth, doubleArrow = false) {
|
|
22
|
+
const arrow = new Group();
|
|
23
|
+
const lineGeometry = new BufferGeometry();
|
|
24
|
+
lineGeometry.setAttribute('position', new Float32BufferAttribute([0, 0, 0, 0, 1, 0], 3));
|
|
25
|
+
const line = new Line(lineGeometry, new LineBasicMaterial({ color: color, toneMapped: false }));
|
|
26
|
+
lineGeometry.rotateX(Math.PI / 2 * direction.z);
|
|
27
|
+
lineGeometry.rotateY(Math.PI / 2 * direction.y);
|
|
28
|
+
lineGeometry.rotateZ(Math.PI / 2 * direction.x);
|
|
29
|
+
const translate = new Vector3((direction.x) / 2, direction.y ? -(direction.y) / 2 : 0, -(direction.z) / 2);
|
|
30
|
+
lineGeometry.translate(translate.x, translate.y, translate.z);
|
|
31
|
+
line.name = 'arrow_line';
|
|
32
|
+
line.matrixAutoUpdate = false;
|
|
33
|
+
arrow.add(line);
|
|
34
|
+
const coneGeometry = new CylinderGeometry(0, 0.5, 1, 5, 1);
|
|
35
|
+
const coneRightGeometry = coneGeometry.clone();
|
|
36
|
+
const cone = new Mesh(coneGeometry, new MeshBasicMaterial({ color: color, toneMapped: false }));
|
|
37
|
+
coneGeometry.rotateX(Math.PI / 2 * -direction.z);
|
|
38
|
+
if (direction.y) {
|
|
39
|
+
coneGeometry.rotateZ(Math.PI);
|
|
40
|
+
}
|
|
41
|
+
coneGeometry.rotateZ(Math.PI / 2 * -direction.x);
|
|
42
|
+
// coneGeometry.translate(translate.x * 2, translate.y * 2, translate.z * 2);
|
|
43
|
+
cone.name = 'arrow_cone_left';
|
|
44
|
+
cone.matrixAutoUpdate = false;
|
|
45
|
+
arrow.add(cone);
|
|
46
|
+
if (doubleArrow) {
|
|
47
|
+
const coneRight = new Mesh(coneRightGeometry, new MeshBasicMaterial({ color: color, toneMapped: false }));
|
|
48
|
+
coneRightGeometry.rotateX(Math.PI / 2 * direction.z);
|
|
49
|
+
coneRightGeometry.rotateZ(Math.PI / 2 * direction.x);
|
|
50
|
+
// coneRightGeometry.translate(-translate.x * 2, -translate.y * 2, -translate.z * 2);
|
|
51
|
+
coneRight.name = 'arrow_cone_right';
|
|
52
|
+
coneRight.matrixAutoUpdate = false;
|
|
53
|
+
arrow.add(coneRight);
|
|
54
|
+
}
|
|
55
|
+
arrow.name = name;
|
|
56
|
+
return ObjectUtils.UpdateArrowLength(arrow, length, direction, headLength, headWidth);
|
|
57
|
+
}
|
|
58
|
+
static UpdateArrowLength(arrow, length, direction, headLength, headWidth, doubleArrow = false) {
|
|
59
|
+
try {
|
|
60
|
+
const arrowLine = arrow.getObjectByName('arrow_line');
|
|
61
|
+
const scale = new Vector3(direction.x ? Math.max(0.0001, length - (doubleArrow ? headLength * 2 : headLength)) : 1, direction.y ? Math.max(0.0001, length - (doubleArrow ? headLength * 2 : headLength)) : 1, direction.z ? Math.max(0.0001, length - (doubleArrow ? headLength * 2 : headLength)) : 1);
|
|
62
|
+
arrowLine.scale.copy(scale);
|
|
63
|
+
arrowLine.updateMatrix();
|
|
64
|
+
const cone = arrow.getObjectByName('arrow_cone_left');
|
|
65
|
+
if (cone) {
|
|
66
|
+
cone.scale.set(headWidth, headLength, headWidth);
|
|
67
|
+
cone.position.x = direction.x ? length / 2 - headLength : 0;
|
|
68
|
+
cone.position.y = direction.y ? -length / 2 + headLength : 0;
|
|
69
|
+
cone.position.z = direction.z ? -length / 2 + headLength : 0;
|
|
70
|
+
cone.updateMatrix();
|
|
71
|
+
}
|
|
72
|
+
const coneRight = arrow.getObjectByName('arrow_cone_right');
|
|
73
|
+
if (coneRight) {
|
|
74
|
+
coneRight.scale.set(headWidth, headLength, headWidth);
|
|
75
|
+
coneRight.position.x = direction.x ? -length / 2 + headLength : 0;
|
|
76
|
+
coneRight.position.y = direction.y ? length / 2 - headLength : 0;
|
|
77
|
+
coneRight.position.z = direction.z ? length / 2 - headLength : 0;
|
|
78
|
+
coneRight.updateMatrix();
|
|
79
|
+
}
|
|
80
|
+
return arrow;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
static ChildOf(obj, parentName) {
|
|
86
|
+
if (obj && obj.parent && obj.parent.name === parentName) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
else if (obj.parent) {
|
|
90
|
+
return ObjectUtils.ChildOf(obj.parent, parentName);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
static GetParentItem(element) {
|
|
97
|
+
if (!element.parent) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (element.parent instanceof Object3D) {
|
|
101
|
+
return element.parent;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
return ObjectUtils.GetParentItem(element.parent);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
static GetDefaultMaterial(object) {
|
|
108
|
+
const children = object.children.filter(c => {
|
|
109
|
+
if (c instanceof Mesh) {
|
|
110
|
+
return Array.isArray(c.material) ?
|
|
111
|
+
c.material.find(m => m.name.toLowerCase().startsWith('default_')) :
|
|
112
|
+
c.material.name.toLowerCase().startsWith('default_');
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return children.map(c => c.material)[0];
|
|
116
|
+
}
|
|
117
|
+
static SameMaterial(first, second) {
|
|
118
|
+
if (!first && !second) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return first.hasOwnProperty('map') && second.hasOwnProperty('map') && first.map && second.map &&
|
|
122
|
+
first.map.image.src === second.map.image.src;
|
|
123
|
+
}
|
|
124
|
+
static GetChanges(firstItems, secondItems) {
|
|
125
|
+
const result = [];
|
|
126
|
+
for (let i = 0; i < secondItems.length; i++) { // check added/changed items
|
|
127
|
+
const secondItem = secondItems[i];
|
|
128
|
+
let oldPosition;
|
|
129
|
+
let oldMaterial;
|
|
130
|
+
const newPosition = new Vector3().copy(secondItem.position);
|
|
131
|
+
const newMaterial = ObjectUtils.GetDefaultMaterial(secondItem);
|
|
132
|
+
const firstItem = firstItems.find(fi => fi.name === secondItems[i].name);
|
|
133
|
+
if (firstItem) {
|
|
134
|
+
oldPosition = new Vector3().copy(firstItem.position);
|
|
135
|
+
oldMaterial = ObjectUtils.GetDefaultMaterial(firstItem);
|
|
136
|
+
}
|
|
137
|
+
if ((!oldPosition || (newPosition && !oldPosition.equals(newPosition))) || !ObjectUtils.SameMaterial(oldMaterial, newMaterial)) {
|
|
138
|
+
result.push({
|
|
139
|
+
object: secondItem,
|
|
140
|
+
name: secondItem.name,
|
|
141
|
+
oldPosition: oldPosition,
|
|
142
|
+
newPosition: newPosition,
|
|
143
|
+
oldMaterial: oldMaterial,
|
|
144
|
+
newMaterial: newMaterial
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (let i = 0; i < firstItems.length; i++) { // check deleted items
|
|
149
|
+
const firstItem = firstItems[i];
|
|
150
|
+
const oldPosition = new Vector3().copy(firstItem.position);
|
|
151
|
+
let newPosition;
|
|
152
|
+
const secondItem = secondItems.find(fi => fi.name === firstItems[i].name);
|
|
153
|
+
if (secondItem) {
|
|
154
|
+
newPosition = new Vector3().copy(secondItem.position);
|
|
155
|
+
}
|
|
156
|
+
if (!newPosition || (newPosition && !oldPosition.equals(newPosition))) {
|
|
157
|
+
result.push({
|
|
158
|
+
object: firstItem,
|
|
159
|
+
name: firstItem.name,
|
|
160
|
+
oldPosition: oldPosition,
|
|
161
|
+
newPosition: newPosition
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
static GetSelectionFromSelectedObject(object) {
|
|
168
|
+
if (object) {
|
|
169
|
+
if (object.userData && object.userData.selection) {
|
|
170
|
+
return object.userData.selection;
|
|
171
|
+
}
|
|
172
|
+
else if (object.parent) {
|
|
173
|
+
return this.GetSelectionFromSelectedObject(object.parent);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
static UpdateUvs(geo) {
|
|
184
|
+
if (geo) {
|
|
185
|
+
const pos = geo.attributes.position;
|
|
186
|
+
const b3 = new THREE.Box3().setFromBufferAttribute(pos);
|
|
187
|
+
const b3size = new THREE.Vector3();
|
|
188
|
+
b3.getSize(b3size);
|
|
189
|
+
const uv = [];
|
|
190
|
+
for (let i = 0; i < pos.count; i++) {
|
|
191
|
+
const x = pos.getX(i);
|
|
192
|
+
const y = pos.getY(i);
|
|
193
|
+
const u = (x - b3.min.x) / b3size.x;
|
|
194
|
+
const v = (y - b3.min.y) / b3size.y;
|
|
195
|
+
uv.push(u, v);
|
|
196
|
+
}
|
|
197
|
+
geo.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
static async LoadHDRI(path, scene) {
|
|
201
|
+
const hdri = await new RGBELoader().loadAsync(path);
|
|
202
|
+
hdri.mapping = EquirectangularReflectionMapping;
|
|
203
|
+
scene.environment = hdri;
|
|
204
|
+
}
|
|
205
|
+
static ProjectToPlane(points) {
|
|
206
|
+
const centroid = new Vector3();
|
|
207
|
+
points.forEach(p => centroid.add(p));
|
|
208
|
+
centroid.divideScalar(points.length);
|
|
209
|
+
const v1 = points[1].clone().sub(points[0]);
|
|
210
|
+
const v2 = points[2].clone().sub(points[0]);
|
|
211
|
+
const normal = v1.clone().cross(v2).normalize();
|
|
212
|
+
const arbitrary = Math.abs(normal.dot(new Vector3(1, 0, 0))) > 0.9
|
|
213
|
+
? new Vector3(0, 1, 0)
|
|
214
|
+
: new Vector3(1, 0, 0);
|
|
215
|
+
const u = new Vector3().crossVectors(normal, arbitrary).normalize();
|
|
216
|
+
const v = new Vector3().crossVectors(normal, u).normalize();
|
|
217
|
+
return points.map(p => {
|
|
218
|
+
const rel = p.clone().sub(centroid);
|
|
219
|
+
return new Vector2(rel.dot(u), rel.dot(v));
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
static CloneMaterial(material, deepClone = false) {
|
|
223
|
+
if (material instanceof Material$1) {
|
|
224
|
+
const onBeforeCompile = material.onBeforeCompile;
|
|
225
|
+
const onBeforeRender = material.onBeforeRender;
|
|
226
|
+
const clone = material.clone();
|
|
227
|
+
clone.onBeforeCompile = onBeforeCompile;
|
|
228
|
+
clone.onBeforeRender = onBeforeRender;
|
|
229
|
+
this.materialProps
|
|
230
|
+
.filter(mapType => clone[mapType] && clone[mapType] instanceof Texture)
|
|
231
|
+
.forEach(mapType => clone[mapType] = ObjectUtils.CloneTexture(clone[mapType], deepClone));
|
|
232
|
+
return clone;
|
|
233
|
+
}
|
|
234
|
+
return material.map((m) => {
|
|
235
|
+
const onBeforeCompile = m.onBeforeCompile;
|
|
236
|
+
const onBeforeRender = m.onBeforeRender;
|
|
237
|
+
const clone = m.clone();
|
|
238
|
+
clone.onBeforeCompile = onBeforeCompile;
|
|
239
|
+
clone.onBeforeRender = onBeforeRender;
|
|
240
|
+
this.materialProps
|
|
241
|
+
.filter(mapType => clone[mapType] && clone[mapType] instanceof Texture)
|
|
242
|
+
.forEach(mapType => clone[mapType] = ObjectUtils.CloneTexture(clone[mapType], deepClone));
|
|
243
|
+
return clone;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* ThreeJS does not clone image property, so it stays a reference to the original image.
|
|
248
|
+
* When deepClone, this method creates a new image and copies the original image data to it.
|
|
249
|
+
* @param texture
|
|
250
|
+
* @param deepClone
|
|
251
|
+
* @constructor
|
|
252
|
+
*/
|
|
253
|
+
static CloneTexture(texture, deepClone = false) {
|
|
254
|
+
const clone = texture.clone();
|
|
255
|
+
if (!deepClone) {
|
|
256
|
+
clone.needsUpdate = true;
|
|
257
|
+
return clone;
|
|
258
|
+
}
|
|
259
|
+
if (texture.image) {
|
|
260
|
+
if (texture.image instanceof HTMLImageElement && texture.image.src) {
|
|
261
|
+
const img = texture.image;
|
|
262
|
+
const newImage = new Image();
|
|
263
|
+
newImage.src = img.src;
|
|
264
|
+
clone.source = new Source(newImage);
|
|
265
|
+
}
|
|
266
|
+
else if (texture.image instanceof HTMLCanvasElement) {
|
|
267
|
+
const canvas = texture.image;
|
|
268
|
+
const newCanvas = document.createElement('canvas');
|
|
269
|
+
newCanvas.width = canvas.width;
|
|
270
|
+
newCanvas.height = canvas.height;
|
|
271
|
+
const ctx = newCanvas.getContext('2d');
|
|
272
|
+
if (ctx) {
|
|
273
|
+
ctx.drawImage(canvas, 0, 0);
|
|
274
|
+
}
|
|
275
|
+
clone.source = new Source(newCanvas);
|
|
276
|
+
}
|
|
277
|
+
else if (texture.image.data && (texture.image.data.slice || texture.image.data instanceof ArrayBuffer)) {
|
|
278
|
+
const imgData = texture.image;
|
|
279
|
+
clone.image = {
|
|
280
|
+
...imgData,
|
|
281
|
+
data: imgData.data.slice ? imgData.data.slice(0) : new Uint8Array(imgData.data).slice(0) // Deep copy the TypedArray
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
clone.needsUpdate = true;
|
|
286
|
+
return clone;
|
|
287
|
+
}
|
|
288
|
+
static CloneObject3D(source) {
|
|
289
|
+
const newObject = new Object3D();
|
|
290
|
+
source.children.forEach((child) => {
|
|
291
|
+
if (!child.visible) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (child instanceof Mesh) {
|
|
295
|
+
newObject.add(child.clone());
|
|
296
|
+
}
|
|
297
|
+
else if (child instanceof Object3D) {
|
|
298
|
+
const clone = ObjectUtils.CloneObject3D(child);
|
|
299
|
+
clone.position.copy(child.position);
|
|
300
|
+
clone.rotation.copy(child.rotation);
|
|
301
|
+
newObject.add(clone);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
return newObject;
|
|
305
|
+
}
|
|
306
|
+
static DeepCloneObject3D(source) {
|
|
307
|
+
if (!source) {
|
|
308
|
+
return new Object3D();
|
|
309
|
+
}
|
|
310
|
+
const clone = source.clone();
|
|
311
|
+
clone.traverse((obj) => {
|
|
312
|
+
if (obj instanceof Mesh && obj.material) {
|
|
313
|
+
obj.material = ObjectUtils.CloneMaterial(obj.material, true);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
return clone;
|
|
317
|
+
}
|
|
318
|
+
static DisposeMaterial(material) {
|
|
319
|
+
if (!material) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (Array.isArray(material)) {
|
|
323
|
+
material.forEach(mtrl => ObjectUtils.DisposeMaterial(mtrl));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
for (const key in material) {
|
|
327
|
+
if (material.hasOwnProperty(key)) {
|
|
328
|
+
const value = material[key];
|
|
329
|
+
if (value && value.isTexture) {
|
|
330
|
+
value.dispose();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
material.dispose();
|
|
335
|
+
}
|
|
336
|
+
static DisposeObject(object) {
|
|
337
|
+
if (!object) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (object.children.length) {
|
|
341
|
+
object.children.forEach(child => this.DisposeObject(child));
|
|
342
|
+
}
|
|
343
|
+
ObjectUtils.DisposeNode(object);
|
|
344
|
+
}
|
|
345
|
+
static GetParentCustomObject(element) {
|
|
346
|
+
if (!element.parent) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
if (element.parent instanceof Object3D) {
|
|
350
|
+
return element.parent;
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
return ObjectUtils.GetParentCustomObject(element.parent);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
static DisposeNode(node) {
|
|
357
|
+
node.traverse((obj) => {
|
|
358
|
+
if (obj instanceof Mesh) {
|
|
359
|
+
if (obj.geometry) {
|
|
360
|
+
obj.geometry.dispose();
|
|
361
|
+
}
|
|
362
|
+
ObjectUtils.DisposeMaterial(obj.material);
|
|
363
|
+
}
|
|
364
|
+
if (typeof obj.dispose === 'function') {
|
|
365
|
+
// @ts-ignore
|
|
366
|
+
obj.dispose();
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
static _remapFloat(v, min0, max0, min1, max1) {
|
|
371
|
+
return min1 + (v - min0) / (max0 - min0) * (max1 - min1);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
class ThreedUtils {
|
|
376
|
+
clips = [];
|
|
377
|
+
_objectCache = new Map();
|
|
378
|
+
clearCache() {
|
|
379
|
+
const objs = Array.from(this._objectCache.values());
|
|
380
|
+
objs.forEach(o => ObjectUtils.DisposeObject(o));
|
|
381
|
+
this._objectCache.clear();
|
|
382
|
+
}
|
|
383
|
+
download3DSource(fileName, setVisibleFalse = true) {
|
|
384
|
+
return new Promise(async (resolve, reject) => {
|
|
385
|
+
fileName = fileName.replace('.unity3d', '');
|
|
386
|
+
let lookupFileName = fileName + (fileName.indexOf('.glb') < 0 ? '.glb' : '');
|
|
387
|
+
if (this._objectCache.has(lookupFileName)) {
|
|
388
|
+
resolve(this._objectCache.get(lookupFileName));
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
this.loadGlbSource(lookupFileName, setVisibleFalse)
|
|
392
|
+
.then((obj) => {
|
|
393
|
+
this._objectCache.set(lookupFileName, obj);
|
|
394
|
+
resolve(obj);
|
|
395
|
+
})
|
|
396
|
+
.catch(() => {
|
|
397
|
+
reject(`GLB source not found! (${lookupFileName})`);
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
readFileAsText(file) {
|
|
402
|
+
const fileReader = new FileReader();
|
|
403
|
+
return new Promise((resolve, reject) => {
|
|
404
|
+
fileReader.onload = (e) => resolve(e.target.result);
|
|
405
|
+
fileReader.onerror = error => reject(error);
|
|
406
|
+
fileReader.readAsText(file);
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
async loadJsonModel(filePath) {
|
|
410
|
+
if (this._objectCache.has(filePath)) {
|
|
411
|
+
return Promise.resolve(this._objectCache.get(filePath));
|
|
412
|
+
}
|
|
413
|
+
const json = await this._readJsonFile(filePath);
|
|
414
|
+
const loader = new THREE.ObjectLoader();
|
|
415
|
+
loader.crossOrigin = 'Anonymous';
|
|
416
|
+
return new Promise((resolve, reject) => {
|
|
417
|
+
try {
|
|
418
|
+
const obj = loader.parse(json);
|
|
419
|
+
this._objectCache.set(filePath, obj);
|
|
420
|
+
resolve(obj);
|
|
421
|
+
}
|
|
422
|
+
catch (e) {
|
|
423
|
+
reject(null);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
async loadJsonObjectModel(filePath) {
|
|
428
|
+
if (this._objectCache.has(filePath)) {
|
|
429
|
+
return Promise.resolve(this._objectCache.get(filePath));
|
|
430
|
+
}
|
|
431
|
+
const loader = new THREE.ObjectLoader();
|
|
432
|
+
loader.setCrossOrigin('Anonymous');
|
|
433
|
+
loader.setResourcePath('');
|
|
434
|
+
return new Promise((resolve, reject) => {
|
|
435
|
+
loader.load(filePath, (object) => {
|
|
436
|
+
const obj = (object.type === 'Scene' && object.children[0].type === 'Object3D') ? object.children[0] : object;
|
|
437
|
+
this._objectCache.set(filePath, obj);
|
|
438
|
+
resolve(obj);
|
|
439
|
+
}, xhr => null, error => reject(error));
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
async loadGlbModel(file, cleanUp = true, dracoPath) {
|
|
443
|
+
if (this._objectCache.has(file)) {
|
|
444
|
+
return Promise.resolve(this._objectCache.get(file));
|
|
445
|
+
}
|
|
446
|
+
if (!window.hasOwnProperty('loadGLTF')) {
|
|
447
|
+
return new Promise((resolve, reject) => {
|
|
448
|
+
const loader = new GLTFLoader();
|
|
449
|
+
loader.setDRACOLoader(new DRACOLoader());
|
|
450
|
+
loader.dracoLoader.setDecoderPath(dracoPath);
|
|
451
|
+
loader.dracoLoader.setDecoderConfig({ type: 'js' });
|
|
452
|
+
loader.load(file, async (object) => {
|
|
453
|
+
this.clips = object.animations || [];
|
|
454
|
+
const obj = this.cleanedUpObjectsWeb(object.scene, false);
|
|
455
|
+
this._objectCache.set(file, obj);
|
|
456
|
+
resolve(obj);
|
|
457
|
+
}, xhr => this._handleUpdateProgressBar(xhr.loaded / xhr.total * 100), error => {
|
|
458
|
+
console.log('Error! ', error);
|
|
459
|
+
reject(error);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
const obj = await window.loadGLTF(file);
|
|
465
|
+
if (obj) {
|
|
466
|
+
this._cleanedUpObjects(obj, cleanUp);
|
|
467
|
+
this._objectCache.set(file, obj);
|
|
468
|
+
return obj;
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
async loadGlbSource(file, setVisibleFalse = true, dracoPath) {
|
|
476
|
+
const obj = await this.loadGlbModel(file, true, dracoPath);
|
|
477
|
+
if (obj) {
|
|
478
|
+
obj.children = obj.children.filter(c => !(c instanceof THREE.Camera || (c.constructor.name && c.constructor.name.toLowerCase().indexOf('camera') > -1)));
|
|
479
|
+
obj.children.sort((a, b) => a['name'] < b['name'] ? 1 : -1);
|
|
480
|
+
obj.children.forEach((c) => {
|
|
481
|
+
c.traverse((t) => {
|
|
482
|
+
t.visible = !t.name.toLowerCase().startsWith('c_');
|
|
483
|
+
});
|
|
484
|
+
if (setVisibleFalse) {
|
|
485
|
+
c.visible = false;
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
if (obj.children.length === 1 && (obj.children[0] instanceof THREE.Group || obj.children[0].constructor.name === 'Group')) { // flatten children
|
|
489
|
+
const children = obj.children[0].children.slice();
|
|
490
|
+
const name = obj.children[0].name;
|
|
491
|
+
obj.children.length = 0;
|
|
492
|
+
const parent = new THREE.Object3D();
|
|
493
|
+
parent.name = name;
|
|
494
|
+
parent.children = children;
|
|
495
|
+
obj.add(parent);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return obj;
|
|
499
|
+
}
|
|
500
|
+
async textureFromUrl(url) {
|
|
501
|
+
// url = this._includeBaseUrl(url);
|
|
502
|
+
return new Promise((resolve, reject) => {
|
|
503
|
+
const textureLoader = new THREE.TextureLoader();
|
|
504
|
+
// textureLoader.setBaseU(this._settingsService.settings.assetPath);
|
|
505
|
+
textureLoader.load(url, (texture) => {
|
|
506
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
507
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
508
|
+
texture.repeat.set(1, 1);
|
|
509
|
+
texture.needsUpdate = true;
|
|
510
|
+
return resolve(texture);
|
|
511
|
+
}, null, reject);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
cleanedUpObjectsWeb(object, cleanUp = true) {
|
|
515
|
+
let obj = new Object3D();
|
|
516
|
+
// console.log(this.clips);
|
|
517
|
+
object.children.forEach((c) => {
|
|
518
|
+
if (!(c instanceof Camera)) {
|
|
519
|
+
if (cleanUp && c instanceof Group || (c.children.length === 1 && c.children[0] instanceof Group)) {
|
|
520
|
+
this._addGroupChildrenToObject(c, obj);
|
|
521
|
+
}
|
|
522
|
+
else if ((cleanUp && !(c instanceof Mesh)) || (!(c instanceof Mesh) && !c.name && c.children.length > 0)) {
|
|
523
|
+
c.children.forEach((child) => {
|
|
524
|
+
child.translateY(c.position.y);
|
|
525
|
+
});
|
|
526
|
+
c.translateY(-c.position.y);
|
|
527
|
+
if (obj.children.length > 0) {
|
|
528
|
+
obj.add(c.clone());
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
obj = c.clone();
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
// if (c.position.y > 0 || c.position.y < 0) {
|
|
536
|
+
// c.children.forEach((child) => {
|
|
537
|
+
// child.translateY(c.position.y);
|
|
538
|
+
// });
|
|
539
|
+
// c.translateY(-c.position.y);
|
|
540
|
+
// }
|
|
541
|
+
obj.add(c.clone());
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
const boundingBox = new Box3().setFromObject(obj);
|
|
546
|
+
const bbCenterPivot = new Vector3();
|
|
547
|
+
boundingBox.getCenter(bbCenterPivot);
|
|
548
|
+
const delta = new Vector3().add(bbCenterPivot).negate();
|
|
549
|
+
obj.children.forEach((cc) => {
|
|
550
|
+
cc.position.add(delta);
|
|
551
|
+
});
|
|
552
|
+
return obj;
|
|
553
|
+
}
|
|
554
|
+
_cleanedUpObjects(object, cleanUp = true) {
|
|
555
|
+
let obj = new THREE.Object3D();
|
|
556
|
+
object.children.forEach((c) => {
|
|
557
|
+
if (!(c instanceof THREE.Camera || (c.constructor.name && c.constructor.name.toLowerCase().indexOf('camera') > -1))) {
|
|
558
|
+
if (cleanUp && (c instanceof THREE.Group || c.constructor.name === 'Group') || (c.children.length === 1 && (c.children[0] instanceof THREE.Group || c.children[0].constructor.name === 'Group'))) {
|
|
559
|
+
this._addGroupChildrenToObject(c, obj);
|
|
560
|
+
}
|
|
561
|
+
else if ((cleanUp && !(c instanceof THREE.Mesh || c.constructor.name === 'Mesh')) || (!(c instanceof THREE.Mesh || c.constructor.name === 'Mesh') && !c.name && c.children.length > 0)) {
|
|
562
|
+
c.children.forEach((child) => {
|
|
563
|
+
child.translateY(c.position.y);
|
|
564
|
+
});
|
|
565
|
+
c.translateY(-c.position.y);
|
|
566
|
+
if (obj.children.length > 0) {
|
|
567
|
+
obj.add(c.clone());
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
obj = c.clone();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
if (c.position.y > 0 || c.position.y < 0) {
|
|
575
|
+
c.children.forEach((child) => {
|
|
576
|
+
child.translateY(c.position.y);
|
|
577
|
+
});
|
|
578
|
+
c.translateY(-c.position.y);
|
|
579
|
+
}
|
|
580
|
+
obj.add(c.clone());
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
const boundingBox = new THREE.Box3().setFromObject(obj);
|
|
585
|
+
const bbCenterPivot = new THREE.Vector3();
|
|
586
|
+
boundingBox.getCenter(bbCenterPivot);
|
|
587
|
+
const delta = new THREE.Vector3().add(bbCenterPivot).negate();
|
|
588
|
+
obj.children.forEach((cc) => {
|
|
589
|
+
cc.position.add(delta);
|
|
590
|
+
});
|
|
591
|
+
return obj;
|
|
592
|
+
}
|
|
593
|
+
_addGroupChildrenToObject(group, obj, cleanUp = true) {
|
|
594
|
+
group.children.forEach((gc) => {
|
|
595
|
+
if (cleanUp && (gc instanceof THREE.Group || gc.constructor.name === 'Group')) {
|
|
596
|
+
this._addGroupChildrenToObject(gc, obj);
|
|
597
|
+
}
|
|
598
|
+
else {
|
|
599
|
+
// gc.translateX(-group.position.x);
|
|
600
|
+
gc.translateY(group.position.y);
|
|
601
|
+
// gc.translateZ(-group.position.z);
|
|
602
|
+
obj.add(gc.clone());
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
_iterateChildren(children, callback) {
|
|
607
|
+
for (let i = 0; i < children.length; i++) {
|
|
608
|
+
const child = children[i];
|
|
609
|
+
if (child instanceof THREE.Mesh || child.constructor.name === 'Mesh') {
|
|
610
|
+
callback(child);
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
this._iterateChildren(child.children, callback);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
async _readJsonFile(filePath) {
|
|
618
|
+
try {
|
|
619
|
+
const response = await fetch(filePath);
|
|
620
|
+
if (!response.ok) {
|
|
621
|
+
return '';
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
let empty = false;
|
|
625
|
+
await response.clone().text().then((value) => {
|
|
626
|
+
if (value === '') {
|
|
627
|
+
empty = true;
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
return empty ? {} : response.json();
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
catch (e) {
|
|
634
|
+
return '';
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
_handleUpdateProgressBar(loaded) {
|
|
638
|
+
// this._progressService.progress = loaded;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// @dynamic
|
|
643
|
+
class ImageUtils {
|
|
644
|
+
static textures = new Map();
|
|
645
|
+
static CreateTextureFromBase64(id, base64, material, defaultFlip = false) {
|
|
646
|
+
return new Promise((resolve) => {
|
|
647
|
+
if (ImageUtils.textures.has(id)) {
|
|
648
|
+
resolve(ImageUtils.textures.get(id));
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
if (!base64) {
|
|
652
|
+
resolve(new Texture());
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
const loader = new THREE.TextureLoader();
|
|
656
|
+
loader.load(base64, (texture) => {
|
|
657
|
+
texture.anisotropy = 16;
|
|
658
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
659
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
660
|
+
texture.repeat = new THREE.Vector2(material ? material.repeatX : 1, material ? material.repeatY : 1);
|
|
661
|
+
texture.flipY = defaultFlip; // sabina stoel gaat hierdoor kapot
|
|
662
|
+
texture.colorSpace = LinearSRGBColorSpace;
|
|
663
|
+
texture.needsUpdate = true;
|
|
664
|
+
ImageUtils.textures.set(id, texture);
|
|
665
|
+
resolve(texture);
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
static getFixedImageFilepathUrl(imageFilepathUrl) {
|
|
672
|
+
return imageFilepathUrl.replace('/content/', '/content43/');
|
|
673
|
+
}
|
|
674
|
+
static getDocBodyWithMimeTypeDefinition(fileName, documentBody) {
|
|
675
|
+
if (documentBody === null) {
|
|
676
|
+
return documentBody;
|
|
677
|
+
}
|
|
678
|
+
const fileExtension = fileName.substr(fileName.lastIndexOf('.') + 1);
|
|
679
|
+
switch (fileExtension.toLowerCase()) {
|
|
680
|
+
case 'jpg':
|
|
681
|
+
case 'jpeg':
|
|
682
|
+
return 'data:image/jpg;base64,' + documentBody;
|
|
683
|
+
case 'png':
|
|
684
|
+
return 'data:image/png;base64,' + documentBody;
|
|
685
|
+
case 'gif':
|
|
686
|
+
return 'data:image/gif;base64,' + documentBody;
|
|
687
|
+
case 'bmp':
|
|
688
|
+
return 'data:image/bmp;base64,' + documentBody;
|
|
689
|
+
default:
|
|
690
|
+
return 'data:image/png;base64,' + documentBody;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
static ClearCache() {
|
|
694
|
+
ImageUtils.textures.forEach(value => {
|
|
695
|
+
value.dispose();
|
|
696
|
+
});
|
|
697
|
+
ImageUtils.textures.clear();
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
class Material {
|
|
702
|
+
name;
|
|
703
|
+
schema;
|
|
704
|
+
specular = new THREE.Color(0.3, 0.3, 0.3);
|
|
705
|
+
shininess = 0;
|
|
706
|
+
// public roughness = 1;
|
|
707
|
+
// public metalness = 0.5;
|
|
708
|
+
normal;
|
|
709
|
+
texture;
|
|
710
|
+
ao;
|
|
711
|
+
metalness;
|
|
712
|
+
roughness;
|
|
713
|
+
repeatX = 4;
|
|
714
|
+
repeatY = 4;
|
|
715
|
+
loaded = false;
|
|
716
|
+
metalnessValue;
|
|
717
|
+
roughnessValue;
|
|
718
|
+
displacement;
|
|
719
|
+
displacementValue;
|
|
720
|
+
sheen;
|
|
721
|
+
sheenColor;
|
|
722
|
+
sheenColorMap;
|
|
723
|
+
sheenRoughness;
|
|
724
|
+
sheenRoughnessMap;
|
|
725
|
+
emissive;
|
|
726
|
+
emissiveValue;
|
|
727
|
+
emissiveIntensityValue;
|
|
728
|
+
envMap;
|
|
729
|
+
envMapIntensity;
|
|
730
|
+
opacity;
|
|
731
|
+
transparent;
|
|
732
|
+
reflectivity;
|
|
733
|
+
side;
|
|
734
|
+
ior;
|
|
735
|
+
transmission;
|
|
736
|
+
thickness;
|
|
737
|
+
specularIntensity;
|
|
738
|
+
transmissionMap;
|
|
739
|
+
clearcoatMap;
|
|
740
|
+
clearcoatRoughnessMap;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
class FurnitureMaterial extends Material {
|
|
744
|
+
textureFilename;
|
|
745
|
+
normalFilename;
|
|
746
|
+
aoFilename;
|
|
747
|
+
metalnessFilename;
|
|
748
|
+
roughnessFilename;
|
|
749
|
+
displacementFilename;
|
|
750
|
+
envMapFilename;
|
|
751
|
+
emissiveFileName;
|
|
752
|
+
sheenColorMapFileName;
|
|
753
|
+
sheenRoughnessMapFileName;
|
|
754
|
+
transmissionMapFileName;
|
|
755
|
+
}
|
|
756
|
+
class AssetUtils {
|
|
757
|
+
static async CreateMaterialFromAsset(asset) {
|
|
758
|
+
const material = new Material();
|
|
759
|
+
if (!asset) {
|
|
760
|
+
return material;
|
|
761
|
+
}
|
|
762
|
+
if (asset.settings) {
|
|
763
|
+
AssetUtils.setSettingsOfMaterial(material, asset.settings);
|
|
764
|
+
}
|
|
765
|
+
if (asset.texture) {
|
|
766
|
+
material.texture = await ImageUtils.CreateTextureFromBase64(asset.id + '_texture', asset.texture, material);
|
|
767
|
+
material.texture.colorSpace = SRGBColorSpace;
|
|
768
|
+
material.textureFilename = asset.textureFilename;
|
|
769
|
+
}
|
|
770
|
+
if (asset.normal) {
|
|
771
|
+
material.normal = await ImageUtils.CreateTextureFromBase64(asset.id + '_normal', asset.normal, material);
|
|
772
|
+
material.normalFilename = asset.normalFilename;
|
|
773
|
+
}
|
|
774
|
+
if (asset.orm) {
|
|
775
|
+
material.ao = await ImageUtils.CreateTextureFromBase64(asset.id + '_orm', asset.orm, material);
|
|
776
|
+
material.roughness = material.ao;
|
|
777
|
+
material.metalness = material.ao;
|
|
778
|
+
material.aoFilename = asset.ormFilename;
|
|
779
|
+
material.roughnessFilename = asset.ormFilename;
|
|
780
|
+
material.metalnessFilename = asset.ormFilename;
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
if (asset.ao) {
|
|
784
|
+
material.ao = await ImageUtils.CreateTextureFromBase64(asset.id + '_ao', asset.ao, material);
|
|
785
|
+
material.aoFilename = asset.aoFilename;
|
|
786
|
+
}
|
|
787
|
+
if (asset.metalness) {
|
|
788
|
+
material.metalness = await ImageUtils.CreateTextureFromBase64(asset.id + '_metalness', asset.metalness, material);
|
|
789
|
+
material.metalnessFilename = asset.metalnessFilename;
|
|
790
|
+
}
|
|
791
|
+
if (asset.roughness) {
|
|
792
|
+
material.roughness = await ImageUtils.CreateTextureFromBase64(asset.id + '_roughness', asset.roughness, material);
|
|
793
|
+
material.roughnessFilename = asset.roughnessFilename;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if (asset.displacement) {
|
|
797
|
+
material.displacement = await ImageUtils.CreateTextureFromBase64(asset.id + '_displacement', asset.displacement, material);
|
|
798
|
+
material.displacementFilename = asset.displacementFilename;
|
|
799
|
+
}
|
|
800
|
+
if (asset.envMap) {
|
|
801
|
+
material.envMap = await ImageUtils.CreateTextureFromBase64(asset.id + '_env', asset.envMap, material, true);
|
|
802
|
+
material.envMapFilename = asset.envMapFilename;
|
|
803
|
+
}
|
|
804
|
+
if (asset.sheenColorMap) {
|
|
805
|
+
material.sheenColorMap = await ImageUtils.CreateTextureFromBase64(asset.id + '_sheen_color', asset.sheenColorMap, material);
|
|
806
|
+
material.sheenColorMapFileName = asset.sheenColorMapFilename;
|
|
807
|
+
}
|
|
808
|
+
if (asset.sheenRoughnessMap) {
|
|
809
|
+
material.sheenRoughnessMap = await ImageUtils.CreateTextureFromBase64(asset.id + '_sheen_roughness', asset.sheenRoughnessMap, material);
|
|
810
|
+
material.sheenRoughnessMapFileName = asset.sheenRoughnessMapFilename;
|
|
811
|
+
}
|
|
812
|
+
if (asset.transmissionMap) {
|
|
813
|
+
material.transmissionMap = await ImageUtils.CreateTextureFromBase64(asset.id + '_transmission', asset.transmissionMap, material);
|
|
814
|
+
material.transmissionMapFileName = asset.transmissionMapFilename;
|
|
815
|
+
}
|
|
816
|
+
if (asset.emissive) {
|
|
817
|
+
material.emissive = await ImageUtils.CreateTextureFromBase64(asset.id + '_emissive', asset.emissive, material);
|
|
818
|
+
material.emissiveFileName = asset.emissiveFilename;
|
|
819
|
+
}
|
|
820
|
+
material.sheen = asset.sheen;
|
|
821
|
+
material.emissiveIntensityValue = asset.emissiveIntensity;
|
|
822
|
+
material.emissiveValue = asset.emissiveValue;
|
|
823
|
+
material.side = asset.side;
|
|
824
|
+
material.sheenColor = asset.sheenColor;
|
|
825
|
+
material.sheenRoughness = asset.sheenRoughness;
|
|
826
|
+
material.opacity = asset.opacity;
|
|
827
|
+
material.transparent = asset.transparent;
|
|
828
|
+
material.envMapIntensity = asset.envMapIntensity;
|
|
829
|
+
material.reflectivity = asset.reflectivity;
|
|
830
|
+
material.displacementValue = asset.displacementValue;
|
|
831
|
+
material.transmission = asset.transmission;
|
|
832
|
+
material.ior = asset.ior;
|
|
833
|
+
material.thickness = asset.thickness;
|
|
834
|
+
material.specularIntensity = asset.specularIntensity;
|
|
835
|
+
return material;
|
|
836
|
+
}
|
|
837
|
+
static setSettingsOfMaterial(material, settings) {
|
|
838
|
+
const shininess = parseFloat(settings['power']);
|
|
839
|
+
if (!isNaN(shininess)) {
|
|
840
|
+
material.shininess = shininess;
|
|
841
|
+
// material.roughness = 1 - (shininess / 100);
|
|
842
|
+
}
|
|
843
|
+
const level = parseFloat(settings['level']);
|
|
844
|
+
if (!isNaN(level)) {
|
|
845
|
+
material.specular = new THREE.Color(level, level, level);
|
|
846
|
+
}
|
|
847
|
+
const repeatObjectUsed = settings.hasOwnProperty('repeat');
|
|
848
|
+
const repeatx = repeatObjectUsed ? parseFloat(settings['repeat']['repeatx']) : parseFloat(settings['repeatx']);
|
|
849
|
+
if (!isNaN(repeatx)) {
|
|
850
|
+
material.repeatX = repeatx;
|
|
851
|
+
}
|
|
852
|
+
const repeaty = repeatObjectUsed ? parseFloat(settings['repeat']['repeaty']) : parseFloat(settings['repeaty']);
|
|
853
|
+
if (!isNaN(repeaty)) {
|
|
854
|
+
material.repeatY = repeaty;
|
|
855
|
+
}
|
|
856
|
+
const metalness = parseFloat(settings['metalness']);
|
|
857
|
+
if (!isNaN(metalness)) {
|
|
858
|
+
material.metalnessValue = Math.min(1, metalness);
|
|
859
|
+
}
|
|
860
|
+
const roughness = parseFloat(settings['roughness']);
|
|
861
|
+
if (!isNaN(roughness)) {
|
|
862
|
+
material.roughnessValue = Math.min(1, roughness);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
class VariationSettingsSettings {
|
|
868
|
+
repeatx;
|
|
869
|
+
repeaty;
|
|
870
|
+
roughness;
|
|
871
|
+
metalness;
|
|
872
|
+
}
|
|
873
|
+
class VariationSettings {
|
|
874
|
+
id;
|
|
875
|
+
settings = new VariationSettingsSettings();
|
|
876
|
+
texture;
|
|
877
|
+
textureFilename;
|
|
878
|
+
normal;
|
|
879
|
+
normalFilename;
|
|
880
|
+
ao;
|
|
881
|
+
aoFilename;
|
|
882
|
+
metalness;
|
|
883
|
+
metalnessFilename;
|
|
884
|
+
roughness;
|
|
885
|
+
roughnessFilename;
|
|
886
|
+
orm;
|
|
887
|
+
ormFilename;
|
|
888
|
+
displacement;
|
|
889
|
+
displacementValue;
|
|
890
|
+
displacementFilename;
|
|
891
|
+
sheen;
|
|
892
|
+
sheenColor;
|
|
893
|
+
sheenColorMap;
|
|
894
|
+
sheenColorMapFilename;
|
|
895
|
+
sheenRoughness;
|
|
896
|
+
sheenRoughnessMap;
|
|
897
|
+
sheenRoughnessMapFilename;
|
|
898
|
+
transmissionMap;
|
|
899
|
+
transmissionMapFilename;
|
|
900
|
+
emissive;
|
|
901
|
+
emissiveFilename;
|
|
902
|
+
emissiveIntensity;
|
|
903
|
+
emissiveValue;
|
|
904
|
+
opacity;
|
|
905
|
+
transparent;
|
|
906
|
+
envMap;
|
|
907
|
+
envMapFilename;
|
|
908
|
+
envMapIntensity;
|
|
909
|
+
reflectivity;
|
|
910
|
+
side;
|
|
911
|
+
transmission;
|
|
912
|
+
ior;
|
|
913
|
+
thickness;
|
|
914
|
+
specularIntensity;
|
|
915
|
+
loading = false;
|
|
916
|
+
loaded = new Subject();
|
|
917
|
+
material;
|
|
918
|
+
copyFrom(settings) {
|
|
919
|
+
this.settings = settings.settings;
|
|
920
|
+
this.texture = settings.texture;
|
|
921
|
+
this.textureFilename = settings.textureFilename;
|
|
922
|
+
this.normal = settings.normal;
|
|
923
|
+
this.normalFilename = settings.normalFilename;
|
|
924
|
+
this.ao = settings.ao;
|
|
925
|
+
this.aoFilename = settings.aoFilename;
|
|
926
|
+
this.metalness = settings.metalness;
|
|
927
|
+
this.metalnessFilename = settings.metalnessFilename;
|
|
928
|
+
this.roughness = settings.roughness;
|
|
929
|
+
this.roughnessFilename = settings.roughnessFilename;
|
|
930
|
+
this.orm = settings.orm;
|
|
931
|
+
this.ormFilename = settings.ormFilename;
|
|
932
|
+
this.displacement = settings.displacement;
|
|
933
|
+
this.displacementValue = settings.displacementValue;
|
|
934
|
+
this.displacementFilename = settings.displacementFilename;
|
|
935
|
+
this.sheen = settings.sheen;
|
|
936
|
+
this.sheenColor = settings.sheenColor;
|
|
937
|
+
this.sheenColorMap = settings.sheenColorMap;
|
|
938
|
+
this.sheenColorMapFilename = settings.sheenColorMapFilename;
|
|
939
|
+
this.transmissionMap = settings.transmissionMap;
|
|
940
|
+
this.transmissionMapFilename = settings.transmissionMapFilename;
|
|
941
|
+
this.sheenRoughness = settings.sheenRoughness;
|
|
942
|
+
this.sheenRoughnessMap = settings.sheenRoughnessMap;
|
|
943
|
+
this.sheenRoughnessMapFilename = settings.sheenRoughnessMapFilename;
|
|
944
|
+
this.emissive = settings.emissive;
|
|
945
|
+
this.emissiveFilename = settings.emissiveFilename;
|
|
946
|
+
this.emissiveIntensity = settings.emissiveIntensity;
|
|
947
|
+
this.emissiveValue = settings.emissiveValue;
|
|
948
|
+
this.opacity = settings.opacity;
|
|
949
|
+
this.transparent = settings.transparent;
|
|
950
|
+
this.envMap = settings.envMap;
|
|
951
|
+
this.envMapFilename = settings.envMapFilename;
|
|
952
|
+
this.envMapIntensity = settings.envMapIntensity;
|
|
953
|
+
this.reflectivity = settings.reflectivity;
|
|
954
|
+
this.side = settings.side;
|
|
955
|
+
this.transmission = settings.transmission;
|
|
956
|
+
this.ior = settings.ior;
|
|
957
|
+
this.thickness = settings.thickness;
|
|
958
|
+
this.specularIntensity = settings.specularIntensity;
|
|
959
|
+
this.material = settings.material;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// Static utility functions holder related to files.
|
|
964
|
+
// @dynamic
|
|
965
|
+
class FileUtils {
|
|
966
|
+
static _cachedTextureUploads = new Map();
|
|
967
|
+
static _filesDontExist = [];
|
|
968
|
+
static _filesExist = [];
|
|
969
|
+
static async DoesFileExist(url) {
|
|
970
|
+
try {
|
|
971
|
+
if (this._filesDontExist.indexOf(url) > -1) { // no need to check again
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
if (this._filesExist.indexOf(url) > -1) { // no need to check again
|
|
975
|
+
return true;
|
|
976
|
+
}
|
|
977
|
+
const response = await fetch(url, { method: 'HEAD' });
|
|
978
|
+
if (response.ok && response.status === 200) {
|
|
979
|
+
this._filesExist.push(url);
|
|
980
|
+
return true;
|
|
981
|
+
}
|
|
982
|
+
this._filesDontExist.push(url);
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
catch (error) {
|
|
986
|
+
this._filesDontExist.push(url);
|
|
987
|
+
return false;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
// Returns the given dataUri string stripped of the mimetype part.
|
|
991
|
+
static StripMimeStringFromDataUri(dataUri) {
|
|
992
|
+
if (!dataUri) {
|
|
993
|
+
return '';
|
|
994
|
+
}
|
|
995
|
+
const mimeString = this.GetMimeStringFromDataUri(dataUri);
|
|
996
|
+
return dataUri.substr(mimeString.length + 1);
|
|
997
|
+
}
|
|
998
|
+
static GetMimeStringFromDataUri(dataUri) {
|
|
999
|
+
if (!dataUri) {
|
|
1000
|
+
return '';
|
|
1001
|
+
}
|
|
1002
|
+
return dataUri.split(',')[0];
|
|
1003
|
+
}
|
|
1004
|
+
static async FileExists(url, assetPath) {
|
|
1005
|
+
if (!assetPath.endsWith('/')) {
|
|
1006
|
+
assetPath = assetPath + '/';
|
|
1007
|
+
}
|
|
1008
|
+
const result = await axios({
|
|
1009
|
+
method: 'get',
|
|
1010
|
+
url: `${assetPath}getFiles.php?assetUrl=${url}`,
|
|
1011
|
+
responseType: "json"
|
|
1012
|
+
});
|
|
1013
|
+
return !!result.data;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* There is some discrepancy regarding locations of h3d objects
|
|
1017
|
+
* Therefor we need to (temporarily?!) fix the content url
|
|
1018
|
+
* Also we need to change some additionals
|
|
1019
|
+
*/
|
|
1020
|
+
static FixUrl(assetUrl) {
|
|
1021
|
+
if (!assetUrl) {
|
|
1022
|
+
return '';
|
|
1023
|
+
}
|
|
1024
|
+
let fixedUrl = assetUrl;
|
|
1025
|
+
if (!fixedUrl.endsWith('glb') && !fixedUrl.endsWith('obj') && !fixedUrl.endsWith('glb.gz') && !fixedUrl.endsWith('obj.gz')) {
|
|
1026
|
+
fixedUrl = FileUtils.FixUnityUrl(fixedUrl);
|
|
1027
|
+
}
|
|
1028
|
+
fixedUrl = fixedUrl.replace('/content/', '/content43/');
|
|
1029
|
+
return fixedUrl;
|
|
1030
|
+
}
|
|
1031
|
+
static FixGlbUrl(assetUrl) {
|
|
1032
|
+
if (!assetUrl) {
|
|
1033
|
+
return '';
|
|
1034
|
+
}
|
|
1035
|
+
let fixedUrl = assetUrl;
|
|
1036
|
+
if (assetUrl.indexOf('_webplayer') === -1) {
|
|
1037
|
+
fixedUrl = assetUrl.concat('_webplayer');
|
|
1038
|
+
}
|
|
1039
|
+
fixedUrl = fixedUrl.replace('/content/', '/content43/');
|
|
1040
|
+
if (!fixedUrl.endsWith('.glb')) {
|
|
1041
|
+
fixedUrl = fixedUrl.concat('.glb');
|
|
1042
|
+
}
|
|
1043
|
+
return fixedUrl;
|
|
1044
|
+
}
|
|
1045
|
+
// Return the mimetype of the given filename.
|
|
1046
|
+
static MimeTypeFromFilename(fileName) {
|
|
1047
|
+
const regEx = /(?:\.([^.]+))?$/; // regex to find extension
|
|
1048
|
+
const extension = regEx.exec(fileName)[1];
|
|
1049
|
+
switch (extension) {
|
|
1050
|
+
case 'jpg':
|
|
1051
|
+
case 'jpeg':
|
|
1052
|
+
return 'image/jpeg';
|
|
1053
|
+
case 'png':
|
|
1054
|
+
return 'image/png';
|
|
1055
|
+
case 'bmp':
|
|
1056
|
+
return 'image/bmp';
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Downloads the given file to the users default download location.
|
|
1061
|
+
* @param fileName With or without extension
|
|
1062
|
+
* @param content File content as a string
|
|
1063
|
+
* @param [mimeType = 'text/plain']
|
|
1064
|
+
*/
|
|
1065
|
+
static DownloadFile(fileName, content, mimeType = 'text/plain') {
|
|
1066
|
+
const element = document.createElement('a');
|
|
1067
|
+
element.setAttribute('href', 'data:' + mimeType + ';charset=utf-8,' + encodeURIComponent(content));
|
|
1068
|
+
element.setAttribute('download', fileName);
|
|
1069
|
+
element.style.display = 'none';
|
|
1070
|
+
document.body.appendChild(element);
|
|
1071
|
+
element.click();
|
|
1072
|
+
document.body.removeChild(element);
|
|
1073
|
+
}
|
|
1074
|
+
// Returns the contents of given file as a text string.
|
|
1075
|
+
static ReadAsText(file) {
|
|
1076
|
+
return new Promise((resolve) => {
|
|
1077
|
+
const reader = new FileReader();
|
|
1078
|
+
reader.readAsText(file);
|
|
1079
|
+
reader.onloadend = (event) => {
|
|
1080
|
+
if (event.target.readyState === 2) {
|
|
1081
|
+
resolve(event.target.result);
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
static GetExtensionFromDataUri(dataUri) {
|
|
1087
|
+
return dataUri.replace(/(data:image\/)(.*?)(;base64.*)/gi, '$2');
|
|
1088
|
+
}
|
|
1089
|
+
static CreateDownloadFileNameFromBase64(dataUri) {
|
|
1090
|
+
const ext = this.GetExtensionFromDataUri(dataUri);
|
|
1091
|
+
return 'preview.' + ext;
|
|
1092
|
+
}
|
|
1093
|
+
static DownloadFromDataUri(dataUri, fileName) {
|
|
1094
|
+
const link = document.createElement('a');
|
|
1095
|
+
link.download = fileName;
|
|
1096
|
+
link.href = dataUri;
|
|
1097
|
+
document.body.appendChild(link);
|
|
1098
|
+
link.click();
|
|
1099
|
+
document.body.removeChild(link);
|
|
1100
|
+
}
|
|
1101
|
+
// todo remove once Connector deals with mimetypes and this method isn't used anymore
|
|
1102
|
+
static DocumentBodyToDataUri(documentBody, mimeType) {
|
|
1103
|
+
if (!!documentBody) {
|
|
1104
|
+
return 'data:' + mimeType + ';base64,' + documentBody;
|
|
1105
|
+
}
|
|
1106
|
+
else {
|
|
1107
|
+
return '';
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
static FixUnityUrl(url) {
|
|
1111
|
+
if (url.indexOf('_webplayer') === -1) {
|
|
1112
|
+
url = url.concat('_webplayer.ione3d');
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
url = url.replace('_webplayer', '_webplayer.ione3d');
|
|
1116
|
+
}
|
|
1117
|
+
if (!url.endsWith('.gz')) {
|
|
1118
|
+
url = url.concat('.gz');
|
|
1119
|
+
}
|
|
1120
|
+
return url.replace('.unity3d', '');
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
class DebugUtils {
|
|
1125
|
+
static log(message) {
|
|
1126
|
+
console.log(message);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// @dynamic
|
|
1131
|
+
class VariationUtils {
|
|
1132
|
+
static MaterialCache = new Map();
|
|
1133
|
+
static ClearCache() {
|
|
1134
|
+
this.MaterialCache.clear();
|
|
1135
|
+
}
|
|
1136
|
+
static async LoadVariation(url, fileName, includeVariationFolder = true) {
|
|
1137
|
+
if (!fileName) {
|
|
1138
|
+
return null;
|
|
1139
|
+
}
|
|
1140
|
+
if (!fileName.includes('ione3d')) {
|
|
1141
|
+
fileName = fileName.concat('.ione3d');
|
|
1142
|
+
}
|
|
1143
|
+
const id = fileName.substr(0, fileName.lastIndexOf('.ione3d'));
|
|
1144
|
+
const variationUrl = `${url + (includeVariationFolder ? '/variation' : '')}/${fileName}`;
|
|
1145
|
+
if (this.MaterialCache.has(id)) {
|
|
1146
|
+
return this.MaterialCache.get(id);
|
|
1147
|
+
}
|
|
1148
|
+
if (!window.hasOwnProperty('downloadVariation')) {
|
|
1149
|
+
try {
|
|
1150
|
+
const fileExists = await FileUtils.DoesFileExist(variationUrl);
|
|
1151
|
+
if (!fileExists) {
|
|
1152
|
+
DebugUtils.log(`Failed to find variation file: ${variationUrl}`);
|
|
1153
|
+
return null;
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
const response = await fetch(variationUrl);
|
|
1157
|
+
if (!response.ok) {
|
|
1158
|
+
DebugUtils.log(`Failed to fetch variation file: ${variationUrl} - ${response.status}`);
|
|
1159
|
+
return null;
|
|
1160
|
+
}
|
|
1161
|
+
const compressed = await response.blob();
|
|
1162
|
+
return await VariationUtils.GetVariationSettingsFromFile(id, compressed);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
catch (err) {
|
|
1166
|
+
const mute = err;
|
|
1167
|
+
return null;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
else {
|
|
1171
|
+
try {
|
|
1172
|
+
const file = await window.downloadVariation(variationUrl);
|
|
1173
|
+
const settings = await VariationUtils.GetVariationSettingsFromFile(id, file);
|
|
1174
|
+
this.MaterialCache.set(id, settings);
|
|
1175
|
+
return settings;
|
|
1176
|
+
}
|
|
1177
|
+
catch (err) {
|
|
1178
|
+
console.error('Error loading variation:', err);
|
|
1179
|
+
throw err;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
static async LoadVariationByUrl(materialCode, url) {
|
|
1184
|
+
if (!url) {
|
|
1185
|
+
return null;
|
|
1186
|
+
}
|
|
1187
|
+
if (!url.includes('ione3d')) {
|
|
1188
|
+
url = url.concat('.ione3d');
|
|
1189
|
+
}
|
|
1190
|
+
if (this.MaterialCache.has(materialCode)) {
|
|
1191
|
+
return this.MaterialCache.get(materialCode);
|
|
1192
|
+
}
|
|
1193
|
+
if (!window.hasOwnProperty('downloadVariation')) {
|
|
1194
|
+
// Normal download
|
|
1195
|
+
try {
|
|
1196
|
+
const fileExists = await FileUtils.DoesFileExist(url);
|
|
1197
|
+
if (!fileExists) {
|
|
1198
|
+
DebugUtils.log(`Failed to find variation file: ${url}`);
|
|
1199
|
+
return null;
|
|
1200
|
+
}
|
|
1201
|
+
else {
|
|
1202
|
+
const response = await fetch(url);
|
|
1203
|
+
if (!response.ok) {
|
|
1204
|
+
DebugUtils.log(`Failed to fetch variation file: ${url} - ${response.status}`);
|
|
1205
|
+
return null;
|
|
1206
|
+
}
|
|
1207
|
+
const compressed = await response.blob();
|
|
1208
|
+
return await VariationUtils.GetVariationSettingsFromFile(materialCode, compressed);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
catch (err) {
|
|
1212
|
+
console.error('Error loading variation:', err);
|
|
1213
|
+
throw err;
|
|
1214
|
+
}
|
|
1215
|
+
// console.error('downloadVariation not defined in window global');
|
|
1216
|
+
// throw new Error('downloadVariation not defined in window global');
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
// Headless
|
|
1220
|
+
try {
|
|
1221
|
+
const file = await window.downloadVariation(url);
|
|
1222
|
+
const settings = await VariationUtils.GetVariationSettingsFromFile(materialCode, file);
|
|
1223
|
+
this.MaterialCache.set(materialCode, settings);
|
|
1224
|
+
return settings;
|
|
1225
|
+
}
|
|
1226
|
+
catch (err) {
|
|
1227
|
+
console.error('Error loading variation:', err);
|
|
1228
|
+
throw err;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
static GetUrl(assetPath, url, fileName, includeVariationFolder = true) {
|
|
1233
|
+
if (fileName.indexOf('ione3d') < 0) {
|
|
1234
|
+
fileName = fileName.concat('.ione3d');
|
|
1235
|
+
}
|
|
1236
|
+
if (assetPath && !assetPath.endsWith('/')) {
|
|
1237
|
+
assetPath += '/';
|
|
1238
|
+
}
|
|
1239
|
+
return `${assetPath}${url + (includeVariationFolder ? '/variation' : '')}/${fileName}`;
|
|
1240
|
+
}
|
|
1241
|
+
static GetFloorAssetUrl(assetPath, url, fileName, articleNumber) {
|
|
1242
|
+
if (fileName.indexOf('ione3d') < 0) {
|
|
1243
|
+
fileName = fileName.concat('.ione3d');
|
|
1244
|
+
}
|
|
1245
|
+
if (assetPath && !assetPath.endsWith('/')) {
|
|
1246
|
+
assetPath += '/';
|
|
1247
|
+
}
|
|
1248
|
+
return `${assetPath}${url + '/' + articleNumber}/${fileName}`;
|
|
1249
|
+
}
|
|
1250
|
+
// public static GetMaterialFromName(variationFolder: string, material: any): Promise<MeshStandardMaterial> {
|
|
1251
|
+
// return new Promise((resolve: Function) => {
|
|
1252
|
+
// if (!material) {
|
|
1253
|
+
// resolve(null);
|
|
1254
|
+
// }
|
|
1255
|
+
// if (this.MaterialCache.has(material.name)) {
|
|
1256
|
+
// resolve(this.MaterialCache.get(material.name).clone());
|
|
1257
|
+
// } else {
|
|
1258
|
+
// VariationUtils.LoadVariation(variationFolder, material.name, false).then((settings: VariationSettings) => {
|
|
1259
|
+
// if (settings) {
|
|
1260
|
+
// AssetUtils.CreateMaterialFromAsset(settings).then((materialObj: Material) => {
|
|
1261
|
+
// const materialParams: MeshStandardMaterialParameters = {};
|
|
1262
|
+
// materialParams.name = material.name;
|
|
1263
|
+
// materialParams.map = materialObj.texture;
|
|
1264
|
+
// materialParams.normalMap = materialObj.normal;
|
|
1265
|
+
// materialParams.aoMap = materialObj.ao;
|
|
1266
|
+
// materialParams.roughnessMap = materialObj.roughness;
|
|
1267
|
+
// materialParams.metalnessMap = materialObj.metalness;
|
|
1268
|
+
// materialParams.roughness = 1;
|
|
1269
|
+
// materialParams.metalness = 1;
|
|
1270
|
+
// const pbrMat: MeshStandardMaterial = new MeshStandardMaterial(materialParams);
|
|
1271
|
+
// this.MaterialCache.set(material.name, pbrMat);
|
|
1272
|
+
// resolve(pbrMat.clone());
|
|
1273
|
+
// });
|
|
1274
|
+
// } else {
|
|
1275
|
+
// resolve(material);
|
|
1276
|
+
// }
|
|
1277
|
+
// });
|
|
1278
|
+
// }
|
|
1279
|
+
// });
|
|
1280
|
+
// }
|
|
1281
|
+
static async GetVariationSettingsFromFile(id, compressedFile) {
|
|
1282
|
+
// TODO CHECK with Patrick
|
|
1283
|
+
if (!compressedFile) {
|
|
1284
|
+
return null;
|
|
1285
|
+
}
|
|
1286
|
+
// const zipContent = await VariationUtils.GetZipContent(compressedFile);
|
|
1287
|
+
// const variationSettings: VariationSettings = new VariationSettings();
|
|
1288
|
+
// let index;
|
|
1289
|
+
// variationSettings.id = id;
|
|
1290
|
+
//
|
|
1291
|
+
// if (zipContent) {
|
|
1292
|
+
// if (zipContent.files['material.glb']) {
|
|
1293
|
+
// const material: string = await zipContent.files['material.glb'].async('arraybuffer');
|
|
1294
|
+
// variationSettings.material = await VariationUtils.LoadMaterialFromGlb(material);
|
|
1295
|
+
// } else {
|
|
1296
|
+
// if (zipContent.files['index.json']) {
|
|
1297
|
+
// const indexFile: string = await zipContent.files['index.json'].async('string');
|
|
1298
|
+
// index = JSON.parse(indexFile);
|
|
1299
|
+
// }
|
|
1300
|
+
// if (index) {
|
|
1301
|
+
// await VariationUtils.CreateSettingsBasedOnIndex(index, variationSettings, zipContent);
|
|
1302
|
+
// } else {
|
|
1303
|
+
// await VariationUtils.CreateSettingsBasedOnFileName(variationSettings, zipContent);
|
|
1304
|
+
// }
|
|
1305
|
+
// }
|
|
1306
|
+
// }
|
|
1307
|
+
// return variationSettings;
|
|
1308
|
+
const zipContent = await VariationUtils.GetZipContent(compressedFile);
|
|
1309
|
+
const variationSettings = new VariationSettings();
|
|
1310
|
+
let index;
|
|
1311
|
+
variationSettings.id = id;
|
|
1312
|
+
if (zipContent.files.hasOwnProperty('index.json')) {
|
|
1313
|
+
const indexFile = await zipContent.files['index.json'].async('string');
|
|
1314
|
+
index = JSON.parse(indexFile);
|
|
1315
|
+
}
|
|
1316
|
+
if (index) {
|
|
1317
|
+
await VariationUtils.CreateSettingsBasedOnIndex(index, variationSettings, zipContent);
|
|
1318
|
+
}
|
|
1319
|
+
else {
|
|
1320
|
+
await VariationUtils.CreateSettingsBasedOnFileName(variationSettings, zipContent);
|
|
1321
|
+
}
|
|
1322
|
+
return variationSettings;
|
|
1323
|
+
}
|
|
1324
|
+
static async CreateSettingsBasedOnIndex(index, variationSettings, zipContent) {
|
|
1325
|
+
if (index.normalFile) {
|
|
1326
|
+
variationSettings.normal = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.normalFile], index.normalFile);
|
|
1327
|
+
variationSettings.normalFilename = index.normalFile;
|
|
1328
|
+
}
|
|
1329
|
+
if (index.diffuseFile) {
|
|
1330
|
+
variationSettings.texture = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.diffuseFile], index.diffuseFile);
|
|
1331
|
+
variationSettings.textureFilename = index.diffuseFile;
|
|
1332
|
+
}
|
|
1333
|
+
if (index.ormFile) {
|
|
1334
|
+
variationSettings.orm = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.ormFile], index.ormFile);
|
|
1335
|
+
variationSettings.ormFilename = index.ormFile;
|
|
1336
|
+
}
|
|
1337
|
+
else {
|
|
1338
|
+
if (index.aoFile) {
|
|
1339
|
+
variationSettings.ao = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.aoFile], index.aoFile);
|
|
1340
|
+
variationSettings.aoFilename = index.aoFile;
|
|
1341
|
+
}
|
|
1342
|
+
if (index.metalnessFile) {
|
|
1343
|
+
variationSettings.metalness = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.metalnessFile], index.metalnessFile);
|
|
1344
|
+
variationSettings.metalnessFilename = index.metalnessFile;
|
|
1345
|
+
}
|
|
1346
|
+
if (index.roughnessFile) {
|
|
1347
|
+
variationSettings.roughness = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.roughnessFile], index.roughnessFile);
|
|
1348
|
+
variationSettings.roughnessFilename = index.roughnessFile;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (index.displacementFile) {
|
|
1352
|
+
variationSettings.displacement = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.displacementFile], index.displacementFile);
|
|
1353
|
+
variationSettings.displacementFilename = index.displacementFile;
|
|
1354
|
+
}
|
|
1355
|
+
if (index.emissiveFile) {
|
|
1356
|
+
variationSettings.emissive = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.emissiveFile], index.emissiveFile);
|
|
1357
|
+
variationSettings.emissiveFilename = index.emissiveFile;
|
|
1358
|
+
}
|
|
1359
|
+
if (index.envMapFile) {
|
|
1360
|
+
variationSettings.envMap = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.envMapFile], index.envMapFile);
|
|
1361
|
+
variationSettings.envMapFilename = index.envMapFile;
|
|
1362
|
+
}
|
|
1363
|
+
if (index.sheenColorMapFile) {
|
|
1364
|
+
variationSettings.sheenColorMap = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.sheenColorMapFile], index.sheenColorMapFile);
|
|
1365
|
+
variationSettings.sheenColorMapFilename = index.sheenColorMapFile;
|
|
1366
|
+
}
|
|
1367
|
+
if (index.sheenRoughnessMapFile) {
|
|
1368
|
+
variationSettings.sheenRoughnessMap = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.sheenRoughnessMapFile], index.sheenRoughnessMapFile);
|
|
1369
|
+
variationSettings.sheenRoughnessMapFilename = index.sheenColorMapFile;
|
|
1370
|
+
}
|
|
1371
|
+
if (index.transmissionMapFile) {
|
|
1372
|
+
variationSettings.transmissionMap = await VariationUtils.LoadFileContentFromZip(zipContent.files[index.transmissionMapFile], index.transmissionMapFile);
|
|
1373
|
+
variationSettings.transmissionMapFilename = index.transmissionMapFile;
|
|
1374
|
+
}
|
|
1375
|
+
if (index.repeat) {
|
|
1376
|
+
variationSettings.settings.repeatx = index.repeat.repeatx;
|
|
1377
|
+
variationSettings.settings.repeaty = index.repeat.repeaty;
|
|
1378
|
+
}
|
|
1379
|
+
variationSettings.settings.metalness = index.metalness;
|
|
1380
|
+
variationSettings.settings.roughness = index.roughness;
|
|
1381
|
+
variationSettings.sheen = index.sheen;
|
|
1382
|
+
if (index.sheenColor) {
|
|
1383
|
+
variationSettings.sheenColor = new Color(index.sheenColor.r, index.sheenColor.g, index.sheenColor.b);
|
|
1384
|
+
}
|
|
1385
|
+
variationSettings.sheenRoughness = index.sheenRoughness;
|
|
1386
|
+
variationSettings.envMapIntensity = index.envMapIntensity;
|
|
1387
|
+
variationSettings.transparent = index.transparent;
|
|
1388
|
+
variationSettings.opacity = index.opacity;
|
|
1389
|
+
if (index.emissiveValue) {
|
|
1390
|
+
variationSettings.emissiveValue = new Color(index.emissiveValue.r, index.emissiveValue.g, index.emissiveValue.b);
|
|
1391
|
+
}
|
|
1392
|
+
variationSettings.emissiveIntensity = index.emissiveIntensity;
|
|
1393
|
+
variationSettings.reflectivity = index.reflectivity;
|
|
1394
|
+
variationSettings.displacementValue = index.displacementValue;
|
|
1395
|
+
variationSettings.side = index.side;
|
|
1396
|
+
variationSettings.transmission = index.transmission;
|
|
1397
|
+
variationSettings.ior = index.ior;
|
|
1398
|
+
variationSettings.thickness = index.thickness;
|
|
1399
|
+
variationSettings.specularIntensity = index.specularIntensity;
|
|
1400
|
+
}
|
|
1401
|
+
static async CreateSettingsBasedOnFileName(variationSettings, zipContent) {
|
|
1402
|
+
const allLoaded = [];
|
|
1403
|
+
for (const fileName in zipContent.files) {
|
|
1404
|
+
if (zipContent.files.hasOwnProperty(fileName)) {
|
|
1405
|
+
const file = await zipContent.files[fileName];
|
|
1406
|
+
if (file.name.toLowerCase().indexOf('normal') > -1 && this.FileIsImage(file.name)) {
|
|
1407
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((normalFile) => {
|
|
1408
|
+
variationSettings.normal = `data:image/${this.GetBase64FileType(file.name)};base64,${normalFile}`;
|
|
1409
|
+
variationSettings.normalFilename = fileName;
|
|
1410
|
+
}));
|
|
1411
|
+
}
|
|
1412
|
+
else if (file.name.toLowerCase().indexOf('ao') > -1 && this.FileIsImage(file.name)) {
|
|
1413
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((aoFile) => {
|
|
1414
|
+
variationSettings.ao = `data:image/${this.GetBase64FileType(file.name)};base64,${aoFile}`;
|
|
1415
|
+
variationSettings.aoFilename = fileName;
|
|
1416
|
+
}));
|
|
1417
|
+
}
|
|
1418
|
+
else if (file.name.toLowerCase().indexOf('metalness') > -1 && this.FileIsImage(file.name)) {
|
|
1419
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((metalnessFile) => {
|
|
1420
|
+
variationSettings.metalness = `data:image/${this.GetBase64FileType(file.name)};base64,${metalnessFile}`;
|
|
1421
|
+
variationSettings.metalnessFilename = fileName;
|
|
1422
|
+
}));
|
|
1423
|
+
}
|
|
1424
|
+
else if (file.name.toLowerCase().indexOf('roughness') > -1 && this.FileIsImage(file.name)) {
|
|
1425
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((roughnessFile) => {
|
|
1426
|
+
variationSettings.roughness = `data:image/${this.GetBase64FileType(file.name)};base64,${roughnessFile}`;
|
|
1427
|
+
variationSettings.roughnessFilename = fileName;
|
|
1428
|
+
}));
|
|
1429
|
+
}
|
|
1430
|
+
else if (file.name.toLowerCase().indexOf('diffuse') > -1 && this.FileIsImage(file.name)) {
|
|
1431
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((diffuseFile) => {
|
|
1432
|
+
variationSettings.texture = `data:image/${this.GetBase64FileType(file.name)};base64,${diffuseFile}`;
|
|
1433
|
+
variationSettings.textureFilename = fileName;
|
|
1434
|
+
}));
|
|
1435
|
+
}
|
|
1436
|
+
else if (file.name.toLowerCase().indexOf('displacement') > -1 && this.FileIsImage(file.name)) {
|
|
1437
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((displacementFile) => {
|
|
1438
|
+
variationSettings.displacement = `data:image/${this.GetBase64FileType(file.name)};base64,${displacementFile}`;
|
|
1439
|
+
variationSettings.displacementFilename = fileName;
|
|
1440
|
+
}));
|
|
1441
|
+
}
|
|
1442
|
+
else if (file.name.toLowerCase().indexOf('emissive') > -1 && this.FileIsImage(file.name)) {
|
|
1443
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((emissiveFile) => {
|
|
1444
|
+
variationSettings.emissive = `data:image/${this.GetBase64FileType(file.name)};base64,${emissiveFile}`;
|
|
1445
|
+
variationSettings.emissiveFilename = fileName;
|
|
1446
|
+
}));
|
|
1447
|
+
}
|
|
1448
|
+
else if (file.name.toLowerCase().indexOf('envMap') > -1 && this.FileIsImage(file.name)) {
|
|
1449
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((envMapFile) => {
|
|
1450
|
+
variationSettings.envMap = `data:image/${this.GetBase64FileType(file.name)};base64,${envMapFile}`;
|
|
1451
|
+
variationSettings.envMapFilename = fileName;
|
|
1452
|
+
}));
|
|
1453
|
+
}
|
|
1454
|
+
else if (file.name.toLowerCase().indexOf('sheenColorMap') > -1 && this.FileIsImage(file.name)) {
|
|
1455
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((sheenColorMapFile) => {
|
|
1456
|
+
variationSettings.sheenColorMap = `data:image/${this.GetBase64FileType(file.name)};base64,${sheenColorMapFile}`;
|
|
1457
|
+
variationSettings.sheenColorMapFilename = fileName;
|
|
1458
|
+
}));
|
|
1459
|
+
}
|
|
1460
|
+
else if (file.name.toLowerCase().indexOf('sheenRoughnessMap') > -1 && this.FileIsImage(file.name)) {
|
|
1461
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((sheenRoughnessMapFile) => {
|
|
1462
|
+
variationSettings.sheenRoughnessMap = `data:image/${this.GetBase64FileType(file.name)};base64,${sheenRoughnessMapFile}`;
|
|
1463
|
+
variationSettings.sheenRoughnessMapFilename = fileName;
|
|
1464
|
+
}));
|
|
1465
|
+
}
|
|
1466
|
+
else if (file.name.toLowerCase().indexOf('transmissionMap') > -1 && this.FileIsImage(file.name)) {
|
|
1467
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((transmissionMapFile) => {
|
|
1468
|
+
variationSettings.transmissionMap = `data:image/${this.GetBase64FileType(file.name)};base64,${transmissionMapFile}`;
|
|
1469
|
+
variationSettings.transmissionMapFilename = fileName;
|
|
1470
|
+
}));
|
|
1471
|
+
}
|
|
1472
|
+
else if (file.name.indexOf('.jp') > -1) {
|
|
1473
|
+
allLoaded.push(zipContent.files[fileName].async('base64').then((textureFile) => {
|
|
1474
|
+
variationSettings.texture = 'data:image/jpeg;base64,' + textureFile;
|
|
1475
|
+
variationSettings.textureFilename = fileName;
|
|
1476
|
+
}));
|
|
1477
|
+
}
|
|
1478
|
+
else if (file.name.indexOf('.json') > -1) {
|
|
1479
|
+
allLoaded.push(zipContent.files[fileName].async('string').then((settingsFile) => {
|
|
1480
|
+
const settingsFileObj = JSON.parse(settingsFile);
|
|
1481
|
+
for (const key in settingsFileObj) {
|
|
1482
|
+
if (settingsFileObj.hasOwnProperty(key)) {
|
|
1483
|
+
variationSettings.settings[key] = settingsFileObj[key];
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}));
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
await Promise.all(allLoaded);
|
|
1491
|
+
}
|
|
1492
|
+
static LoadMaterialFromJson(material) {
|
|
1493
|
+
const loader = new MaterialLoader();
|
|
1494
|
+
if (material.textures) {
|
|
1495
|
+
const textures = {};
|
|
1496
|
+
for (let i = 0; i < material.textures.length; i++) {
|
|
1497
|
+
textures[material.textures[i].uuid] = material.textures[i];
|
|
1498
|
+
}
|
|
1499
|
+
loader.setTextures(textures);
|
|
1500
|
+
}
|
|
1501
|
+
return loader.parse(material);
|
|
1502
|
+
}
|
|
1503
|
+
static LoadMaterialFromGlb(material) {
|
|
1504
|
+
return new Promise(async (resolve, reject) => {
|
|
1505
|
+
if (!window.hasOwnProperty('loadGLTF')) {
|
|
1506
|
+
console.error('loadGLTF not defined in window global');
|
|
1507
|
+
return reject();
|
|
1508
|
+
}
|
|
1509
|
+
const obj = await window.loadGLTF(material, false);
|
|
1510
|
+
if (obj) {
|
|
1511
|
+
return resolve(obj.children[0].material);
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
static LoadFileContentFromZip(zip, fileName, base64 = true) {
|
|
1516
|
+
return new Promise((resolve) => {
|
|
1517
|
+
if (zip && fileName) {
|
|
1518
|
+
zip.async(base64 ? 'base64' : 'string').then((fileContent) => {
|
|
1519
|
+
if (base64) {
|
|
1520
|
+
resolve(`data:image/${this.GetBase64FileType(fileName)};base64,${fileContent}`);
|
|
1521
|
+
}
|
|
1522
|
+
else {
|
|
1523
|
+
resolve(fileContent);
|
|
1524
|
+
}
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
else {
|
|
1528
|
+
resolve(undefined);
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
static FileIsImage(fileName) {
|
|
1533
|
+
const ext = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length).toLowerCase();
|
|
1534
|
+
switch (ext) {
|
|
1535
|
+
case 'jpg':
|
|
1536
|
+
case 'jpeg':
|
|
1537
|
+
case 'png':
|
|
1538
|
+
case 'bmp':
|
|
1539
|
+
return true;
|
|
1540
|
+
default:
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
static GetBase64FileType(fileName) {
|
|
1545
|
+
const ext = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length).toLowerCase();
|
|
1546
|
+
switch (ext) {
|
|
1547
|
+
case 'jpg':
|
|
1548
|
+
case 'jpeg':
|
|
1549
|
+
return 'jpeg';
|
|
1550
|
+
case 'png':
|
|
1551
|
+
return 'png';
|
|
1552
|
+
case 'bmp':
|
|
1553
|
+
return 'bmp';
|
|
1554
|
+
default:
|
|
1555
|
+
return 'jpeg';
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
// Get the content
|
|
1559
|
+
static async GetZipContent(file) {
|
|
1560
|
+
try {
|
|
1561
|
+
const jszip = new JSZip();
|
|
1562
|
+
return await jszip.loadAsync(file);
|
|
1563
|
+
}
|
|
1564
|
+
catch (e) {
|
|
1565
|
+
return null;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
class Variation {
|
|
1571
|
+
decoId;
|
|
1572
|
+
brandId;
|
|
1573
|
+
gameObjectName;
|
|
1574
|
+
node;
|
|
1575
|
+
optionText;
|
|
1576
|
+
supplierArticleNr;
|
|
1577
|
+
materialId;
|
|
1578
|
+
material;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
class VariationCacheHelper {
|
|
1582
|
+
_variations = [];
|
|
1583
|
+
assetPath = '';
|
|
1584
|
+
threeDAssetPath = '';
|
|
1585
|
+
needsMaterials = true;
|
|
1586
|
+
debug;
|
|
1587
|
+
destroy() {
|
|
1588
|
+
this._variations.length = 0;
|
|
1589
|
+
}
|
|
1590
|
+
preloadVariations(schema, decoNodes, articleAssetPath = '') {
|
|
1591
|
+
if (!articleAssetPath.endsWith('/')) {
|
|
1592
|
+
articleAssetPath += '/';
|
|
1593
|
+
}
|
|
1594
|
+
decoNodes.forEach((decoNode) => {
|
|
1595
|
+
let fileName;
|
|
1596
|
+
let fileUrl;
|
|
1597
|
+
let includeVariationFolder = true;
|
|
1598
|
+
if (decoNode.materialUrl) {
|
|
1599
|
+
const fileNameFromUrl = decoNode.materialUrl ? decoNode.materialUrl.substr(decoNode.materialUrl.lastIndexOf('/') + 1, decoNode.materialUrl.length) : null;
|
|
1600
|
+
fileName = fileNameFromUrl ? fileNameFromUrl.substr(0, fileNameFromUrl.lastIndexOf('.')) : null; // chop extension
|
|
1601
|
+
fileUrl = decoNode.materialUrl ? decoNode.materialUrl.substr(0, decoNode.materialUrl.lastIndexOf('/')) : null;
|
|
1602
|
+
includeVariationFolder = false;
|
|
1603
|
+
}
|
|
1604
|
+
else if (decoNode.gameObjectName) {
|
|
1605
|
+
fileName = decoNode.gameObjectName;
|
|
1606
|
+
fileUrl = (articleAssetPath ? articleAssetPath : this.threeDAssetPath) + schema;
|
|
1607
|
+
}
|
|
1608
|
+
if (fileUrl && fileName && this.needsMaterials) {
|
|
1609
|
+
if (!this._get(fileName)) {
|
|
1610
|
+
const settings = this._createSettingsForFileName(fileName);
|
|
1611
|
+
VariationUtils.LoadVariation(fileUrl, fileName, includeVariationFolder).then((variationSettings) => {
|
|
1612
|
+
settings.loading = false;
|
|
1613
|
+
settings.loaded.next(variationSettings);
|
|
1614
|
+
if (variationSettings) {
|
|
1615
|
+
this._set(variationSettings);
|
|
1616
|
+
}
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
async preloadVariationsAsync(schema, decoNodes, articleAssetPath = '') {
|
|
1623
|
+
const promises = [];
|
|
1624
|
+
decoNodes.forEach((decoNode, index, array) => {
|
|
1625
|
+
let fileName;
|
|
1626
|
+
let fileUrl;
|
|
1627
|
+
let includeVariationFolder = true;
|
|
1628
|
+
if (decoNode.materialUrl) {
|
|
1629
|
+
const fileNameFromUrl = decoNode.materialUrl ? decoNode.materialUrl.substr(decoNode.materialUrl.lastIndexOf('/') + 1, decoNode.materialUrl.length) : null;
|
|
1630
|
+
fileName = fileNameFromUrl ? fileNameFromUrl.substr(0, fileNameFromUrl.lastIndexOf('.')) : null; // chop extension
|
|
1631
|
+
fileUrl = decoNode.materialUrl ? decoNode.materialUrl.substr(0, decoNode.materialUrl.lastIndexOf('/')) : null;
|
|
1632
|
+
includeVariationFolder = false;
|
|
1633
|
+
}
|
|
1634
|
+
else if (decoNode instanceof DecoNode && decoNode.gameObjectName) {
|
|
1635
|
+
fileName = decoNode.gameObjectName;
|
|
1636
|
+
fileUrl = (articleAssetPath ? articleAssetPath : this.threeDAssetPath) + schema;
|
|
1637
|
+
}
|
|
1638
|
+
else if ((decoNode instanceof Answer || decoNode instanceof SelectorStructure) && decoNode.gameObject) {
|
|
1639
|
+
fileName = decoNode.gameObject;
|
|
1640
|
+
fileUrl = (articleAssetPath ? articleAssetPath : this.threeDAssetPath) + schema;
|
|
1641
|
+
}
|
|
1642
|
+
if (fileName && !this._get(fileName) && this.needsMaterials) {
|
|
1643
|
+
const settings = this._createSettingsForFileName(fileName);
|
|
1644
|
+
promises.push(new Promise(resolve => {
|
|
1645
|
+
VariationUtils.LoadVariation(fileUrl, fileName, includeVariationFolder).then((variationSettings) => {
|
|
1646
|
+
settings.loading = false;
|
|
1647
|
+
settings.loaded.next(variationSettings);
|
|
1648
|
+
if (variationSettings) {
|
|
1649
|
+
this._set(variationSettings);
|
|
1650
|
+
resolve();
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
}));
|
|
1654
|
+
}
|
|
1655
|
+
});
|
|
1656
|
+
await Promise.all(promises);
|
|
1657
|
+
}
|
|
1658
|
+
log(message) {
|
|
1659
|
+
if (this.debug) {
|
|
1660
|
+
this.debug(message);
|
|
1661
|
+
console.log(new Date(), message);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
async loadCachedVariation(fileName) {
|
|
1665
|
+
if (!fileName) {
|
|
1666
|
+
return null;
|
|
1667
|
+
}
|
|
1668
|
+
if (this._get(fileName)) {
|
|
1669
|
+
const settings = this._get(fileName);
|
|
1670
|
+
if (settings.loading) {
|
|
1671
|
+
return await this._waitForVariationToLoad(settings);
|
|
1672
|
+
}
|
|
1673
|
+
return settings;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
_get(id) {
|
|
1677
|
+
const len = this._variations.length;
|
|
1678
|
+
for (let i = 0; i < len; i++) {
|
|
1679
|
+
if (this._variations[i].id && this._variations[i].id === id) {
|
|
1680
|
+
return this._variations[i];
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
_set(variations) {
|
|
1685
|
+
const idx = this._variations.findIndex(v => v.id === variations.id);
|
|
1686
|
+
if (idx > -1) {
|
|
1687
|
+
this._variations[idx] = variations;
|
|
1688
|
+
}
|
|
1689
|
+
else {
|
|
1690
|
+
this._variations.push(variations);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
_waitForVariationToLoad(settings) {
|
|
1694
|
+
return new Promise((resolve) => {
|
|
1695
|
+
settings.loaded.subscribe((value) => {
|
|
1696
|
+
resolve(value);
|
|
1697
|
+
});
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
_createSettingsForFileName(fileName) {
|
|
1701
|
+
const settings = new VariationSettings();
|
|
1702
|
+
settings.id = fileName;
|
|
1703
|
+
settings.loading = true;
|
|
1704
|
+
this._variations.push(settings);
|
|
1705
|
+
return settings;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
class VariationHelper extends VariationCacheHelper {
|
|
1710
|
+
loadedAsset;
|
|
1711
|
+
_lastKnownVariations = new Map();
|
|
1712
|
+
clearCache() {
|
|
1713
|
+
const variationMap = Array.from(this._lastKnownVariations.values());
|
|
1714
|
+
variationMap.forEach((variations) => {
|
|
1715
|
+
variations.forEach((variation) => {
|
|
1716
|
+
try {
|
|
1717
|
+
if (variation.material) {
|
|
1718
|
+
if (variation.material.texture) {
|
|
1719
|
+
variation.material.texture.dispose();
|
|
1720
|
+
}
|
|
1721
|
+
if (variation.material.normal) {
|
|
1722
|
+
variation.material.normal.dispose();
|
|
1723
|
+
}
|
|
1724
|
+
if (variation.material.metalness) {
|
|
1725
|
+
variation.material.metalness.dispose();
|
|
1726
|
+
}
|
|
1727
|
+
if (variation.material.roughness) {
|
|
1728
|
+
variation.material.roughness.dispose();
|
|
1729
|
+
}
|
|
1730
|
+
if (variation.material.ao) {
|
|
1731
|
+
variation.material.ao.dispose();
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
catch (e) {
|
|
1736
|
+
DebugUtils.log('Failed to dispose material: ' + e);
|
|
1737
|
+
}
|
|
1738
|
+
});
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
async loadPart(assetPath, parts, obj, usePbr = false) {
|
|
1742
|
+
try {
|
|
1743
|
+
const len = parts.length;
|
|
1744
|
+
for (let i = 0; i < len; i++) {
|
|
1745
|
+
if (parts[i].decoNode && parts[i].decoNode.gameObjectName && parts[i].decoNode.type === DecoNodeType.Part) {
|
|
1746
|
+
let partSettings;
|
|
1747
|
+
partSettings = await this.loadCachedVariation(parts[i].decoNode.materialUrl ? parts[i].decoNode.materialCode : (parts[i].decoNode.gameObjectName || parts[i].decoId));
|
|
1748
|
+
if (partSettings) {
|
|
1749
|
+
const partVariation = new Variation();
|
|
1750
|
+
partVariation.decoId = parseFloat(parts[i].decoNode.id);
|
|
1751
|
+
partVariation.brandId = parts[i].decoNode.brandId;
|
|
1752
|
+
partVariation.gameObjectName = parts[i].decoNode.gameObjectName;
|
|
1753
|
+
partVariation.material = await AssetUtils.CreateMaterialFromAsset(partSettings);
|
|
1754
|
+
this.loadedAsset = VariationUtils.GetUrl(assetPath, parts[i].schema, parts[i].decoNode.gameObjectName || parts[i].decoId);
|
|
1755
|
+
// parts[i].variation = partVariation;
|
|
1756
|
+
this._applyMaterialPart(partVariation, parts[i].node, obj, usePbr);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
catch (e) {
|
|
1762
|
+
DebugUtils.log('Failed to load part: ' + e);
|
|
1763
|
+
// console.error(e);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
async loadVariation(assetPath, parts, obj, usePbr = false) {
|
|
1767
|
+
return new Promise(async (resolve, reject) => {
|
|
1768
|
+
try {
|
|
1769
|
+
const len = parts.length;
|
|
1770
|
+
for (let i = 0; i < len; i++) {
|
|
1771
|
+
const variations = parts[i].variations;
|
|
1772
|
+
if (!variations || variations.length === 0) {
|
|
1773
|
+
if (this._getLastKnownVariations(`${parts[i].nodeId}_${parts[i].node}`)) {
|
|
1774
|
+
parts[i].variations = this._getLastKnownVariations(`${parts[i].nodeId}_${parts[i].node}`);
|
|
1775
|
+
this._applyVariations(parts[i], obj, usePbr);
|
|
1776
|
+
continue;
|
|
1777
|
+
}
|
|
1778
|
+
else {
|
|
1779
|
+
continue;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
const lastKnownVariations = [];
|
|
1783
|
+
const variationPromise = [];
|
|
1784
|
+
for (let j = 0; j < variations.length; j++) {
|
|
1785
|
+
variationPromise.push(this.loadCachedVariation(variations[j].materialUrl ? variations[j].materialCode : (variations[j].gameObjectName || parts[i].decoId)).then(async (variationSettings) => {
|
|
1786
|
+
const newVariation = this._createVariationFromNode(variations[j]);
|
|
1787
|
+
newVariation.material = await AssetUtils.CreateMaterialFromAsset(variationSettings);
|
|
1788
|
+
this.loadedAsset = variations[j].materialUrl ? variations[j].materialUrl : VariationUtils.GetUrl(assetPath, parts[i].schema, variations[j].gameObjectName || parts[i].decoId);
|
|
1789
|
+
lastKnownVariations.push(newVariation);
|
|
1790
|
+
}));
|
|
1791
|
+
}
|
|
1792
|
+
await Promise.all(variationPromise);
|
|
1793
|
+
this._setLastKnownVariations(`${parts[i].nodeId}_${parts[i].node}`, lastKnownVariations);
|
|
1794
|
+
parts[i].variations = lastKnownVariations;
|
|
1795
|
+
this._applyVariations(parts[i], obj, usePbr);
|
|
1796
|
+
}
|
|
1797
|
+
resolve();
|
|
1798
|
+
}
|
|
1799
|
+
catch (e) {
|
|
1800
|
+
DebugUtils.log('Failed to load variation: ' + e);
|
|
1801
|
+
// console.error(e);
|
|
1802
|
+
reject();
|
|
1803
|
+
}
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
async loadVariationFromLocalFile(id, file, obj) {
|
|
1807
|
+
try {
|
|
1808
|
+
const variationSettings = await VariationUtils.GetVariationSettingsFromFile(id, file);
|
|
1809
|
+
const material = await AssetUtils.CreateMaterialFromAsset(variationSettings);
|
|
1810
|
+
this._applyMaterial(obj, material);
|
|
1811
|
+
}
|
|
1812
|
+
catch (e) {
|
|
1813
|
+
console.error(e);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
async loadVariationForMaterial(gameObject) {
|
|
1817
|
+
const partSettings = await this.loadCachedVariation(gameObject);
|
|
1818
|
+
if (partSettings) {
|
|
1819
|
+
const partVariation = new Variation();
|
|
1820
|
+
partVariation.gameObjectName = gameObject;
|
|
1821
|
+
partVariation.material = await AssetUtils.CreateMaterialFromAsset(partSettings);
|
|
1822
|
+
return this._setMeshMaterialFromVariation(gameObject, partVariation.material, true);
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
async loadVariationByAssetUrl(assetUrl) {
|
|
1826
|
+
const fileName = assetUrl.substring(assetUrl.lastIndexOf('/') + 1);
|
|
1827
|
+
const id = 'default_' + fileName.substring(0, fileName.lastIndexOf('.'));
|
|
1828
|
+
const variationSettings = await VariationUtils.LoadVariationByUrl(id, assetUrl);
|
|
1829
|
+
if (variationSettings) {
|
|
1830
|
+
const materialFromAsset = await AssetUtils.CreateMaterialFromAsset(variationSettings);
|
|
1831
|
+
if (materialFromAsset) {
|
|
1832
|
+
return this._setMeshMaterialFromVariation(id, materialFromAsset, true);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
async createVariationForMaterialPreview(compressedZip) {
|
|
1837
|
+
const id = String(Math.floor(Math.random() * 10) + 1);
|
|
1838
|
+
const variationSettings = await VariationUtils.GetVariationSettingsFromFile(id, compressedZip);
|
|
1839
|
+
if (variationSettings) {
|
|
1840
|
+
const materialFromAsset = await AssetUtils.CreateMaterialFromAsset(variationSettings);
|
|
1841
|
+
if (materialFromAsset) {
|
|
1842
|
+
return this._setMeshMaterialFromVariation(id, materialFromAsset, true);
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
_applyMaterialPart(partMaterial, nodeId, obj, usePbr = false) {
|
|
1847
|
+
const children = this._getChildrenFilterByProp(obj, 'selection', 'node', nodeId);
|
|
1848
|
+
const len = children.length;
|
|
1849
|
+
for (let i = 0; i < len; i++) {
|
|
1850
|
+
const child = children[i];
|
|
1851
|
+
if (child !== null && child !== undefined) {
|
|
1852
|
+
child.traverse((mesh) => {
|
|
1853
|
+
if (mesh instanceof Mesh && partMaterial) {
|
|
1854
|
+
if (Array.isArray(mesh.material)) { // multimaterial support
|
|
1855
|
+
for (let j = 0, jlen = mesh.material.length; j < jlen; j++) {
|
|
1856
|
+
if (mesh.material[j].name.toLowerCase().indexOf('fixed_frame') !== -1) {
|
|
1857
|
+
mesh.material[j] = this._setMeshMaterialFromVariation(mesh.material[j].name, partMaterial, usePbr);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
else {
|
|
1862
|
+
if (mesh.material.name.toLowerCase().indexOf('fixed_frame') !== -1) {
|
|
1863
|
+
mesh.material = this._setMeshMaterialFromVariation(mesh.material.name, partMaterial, usePbr);
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
_applyVariations(part, obj, usePbr = false) {
|
|
1872
|
+
const children = this._getChildrenFilterByProp(obj, 'selection', 'node', part.node);
|
|
1873
|
+
const len = children.length;
|
|
1874
|
+
for (let i = 0; i < len; i++) {
|
|
1875
|
+
const child = children[i];
|
|
1876
|
+
if (child !== null && child !== undefined) {
|
|
1877
|
+
child.traverse((mesh) => {
|
|
1878
|
+
if (mesh instanceof Mesh && part.variations && part.variations.length > 0 && mesh.name.toLowerCase().indexOf('c_')) {
|
|
1879
|
+
//if ((mesh instanceof Mesh || mesh.constructor.name === 'Mesh') && part.variations && part.variations.length > 0 && mesh.name.toLowerCase().indexOf('c_')) {
|
|
1880
|
+
for (let j = 0; j < part.variations.length; j++) {
|
|
1881
|
+
const variation = part.variations[j];
|
|
1882
|
+
if (variation.material) {
|
|
1883
|
+
const materialToSearch = !!variation.materialId ? variation.materialId.toLowerCase() : 'default';
|
|
1884
|
+
if (Array.isArray(mesh.material)) { // multimaterial support
|
|
1885
|
+
for (let m = 0, mlen = mesh.material.length; m < mlen; m++) {
|
|
1886
|
+
if ((variation.materialId && mesh.material[m].name.toLowerCase() === materialToSearch) ||
|
|
1887
|
+
(!variation.materialId && mesh.material[m].name.toLowerCase().indexOf(materialToSearch) !== -1)) {
|
|
1888
|
+
mesh.material[m] = this._setMeshMaterialFromVariation(mesh.material[m].name, variation.material, usePbr);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
else {
|
|
1893
|
+
if ((variation.materialId && mesh.material.name.toLowerCase() === materialToSearch) ||
|
|
1894
|
+
(!variation.materialId && mesh.material.name.toLowerCase().indexOf(materialToSearch) !== -1)) {
|
|
1895
|
+
mesh.material = this._setMeshMaterialFromVariation(mesh.material.name, variation.material, usePbr);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
_applyMaterial(obj, material) {
|
|
1906
|
+
obj.traverse((mesh) => {
|
|
1907
|
+
if (mesh instanceof Mesh) {
|
|
1908
|
+
if (Array.isArray(mesh.material)) { // multimaterial support
|
|
1909
|
+
for (let m = 0, mlen = mesh.material.length; m < mlen; m++) {
|
|
1910
|
+
if (mesh.material[m].name.toLowerCase().indexOf('default') !== -1) {
|
|
1911
|
+
ObjectUtils.DisposeMaterial(mesh.material[m]);
|
|
1912
|
+
mesh.material[m] = this._setMeshMaterialFromVariation(mesh.material[m].name, material, true);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
else {
|
|
1917
|
+
if (mesh.material.name.toLowerCase().indexOf('default') !== -1) {
|
|
1918
|
+
ObjectUtils.DisposeMaterial(mesh.material);
|
|
1919
|
+
mesh.material = this._setMeshMaterialFromVariation(mesh.material.name, material, true);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
_setMeshMaterialFromVariation(name, material, usePbr = false) {
|
|
1926
|
+
if (material.texture) {
|
|
1927
|
+
material.texture.needsUpdate = true;
|
|
1928
|
+
material.texture.mapping = EquirectangularReflectionMapping;
|
|
1929
|
+
}
|
|
1930
|
+
if (!usePbr) {
|
|
1931
|
+
const newMaterial = new MeshPhongMaterial({
|
|
1932
|
+
name: name,
|
|
1933
|
+
shininess: material.shininess,
|
|
1934
|
+
specular: material.specular,
|
|
1935
|
+
map: material.texture,
|
|
1936
|
+
normalMap: material.normal
|
|
1937
|
+
});
|
|
1938
|
+
newMaterial.color.setRGB(0.8, 0.8, 0.8);
|
|
1939
|
+
newMaterial.needsUpdate = true;
|
|
1940
|
+
return newMaterial;
|
|
1941
|
+
}
|
|
1942
|
+
if (material.sheen || material.sheenColor || material.reflectivity || material.transmission) { // TODO: Proper check for all unique physical material properties
|
|
1943
|
+
const params = {
|
|
1944
|
+
// side: material.side ? material.side : FrontSide,
|
|
1945
|
+
name: name,
|
|
1946
|
+
roughness: material.roughnessValue !== undefined && material.roughnessValue !== null ? material.roughnessValue : 1,
|
|
1947
|
+
metalness: material.metalnessValue !== undefined && material.metalnessValue !== null ? material.metalnessValue : 0,
|
|
1948
|
+
envMapIntensity: material.envMapIntensity ? material.envMapIntensity : 0.01,
|
|
1949
|
+
clearcoatMap: material.clearcoatMap ? material.clearcoatMap : null,
|
|
1950
|
+
clearcoatRoughnessMap: material.clearcoatRoughnessMap ? material.clearcoatRoughnessMap : null,
|
|
1951
|
+
attenuationDistance: Infinity
|
|
1952
|
+
// wireframe: true,
|
|
1953
|
+
// opacity: 0.3,
|
|
1954
|
+
// transparent: true,
|
|
1955
|
+
};
|
|
1956
|
+
if (material.displacementValue) {
|
|
1957
|
+
params.displacementScale = material.displacementValue;
|
|
1958
|
+
}
|
|
1959
|
+
if (material.opacity) {
|
|
1960
|
+
params.opacity = material.opacity;
|
|
1961
|
+
}
|
|
1962
|
+
if (material.transparent) {
|
|
1963
|
+
params.transparent = material.transparent;
|
|
1964
|
+
}
|
|
1965
|
+
if (material.emissiveValue) {
|
|
1966
|
+
params.emissive = material.emissiveValue;
|
|
1967
|
+
}
|
|
1968
|
+
if (material.emissiveIntensityValue) {
|
|
1969
|
+
params.emissiveIntensity = material.emissiveIntensityValue;
|
|
1970
|
+
}
|
|
1971
|
+
if (material.texture) {
|
|
1972
|
+
params.map = material.texture;
|
|
1973
|
+
params.map.needsUpdate = true;
|
|
1974
|
+
}
|
|
1975
|
+
if (material.ao) {
|
|
1976
|
+
params.aoMap = material.ao;
|
|
1977
|
+
params.aoMap.needsUpdate = true;
|
|
1978
|
+
}
|
|
1979
|
+
if (material.roughness) {
|
|
1980
|
+
params.roughnessMap = material.roughness;
|
|
1981
|
+
params.roughnessMap.needsUpdate = true;
|
|
1982
|
+
// material.roughness.magFilter = NearestFilter;
|
|
1983
|
+
}
|
|
1984
|
+
if (material.metalness) {
|
|
1985
|
+
params.metalnessMap = material.metalness;
|
|
1986
|
+
params.metalnessMap.needsUpdate = true;
|
|
1987
|
+
}
|
|
1988
|
+
if (material.normal) {
|
|
1989
|
+
params.normalMap = material.normal;
|
|
1990
|
+
params.normalMap.needsUpdate = true;
|
|
1991
|
+
}
|
|
1992
|
+
if (material.displacement) {
|
|
1993
|
+
params.displacementMap = material.displacement;
|
|
1994
|
+
params.displacementMap.needsUpdate = true;
|
|
1995
|
+
}
|
|
1996
|
+
if (material.emissive) {
|
|
1997
|
+
params.emissiveMap = material.emissive;
|
|
1998
|
+
params.emissiveMap.needsUpdate = true;
|
|
1999
|
+
}
|
|
2000
|
+
if (material.envMap) {
|
|
2001
|
+
if (material.envMapIntensity != null || 0) {
|
|
2002
|
+
params.envMap = material.envMap;
|
|
2003
|
+
params.envMap.needsUpdate = true;
|
|
2004
|
+
material.envMap.mapping = EquirectangularReflectionMapping;
|
|
2005
|
+
material.envMap.minFilter = NearestFilter;
|
|
2006
|
+
material.envMap.magFilter = NearestFilter;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
if (material.reflectivity) {
|
|
2010
|
+
params.reflectivity = material.reflectivity;
|
|
2011
|
+
}
|
|
2012
|
+
if (material.side) {
|
|
2013
|
+
params.side = material.side;
|
|
2014
|
+
}
|
|
2015
|
+
else {
|
|
2016
|
+
params.side = DoubleSide;
|
|
2017
|
+
}
|
|
2018
|
+
const newMaterial = new MeshPhysicalMaterial(params);
|
|
2019
|
+
newMaterial.color.setRGB(1, 1, 1);
|
|
2020
|
+
if (material.sheen) {
|
|
2021
|
+
newMaterial.sheen = material.sheen;
|
|
2022
|
+
}
|
|
2023
|
+
if (material.sheenColor) {
|
|
2024
|
+
newMaterial.sheenColor = material.sheenColor;
|
|
2025
|
+
}
|
|
2026
|
+
else {
|
|
2027
|
+
// Add fallback for blender render
|
|
2028
|
+
newMaterial.sheenColor = new Color(1, 1, 1);
|
|
2029
|
+
}
|
|
2030
|
+
if (material.sheenRoughness) {
|
|
2031
|
+
newMaterial.sheenRoughness = material.sheenRoughness;
|
|
2032
|
+
}
|
|
2033
|
+
if (material.sheenColorMap) {
|
|
2034
|
+
newMaterial.sheenColorMap = material.sheenColorMap;
|
|
2035
|
+
newMaterial.sheenColorMap.needsUpdate = true;
|
|
2036
|
+
}
|
|
2037
|
+
if (material.sheenRoughnessMap) {
|
|
2038
|
+
newMaterial.sheenRoughnessMap = material.sheenRoughnessMap;
|
|
2039
|
+
newMaterial.sheenRoughnessMap.needsUpdate = true;
|
|
2040
|
+
}
|
|
2041
|
+
if (material.transmission) {
|
|
2042
|
+
newMaterial.transmission = material.transmission;
|
|
2043
|
+
}
|
|
2044
|
+
if (material.ior !== undefined && material.ior !== null) {
|
|
2045
|
+
newMaterial.ior = material.ior;
|
|
2046
|
+
}
|
|
2047
|
+
if (material.thickness !== undefined && material.thickness !== null) {
|
|
2048
|
+
newMaterial.thickness = material.thickness;
|
|
2049
|
+
}
|
|
2050
|
+
if (material.specularIntensity !== undefined && material.specularIntensity !== null) {
|
|
2051
|
+
newMaterial.specularIntensity = material.specularIntensity;
|
|
2052
|
+
}
|
|
2053
|
+
if (material.transmissionMap) {
|
|
2054
|
+
newMaterial.transmissionMap = material.transmissionMap;
|
|
2055
|
+
newMaterial.transmissionMap.needsUpdate = true;
|
|
2056
|
+
}
|
|
2057
|
+
newMaterial.needsUpdate = true;
|
|
2058
|
+
return newMaterial;
|
|
2059
|
+
}
|
|
2060
|
+
else {
|
|
2061
|
+
const params = {
|
|
2062
|
+
// side: material.side ? material.side : FrontSide,
|
|
2063
|
+
name: name,
|
|
2064
|
+
roughness: material.roughnessValue !== undefined && material.roughnessValue !== null ? material.roughnessValue : 1,
|
|
2065
|
+
metalness: material.metalnessValue !== undefined && material.metalnessValue !== null ? material.metalnessValue : 0,
|
|
2066
|
+
envMapIntensity: material.envMapIntensity ? material.envMapIntensity : 0.01
|
|
2067
|
+
// wireframe: true,
|
|
2068
|
+
// opacity: 0.3,
|
|
2069
|
+
// transparent: true,
|
|
2070
|
+
};
|
|
2071
|
+
if (material.displacementValue) {
|
|
2072
|
+
params.displacementScale = material.displacementValue;
|
|
2073
|
+
}
|
|
2074
|
+
if (material.opacity) {
|
|
2075
|
+
params.opacity = material.opacity;
|
|
2076
|
+
}
|
|
2077
|
+
if (material.transparent) {
|
|
2078
|
+
params.transparent = material.transparent;
|
|
2079
|
+
}
|
|
2080
|
+
if (material.emissiveValue) {
|
|
2081
|
+
params.emissive = material.emissiveValue;
|
|
2082
|
+
}
|
|
2083
|
+
if (material.emissiveIntensityValue) {
|
|
2084
|
+
params.emissiveIntensity = material.emissiveIntensityValue;
|
|
2085
|
+
}
|
|
2086
|
+
if (material.texture) {
|
|
2087
|
+
params.map = material.texture;
|
|
2088
|
+
params.map.needsUpdate = true;
|
|
2089
|
+
}
|
|
2090
|
+
if (material.ao) {
|
|
2091
|
+
params.aoMap = material.ao;
|
|
2092
|
+
params.aoMap.needsUpdate = true;
|
|
2093
|
+
}
|
|
2094
|
+
if (material.roughness) {
|
|
2095
|
+
params.roughnessMap = material.roughness;
|
|
2096
|
+
params.roughnessMap.needsUpdate = true;
|
|
2097
|
+
// material.roughness.magFilter = NearestFilter;
|
|
2098
|
+
}
|
|
2099
|
+
if (material.metalness) {
|
|
2100
|
+
params.metalnessMap = material.metalness;
|
|
2101
|
+
params.metalnessMap.needsUpdate = true;
|
|
2102
|
+
}
|
|
2103
|
+
if (material.normal) {
|
|
2104
|
+
params.normalMap = material.normal;
|
|
2105
|
+
params.normalMap.needsUpdate = true;
|
|
2106
|
+
}
|
|
2107
|
+
if (material.displacement) {
|
|
2108
|
+
params.displacementMap = material.displacement;
|
|
2109
|
+
params.displacementMap.needsUpdate = true;
|
|
2110
|
+
}
|
|
2111
|
+
if (material.emissive) {
|
|
2112
|
+
params.emissiveMap = material.emissive;
|
|
2113
|
+
params.emissiveMap.needsUpdate = true;
|
|
2114
|
+
}
|
|
2115
|
+
if (material.envMap) {
|
|
2116
|
+
if (material.envMapIntensity != null || 0) {
|
|
2117
|
+
params.envMap = material.envMap;
|
|
2118
|
+
params.envMap.needsUpdate = true;
|
|
2119
|
+
material.envMap.mapping = EquirectangularReflectionMapping;
|
|
2120
|
+
material.envMap.minFilter = NearestFilter;
|
|
2121
|
+
material.envMap.magFilter = NearestFilter;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
if (material.side) {
|
|
2125
|
+
params.side = material.side;
|
|
2126
|
+
}
|
|
2127
|
+
else {
|
|
2128
|
+
params.side = DoubleSide;
|
|
2129
|
+
}
|
|
2130
|
+
const newMaterial = new MeshStandardMaterial(params);
|
|
2131
|
+
newMaterial.color.setRGB(1, 1, 1);
|
|
2132
|
+
newMaterial.needsUpdate = true;
|
|
2133
|
+
return newMaterial;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
_setLastKnownVariations(id, variation) {
|
|
2137
|
+
this._lastKnownVariations.set(id, variation);
|
|
2138
|
+
}
|
|
2139
|
+
_getLastKnownVariations(id) {
|
|
2140
|
+
if (this._lastKnownVariations.has(id)) {
|
|
2141
|
+
return this._lastKnownVariations.get(id);
|
|
2142
|
+
}
|
|
2143
|
+
return null;
|
|
2144
|
+
}
|
|
2145
|
+
_getChildrenFilterByProp(obj, userDataObjectProp, prop, value) {
|
|
2146
|
+
return obj.children.filter((child) => {
|
|
2147
|
+
return child.userData &&
|
|
2148
|
+
child.userData.hasOwnProperty(userDataObjectProp) &&
|
|
2149
|
+
child.userData[userDataObjectProp].hasOwnProperty(prop) &&
|
|
2150
|
+
child.userData[userDataObjectProp][prop] === value;
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
_createVariationFromNode(node) {
|
|
2154
|
+
const newVariation = new Variation();
|
|
2155
|
+
newVariation.decoId = node instanceof Variation ? node.decoId : parseFloat(node.id);
|
|
2156
|
+
newVariation.node = node instanceof Variation ? node.node : node.nodeId;
|
|
2157
|
+
newVariation.brandId = node.brandId;
|
|
2158
|
+
newVariation.optionText = node.optionText;
|
|
2159
|
+
newVariation.gameObjectName = node.gameObjectName;
|
|
2160
|
+
newVariation.supplierArticleNr = node.supplierArticleNr;
|
|
2161
|
+
newVariation.materialId = node.materialId;
|
|
2162
|
+
return newVariation;
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
class Scene3DUtil {
|
|
2167
|
+
static updatePivot(obj) {
|
|
2168
|
+
const boundingBox = new Box3().setFromObject(obj);
|
|
2169
|
+
const bbCenterPivot = new Vector3();
|
|
2170
|
+
boundingBox.getCenter(bbCenterPivot);
|
|
2171
|
+
const delta = new Vector3().sub(bbCenterPivot).setY(Math.abs(Math.min(boundingBox.min.y, 0)));
|
|
2172
|
+
obj.children.forEach((child) => {
|
|
2173
|
+
child.position.add(delta);
|
|
2174
|
+
});
|
|
2175
|
+
obj.updateWorldMatrix(false, true);
|
|
2176
|
+
}
|
|
2177
|
+
static TrySelectorConnection(scene, parent, part1, part2, isFirstElement, createAddableFn) {
|
|
2178
|
+
let addable;
|
|
2179
|
+
if (createAddableFn) {
|
|
2180
|
+
addable = part2;
|
|
2181
|
+
part2 = createAddableFn(addable);
|
|
2182
|
+
}
|
|
2183
|
+
if (part1 && part2) {
|
|
2184
|
+
let con1;
|
|
2185
|
+
let con2;
|
|
2186
|
+
// if part2 is an addable and decoConnection is present, then no need to iterate through connectors
|
|
2187
|
+
if (addable && addable instanceof Selection && addable.decoConnection && addable.hdecoPositioning === HdecoPositioning.Variable) {
|
|
2188
|
+
con1 = part1.children.find(c => c.name === addable.decoConnection);
|
|
2189
|
+
if (!con1) {
|
|
2190
|
+
return false;
|
|
2191
|
+
}
|
|
2192
|
+
for (let ii = 0; ii < part2.children.length; ii++) {
|
|
2193
|
+
con2 = part2.children[ii];
|
|
2194
|
+
// if these connectors can connect connect them
|
|
2195
|
+
if (!con1.userData.connected && !con2.userData.connected && this.CanSelectorConnect(part1.children, con1, con2, isFirstElement)) {
|
|
2196
|
+
// if (!con1['connected'] && !con2['connected'] && this.CanSelectorConnect(part1.children, con1, con2, isFirstElement)) {
|
|
2197
|
+
// if addable, continue this loop with a new addable
|
|
2198
|
+
if (addable) {
|
|
2199
|
+
const newPart2 = createAddableFn(addable, part2, part1);
|
|
2200
|
+
// reference of part2 changed, so refresh con2
|
|
2201
|
+
this.SelectorConnect(scene, parent, con1, newPart2.children[ii]);
|
|
2202
|
+
}
|
|
2203
|
+
else {
|
|
2204
|
+
return this.SelectorConnect(scene, parent, con1, con2);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
else {
|
|
2210
|
+
for (let i = 0; i < part1.children.length; i++) {
|
|
2211
|
+
for (let ii = 0; ii < part2.children.length; ii++) {
|
|
2212
|
+
con1 = part1.children[i];
|
|
2213
|
+
con2 = part2.children[ii];
|
|
2214
|
+
let con1Connected = false;
|
|
2215
|
+
if (con1 && con1.userData) {
|
|
2216
|
+
con1Connected = con1.userData.connected;
|
|
2217
|
+
}
|
|
2218
|
+
let con2Connected = false;
|
|
2219
|
+
if (con2 && con2.userData) {
|
|
2220
|
+
con2Connected = con2.userData.connected;
|
|
2221
|
+
}
|
|
2222
|
+
// if these connectors can connect connect them
|
|
2223
|
+
if (!con1Connected && !con2Connected && this.CanSelectorConnect(part1.children, con1, con2, isFirstElement)) {
|
|
2224
|
+
// if addable, continue this loop with a new addable
|
|
2225
|
+
if (addable) {
|
|
2226
|
+
const newPart2 = createAddableFn(addable, part2, part1);
|
|
2227
|
+
// reference of part2 changed, so refresh con2
|
|
2228
|
+
this.SelectorConnect(scene, parent, con1, newPart2.children[ii]);
|
|
2229
|
+
}
|
|
2230
|
+
else {
|
|
2231
|
+
return this.SelectorConnect(scene, parent, con1, con2);
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
return false;
|
|
2239
|
+
}
|
|
2240
|
+
// public static TrySelectorConnection(scene: Scene, parent: Object3D,
|
|
2241
|
+
// part1: any, part2: any, createAddableFn?: Function): boolean {
|
|
2242
|
+
// let addable: any;
|
|
2243
|
+
// if (createAddableFn) {
|
|
2244
|
+
// addable = part2;
|
|
2245
|
+
// part2 = createAddableFn(addable);
|
|
2246
|
+
// }
|
|
2247
|
+
// for (let i = 0; i < part1.children.length; i++) {
|
|
2248
|
+
// for (let ii = 0; ii < part2.children.length; ii++) {
|
|
2249
|
+
// const con1: Object3D = part1.children[i];
|
|
2250
|
+
// const con2: Object3D = part2.children[ii];
|
|
2251
|
+
// // if these connectors can connect connect them
|
|
2252
|
+
// if (!con1['connected'] && !con2['connected'] && this.CanSelectorConnect(con1, con2)) {
|
|
2253
|
+
// // if addable, continue this loop with a new addable
|
|
2254
|
+
// if (addable) {
|
|
2255
|
+
// const newPart2: Object3D = createAddableFn(addable, part2, part1);
|
|
2256
|
+
// // reference of part2 changed, so refresh con2
|
|
2257
|
+
// this.SelectorConnect(scene, parent, con1, newPart2.children[ii]);
|
|
2258
|
+
// } else {
|
|
2259
|
+
// return this.SelectorConnect(scene, parent, con1, con2);
|
|
2260
|
+
// }
|
|
2261
|
+
// }
|
|
2262
|
+
// }
|
|
2263
|
+
// }
|
|
2264
|
+
// return false;
|
|
2265
|
+
// }
|
|
2266
|
+
static Convert3DPointToScreenPoint(point, camera, width, height) {
|
|
2267
|
+
if (!point) {
|
|
2268
|
+
return new Vector2();
|
|
2269
|
+
}
|
|
2270
|
+
const vector = point.clone().project(camera);
|
|
2271
|
+
vector.x = (vector.x + 1) / 2 * width;
|
|
2272
|
+
vector.y = -(vector.y - 1) / 2 * height;
|
|
2273
|
+
return new Vector2(vector.x, vector.y);
|
|
2274
|
+
}
|
|
2275
|
+
static CanSelectorConnect(consPart1, con1, con2, startWithMale) {
|
|
2276
|
+
const con1Name = (con1 instanceof Object3D || con1 instanceof Mesh) ? con1.name : con1.connector;
|
|
2277
|
+
const con2Name = (con2 instanceof Object3D || con2 instanceof Mesh) ? con2.name : con2.connector;
|
|
2278
|
+
const sameParent = (con1 instanceof Object3D || con1 instanceof Mesh) &&
|
|
2279
|
+
(con2 instanceof Object3D || con2 instanceof Mesh) ? con1.parent === con2.parent : false;
|
|
2280
|
+
if (!con1Name || !con2Name) {
|
|
2281
|
+
return false;
|
|
2282
|
+
}
|
|
2283
|
+
const parts1 = con1Name.toUpperCase().split('_'), parts2 = con2Name.toUpperCase().split('_');
|
|
2284
|
+
if (parts1.length >= 3 && parts2.length >= 3 && !sameParent) {
|
|
2285
|
+
const connectable = parts1[0] === 'C' && parts2[0] === 'C' &&
|
|
2286
|
+
parts1[1] === parts2[1] && parts1[2] !== parts2[2];
|
|
2287
|
+
return connectable;
|
|
2288
|
+
}
|
|
2289
|
+
return false;
|
|
2290
|
+
}
|
|
2291
|
+
// public static CanSelectorConnect(con1: Object3D | any, con2: Object3D | any): boolean {
|
|
2292
|
+
// const con1Name: string = con1 instanceof Object3D ? con1.name : con1.connector;
|
|
2293
|
+
// const con2Name: string = con2 instanceof Object3D ? con2.name : con2.connector;
|
|
2294
|
+
// const sameParent: boolean = con1 instanceof Object3D && con2 instanceof Object3D ? con1.parent === con2.parent : false;
|
|
2295
|
+
// const parts1: string[] = con1Name.toUpperCase().split('_'),
|
|
2296
|
+
// parts2: string[] = con2Name.toUpperCase().split('_');
|
|
2297
|
+
// if (parts1.length >= 3 && parts2.length >= 3 && !sameParent) {
|
|
2298
|
+
// const connectable: boolean = parts1[0] === 'C' && parts2[0] === 'C' &&
|
|
2299
|
+
// parts1[1] === parts2[1] && parts1[2] !== parts2[2];
|
|
2300
|
+
// return connectable;
|
|
2301
|
+
// }
|
|
2302
|
+
// return false;
|
|
2303
|
+
// }
|
|
2304
|
+
static SelectorConnect(scene, parent, con1, con2) {
|
|
2305
|
+
if (!scene || !parent) {
|
|
2306
|
+
return false;
|
|
2307
|
+
}
|
|
2308
|
+
con1['connectedTo'] = con2 && con2.parent ? con2.parent.name : '';
|
|
2309
|
+
con2['connectedTo'] = con1 && con1.parent ? con1.parent.name : '';
|
|
2310
|
+
con1.userData.connectedTo = con2 && con2.parent ? con2.parent.name : '';
|
|
2311
|
+
con1.userData.connected = false;
|
|
2312
|
+
con2.userData.connectedTo = con1 && con1.parent ? con1.parent.name : '';
|
|
2313
|
+
con2.userData.connected = false;
|
|
2314
|
+
const motherRotation = new Euler(0, 0, 0);
|
|
2315
|
+
const motherPosition = new Vector3(0, 0, 0);
|
|
2316
|
+
parent.updateMatrixWorld();
|
|
2317
|
+
motherRotation.copy(parent.rotation);
|
|
2318
|
+
parent.getWorldPosition(motherPosition);
|
|
2319
|
+
parent.rotation.set(0, 0, 0);
|
|
2320
|
+
parent.position.set(0, 0, 0);
|
|
2321
|
+
scene.updateMatrixWorld(true);
|
|
2322
|
+
const con1Quat = new Quaternion();
|
|
2323
|
+
if (con1) {
|
|
2324
|
+
con1.getWorldQuaternion(con1Quat);
|
|
2325
|
+
}
|
|
2326
|
+
const con2Quat = new Quaternion();
|
|
2327
|
+
if (con2) {
|
|
2328
|
+
con2.getWorldQuaternion(con2Quat);
|
|
2329
|
+
}
|
|
2330
|
+
const con1QuatParent = new Quaternion();
|
|
2331
|
+
if (con1 && con1.parent) {
|
|
2332
|
+
con1.parent.getWorldQuaternion(con1QuatParent);
|
|
2333
|
+
}
|
|
2334
|
+
const con2QuatParent = new Quaternion();
|
|
2335
|
+
if (con2 && con2.parent) {
|
|
2336
|
+
con2.parent.getWorldQuaternion(con2QuatParent);
|
|
2337
|
+
}
|
|
2338
|
+
const rotation = new Quaternion().multiplyQuaternions(con1Quat.invert(), con2Quat).multiply(new Quaternion().multiplyQuaternions(con1QuatParent, con1QuatParent));
|
|
2339
|
+
if (con2 && con2.parent) {
|
|
2340
|
+
con2.parent.quaternion.copy(rotation);
|
|
2341
|
+
}
|
|
2342
|
+
// Update because the matrix has been tempered with
|
|
2343
|
+
scene.updateMatrixWorld(true);
|
|
2344
|
+
// Move the connectors towards eachother
|
|
2345
|
+
const con1Pos = new Vector3();
|
|
2346
|
+
if (con1) {
|
|
2347
|
+
con1.getWorldPosition(con1Pos);
|
|
2348
|
+
}
|
|
2349
|
+
const con2Pos = new Vector3();
|
|
2350
|
+
if (con2) {
|
|
2351
|
+
con2.getWorldPosition(con2Pos);
|
|
2352
|
+
}
|
|
2353
|
+
const move = con1Pos.sub(con2Pos);
|
|
2354
|
+
if (con2 && con2.parent) {
|
|
2355
|
+
con2.parent.position.x += move.x;
|
|
2356
|
+
con2.parent.position.y += move.y;
|
|
2357
|
+
con2.parent.position.z += move.z;
|
|
2358
|
+
}
|
|
2359
|
+
// reset parent's objects rotation and position
|
|
2360
|
+
parent.rotation.copy(motherRotation);
|
|
2361
|
+
parent.position.copy(motherPosition);
|
|
2362
|
+
scene.updateMatrixWorld(true);
|
|
2363
|
+
// Set the connected flag
|
|
2364
|
+
if (con1) {
|
|
2365
|
+
// con1['connected'] = true;
|
|
2366
|
+
con1.userData.connected = true;
|
|
2367
|
+
}
|
|
2368
|
+
if (con2) {
|
|
2369
|
+
// con2['connected'] = true;
|
|
2370
|
+
con2.userData.connected = true;
|
|
2371
|
+
}
|
|
2372
|
+
return true;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
class SelectionUtils {
|
|
2377
|
+
static BuildFromAdjustables(scene, item, adjustables, placedAdjustables, sourceObj, activeConnector, baseElementNodeId) {
|
|
2378
|
+
const result = [];
|
|
2379
|
+
if (adjustables && adjustables.length > 0) {
|
|
2380
|
+
let connected = false;
|
|
2381
|
+
for (let i = 0, len = adjustables.length; i < len; i++) {
|
|
2382
|
+
const adjustable = SelectionUtils.CreateAdjustable(item, adjustables[i], placedAdjustables, sourceObj);
|
|
2383
|
+
if (adjustable) {
|
|
2384
|
+
for (let ii = placedAdjustables.length - 1; ii >= 0; ii--) {
|
|
2385
|
+
if (SelectionUtils.IsMoveableObject(adjustable)) { // vrije verplaatsing mogelijk, connecten aan opgeslagen connector
|
|
2386
|
+
const selection = adjustable.userData.selection;
|
|
2387
|
+
SelectionUtils.AddElementOnConnector(item, adjustable, selection.decoConnection ? selection.decoConnection : activeConnector, baseElementNodeId);
|
|
2388
|
+
adjustable.visible = true;
|
|
2389
|
+
connected = true;
|
|
2390
|
+
break;
|
|
2391
|
+
}
|
|
2392
|
+
else {
|
|
2393
|
+
if (Scene3DUtil.TrySelectorConnection(scene, item, placedAdjustables[ii], adjustable, i === 1)) {
|
|
2394
|
+
adjustable.visible = true;
|
|
2395
|
+
connected = true;
|
|
2396
|
+
break;
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
connected = false;
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
if (!connected && placedAdjustables.length > 1) {
|
|
2403
|
+
DebugUtils.log(`No connection found for: ${adjustable ? adjustable.name : adjustables[i].decoNode.gameObjectName}`);
|
|
2404
|
+
result.push(`No connection found for: ${adjustable ? adjustable.name : adjustables[i].decoNode.gameObjectName}`);
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
return result;
|
|
2409
|
+
}
|
|
2410
|
+
static LinkSelectionsAndDecos(selections, decos, variations) {
|
|
2411
|
+
const len = selections.length;
|
|
2412
|
+
for (let i = 0; i < len; i++) {
|
|
2413
|
+
// const id: string = this.selections[i].artNodeIdDeco;
|
|
2414
|
+
let deco = decos ? decos.find(d => d.nodeId === selections[i].node) : null;
|
|
2415
|
+
if (!deco) {
|
|
2416
|
+
deco = new DecoNode();
|
|
2417
|
+
}
|
|
2418
|
+
if (deco.type !== DecoNodeType.Variation) {
|
|
2419
|
+
const variation = variations ? variations.find(v => v.parentId === selections[i].artNodeIdDeco) : null;
|
|
2420
|
+
if (variation) {
|
|
2421
|
+
deco.variation = variation;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
selections[i].decoNode = deco;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
static PrepareTheSelections(selections, adjustables, addables) {
|
|
2428
|
+
const selectionOfArticle = selections.find(s => s.nodeType === NodeType.Article);
|
|
2429
|
+
const adjustableSelections = selections.filter(s => s.addAdjust === '2');
|
|
2430
|
+
const isArticleWithMaterial = adjustableSelections.length === 0 &&
|
|
2431
|
+
selectionOfArticle.gameObject &&
|
|
2432
|
+
selectionOfArticle.gameObject.length > 0;
|
|
2433
|
+
// get generic variations
|
|
2434
|
+
const globalVariations = selections
|
|
2435
|
+
.filter(s => (s.generic || adjustableSelections.length === 1) && s.decoNode.variation && (!s.elementType || s.elementType === 'variation'))
|
|
2436
|
+
.map((value, index, array) => {
|
|
2437
|
+
// find selection of variation
|
|
2438
|
+
const sel = selections.find(s => s.artNodeIdDeco === value.decoNode.variation.parentId);
|
|
2439
|
+
if (sel) {
|
|
2440
|
+
value.decoNode.variation.supplierArticleNr = sel.supplierArticleNr;
|
|
2441
|
+
}
|
|
2442
|
+
value.decoNode.variation.materialId = SelectionUtils.GetMaterialIdFromParent(selections, value.node);
|
|
2443
|
+
return value.decoNode.variation;
|
|
2444
|
+
});
|
|
2445
|
+
let globalVariationsRewrite = true;
|
|
2446
|
+
const len = selections.length;
|
|
2447
|
+
let lastAdded;
|
|
2448
|
+
let lastAdjustable;
|
|
2449
|
+
let newPart = false;
|
|
2450
|
+
let previousPresLevel = -1;
|
|
2451
|
+
let positioning;
|
|
2452
|
+
let optionText;
|
|
2453
|
+
for (let i = 0; i < len; i++) {
|
|
2454
|
+
const selection = selections[i];
|
|
2455
|
+
if (selection.presentationLevel === 1) {
|
|
2456
|
+
positioning = selection.hdecoPositioning;
|
|
2457
|
+
optionText = selection.question;
|
|
2458
|
+
}
|
|
2459
|
+
if (selection.presentationLevel > previousPresLevel) {
|
|
2460
|
+
selection.hdecoPositioning = selection.hdecoPositioning || positioning;
|
|
2461
|
+
}
|
|
2462
|
+
if (selection.decoNode) {
|
|
2463
|
+
if (selection.decoNode.type === DecoNodeType.Variation) {
|
|
2464
|
+
const decoNode = selection.decoNode;
|
|
2465
|
+
decoNode.optionText = optionText;
|
|
2466
|
+
// find selection of variation and set materialId in case of multimaterial
|
|
2467
|
+
if (!decoNode.materialId) {
|
|
2468
|
+
decoNode.materialId = SelectionUtils.GetMaterialIdFromParent(selections, decoNode.nodeId);
|
|
2469
|
+
}
|
|
2470
|
+
if (lastAdded) {
|
|
2471
|
+
if (newPart) {
|
|
2472
|
+
if (decoNode.materialId) {
|
|
2473
|
+
lastAdded.variations.push(decoNode);
|
|
2474
|
+
}
|
|
2475
|
+
else {
|
|
2476
|
+
lastAdded.variations = [decoNode];
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
else {
|
|
2480
|
+
lastAdded.variations.push(decoNode);
|
|
2481
|
+
}
|
|
2482
|
+
newPart = false;
|
|
2483
|
+
}
|
|
2484
|
+
else {
|
|
2485
|
+
globalVariations.push(decoNode);
|
|
2486
|
+
}
|
|
2487
|
+
// else {
|
|
2488
|
+
// if (globalVariationsRewrite) {
|
|
2489
|
+
// globalVariations.length = 0;
|
|
2490
|
+
// globalVariationsRewrite = false;
|
|
2491
|
+
// }
|
|
2492
|
+
// globalVariations.push(decoNode);
|
|
2493
|
+
// }
|
|
2494
|
+
// const variation: FurniturePartVariation = new FurniturePartVariation();
|
|
2495
|
+
// variation.BrandId = selection.decoNode.brandId;
|
|
2496
|
+
// variation.Description = selection.decoNode.gameObjectName;
|
|
2497
|
+
// variation.MaterialId = (selection.decoNode as any).materialId;
|
|
2498
|
+
// variation.SupplierArticleNr = (selection.decoNode as any).supplierArticleNr;
|
|
2499
|
+
// usedVariations.push(variation);
|
|
2500
|
+
}
|
|
2501
|
+
else if ((selection.decoNode.type === DecoNodeType.Part &&
|
|
2502
|
+
typeof selection.decoNode.gameObjectName === 'string' &&
|
|
2503
|
+
selection.decoNode.gameObjectName.length) || (isArticleWithMaterial)) {
|
|
2504
|
+
if (selection.decoNode.kind === DecoNodeKind.Adjustable || (isArticleWithMaterial)) {
|
|
2505
|
+
selection.variations = globalVariations.slice();
|
|
2506
|
+
adjustables.push(selection);
|
|
2507
|
+
if (!lastAdded || (lastAdded.nodeId !== selection.nodeId || lastAdded.node !== selection.node)) {
|
|
2508
|
+
newPart = true;
|
|
2509
|
+
}
|
|
2510
|
+
lastAdded = selection;
|
|
2511
|
+
lastAdjustable = selection;
|
|
2512
|
+
}
|
|
2513
|
+
else if (selection.decoNode.kind === DecoNodeKind.Addable) {
|
|
2514
|
+
selection.variations = lastAdjustable ? lastAdjustable.variations : globalVariations.slice();
|
|
2515
|
+
if (lastAdjustable) {
|
|
2516
|
+
lastAdjustable.addables.push(selection);
|
|
2517
|
+
}
|
|
2518
|
+
addables.push(selection);
|
|
2519
|
+
if (!lastAdded || (lastAdded.nodeId !== selection.nodeId || lastAdded.node !== selection.node)) {
|
|
2520
|
+
newPart = true;
|
|
2521
|
+
}
|
|
2522
|
+
lastAdded = selection;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
previousPresLevel = selection.presentationLevel;
|
|
2527
|
+
}
|
|
2528
|
+
// this._upsertFurniture(this.activeInstance,
|
|
2529
|
+
// {Variations: usedVariations});
|
|
2530
|
+
}
|
|
2531
|
+
/**
|
|
2532
|
+
* Returns the materialId of the parent up the tree until presentionlevel 1 is reached
|
|
2533
|
+
* @param id
|
|
2534
|
+
* @private
|
|
2535
|
+
*/
|
|
2536
|
+
static GetMaterialIdFromParent(selections, id) {
|
|
2537
|
+
if (!selections) {
|
|
2538
|
+
return undefined;
|
|
2539
|
+
}
|
|
2540
|
+
const idx = selections.findIndex(s => s.node === id);
|
|
2541
|
+
let currentLevel = 999;
|
|
2542
|
+
if (idx > -1) {
|
|
2543
|
+
for (let i = idx; i > 0; i--) {
|
|
2544
|
+
const selection = selections[i];
|
|
2545
|
+
if (selection.presentationLevel >= currentLevel) {
|
|
2546
|
+
break;
|
|
2547
|
+
}
|
|
2548
|
+
currentLevel = selection.presentationLevel;
|
|
2549
|
+
if (selection.hdecoGameObject) {
|
|
2550
|
+
return selection.hdecoGameObject;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
return undefined;
|
|
2555
|
+
}
|
|
2556
|
+
static CreateAdjustable(item, adj, placedAdjustables, sourceObj) {
|
|
2557
|
+
let obj = sourceObj ? sourceObj.getObjectByName(adj.decoNode.gameObjectName || adj.gameObject) : null;
|
|
2558
|
+
if (!obj) {
|
|
2559
|
+
// in case of glb files, the importer removes dots from names
|
|
2560
|
+
const name = adj.decoNode.gameObjectName.replace(/[.]/g, '');
|
|
2561
|
+
obj = sourceObj ? sourceObj.getObjectByName(name) : null;
|
|
2562
|
+
if (!obj) {
|
|
2563
|
+
DebugUtils.log(`No object with name ${adj.decoNode.gameObjectName} found!`);
|
|
2564
|
+
return null;
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
let adjustable = obj.clone();
|
|
2568
|
+
adjustable.name = SelectionUtils.CreateUniqueName(item, obj);
|
|
2569
|
+
adjustable.userData.selection = adj;
|
|
2570
|
+
adjustable.position.set(0, 0, 0);
|
|
2571
|
+
adjustable.traverse(c => {
|
|
2572
|
+
c.visible = !c.name.toLowerCase().startsWith('c_');
|
|
2573
|
+
});
|
|
2574
|
+
item.add(adjustable);
|
|
2575
|
+
adjustable = item.getObjectByName(adjustable.name);
|
|
2576
|
+
placedAdjustables.push(adjustable);
|
|
2577
|
+
return adjustable;
|
|
2578
|
+
}
|
|
2579
|
+
static CreateAddable(sourceObj, item, placedAddables, add, part2, part1) {
|
|
2580
|
+
const obj = sourceObj.getObjectByName(add.decoNode.gameObjectName);
|
|
2581
|
+
if (!obj) {
|
|
2582
|
+
return null;
|
|
2583
|
+
}
|
|
2584
|
+
// const selection: Selection = this._getSelectionFromId(adj.artNodeIdDeco);
|
|
2585
|
+
const addable = obj.clone();
|
|
2586
|
+
addable.name = SelectionUtils.CreateUniqueName(item, obj);
|
|
2587
|
+
addable.userData.selection = add;
|
|
2588
|
+
addable.position.set(0, 0, 0);
|
|
2589
|
+
addable.visible = true;
|
|
2590
|
+
if (part1 && part2) {
|
|
2591
|
+
return SelectionUtils.PlaceAddable(item, placedAddables, addable);
|
|
2592
|
+
}
|
|
2593
|
+
return addable;
|
|
2594
|
+
}
|
|
2595
|
+
static PlaceAddable(item, placedAddables, add) {
|
|
2596
|
+
item.add(add);
|
|
2597
|
+
const addable = item.getObjectByName(add.name);
|
|
2598
|
+
placedAddables.push(addable);
|
|
2599
|
+
return addable;
|
|
2600
|
+
}
|
|
2601
|
+
static PlaceAddables(scene, sourceObj, item, placedAdjustables, placedAddables) {
|
|
2602
|
+
const len = placedAdjustables.length;
|
|
2603
|
+
for (let i = 0; i < len; i++) {
|
|
2604
|
+
if (placedAdjustables[i].userData.hasOwnProperty('selection') && placedAdjustables[i].userData.selection) {
|
|
2605
|
+
const adjustableSelection = placedAdjustables[i].userData.selection;
|
|
2606
|
+
if (adjustableSelection) {
|
|
2607
|
+
const lena = adjustableSelection.addables.length;
|
|
2608
|
+
let conAddable;
|
|
2609
|
+
for (let ia = 0; ia < lena; ia++) {
|
|
2610
|
+
Scene3DUtil.TrySelectorConnection(scene, item, placedAdjustables[i], adjustableSelection.addables[ia], false, (add, part2, part1) => SelectionUtils.CreateAddable(sourceObj, item, placedAddables, add, part2, part1));
|
|
2611
|
+
if (conAddable) {
|
|
2612
|
+
Scene3DUtil.TrySelectorConnection(scene, item, conAddable, adjustableSelection.addables[ia], false, (add, part2, part1) => SelectionUtils.CreateAddable(sourceObj, item, placedAddables, add, part2, part1));
|
|
2613
|
+
}
|
|
2614
|
+
conAddable = placedAddables[placedAddables.length - 1];
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
static CreateUniqueName(item, obj) {
|
|
2621
|
+
let iteration = 0;
|
|
2622
|
+
let name = `${item.name}_${obj.name}`;
|
|
2623
|
+
let existingObj = item.getObjectByName(name);
|
|
2624
|
+
while (existingObj) {
|
|
2625
|
+
iteration++;
|
|
2626
|
+
name = `${item.name}_${obj.name}` + (iteration !== 0 ? ('_' + iteration) : '');
|
|
2627
|
+
existingObj = item.getObjectByName(name);
|
|
2628
|
+
}
|
|
2629
|
+
return name;
|
|
2630
|
+
}
|
|
2631
|
+
static IsMoveableObject(obj) {
|
|
2632
|
+
return obj.userData && obj.userData.selection && obj.userData.selection.hdecoPositioning === "V";
|
|
2633
|
+
}
|
|
2634
|
+
static AddElementOnConnector(currentItem, element, connector, connectedNodeId) {
|
|
2635
|
+
// TODO this should do something, but not sure what
|
|
2636
|
+
// const connectorFromElement = currentItem.connectorFromElement(element.userData.selection);
|
|
2637
|
+
// const idFromBaseElement: number = connectedNodeId ? connectedNodeId : connectorFromElement.connectedNodeId;
|
|
2638
|
+
// const baseElement: Object3D[] = currentItem.getObjectsByUserDataProp('selection', 'nodeId', idFromBaseElement);
|
|
2639
|
+
//
|
|
2640
|
+
// const item: Item = ObjectUtils.GetParentItem(element);
|
|
2641
|
+
// if (item) {
|
|
2642
|
+
// const conn: string =
|
|
2643
|
+
// await this.elementService.placeElementOnConnector(
|
|
2644
|
+
// item.metadata.itemId,
|
|
2645
|
+
// element,
|
|
2646
|
+
// baseElement.length > 0 ? baseElement[0] : null,
|
|
2647
|
+
// false,
|
|
2648
|
+
// connector,
|
|
2649
|
+
// false
|
|
2650
|
+
// );
|
|
2651
|
+
// this.saveElementConnector(element, conn);
|
|
2652
|
+
// }
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
class Builder {
|
|
2657
|
+
modelLoaded = new BehaviorSubject(null);
|
|
2658
|
+
set debug(value) {
|
|
2659
|
+
if (value) {
|
|
2660
|
+
this._debug = value;
|
|
2661
|
+
if (this._variationHelper) {
|
|
2662
|
+
this._variationHelper.debug = this._debug;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
get debug() {
|
|
2667
|
+
return this._debug;
|
|
2668
|
+
}
|
|
2669
|
+
_scene;
|
|
2670
|
+
_instanceId;
|
|
2671
|
+
_sku;
|
|
2672
|
+
_goodId;
|
|
2673
|
+
_assetPath;
|
|
2674
|
+
_selections = [];
|
|
2675
|
+
_answers = [];
|
|
2676
|
+
_decos = [];
|
|
2677
|
+
_placedAdjustables = [];
|
|
2678
|
+
_placedAddables = [];
|
|
2679
|
+
_adjustables = [];
|
|
2680
|
+
_addables = [];
|
|
2681
|
+
_debug;
|
|
2682
|
+
_imageCache = new Map();
|
|
2683
|
+
_boFactory;
|
|
2684
|
+
_source;
|
|
2685
|
+
_threedUtils;
|
|
2686
|
+
_variationHelper;
|
|
2687
|
+
_articleCache = new Map();
|
|
2688
|
+
constructor() {
|
|
2689
|
+
}
|
|
2690
|
+
init(scene) {
|
|
2691
|
+
this._boFactory = new BusinessObjectFactory();
|
|
2692
|
+
this._threedUtils = new ThreedUtils();
|
|
2693
|
+
this._variationHelper = new VariationHelper();
|
|
2694
|
+
this._variationHelper.debug = this._debug;
|
|
2695
|
+
if (!scene) {
|
|
2696
|
+
throw 'No scene object provided!';
|
|
2697
|
+
}
|
|
2698
|
+
// this._imageCacheService = new ImageCacheService();
|
|
2699
|
+
this._scene = scene;
|
|
2700
|
+
}
|
|
2701
|
+
// public async buildModel(sku?: string, instanceId?: string, goodId?: number): Promise<THREE.Object3D> {
|
|
2702
|
+
// if (!this._scene) {
|
|
2703
|
+
// return;
|
|
2704
|
+
// }
|
|
2705
|
+
// try {
|
|
2706
|
+
// await this._setInstanceId(sku, instanceId, goodId);
|
|
2707
|
+
// await this._prepareConfiguration(this._sku, this._goodId);
|
|
2708
|
+
// if (this._source) {
|
|
2709
|
+
// await this._configuratorService.setInstanceToConfigure(this._instanceId);
|
|
2710
|
+
// const promises: Promise<any>[] = [];
|
|
2711
|
+
// this._reset();
|
|
2712
|
+
// promises.push(this.getQuestionAndAnswers());
|
|
2713
|
+
// promises.push(this._getSelections(this._instanceId));
|
|
2714
|
+
// promises.push(this._getDecos());
|
|
2715
|
+
// await Promise.all(promises);
|
|
2716
|
+
// if (this._answers.length > 0) {
|
|
2717
|
+
// return;
|
|
2718
|
+
// }
|
|
2719
|
+
// this._linkSelectionsAndDecos();
|
|
2720
|
+
// this._prepareTheSelections();
|
|
2721
|
+
// this._preloadMaterials();
|
|
2722
|
+
// const build = await this._build();
|
|
2723
|
+
// return build;
|
|
2724
|
+
// } else {
|
|
2725
|
+
// throw 'GLB source not found!';
|
|
2726
|
+
// }
|
|
2727
|
+
// } catch (e) {
|
|
2728
|
+
// throw e;
|
|
2729
|
+
// }
|
|
2730
|
+
// }
|
|
2731
|
+
async buildModelFromData(selections, decos, assetUrl, cdnUrl, schema) {
|
|
2732
|
+
return new Promise(async (resolve, reject) => {
|
|
2733
|
+
if (!this._scene) {
|
|
2734
|
+
reject('no scene provided!');
|
|
2735
|
+
}
|
|
2736
|
+
try {
|
|
2737
|
+
this._log('start build', true);
|
|
2738
|
+
await this._downloadAsset(assetUrl, cdnUrl, schema, selections && selections.length > 1 && decos && decos.length > 0);
|
|
2739
|
+
try {
|
|
2740
|
+
if (this._source) {
|
|
2741
|
+
try {
|
|
2742
|
+
if (selections && selections.length > 1 && decos && decos.length > 0) {
|
|
2743
|
+
this._reset();
|
|
2744
|
+
this._assetPath = assetUrl;
|
|
2745
|
+
this._selections = selections;
|
|
2746
|
+
this._decos = decos;
|
|
2747
|
+
this._linkSelectionsAndDecos();
|
|
2748
|
+
this._prepareTheSelections();
|
|
2749
|
+
this._preloadMaterials(schema, cdnUrl);
|
|
2750
|
+
const build = await this._build();
|
|
2751
|
+
resolve(build);
|
|
2752
|
+
}
|
|
2753
|
+
else {
|
|
2754
|
+
resolve(this._source); // just return the source for simplicity
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
catch (e) {
|
|
2758
|
+
reject(e.message);
|
|
2759
|
+
}
|
|
2760
|
+
{
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
else {
|
|
2764
|
+
if (assetUrl) {
|
|
2765
|
+
reject(`Error downloading source: ${assetUrl}`);
|
|
2766
|
+
}
|
|
2767
|
+
else {
|
|
2768
|
+
reject('No 3D source provided!');
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
finally {
|
|
2773
|
+
this._cleanUp();
|
|
2774
|
+
this._log('finish build', true);
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
catch (e) {
|
|
2778
|
+
reject(e);
|
|
2779
|
+
}
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
destroy() {
|
|
2783
|
+
this._threedUtils.clearCache();
|
|
2784
|
+
this._variationHelper.clearCache();
|
|
2785
|
+
}
|
|
2786
|
+
_cleanUp() {
|
|
2787
|
+
this._sku = undefined;
|
|
2788
|
+
this._goodId = undefined;
|
|
2789
|
+
this._instanceId = undefined;
|
|
2790
|
+
this._variationHelper.clearCache();
|
|
2791
|
+
}
|
|
2792
|
+
_handleResponseData(includeMimetype, thumb, responseData) {
|
|
2793
|
+
if (responseData && responseData.resultObject) {
|
|
2794
|
+
if (responseData.resultObject.filePath !== null && responseData.resultObject.filePath !== "") {
|
|
2795
|
+
return ImageUtils.getFixedImageFilepathUrl(responseData.resultObject.filePath);
|
|
2796
|
+
}
|
|
2797
|
+
else {
|
|
2798
|
+
if (includeMimetype) {
|
|
2799
|
+
return ImageUtils.getDocBodyWithMimeTypeDefinition(responseData.resultObject.fileName, thumb ? responseData.resultObject.thumbnailBody : responseData.resultObject.documentBody);
|
|
2800
|
+
}
|
|
2801
|
+
else {
|
|
2802
|
+
return thumb ? responseData.resultObject.thumbnailBody : responseData.resultObject.documentBody;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
else {
|
|
2807
|
+
return '';
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
_preloadMaterials(schema, assetPath) {
|
|
2811
|
+
if (this._decos && this._decos.length) {
|
|
2812
|
+
const materials = [...new Set(this._decos
|
|
2813
|
+
.filter(d => (d.gameObjectName || d.materialUrl) && d.type === DecoNodeType.Variation)
|
|
2814
|
+
.map(d => d))];
|
|
2815
|
+
this._variationHelper.preloadVariations(schema, materials, assetPath);
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
async _downloadAsset(assetUrl, cdnUrl, schema, setVisibleFalse = true) {
|
|
2819
|
+
this._source = await this._threedUtils.download3DSource(assetUrl, setVisibleFalse)
|
|
2820
|
+
.catch((error) => {
|
|
2821
|
+
throw error;
|
|
2822
|
+
});
|
|
2823
|
+
if (cdnUrl) {
|
|
2824
|
+
this._variationHelper.assetPath =
|
|
2825
|
+
cdnUrl +
|
|
2826
|
+
(cdnUrl.endsWith('/') ? '' : '/') +
|
|
2827
|
+
(schema ? schema : 'UP_DBA');
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
async _build() {
|
|
2831
|
+
const adjustables = this._getAdjustables();
|
|
2832
|
+
if (adjustables && adjustables.length === 0 && this._selections && this._selections.length > 0) { // check if article has a gameObject
|
|
2833
|
+
if (this._selections[0].nodeType === NodeType.Article && this._selections[0].gameObject) {
|
|
2834
|
+
adjustables.push(this._selections[0]);
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
const obj = new THREE.Object3D();
|
|
2838
|
+
obj.visible = false; // no need to render visualy
|
|
2839
|
+
const adjustableResult = SelectionUtils.BuildFromAdjustables(this._scene, obj, adjustables, this._placedAdjustables, this._source);
|
|
2840
|
+
if (adjustableResult.length === 0) {
|
|
2841
|
+
this._log('place addables');
|
|
2842
|
+
SelectionUtils.PlaceAddables(this._scene, this._source, obj, this._placedAdjustables, this._placedAddables);
|
|
2843
|
+
this._log('update pivot');
|
|
2844
|
+
this._updatePivot(obj);
|
|
2845
|
+
this._log('load variations');
|
|
2846
|
+
await this._loadVariations(this._assetPath, obj);
|
|
2847
|
+
// this._variationHelper.clearCache();
|
|
2848
|
+
this._log('remove from scene');
|
|
2849
|
+
this._scene.remove(obj);
|
|
2850
|
+
ObjectUtils.DisposeObject(this._source);
|
|
2851
|
+
// this._cleanUp();
|
|
2852
|
+
this._log('ready!');
|
|
2853
|
+
this.modelLoaded.next(obj);
|
|
2854
|
+
return obj;
|
|
2855
|
+
}
|
|
2856
|
+
else {
|
|
2857
|
+
throw 'No adjustables found!';
|
|
2858
|
+
// this._building = false;
|
|
2859
|
+
// if (this.selections.length < 2) {
|
|
2860
|
+
// this._errorService.addError(this.activeInstance, {message: 'NO_SELECTIONS_OR_DECOS', description: 'NO_SELECTIONS_OR_DECOS_INFO'});
|
|
2861
|
+
// this.buildFinished.next({instanceId: this.activeInstance, resultType: ResultType.NoSelections});
|
|
2862
|
+
// } else if (this.decos.size === 0) {
|
|
2863
|
+
// this._errorService.addError(this.activeInstance, {message: 'NO_SELECTIONS_OR_DECOS', description: 'NO_SELECTIONS_OR_DECOS_INFO'});
|
|
2864
|
+
// this.buildFinished.next({instanceId: this.activeInstance, resultType: ResultType.NoDecoNodes});
|
|
2865
|
+
// } else {
|
|
2866
|
+
// this._errorService.addError(this.activeInstance, {message: 'NO_ADJUSTABLES', description: 'NO_ADJUSTABLES_INFO'});
|
|
2867
|
+
// this.buildFinished.next({instanceId: this.activeInstance, resultType: ResultType.NoAdjustables});
|
|
2868
|
+
// }
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
_prepareTheSelections() {
|
|
2872
|
+
if (!this._selections || !this._selections.length) {
|
|
2873
|
+
return;
|
|
2874
|
+
}
|
|
2875
|
+
SelectionUtils.PrepareTheSelections(this._selections, this._adjustables, this._addables);
|
|
2876
|
+
}
|
|
2877
|
+
_linkSelectionsAndDecos() {
|
|
2878
|
+
if (!this._selections || !this._selections.length) {
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
SelectionUtils.LinkSelectionsAndDecos(this._selections, this._decos, this._getVariations());
|
|
2882
|
+
}
|
|
2883
|
+
_getVariations() {
|
|
2884
|
+
if (this._decos && this._decos.length) {
|
|
2885
|
+
return this._decos.filter((deco) => {
|
|
2886
|
+
return deco.type === DecoNodeType.Variation;
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
return [];
|
|
2890
|
+
}
|
|
2891
|
+
async _loadVariations(assetPath, obj) {
|
|
2892
|
+
this._log('load variation for parts');
|
|
2893
|
+
await this._variationHelper.loadPart(assetPath, this._adjustables, obj, true);
|
|
2894
|
+
this._log('load variation for adjustables');
|
|
2895
|
+
await this._variationHelper.loadVariation(assetPath, this._adjustables, obj, true);
|
|
2896
|
+
this._log('load variation for addables');
|
|
2897
|
+
await this._variationHelper.loadVariation(assetPath, this._addables, obj, true);
|
|
2898
|
+
this._log('load variation clear cache');
|
|
2899
|
+
this._variationHelper.clearCache();
|
|
2900
|
+
this._log('load variations done');
|
|
2901
|
+
}
|
|
2902
|
+
_getAdjustables() {
|
|
2903
|
+
if (!this._selections || !this._selections.length) {
|
|
2904
|
+
return [];
|
|
2905
|
+
}
|
|
2906
|
+
return this._selections.filter(s => {
|
|
2907
|
+
const node = s.decoNode;
|
|
2908
|
+
return node && node.gameObjectName && node.type === DecoNodeType.Part && node.kind === DecoNodeKind.Adjustable;
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2911
|
+
_updatePivot(obj) {
|
|
2912
|
+
const boundingBox = new THREE.Box3().setFromObject(obj);
|
|
2913
|
+
const bbCenterPivot = new THREE.Vector3();
|
|
2914
|
+
boundingBox.getCenter(bbCenterPivot);
|
|
2915
|
+
const delta = new THREE.Vector3().sub(bbCenterPivot).setY(Math.abs(Math.min(boundingBox.min.y, 0)));
|
|
2916
|
+
obj.children.forEach((child) => {
|
|
2917
|
+
child.position.add(delta);
|
|
2918
|
+
});
|
|
2919
|
+
obj.updateWorldMatrix(false, true);
|
|
2920
|
+
}
|
|
2921
|
+
_reset() {
|
|
2922
|
+
this._placedAddables.length = 0;
|
|
2923
|
+
this._placedAdjustables.length = 0;
|
|
2924
|
+
this._adjustables.length = 0;
|
|
2925
|
+
this._addables.length = 0;
|
|
2926
|
+
// this._prepareTheSelections();
|
|
2927
|
+
}
|
|
2928
|
+
_log(message, force = false) {
|
|
2929
|
+
if (this.debug) {
|
|
2930
|
+
this.debug(message);
|
|
2931
|
+
console.log(new Date(), message);
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
/**
|
|
2937
|
+
* Generated bundle index. Do not edit.
|
|
2938
|
+
*/
|
|
2939
|
+
|
|
2940
|
+
export { Builder, DebugUtils, ImageUtils, Material, ObjectUtils, Scene3DUtil, SelectionUtils, ThreedUtils, VariationCacheHelper, VariationHelper };
|
|
2941
|
+
//# sourceMappingURL=colijnit-configuratorcore.mjs.map
|