@itwin/core-frontend 4.1.0-dev.5 → 4.1.0-dev.7
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/lib/cjs/core-frontend.d.ts +3 -0
- package/lib/cjs/core-frontend.d.ts.map +1 -1
- package/lib/cjs/core-frontend.js +3 -0
- package/lib/cjs/core-frontend.js.map +1 -1
- package/lib/cjs/imdl/ImdlGraphicsCreator.d.ts +19 -0
- package/lib/cjs/imdl/ImdlGraphicsCreator.d.ts.map +1 -0
- package/lib/cjs/imdl/ImdlGraphicsCreator.js +328 -0
- package/lib/cjs/imdl/ImdlGraphicsCreator.js.map +1 -0
- package/lib/cjs/imdl/ImdlModel.d.ts +181 -0
- package/lib/cjs/imdl/ImdlModel.d.ts.map +1 -0
- package/lib/cjs/imdl/ImdlModel.js +10 -0
- package/lib/cjs/imdl/ImdlModel.js.map +1 -0
- package/lib/cjs/imdl/ImdlParser.d.ts +40 -0
- package/lib/cjs/imdl/ImdlParser.d.ts.map +1 -0
- package/lib/cjs/imdl/ImdlParser.js +996 -0
- package/lib/cjs/imdl/ImdlParser.js.map +1 -0
- package/lib/cjs/imdl/ImdlSchema.d.ts +380 -0
- package/lib/cjs/imdl/ImdlSchema.d.ts.map +1 -0
- package/lib/cjs/imdl/ImdlSchema.js +10 -0
- package/lib/cjs/imdl/ImdlSchema.js.map +1 -0
- package/lib/cjs/render/primitives/AuxChannelTable.d.ts +4 -0
- package/lib/cjs/render/primitives/AuxChannelTable.d.ts.map +1 -1
- package/lib/cjs/render/primitives/AuxChannelTable.js +33 -0
- package/lib/cjs/render/primitives/AuxChannelTable.js.map +1 -1
- package/lib/cjs/render/primitives/VertexTable.d.ts +3 -3
- package/lib/cjs/render/primitives/VertexTable.d.ts.map +1 -1
- package/lib/cjs/render/primitives/VertexTable.js.map +1 -1
- package/lib/cjs/render/primitives/VertexTableSplitter.d.ts +5 -1
- package/lib/cjs/render/primitives/VertexTableSplitter.d.ts.map +1 -1
- package/lib/cjs/render/primitives/VertexTableSplitter.js +13 -12
- package/lib/cjs/render/primitives/VertexTableSplitter.js.map +1 -1
- package/lib/cjs/tile/IModelTile.d.ts.map +1 -1
- package/lib/cjs/tile/IModelTile.js +14 -15
- package/lib/cjs/tile/IModelTile.js.map +1 -1
- package/lib/cjs/tile/ImdlReader.d.ts +11 -420
- package/lib/cjs/tile/ImdlReader.d.ts.map +1 -1
- package/lib/cjs/tile/ImdlReader.js +64 -902
- package/lib/cjs/tile/ImdlReader.js.map +1 -1
- package/lib/cjs/tile/map/MapTile.d.ts +6 -1
- package/lib/cjs/tile/map/MapTile.d.ts.map +1 -1
- package/lib/cjs/tile/map/MapTile.js +8 -7
- package/lib/cjs/tile/map/MapTile.js.map +1 -1
- package/lib/cjs/tile/map/MapTileTree.d.ts.map +1 -1
- package/lib/cjs/tile/map/MapTileTree.js +8 -2
- package/lib/cjs/tile/map/MapTileTree.js.map +1 -1
- package/lib/esm/core-frontend.d.ts +3 -0
- package/lib/esm/core-frontend.d.ts.map +1 -1
- package/lib/esm/core-frontend.js +3 -0
- package/lib/esm/core-frontend.js.map +1 -1
- package/lib/esm/imdl/ImdlGraphicsCreator.d.ts +19 -0
- package/lib/esm/imdl/ImdlGraphicsCreator.d.ts.map +1 -0
- package/lib/esm/imdl/ImdlGraphicsCreator.js +324 -0
- package/lib/esm/imdl/ImdlGraphicsCreator.js.map +1 -0
- package/lib/esm/imdl/ImdlModel.d.ts +181 -0
- package/lib/esm/imdl/ImdlModel.d.ts.map +1 -0
- package/lib/esm/imdl/ImdlModel.js +9 -0
- package/lib/esm/imdl/ImdlModel.js.map +1 -0
- package/lib/esm/imdl/ImdlParser.d.ts +40 -0
- package/lib/esm/imdl/ImdlParser.d.ts.map +1 -0
- package/lib/esm/imdl/ImdlParser.js +988 -0
- package/lib/esm/imdl/ImdlParser.js.map +1 -0
- package/lib/esm/imdl/ImdlSchema.d.ts +380 -0
- package/lib/esm/imdl/ImdlSchema.d.ts.map +1 -0
- package/lib/esm/imdl/ImdlSchema.js +9 -0
- package/lib/esm/imdl/ImdlSchema.js.map +1 -0
- package/lib/esm/render/primitives/AuxChannelTable.d.ts +4 -0
- package/lib/esm/render/primitives/AuxChannelTable.d.ts.map +1 -1
- package/lib/esm/render/primitives/AuxChannelTable.js +33 -0
- package/lib/esm/render/primitives/AuxChannelTable.js.map +1 -1
- package/lib/esm/render/primitives/VertexTable.d.ts +3 -3
- package/lib/esm/render/primitives/VertexTable.d.ts.map +1 -1
- package/lib/esm/render/primitives/VertexTable.js.map +1 -1
- package/lib/esm/render/primitives/VertexTableSplitter.d.ts +5 -1
- package/lib/esm/render/primitives/VertexTableSplitter.d.ts.map +1 -1
- package/lib/esm/render/primitives/VertexTableSplitter.js +13 -12
- package/lib/esm/render/primitives/VertexTableSplitter.js.map +1 -1
- package/lib/esm/tile/IModelTile.d.ts.map +1 -1
- package/lib/esm/tile/IModelTile.js +14 -15
- package/lib/esm/tile/IModelTile.js.map +1 -1
- package/lib/esm/tile/ImdlReader.d.ts +11 -420
- package/lib/esm/tile/ImdlReader.d.ts.map +1 -1
- package/lib/esm/tile/ImdlReader.js +67 -903
- package/lib/esm/tile/ImdlReader.js.map +1 -1
- package/lib/esm/tile/map/MapTile.d.ts +6 -1
- package/lib/esm/tile/map/MapTile.d.ts.map +1 -1
- package/lib/esm/tile/map/MapTile.js +8 -7
- package/lib/esm/tile/map/MapTile.js.map +1 -1
- package/lib/esm/tile/map/MapTileTree.d.ts.map +1 -1
- package/lib/esm/tile/map/MapTileTree.js +8 -2
- package/lib/esm/tile/map/MapTileTree.js.map +1 -1
- package/package.json +18 -18
|
@@ -0,0 +1,988 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
/** @packageDocumentation
|
|
6
|
+
* @module Tiles
|
|
7
|
+
*/
|
|
8
|
+
import { assert, JsonUtils, utf8ToString } from "@itwin/core-bentley";
|
|
9
|
+
import { Point3d, Range2d, Range3d } from "@itwin/core-geometry";
|
|
10
|
+
import { BatchType, ColorDef, FeatureTableHeader, FillFlags, GltfV2ChunkTypes, GltfVersions, Gradient, ImdlFlags, ImdlHeader, LinePixels, MultiModelPackedFeatureTable, PackedFeatureTable, PolylineTypeFlags, QParams2d, QParams3d, RenderMaterial, RenderTexture, RgbColor, TextureMapping, TileFormat, TileHeader, TileReadStatus, } from "@itwin/core-common";
|
|
11
|
+
import { Mesh } from "../render/primitives/mesh/MeshPrimitives";
|
|
12
|
+
import { isValidSurfaceType } from "../render/primitives/SurfaceParams";
|
|
13
|
+
import { DisplayParams } from "../render/primitives/DisplayParams";
|
|
14
|
+
import { AuxChannelTable } from "../render/primitives/AuxChannelTable";
|
|
15
|
+
import { splitMeshParams, splitPointStringParams, splitPolylineParams } from "../render/primitives/VertexTableSplitter";
|
|
16
|
+
import { AnimationNodeId } from "../render/GraphicBranch";
|
|
17
|
+
import { VertexIndices, VertexTable } from "../render/primitives/VertexTable";
|
|
18
|
+
/** Header preceding "glTF" data in iMdl tile. */
|
|
19
|
+
class GltfHeader extends TileHeader {
|
|
20
|
+
get isValid() { return TileFormat.Gltf === this.format; }
|
|
21
|
+
constructor(stream) {
|
|
22
|
+
super(stream);
|
|
23
|
+
this.scenePosition = 0;
|
|
24
|
+
this.sceneStrLength = 0;
|
|
25
|
+
this.binaryPosition = 0;
|
|
26
|
+
this.gltfLength = stream.readUint32();
|
|
27
|
+
this.sceneStrLength = stream.readUint32();
|
|
28
|
+
const value5 = stream.readUint32();
|
|
29
|
+
// Early versions of the reality data tile publisher incorrectly put version 2 into header - handle these old tiles
|
|
30
|
+
// validating the chunk type.
|
|
31
|
+
if (this.version === GltfVersions.Version2 && value5 === GltfVersions.Gltf1SceneFormat)
|
|
32
|
+
this.version = GltfVersions.Version1;
|
|
33
|
+
if (this.version === GltfVersions.Version1) {
|
|
34
|
+
const gltfSceneFormat = value5;
|
|
35
|
+
if (GltfVersions.Gltf1SceneFormat !== gltfSceneFormat) {
|
|
36
|
+
this.invalidate();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.scenePosition = stream.curPos;
|
|
40
|
+
this.binaryPosition = stream.curPos + this.sceneStrLength;
|
|
41
|
+
}
|
|
42
|
+
else if (this.version === GltfVersions.Version2) {
|
|
43
|
+
const sceneChunkType = value5;
|
|
44
|
+
this.scenePosition = stream.curPos;
|
|
45
|
+
stream.curPos = stream.curPos + this.sceneStrLength;
|
|
46
|
+
const binaryLength = stream.readUint32();
|
|
47
|
+
const binaryChunkType = stream.readUint32();
|
|
48
|
+
if (GltfV2ChunkTypes.JSON !== sceneChunkType || GltfV2ChunkTypes.Binary !== binaryChunkType || 0 === binaryLength) {
|
|
49
|
+
this.invalidate();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.binaryPosition = stream.curPos;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
this.invalidate();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const nodeIdRegex = /Node_(.*)/;
|
|
60
|
+
function extractNodeId(nodeName) {
|
|
61
|
+
const match = nodeName.match(nodeIdRegex);
|
|
62
|
+
assert(!!match && match.length === 2);
|
|
63
|
+
if (!match || match.length !== 2)
|
|
64
|
+
return 0;
|
|
65
|
+
const nodeId = Number.parseInt(match[1], 10);
|
|
66
|
+
assert(!Number.isNaN(nodeId));
|
|
67
|
+
return Number.isNaN(nodeId) ? 0 : nodeId;
|
|
68
|
+
}
|
|
69
|
+
class Texture extends RenderTexture {
|
|
70
|
+
constructor(type) {
|
|
71
|
+
super(type);
|
|
72
|
+
}
|
|
73
|
+
dispose() { }
|
|
74
|
+
get bytesUsed() { return 0; }
|
|
75
|
+
}
|
|
76
|
+
class NamedTexture extends Texture {
|
|
77
|
+
constructor(_name, type) {
|
|
78
|
+
super(type);
|
|
79
|
+
this._name = _name;
|
|
80
|
+
}
|
|
81
|
+
toImdl() {
|
|
82
|
+
return this._name;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
class GradientTexture extends Texture {
|
|
86
|
+
constructor(_gradient) {
|
|
87
|
+
super(RenderTexture.Type.Normal);
|
|
88
|
+
this._gradient = _gradient;
|
|
89
|
+
}
|
|
90
|
+
toImdl() {
|
|
91
|
+
return this._gradient;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
class Material extends RenderMaterial {
|
|
95
|
+
toImdl() {
|
|
96
|
+
const material = this.key ?? this.materialParams;
|
|
97
|
+
return { isAtlas: false, material };
|
|
98
|
+
}
|
|
99
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
100
|
+
constructor(params, imdl) {
|
|
101
|
+
super(params);
|
|
102
|
+
this.materialParams = imdl ?? {
|
|
103
|
+
alpha: params.alpha,
|
|
104
|
+
diffuse: {
|
|
105
|
+
color: params.diffuseColor?.toJSON(),
|
|
106
|
+
weight: params.diffuse,
|
|
107
|
+
},
|
|
108
|
+
specular: {
|
|
109
|
+
color: params.specularColor?.toJSON(),
|
|
110
|
+
weight: params.specular,
|
|
111
|
+
exponent: params.specularExponent,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
static create(args) {
|
|
116
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
117
|
+
const params = new RenderMaterial.Params();
|
|
118
|
+
params.alpha = args.alpha;
|
|
119
|
+
if (args.diffuse) {
|
|
120
|
+
if (undefined !== args.diffuse.weight)
|
|
121
|
+
params.diffuse = args.diffuse?.weight;
|
|
122
|
+
if (args.diffuse?.color)
|
|
123
|
+
params.diffuseColor = args.diffuse.color instanceof ColorDef ? args.diffuse.color : RgbColor.fromJSON(args.diffuse.color).toColorDef();
|
|
124
|
+
}
|
|
125
|
+
if (args.specular) {
|
|
126
|
+
if (undefined !== args.specular.weight)
|
|
127
|
+
params.specular = args.specular.weight;
|
|
128
|
+
if (undefined !== args.specular.exponent)
|
|
129
|
+
params.specularExponent = args.specular.exponent;
|
|
130
|
+
if (args.specular.color)
|
|
131
|
+
params.specularColor = args.specular.color instanceof ColorDef ? args.specular.color : RgbColor.fromJSON(args.specular.color).toColorDef();
|
|
132
|
+
}
|
|
133
|
+
return new Material(params);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** @internal */
|
|
137
|
+
export function toVertexTable(imdl) {
|
|
138
|
+
return new VertexTable({
|
|
139
|
+
...imdl,
|
|
140
|
+
uniformColor: undefined !== imdl.uniformColor ? ColorDef.fromJSON(imdl.uniformColor) : undefined,
|
|
141
|
+
qparams: QParams3d.fromJSON(imdl.qparams),
|
|
142
|
+
uvParams: imdl.uvParams ? QParams2d.fromJSON(imdl.uvParams) : undefined,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function fromVertexTable(table) {
|
|
146
|
+
return {
|
|
147
|
+
...table,
|
|
148
|
+
uniformColor: table.uniformColor?.toJSON(),
|
|
149
|
+
qparams: table.qparams.toJSON(),
|
|
150
|
+
uvParams: table.uvParams?.toJSON(),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** @internal */
|
|
154
|
+
export function edgeParamsFromImdl(imdl) {
|
|
155
|
+
return {
|
|
156
|
+
...imdl,
|
|
157
|
+
segments: imdl.segments ? {
|
|
158
|
+
...imdl.segments,
|
|
159
|
+
indices: new VertexIndices(imdl.segments.indices),
|
|
160
|
+
} : undefined,
|
|
161
|
+
silhouettes: imdl.silhouettes ? {
|
|
162
|
+
...imdl.silhouettes,
|
|
163
|
+
indices: new VertexIndices(imdl.silhouettes.indices),
|
|
164
|
+
} : undefined,
|
|
165
|
+
polylines: imdl.polylines ? {
|
|
166
|
+
...imdl.polylines,
|
|
167
|
+
indices: new VertexIndices(imdl.polylines.indices),
|
|
168
|
+
prevIndices: new VertexIndices(imdl.polylines.prevIndices),
|
|
169
|
+
} : undefined,
|
|
170
|
+
indexed: imdl.indexed ? {
|
|
171
|
+
indices: new VertexIndices(imdl.indexed.indices),
|
|
172
|
+
edges: imdl.indexed.edges,
|
|
173
|
+
} : undefined,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function edgeParamsToImdl(params) {
|
|
177
|
+
return {
|
|
178
|
+
...params,
|
|
179
|
+
segments: params.segments ? {
|
|
180
|
+
...params.segments,
|
|
181
|
+
indices: params.segments.indices.data,
|
|
182
|
+
} : undefined,
|
|
183
|
+
silhouettes: params.silhouettes ? {
|
|
184
|
+
...params.silhouettes,
|
|
185
|
+
indices: params.silhouettes.indices.data,
|
|
186
|
+
} : undefined,
|
|
187
|
+
polylines: params.polylines ? {
|
|
188
|
+
...params.polylines,
|
|
189
|
+
indices: params.polylines.indices.data,
|
|
190
|
+
prevIndices: params.polylines.prevIndices.data,
|
|
191
|
+
} : undefined,
|
|
192
|
+
indexed: params.indexed ? {
|
|
193
|
+
indices: params.indexed.indices.data,
|
|
194
|
+
edges: params.indexed.edges,
|
|
195
|
+
} : undefined,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
class ImdlParser {
|
|
199
|
+
get _stream() {
|
|
200
|
+
return this._options.stream;
|
|
201
|
+
}
|
|
202
|
+
constructor(doc, binaryData, options, featureTableInfo) {
|
|
203
|
+
this._patterns = new Map();
|
|
204
|
+
this._document = doc;
|
|
205
|
+
this._binaryData = binaryData;
|
|
206
|
+
this._options = options;
|
|
207
|
+
this._featureTableInfo = featureTableInfo;
|
|
208
|
+
}
|
|
209
|
+
parse() {
|
|
210
|
+
const featureTable = this.parseFeatureTable();
|
|
211
|
+
if (!featureTable)
|
|
212
|
+
return TileReadStatus.InvalidFeatureTable;
|
|
213
|
+
const rtcCenter = this._document.rtcCenter ? {
|
|
214
|
+
x: this._document.rtcCenter[0] ?? 0,
|
|
215
|
+
y: this._document.rtcCenter[1] ?? 0,
|
|
216
|
+
z: this._document.rtcCenter[2] ?? 0,
|
|
217
|
+
} : undefined;
|
|
218
|
+
const nodes = this.parseNodes(featureTable);
|
|
219
|
+
return {
|
|
220
|
+
featureTable,
|
|
221
|
+
nodes,
|
|
222
|
+
rtcCenter,
|
|
223
|
+
binaryData: this._binaryData,
|
|
224
|
+
json: this._document,
|
|
225
|
+
patterns: this._patterns,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
parseFeatureTable() {
|
|
229
|
+
this._stream.curPos = this._featureTableInfo.startPos;
|
|
230
|
+
const header = FeatureTableHeader.readFrom(this._stream);
|
|
231
|
+
if (!header || 0 !== header.length % 4)
|
|
232
|
+
return undefined;
|
|
233
|
+
// NB: We make a copy of the sub-array because we don't want to pin the entire data array in memory.
|
|
234
|
+
const numUint32s = (header.length - FeatureTableHeader.sizeInBytes) / 4;
|
|
235
|
+
const packedFeatureArray = new Uint32Array(this._stream.nextUint32s(numUint32s));
|
|
236
|
+
if (this._stream.isPastTheEnd)
|
|
237
|
+
return undefined;
|
|
238
|
+
let featureTable;
|
|
239
|
+
if (this._featureTableInfo.multiModel) {
|
|
240
|
+
featureTable = {
|
|
241
|
+
multiModel: true,
|
|
242
|
+
data: packedFeatureArray,
|
|
243
|
+
numFeatures: header.count,
|
|
244
|
+
numSubCategories: header.numSubCategories,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
let animNodesArray;
|
|
249
|
+
const animationNodes = this._document.animationNodes;
|
|
250
|
+
if (undefined !== animationNodes) {
|
|
251
|
+
const bytesPerId = JsonUtils.asInt(animationNodes.bytesPerId);
|
|
252
|
+
const bufferViewId = JsonUtils.asString(animationNodes.bufferView);
|
|
253
|
+
const bufferViewJson = this._document.bufferViews[bufferViewId];
|
|
254
|
+
if (undefined !== bufferViewJson) {
|
|
255
|
+
const byteOffset = JsonUtils.asInt(bufferViewJson.byteOffset);
|
|
256
|
+
const byteLength = JsonUtils.asInt(bufferViewJson.byteLength);
|
|
257
|
+
const bytes = this._binaryData.subarray(byteOffset, byteOffset + byteLength);
|
|
258
|
+
switch (bytesPerId) {
|
|
259
|
+
case 1:
|
|
260
|
+
animNodesArray = new Uint8Array(bytes);
|
|
261
|
+
break;
|
|
262
|
+
case 2:
|
|
263
|
+
// NB: A *copy* of the subarray.
|
|
264
|
+
animNodesArray = Uint16Array.from(new Uint16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2));
|
|
265
|
+
break;
|
|
266
|
+
case 4:
|
|
267
|
+
// NB: A *copy* of the subarray.
|
|
268
|
+
animNodesArray = Uint32Array.from(new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4));
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
featureTable = {
|
|
274
|
+
multiModel: false,
|
|
275
|
+
data: packedFeatureArray,
|
|
276
|
+
numFeatures: header.count,
|
|
277
|
+
animationNodeIds: animNodesArray,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
this._stream.curPos = this._featureTableInfo.startPos + header.length;
|
|
281
|
+
return featureTable;
|
|
282
|
+
}
|
|
283
|
+
parseNodes(featureTable) {
|
|
284
|
+
const nodes = [];
|
|
285
|
+
const docNodes = this._document.nodes;
|
|
286
|
+
const docMeshes = this._document.meshes;
|
|
287
|
+
if (undefined === docNodes.Node_Root) {
|
|
288
|
+
// A veeeery early version of the tile format (prior to introduction of schedule animation support) just supplied a flat list of meshes.
|
|
289
|
+
// We shall never encounter such tiles again.
|
|
290
|
+
return nodes;
|
|
291
|
+
}
|
|
292
|
+
for (const nodeKey of Object.keys(docNodes)) {
|
|
293
|
+
const docNode = this._document.nodes[nodeKey];
|
|
294
|
+
assert(undefined !== docNode); // we're iterating the keys...
|
|
295
|
+
const docMesh = docMeshes[docNode];
|
|
296
|
+
const docPrimitives = docMesh?.primitives;
|
|
297
|
+
if (!docPrimitives)
|
|
298
|
+
continue;
|
|
299
|
+
const layerId = docMesh.layer;
|
|
300
|
+
if ("Node_Root" === nodeKey) {
|
|
301
|
+
if (this._options.timeline) {
|
|
302
|
+
// Split up the root node into transform nodes.
|
|
303
|
+
this.parseAnimationBranches(nodes, docMesh, featureTable, this._options.timeline);
|
|
304
|
+
}
|
|
305
|
+
else if (this._options.createUntransformedRootNode) {
|
|
306
|
+
// If transform nodes exist in the tile tree, then we need to create a branch for the root node so that elements not associated with
|
|
307
|
+
// any node in the schedule script can be grouped together.
|
|
308
|
+
nodes.push({
|
|
309
|
+
animationNodeId: AnimationNodeId.Untransformed,
|
|
310
|
+
primitives: this.parseNodePrimitives(docPrimitives),
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
nodes.push({ primitives: this.parseNodePrimitives(docPrimitives) });
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
else if (undefined === layerId) {
|
|
318
|
+
nodes.push({
|
|
319
|
+
animationNodeId: extractNodeId(nodeKey),
|
|
320
|
+
animationId: `${this._options.batchModelId}_${nodeKey}`,
|
|
321
|
+
primitives: this.parseNodePrimitives(docPrimitives),
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
nodes.push({
|
|
326
|
+
layerId,
|
|
327
|
+
primitives: this.parseNodePrimitives(docPrimitives),
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return nodes;
|
|
332
|
+
}
|
|
333
|
+
parseAnimationBranches(output, docMesh, imdlFeatureTable, timeline) {
|
|
334
|
+
const docPrimitives = docMesh.primitives;
|
|
335
|
+
if (!docPrimitives)
|
|
336
|
+
return;
|
|
337
|
+
const nodesById = new Map();
|
|
338
|
+
const getNode = (nodeId) => {
|
|
339
|
+
let node = nodesById.get(nodeId);
|
|
340
|
+
if (!node) {
|
|
341
|
+
node = {
|
|
342
|
+
animationNodeId: nodeId,
|
|
343
|
+
animationId: `${this._options.batchModelId}_Node_${nodeId}`,
|
|
344
|
+
primitives: [],
|
|
345
|
+
};
|
|
346
|
+
nodesById.set(nodeId, node);
|
|
347
|
+
output.push(node);
|
|
348
|
+
}
|
|
349
|
+
return node;
|
|
350
|
+
};
|
|
351
|
+
// NB: The BatchType is irrelevant - just use Primary.
|
|
352
|
+
assert(undefined === imdlFeatureTable.animationNodeIds);
|
|
353
|
+
const featureTable = convertFeatureTable(imdlFeatureTable, this._options.batchModelId);
|
|
354
|
+
featureTable.populateAnimationNodeIds((feature) => timeline.getBatchIdForFeature(feature), timeline.maxBatchId);
|
|
355
|
+
imdlFeatureTable.animationNodeIds = featureTable.animationNodeIds;
|
|
356
|
+
const discreteNodeIds = timeline.discreteBatchIds;
|
|
357
|
+
const computeNodeId = (featureIndex) => {
|
|
358
|
+
const nodeId = featureTable.getAnimationNodeId(featureIndex);
|
|
359
|
+
return 0 !== nodeId && discreteNodeIds.has(nodeId) ? nodeId : 0;
|
|
360
|
+
};
|
|
361
|
+
const splitArgs = {
|
|
362
|
+
maxDimension: this._options.maxVertexTableSize,
|
|
363
|
+
computeNodeId,
|
|
364
|
+
featureTable,
|
|
365
|
+
};
|
|
366
|
+
const convertMaterial = (imdl) => {
|
|
367
|
+
if (!imdl)
|
|
368
|
+
return undefined;
|
|
369
|
+
else if (imdl.isAtlas)
|
|
370
|
+
return imdl;
|
|
371
|
+
const material = (typeof imdl.material === "string") ? this.materialFromJson(imdl.material) : Material.create(toMaterialArgs(imdl.material));
|
|
372
|
+
return material ? { isAtlas: false, material } : undefined;
|
|
373
|
+
};
|
|
374
|
+
for (const docPrimitive of docPrimitives) {
|
|
375
|
+
const primitive = this.parseNodePrimitive(docPrimitive);
|
|
376
|
+
if (!primitive)
|
|
377
|
+
continue;
|
|
378
|
+
switch (primitive.type) {
|
|
379
|
+
case "pattern":
|
|
380
|
+
// ###TODO animated area patterns
|
|
381
|
+
getNode(AnimationNodeId.Untransformed).primitives.push(primitive);
|
|
382
|
+
break;
|
|
383
|
+
case "mesh": {
|
|
384
|
+
const mesh = primitive.params;
|
|
385
|
+
const texMap = mesh.surface.textureMapping;
|
|
386
|
+
const params = {
|
|
387
|
+
vertices: toVertexTable(primitive.params.vertices),
|
|
388
|
+
surface: {
|
|
389
|
+
...primitive.params.surface,
|
|
390
|
+
indices: new VertexIndices(primitive.params.surface.indices),
|
|
391
|
+
material: convertMaterial(mesh.surface.material),
|
|
392
|
+
textureMapping: texMap ? {
|
|
393
|
+
alwaysDisplayed: texMap.alwaysDisplayed,
|
|
394
|
+
// The texture type doesn't actually matter here.
|
|
395
|
+
texture: typeof texMap.texture === "string" ? new NamedTexture(texMap.texture, RenderTexture.Type.Normal) : new GradientTexture(texMap.texture),
|
|
396
|
+
} : undefined,
|
|
397
|
+
},
|
|
398
|
+
edges: primitive.params.edges ? edgeParamsFromImdl(primitive.params.edges) : undefined,
|
|
399
|
+
isPlanar: primitive.params.isPlanar,
|
|
400
|
+
auxChannels: primitive.params.auxChannels ? AuxChannelTable.fromJSON(primitive.params.auxChannels) : undefined,
|
|
401
|
+
};
|
|
402
|
+
const split = splitMeshParams({
|
|
403
|
+
...splitArgs,
|
|
404
|
+
params,
|
|
405
|
+
createMaterial: (args) => Material.create(args),
|
|
406
|
+
});
|
|
407
|
+
for (const [nodeId, p] of split) {
|
|
408
|
+
let material;
|
|
409
|
+
if (p.surface.material) {
|
|
410
|
+
if (p.surface.material.isAtlas) {
|
|
411
|
+
material = p.surface.material;
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
assert(p.surface.material.material instanceof Material);
|
|
415
|
+
material = p.surface.material.material.toImdl();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
assert(p.surface.textureMapping === undefined || p.surface.textureMapping.texture instanceof Texture);
|
|
419
|
+
getNode(nodeId).primitives.push({
|
|
420
|
+
type: "mesh",
|
|
421
|
+
params: {
|
|
422
|
+
vertices: fromVertexTable(p.vertices),
|
|
423
|
+
surface: {
|
|
424
|
+
...p.surface,
|
|
425
|
+
indices: p.surface.indices.data,
|
|
426
|
+
material,
|
|
427
|
+
textureMapping: p.surface.textureMapping?.texture instanceof Texture ? {
|
|
428
|
+
texture: p.surface.textureMapping.texture.toImdl(),
|
|
429
|
+
alwaysDisplayed: p.surface.textureMapping.alwaysDisplayed,
|
|
430
|
+
} : undefined,
|
|
431
|
+
},
|
|
432
|
+
edges: p.edges ? edgeParamsToImdl(p.edges) : undefined,
|
|
433
|
+
isPlanar: p.isPlanar,
|
|
434
|
+
auxChannels: p.auxChannels?.toJSON(),
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
case "point": {
|
|
441
|
+
const params = {
|
|
442
|
+
vertices: toVertexTable(primitive.params.vertices),
|
|
443
|
+
indices: new VertexIndices(primitive.params.indices),
|
|
444
|
+
weight: primitive.params.weight,
|
|
445
|
+
};
|
|
446
|
+
const split = splitPointStringParams({ ...splitArgs, params });
|
|
447
|
+
for (const [nodeId, p] of split) {
|
|
448
|
+
getNode(nodeId).primitives.push({
|
|
449
|
+
type: "point",
|
|
450
|
+
params: {
|
|
451
|
+
vertices: fromVertexTable(p.vertices),
|
|
452
|
+
indices: p.indices.data,
|
|
453
|
+
weight: p.weight,
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
case "polyline": {
|
|
460
|
+
const params = {
|
|
461
|
+
...primitive.params,
|
|
462
|
+
vertices: toVertexTable(primitive.params.vertices),
|
|
463
|
+
polyline: {
|
|
464
|
+
indices: new VertexIndices(primitive.params.polyline.indices),
|
|
465
|
+
prevIndices: new VertexIndices(primitive.params.polyline.prevIndices),
|
|
466
|
+
nextIndicesAndParams: primitive.params.polyline.nextIndicesAndParams,
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
const split = splitPolylineParams({ ...splitArgs, params });
|
|
470
|
+
for (const [nodeId, p] of split) {
|
|
471
|
+
getNode(nodeId).primitives.push({
|
|
472
|
+
type: "polyline",
|
|
473
|
+
params: {
|
|
474
|
+
...p,
|
|
475
|
+
vertices: fromVertexTable(p.vertices),
|
|
476
|
+
polyline: {
|
|
477
|
+
indices: p.polyline.indices.data,
|
|
478
|
+
prevIndices: p.polyline.prevIndices.data,
|
|
479
|
+
nextIndicesAndParams: p.polyline.nextIndicesAndParams,
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
parseTesselatedPolyline(json) {
|
|
490
|
+
const indices = this.findBuffer(json.indices);
|
|
491
|
+
const prevIndices = this.findBuffer(json.prevIndices);
|
|
492
|
+
const nextIndicesAndParams = this.findBuffer(json.nextIndicesAndParams);
|
|
493
|
+
return indices && prevIndices && nextIndicesAndParams ? { indices, prevIndices, nextIndicesAndParams } : undefined;
|
|
494
|
+
}
|
|
495
|
+
parseSegmentEdges(imdl) {
|
|
496
|
+
const indices = this.findBuffer(imdl.indices);
|
|
497
|
+
const endPointAndQuadIndices = this.findBuffer(imdl.endPointAndQuadIndices);
|
|
498
|
+
return indices && endPointAndQuadIndices ? { indices, endPointAndQuadIndices } : undefined;
|
|
499
|
+
}
|
|
500
|
+
parseSilhouetteEdges(imdl) {
|
|
501
|
+
const segments = this.parseSegmentEdges(imdl);
|
|
502
|
+
const normalPairs = this.findBuffer(imdl.normalPairs);
|
|
503
|
+
return segments && normalPairs ? { ...segments, normalPairs } : undefined;
|
|
504
|
+
}
|
|
505
|
+
parseIndexedEdges(imdl) {
|
|
506
|
+
const indices = this.findBuffer(imdl.indices);
|
|
507
|
+
const edgeTable = this.findBuffer(imdl.edges);
|
|
508
|
+
if (!indices || !edgeTable)
|
|
509
|
+
return undefined;
|
|
510
|
+
return {
|
|
511
|
+
indices,
|
|
512
|
+
edges: {
|
|
513
|
+
data: edgeTable,
|
|
514
|
+
width: imdl.width,
|
|
515
|
+
height: imdl.height,
|
|
516
|
+
silhouettePadding: imdl.silhouettePadding,
|
|
517
|
+
numSegments: imdl.numSegments,
|
|
518
|
+
},
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
parseEdges(imdl, displayParams) {
|
|
522
|
+
if (!imdl)
|
|
523
|
+
return undefined;
|
|
524
|
+
const segments = imdl.segments ? this.parseSegmentEdges(imdl.segments) : undefined;
|
|
525
|
+
const silhouettes = imdl.silhouettes ? this.parseSilhouetteEdges(imdl.silhouettes) : undefined;
|
|
526
|
+
const indexed = imdl.indexed ? this.parseIndexedEdges(imdl.indexed) : undefined;
|
|
527
|
+
const polylines = imdl.polylines ? this.parseTesselatedPolyline(imdl.polylines) : undefined;
|
|
528
|
+
if (!segments && !silhouettes && !indexed && !polylines)
|
|
529
|
+
return undefined;
|
|
530
|
+
return {
|
|
531
|
+
segments,
|
|
532
|
+
silhouettes,
|
|
533
|
+
polylines,
|
|
534
|
+
indexed,
|
|
535
|
+
weight: displayParams.width,
|
|
536
|
+
linePixels: displayParams.linePixels,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
getPattern(name) {
|
|
540
|
+
let primitives = this._patterns.get(name);
|
|
541
|
+
if (!primitives) {
|
|
542
|
+
const symbol = this._document.patternSymbols[name];
|
|
543
|
+
primitives = symbol ? this.parsePrimitives(symbol.primitives) : [];
|
|
544
|
+
this._patterns.set(name, primitives);
|
|
545
|
+
}
|
|
546
|
+
return primitives.length > 0 ? primitives : undefined;
|
|
547
|
+
}
|
|
548
|
+
parseAreaPattern(json) {
|
|
549
|
+
const primitives = this.getPattern(json.symbolName);
|
|
550
|
+
if (!primitives || primitives.length === 0)
|
|
551
|
+
return undefined;
|
|
552
|
+
const xyOffsets = this.findBuffer(json.xyOffsets);
|
|
553
|
+
if (!xyOffsets)
|
|
554
|
+
return undefined;
|
|
555
|
+
return {
|
|
556
|
+
type: "pattern",
|
|
557
|
+
params: {
|
|
558
|
+
...json,
|
|
559
|
+
xyOffsets: new Float32Array(xyOffsets.buffer, xyOffsets.byteOffset, xyOffsets.byteLength / 4),
|
|
560
|
+
},
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
parseNodePrimitives(docPrimitives) {
|
|
564
|
+
const primitives = [];
|
|
565
|
+
for (const docPrimitive of docPrimitives) {
|
|
566
|
+
const primitive = this.parseNodePrimitive(docPrimitive);
|
|
567
|
+
if (primitive)
|
|
568
|
+
primitives.push(primitive);
|
|
569
|
+
}
|
|
570
|
+
return primitives;
|
|
571
|
+
}
|
|
572
|
+
parseNodePrimitive(docPrimitive) {
|
|
573
|
+
return docPrimitive.type === "areaPattern" ? this.parseAreaPattern(docPrimitive) : this.parsePrimitive(docPrimitive);
|
|
574
|
+
}
|
|
575
|
+
parsePrimitives(docPrimitives) {
|
|
576
|
+
const primitives = [];
|
|
577
|
+
for (const docPrimitive of docPrimitives) {
|
|
578
|
+
const primitive = this.parsePrimitive(docPrimitive);
|
|
579
|
+
if (primitive)
|
|
580
|
+
primitives.push(primitive);
|
|
581
|
+
}
|
|
582
|
+
return primitives;
|
|
583
|
+
}
|
|
584
|
+
parsePrimitive(docPrimitive) {
|
|
585
|
+
let modifier = this.parseInstances(docPrimitive);
|
|
586
|
+
if (!modifier && docPrimitive.viewIndependentOrigin) {
|
|
587
|
+
const origin = Point3d.fromJSON(docPrimitive.viewIndependentOrigin);
|
|
588
|
+
modifier = {
|
|
589
|
+
type: "viewIndependentOrigin",
|
|
590
|
+
origin: { x: origin.x, y: origin.y, z: origin.z },
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
const materialName = docPrimitive.material ?? "";
|
|
594
|
+
const dpMaterial = materialName.length ? JsonUtils.asObject(this._document.materials[materialName]) : undefined;
|
|
595
|
+
const displayParams = dpMaterial ? this.parseDisplayParams(dpMaterial) : undefined;
|
|
596
|
+
if (!displayParams)
|
|
597
|
+
return undefined;
|
|
598
|
+
const vertices = this.parseVertexTable(docPrimitive);
|
|
599
|
+
if (!vertices)
|
|
600
|
+
return undefined;
|
|
601
|
+
let primitive;
|
|
602
|
+
const isPlanar = !this._options.is3d || JsonUtils.asBool(docPrimitive.isPlanar);
|
|
603
|
+
switch (docPrimitive.type) {
|
|
604
|
+
case Mesh.PrimitiveType.Mesh: {
|
|
605
|
+
const surface = this.parseSurface(docPrimitive, displayParams);
|
|
606
|
+
if (surface) {
|
|
607
|
+
primitive = {
|
|
608
|
+
type: "mesh",
|
|
609
|
+
params: {
|
|
610
|
+
vertices,
|
|
611
|
+
surface,
|
|
612
|
+
isPlanar,
|
|
613
|
+
auxChannels: this.parseAuxChannelTable(docPrimitive),
|
|
614
|
+
edges: this.parseEdges(docPrimitive.edges, displayParams),
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
620
|
+
case Mesh.PrimitiveType.Polyline: {
|
|
621
|
+
const polyline = this.parseTesselatedPolyline(docPrimitive);
|
|
622
|
+
if (polyline) {
|
|
623
|
+
let type = PolylineTypeFlags.Normal;
|
|
624
|
+
if (DisplayParams.RegionEdgeType.Outline === displayParams.regionEdgeType)
|
|
625
|
+
type = (!displayParams.gradient || displayParams.gradient.isOutlined) ? PolylineTypeFlags.Edge : PolylineTypeFlags.Outline;
|
|
626
|
+
primitive = {
|
|
627
|
+
type: "polyline",
|
|
628
|
+
params: {
|
|
629
|
+
vertices,
|
|
630
|
+
polyline,
|
|
631
|
+
isPlanar,
|
|
632
|
+
type,
|
|
633
|
+
weight: displayParams.width,
|
|
634
|
+
linePixels: displayParams.linePixels,
|
|
635
|
+
},
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
case Mesh.PrimitiveType.Point: {
|
|
641
|
+
const indices = this.findBuffer(docPrimitive.indices);
|
|
642
|
+
const weight = displayParams.width;
|
|
643
|
+
if (indices) {
|
|
644
|
+
primitive = {
|
|
645
|
+
type: "point",
|
|
646
|
+
params: { vertices, indices, weight },
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (primitive)
|
|
653
|
+
primitive.modifier = modifier;
|
|
654
|
+
return primitive;
|
|
655
|
+
}
|
|
656
|
+
parseSurface(mesh, displayParams) {
|
|
657
|
+
const surf = mesh.surface;
|
|
658
|
+
if (!surf)
|
|
659
|
+
return undefined;
|
|
660
|
+
const indices = this.findBuffer(surf.indices);
|
|
661
|
+
if (!indices)
|
|
662
|
+
return undefined;
|
|
663
|
+
const type = surf.type;
|
|
664
|
+
if (!isValidSurfaceType(type))
|
|
665
|
+
return undefined;
|
|
666
|
+
const texture = displayParams.textureMapping?.texture;
|
|
667
|
+
let material;
|
|
668
|
+
const atlas = mesh.vertices.materialAtlas;
|
|
669
|
+
const numColors = mesh.vertices.numColors;
|
|
670
|
+
if (atlas && undefined !== numColors) {
|
|
671
|
+
material = {
|
|
672
|
+
isAtlas: true,
|
|
673
|
+
hasTranslucency: JsonUtils.asBool(atlas.hasTranslucency),
|
|
674
|
+
overridesAlpha: JsonUtils.asBool(atlas.overridesAlpha, false),
|
|
675
|
+
vertexTableOffset: JsonUtils.asInt(numColors),
|
|
676
|
+
numMaterials: JsonUtils.asInt(atlas.numMaterials),
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
else if (displayParams.material) {
|
|
680
|
+
assert(displayParams.material instanceof Material);
|
|
681
|
+
material = displayParams.material.toImdl();
|
|
682
|
+
}
|
|
683
|
+
let textureMapping;
|
|
684
|
+
if (texture) {
|
|
685
|
+
assert(texture instanceof Texture);
|
|
686
|
+
textureMapping = {
|
|
687
|
+
texture: texture.toImdl(),
|
|
688
|
+
alwaysDisplayed: JsonUtils.asBool(surf.alwaysDisplayTexture),
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
return {
|
|
692
|
+
type,
|
|
693
|
+
indices,
|
|
694
|
+
fillFlags: displayParams.fillFlags,
|
|
695
|
+
hasBakedLighting: false,
|
|
696
|
+
material,
|
|
697
|
+
textureMapping,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
parseAuxChannelTable(primitive) {
|
|
701
|
+
const json = primitive.auxChannels;
|
|
702
|
+
if (undefined === json)
|
|
703
|
+
return undefined;
|
|
704
|
+
const bytes = this.findBuffer(JsonUtils.asString(json.bufferView));
|
|
705
|
+
if (undefined === bytes)
|
|
706
|
+
return undefined;
|
|
707
|
+
return {
|
|
708
|
+
data: bytes,
|
|
709
|
+
width: json.width,
|
|
710
|
+
height: json.height,
|
|
711
|
+
count: json.count,
|
|
712
|
+
numBytesPerVertex: json.numBytesPerVertex,
|
|
713
|
+
displacements: json.displacements,
|
|
714
|
+
normals: json.normals,
|
|
715
|
+
params: json.params,
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
parseVertexTable(primitive) {
|
|
719
|
+
const json = primitive.vertices;
|
|
720
|
+
if (!json)
|
|
721
|
+
return undefined;
|
|
722
|
+
const bytes = this.findBuffer(JsonUtils.asString(json.bufferView));
|
|
723
|
+
if (!bytes)
|
|
724
|
+
return undefined;
|
|
725
|
+
const uniformFeatureID = undefined !== json.featureID ? JsonUtils.asInt(json.featureID) : undefined;
|
|
726
|
+
const rangeMin = JsonUtils.asArray(json.params.decodedMin);
|
|
727
|
+
const rangeMax = JsonUtils.asArray(json.params.decodedMax);
|
|
728
|
+
if (undefined === rangeMin || undefined === rangeMax)
|
|
729
|
+
return undefined;
|
|
730
|
+
const qparams = QParams3d.fromRange(Range3d.create(Point3d.create(rangeMin[0], rangeMin[1], rangeMin[2]), Point3d.create(rangeMax[0], rangeMax[1], rangeMax[2])));
|
|
731
|
+
const uniformColor = undefined !== json.uniformColor ? ColorDef.fromJSON(json.uniformColor) : undefined;
|
|
732
|
+
let uvParams;
|
|
733
|
+
if (Mesh.PrimitiveType.Mesh === primitive.type && primitive.surface && primitive.surface.uvParams) {
|
|
734
|
+
const uvMin = primitive.surface.uvParams.decodedMin;
|
|
735
|
+
const uvMax = primitive.surface.uvParams.decodedMax;
|
|
736
|
+
const uvRange = new Range2d(uvMin[0], uvMin[1], uvMax[0], uvMax[1]);
|
|
737
|
+
uvParams = QParams2d.fromRange(uvRange);
|
|
738
|
+
}
|
|
739
|
+
return {
|
|
740
|
+
data: bytes,
|
|
741
|
+
usesUnquantizedPositions: true === json.usesUnquantizedPositions,
|
|
742
|
+
qparams: qparams.toJSON(),
|
|
743
|
+
width: json.width,
|
|
744
|
+
height: json.height,
|
|
745
|
+
hasTranslucency: json.hasTranslucency,
|
|
746
|
+
uniformColor: uniformColor?.toJSON(),
|
|
747
|
+
featureIndexType: json.featureIndexType,
|
|
748
|
+
uniformFeatureID,
|
|
749
|
+
numVertices: json.count,
|
|
750
|
+
numRgbaPerVertex: json.numRgbaPerVertex,
|
|
751
|
+
uvParams: uvParams?.toJSON(),
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
parseInstances(primitive) {
|
|
755
|
+
const json = primitive.instances;
|
|
756
|
+
if (!json)
|
|
757
|
+
return undefined;
|
|
758
|
+
const count = JsonUtils.asInt(json.count, 0);
|
|
759
|
+
if (count <= 0)
|
|
760
|
+
return undefined;
|
|
761
|
+
const centerComponents = JsonUtils.asArray(json.transformCenter);
|
|
762
|
+
if (undefined === centerComponents || 3 !== centerComponents.length)
|
|
763
|
+
return undefined;
|
|
764
|
+
const transformCenter = Point3d.create(centerComponents[0], centerComponents[1], centerComponents[2]);
|
|
765
|
+
const featureIds = this.findBuffer(JsonUtils.asString(json.featureIds));
|
|
766
|
+
if (undefined === featureIds)
|
|
767
|
+
return undefined;
|
|
768
|
+
const transformBytes = this.findBuffer(JsonUtils.asString(json.transforms));
|
|
769
|
+
if (undefined === transformBytes)
|
|
770
|
+
return undefined;
|
|
771
|
+
// 1 transform = 3 rows of 4 floats = 12 floats per instance
|
|
772
|
+
const numFloats = transformBytes.byteLength / 4;
|
|
773
|
+
assert(Math.floor(numFloats) === numFloats);
|
|
774
|
+
assert(0 === numFloats % 12);
|
|
775
|
+
const transforms = new Float32Array(transformBytes.buffer, transformBytes.byteOffset, numFloats);
|
|
776
|
+
let symbologyOverrides;
|
|
777
|
+
if (undefined !== json.symbologyOverrides)
|
|
778
|
+
symbologyOverrides = this.findBuffer(JsonUtils.asString(json.symbologyOverrides));
|
|
779
|
+
return {
|
|
780
|
+
type: "instances",
|
|
781
|
+
count,
|
|
782
|
+
transforms,
|
|
783
|
+
transformCenter,
|
|
784
|
+
featureIds,
|
|
785
|
+
symbologyOverrides,
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
findBuffer(bufferViewId) {
|
|
789
|
+
if (typeof bufferViewId !== "string" || 0 === bufferViewId.length)
|
|
790
|
+
return undefined;
|
|
791
|
+
const bufferViewJson = this._document.bufferViews[bufferViewId];
|
|
792
|
+
if (undefined === bufferViewJson)
|
|
793
|
+
return undefined;
|
|
794
|
+
const byteOffset = JsonUtils.asInt(bufferViewJson.byteOffset);
|
|
795
|
+
const byteLength = JsonUtils.asInt(bufferViewJson.byteLength);
|
|
796
|
+
if (0 === byteLength)
|
|
797
|
+
return undefined;
|
|
798
|
+
return this._binaryData.subarray(byteOffset, byteOffset + byteLength);
|
|
799
|
+
}
|
|
800
|
+
colorDefFromMaterialJson(json) {
|
|
801
|
+
return undefined !== json ? ColorDef.from(json[0] * 255 + 0.5, json[1] * 255 + 0.5, json[2] * 255 + 0.5) : undefined;
|
|
802
|
+
}
|
|
803
|
+
materialFromJson(key) {
|
|
804
|
+
const materialJson = this._document.renderMaterials[key];
|
|
805
|
+
if (!materialJson)
|
|
806
|
+
return undefined;
|
|
807
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
808
|
+
const materialParams = new RenderMaterial.Params(key);
|
|
809
|
+
materialParams.diffuseColor = this.colorDefFromMaterialJson(materialJson.diffuseColor);
|
|
810
|
+
if (materialJson.diffuse !== undefined)
|
|
811
|
+
materialParams.diffuse = JsonUtils.asDouble(materialJson.diffuse);
|
|
812
|
+
materialParams.specularColor = this.colorDefFromMaterialJson(materialJson.specularColor);
|
|
813
|
+
if (materialJson.specular !== undefined)
|
|
814
|
+
materialParams.specular = JsonUtils.asDouble(materialJson.specular);
|
|
815
|
+
materialParams.reflectColor = this.colorDefFromMaterialJson(materialJson.reflectColor);
|
|
816
|
+
if (materialJson.reflect !== undefined)
|
|
817
|
+
materialParams.reflect = JsonUtils.asDouble(materialJson.reflect);
|
|
818
|
+
if (materialJson.specularExponent !== undefined)
|
|
819
|
+
materialParams.specularExponent = materialJson.specularExponent;
|
|
820
|
+
if (undefined !== materialJson.transparency)
|
|
821
|
+
materialParams.alpha = 1.0 - materialJson.transparency;
|
|
822
|
+
materialParams.refract = JsonUtils.asDouble(materialJson.refract);
|
|
823
|
+
materialParams.shadows = JsonUtils.asBool(materialJson.shadows);
|
|
824
|
+
materialParams.ambient = JsonUtils.asDouble(materialJson.ambient);
|
|
825
|
+
if (undefined !== materialJson.textureMapping)
|
|
826
|
+
materialParams.textureMapping = this.textureMappingFromJson(materialJson.textureMapping.texture);
|
|
827
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
828
|
+
return new Material(materialParams);
|
|
829
|
+
}
|
|
830
|
+
parseNamedTexture(namedTex, name) {
|
|
831
|
+
const textureType = JsonUtils.asBool(namedTex.isGlyph) ? RenderTexture.Type.Glyph :
|
|
832
|
+
(JsonUtils.asBool(namedTex.isTileSection) ? RenderTexture.Type.TileSection : RenderTexture.Type.Normal);
|
|
833
|
+
return new NamedTexture(name, textureType);
|
|
834
|
+
}
|
|
835
|
+
parseConstantLodProps(propsJson) {
|
|
836
|
+
if (undefined === propsJson)
|
|
837
|
+
return undefined;
|
|
838
|
+
return {
|
|
839
|
+
repetitions: JsonUtils.asDouble(propsJson.repetitions, 1.0),
|
|
840
|
+
offset: { x: propsJson.offset ? JsonUtils.asDouble(propsJson.offset[0]) : 0.0, y: propsJson.offset ? JsonUtils.asDouble(propsJson.offset[1]) : 0.0 },
|
|
841
|
+
minDistClamp: JsonUtils.asDouble(propsJson.minDistClamp, 1.0),
|
|
842
|
+
maxDistClamp: JsonUtils.asDouble(propsJson.maxDistClamp, 4096.0 * 1024.0 * 1024.0),
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
textureMappingFromJson(json) {
|
|
846
|
+
if (!json)
|
|
847
|
+
return undefined;
|
|
848
|
+
const name = JsonUtils.asString(json.name);
|
|
849
|
+
const namedTex = 0 !== name.length ? this._document.namedTextures[name] : undefined;
|
|
850
|
+
const texture = namedTex ? this.parseNamedTexture(namedTex, name) : undefined;
|
|
851
|
+
if (!texture)
|
|
852
|
+
return undefined;
|
|
853
|
+
const paramsJson = json.params;
|
|
854
|
+
const tf = paramsJson.transform;
|
|
855
|
+
const paramProps = {
|
|
856
|
+
textureMat2x3: new TextureMapping.Trans2x3(tf[0][0], tf[0][1], tf[0][2], tf[1][0], tf[1][1], tf[1][2]),
|
|
857
|
+
textureWeight: JsonUtils.asDouble(paramsJson.weight, 1.0),
|
|
858
|
+
mapMode: JsonUtils.asInt(paramsJson.mode),
|
|
859
|
+
worldMapping: JsonUtils.asBool(paramsJson.worldMapping),
|
|
860
|
+
useConstantLod: JsonUtils.asBool(paramsJson.useConstantLod),
|
|
861
|
+
constantLodProps: this.parseConstantLodProps(paramsJson.constantLodParams),
|
|
862
|
+
};
|
|
863
|
+
const textureMapping = new TextureMapping(texture, new TextureMapping.Params(paramProps));
|
|
864
|
+
const normalMapJson = json.normalMapParams;
|
|
865
|
+
if (normalMapJson) {
|
|
866
|
+
const normalTexName = JsonUtils.asString(normalMapJson.textureName);
|
|
867
|
+
const namedNormalTex = normalTexName.length > 0 ? this._document.namedTextures[normalTexName] : undefined;
|
|
868
|
+
const normalMap = namedNormalTex ? this.parseNamedTexture(namedNormalTex, normalTexName) : undefined;
|
|
869
|
+
if (normalMap) {
|
|
870
|
+
textureMapping.normalMapParams = {
|
|
871
|
+
normalMap,
|
|
872
|
+
greenUp: JsonUtils.asBool(normalMapJson.greenUp),
|
|
873
|
+
scale: JsonUtils.asDouble(normalMapJson.scale, 1),
|
|
874
|
+
useConstantLod: JsonUtils.asBool(normalMapJson.useConstantLod),
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
return textureMapping;
|
|
879
|
+
}
|
|
880
|
+
parseDisplayParams(json) {
|
|
881
|
+
const type = JsonUtils.asInt(json.type, DisplayParams.Type.Mesh);
|
|
882
|
+
const lineColor = ColorDef.create(JsonUtils.asInt(json.lineColor));
|
|
883
|
+
const fillColor = ColorDef.create(JsonUtils.asInt(json.fillColor));
|
|
884
|
+
const width = JsonUtils.asInt(json.lineWidth);
|
|
885
|
+
const linePixels = JsonUtils.asInt(json.linePixels, LinePixels.Solid);
|
|
886
|
+
const fillFlags = JsonUtils.asInt(json.fillFlags, FillFlags.None);
|
|
887
|
+
const ignoreLighting = JsonUtils.asBool(json.ignoreLighting);
|
|
888
|
+
// Material will always contain its own texture if it has one
|
|
889
|
+
const materialKey = json.materialId;
|
|
890
|
+
const material = undefined !== materialKey ? this.materialFromJson(materialKey) : undefined;
|
|
891
|
+
// We will only attempt to include the texture if material is undefined
|
|
892
|
+
let textureMapping;
|
|
893
|
+
let gradient;
|
|
894
|
+
if (!material) {
|
|
895
|
+
const textureJson = json.texture;
|
|
896
|
+
textureMapping = undefined !== textureJson ? this.textureMappingFromJson(textureJson) : undefined;
|
|
897
|
+
if (undefined === textureMapping) {
|
|
898
|
+
const gradientProps = json.gradient;
|
|
899
|
+
gradient = undefined !== gradientProps ? Gradient.Symb.fromJSON(gradientProps) : undefined;
|
|
900
|
+
if (gradient) {
|
|
901
|
+
assert(undefined !== gradientProps);
|
|
902
|
+
const texture = new GradientTexture(gradientProps);
|
|
903
|
+
textureMapping = new TextureMapping(texture, new TextureMapping.Params({ textureMat2x3: new TextureMapping.Trans2x3(0, 1, 0, 1, 0, 0) }));
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return new DisplayParams(type, lineColor, fillColor, width, linePixels, fillFlags, material, gradient, ignoreLighting, textureMapping);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
/** @internal */
|
|
911
|
+
export function toMaterialArgs(mat) {
|
|
912
|
+
const args = { alpha: mat.alpha };
|
|
913
|
+
if (mat.diffuse) {
|
|
914
|
+
args.diffuse = {
|
|
915
|
+
weight: mat.diffuse.weight,
|
|
916
|
+
color: undefined !== mat.diffuse.color ? ColorDef.fromJSON(mat.diffuse.color) : undefined,
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
if (mat.specular) {
|
|
920
|
+
args.specular = {
|
|
921
|
+
weight: mat.specular.weight,
|
|
922
|
+
exponent: mat.specular.exponent,
|
|
923
|
+
color: undefined !== mat.specular.color ? ColorDef.fromJSON(mat.specular.color) : undefined,
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
return args;
|
|
927
|
+
}
|
|
928
|
+
/** @internal */
|
|
929
|
+
export function convertFeatureTable(imdlFeatureTable, batchModelId) {
|
|
930
|
+
const table = imdlFeatureTable.multiModel
|
|
931
|
+
? MultiModelPackedFeatureTable.create(imdlFeatureTable.data, batchModelId, imdlFeatureTable.numFeatures, BatchType.Primary, imdlFeatureTable.numSubCategories)
|
|
932
|
+
: new PackedFeatureTable(imdlFeatureTable.data, batchModelId, imdlFeatureTable.numFeatures, BatchType.Primary);
|
|
933
|
+
table.animationNodeIds = imdlFeatureTable.animationNodeIds;
|
|
934
|
+
return table;
|
|
935
|
+
}
|
|
936
|
+
/** @internal */
|
|
937
|
+
export function parseImdlDocument(options) {
|
|
938
|
+
const stream = options.stream;
|
|
939
|
+
const imdlHeader = new ImdlHeader(stream);
|
|
940
|
+
if (!imdlHeader.isValid)
|
|
941
|
+
return TileReadStatus.InvalidHeader;
|
|
942
|
+
else if (!imdlHeader.isReadableVersion)
|
|
943
|
+
return TileReadStatus.NewerMajorVersion;
|
|
944
|
+
// Skip the feature table - we need to parse the JSON segment first to access its animationNodeIds.
|
|
945
|
+
const ftStartPos = stream.curPos;
|
|
946
|
+
const ftHeader = FeatureTableHeader.readFrom(stream);
|
|
947
|
+
if (!ftHeader)
|
|
948
|
+
return TileReadStatus.InvalidFeatureTable;
|
|
949
|
+
stream.curPos = ftStartPos + ftHeader.length;
|
|
950
|
+
// A glTF header follows the feature table
|
|
951
|
+
const gltfHeader = new GltfHeader(stream);
|
|
952
|
+
if (!gltfHeader.isValid)
|
|
953
|
+
return TileReadStatus.InvalidTileData;
|
|
954
|
+
stream.curPos = gltfHeader.scenePosition;
|
|
955
|
+
const sceneStrData = stream.nextBytes(gltfHeader.sceneStrLength);
|
|
956
|
+
const sceneStr = utf8ToString(sceneStrData);
|
|
957
|
+
if (!sceneStr)
|
|
958
|
+
return TileReadStatus.InvalidScene;
|
|
959
|
+
try {
|
|
960
|
+
const sceneValue = JSON.parse(sceneStr);
|
|
961
|
+
const imdlDoc = {
|
|
962
|
+
scene: JsonUtils.asString(sceneValue.scene),
|
|
963
|
+
scenes: JsonUtils.asArray(sceneValue.scenes),
|
|
964
|
+
animationNodes: JsonUtils.asObject(sceneValue.animationNodes),
|
|
965
|
+
bufferViews: JsonUtils.asObject(sceneValue.bufferViews) ?? {},
|
|
966
|
+
meshes: JsonUtils.asObject(sceneValue.meshes),
|
|
967
|
+
nodes: JsonUtils.asObject(sceneValue.nodes) ?? {},
|
|
968
|
+
materials: JsonUtils.asObject(sceneValue.materials) ?? {},
|
|
969
|
+
renderMaterials: JsonUtils.asObject(sceneValue.renderMaterials) ?? {},
|
|
970
|
+
namedTextures: JsonUtils.asObject(sceneValue.namedTextures) ?? {},
|
|
971
|
+
patternSymbols: JsonUtils.asObject(sceneValue.patternSymbols) ?? {},
|
|
972
|
+
rtcCenter: JsonUtils.asArray(sceneValue.rtcCenter),
|
|
973
|
+
};
|
|
974
|
+
if (!imdlDoc.meshes)
|
|
975
|
+
return TileReadStatus.InvalidTileData;
|
|
976
|
+
const binaryData = new Uint8Array(stream.arrayBuffer, gltfHeader.binaryPosition);
|
|
977
|
+
const featureTable = {
|
|
978
|
+
startPos: ftStartPos,
|
|
979
|
+
multiModel: 0 !== (imdlHeader.flags & ImdlFlags.MultiModelFeatureTable),
|
|
980
|
+
};
|
|
981
|
+
const parser = new ImdlParser(imdlDoc, binaryData, options, featureTable);
|
|
982
|
+
return parser.parse();
|
|
983
|
+
}
|
|
984
|
+
catch (_) {
|
|
985
|
+
return TileReadStatus.InvalidTileData;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
//# sourceMappingURL=ImdlParser.js.map
|