@loaders.gl/i3s 4.2.0-alpha.4 → 4.2.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/arcgis-webscene-loader.d.ts +1 -1
  2. package/dist/arcgis-webscene-loader.d.ts.map +1 -1
  3. package/dist/arcgis-webscene-loader.js +19 -10
  4. package/dist/dist.dev.js +1244 -731
  5. package/dist/dist.min.js +9 -0
  6. package/dist/i3s-attribute-loader.d.ts +2 -2
  7. package/dist/i3s-attribute-loader.d.ts.map +1 -1
  8. package/dist/i3s-attribute-loader.js +145 -94
  9. package/dist/i3s-building-scene-layer-loader.d.ts +2 -2
  10. package/dist/i3s-building-scene-layer-loader.d.ts.map +1 -1
  11. package/dist/i3s-building-scene-layer-loader.js +17 -13
  12. package/dist/i3s-content-loader.d.ts +2 -2
  13. package/dist/i3s-content-loader.d.ts.map +1 -1
  14. package/dist/i3s-content-loader.js +23 -24
  15. package/dist/i3s-content-worker-node.js +1 -1
  16. package/dist/i3s-content-worker-node.js.map +2 -2
  17. package/dist/i3s-content-worker.js +3 -1
  18. package/dist/i3s-loader.d.ts +2 -2
  19. package/dist/i3s-loader.d.ts.map +1 -1
  20. package/dist/i3s-loader.js +76 -65
  21. package/dist/i3s-node-page-loader.d.ts +2 -2
  22. package/dist/i3s-node-page-loader.d.ts.map +1 -1
  23. package/dist/i3s-node-page-loader.js +16 -12
  24. package/dist/i3s-slpk-loader.js +18 -14
  25. package/dist/index.cjs +73 -138
  26. package/dist/index.cjs.map +7 -0
  27. package/dist/index.d.ts +14 -14
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +3 -1
  30. package/dist/lib/helpers/i3s-nodepages-tiles.d.ts +1 -1
  31. package/dist/lib/helpers/i3s-nodepages-tiles.d.ts.map +1 -1
  32. package/dist/lib/helpers/i3s-nodepages-tiles.js +226 -184
  33. package/dist/lib/parsers/constants.js +72 -45
  34. package/dist/lib/parsers/parse-arcgis-webscene.d.ts +1 -1
  35. package/dist/lib/parsers/parse-arcgis-webscene.d.ts.map +1 -1
  36. package/dist/lib/parsers/parse-arcgis-webscene.js +79 -59
  37. package/dist/lib/parsers/parse-i3s-attribute.js +83 -46
  38. package/dist/lib/parsers/parse-i3s-building-scene-layer.d.ts +1 -1
  39. package/dist/lib/parsers/parse-i3s-building-scene-layer.d.ts.map +1 -1
  40. package/dist/lib/parsers/parse-i3s-building-scene-layer.js +36 -33
  41. package/dist/lib/parsers/parse-i3s-tile-content.d.ts +1 -1
  42. package/dist/lib/parsers/parse-i3s-tile-content.d.ts.map +1 -1
  43. package/dist/lib/parsers/parse-i3s-tile-content.js +460 -394
  44. package/dist/lib/parsers/parse-i3s.d.ts +1 -1
  45. package/dist/lib/parsers/parse-i3s.d.ts.map +1 -1
  46. package/dist/lib/parsers/parse-i3s.js +84 -81
  47. package/dist/lib/parsers/parse-slpk/parse-slpk.d.ts +1 -1
  48. package/dist/lib/parsers/parse-slpk/parse-slpk.d.ts.map +1 -1
  49. package/dist/lib/parsers/parse-slpk/parse-slpk.js +23 -16
  50. package/dist/lib/parsers/parse-slpk/slpk-archieve.js +132 -97
  51. package/dist/lib/utils/convert-i3s-obb-to-mbs.js +12 -5
  52. package/dist/lib/utils/customize-colors.d.ts +1 -1
  53. package/dist/lib/utils/customize-colors.d.ts.map +1 -1
  54. package/dist/lib/utils/customize-colors.js +95 -81
  55. package/dist/lib/utils/url-utils.d.ts +1 -1
  56. package/dist/lib/utils/url-utils.d.ts.map +1 -1
  57. package/dist/lib/utils/url-utils.js +48 -28
  58. package/dist/types.d.ts +1 -1
  59. package/dist/types.d.ts.map +1 -1
  60. package/dist/types.js +5 -6
  61. package/dist/workers/i3s-content-worker-node.js +1 -1
  62. package/dist/workers/i3s-content-worker.js +0 -1
  63. package/package.json +13 -12
  64. package/dist/arcgis-webscene-loader.js.map +0 -1
  65. package/dist/i3s-attribute-loader.js.map +0 -1
  66. package/dist/i3s-building-scene-layer-loader.js.map +0 -1
  67. package/dist/i3s-content-loader.js.map +0 -1
  68. package/dist/i3s-loader.js.map +0 -1
  69. package/dist/i3s-node-page-loader.js.map +0 -1
  70. package/dist/i3s-slpk-loader.js.map +0 -1
  71. package/dist/index.js.map +0 -1
  72. package/dist/lib/helpers/i3s-nodepages-tiles.js.map +0 -1
  73. package/dist/lib/parsers/constants.js.map +0 -1
  74. package/dist/lib/parsers/parse-arcgis-webscene.js.map +0 -1
  75. package/dist/lib/parsers/parse-i3s-attribute.js.map +0 -1
  76. package/dist/lib/parsers/parse-i3s-building-scene-layer.js.map +0 -1
  77. package/dist/lib/parsers/parse-i3s-tile-content.js.map +0 -1
  78. package/dist/lib/parsers/parse-i3s.js.map +0 -1
  79. package/dist/lib/parsers/parse-slpk/parse-slpk.js.map +0 -1
  80. package/dist/lib/parsers/parse-slpk/slpk-archieve.js.map +0 -1
  81. package/dist/lib/utils/convert-i3s-obb-to-mbs.js.map +0 -1
  82. package/dist/lib/utils/customize-colors.js.map +0 -1
  83. package/dist/lib/utils/url-utils.js.map +0 -1
  84. package/dist/types.js.map +0 -1
  85. package/dist/workers/i3s-content-worker-node.js.map +0 -1
  86. package/dist/workers/i3s-content-worker.js.map +0 -1
@@ -10,440 +10,506 @@ import { getUrlWithToken } from "../utils/url-utils.js";
10
10
  import { GL_TYPE_MAP, getConstructorForDataFormat, sizeOf, COORDINATE_SYSTEM } from "./constants.js";
11
11
  const scratchVector = new Vector3([0, 0, 0]);
12
12
  function getLoaderForTextureFormat(textureFormat) {
13
- switch (textureFormat) {
14
- case 'ktx-etc2':
15
- case 'dds':
16
- return CompressedTextureLoader;
17
- case 'ktx2':
18
- return BasisLoader;
19
- case 'jpg':
20
- case 'png':
21
- default:
22
- return ImageLoader;
23
- }
13
+ switch (textureFormat) {
14
+ case 'ktx-etc2':
15
+ case 'dds':
16
+ return CompressedTextureLoader;
17
+ case 'ktx2':
18
+ return BasisLoader;
19
+ case 'jpg':
20
+ case 'png':
21
+ default:
22
+ return ImageLoader;
23
+ }
24
24
  }
25
25
  const I3S_ATTRIBUTE_TYPE = 'i3s-attribute-type';
26
26
  export async function parseI3STileContent(arrayBuffer, tileOptions, tilesetOptions, options, context) {
27
- const content = {
28
- attributes: {},
29
- indices: null,
30
- featureIds: [],
31
- vertexCount: 0,
32
- modelMatrix: new Matrix4(),
33
- coordinateSystem: 0,
34
- byteLength: 0,
35
- texture: null
36
- };
37
- if (tileOptions.textureUrl) {
38
- var _options$i3s;
39
- const url = getUrlWithToken(getInternalPathFromUrl(tileOptions.textureUrl), options === null || options === void 0 ? void 0 : (_options$i3s = options.i3s) === null || _options$i3s === void 0 ? void 0 : _options$i3s.token);
40
- const loader = getLoaderForTextureFormat(tileOptions.textureFormat);
41
- const fetchFunc = (context === null || context === void 0 ? void 0 : context.fetch) || fetch;
42
- const response = await fetchFunc(url);
43
- const arrayBuffer = await response.arrayBuffer();
44
- if (options !== null && options !== void 0 && options.i3s.decodeTextures) {
45
- if (loader === ImageLoader) {
46
- const options = {
47
- ...tileOptions.textureLoaderOptions,
48
- image: {
49
- type: 'data'
50
- }
51
- };
52
- try {
53
- const texture = await parseFromContext(arrayBuffer, [], options, context);
54
- content.texture = texture;
55
- } catch (e) {
56
- const texture = await parse(arrayBuffer, loader, options, context);
57
- content.texture = texture;
27
+ const content = {
28
+ attributes: {},
29
+ indices: null,
30
+ featureIds: [],
31
+ vertexCount: 0,
32
+ modelMatrix: new Matrix4(),
33
+ coordinateSystem: 0,
34
+ byteLength: 0,
35
+ texture: null
36
+ };
37
+ if (tileOptions.textureUrl) {
38
+ const url = getUrlWithToken(getInternalPathFromUrl(tileOptions.textureUrl),
39
+ // @ts-expect-error options is not properly typed
40
+ options?.i3s?.token);
41
+ const loader = getLoaderForTextureFormat(tileOptions.textureFormat);
42
+ const fetchFunc = context?.fetch || fetch;
43
+ const response = await fetchFunc(url); // options?.fetch
44
+ const arrayBuffer = await response.arrayBuffer();
45
+ // @ts-expect-error options is not properly typed
46
+ if (options?.i3s.decodeTextures) {
47
+ // TODO - replace with switch
48
+ if (loader === ImageLoader) {
49
+ const options = { ...tileOptions.textureLoaderOptions, image: { type: 'data' } };
50
+ try {
51
+ // Image constructor is not supported in worker thread.
52
+ // Do parsing image data on the main thread by using context to avoid worker issues.
53
+ const texture = await parseFromContext(arrayBuffer, [], options, context);
54
+ // @ts-expect-error
55
+ content.texture = texture;
56
+ }
57
+ catch (e) {
58
+ // context object is different between worker and node.js conversion script.
59
+ // To prevent error we parse data in ordinary way if it is not parsed by using context.
60
+ const texture = await parse(arrayBuffer, loader, options, context);
61
+ content.texture = texture;
62
+ }
63
+ }
64
+ else if (loader === CompressedTextureLoader || loader === BasisLoader) {
65
+ let texture = await load(arrayBuffer, loader, tileOptions.textureLoaderOptions);
66
+ if (loader === BasisLoader) {
67
+ texture = texture[0];
68
+ }
69
+ content.texture = {
70
+ compressed: true,
71
+ mipmaps: false,
72
+ width: texture[0].width,
73
+ height: texture[0].height,
74
+ data: texture
75
+ };
76
+ }
58
77
  }
59
- } else if (loader === CompressedTextureLoader || loader === BasisLoader) {
60
- let texture = await load(arrayBuffer, loader, tileOptions.textureLoaderOptions);
61
- if (loader === BasisLoader) {
62
- texture = texture[0];
78
+ else {
79
+ content.texture = arrayBuffer;
63
80
  }
64
- content.texture = {
65
- compressed: true,
66
- mipmaps: false,
67
- width: texture[0].width,
68
- height: texture[0].height,
69
- data: texture
70
- };
71
- }
72
- } else {
73
- content.texture = arrayBuffer;
74
- }
75
- }
76
- content.material = makePbrMaterial(tileOptions.materialDefinition, content.texture);
77
- if (content.material) {
78
- content.texture = null;
79
- }
80
- return await parseI3SNodeGeometry(arrayBuffer, content, tileOptions, tilesetOptions, options);
81
+ }
82
+ content.material = makePbrMaterial(tileOptions.materialDefinition, content.texture);
83
+ if (content.material) {
84
+ content.texture = null;
85
+ }
86
+ return await parseI3SNodeGeometry(arrayBuffer, content, tileOptions, tilesetOptions, options);
81
87
  }
88
+ /**
89
+ * Get the URL inside SLPK archive
90
+ * @param url - full url with *.slpk prefix
91
+ * @returns URL inside SLPK archive
92
+ */
82
93
  function getInternalPathFromUrl(url) {
83
- const slpkUrlParts = url.split('.slpk');
84
- let filename;
85
- if (slpkUrlParts.length === 1) {
86
- filename = url;
87
- } else if (slpkUrlParts.length === 2) {
88
- filename = slpkUrlParts[1].slice(1);
89
- } else {
90
- filename = url;
91
- }
92
- return filename;
94
+ const slpkUrlParts = url.split('.slpk');
95
+ let filename;
96
+ // Not '.slpk'. The file will be loaded with global fetch function
97
+ if (slpkUrlParts.length === 1) {
98
+ filename = url;
99
+ }
100
+ else if (slpkUrlParts.length === 2) {
101
+ filename = slpkUrlParts[1].slice(1);
102
+ }
103
+ else {
104
+ filename = url;
105
+ }
106
+ return filename;
93
107
  }
108
+ /* eslint-disable max-statements */
94
109
  async function parseI3SNodeGeometry(arrayBuffer, content, tileOptions, tilesetOptions, options) {
95
- var _options$i3s2;
96
- const contentByteLength = arrayBuffer.byteLength;
97
- let attributes;
98
- let vertexCount;
99
- let byteOffset = 0;
100
- let featureCount = 0;
101
- let indices;
102
- if (tileOptions.isDracoGeometry) {
103
- var _decompressedGeometry;
104
- const decompressedGeometry = await parse(arrayBuffer, DracoLoader, {
105
- draco: {
106
- attributeNameEntry: I3S_ATTRIBUTE_TYPE
107
- }
108
- });
109
- vertexCount = decompressedGeometry.header.vertexCount;
110
- indices = (_decompressedGeometry = decompressedGeometry.indices) === null || _decompressedGeometry === void 0 ? void 0 : _decompressedGeometry.value;
111
- const {
112
- POSITION,
113
- NORMAL,
114
- COLOR_0,
115
- TEXCOORD_0,
116
- ['feature-index']: featureIndex,
117
- ['uv-region']: uvRegion
118
- } = decompressedGeometry.attributes;
119
- attributes = {
120
- position: POSITION,
121
- normal: NORMAL,
122
- color: COLOR_0,
123
- uv0: TEXCOORD_0,
124
- uvRegion,
125
- id: featureIndex
110
+ const contentByteLength = arrayBuffer.byteLength;
111
+ let attributes;
112
+ let vertexCount;
113
+ let byteOffset = 0;
114
+ let featureCount = 0;
115
+ let indices;
116
+ if (tileOptions.isDracoGeometry) {
117
+ const decompressedGeometry = await parse(arrayBuffer, DracoLoader, {
118
+ draco: {
119
+ attributeNameEntry: I3S_ATTRIBUTE_TYPE
120
+ }
121
+ });
122
+ // @ts-expect-error
123
+ vertexCount = decompressedGeometry.header.vertexCount;
124
+ indices = decompressedGeometry.indices?.value;
125
+ const { POSITION, NORMAL, COLOR_0, TEXCOORD_0, ['feature-index']: featureIndex, ['uv-region']: uvRegion } = decompressedGeometry.attributes;
126
+ attributes = {
127
+ position: POSITION,
128
+ normal: NORMAL,
129
+ color: COLOR_0,
130
+ uv0: TEXCOORD_0,
131
+ uvRegion,
132
+ id: featureIndex
133
+ };
134
+ updateAttributesMetadata(attributes, decompressedGeometry);
135
+ const featureIds = getFeatureIdsFromFeatureIndexMetadata(featureIndex);
136
+ if (featureIds) {
137
+ flattenFeatureIdsByFeatureIndices(attributes, featureIds);
138
+ }
139
+ }
140
+ else {
141
+ const { vertexAttributes, ordering: attributesOrder, featureAttributes, featureAttributeOrder } = tilesetOptions.store.defaultGeometrySchema;
142
+ // First 8 bytes reserved for header (vertexCount and featureCount)
143
+ const headers = parseHeaders(arrayBuffer, tilesetOptions);
144
+ byteOffset = headers.byteOffset;
145
+ vertexCount = headers.vertexCount;
146
+ featureCount = headers.featureCount;
147
+ // Getting vertex attributes such as positions, normals, colors, etc...
148
+ const { attributes: normalizedVertexAttributes, byteOffset: offset } = normalizeAttributes(arrayBuffer, byteOffset, vertexAttributes, vertexCount, attributesOrder);
149
+ // Getting feature attributes such as featureIds and faceRange
150
+ const { attributes: normalizedFeatureAttributes } = normalizeAttributes(arrayBuffer, offset, featureAttributes, featureCount, featureAttributeOrder);
151
+ flattenFeatureIdsByFaceRanges(normalizedFeatureAttributes);
152
+ attributes = concatAttributes(normalizedVertexAttributes, normalizedFeatureAttributes);
153
+ }
154
+ if (!options?.i3s?.coordinateSystem ||
155
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
156
+ options.i3s.coordinateSystem === COORDINATE_SYSTEM.METER_OFFSETS) {
157
+ const enuMatrix = parsePositions(attributes.position, tileOptions);
158
+ content.modelMatrix = enuMatrix.invert();
159
+ content.coordinateSystem = COORDINATE_SYSTEM.METER_OFFSETS;
160
+ }
161
+ else {
162
+ content.modelMatrix = getModelMatrix(attributes.position);
163
+ content.coordinateSystem = COORDINATE_SYSTEM.LNGLAT_OFFSETS;
164
+ }
165
+ content.attributes = {
166
+ positions: attributes.position,
167
+ normals: attributes.normal,
168
+ colors: normalizeAttribute(attributes.color), // Normalize from UInt8
169
+ texCoords: attributes.uv0,
170
+ uvRegions: normalizeAttribute(attributes.uvRegion || attributes.region) // Normalize from UInt16
126
171
  };
127
- updateAttributesMetadata(attributes, decompressedGeometry);
128
- const featureIds = getFeatureIdsFromFeatureIndexMetadata(featureIndex);
129
- if (featureIds) {
130
- flattenFeatureIdsByFeatureIndices(attributes, featureIds);
131
- }
132
- } else {
133
- const {
134
- vertexAttributes,
135
- ordering: attributesOrder,
136
- featureAttributes,
137
- featureAttributeOrder
138
- } = tilesetOptions.store.defaultGeometrySchema;
139
- const headers = parseHeaders(arrayBuffer, tilesetOptions);
140
- byteOffset = headers.byteOffset;
141
- vertexCount = headers.vertexCount;
142
- featureCount = headers.featureCount;
143
- const {
144
- attributes: normalizedVertexAttributes,
145
- byteOffset: offset
146
- } = normalizeAttributes(arrayBuffer, byteOffset, vertexAttributes, vertexCount, attributesOrder);
147
- const {
148
- attributes: normalizedFeatureAttributes
149
- } = normalizeAttributes(arrayBuffer, offset, featureAttributes, featureCount, featureAttributeOrder);
150
- flattenFeatureIdsByFaceRanges(normalizedFeatureAttributes);
151
- attributes = concatAttributes(normalizedVertexAttributes, normalizedFeatureAttributes);
152
- }
153
- if (!(options !== null && options !== void 0 && (_options$i3s2 = options.i3s) !== null && _options$i3s2 !== void 0 && _options$i3s2.coordinateSystem) || options.i3s.coordinateSystem === COORDINATE_SYSTEM.METER_OFFSETS) {
154
- const enuMatrix = parsePositions(attributes.position, tileOptions);
155
- content.modelMatrix = enuMatrix.invert();
156
- content.coordinateSystem = COORDINATE_SYSTEM.METER_OFFSETS;
157
- } else {
158
- content.modelMatrix = getModelMatrix(attributes.position);
159
- content.coordinateSystem = COORDINATE_SYSTEM.LNGLAT_OFFSETS;
160
- }
161
- content.attributes = {
162
- positions: attributes.position,
163
- normals: attributes.normal,
164
- colors: normalizeAttribute(attributes.color),
165
- texCoords: attributes.uv0,
166
- uvRegions: normalizeAttribute(attributes.uvRegion || attributes.region)
167
- };
168
- content.indices = indices || null;
169
- if (attributes.id && attributes.id.value) {
170
- content.featureIds = attributes.id.value;
171
- }
172
- for (const attributeIndex in content.attributes) {
173
- if (!content.attributes[attributeIndex]) {
174
- delete content.attributes[attributeIndex];
175
- }
176
- }
177
- content.vertexCount = vertexCount;
178
- content.byteLength = contentByteLength;
179
- return content;
172
+ content.indices = indices || null;
173
+ if (attributes.id && attributes.id.value) {
174
+ content.featureIds = attributes.id.value;
175
+ }
176
+ // Remove undefined attributes
177
+ for (const attributeIndex in content.attributes) {
178
+ if (!content.attributes[attributeIndex]) {
179
+ delete content.attributes[attributeIndex];
180
+ }
181
+ }
182
+ content.vertexCount = vertexCount;
183
+ content.byteLength = contentByteLength;
184
+ return content;
180
185
  }
186
+ /**
187
+ * Update attributes with metadata from decompressed geometry.
188
+ * @param decompressedGeometry
189
+ * @param attributes
190
+ */
181
191
  function updateAttributesMetadata(attributes, decompressedGeometry) {
182
- for (const key in decompressedGeometry.loaderData.attributes) {
183
- const dracoAttribute = decompressedGeometry.loaderData.attributes[key];
184
- switch (dracoAttribute.name) {
185
- case 'POSITION':
186
- attributes.position.metadata = dracoAttribute.metadata;
187
- break;
188
- case 'feature-index':
189
- attributes.id.metadata = dracoAttribute.metadata;
190
- break;
191
- default:
192
- break;
193
- }
194
- }
192
+ for (const key in decompressedGeometry.loaderData.attributes) {
193
+ const dracoAttribute = decompressedGeometry.loaderData.attributes[key];
194
+ switch (dracoAttribute.name) {
195
+ case 'POSITION':
196
+ attributes.position.metadata = dracoAttribute.metadata;
197
+ break;
198
+ case 'feature-index':
199
+ attributes.id.metadata = dracoAttribute.metadata;
200
+ break;
201
+ default:
202
+ break;
203
+ }
204
+ }
195
205
  }
206
+ /**
207
+ * Do concatenation of attribute objects.
208
+ * Done as separate fucntion to avoid ts errors.
209
+ * @param normalizedVertexAttributes
210
+ * @param normalizedFeatureAttributes
211
+ * @returns - result of attributes concatenation.
212
+ */
196
213
  function concatAttributes(normalizedVertexAttributes, normalizedFeatureAttributes) {
197
- return {
198
- ...normalizedVertexAttributes,
199
- ...normalizedFeatureAttributes
200
- };
214
+ return { ...normalizedVertexAttributes, ...normalizedFeatureAttributes };
201
215
  }
216
+ /**
217
+ * Normalize attribute to range [0..1] . Eg. convert colors buffer from [255,255,255,255] to [1,1,1,1]
218
+ * @param attribute - geometry attribute
219
+ * @returns - geometry attribute in right format
220
+ */
202
221
  function normalizeAttribute(attribute) {
203
- if (!attribute) {
222
+ if (!attribute) {
223
+ return attribute;
224
+ }
225
+ attribute.normalized = true;
204
226
  return attribute;
205
- }
206
- attribute.normalized = true;
207
- return attribute;
208
227
  }
209
228
  function parseHeaders(arrayBuffer, options) {
210
- let byteOffset = 0;
211
- let vertexCount = 0;
212
- let featureCount = 0;
213
- for (const {
214
- property,
215
- type
216
- } of options.store.defaultGeometrySchema.header) {
217
- const TypedArrayTypeHeader = getConstructorForDataFormat(type);
218
- switch (property) {
219
- case HeaderAttributeProperty.vertexCount:
220
- vertexCount = new TypedArrayTypeHeader(arrayBuffer, 0, 4)[0];
221
- byteOffset += sizeOf(type);
222
- break;
223
- case HeaderAttributeProperty.featureCount:
224
- featureCount = new TypedArrayTypeHeader(arrayBuffer, 4, 4)[0];
225
- byteOffset += sizeOf(type);
226
- break;
227
- default:
228
- break;
229
- }
230
- }
231
- return {
232
- vertexCount,
233
- featureCount,
234
- byteOffset
235
- };
229
+ let byteOffset = 0;
230
+ // First 8 bytes reserved for header (vertexCount and featurecount)
231
+ let vertexCount = 0;
232
+ let featureCount = 0;
233
+ for (const { property, type } of options.store.defaultGeometrySchema.header) {
234
+ const TypedArrayTypeHeader = getConstructorForDataFormat(type);
235
+ switch (property) {
236
+ case HeaderAttributeProperty.vertexCount:
237
+ vertexCount = new TypedArrayTypeHeader(arrayBuffer, 0, 4)[0];
238
+ byteOffset += sizeOf(type);
239
+ break;
240
+ case HeaderAttributeProperty.featureCount:
241
+ featureCount = new TypedArrayTypeHeader(arrayBuffer, 4, 4)[0];
242
+ byteOffset += sizeOf(type);
243
+ break;
244
+ default:
245
+ break;
246
+ }
247
+ }
248
+ return {
249
+ vertexCount,
250
+ featureCount,
251
+ byteOffset
252
+ };
236
253
  }
254
+ /* eslint-enable max-statements */
237
255
  function normalizeAttributes(arrayBuffer, byteOffset, vertexAttributes, attributeCount, attributesOrder) {
238
- const attributes = {};
239
- for (const attribute of attributesOrder) {
240
- if (vertexAttributes[attribute]) {
241
- const {
242
- valueType,
243
- valuesPerElement
244
- } = vertexAttributes[attribute];
245
- if (byteOffset + attributeCount * valuesPerElement * sizeOf(valueType) <= arrayBuffer.byteLength) {
246
- const buffer = arrayBuffer.slice(byteOffset);
247
- let value;
248
- if (valueType === 'UInt64') {
249
- value = parseUint64Values(buffer, attributeCount * valuesPerElement, sizeOf(valueType));
250
- } else {
251
- const TypedArrayType = getConstructorForDataFormat(valueType);
252
- value = new TypedArrayType(buffer, 0, attributeCount * valuesPerElement);
253
- }
254
- attributes[attribute] = {
255
- value,
256
- type: GL_TYPE_MAP[valueType],
257
- size: valuesPerElement
258
- };
259
- switch (attribute) {
260
- case 'color':
261
- attributes.color.normalized = true;
262
- break;
263
- case 'position':
264
- case 'region':
265
- case 'normal':
266
- default:
256
+ const attributes = {};
257
+ // the order of attributes depend on the order being added to the vertexAttributes object
258
+ for (const attribute of attributesOrder) {
259
+ if (vertexAttributes[attribute]) {
260
+ const { valueType, valuesPerElement } = vertexAttributes[attribute];
261
+ // protect from arrayBuffer read overunns by NOT assuming node has regions always even though its declared in defaultGeometrySchema.
262
+ // In i3s 1.6: client is required to decide that based on ./shared resource of the node (materialDefinitions.[Mat_id].params.vertexRegions == true)
263
+ // In i3s 1.7 the property has been rolled into the 3d scene layer json/node pages.
264
+ // Code below does not account when the bytelength is actually bigger than
265
+ // the calculated value (b\c the tile potentially could have mesh segmentation information).
266
+ // In those cases tiles without regions could fail or have garbage values.
267
+ if (byteOffset + attributeCount * valuesPerElement * sizeOf(valueType) <=
268
+ arrayBuffer.byteLength) {
269
+ const buffer = arrayBuffer.slice(byteOffset);
270
+ let value;
271
+ if (valueType === 'UInt64') {
272
+ value = parseUint64Values(buffer, attributeCount * valuesPerElement, sizeOf(valueType));
273
+ }
274
+ else {
275
+ const TypedArrayType = getConstructorForDataFormat(valueType);
276
+ value = new TypedArrayType(buffer, 0, attributeCount * valuesPerElement);
277
+ }
278
+ attributes[attribute] = {
279
+ value,
280
+ type: GL_TYPE_MAP[valueType],
281
+ size: valuesPerElement
282
+ };
283
+ switch (attribute) {
284
+ case 'color':
285
+ attributes.color.normalized = true;
286
+ break;
287
+ case 'position':
288
+ case 'region':
289
+ case 'normal':
290
+ default:
291
+ }
292
+ byteOffset = byteOffset + attributeCount * valuesPerElement * sizeOf(valueType);
293
+ }
294
+ else if (attribute !== 'uv0') {
295
+ break;
296
+ }
267
297
  }
268
- byteOffset = byteOffset + attributeCount * valuesPerElement * sizeOf(valueType);
269
- } else if (attribute !== 'uv0') {
270
- break;
271
- }
272
- }
273
- }
274
- return {
275
- attributes,
276
- byteOffset
277
- };
298
+ }
299
+ return { attributes, byteOffset };
278
300
  }
301
+ /**
302
+ * Parse buffer to return array of uint64 values
303
+ *
304
+ * @param buffer
305
+ * @param elementsCount
306
+ * @returns 64-bit array of values until precision is lost after Number.MAX_SAFE_INTEGER
307
+ */
279
308
  function parseUint64Values(buffer, elementsCount, attributeSize) {
280
- const values = [];
281
- const dataView = new DataView(buffer);
282
- let offset = 0;
283
- for (let index = 0; index < elementsCount; index++) {
284
- const left = dataView.getUint32(offset, true);
285
- const right = dataView.getUint32(offset + 4, true);
286
- const value = left + 2 ** 32 * right;
287
- values.push(value);
288
- offset += attributeSize;
289
- }
290
- return new Uint32Array(values);
309
+ const values = [];
310
+ const dataView = new DataView(buffer);
311
+ let offset = 0;
312
+ for (let index = 0; index < elementsCount; index++) {
313
+ // split 64-bit number into two 32-bit parts
314
+ const left = dataView.getUint32(offset, true);
315
+ const right = dataView.getUint32(offset + 4, true);
316
+ // combine the two 32-bit values
317
+ const value = left + 2 ** 32 * right;
318
+ values.push(value);
319
+ offset += attributeSize;
320
+ }
321
+ return new Uint32Array(values);
291
322
  }
292
323
  function parsePositions(attribute, options) {
293
- const mbs = options.mbs;
294
- const value = attribute.value;
295
- const metadata = attribute.metadata;
296
- const enuMatrix = new Matrix4();
297
- const cartographicOrigin = new Vector3(mbs[0], mbs[1], mbs[2]);
298
- const cartesianOrigin = new Vector3();
299
- Ellipsoid.WGS84.cartographicToCartesian(cartographicOrigin, cartesianOrigin);
300
- Ellipsoid.WGS84.eastNorthUpToFixedFrame(cartesianOrigin, enuMatrix);
301
- attribute.value = offsetsToCartesians(value, metadata, cartographicOrigin);
302
- return enuMatrix;
324
+ const mbs = options.mbs;
325
+ const value = attribute.value;
326
+ const metadata = attribute.metadata;
327
+ const enuMatrix = new Matrix4();
328
+ const cartographicOrigin = new Vector3(mbs[0], mbs[1], mbs[2]);
329
+ const cartesianOrigin = new Vector3();
330
+ Ellipsoid.WGS84.cartographicToCartesian(cartographicOrigin, cartesianOrigin);
331
+ Ellipsoid.WGS84.eastNorthUpToFixedFrame(cartesianOrigin, enuMatrix);
332
+ attribute.value = offsetsToCartesians(value, metadata, cartographicOrigin);
333
+ return enuMatrix;
303
334
  }
304
- function offsetsToCartesians(vertices) {
305
- let metadata = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
306
- let cartographicOrigin = arguments.length > 2 ? arguments[2] : undefined;
307
- const positions = new Float64Array(vertices.length);
308
- const scaleX = metadata['i3s-scale_x'] && metadata['i3s-scale_x'].double || 1;
309
- const scaleY = metadata['i3s-scale_y'] && metadata['i3s-scale_y'].double || 1;
310
- for (let i = 0; i < positions.length; i += 3) {
311
- positions[i] = vertices[i] * scaleX + cartographicOrigin.x;
312
- positions[i + 1] = vertices[i + 1] * scaleY + cartographicOrigin.y;
313
- positions[i + 2] = vertices[i + 2] + cartographicOrigin.z;
314
- }
315
- for (let i = 0; i < positions.length; i += 3) {
316
- Ellipsoid.WGS84.cartographicToCartesian(positions.subarray(i, i + 3), scratchVector);
317
- positions[i] = scratchVector.x;
318
- positions[i + 1] = scratchVector.y;
319
- positions[i + 2] = scratchVector.z;
320
- }
321
- return positions;
335
+ /**
336
+ * Converts position coordinates to absolute cartesian coordinates
337
+ * @param vertices - "position" attribute data
338
+ * @param metadata - When the geometry is DRACO compressed, contain position attribute's metadata
339
+ * https://github.com/Esri/i3s-spec/blob/master/docs/1.7/compressedAttributes.cmn.md
340
+ * @param cartographicOrigin - Cartographic origin coordinates
341
+ * @returns - converted "position" data
342
+ */
343
+ function offsetsToCartesians(vertices, metadata = {}, cartographicOrigin) {
344
+ const positions = new Float64Array(vertices.length);
345
+ const scaleX = (metadata['i3s-scale_x'] && metadata['i3s-scale_x'].double) || 1;
346
+ const scaleY = (metadata['i3s-scale_y'] && metadata['i3s-scale_y'].double) || 1;
347
+ for (let i = 0; i < positions.length; i += 3) {
348
+ positions[i] = vertices[i] * scaleX + cartographicOrigin.x;
349
+ positions[i + 1] = vertices[i + 1] * scaleY + cartographicOrigin.y;
350
+ positions[i + 2] = vertices[i + 2] + cartographicOrigin.z;
351
+ }
352
+ for (let i = 0; i < positions.length; i += 3) {
353
+ // @ts-ignore
354
+ Ellipsoid.WGS84.cartographicToCartesian(positions.subarray(i, i + 3), scratchVector);
355
+ positions[i] = scratchVector.x;
356
+ positions[i + 1] = scratchVector.y;
357
+ positions[i + 2] = scratchVector.z;
358
+ }
359
+ return positions;
322
360
  }
361
+ /**
362
+ * Get model matrix for loaded vertices
363
+ * @param positions positions attribute
364
+ * @returns Matrix4 - model matrix for geometry transformation
365
+ */
323
366
  function getModelMatrix(positions) {
324
- var _metadata$i3sScale_x, _metadata$i3sScale_y;
325
- const metadata = positions.metadata;
326
- const scaleX = (metadata === null || metadata === void 0 ? void 0 : (_metadata$i3sScale_x = metadata['i3s-scale_x']) === null || _metadata$i3sScale_x === void 0 ? void 0 : _metadata$i3sScale_x.double) || 1;
327
- const scaleY = (metadata === null || metadata === void 0 ? void 0 : (_metadata$i3sScale_y = metadata['i3s-scale_y']) === null || _metadata$i3sScale_y === void 0 ? void 0 : _metadata$i3sScale_y.double) || 1;
328
- const modelMatrix = new Matrix4();
329
- modelMatrix[0] = scaleX;
330
- modelMatrix[5] = scaleY;
331
- return modelMatrix;
367
+ const metadata = positions.metadata;
368
+ const scaleX = metadata?.['i3s-scale_x']?.double || 1;
369
+ const scaleY = metadata?.['i3s-scale_y']?.double || 1;
370
+ const modelMatrix = new Matrix4();
371
+ modelMatrix[0] = scaleX;
372
+ modelMatrix[5] = scaleY;
373
+ return modelMatrix;
332
374
  }
375
+ /**
376
+ * Makes a glTF-compatible PBR material from an I3S material definition
377
+ * @param materialDefinition - i3s material definition
378
+ * https://github.com/Esri/i3s-spec/blob/master/docs/1.7/materialDefinitions.cmn.md
379
+ * @param texture - texture image
380
+ * @returns {object}
381
+ */
333
382
  function makePbrMaterial(materialDefinition, texture) {
334
- let pbrMaterial;
335
- if (materialDefinition) {
336
- pbrMaterial = {
337
- ...materialDefinition,
338
- pbrMetallicRoughness: materialDefinition.pbrMetallicRoughness ? {
339
- ...materialDefinition.pbrMetallicRoughness
340
- } : {
341
- baseColorFactor: [255, 255, 255, 255]
342
- }
343
- };
344
- } else {
345
- pbrMaterial = {
346
- pbrMetallicRoughness: {}
347
- };
383
+ let pbrMaterial;
384
+ if (materialDefinition) {
385
+ pbrMaterial = {
386
+ ...materialDefinition,
387
+ pbrMetallicRoughness: materialDefinition.pbrMetallicRoughness
388
+ ? { ...materialDefinition.pbrMetallicRoughness }
389
+ : { baseColorFactor: [255, 255, 255, 255] }
390
+ };
391
+ }
392
+ else {
393
+ pbrMaterial = {
394
+ pbrMetallicRoughness: {}
395
+ };
396
+ if (texture) {
397
+ pbrMaterial.pbrMetallicRoughness.baseColorTexture = { texCoord: 0 };
398
+ }
399
+ else {
400
+ pbrMaterial.pbrMetallicRoughness.baseColorFactor = [255, 255, 255, 255];
401
+ }
402
+ }
403
+ // Set default 0.25 per spec https://github.com/Esri/i3s-spec/blob/master/docs/1.7/materialDefinitions.cmn.md
404
+ pbrMaterial.alphaCutoff = pbrMaterial.alphaCutoff || 0.25;
405
+ if (pbrMaterial.alphaMode) {
406
+ // I3S contain alphaMode in lowerCase
407
+ pbrMaterial.alphaMode = pbrMaterial.alphaMode.toUpperCase();
408
+ }
409
+ // Convert colors from [255,255,255,255] to [1,1,1,1]
410
+ if (pbrMaterial.emissiveFactor) {
411
+ pbrMaterial.emissiveFactor = convertColorFormat(pbrMaterial.emissiveFactor);
412
+ }
413
+ if (pbrMaterial.pbrMetallicRoughness && pbrMaterial.pbrMetallicRoughness.baseColorFactor) {
414
+ pbrMaterial.pbrMetallicRoughness.baseColorFactor = convertColorFormat(pbrMaterial.pbrMetallicRoughness.baseColorFactor);
415
+ }
348
416
  if (texture) {
349
- pbrMaterial.pbrMetallicRoughness.baseColorTexture = {
350
- texCoord: 0
351
- };
352
- } else {
353
- pbrMaterial.pbrMetallicRoughness.baseColorFactor = [255, 255, 255, 255];
354
- }
355
- }
356
- pbrMaterial.alphaCutoff = pbrMaterial.alphaCutoff || 0.25;
357
- if (pbrMaterial.alphaMode) {
358
- pbrMaterial.alphaMode = pbrMaterial.alphaMode.toUpperCase();
359
- }
360
- if (pbrMaterial.emissiveFactor) {
361
- pbrMaterial.emissiveFactor = convertColorFormat(pbrMaterial.emissiveFactor);
362
- }
363
- if (pbrMaterial.pbrMetallicRoughness && pbrMaterial.pbrMetallicRoughness.baseColorFactor) {
364
- pbrMaterial.pbrMetallicRoughness.baseColorFactor = convertColorFormat(pbrMaterial.pbrMetallicRoughness.baseColorFactor);
365
- }
366
- if (texture) {
367
- setMaterialTexture(pbrMaterial, texture);
368
- }
369
- return pbrMaterial;
417
+ setMaterialTexture(pbrMaterial, texture);
418
+ }
419
+ return pbrMaterial;
370
420
  }
421
+ /**
422
+ * Convert color from [255,255,255,255] to [1,1,1,1]
423
+ * @param colorFactor - color array
424
+ * @returns - new color array
425
+ */
371
426
  function convertColorFormat(colorFactor) {
372
- const normalizedColor = [...colorFactor];
373
- for (let index = 0; index < colorFactor.length; index++) {
374
- normalizedColor[index] = colorFactor[index] / 255;
375
- }
376
- return normalizedColor;
427
+ const normalizedColor = [...colorFactor];
428
+ for (let index = 0; index < colorFactor.length; index++) {
429
+ normalizedColor[index] = colorFactor[index] / 255;
430
+ }
431
+ return normalizedColor;
377
432
  }
433
+ /**
434
+ * Set texture in PBR material
435
+ * @param {object} material - i3s material definition
436
+ * @param image - texture image
437
+ * @returns
438
+ */
378
439
  function setMaterialTexture(material, image) {
379
- const texture = {
380
- source: {
381
- image
382
- }
383
- };
384
- if (material.pbrMetallicRoughness && material.pbrMetallicRoughness.baseColorTexture) {
385
- material.pbrMetallicRoughness.baseColorTexture = {
386
- ...material.pbrMetallicRoughness.baseColorTexture,
387
- texture
388
- };
389
- } else if (material.emissiveTexture) {
390
- material.emissiveTexture = {
391
- ...material.emissiveTexture,
392
- texture
393
- };
394
- } else if (material.pbrMetallicRoughness && material.pbrMetallicRoughness.metallicRoughnessTexture) {
395
- material.pbrMetallicRoughness.metallicRoughnessTexture = {
396
- ...material.pbrMetallicRoughness.metallicRoughnessTexture,
397
- texture
398
- };
399
- } else if (material.normalTexture) {
400
- material.normalTexture = {
401
- ...material.normalTexture,
402
- texture
403
- };
404
- } else if (material.occlusionTexture) {
405
- material.occlusionTexture = {
406
- ...material.occlusionTexture,
407
- texture
408
- };
409
- }
440
+ const texture = { source: { image } };
441
+ // I3SLoader now support loading only one texture. This elseif sequence will assign this texture to one of
442
+ // properties defined in materialDefinition
443
+ if (material.pbrMetallicRoughness && material.pbrMetallicRoughness.baseColorTexture) {
444
+ material.pbrMetallicRoughness.baseColorTexture = {
445
+ ...material.pbrMetallicRoughness.baseColorTexture,
446
+ texture
447
+ };
448
+ }
449
+ else if (material.emissiveTexture) {
450
+ material.emissiveTexture = { ...material.emissiveTexture, texture };
451
+ }
452
+ else if (material.pbrMetallicRoughness &&
453
+ material.pbrMetallicRoughness.metallicRoughnessTexture) {
454
+ material.pbrMetallicRoughness.metallicRoughnessTexture = {
455
+ ...material.pbrMetallicRoughness.metallicRoughnessTexture,
456
+ texture
457
+ };
458
+ }
459
+ else if (material.normalTexture) {
460
+ material.normalTexture = { ...material.normalTexture, texture };
461
+ }
462
+ else if (material.occlusionTexture) {
463
+ material.occlusionTexture = { ...material.occlusionTexture, texture };
464
+ }
410
465
  }
466
+ /**
467
+ * Flatten feature ids using face ranges
468
+ * @param normalizedFeatureAttributes
469
+ * @returns
470
+ */
411
471
  function flattenFeatureIdsByFaceRanges(normalizedFeatureAttributes) {
412
- const {
413
- id,
414
- faceRange
415
- } = normalizedFeatureAttributes;
416
- if (!id || !faceRange) {
417
- return;
418
- }
419
- const featureIds = id.value;
420
- const range = faceRange.value;
421
- const featureIdsLength = range[range.length - 1] + 1;
422
- const orderedFeatureIndices = new Uint32Array(featureIdsLength * 3);
423
- let featureIndex = 0;
424
- let startIndex = 0;
425
- for (let index = 1; index < range.length; index += 2) {
426
- const fillId = Number(featureIds[featureIndex]);
427
- const endValue = range[index];
428
- const prevValue = range[index - 1];
429
- const trianglesCount = endValue - prevValue + 1;
430
- const endIndex = startIndex + trianglesCount * 3;
431
- orderedFeatureIndices.fill(fillId, startIndex, endIndex);
432
- featureIndex++;
433
- startIndex = endIndex;
434
- }
435
- normalizedFeatureAttributes.id.value = orderedFeatureIndices;
472
+ const { id, faceRange } = normalizedFeatureAttributes;
473
+ if (!id || !faceRange) {
474
+ return;
475
+ }
476
+ const featureIds = id.value;
477
+ const range = faceRange.value;
478
+ const featureIdsLength = range[range.length - 1] + 1;
479
+ const orderedFeatureIndices = new Uint32Array(featureIdsLength * 3);
480
+ let featureIndex = 0;
481
+ let startIndex = 0;
482
+ for (let index = 1; index < range.length; index += 2) {
483
+ const fillId = Number(featureIds[featureIndex]);
484
+ const endValue = range[index];
485
+ const prevValue = range[index - 1];
486
+ const trianglesCount = endValue - prevValue + 1;
487
+ const endIndex = startIndex + trianglesCount * 3;
488
+ orderedFeatureIndices.fill(fillId, startIndex, endIndex);
489
+ featureIndex++;
490
+ startIndex = endIndex;
491
+ }
492
+ normalizedFeatureAttributes.id.value = orderedFeatureIndices;
436
493
  }
494
+ /**
495
+ * Flatten feature ids using featureIndices
496
+ * @param attributes
497
+ * @param featureIds
498
+ * @returns
499
+ */
437
500
  function flattenFeatureIdsByFeatureIndices(attributes, featureIds) {
438
- const featureIndices = attributes.id.value;
439
- const result = new Float32Array(featureIndices.length);
440
- for (let index = 0; index < featureIndices.length; index++) {
441
- result[index] = featureIds[featureIndices[index]];
442
- }
443
- attributes.id.value = result;
501
+ const featureIndices = attributes.id.value;
502
+ const result = new Float32Array(featureIndices.length);
503
+ for (let index = 0; index < featureIndices.length; index++) {
504
+ result[index] = featureIds[featureIndices[index]];
505
+ }
506
+ attributes.id.value = result;
444
507
  }
508
+ /**
509
+ * Flatten feature ids using featureIndices
510
+ * @param featureIndex
511
+ * @returns
512
+ */
445
513
  function getFeatureIdsFromFeatureIndexMetadata(featureIndex) {
446
- var _featureIndex$metadat, _featureIndex$metadat2;
447
- return featureIndex === null || featureIndex === void 0 ? void 0 : (_featureIndex$metadat = featureIndex.metadata) === null || _featureIndex$metadat === void 0 ? void 0 : (_featureIndex$metadat2 = _featureIndex$metadat['i3s-feature-ids']) === null || _featureIndex$metadat2 === void 0 ? void 0 : _featureIndex$metadat2.intArray;
514
+ return featureIndex?.metadata?.['i3s-feature-ids']?.intArray;
448
515
  }
449
- //# sourceMappingURL=parse-i3s-tile-content.js.map