@loaders.gl/tile-converter 4.1.0 → 4.2.0-alpha.1

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 (27) hide show
  1. package/dist/converter.min.cjs +82 -82
  2. package/dist/deps-installer/deps-installer.js +1 -1
  3. package/dist/deps-installer/deps-installer.js.map +1 -1
  4. package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts +10 -0
  5. package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts.map +1 -1
  6. package/dist/i3s-converter/helpers/attribute-metadata-info.js +5 -0
  7. package/dist/i3s-converter/helpers/attribute-metadata-info.js.map +1 -1
  8. package/dist/i3s-converter/helpers/node-index-document.d.ts +2 -1
  9. package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -1
  10. package/dist/i3s-converter/helpers/node-index-document.js +6 -8
  11. package/dist/i3s-converter/helpers/node-index-document.js.map +1 -1
  12. package/dist/i3s-converter/i3s-converter.d.ts +18 -0
  13. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  14. package/dist/i3s-converter/i3s-converter.js +121 -24
  15. package/dist/i3s-converter/i3s-converter.js.map +1 -1
  16. package/dist/index.cjs +283 -56
  17. package/dist/lib/utils/conversion-dump.d.ts +55 -5
  18. package/dist/lib/utils/conversion-dump.d.ts.map +1 -1
  19. package/dist/lib/utils/conversion-dump.js +77 -17
  20. package/dist/lib/utils/conversion-dump.js.map +1 -1
  21. package/dist/pgm-loader.js +1 -1
  22. package/dist/pgm-loader.js.map +1 -1
  23. package/package.json +14 -14
  24. package/src/i3s-converter/helpers/attribute-metadata-info.ts +16 -0
  25. package/src/i3s-converter/helpers/node-index-document.ts +18 -8
  26. package/src/i3s-converter/i3s-converter.ts +198 -41
  27. package/src/lib/utils/conversion-dump.ts +143 -21
@@ -17,7 +17,8 @@ import type {
17
17
  BoundingVolumes,
18
18
  MaxScreenThresholdSQ,
19
19
  NodeInPage,
20
- Attribute
20
+ Attribute,
21
+ Node3DIndexDocument
21
22
  } from '@loaders.gl/i3s';
22
23
  import {load, encode, isBrowser} from '@loaders.gl/core';
23
24
  import {CesiumIonLoader, Tiles3DLoader} from '@loaders.gl/3d-tiles';
@@ -78,7 +79,7 @@ import {TraversalConversionProps, traverseDatasetWith} from './helpers/tileset-t
78
79
  import {analyzeTileContent, mergePreprocessData} from './helpers/preprocess-3d-tiles';
79
80
  import {Progress} from './helpers/progress';
80
81
  import {composeHashFile, createZip} from '@loaders.gl/zip';
81
- import {ConversionDump, ConversionDumpOptions} from '../lib/utils/conversion-dump';
82
+ import {ConversionDump, ConversionDumpOptions, DumpMetadata} from '../lib/utils/conversion-dump';
82
83
 
83
84
  const ION_DEFAULT_TOKEN = process.env?.IonToken;
84
85
  const HARDCODED_NODES_PER_PAGE = 64;
@@ -259,9 +260,6 @@ export default class I3SConverter {
259
260
  this.nodePages.useWriteFunction(writeFileForSlpk);
260
261
  }
261
262
 
262
- //create a dump file with convertion options
263
- await this.conversionDump.createDumpFile(options as ConversionDumpOptions);
264
-
265
263
  try {
266
264
  const preloadOptions = await this._fetchPreloadOptions();
267
265
  let tilesetUrl = inputUrl;
@@ -415,18 +413,49 @@ export default class I3SConverter {
415
413
  */
416
414
  private async _createAndSaveTileset(outputPath: string, tilesetName: string): Promise<void> {
417
415
  const tilesetPath = join(`${outputPath}`, `${tilesetName}`);
416
+
417
+ await this.conversionDump.createDump(this.options as ConversionDumpOptions);
418
+ if (this.conversionDump.restored && this.options.inquirer) {
419
+ const result = await this.options.inquirer.prompt([
420
+ {
421
+ name: 'resumeConversion',
422
+ type: 'confirm',
423
+ message:
424
+ 'Dump file of the previous conversion exists, do you want to resume that conversion?'
425
+ }
426
+ ]);
427
+ if (!result.resumeConversion) {
428
+ this.conversionDump.reset();
429
+ }
430
+ }
431
+
432
+ this.layers0Path = join(tilesetPath, 'SceneServer', 'layers', '0');
433
+
418
434
  // Removing the tilesetPath needed to exclude erroneous files after conversion
435
+ const removePath = this.conversionDump.restored
436
+ ? join(this.layers0Path, 'nodepages')
437
+ : tilesetPath;
419
438
  try {
420
- await removeDir(tilesetPath);
439
+ await removeDir(removePath);
421
440
  } catch (e) {
422
441
  // do nothing
423
442
  }
424
443
 
425
- this.layers0Path = join(tilesetPath, 'SceneServer', 'layers', '0');
444
+ if (this.conversionDump.restored && this.conversionDump.attributeMetadataInfo) {
445
+ this.attributeMetadataInfo.fromObject(this.conversionDump.attributeMetadataInfo);
446
+ }
426
447
 
427
448
  this.materialDefinitions = [];
428
449
  this.materialMap = new Map();
429
450
 
451
+ if (this.conversionDump.restored && this.conversionDump.materialDefinitions) {
452
+ for (let i = 0; i < this.conversionDump.materialDefinitions.length; i++) {
453
+ const hash = md5(JSON.stringify(this.conversionDump.materialDefinitions[i]));
454
+ this.materialMap.set(hash, i);
455
+ }
456
+ this.materialDefinitions = this.conversionDump.materialDefinitions;
457
+ }
458
+
430
459
  const sourceRootTile: Tiles3DTileJSONPostprocessed = this.sourceTileset!.root!;
431
460
  const sourceBoundingVolume = createBoundingVolume(
432
461
  sourceRootTile.boundingVolume,
@@ -471,6 +500,10 @@ export default class I3SConverter {
471
500
  this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
472
501
  }
473
502
 
503
+ if (this.conversionDump.restored && this.conversionDump.textureSetDefinitions) {
504
+ this.layers0!.textureSetDefinitions = this.conversionDump.textureSetDefinitions;
505
+ }
506
+
474
507
  this.layers0!.materialDefinitions = this.materialDefinitions;
475
508
  // @ts-ignore
476
509
  this.layers0.geometryDefinitions = transform(
@@ -607,7 +640,13 @@ export default class I3SConverter {
607
640
  transformationMatrix = transformationMatrix.multiplyRight(sourceTile.transform);
608
641
  }
609
642
  const parentNode = parentNodes[0];
610
- const childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);
643
+ const restoreResult = await this._restoreNode(parentNode, sourceTile, transformationMatrix);
644
+ let childNodes;
645
+ if (restoreResult === null) {
646
+ childNodes = await this._createNode(parentNode, sourceTile, transformationMatrix);
647
+ } else {
648
+ childNodes = restoreResult;
649
+ }
611
650
  await parentNode.addChildren(childNodes);
612
651
 
613
652
  const newTraversalProps: TraversalConversionProps = {
@@ -651,6 +690,114 @@ export default class I3SConverter {
651
690
  }
652
691
  }
653
692
 
693
+ /**
694
+ * Generate NodeIndexDocument
695
+ * @param boundingVolumes - Bounding volumes
696
+ * @param resources - converted or dumped node resources data
697
+ * @param parentNode - 3DNodeIndexDocument of parent node
698
+ * @param sourceTile - source 3DTile data
699
+ * @param isDumped - indicator if the node is dumped
700
+ * @return NodeIndexDocument, nodeInPage and node data
701
+ */
702
+ private async _generateNodeIndexDocument(
703
+ boundingVolumes: BoundingVolumes,
704
+ resources: I3SConvertedResources | DumpMetadata,
705
+ parentNode: NodeIndexDocument,
706
+ sourceTile: Tiles3DTileJSONPostprocessed,
707
+ isDumped: boolean
708
+ ): Promise<{node: NodeIndexDocument; nodeInPage: NodeInPage; nodeData: Node3DIndexDocument}> {
709
+ this.layersHasTexture =
710
+ this.layersHasTexture ||
711
+ Boolean(
712
+ ('texture' in resources && resources.texture) ||
713
+ ('texelCountHint' in resources && resources.texelCountHint)
714
+ );
715
+
716
+ if (this.generateBoundingVolumes && resources.boundingVolumes) {
717
+ boundingVolumes = resources.boundingVolumes;
718
+ }
719
+
720
+ const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
721
+ const maxScreenThresholdSQ = lodSelection.find(
722
+ (val) => val.metricType === 'maxScreenThresholdSQ'
723
+ ) || {maxError: 0};
724
+
725
+ if (isDumped) {
726
+ const draftObb = {
727
+ center: [],
728
+ halfSize: [],
729
+ quaternion: []
730
+ };
731
+ await this.nodePages.push({index: 0, obb: draftObb}, parentNode.inPageId);
732
+ }
733
+
734
+ const nodeInPage = await this._updateNodeInNodePages(
735
+ maxScreenThresholdSQ,
736
+ boundingVolumes,
737
+ sourceTile,
738
+ parentNode.inPageId,
739
+ resources
740
+ );
741
+
742
+ const nodeData = await NodeIndexDocument.createNodeIndexDocument(
743
+ parentNode,
744
+ boundingVolumes,
745
+ lodSelection,
746
+ nodeInPage,
747
+ resources
748
+ );
749
+
750
+ const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
751
+ return {node, nodeInPage, nodeData};
752
+ }
753
+
754
+ /**
755
+ * Restore 3DNodeIndexDocument from a comversion dump file
756
+ * @param parentNode - 3DNodeIndexDocument of parent node
757
+ * @param sourceTile - source 3DTile data
758
+ * @param transformationMatrix - transformation matrix of the current tile, calculated recursively multiplying
759
+ * transform of all parent tiles and transform of the current tile
760
+ */
761
+ private async _restoreNode(
762
+ parentNode: NodeIndexDocument,
763
+ sourceTile: Tiles3DTileJSONPostprocessed,
764
+ transformationMatrix: Matrix4
765
+ ): Promise<null | NodeIndexDocument[]> {
766
+ this._checkAddRefinementTypeForTile(sourceTile);
767
+ await this._updateTilesetOptions();
768
+ if (
769
+ this.conversionDump.restored &&
770
+ sourceTile.id &&
771
+ this.conversionDump.isFileConversionComplete(sourceTile.id)
772
+ ) {
773
+ const sourceBoundingVolume = createBoundingVolume(
774
+ sourceTile.boundingVolume,
775
+ transformationMatrix,
776
+ null
777
+ );
778
+ let boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel!);
779
+ const nodes: NodeIndexDocument[] = [];
780
+ for (const convertedNode of this.conversionDump.tilesConverted[sourceTile.id].nodes) {
781
+ const {node} = await this._generateNodeIndexDocument(
782
+ boundingVolumes,
783
+ {
784
+ ...(convertedNode.dumpMetadata as DumpMetadata),
785
+ nodeId: convertedNode.nodeId
786
+ } as I3SConvertedResources | DumpMetadata,
787
+ parentNode,
788
+ sourceTile,
789
+ true
790
+ );
791
+ nodes.push(node);
792
+ }
793
+ return nodes;
794
+ } else if (this.conversionDump.restored && sourceTile.id) {
795
+ //clear existing record in a dump
796
+ this.conversionDump.clearDumpRecord(sourceTile.id);
797
+ }
798
+ return null;
799
+ }
800
+
654
801
  /**
655
802
  * Convert tile to one or more I3S nodes
656
803
  * @param parentNode - 3DNodeIndexDocument of parent node
@@ -684,6 +831,12 @@ export default class I3SConverter {
684
831
  const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
685
832
  this.createAttributeStorageInfo(tileContent, propertyTable);
686
833
 
834
+ this.conversionDump.attributeMetadataInfo = {
835
+ attributeStorageInfo: this.attributeMetadataInfo.attributeStorageInfo,
836
+ fields: this.attributeMetadataInfo.fields,
837
+ popupInfo: this.attributeMetadataInfo.popupInfo
838
+ };
839
+
687
840
  const resourcesData = await this._convertResources(
688
841
  sourceTile,
689
842
  transformationMatrix,
@@ -710,39 +863,30 @@ export default class I3SConverter {
710
863
  };
711
864
 
712
865
  for (const resources of resourcesData || [emptyResources]) {
713
- this.layersHasTexture = this.layersHasTexture || Boolean(resources.texture);
714
-
715
- if (this.generateBoundingVolumes && resources.boundingVolumes) {
716
- boundingVolumes = resources.boundingVolumes;
717
- }
718
-
719
- const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
720
- const maxScreenThresholdSQ = lodSelection.find(
721
- (val) => val.metricType === 'maxScreenThresholdSQ'
722
- ) || {maxError: 0};
723
-
724
- const nodeInPage = await this._updateNodeInNodePages(
725
- maxScreenThresholdSQ,
866
+ const {node, nodeInPage, nodeData} = await this._generateNodeIndexDocument(
726
867
  boundingVolumes,
727
- sourceTile,
728
- parentNode.inPageId,
729
- resources
730
- );
731
-
732
- const nodeData = await NodeIndexDocument.createNodeIndexDocument(
868
+ resources,
733
869
  parentNode,
734
- boundingVolumes,
735
- lodSelection,
736
- nodeInPage,
737
- resources
870
+ sourceTile,
871
+ false
738
872
  );
739
- const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
740
873
  nodes.push(node);
741
874
 
742
875
  if (nodeInPage.mesh) {
743
876
  //update a record in a dump file
744
877
  if (sourceTile.id) {
745
- await this.conversionDump.addNode(sourceTile.id, nodeInPage.index);
878
+ const dumpMetadata = {
879
+ boundingVolumes: resources.boundingVolumes,
880
+ attributesCount: resources.attributes?.length,
881
+ featureCount: resources.featureCount,
882
+ geometry: Boolean(resources.geometry),
883
+ hasUvRegions: resources.hasUvRegions,
884
+ materialId: nodeInPage.mesh.material.definition,
885
+ texelCountHint: nodeInPage.mesh.material.texelCountHint,
886
+ vertexCount: resources.vertexCount
887
+ };
888
+ this.conversionDump.setMaterialsDefinitions(this.materialDefinitions);
889
+ await this.conversionDump.addNode(sourceTile.id, nodeInPage.index, dumpMetadata);
746
890
  }
747
891
 
748
892
  //write resources
@@ -829,9 +973,9 @@ export default class I3SConverter {
829
973
  boundingVolumes: BoundingVolumes,
830
974
  sourceTile: Tiles3DTileJSONPostprocessed,
831
975
  parentId: number,
832
- resources: I3SConvertedResources
976
+ resources: I3SConvertedResources | DumpMetadata
833
977
  ): Promise<NodeInPage> {
834
- const {meshMaterial, texture, vertexCount, featureCount, geometry, hasUvRegions} = resources;
978
+ const {vertexCount, featureCount, geometry, hasUvRegions} = resources;
835
979
  const nodeInPage: NodeInPage = {
836
980
  index: 0,
837
981
  lodThreshold: maxScreenThresholdSQ.maxError,
@@ -841,7 +985,13 @@ export default class I3SConverter {
841
985
  if (geometry && this.isContentSupported(sourceTile)) {
842
986
  nodeInPage.mesh = {
843
987
  geometry: {
844
- definition: this.findOrCreateGeometryDefinition(Boolean(texture), hasUvRegions),
988
+ definition: this.findOrCreateGeometryDefinition(
989
+ Boolean(
990
+ ('texture' in resources && resources.texture) ||
991
+ ('texelCountHint' in resources && resources.texelCountHint)
992
+ ),
993
+ hasUvRegions
994
+ ),
845
995
  resource: 0
846
996
  },
847
997
  attribute: {
@@ -853,7 +1003,7 @@ export default class I3SConverter {
853
1003
  };
854
1004
  }
855
1005
 
856
- let nodeId = resources.nodeId;
1006
+ let nodeId = 'nodeId' in resources ? resources.nodeId : undefined;
857
1007
  let node: NodeInPage;
858
1008
  if (!nodeId) {
859
1009
  node = await this.nodePages.push(nodeInPage, parentId);
@@ -866,12 +1016,16 @@ export default class I3SConverter {
866
1016
  }
867
1017
 
868
1018
  NodePages.updateAll(node, nodeInPage);
869
- if (meshMaterial) {
870
- NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(meshMaterial));
1019
+ if ('meshMaterial' in resources && resources.meshMaterial) {
1020
+ NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(resources.meshMaterial));
1021
+ } else if ('materialId' in resources && resources.materialId !== null) {
1022
+ NodePages.updateMaterialByNodeId(node, resources.materialId);
871
1023
  }
872
- if (texture) {
873
- const texelCountHint = texture.image.height * texture.image.width;
1024
+ if ('texture' in resources && resources.texture) {
1025
+ const texelCountHint = resources.texture.image.height * resources.texture.image.width;
874
1026
  NodePages.updateTexelCountHintByNodeId(node, texelCountHint);
1027
+ } else if ('texelCountHint' in resources && resources.texelCountHint) {
1028
+ NodePages.updateTexelCountHintByNodeId(node, resources.texelCountHint);
875
1029
  }
876
1030
  if (vertexCount) {
877
1031
  this.vertexCounter += vertexCount;
@@ -1178,6 +1332,9 @@ export default class I3SConverter {
1178
1332
  if (!this.layers0!.textureSetDefinitions!.length) {
1179
1333
  this.layers0!.textureSetDefinitions!.push({formats});
1180
1334
  this.layers0!.textureSetDefinitions!.push({formats, atlas: true});
1335
+ if (this.layers0!.textureSetDefinitions) {
1336
+ this.conversionDump.addTexturesDefinitions(this.layers0!.textureSetDefinitions);
1337
+ }
1181
1338
  }
1182
1339
  }
1183
1340
  }
@@ -1,6 +1,9 @@
1
+ import {isDeepStrictEqual} from 'util';
1
2
  import {DUMP_FILE_SUFFIX} from '../../constants';
2
- import {removeFile, writeFile} from './file-utils';
3
+ import {isFileExists, openJson, removeFile, writeFile} from './file-utils';
3
4
  import {join} from 'path';
5
+ import {BoundingVolumes, I3SMaterialDefinition, TextureSetDefinitionFormats} from '@loaders.gl/i3s';
6
+ import {AttributeMetadataInfoObject} from '../../i3s-converter/helpers/attribute-metadata-info';
4
7
 
5
8
  export type ConversionDumpOptions = {
6
9
  inputUrl: string;
@@ -21,28 +24,53 @@ export type ConversionDumpOptions = {
21
24
  type NodeDoneStatus = {
22
25
  nodeId: number;
23
26
  done: boolean;
24
- progress: Record<string, boolean>;
27
+ progress?: Record<string, boolean>;
28
+ dumpMetadata?: DumpMetadata;
25
29
  };
26
30
 
27
31
  type TilesConverted = {
28
32
  nodes: NodeDoneStatus[];
29
33
  };
30
34
 
35
+ export type DumpMetadata = {
36
+ boundingVolumes: BoundingVolumes | null;
37
+ attributesCount?: number;
38
+ featureCount: number | null;
39
+ geometry: boolean;
40
+ hasUvRegions: boolean;
41
+ materialId: number | null;
42
+ texelCountHint?: number;
43
+ vertexCount: number | null;
44
+ };
45
+
46
+ export type TextureSetDefinition = {
47
+ formats: TextureSetDefinitionFormats;
48
+ atlas?: boolean;
49
+ };
50
+
31
51
  export class ConversionDump {
52
+ /**Restored/resumed dump indicator */
53
+ restored: boolean = false;
32
54
  /** Conversion options */
33
55
  private options?: ConversionDumpOptions;
34
56
  /** Tiles conversion progress status map */
35
57
  tilesConverted: Record<string, TilesConverted>;
58
+ /** Textures formats definitions */
59
+ textureSetDefinitions?: TextureSetDefinition[];
60
+ /** Attributes Metadata */
61
+ attributeMetadataInfo?: AttributeMetadataInfoObject;
62
+ /** Array of materials definitions */
63
+ materialDefinitions: I3SMaterialDefinition[] = [];
36
64
 
37
65
  constructor() {
38
66
  this.tilesConverted = {};
39
67
  }
40
68
 
41
69
  /**
42
- * Create a dump file with convertion options
43
- * @param options - converter options
70
+ * Create a dump with convertion options
71
+ * @param currentOptions - converter options
44
72
  */
45
- async createDumpFile(options: ConversionDumpOptions): Promise<void> {
73
+ async createDump(currentOptions: ConversionDumpOptions): Promise<void> {
46
74
  const {
47
75
  tilesetName,
48
76
  slpk,
@@ -57,7 +85,7 @@ export class ConversionDump {
57
85
  mergeMaterials = true,
58
86
  metadataClass,
59
87
  analyze = false
60
- } = options;
88
+ } = currentOptions;
61
89
  this.options = {
62
90
  tilesetName,
63
91
  slpk,
@@ -74,14 +102,48 @@ export class ConversionDump {
74
102
  analyze
75
103
  };
76
104
 
77
- try {
78
- await writeFile(
79
- options.outputPath,
80
- JSON.stringify({options: this.options}),
81
- `${options.tilesetName}${DUMP_FILE_SUFFIX}`
105
+ const dumpFilename = join(
106
+ this.options.outputPath,
107
+ this.options.tilesetName,
108
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
109
+ );
110
+ if (await isFileExists(dumpFilename)) {
111
+ const {
112
+ options,
113
+ tilesConverted,
114
+ textureSetDefinitions,
115
+ attributeMetadataInfo,
116
+ materialDefinitions
117
+ } = await openJson(
118
+ join(this.options.outputPath, this.options.tilesetName),
119
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
82
120
  );
83
- } catch (error) {
84
- console.log("Can't create dump file", error);
121
+ if (isDeepStrictEqual(options, JSON.parse(JSON.stringify(this.options)))) {
122
+ this.tilesConverted = tilesConverted;
123
+ this.textureSetDefinitions = textureSetDefinitions;
124
+ this.attributeMetadataInfo = attributeMetadataInfo;
125
+ this.materialDefinitions = materialDefinitions;
126
+ this.restored = true;
127
+ return;
128
+ }
129
+ }
130
+ await this.deleteDumpFile();
131
+ }
132
+
133
+ /**
134
+ * Reset a dump
135
+ */
136
+ reset(): void {
137
+ this.restored = false;
138
+ this.tilesConverted = {};
139
+ if (this.textureSetDefinitions) {
140
+ delete this.textureSetDefinitions;
141
+ }
142
+ if (this.attributeMetadataInfo) {
143
+ delete this.attributeMetadataInfo;
144
+ }
145
+ if (this.materialDefinitions.length > 0) {
146
+ this.materialDefinitions = [];
85
147
  }
86
148
  }
87
149
 
@@ -92,10 +154,13 @@ export class ConversionDump {
92
154
  if (this.options?.outputPath && this.options.tilesetName) {
93
155
  try {
94
156
  await writeFile(
95
- this.options.outputPath,
157
+ join(this.options.outputPath, this.options.tilesetName),
96
158
  JSON.stringify({
97
159
  options: this.options,
98
- tilesConverted: this.tilesConverted
160
+ tilesConverted: this.tilesConverted,
161
+ textureSetDefinitions: this.textureSetDefinitions,
162
+ attributeMetadataInfo: this.attributeMetadataInfo,
163
+ materialDefinitions: this.materialDefinitions
99
164
  }),
100
165
  `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
101
166
  );
@@ -109,9 +174,23 @@ export class ConversionDump {
109
174
  * Delete a dump file
110
175
  */
111
176
  async deleteDumpFile(): Promise<void> {
112
- if (this.options?.outputPath && this.options.tilesetName) {
177
+ if (
178
+ this.options?.outputPath &&
179
+ this.options.tilesetName &&
180
+ (await isFileExists(
181
+ join(
182
+ this.options.outputPath,
183
+ this.options.tilesetName,
184
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
185
+ )
186
+ ))
187
+ ) {
113
188
  await removeFile(
114
- join(this.options.outputPath, `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`)
189
+ join(
190
+ this.options.outputPath,
191
+ this.options.tilesetName,
192
+ `${this.options.tilesetName}${DUMP_FILE_SUFFIX}`
193
+ )
115
194
  );
116
195
  }
117
196
  }
@@ -139,15 +218,31 @@ export class ConversionDump {
139
218
  * @param fileName - source filename
140
219
  * @param nodeId - nodeId of the node
141
220
  */
142
- async addNode(filename: string, nodeId: number) {
221
+ async addNode(filename: string, nodeId: number, dumpMetadata: DumpMetadata) {
143
222
  const {nodes} = this.getRecord(filename) || {nodes: []};
144
- nodes.push({nodeId, done: false, progress: {}});
223
+ nodes.push({nodeId, done: false, progress: {}, dumpMetadata});
145
224
  if (nodes.length === 1) {
146
225
  this.setRecord(filename, {nodes});
147
226
  }
148
227
  await this.updateDumpFile();
149
228
  }
150
229
 
230
+ /**
231
+ * Clear dump record got the source filename
232
+ * @param fileName - source filename
233
+ */
234
+ clearDumpRecord(filename: string) {
235
+ this.setRecord(filename, {nodes: []});
236
+ }
237
+
238
+ /**
239
+ * Add textures definitions into the dump file
240
+ * @param textureDefinitions - textures definitions array
241
+ */
242
+ addTexturesDefinitions(textureDefinitions: TextureSetDefinition[]) {
243
+ this.textureSetDefinitions = textureDefinitions;
244
+ }
245
+
151
246
  /**
152
247
  * Update done status object for the writing resources
153
248
  * @param fileName - key - source filename
@@ -160,6 +255,9 @@ export class ConversionDump {
160
255
  (element) => element.nodeId === nodeId
161
256
  );
162
257
  if (nodeDump) {
258
+ if (!nodeDump.progress) {
259
+ nodeDump.progress = {};
260
+ }
163
261
  nodeDump.progress[resourceType] = value;
164
262
  if (!value) {
165
263
  nodeDump.done = false;
@@ -181,7 +279,7 @@ export class ConversionDump {
181
279
  const {sourceId, resourceType, outputId} = changedRecords[i];
182
280
  if (!sourceId || !resourceType || !outputId) continue;
183
281
  for (const node of this.tilesConverted[sourceId].nodes) {
184
- if (node.nodeId === outputId) {
282
+ if (node.nodeId === outputId && node.progress) {
185
283
  node.progress[resourceType] = true;
186
284
 
187
285
  let done = false;
@@ -191,7 +289,7 @@ export class ConversionDump {
191
289
  }
192
290
  node.done = done;
193
291
  if (node.done) {
194
- node.progress = {};
292
+ delete node.progress;
195
293
  }
196
294
  break;
197
295
  }
@@ -200,4 +298,28 @@ export class ConversionDump {
200
298
  }
201
299
  await this.updateDumpFile();
202
300
  }
301
+
302
+ /**
303
+ * Check is source file conversion complete
304
+ * @param filename - source filename
305
+ * @returns true if source file conversion complete
306
+ */
307
+ isFileConversionComplete(filename: string): boolean {
308
+ let result = true;
309
+ for (const node of this.tilesConverted[filename]?.nodes || []) {
310
+ if (!node.done) {
311
+ result = false;
312
+ break;
313
+ }
314
+ }
315
+ return result && this.tilesConverted[filename]?.nodes?.length > 0;
316
+ }
317
+
318
+ /**
319
+ * Set materialDefinitions into a dump
320
+ * @param materialDefinitions - Array materialDefinitions
321
+ */
322
+ setMaterialsDefinitions(materialDefinitions: I3SMaterialDefinition[]): void {
323
+ this.materialDefinitions = materialDefinitions;
324
+ }
203
325
  }