@xeokit/xeokit-sdk 2.6.35 → 2.6.37

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,657 @@
1
+ /*
2
+ Parser for .XKT Format V11
3
+ */
4
+
5
+ import {utils} from "../../../viewer/scene/utils.js";
6
+ import {math} from "../../../viewer/scene/math/math.js";
7
+ import {geometryCompressionUtils} from "../../../viewer/scene/math/geometryCompressionUtils.js";
8
+ import {JPEGMediaType, PNGMediaType} from "../../../viewer/scene/constants/constants.js";
9
+
10
+ const tempVec4a = math.vec4();
11
+ const tempVec4b = math.vec4();
12
+
13
+ const NUM_TEXTURE_ATTRIBUTES = 9;
14
+
15
+ function decodeData(arrayBuffer) {
16
+ const requiresSwapFromLittleEndian = (function() {
17
+ const buffer = new ArrayBuffer(2);
18
+ new Uint16Array(buffer)[0] = 1;
19
+ return new Uint8Array(buffer)[0] !== 1;
20
+ })();
21
+
22
+ const nextArray = (function() {
23
+ let i = 0;
24
+ const dataView = new DataView(arrayBuffer);
25
+ return function(type) {
26
+ const idx = 1 + 2 * i++; // `1' for the version nr
27
+ const byteOffset = dataView.getUint32(idx * 4, true);
28
+ const byteLength = dataView.getUint32((idx + 1) * 4, true);
29
+
30
+ const BPE = type.BYTES_PER_ELEMENT;
31
+ if (requiresSwapFromLittleEndian && (BPE > 1)) {
32
+ const subarray = new Uint8Array(arrayBuffer, byteOffset, byteLength);
33
+ const swaps = BPE / 2;
34
+ const cnt = subarray.length / BPE;
35
+ for (let b = 0; b < cnt; b++) {
36
+ const offset = b * BPE;
37
+ for (let j = 0; j < swaps; j++) {
38
+ const i1 = offset + j;
39
+ const i2 = offset - j + BPE - 1;
40
+ const tmp = subarray[i1];
41
+ subarray[i1] = subarray[i2];
42
+ subarray[i2] = tmp;
43
+ }
44
+ }
45
+ }
46
+
47
+ return new type(arrayBuffer, byteOffset, byteLength / BPE);
48
+ };
49
+ })();
50
+
51
+ const nextObject = (function() {
52
+ const decoder = new TextDecoder();
53
+ return () => JSON.parse(decoder.decode(nextArray(Uint8Array)));
54
+ })();
55
+
56
+ return {
57
+ metadata: nextObject(),
58
+ textureData: nextArray(Uint8Array), // <<----------------------------- ??? ZIPPing to blame?
59
+ eachTextureDataPortion: nextArray(Uint32Array),
60
+ eachTextureAttributes: nextArray(Uint16Array),
61
+ positions: nextArray(Uint16Array),
62
+ normals: nextArray(Int8Array),
63
+ colors: nextArray(Uint8Array),
64
+ uvs: nextArray(Float32Array),
65
+ indices: nextArray(Uint32Array),
66
+ edgeIndices: nextArray(Uint32Array),
67
+ eachTextureSetTextures: nextArray(Int32Array),
68
+ matrices: nextArray(Float32Array),
69
+ reusedGeometriesDecodeMatrix: nextArray(Float32Array),
70
+ eachGeometryPrimitiveType: nextArray(Uint8Array),
71
+ eachGeometryPositionsPortion: nextArray(Uint32Array),
72
+ eachGeometryNormalsPortion: nextArray(Uint32Array),
73
+ eachGeometryColorsPortion: nextArray(Uint32Array),
74
+ eachGeometryUVsPortion: nextArray(Uint32Array),
75
+ eachGeometryIndicesPortion: nextArray(Uint32Array),
76
+ eachGeometryEdgeIndicesPortion: nextArray(Uint32Array),
77
+ eachMeshGeometriesPortion: nextArray(Uint32Array),
78
+ eachMeshMatricesPortion: nextArray(Uint32Array),
79
+ eachMeshTextureSet: nextArray(Int32Array), // Can be -1
80
+ eachMeshMaterialAttributes: nextArray(Uint8Array),
81
+ eachEntityId: nextObject(),
82
+ eachEntityMeshesPortion: nextArray(Uint32Array),
83
+ eachTileAABB: nextArray(Float64Array),
84
+ eachTileEntitiesPortion: nextArray(Uint32Array),
85
+ };
86
+ }
87
+
88
+ const decompressColor = (function () {
89
+ const floatColor = new Float32Array(3);
90
+ return function (intColor) {
91
+ floatColor[0] = intColor[0] / 255.0;
92
+ floatColor[1] = intColor[1] / 255.0;
93
+ floatColor[2] = intColor[2] / 255.0;
94
+ return floatColor;
95
+ };
96
+ })();
97
+
98
+ const imagDataToImage = (function () {
99
+ const canvas = document.createElement('canvas');
100
+ const context = canvas.getContext('2d');
101
+ return function (imagedata) {
102
+ canvas.width = imagedata.width;
103
+ canvas.height = imagedata.height;
104
+ context.putImageData(imagedata, 0, 0);
105
+ return canvas.toDataURL();
106
+ };
107
+ })();
108
+
109
+ function load(viewer, options, inflatedData, sceneModel, metaModel, manifestCtx) {
110
+
111
+ const modelPartId = manifestCtx.getNextId();
112
+
113
+ const metadata = inflatedData.metadata;
114
+ const textureData = inflatedData.textureData;
115
+ const eachTextureDataPortion = inflatedData.eachTextureDataPortion;
116
+ const eachTextureAttributes = inflatedData.eachTextureAttributes;
117
+ const positions = inflatedData.positions;
118
+ const normals = inflatedData.normals;
119
+ const colors = inflatedData.colors;
120
+ const uvs = inflatedData.uvs;
121
+ const indices = inflatedData.indices;
122
+ const edgeIndices = inflatedData.edgeIndices;
123
+ const eachTextureSetTextures = inflatedData.eachTextureSetTextures;
124
+ const matrices = inflatedData.matrices;
125
+ const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix;
126
+ const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType;
127
+ const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion;
128
+ const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion;
129
+ const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion;
130
+ const eachGeometryUVsPortion = inflatedData.eachGeometryUVsPortion;
131
+ const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion;
132
+ const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion;
133
+ const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion;
134
+ const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion;
135
+ const eachMeshTextureSet = inflatedData.eachMeshTextureSet;
136
+ const eachMeshMaterialAttributes = inflatedData.eachMeshMaterialAttributes;
137
+ const eachEntityId = inflatedData.eachEntityId;
138
+ const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion;
139
+ const eachTileAABB = inflatedData.eachTileAABB;
140
+ const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion;
141
+
142
+ const numTextures = eachTextureDataPortion.length;
143
+ const numTextureSets = eachTextureSetTextures.length / 5;
144
+ const numGeometries = eachGeometryPositionsPortion.length;
145
+ const numMeshes = eachMeshGeometriesPortion.length;
146
+ const numEntities = eachEntityMeshesPortion.length;
147
+ const numTiles = eachTileEntitiesPortion.length;
148
+
149
+ if (metaModel) {
150
+ metaModel.loadData(metadata, {
151
+ includeTypes: options.includeTypes,
152
+ excludeTypes: options.excludeTypes,
153
+ globalizeObjectIds: options.globalizeObjectIds
154
+ }); // Can be empty
155
+ }
156
+
157
+ // Create textures
158
+
159
+ for (let textureIndex = 0; textureIndex < numTextures; textureIndex++) {
160
+ const atLastTexture = (textureIndex === (numTextures - 1));
161
+ const textureDataPortionStart = eachTextureDataPortion[textureIndex];
162
+ const textureDataPortionEnd = atLastTexture ? textureData.length : (eachTextureDataPortion[textureIndex + 1]);
163
+
164
+ const textureDataPortionSize = textureDataPortionEnd - textureDataPortionStart;
165
+ const textureDataPortionExists = (textureDataPortionSize > 0);
166
+
167
+ const textureAttrBaseIdx = (textureIndex * NUM_TEXTURE_ATTRIBUTES);
168
+
169
+ const compressed = (eachTextureAttributes[textureAttrBaseIdx + 0] === 1);
170
+ const mediaType = eachTextureAttributes[textureAttrBaseIdx + 1];
171
+ const width = eachTextureAttributes[textureAttrBaseIdx + 2];
172
+ const height = eachTextureAttributes[textureAttrBaseIdx + 3];
173
+ const minFilter = eachTextureAttributes[textureAttrBaseIdx + 4];
174
+ const magFilter = eachTextureAttributes[textureAttrBaseIdx + 5]; // LinearFilter | NearestFilter
175
+ const wrapS = eachTextureAttributes[textureAttrBaseIdx + 6]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping
176
+ const wrapT = eachTextureAttributes[textureAttrBaseIdx + 7]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping
177
+ const wrapR = eachTextureAttributes[textureAttrBaseIdx + 8]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping
178
+
179
+ if (textureDataPortionExists) {
180
+
181
+ const imageDataSubarray = new Uint8Array(textureData.subarray(textureDataPortionStart, textureDataPortionEnd));
182
+ const arrayBuffer = imageDataSubarray.buffer;
183
+ const textureId = `${modelPartId}-texture-${textureIndex}`;
184
+
185
+ if (compressed) {
186
+
187
+ sceneModel.createTexture({
188
+ id: textureId,
189
+ buffers: [arrayBuffer],
190
+ minFilter,
191
+ magFilter,
192
+ wrapS,
193
+ wrapT,
194
+ wrapR
195
+ });
196
+
197
+ } else {
198
+
199
+ const mimeType = mediaType === JPEGMediaType ? "image/jpeg" : (mediaType === PNGMediaType ? "image/png" : "image/gif");
200
+ const blob = new Blob([arrayBuffer], {type: mimeType});
201
+ const urlCreator = window.URL || window.webkitURL;
202
+ const imageUrl = urlCreator.createObjectURL(blob);
203
+ const img = document.createElement('img');
204
+ img.src = imageUrl;
205
+
206
+ sceneModel.createTexture({
207
+ id: textureId,
208
+ image: img,
209
+ //mediaType,
210
+ minFilter,
211
+ magFilter,
212
+ wrapS,
213
+ wrapT,
214
+ wrapR
215
+ });
216
+ }
217
+ }
218
+ }
219
+
220
+ // Create texture sets
221
+
222
+ for (let textureSetIndex = 0; textureSetIndex < numTextureSets; textureSetIndex++) {
223
+ const eachTextureSetTexturesIndex = textureSetIndex * 5;
224
+ const textureSetId = `${modelPartId}-textureSet-${textureSetIndex}`;
225
+ const colorTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 0];
226
+ const metallicRoughnessTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 1];
227
+ const normalsTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 2];
228
+ const emissiveTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 3];
229
+ const occlusionTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 4];
230
+ sceneModel.createTextureSet({
231
+ id: textureSetId,
232
+ colorTextureId: colorTextureIndex >= 0 ? `${modelPartId}-texture-${colorTextureIndex}` : null,
233
+ normalsTextureId: normalsTextureIndex >= 0 ? `${modelPartId}-texture-${normalsTextureIndex}` : null,
234
+ metallicRoughnessTextureId: metallicRoughnessTextureIndex >= 0 ? `${modelPartId}-texture-${metallicRoughnessTextureIndex}` : null,
235
+ emissiveTextureId: emissiveTextureIndex >= 0 ? `${modelPartId}-texture-${emissiveTextureIndex}` : null,
236
+ occlusionTextureId: occlusionTextureIndex >= 0 ? `${modelPartId}-texture-${occlusionTextureIndex}` : null
237
+ });
238
+ }
239
+
240
+ // Count instances of each geometry
241
+
242
+ const geometryReuseCounts = new Uint32Array(numGeometries);
243
+
244
+ for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) {
245
+ const geometryIndex = eachMeshGeometriesPortion[meshIndex];
246
+ if (geometryReuseCounts[geometryIndex] !== undefined) {
247
+ geometryReuseCounts[geometryIndex]++;
248
+ } else {
249
+ geometryReuseCounts[geometryIndex] = 1;
250
+ }
251
+ }
252
+
253
+ // Iterate over tiles
254
+
255
+ const tileCenter = math.vec3();
256
+ const rtcAABB = math.AABB3();
257
+
258
+ const geometryArraysCache = {};
259
+
260
+ for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) {
261
+
262
+ const lastTileIndex = (numTiles - 1);
263
+
264
+ const atLastTile = (tileIndex === lastTileIndex);
265
+
266
+ const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex];
267
+ const lastTileEntityIndex = atLastTile ? (numEntities - 1) : (eachTileEntitiesPortion[tileIndex + 1] - 1);
268
+
269
+ const tileAABBIndex = tileIndex * 6;
270
+ const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6);
271
+
272
+ math.getAABB3Center(tileAABB, tileCenter);
273
+
274
+ rtcAABB[0] = tileAABB[0] - tileCenter[0];
275
+ rtcAABB[1] = tileAABB[1] - tileCenter[1];
276
+ rtcAABB[2] = tileAABB[2] - tileCenter[2];
277
+ rtcAABB[3] = tileAABB[3] - tileCenter[0];
278
+ rtcAABB[4] = tileAABB[4] - tileCenter[1];
279
+ rtcAABB[5] = tileAABB[5] - tileCenter[2];
280
+
281
+ const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB);
282
+
283
+ const geometryCreatedInTile = {};
284
+
285
+ // Iterate over each tile's entities
286
+
287
+ for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex <= lastTileEntityIndex; tileEntityIndex++) {
288
+
289
+ const xktEntityId = eachEntityId[tileEntityIndex];
290
+
291
+ const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId;
292
+
293
+ const finalTileEntityIndex = (numEntities - 1);
294
+ const atLastTileEntity = (tileEntityIndex === finalTileEntityIndex);
295
+ const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex];
296
+ const lastMeshIndex = atLastTileEntity ? (eachMeshGeometriesPortion.length - 1) : (eachEntityMeshesPortion[tileEntityIndex + 1] - 1);
297
+
298
+ const meshIds = [];
299
+
300
+ const metaObject = viewer.metaScene.metaObjects[entityId];
301
+ const entityDefaults = {};
302
+ const meshDefaults = {};
303
+
304
+ if (metaObject) {
305
+
306
+ // Mask loading of object types
307
+
308
+ if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) {
309
+ continue;
310
+ }
311
+
312
+ if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) {
313
+ continue;
314
+ }
315
+
316
+ // Get initial property values for object types
317
+
318
+ const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null;
319
+
320
+ if (props) {
321
+ if (props.visible === false) {
322
+ entityDefaults.visible = false;
323
+ }
324
+ if (props.pickable === false) {
325
+ entityDefaults.pickable = false;
326
+ }
327
+ if (props.colorize) {
328
+ meshDefaults.color = props.colorize;
329
+ }
330
+ if (props.opacity !== undefined && props.opacity !== null) {
331
+ meshDefaults.opacity = props.opacity;
332
+ }
333
+ if (props.metallic !== undefined && props.metallic !== null) {
334
+ meshDefaults.metallic = props.metallic;
335
+ }
336
+ if (props.roughness !== undefined && props.roughness !== null) {
337
+ meshDefaults.roughness = props.roughness;
338
+ }
339
+ }
340
+
341
+ } else {
342
+ if (options.excludeUnclassifiedObjects) {
343
+ continue;
344
+ }
345
+ }
346
+
347
+ // Iterate each entity's meshes
348
+
349
+ for (let meshIndex = firstMeshIndex; meshIndex <= lastMeshIndex; meshIndex++) {
350
+
351
+ const geometryIndex = eachMeshGeometriesPortion[meshIndex];
352
+ const geometryReuseCount = geometryReuseCounts[geometryIndex];
353
+ const isReusedGeometry = (geometryReuseCount > 1);
354
+
355
+ const atLastGeometry = (geometryIndex === (numGeometries - 1));
356
+
357
+ const textureSetIndex = eachMeshTextureSet[meshIndex];
358
+
359
+ const textureSetId = (textureSetIndex >= 0) ? `${modelPartId}-textureSet-${textureSetIndex}` : null;
360
+
361
+ const meshColor = decompressColor(eachMeshMaterialAttributes.subarray((meshIndex * 6), (meshIndex * 6) + 3));
362
+ const meshOpacity = eachMeshMaterialAttributes[(meshIndex * 6) + 3] / 255.0;
363
+ const meshMetallic = eachMeshMaterialAttributes[(meshIndex * 6) + 4] / 255.0;
364
+ const meshRoughness = eachMeshMaterialAttributes[(meshIndex * 6) + 5] / 255.0;
365
+
366
+ const meshId = manifestCtx.getNextId();
367
+
368
+ if (isReusedGeometry) {
369
+
370
+ // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry
371
+
372
+ const meshMatrixIndex = eachMeshMatricesPortion[meshIndex];
373
+ const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16);
374
+
375
+ const geometryId = `${modelPartId}-geometry.${tileIndex}.${geometryIndex}`; // These IDs are local to the SceneModel
376
+
377
+ let geometryArrays = geometryArraysCache[geometryId];
378
+
379
+ if (!geometryArrays) {
380
+ geometryArrays = {
381
+ batchThisMesh: (!options.reuseGeometries)
382
+ };
383
+ const primitiveType = eachGeometryPrimitiveType[geometryIndex];
384
+ let geometryValid = false;
385
+ switch (primitiveType) {
386
+ case 0:
387
+ geometryArrays.primitiveName = "solid";
388
+ geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
389
+ geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
390
+ geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
391
+ geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
392
+ geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
393
+ geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
394
+ break;
395
+ case 1:
396
+ geometryArrays.primitiveName = "surface";
397
+ geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
398
+ geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
399
+ geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
400
+ geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
401
+ geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
402
+ geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
403
+ break;
404
+ case 2:
405
+ geometryArrays.primitiveName = "points";
406
+ geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
407
+ geometryArrays.geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]);
408
+ geometryValid = (geometryArrays.geometryPositions.length > 0);
409
+ break;
410
+ case 3:
411
+ geometryArrays.primitiveName = "lines";
412
+ geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
413
+ geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
414
+ geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
415
+ break;
416
+ case 4:
417
+ geometryArrays.primitiveName = "lines";
418
+ geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
419
+ geometryArrays.geometryIndices = lineStripToLines(
420
+ geometryArrays.geometryPositions,
421
+ indices.subarray(eachGeometryIndicesPortion [geometryIndex],
422
+ atLastGeometry
423
+ ? indices.length
424
+ : eachGeometryIndicesPortion [geometryIndex + 1]));
425
+ geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0);
426
+ break;
427
+ default:
428
+ continue;
429
+ }
430
+
431
+ if (!geometryValid) {
432
+ geometryArrays = null;
433
+ }
434
+
435
+ if (geometryArrays) {
436
+ if (geometryReuseCount > 1000) { // TODO: Heuristic to force batching of instanced geometry beyond a certain reuse count (or budget)?
437
+ // geometryArrays.batchThisMesh = true;
438
+ }
439
+ if (geometryArrays.geometryPositions.length > 1000) { // TODO: Heuristic to force batching on instanced geometry above certain vertex size?
440
+ // geometryArrays.batchThisMesh = true;
441
+ }
442
+ if (geometryArrays.batchThisMesh) {
443
+ geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length);
444
+ geometryArrays.transformedAndRecompressedPositions = new Uint16Array(geometryArrays.geometryPositions.length)
445
+ const geometryPositions = geometryArrays.geometryPositions;
446
+ const decompressedPositions = geometryArrays.decompressedPositions;
447
+ for (let i = 0, len = geometryPositions.length; i < len; i += 3) {
448
+ decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12];
449
+ decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13];
450
+ decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14];
451
+ }
452
+ geometryArrays.geometryPositions = null;
453
+ geometryArraysCache[geometryId] = geometryArrays;
454
+ }
455
+ }
456
+ }
457
+
458
+ if (geometryArrays) {
459
+
460
+ if (geometryArrays.batchThisMesh) {
461
+
462
+ const decompressedPositions = geometryArrays.decompressedPositions;
463
+ const transformedAndRecompressedPositions = geometryArrays.transformedAndRecompressedPositions;
464
+
465
+ for (let i = 0, len = decompressedPositions.length; i < len; i += 3) {
466
+ tempVec4a[0] = decompressedPositions[i + 0];
467
+ tempVec4a[1] = decompressedPositions[i + 1];
468
+ tempVec4a[2] = decompressedPositions[i + 2];
469
+ tempVec4a[3] = 1;
470
+ math.transformVec4(meshMatrix, tempVec4a, tempVec4b);
471
+ geometryCompressionUtils.compressPosition(tempVec4b, rtcAABB, tempVec4a)
472
+ transformedAndRecompressedPositions[i + 0] = tempVec4a[0];
473
+ transformedAndRecompressedPositions[i + 1] = tempVec4a[1];
474
+ transformedAndRecompressedPositions[i + 2] = tempVec4a[2];
475
+ }
476
+
477
+ sceneModel.createMesh(utils.apply(meshDefaults, {
478
+ id: meshId,
479
+ textureSetId,
480
+ origin: tileCenter,
481
+ primitive: geometryArrays.primitiveName,
482
+ positionsCompressed: transformedAndRecompressedPositions,
483
+ normalsCompressed: geometryArrays.geometryNormals,
484
+ uv: geometryArrays.geometryUVs,
485
+ colorsCompressed: geometryArrays.geometryColors,
486
+ indices: geometryArrays.geometryIndices,
487
+ edgeIndices: geometryArrays.geometryEdgeIndices,
488
+ positionsDecodeMatrix: tileDecodeMatrix,
489
+ color: meshColor,
490
+ metallic: meshMetallic,
491
+ roughness: meshRoughness,
492
+ opacity: meshOpacity
493
+ }));
494
+
495
+ meshIds.push(meshId);
496
+
497
+ } else {
498
+
499
+ if (!geometryCreatedInTile[geometryId]) {
500
+
501
+ sceneModel.createGeometry({
502
+ id: geometryId,
503
+ primitive: geometryArrays.primitiveName,
504
+ positionsCompressed: geometryArrays.geometryPositions,
505
+ normalsCompressed: geometryArrays.geometryNormals,
506
+ uv: geometryArrays.geometryUVs,
507
+ colorsCompressed: geometryArrays.geometryColors,
508
+ indices: geometryArrays.geometryIndices,
509
+ edgeIndices: geometryArrays.geometryEdgeIndices,
510
+ positionsDecodeMatrix: reusedGeometriesDecodeMatrix
511
+ });
512
+
513
+ geometryCreatedInTile[geometryId] = true;
514
+ }
515
+
516
+ sceneModel.createMesh(utils.apply(meshDefaults, {
517
+ id: meshId,
518
+ geometryId,
519
+ textureSetId,
520
+ matrix: meshMatrix,
521
+ color: meshColor,
522
+ metallic: meshMetallic,
523
+ roughness: meshRoughness,
524
+ opacity: meshOpacity,
525
+ origin: tileCenter
526
+ }));
527
+
528
+ meshIds.push(meshId);
529
+ }
530
+ }
531
+
532
+ } else { // Do not reuse geometry
533
+
534
+ const primitiveType = eachGeometryPrimitiveType[geometryIndex];
535
+
536
+ let primitiveName;
537
+ let geometryPositions;
538
+ let geometryNormals;
539
+ let geometryUVs;
540
+ let geometryColors;
541
+ let geometryIndices;
542
+ let geometryEdgeIndices;
543
+ let geometryValid = false;
544
+
545
+ switch (primitiveType) {
546
+ case 0:
547
+ primitiveName = "solid";
548
+ geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
549
+ geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
550
+ geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
551
+ geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
552
+ geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
553
+ geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
554
+ break;
555
+ case 1:
556
+ primitiveName = "surface";
557
+ geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
558
+ geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]);
559
+ geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]);
560
+ geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
561
+ geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]);
562
+ geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
563
+ break;
564
+ case 2:
565
+ primitiveName = "points";
566
+ geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
567
+ geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]);
568
+ geometryValid = (geometryPositions.length > 0);
569
+ break;
570
+ case 3:
571
+ primitiveName = "lines";
572
+ geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
573
+ geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]);
574
+ geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
575
+ break;
576
+ case 4:
577
+ primitiveName = "lines";
578
+ geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]);
579
+ geometryIndices = lineStripToLines(
580
+ geometryPositions,
581
+ indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry
582
+ ? indices.length
583
+ : eachGeometryIndicesPortion [geometryIndex + 1]));
584
+ geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0);
585
+ break;
586
+ default:
587
+ continue;
588
+ }
589
+
590
+ if (geometryValid) {
591
+
592
+ sceneModel.createMesh(utils.apply(meshDefaults, {
593
+ id: meshId,
594
+ textureSetId,
595
+ origin: tileCenter,
596
+ primitive: primitiveName,
597
+ positionsCompressed: geometryPositions,
598
+ normalsCompressed: geometryNormals,
599
+ uv: geometryUVs && geometryUVs.length > 0 ? geometryUVs : null,
600
+ colorsCompressed: geometryColors,
601
+ indices: geometryIndices,
602
+ edgeIndices: geometryEdgeIndices,
603
+ positionsDecodeMatrix: tileDecodeMatrix,
604
+ color: meshColor,
605
+ metallic: meshMetallic,
606
+ roughness: meshRoughness,
607
+ opacity: meshOpacity
608
+ }));
609
+
610
+ meshIds.push(meshId);
611
+ }
612
+ }
613
+ }
614
+
615
+ if (meshIds.length > 0) {
616
+
617
+ sceneModel.createEntity(utils.apply(entityDefaults, {
618
+ id: entityId,
619
+ isObject: true,
620
+ meshIds: meshIds
621
+ }));
622
+ }
623
+ }
624
+ }
625
+ }
626
+
627
+ function lineStripToLines(positions, indices) {
628
+ const linesIndices = [];
629
+ if (indices.length > 1) {
630
+ for (let i = 0, len = indices.length - 1; i < len; i++) {
631
+ linesIndices.push(indices[i]);
632
+ linesIndices.push(indices[i + 1]);
633
+ }
634
+ } else if (positions.length > 1) {
635
+ for (let i = 0, len = (positions.length / 3) - 1; i < len; i++) {
636
+ linesIndices.push(i);
637
+ linesIndices.push(i + 1);
638
+ }
639
+ }
640
+ return linesIndices;
641
+ }
642
+
643
+ /** @private */
644
+ // V11 uses a single uncompressed Uint8Array buffer to store arrays of different types.
645
+ // To efficiently create typed arrays from this buffer,
646
+ // each typed array's source data needs to be aligned with its element byte size.
647
+ // This sometimes requires padding subarrays inside the single Uint8Array, so the byteOffset needs to be stored alongside element count.
648
+ // It is a different encoding than used in earlier versions, and requires different approach to parsing elements.
649
+ const ParserV11 = {
650
+ version: 11,
651
+ parseArrayBuffer: function (viewer, options, arrayBuffer, sceneModel, metaModel, manifestCtx) {
652
+ const inflatedData = decodeData(arrayBuffer);
653
+ load(viewer, options, inflatedData, sceneModel, metaModel, manifestCtx);
654
+ }
655
+ };
656
+
657
+ export {ParserV11};