@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.
- package/dist/converter.min.cjs +82 -82
- package/dist/deps-installer/deps-installer.js +1 -1
- package/dist/deps-installer/deps-installer.js.map +1 -1
- package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts +10 -0
- package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/attribute-metadata-info.js +5 -0
- package/dist/i3s-converter/helpers/attribute-metadata-info.js.map +1 -1
- package/dist/i3s-converter/helpers/node-index-document.d.ts +2 -1
- package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/node-index-document.js +6 -8
- package/dist/i3s-converter/helpers/node-index-document.js.map +1 -1
- package/dist/i3s-converter/i3s-converter.d.ts +18 -0
- package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
- package/dist/i3s-converter/i3s-converter.js +121 -24
- package/dist/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/index.cjs +283 -56
- package/dist/lib/utils/conversion-dump.d.ts +55 -5
- package/dist/lib/utils/conversion-dump.d.ts.map +1 -1
- package/dist/lib/utils/conversion-dump.js +77 -17
- package/dist/lib/utils/conversion-dump.js.map +1 -1
- package/dist/pgm-loader.js +1 -1
- package/dist/pgm-loader.js.map +1 -1
- package/package.json +14 -14
- package/src/i3s-converter/helpers/attribute-metadata-info.ts +16 -0
- package/src/i3s-converter/helpers/node-index-document.ts +18 -8
- package/src/i3s-converter/i3s-converter.ts +198 -41
- 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(
|
|
439
|
+
await removeDir(removePath);
|
|
421
440
|
} catch (e) {
|
|
422
441
|
// do nothing
|
|
423
442
|
}
|
|
424
443
|
|
|
425
|
-
this.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
728
|
-
parentNode.inPageId,
|
|
729
|
-
resources
|
|
730
|
-
);
|
|
731
|
-
|
|
732
|
-
const nodeData = await NodeIndexDocument.createNodeIndexDocument(
|
|
868
|
+
resources,
|
|
733
869
|
parentNode,
|
|
734
|
-
|
|
735
|
-
|
|
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
|
-
|
|
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 {
|
|
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(
|
|
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
|
|
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
|
|
43
|
-
* @param
|
|
70
|
+
* Create a dump with convertion options
|
|
71
|
+
* @param currentOptions - converter options
|
|
44
72
|
*/
|
|
45
|
-
async
|
|
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
|
-
} =
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
84
|
-
|
|
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 (
|
|
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(
|
|
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
|
}
|