@loaders.gl/i3s 3.1.0-beta.7 → 3.1.3

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 (91) hide show
  1. package/dist/bundle.js +5 -10364
  2. package/dist/dist.min.js +10371 -0
  3. package/dist/es5/bundle.js +1 -1
  4. package/dist/es5/bundle.js.map +1 -1
  5. package/dist/es5/i3s-attribute-loader.js +147 -62
  6. package/dist/es5/i3s-attribute-loader.js.map +1 -1
  7. package/dist/es5/i3s-building-scene-layer-loader.js +36 -8
  8. package/dist/es5/i3s-building-scene-layer-loader.js.map +1 -1
  9. package/dist/es5/i3s-content-loader.js +36 -10
  10. package/dist/es5/i3s-content-loader.js.map +1 -1
  11. package/dist/es5/i3s-loader.js +175 -51
  12. package/dist/es5/i3s-loader.js.map +1 -1
  13. package/dist/es5/i3s-node-page-loader.js +51 -8
  14. package/dist/es5/i3s-node-page-loader.js.map +1 -1
  15. package/dist/es5/index.js +6 -6
  16. package/dist/es5/index.js.map +1 -1
  17. package/dist/es5/lib/helpers/i3s-nodepages-tiles.js +328 -173
  18. package/dist/es5/lib/helpers/i3s-nodepages-tiles.js.map +1 -1
  19. package/dist/es5/lib/parsers/constants.js +9 -28
  20. package/dist/es5/lib/parsers/constants.js.map +1 -1
  21. package/dist/es5/lib/parsers/parse-i3s-attribute.js +69 -27
  22. package/dist/es5/lib/parsers/parse-i3s-attribute.js.map +1 -1
  23. package/dist/es5/lib/parsers/parse-i3s-building-scene-layer.js +62 -28
  24. package/dist/es5/lib/parsers/parse-i3s-building-scene-layer.js.map +1 -1
  25. package/dist/es5/lib/parsers/parse-i3s-tile-content.js +416 -314
  26. package/dist/es5/lib/parsers/parse-i3s-tile-content.js.map +1 -1
  27. package/dist/es5/lib/parsers/parse-i3s.js +109 -49
  28. package/dist/es5/lib/parsers/parse-i3s.js.map +1 -1
  29. package/dist/es5/lib/utils/convert-i3s-obb-to-mbs.js +8 -4
  30. package/dist/es5/lib/utils/convert-i3s-obb-to-mbs.js.map +1 -1
  31. package/dist/es5/lib/utils/url-utils.js +14 -17
  32. package/dist/es5/lib/utils/url-utils.js.map +1 -1
  33. package/dist/es5/types.js +10 -2
  34. package/dist/es5/types.js.map +1 -1
  35. package/dist/esm/i3s-attribute-loader.js +1 -1
  36. package/dist/esm/i3s-attribute-loader.js.map +1 -1
  37. package/dist/esm/i3s-building-scene-layer-loader.js +1 -1
  38. package/dist/esm/i3s-building-scene-layer-loader.js.map +1 -1
  39. package/dist/esm/i3s-content-loader.js +1 -1
  40. package/dist/esm/i3s-content-loader.js.map +1 -1
  41. package/dist/esm/i3s-loader.js +1 -1
  42. package/dist/esm/i3s-loader.js.map +1 -1
  43. package/dist/esm/i3s-node-page-loader.js +1 -1
  44. package/dist/esm/i3s-node-page-loader.js.map +1 -1
  45. package/dist/esm/index.js.map +1 -1
  46. package/dist/esm/lib/helpers/i3s-nodepages-tiles.js +33 -23
  47. package/dist/esm/lib/helpers/i3s-nodepages-tiles.js.map +1 -1
  48. package/dist/esm/lib/parsers/constants.js +2 -18
  49. package/dist/esm/lib/parsers/constants.js.map +1 -1
  50. package/dist/esm/lib/parsers/parse-i3s-tile-content.js +44 -61
  51. package/dist/esm/lib/parsers/parse-i3s-tile-content.js.map +1 -1
  52. package/dist/esm/lib/parsers/parse-i3s.js +40 -25
  53. package/dist/esm/lib/parsers/parse-i3s.js.map +1 -1
  54. package/dist/esm/lib/utils/url-utils.js +2 -3
  55. package/dist/esm/lib/utils/url-utils.js.map +1 -1
  56. package/dist/esm/types.js +7 -0
  57. package/dist/esm/types.js.map +1 -1
  58. package/dist/i3s-building-scene-layer-loader.js +1 -1
  59. package/dist/i3s-content-loader.js +1 -1
  60. package/dist/i3s-content-worker.js +106 -95
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/lib/helpers/i3s-nodepages-tiles.d.ts +20 -20
  64. package/dist/lib/helpers/i3s-nodepages-tiles.d.ts.map +1 -1
  65. package/dist/lib/helpers/i3s-nodepages-tiles.js +33 -32
  66. package/dist/lib/parsers/constants.d.ts +1 -17
  67. package/dist/lib/parsers/constants.d.ts.map +1 -1
  68. package/dist/lib/parsers/constants.js +3 -21
  69. package/dist/lib/parsers/parse-i3s-attribute.d.ts +1 -1
  70. package/dist/lib/parsers/parse-i3s-tile-content.d.ts +2 -2
  71. package/dist/lib/parsers/parse-i3s-tile-content.d.ts.map +1 -1
  72. package/dist/lib/parsers/parse-i3s-tile-content.js +35 -61
  73. package/dist/lib/parsers/parse-i3s.d.ts +5 -3
  74. package/dist/lib/parsers/parse-i3s.d.ts.map +1 -1
  75. package/dist/lib/parsers/parse-i3s.js +37 -32
  76. package/dist/lib/utils/url-utils.d.ts +6 -6
  77. package/dist/lib/utils/url-utils.d.ts.map +1 -1
  78. package/dist/lib/utils/url-utils.js +5 -5
  79. package/dist/types.d.ts +289 -74
  80. package/dist/types.d.ts.map +1 -1
  81. package/dist/types.js +6 -1
  82. package/package.json +10 -10
  83. package/src/i3s-building-scene-layer-loader.ts +1 -1
  84. package/src/i3s-content-loader.ts +1 -1
  85. package/src/index.ts +3 -3
  86. package/src/lib/helpers/i3s-nodepages-tiles.ts +71 -55
  87. package/src/lib/parsers/constants.ts +2 -22
  88. package/src/lib/parsers/parse-i3s-tile-content.ts +74 -103
  89. package/src/lib/parsers/parse-i3s.ts +48 -37
  90. package/src/lib/utils/url-utils.ts +7 -7
  91. package/src/types.ts +302 -93
package/src/index.ts CHANGED
@@ -15,13 +15,13 @@ export type {
15
15
  LodSelection,
16
16
  NodeReference,
17
17
  Resource,
18
- I3SGeometry,
19
18
  MaxScreenThresholdSQ,
20
19
  NodeInPage,
21
20
  SharedResources,
22
- TextureImage,
23
21
  Attribute,
24
22
  Extent,
25
- FeatureAttribute
23
+ FeatureAttribute,
24
+ FieldInfo,
25
+ I3SMaterialDefinition
26
26
  } from './types';
27
27
  export {COORDINATE_SYSTEM} from './lib/parsers/constants';
@@ -1,21 +1,33 @@
1
1
  import {load} from '@loaders.gl/core';
2
2
  import {getSupportedGPUTextureFormats, selectSupportedBasisFormat} from '@loaders.gl/textures';
3
- import {Tileset, NodePage} from '../../types';
4
3
  import {I3SNodePageLoader} from '../../i3s-node-page-loader';
5
4
  import {normalizeTileNonUrlData} from '../parsers/parse-i3s';
6
5
  import {getUrlWithToken, generateTilesetAttributeUrls} from '../utils/url-utils';
6
+ import type {LoaderOptions} from '@loaders.gl/loader-utils';
7
+ import {
8
+ I3STilesetHeader,
9
+ LodSelection,
10
+ NodePage,
11
+ NodeInPage,
12
+ Obb,
13
+ MeshMaterial,
14
+ I3SMaterialDefinition,
15
+ I3STextureFormat,
16
+ MeshGeometry,
17
+ I3STileHeader
18
+ } from '../../types';
7
19
 
8
20
  /**
9
21
  * class I3SNodePagesTiles - loads nodePages and form i3s tiles from them
10
22
  */
11
23
  export default class I3SNodePagesTiles {
12
- tileset: Tileset;
24
+ tileset: I3STilesetHeader;
13
25
  nodePages: NodePage[] = [];
14
26
  pendingNodePages: {promise: Promise<NodePage>; status: 'Pending' | 'Done'}[] = [];
15
27
  nodesPerPage: number;
16
- options: {[key: string]: any};
17
- lodSelectionMetricType: any;
18
- textureDefinitionsSelectedFormats: any[] = [];
28
+ options: LoaderOptions;
29
+ lodSelectionMetricType?: string;
30
+ textureDefinitionsSelectedFormats: ({format: I3STextureFormat; name: string} | null)[] = [];
19
31
  private textureLoaderOptions: {[key: string]: any} = {};
20
32
 
21
33
  /**
@@ -24,10 +36,10 @@ export default class I3SNodePagesTiles {
24
36
  * @param tileset - i3s tileset header ('layers/0')
25
37
  * @param options - i3s loader options
26
38
  */
27
- constructor(tileset: Tileset, options: object) {
39
+ constructor(tileset: I3STilesetHeader, options: LoaderOptions) {
28
40
  this.tileset = {...tileset}; // spread the tileset to avoid circular reference
29
- this.nodesPerPage = tileset.nodePages.nodesPerPage;
30
- this.lodSelectionMetricType = tileset.nodePages.lodSelectionMetricType;
41
+ this.nodesPerPage = tileset.nodePages?.nodesPerPage || 64;
42
+ this.lodSelectionMetricType = tileset.nodePages?.lodSelectionMetricType;
31
43
  this.options = options;
32
44
 
33
45
  this.initSelectedFormatsForTextureDefinitions(tileset);
@@ -37,7 +49,7 @@ export default class I3SNodePagesTiles {
37
49
  * Loads some nodePage and return a particular node from it
38
50
  * @param id - id of node through all node pages
39
51
  */
40
- async getNodeById(id: number) {
52
+ async getNodeById(id: number): Promise<NodeInPage> {
41
53
  const pageIndex = Math.floor(id / this.nodesPerPage);
42
54
  if (!this.nodePages[pageIndex] && !this.pendingNodePages[pageIndex]) {
43
55
  const nodePageUrl = getUrlWithToken(
@@ -63,34 +75,33 @@ export default class I3SNodePagesTiles {
63
75
  * @param id - id of node through all node pages
64
76
  */
65
77
  // eslint-disable-next-line complexity
66
- async formTileFromNodePages(id: number) {
67
- const node = await this.getNodeById(id);
68
- const children: any[] = [];
78
+ async formTileFromNodePages(id: number): Promise<I3STileHeader> {
79
+ const node: NodeInPage = await this.getNodeById(id);
80
+ const children: {id: string; obb: Obb}[] = [];
69
81
  for (const child of node.children || []) {
70
82
  const childNode = await this.getNodeById(child);
71
83
  children.push({
72
- id: child,
84
+ id: child.toString(),
73
85
  obb: childNode.obb
74
86
  });
75
87
  }
76
88
 
77
- let contentUrl = null;
78
- let textureUrl: string | null = null;
79
- let materialDefinition = null;
80
- let textureFormat = 'jpeg';
89
+ let contentUrl: string | undefined;
90
+ let textureUrl: string | undefined;
91
+ let materialDefinition: I3SMaterialDefinition | undefined;
92
+ let textureFormat: I3STextureFormat = 'jpg';
81
93
  let attributeUrls: string[] = [];
82
- let isDracoGeometry = false;
94
+ let isDracoGeometry: boolean = false;
83
95
 
84
96
  if (node && node.mesh) {
85
97
  // Get geometry resource URL and type (compressed / non-compressed)
86
98
  const {url, isDracoGeometry: isDracoGeometryResult} = (node.mesh.geometry &&
87
- this.getContentUrl(node.mesh.geometry)) || {url: null, isDracoGeometry: null};
99
+ this.getContentUrl(node.mesh.geometry)) || {isDracoGeometry: false};
88
100
  contentUrl = url;
89
101
  isDracoGeometry = isDracoGeometryResult;
90
102
 
91
- const [textureData, nodeMaterialDefinition] = this.getInformationFromMaterial(
92
- node.mesh.material
93
- );
103
+ const {textureData, materialDefinition: nodeMaterialDefinition} =
104
+ this.getInformationFromMaterial(node.mesh.material);
94
105
  materialDefinition = nodeMaterialDefinition;
95
106
  textureFormat = textureData.format || textureFormat;
96
107
  if (textureData.name) {
@@ -105,7 +116,7 @@ export default class I3SNodePagesTiles {
105
116
  const lodSelection = this.getLodSelection(node);
106
117
 
107
118
  return normalizeTileNonUrlData({
108
- id,
119
+ id: id.toString(),
109
120
  lodSelection,
110
121
  obb: node.obb,
111
122
  contentUrl,
@@ -121,13 +132,14 @@ export default class I3SNodePagesTiles {
121
132
 
122
133
  /**
123
134
  * Forms url and type of geometry resource by nodepage's data and `geometryDefinitions` in the tileset
124
- * @param {Object} meshGeometryData - data about the node's mesh from the nodepage
125
- * @returns {Object} -
135
+ * @param - data about the node's mesh from the nodepage
136
+ * @returns -
126
137
  * {string} url - url to the geometry resource
127
138
  * {boolean} isDracoGeometry - whether the geometry resource contain DRACO compressed geometry
128
139
  */
129
- private getContentUrl(meshGeometryData) {
130
- let result = {};
140
+ private getContentUrl(meshGeometryData: MeshGeometry) {
141
+ let result: {url: string; isDracoGeometry: boolean} | null = null;
142
+ // @ts-ignore
131
143
  const geometryDefinition = this.tileset.geometryDefinitions[meshGeometryData.definition];
132
144
  let geometryIndex = -1;
133
145
  // Try to find DRACO geometryDefinition of `useDracoGeometry` option is set
@@ -156,21 +168,21 @@ export default class I3SNodePagesTiles {
156
168
 
157
169
  /**
158
170
  * Forms 1.6 compatible LOD selection object from a nodepage's node data
159
- * @param {Object} node - a node from nodepage
160
- * @returns {Object[]} - Array of object of following properties:
161
- * {string} metricType - the label of the LOD metric
162
- * {number} maxError - the value of the metric
171
+ * @param node - a node from nodepage
172
+ * @returns- Array of LodSelection
163
173
  */
164
- private getLodSelection(node): object[] {
165
- const lodSelection: object[] = [];
174
+ private getLodSelection(node: NodeInPage): LodSelection[] {
175
+ const lodSelection: LodSelection[] = [];
166
176
  if (this.lodSelectionMetricType === 'maxScreenThresholdSQ') {
167
177
  lodSelection.push({
168
178
  metricType: 'maxScreenThreshold',
179
+ // @ts-ignore
169
180
  maxError: Math.sqrt(node.lodThreshold / (Math.PI * 0.25))
170
181
  });
171
182
  }
172
183
  lodSelection.push({
173
184
  metricType: this.lodSelectionMetricType,
185
+ // @ts-ignore
174
186
  maxError: node.lodThreshold
175
187
  });
176
188
  return lodSelection;
@@ -178,43 +190,47 @@ export default class I3SNodePagesTiles {
178
190
 
179
191
  /**
180
192
  * Returns information about texture and material from `materialDefinitions`
181
- * @param {Object} material - material data from nodepage
182
- * @returns {Object[]} - Couple [textureData, materialDefinition]
193
+ * @param material - material data from nodepage
194
+ * @returns - Couple {textureData, materialDefinition}
183
195
  * {string} textureData.name - path name of the texture
184
196
  * {string} textureData.format - format of the texture
185
197
  * materialDefinition - PBR-like material definition from `materialDefinitions`
186
198
  */
187
- private getInformationFromMaterial(material) {
188
- const textureDataDefault = {name: null, format: null};
199
+ private getInformationFromMaterial(material: MeshMaterial) {
200
+ const informationFromMaterial: {
201
+ textureData: {name: string | null; format?: I3STextureFormat};
202
+ materialDefinition?: I3SMaterialDefinition;
203
+ } = {textureData: {name: null}};
204
+
189
205
  if (material) {
190
- const materialDefinition = this.tileset.materialDefinitions[material.definition];
191
- const textureSetDefinitionIndex =
192
- materialDefinition &&
193
- materialDefinition.pbrMetallicRoughness &&
194
- materialDefinition.pbrMetallicRoughness.baseColorTexture &&
195
- materialDefinition.pbrMetallicRoughness.baseColorTexture.textureSetDefinitionId;
196
- if (textureSetDefinitionIndex || textureSetDefinitionIndex === 0) {
197
- const textureData =
198
- this.textureDefinitionsSelectedFormats[textureSetDefinitionIndex] || textureDataDefault;
199
- return [textureData, materialDefinition];
206
+ const materialDefinition = this.tileset.materialDefinitions?.[material.definition];
207
+ if (materialDefinition) {
208
+ informationFromMaterial.materialDefinition = materialDefinition;
209
+ const textureSetDefinitionIndex =
210
+ materialDefinition?.pbrMetallicRoughness?.baseColorTexture?.textureSetDefinitionId;
211
+
212
+ if (typeof textureSetDefinitionIndex === 'number') {
213
+ informationFromMaterial.textureData =
214
+ this.textureDefinitionsSelectedFormats[textureSetDefinitionIndex] ||
215
+ informationFromMaterial.textureData;
216
+ }
200
217
  }
201
- return [textureDataDefault, materialDefinition];
202
218
  }
203
- return [textureDataDefault, null];
219
+ return informationFromMaterial;
204
220
  }
205
221
 
206
222
  /**
207
223
  * Sets preferable and supported format for each textureDefinition of the tileset
208
- * @param {Object} tileset - I3S layer data
209
- * @returns {void}
224
+ * @param tileset - I3S layer data
225
+ * @returns
210
226
  */
211
- private initSelectedFormatsForTextureDefinitions(tileset) {
227
+ private initSelectedFormatsForTextureDefinitions(tileset: I3STilesetHeader): void {
212
228
  this.textureDefinitionsSelectedFormats = [];
213
229
  const possibleI3sFormats = this.getSupportedTextureFormats();
214
230
  const textureSetDefinitions = tileset.textureSetDefinitions || [];
215
231
  for (const textureSetDefinition of textureSetDefinitions) {
216
232
  const formats = (textureSetDefinition && textureSetDefinition.formats) || [];
217
- let selectedFormat: {format: string; name: string} | null = null;
233
+ let selectedFormat: {name: string; format: I3STextureFormat} | null = null;
218
234
  for (const i3sFormat of possibleI3sFormats) {
219
235
  const format = formats.find((value) => value.format === i3sFormat);
220
236
  if (format) {
@@ -239,8 +255,8 @@ export default class I3SNodePagesTiles {
239
255
  * Returns the array of supported texture format
240
256
  * @returns list of format strings
241
257
  */
242
- private getSupportedTextureFormats(): string[] {
243
- const formats: string[] = [];
258
+ private getSupportedTextureFormats(): I3STextureFormat[] {
259
+ const formats: I3STextureFormat[] = [];
244
260
  if (!this.options.i3s || this.options.i3s.useCompressedTextures) {
245
261
  // I3S 1.7 selection
246
262
  const supportedCompressedFormats = getSupportedGPUTextureFormats();
@@ -14,7 +14,7 @@ export function getConstructorForDataFormat(dataType: string) {
14
14
  case DATA_TYPE.UInt64:
15
15
  return Float64Array;
16
16
  default:
17
- return null;
17
+ throw new Error(`parse i3s tile content: unknown type of data: ${dataType}`);
18
18
  }
19
19
  }
20
20
 
@@ -25,26 +25,6 @@ export const GL_TYPE_MAP: {[key: string]: number} = {
25
25
  UInt32: GL.UNSIGNED_INT,
26
26
  UInt64: GL.DOUBLE
27
27
  };
28
-
29
- export const I3S_NAMED_VERTEX_ATTRIBUTES = {
30
- position: 'position',
31
- normal: 'normal',
32
- uv0: 'uv0',
33
- color: 'color',
34
- region: 'region'
35
- };
36
-
37
- export const I3S_NAMED_GEOMETRY_ATTRIBUTES = {
38
- vertexAttributes: 'vertexAttributes',
39
- featureAttributeOrder: 'featureAttributeOrder',
40
- featureAttributes: 'featureAttributes'
41
- };
42
- // TODO Remove Named Attributes and replase with Typescipt types
43
- export const I3S_NAMED_HEADER_ATTRIBUTES = {
44
- // header: 'header',
45
- vertexCount: 'vertexCount',
46
- featureCount: 'featureCount'
47
- };
48
28
  /**
49
29
  * Returns how many bytes a type occupies
50
30
  * @param dataType
@@ -66,7 +46,7 @@ export function sizeOf(dataType: string): number {
66
46
  case DATA_TYPE.Float64:
67
47
  return 8;
68
48
  default:
69
- return NaN;
49
+ throw new Error(`parse i3s tile content: unknown size of data: ${dataType}`);
70
50
  }
71
51
  }
72
52
 
@@ -2,49 +2,39 @@ import type {TypedArray} from '@loaders.gl/schema';
2
2
  import {load, parse} from '@loaders.gl/core';
3
3
  import {Vector3, Matrix4} from '@math.gl/core';
4
4
  import {Ellipsoid} from '@math.gl/geospatial';
5
-
6
- import type {GLTFMaterial} from '@loaders.gl/gltf';
7
5
  import type {LoaderOptions, LoaderContext} from '@loaders.gl/loader-utils';
8
6
  import {ImageLoader} from '@loaders.gl/images';
9
- import {DracoLoader} from '@loaders.gl/draco';
7
+ import {DracoLoader, DracoMesh} from '@loaders.gl/draco';
10
8
  import {BasisLoader, CompressedTextureLoader} from '@loaders.gl/textures';
11
9
 
12
- import type {
13
- Tileset,
14
- Tile,
10
+ import {
11
+ I3STilesetHeader,
12
+ I3STileHeader,
15
13
  FeatureAttribute,
16
- TileContent,
17
14
  VertexAttribute,
18
- NormalizedAttribute,
19
- NormalizedAttributes,
20
- TileContentTexture
15
+ I3SMeshAttributes,
16
+ I3SMeshAttribute,
17
+ TileContentTexture,
18
+ HeaderAttributeProperty,
19
+ I3SMaterialDefinition
21
20
  } from '../../types';
22
21
  import {getUrlWithToken} from '../utils/url-utils';
23
22
 
24
- import {
25
- GL_TYPE_MAP,
26
- getConstructorForDataFormat,
27
- sizeOf,
28
- I3S_NAMED_HEADER_ATTRIBUTES,
29
- I3S_NAMED_VERTEX_ATTRIBUTES,
30
- I3S_NAMED_GEOMETRY_ATTRIBUTES,
31
- COORDINATE_SYSTEM
32
- } from './constants';
23
+ import {GL_TYPE_MAP, getConstructorForDataFormat, sizeOf, COORDINATE_SYSTEM} from './constants';
33
24
 
34
25
  const scratchVector = new Vector3([0, 0, 0]);
35
26
 
36
- function getLoaderForTextureFormat(textureFormat: 'jpeg' | 'png' | 'ktx-etc2' | 'dds' | 'ktx2') {
27
+ function getLoaderForTextureFormat(textureFormat?: 'jpg' | 'png' | 'ktx-etc2' | 'dds' | 'ktx2') {
37
28
  switch (textureFormat) {
38
- case 'jpeg':
39
- case 'png':
40
- return ImageLoader;
41
29
  case 'ktx-etc2':
42
30
  case 'dds':
43
31
  return CompressedTextureLoader;
44
32
  case 'ktx2':
45
33
  return BasisLoader;
34
+ case 'jpg':
35
+ case 'png':
46
36
  default:
47
- return null;
37
+ return ImageLoader;
48
38
  }
49
39
  }
50
40
 
@@ -52,22 +42,19 @@ const I3S_ATTRIBUTE_TYPE = 'i3s-attribute-type';
52
42
 
53
43
  export async function parseI3STileContent(
54
44
  arrayBuffer: ArrayBuffer,
55
- tile: Tile,
56
- tileset: Tileset,
45
+ tile: I3STileHeader,
46
+ tileset: I3STilesetHeader,
57
47
  options?: LoaderOptions,
58
48
  context?: LoaderContext
59
49
  ) {
60
50
  tile.content = tile.content || {};
61
51
  tile.content.featureIds = tile.content.featureIds || null;
62
52
 
63
- // construct featureData from defaultGeometrySchema;
64
- tile.content.featureData = constructFeatureDataStruct(tileset);
65
53
  tile.content.attributes = {};
66
54
 
67
55
  if (tile.textureUrl) {
68
56
  const url = getUrlWithToken(tile.textureUrl, options?.i3s?.token);
69
- const loader = getLoaderForTextureFormat(tile.textureFormat) || ImageLoader;
70
- // @ts-ignore context must be defined
57
+ const loader = getLoaderForTextureFormat(tile.textureFormat);
71
58
  const response = await fetch(url);
72
59
  const arrayBuffer = await response.arrayBuffer();
73
60
 
@@ -104,30 +91,36 @@ export async function parseI3STileContent(
104
91
  tile.content.texture = null;
105
92
  }
106
93
 
107
- return await parseI3SNodeGeometry(arrayBuffer, tile, options);
94
+ return await parseI3SNodeGeometry(arrayBuffer, tile, tileset, options);
108
95
  }
109
96
 
110
97
  /* eslint-disable max-statements */
111
- async function parseI3SNodeGeometry(arrayBuffer: ArrayBuffer, tile: Tile, options?: LoaderOptions) {
98
+ async function parseI3SNodeGeometry(
99
+ arrayBuffer: ArrayBuffer,
100
+ tile: I3STileHeader,
101
+ tileset: I3STilesetHeader,
102
+ options?: LoaderOptions
103
+ ) {
112
104
  if (!tile.content) {
113
105
  return tile;
114
106
  }
115
107
 
116
108
  const content = tile.content;
117
- let attributes: NormalizedAttributes;
109
+ let attributes: I3SMeshAttributes;
118
110
  let vertexCount: number;
119
111
  let byteOffset: number = 0;
120
112
  let featureCount: number = 0;
113
+ let indices: TypedArray | undefined;
121
114
 
122
115
  if (tile.isDracoGeometry) {
123
- const decompressedGeometry = await parse(arrayBuffer, DracoLoader, {
116
+ const decompressedGeometry: DracoMesh = await parse(arrayBuffer, DracoLoader, {
124
117
  draco: {
125
118
  attributeNameEntry: I3S_ATTRIBUTE_TYPE
126
119
  }
127
120
  });
128
-
121
+ // @ts-expect-error
129
122
  vertexCount = decompressedGeometry.header.vertexCount;
130
- const indices = decompressedGeometry.indices.value;
123
+ indices = decompressedGeometry.indices?.value;
131
124
  const {
132
125
  POSITION,
133
126
  NORMAL,
@@ -143,8 +136,7 @@ async function parseI3SNodeGeometry(arrayBuffer: ArrayBuffer, tile: Tile, option
143
136
  color: COLOR_0,
144
137
  uv0: TEXCOORD_0,
145
138
  uvRegion,
146
- id: featureIndex,
147
- indices
139
+ id: featureIndex
148
140
  };
149
141
 
150
142
  updateAttributesMetadata(attributes, decompressedGeometry);
@@ -155,10 +147,14 @@ async function parseI3SNodeGeometry(arrayBuffer: ArrayBuffer, tile: Tile, option
155
147
  flattenFeatureIdsByFeatureIndices(attributes, featureIds);
156
148
  }
157
149
  } else {
158
- const {vertexAttributes, attributesOrder, featureAttributes, featureAttributeOrder} =
159
- content.featureData;
150
+ const {
151
+ vertexAttributes,
152
+ ordering: attributesOrder,
153
+ featureAttributes,
154
+ featureAttributeOrder
155
+ } = tileset.store.defaultGeometrySchema;
160
156
  // First 8 bytes reserved for header (vertexCount and featureCount)
161
- const headers = parseHeaders(content, arrayBuffer);
157
+ const headers = parseHeaders(tileset, arrayBuffer);
162
158
  byteOffset = headers.byteOffset;
163
159
  vertexCount = headers.vertexCount;
164
160
  featureCount = headers.featureCount;
@@ -168,7 +164,6 @@ async function parseI3SNodeGeometry(arrayBuffer: ArrayBuffer, tile: Tile, option
168
164
  byteOffset,
169
165
  vertexAttributes,
170
166
  vertexCount,
171
- // @ts-expect-error
172
167
  attributesOrder
173
168
  );
174
169
 
@@ -204,7 +199,7 @@ async function parseI3SNodeGeometry(arrayBuffer: ArrayBuffer, tile: Tile, option
204
199
  texCoords: attributes.uv0,
205
200
  uvRegions: normalizeAttribute(attributes.uvRegion) // Normalize from UInt16
206
201
  };
207
- content.indices = attributes.indices || null;
202
+ content.indices = indices || null;
208
203
 
209
204
  if (attributes.id && attributes.id.value) {
210
205
  tile.content.featureIds = attributes.id.value;
@@ -228,7 +223,10 @@ async function parseI3SNodeGeometry(arrayBuffer: ArrayBuffer, tile: Tile, option
228
223
  * @param decompressedGeometry
229
224
  * @param attributes
230
225
  */
231
- function updateAttributesMetadata(attributes: NormalizedAttributes, decompressedGeometry): void {
226
+ function updateAttributesMetadata(
227
+ attributes: I3SMeshAttributes,
228
+ decompressedGeometry: DracoMesh
229
+ ): void {
232
230
  for (const key in decompressedGeometry.loaderData.attributes) {
233
231
  const dracoAttribute = decompressedGeometry.loaderData.attributes[key];
234
232
 
@@ -253,9 +251,9 @@ function updateAttributesMetadata(attributes: NormalizedAttributes, decompressed
253
251
  * @returns - result of attributes concatenation.
254
252
  */
255
253
  function concatAttributes(
256
- normalizedVertexAttributes: NormalizedAttributes,
257
- normalizedFeatureAttributes: NormalizedAttributes
258
- ): NormalizedAttributes {
254
+ normalizedVertexAttributes: I3SMeshAttributes,
255
+ normalizedFeatureAttributes: I3SMeshAttributes
256
+ ): I3SMeshAttributes {
259
257
  return {...normalizedVertexAttributes, ...normalizedFeatureAttributes};
260
258
  }
261
259
 
@@ -264,7 +262,7 @@ function concatAttributes(
264
262
  * @param attribute - geometry attribute
265
263
  * @returns - geometry attribute in right format
266
264
  */
267
- function normalizeAttribute(attribute: NormalizedAttribute): NormalizedAttribute {
265
+ function normalizeAttribute(attribute: I3SMeshAttribute): I3SMeshAttribute {
268
266
  if (!attribute) {
269
267
  return attribute;
270
268
  }
@@ -272,49 +270,26 @@ function normalizeAttribute(attribute: NormalizedAttribute): NormalizedAttribute
272
270
  return attribute;
273
271
  }
274
272
 
275
- function constructFeatureDataStruct(tileset: Tileset) {
276
- // seed featureData from defaultGeometrySchema
277
- const defaultGeometrySchema = tileset.store.defaultGeometrySchema;
278
- const featureData = defaultGeometrySchema;
279
- // populate the vertex attributes value types and values per element
280
- for (const geometryAttribute in I3S_NAMED_GEOMETRY_ATTRIBUTES) {
281
- for (const namedAttribute in I3S_NAMED_VERTEX_ATTRIBUTES) {
282
- const attribute = defaultGeometrySchema[geometryAttribute][namedAttribute];
283
- if (attribute) {
284
- const {byteOffset = 0, count = 0, valueType, valuesPerElement} = attribute;
285
-
286
- featureData[geometryAttribute][namedAttribute] = {
287
- valueType,
288
- valuesPerElement,
289
- byteOffset,
290
- count
291
- };
292
- }
293
- }
294
- }
295
-
296
- featureData.attributesOrder = defaultGeometrySchema.ordering;
297
- return featureData;
298
- }
299
-
300
- function parseHeaders(content: TileContent, arrayBuffer: ArrayBuffer) {
273
+ function parseHeaders(tileset: I3STilesetHeader, arrayBuffer: ArrayBuffer) {
301
274
  let byteOffset = 0;
302
275
  // First 8 bytes reserved for header (vertexCount and featurecount)
303
276
  let vertexCount = 0;
304
277
  let featureCount = 0;
305
- content.featureData.header.forEach(({property, type}) => {
278
+ for (const {property, type} of tileset.store.defaultGeometrySchema.header) {
306
279
  const TypedArrayTypeHeader = getConstructorForDataFormat(type);
307
- if (property === I3S_NAMED_HEADER_ATTRIBUTES.vertexCount) {
308
- // @ts-expect-error
309
- vertexCount = new TypedArrayTypeHeader(arrayBuffer, 0, 4)[0];
310
- byteOffset += sizeOf(type);
311
- }
312
- if (property === I3S_NAMED_HEADER_ATTRIBUTES.featureCount) {
313
- // @ts-expect-error
314
- featureCount = new TypedArrayTypeHeader(arrayBuffer, 4, 4)[0];
315
- byteOffset += sizeOf(type);
280
+ switch (property) {
281
+ case HeaderAttributeProperty.vertexCount:
282
+ vertexCount = new TypedArrayTypeHeader(arrayBuffer, 0, 4)[0];
283
+ byteOffset += sizeOf(type);
284
+ break;
285
+ case HeaderAttributeProperty.featureCount:
286
+ featureCount = new TypedArrayTypeHeader(arrayBuffer, 4, 4)[0];
287
+ byteOffset += sizeOf(type);
288
+ break;
289
+ default:
290
+ break;
316
291
  }
317
- });
292
+ }
318
293
 
319
294
  return {
320
295
  vertexCount,
@@ -332,7 +307,7 @@ function normalizeAttributes(
332
307
  vertexCount: number,
333
308
  attributesOrder: string[]
334
309
  ) {
335
- const attributes: NormalizedAttributes = {};
310
+ const attributes: I3SMeshAttributes = {};
336
311
 
337
312
  // the order of attributes depend on the order being added to the vertexAttributes object
338
313
  for (const attribute of attributesOrder) {
@@ -351,13 +326,12 @@ function normalizeAttributes(
351
326
  break;
352
327
  }
353
328
  const buffer = arrayBuffer.slice(byteOffset);
354
- let value: number[] | TypedArray = [];
329
+ let value: TypedArray;
355
330
 
356
331
  if (valueType === 'UInt64') {
357
332
  value = parseUint64Values(buffer, count * valuesPerElement, sizeOf(valueType));
358
333
  } else {
359
334
  const TypedArrayType = getConstructorForDataFormat(valueType);
360
- // @ts-expect-error
361
335
  value = new TypedArrayType(buffer, 0, count * valuesPerElement);
362
336
  }
363
337
 
@@ -395,7 +369,7 @@ function parseUint64Values(
395
369
  buffer: ArrayBuffer,
396
370
  elementsCount: number,
397
371
  attributeSize: number
398
- ): number[] {
372
+ ): Uint32Array {
399
373
  const values: number[] = [];
400
374
  const dataView = new DataView(buffer);
401
375
  let offset = 0;
@@ -411,10 +385,10 @@ function parseUint64Values(
411
385
  offset += attributeSize;
412
386
  }
413
387
 
414
- return values;
388
+ return new Uint32Array(values);
415
389
  }
416
390
 
417
- function parsePositions(attribute: NormalizedAttribute, tile: Tile): Matrix4 {
391
+ function parsePositions(attribute: I3SMeshAttribute, tile: I3STileHeader): Matrix4 {
418
392
  const mbs = tile.mbs;
419
393
  const value = attribute.value;
420
394
  const metadata = attribute.metadata;
@@ -466,7 +440,7 @@ function offsetsToCartesians(
466
440
  * @param positions positions attribute
467
441
  * @returns Matrix4 - model matrix for geometry transformation
468
442
  */
469
- function getModelMatrix(positions: NormalizedAttribute): Matrix4 {
443
+ function getModelMatrix(positions: I3SMeshAttribute): Matrix4 {
470
444
  const metadata = positions.metadata;
471
445
  const scaleX: number = metadata?.['i3s-scale_x']?.double || 1;
472
446
  const scaleY: number = metadata?.['i3s-scale_y']?.double || 1;
@@ -483,7 +457,7 @@ function getModelMatrix(positions: NormalizedAttribute): Matrix4 {
483
457
  * @param texture - texture image
484
458
  * @returns {object}
485
459
  */
486
- function makePbrMaterial(materialDefinition: GLTFMaterial, texture: TileContentTexture) {
460
+ function makePbrMaterial(materialDefinition?: I3SMaterialDefinition, texture?: TileContentTexture) {
487
461
  let pbrMaterial;
488
462
  if (materialDefinition) {
489
463
  pbrMaterial = {
@@ -521,7 +495,9 @@ function makePbrMaterial(materialDefinition: GLTFMaterial, texture: TileContentT
521
495
  );
522
496
  }
523
497
 
524
- setMaterialTexture(pbrMaterial, texture);
498
+ if (texture) {
499
+ setMaterialTexture(pbrMaterial, texture);
500
+ }
525
501
 
526
502
  return pbrMaterial;
527
503
  }
@@ -576,7 +552,7 @@ function setMaterialTexture(material, image: TileContentTexture): void {
576
552
  * @param normalizedFeatureAttributes
577
553
  * @returns
578
554
  */
579
- function flattenFeatureIdsByFaceRanges(normalizedFeatureAttributes: NormalizedAttributes): void {
555
+ function flattenFeatureIdsByFaceRanges(normalizedFeatureAttributes: I3SMeshAttributes): void {
580
556
  const {id, faceRange} = normalizedFeatureAttributes;
581
557
 
582
558
  if (!id || !faceRange) {
@@ -614,7 +590,7 @@ function flattenFeatureIdsByFaceRanges(normalizedFeatureAttributes: NormalizedAt
614
590
  * @returns
615
591
  */
616
592
  function flattenFeatureIdsByFeatureIndices(
617
- attributes: NormalizedAttributes,
593
+ attributes: I3SMeshAttributes,
618
594
  featureIds: Int32Array
619
595
  ): void {
620
596
  const featureIndices = attributes.id.value;
@@ -633,12 +609,7 @@ function flattenFeatureIdsByFeatureIndices(
633
609
  * @returns
634
610
  */
635
611
  function getFeatureIdsFromFeatureIndexMetadata(
636
- featureIndex: NormalizedAttribute
612
+ featureIndex: I3SMeshAttribute
637
613
  ): Int32Array | undefined {
638
- return (
639
- featureIndex &&
640
- featureIndex.metadata &&
641
- featureIndex.metadata['i3s-feature-ids'] &&
642
- featureIndex.metadata['i3s-feature-ids'].intArray
643
- );
614
+ return featureIndex?.metadata?.['i3s-feature-ids']?.intArray;
644
615
  }