@itwin/core-frontend 3.0.0-dev.170 → 3.0.0-dev.175

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.
@@ -5,7 +5,7 @@
5
5
  /** @packageDocumentation
6
6
  * @module Tiles
7
7
  */
8
- import { assert, ByteStream, JsonUtils, utf8ToString } from "@itwin/core-bentley";
8
+ import { assert, ByteStream, compareBooleans, compareNumbers, compareStrings, Dictionary, JsonUtils, utf8ToString } from "@itwin/core-bentley";
9
9
  import { Angle, Matrix3d, Point2d, Point3d, Point4d, Range2d, Range3d, Transform, Vector3d } from "@itwin/core-geometry";
10
10
  import { BatchType, ColorDef, Feature, FeatureTable, FillFlags, GlbHeader, ImageSource, LinePixels, MeshEdge, MeshEdges, MeshPolyline, OctEncodedNormal, PackedFeatureTable, QParams2d, QParams3d, QPoint2dList, QPoint3dList, Quantization, RenderTexture, TextureMapping, TileFormat, TileReadStatus, } from "@itwin/core-common";
11
11
  import { getImageSourceFormatForMimeType, imageElementFromImageSource, tryImageElementFromUrl } from "../ImageUtil";
@@ -99,6 +99,12 @@ function getNodeMeshIds(node) {
99
99
  return [node.mesh];
100
100
  return [];
101
101
  }
102
+ /** GL states that can be enabled by a [[GltfTechnique]]. Only those queried by this implementation are enumerated. */
103
+ var GltfTechniqueState;
104
+ (function (GltfTechniqueState) {
105
+ /** Enables alpha blending. */
106
+ GltfTechniqueState[GltfTechniqueState["Blend"] = 3042] = "Blend";
107
+ })(GltfTechniqueState || (GltfTechniqueState = {}));
102
108
  function isGltf1Material(material) {
103
109
  const mat1 = material;
104
110
  return undefined !== mat1.technique || undefined !== mat1.values;
@@ -283,21 +289,23 @@ const emptyDict = {};
283
289
  function colorFromJson(values) {
284
290
  return ColorDef.from(values[0] * 255, values[1] * 255, values[2] * 255, (1.0 - values[3]) * 255);
285
291
  }
286
- function colorFromMaterial(material) {
292
+ function colorFromMaterial(material, isTransparent) {
287
293
  var _a, _b, _c, _d, _e;
288
- if (material) {
289
- if (isGltf1Material(material)) {
290
- if (((_a = material.values) === null || _a === void 0 ? void 0 : _a.color) && Array.isArray(material.values.color))
291
- return colorFromJson(material.values.color);
292
- }
293
- else if ((_d = (_c = (_b = material.extensions) === null || _b === void 0 ? void 0 : _b.KHR_techniques_webgl) === null || _c === void 0 ? void 0 : _c.values) === null || _d === void 0 ? void 0 : _d.u_color) {
294
- return colorFromJson(material.extensions.KHR_techniques_webgl.values.u_color);
295
- }
296
- else if ((_e = material.pbrMetallicRoughness) === null || _e === void 0 ? void 0 : _e.baseColorFactor) {
297
- return colorFromJson(material.pbrMetallicRoughness.baseColorFactor);
298
- }
294
+ let color = ColorDef.white;
295
+ if (isGltf1Material(material)) {
296
+ if (((_a = material.values) === null || _a === void 0 ? void 0 : _a.color) && Array.isArray(material.values.color))
297
+ color = colorFromJson(material.values.color);
298
+ }
299
+ else if ((_d = (_c = (_b = material.extensions) === null || _b === void 0 ? void 0 : _b.KHR_techniques_webgl) === null || _c === void 0 ? void 0 : _c.values) === null || _d === void 0 ? void 0 : _d.u_color) {
300
+ color = colorFromJson(material.extensions.KHR_techniques_webgl.values.u_color);
301
+ }
302
+ else if ((_e = material.pbrMetallicRoughness) === null || _e === void 0 ? void 0 : _e.baseColorFactor) {
303
+ color = colorFromJson(material.pbrMetallicRoughness.baseColorFactor);
299
304
  }
300
- return ColorDef.white;
305
+ // SPEC: Opaque materials ignore any alpha channel.
306
+ if (!isTransparent)
307
+ color = color.withTransparency(0);
308
+ return color;
301
309
  }
302
310
  class TransformStack {
303
311
  constructor() {
@@ -351,12 +359,25 @@ function* traverseNodes(ids, nodes, traversed) {
351
359
  yield child;
352
360
  }
353
361
  }
362
+ function compareTextureKeys(lhs, rhs) {
363
+ const cmp = compareBooleans(lhs.isTransparent, rhs.isTransparent);
364
+ if (0 !== cmp)
365
+ return cmp;
366
+ assert(typeof lhs.id === typeof rhs.id);
367
+ if ("string" === typeof lhs.id) {
368
+ assert("string" === typeof rhs.id);
369
+ return compareStrings(lhs.id, rhs.id);
370
+ }
371
+ assert("number" === typeof lhs.id && "number" === typeof rhs.id);
372
+ return compareNumbers(lhs.id, rhs.id);
373
+ }
354
374
  /** Deserializes [glTF](https://www.khronos.org/gltf/).
355
375
  * @internal
356
376
  */
357
377
  export class GltfReader {
358
378
  constructor(args) {
359
379
  var _a, _b, _c, _d, _e, _f, _g;
380
+ this._resolvedTextures = new Dictionary((lhs, rhs) => compareTextureKeys(lhs, rhs));
360
381
  this._glTF = args.props.glTF;
361
382
  this._version = args.props.version;
362
383
  this._yAxisUp = args.props.yAxisUp;
@@ -654,22 +675,41 @@ export class GltfReader {
654
675
  }
655
676
  }
656
677
  }
657
- const id = extractId((_g = material.emissiveTexture) === null || _g === void 0 ? void 0 : _g.index);
658
- return id !== null && id !== void 0 ? id : extractId((_j = (_h = material.pbrMetallicRoughness) === null || _h === void 0 ? void 0 : _h.baseColorTexture) === null || _j === void 0 ? void 0 : _j.index);
678
+ const id = extractId((_h = (_g = material.pbrMetallicRoughness) === null || _g === void 0 ? void 0 : _g.baseColorTexture) === null || _h === void 0 ? void 0 : _h.index);
679
+ return id !== null && id !== void 0 ? id : extractId((_j = material.emissiveTexture) === null || _j === void 0 ? void 0 : _j.index);
680
+ }
681
+ isMaterialTransparent(material) {
682
+ var _a, _b;
683
+ if (isGltf1Material(material)) {
684
+ if (this._glTF.techniques && undefined !== material.technique) {
685
+ const technique = this._glTF.techniques[material.technique];
686
+ if ((_b = (_a = technique === null || technique === void 0 ? void 0 : technique.states) === null || _a === void 0 ? void 0 : _a.enable) === null || _b === void 0 ? void 0 : _b.some((state) => state === GltfTechniqueState.Blend))
687
+ return true;
688
+ }
689
+ return false;
690
+ }
691
+ else {
692
+ // Default: OPAQUE.
693
+ // ###TODO support MASK. For now treat as opaque.
694
+ return "BLEND" === material.alphaMode;
695
+ }
659
696
  }
660
- createDisplayParams(materialJson, hasBakedLighting) {
661
- const textureId = this.extractTextureId(materialJson);
662
- const textureMapping = undefined !== textureId ? this.findTextureMapping(textureId) : undefined;
663
- const color = colorFromMaterial(materialJson);
697
+ createDisplayParams(material, hasBakedLighting) {
698
+ const isTransparent = this.isMaterialTransparent(material);
699
+ const textureId = this.extractTextureId(material);
700
+ const textureMapping = undefined !== textureId ? this.findTextureMapping(textureId, isTransparent) : undefined;
701
+ const color = colorFromMaterial(material, isTransparent);
664
702
  return new DisplayParams(DisplayParams.Type.Mesh, color, color, 1, LinePixels.Solid, FillFlags.Always, undefined, undefined, hasBakedLighting, textureMapping);
665
703
  }
666
704
  readMeshPrimitive(primitive, featureTable, pseudoRtcBias) {
667
- var _a, _b, _c, _d, _e, _f;
705
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
668
706
  const materialName = JsonUtils.asString(primitive.material);
669
- const hasBakedLighting = undefined === primitive.attributes.NORMAL;
670
707
  const material = 0 < materialName.length ? this._materials[materialName] : undefined;
708
+ if (!material)
709
+ return undefined;
710
+ const hasBakedLighting = undefined === primitive.attributes.NORMAL || undefined !== ((_a = material.extensions) === null || _a === void 0 ? void 0 : _a.KHR_materials_unlit);
671
711
  const displayParams = material ? this.createDisplayParams(material, hasBakedLighting) : undefined;
672
- if (undefined === displayParams)
712
+ if (!displayParams)
673
713
  return undefined;
674
714
  let primitiveType = -1;
675
715
  const meshMode = JsonUtils.asInt(primitive.mode, GltfMeshMode.Triangles);
@@ -707,9 +747,9 @@ export class GltfReader {
707
747
  if (undefined !== colorIndices && material) {
708
748
  let texStep;
709
749
  if (isGltf1Material(material))
710
- texStep = (_a = material.values) === null || _a === void 0 ? void 0 : _a.texStep;
750
+ texStep = (_b = material.values) === null || _b === void 0 ? void 0 : _b.texStep;
711
751
  else
712
- texStep = (_d = (_c = (_b = material.extensions) === null || _b === void 0 ? void 0 : _b.KHR_techniques_webgl) === null || _c === void 0 ? void 0 : _c.values) === null || _d === void 0 ? void 0 : _d.u_texStep;
752
+ texStep = (_e = (_d = (_c = material.extensions) === null || _c === void 0 ? void 0 : _c.KHR_techniques_webgl) === null || _d === void 0 ? void 0 : _d.values) === null || _e === void 0 ? void 0 : _e.u_texStep;
713
753
  if (texStep) {
714
754
  const uvParams = [];
715
755
  for (let i = 0; i < colorIndices.count; i++)
@@ -719,7 +759,7 @@ export class GltfReader {
719
759
  mesh.uvQParams = paramList.params;
720
760
  }
721
761
  }
722
- if ((_e = primitive.extensions) === null || _e === void 0 ? void 0 : _e.KHR_draco_mesh_compression) {
762
+ if ((_f = primitive.extensions) === null || _f === void 0 ? void 0 : _f.KHR_draco_mesh_compression) {
723
763
  return undefined; // Defer Draco decompression until web workers implementation.
724
764
  /*
725
765
  const dracoExtension = primitive.extensions.KHR_draco_mesh_compression;
@@ -738,8 +778,12 @@ export class GltfReader {
738
778
  return undefined;
739
779
  if (!displayParams.ignoreLighting && !this.readNormals(mesh, primitive.attributes, "NORMAL"))
740
780
  return undefined;
741
- if (!mesh.uvs)
742
- this.readUVParams(mesh, primitive.attributes, "TEXCOORD_0");
781
+ if (!mesh.uvs) {
782
+ let texCoordIndex = 0;
783
+ if (!isGltf1Material(material) && undefined !== ((_h = (_g = material.pbrMetallicRoughness) === null || _g === void 0 ? void 0 : _g.baseColorTexture) === null || _h === void 0 ? void 0 : _h.texCoord))
784
+ texCoordIndex = JsonUtils.asInt(material.pbrMetallicRoughness.baseColorTexture.texCoord);
785
+ this.readUVParams(mesh, primitive.attributes, `TEXCOORD_${texCoordIndex}`);
786
+ }
743
787
  if (this._deduplicateVertices && !this.deduplicateVertices(mesh))
744
788
  return undefined;
745
789
  break;
@@ -757,7 +801,7 @@ export class GltfReader {
757
801
  }
758
802
  if (displayParams.textureMapping && !mesh.uvs)
759
803
  return undefined;
760
- if ((_f = primitive.extensions) === null || _f === void 0 ? void 0 : _f.CESIUM_primitive_outline) {
804
+ if ((_j = primitive.extensions) === null || _j === void 0 ? void 0 : _j.CESIUM_primitive_outline) {
761
805
  const data = this.readBufferData32(primitive.extensions.CESIUM_primitive_outline, "indices");
762
806
  if (data !== undefined) {
763
807
  assert(0 === data.count % 2);
@@ -776,6 +820,8 @@ export class GltfReader {
776
820
  const indices = mesh.indices;
777
821
  if (indices instanceof Uint16Array && numPoints > 0xffff)
778
822
  mesh.indices = new Uint32Array(numPoints);
823
+ else if (indices instanceof Uint8Array && numPoints > 0xff)
824
+ mesh.indices = new Uint32Array(numPoints);
779
825
  const points = new Uint16Array(3 * numPoints);
780
826
  const normals = mesh.normals ? new Uint16Array(numPoints) : undefined;
781
827
  const uvs = mesh.uvs ? new Uint16Array(2 * numPoints) : undefined;
@@ -876,10 +922,22 @@ export class GltfReader {
876
922
  readBatchTable(_mesh, _json) {
877
923
  }
878
924
  readMeshIndices(mesh, json) {
879
- const data = this.readBufferData16(json, "indices") || this.readBufferData32(json, "indices");
880
- if (undefined === data || (!(data.buffer instanceof (Uint16Array)) && !(data.buffer instanceof (Uint32Array))))
925
+ var _a;
926
+ if (undefined !== json.indices) {
927
+ const data = this.readBufferData16(json, "indices") || this.readBufferData32(json, "indices");
928
+ if (data && (data.buffer instanceof Uint8Array || data.buffer instanceof Uint16Array || data.buffer instanceof Uint32Array)) {
929
+ mesh.indices = data.buffer;
930
+ return true;
931
+ }
932
+ return false;
933
+ }
934
+ // Non-indexed geometry. Manufacture triangle indices from points.
935
+ const numPoints = (_a = mesh.points) === null || _a === void 0 ? void 0 : _a.length;
936
+ if (undefined === numPoints || 0 !== numPoints % 3)
881
937
  return false;
882
- mesh.indices = data.buffer;
938
+ mesh.indices = numPoints < 255 ? new Uint8Array(numPoints) : (numPoints < 0xffff ? new Uint16Array(numPoints) : new Uint32Array(numPoints));
939
+ for (let i = 0; i < numPoints; i++)
940
+ mesh.indices[i] = i;
883
941
  return true;
884
942
  }
885
943
  readNormals(mesh, json, accessorName) {
@@ -1017,9 +1075,6 @@ export class GltfReader {
1017
1075
  if (!image.resolvedImage)
1018
1076
  promises.push(this.resolveImage(image));
1019
1077
  await Promise.all(promises);
1020
- if (this._isCanceled)
1021
- return;
1022
- this.resolveTextures();
1023
1078
  }
1024
1079
  catch (_) {
1025
1080
  }
@@ -1077,64 +1132,33 @@ export class GltfReader {
1077
1132
  if (undefined !== url)
1078
1133
  image.resolvedImage = await tryImageElementFromUrl(url);
1079
1134
  }
1080
- resolveTextures() {
1081
- var _a, _b;
1082
- if (undefined === this._glTF.textures)
1083
- return;
1084
- // ###TODO this seems pretty hacky, and won't work for glTF 2.0 even if the KHR_techniques_webgl extension is used...
1085
- const transparentTextures = new Set();
1086
- if (this._glTF.techniques) {
1087
- for (const name of Object.keys(this._materials)) {
1088
- const material = this._materials[name];
1089
- if (material && isGltf1Material(material) && undefined !== material.technique && undefined !== ((_a = material.values) === null || _a === void 0 ? void 0 : _a.tex)) {
1090
- const technique = this._glTF.techniques[material.technique];
1091
- if ((_b = technique === null || technique === void 0 ? void 0 : technique.states) === null || _b === void 0 ? void 0 : _b.enable) {
1092
- for (const enable of technique.states.enable) {
1093
- if (3042 === enable) { // 3042 = BLEND
1094
- transparentTextures.add(material.values.tex.toString());
1095
- break;
1096
- }
1097
- }
1098
- }
1099
- }
1100
- }
1101
- }
1102
- for (const node of this.traverseScene()) {
1103
- for (const meshId of getNodeMeshIds(node)) {
1104
- const mesh = this._meshes[meshId];
1105
- if (!(mesh === null || mesh === void 0 ? void 0 : mesh.primitives))
1106
- continue;
1107
- for (const primitive of mesh.primitives) {
1108
- const material = undefined !== primitive.material ? this._materials[primitive.material] : undefined;
1109
- const textureId = material ? this.extractTextureId(material) : undefined;
1110
- if (undefined !== textureId)
1111
- this.resolveTexture(textureId, transparentTextures.has(textureId));
1112
- }
1113
- }
1114
- }
1115
- }
1116
1135
  resolveTexture(textureId, isTransparent) {
1117
1136
  var _a;
1118
1137
  const texture = this._textures[textureId];
1119
- if (!texture || texture.resolvedTexture || undefined === texture.source)
1120
- return;
1138
+ if (!texture || undefined === texture.source)
1139
+ return false;
1121
1140
  const image = (_a = this._images[texture.source]) === null || _a === void 0 ? void 0 : _a.resolvedImage;
1122
1141
  if (!image)
1123
- return;
1142
+ return false;
1124
1143
  const samplerId = texture.sampler;
1125
1144
  const sampler = undefined !== samplerId ? this._samplers[samplerId] : undefined;
1126
- const textureType = undefined !== (sampler === null || sampler === void 0 ? void 0 : sampler.wrapS) || undefined !== (sampler === null || sampler === void 0 ? void 0 : sampler.wrapT) ? RenderTexture.Type.TileSection : RenderTexture.Type.Normal;
1127
- texture.resolvedTexture = this._system.createTexture({
1145
+ // ###TODO: RenderTexture should support different wrapping behavior for U vs V, and support mirrored repeat.
1146
+ // For now, repeat unless either explicitly clamps.
1147
+ const textureType = GltfWrapMode.ClampToEdge === (sampler === null || sampler === void 0 ? void 0 : sampler.wrapS) || GltfWrapMode.ClampToEdge === (sampler === null || sampler === void 0 ? void 0 : sampler.wrapT) ? RenderTexture.Type.TileSection : RenderTexture.Type.Normal;
1148
+ const renderTexture = this._system.createTexture({
1128
1149
  type: textureType,
1129
1150
  image: {
1130
1151
  source: image,
1131
1152
  transparency: isTransparent ? TextureTransparency.Translucent : TextureTransparency.Opaque,
1132
1153
  },
1133
1154
  });
1155
+ return renderTexture !== null && renderTexture !== void 0 ? renderTexture : false;
1134
1156
  }
1135
- findTextureMapping(textureId) {
1136
- const texture = this._textures[textureId];
1137
- return (texture === null || texture === void 0 ? void 0 : texture.resolvedTexture) ? new TextureMapping(texture.resolvedTexture, new TextureMapping.Params()) : undefined;
1157
+ findTextureMapping(id, isTransparent) {
1158
+ let texture = this._resolvedTextures.get({ id, isTransparent });
1159
+ if (undefined === texture)
1160
+ this._resolvedTextures.set({ id, isTransparent }, texture = this.resolveTexture(id, isTransparent));
1161
+ return texture ? new TextureMapping(texture, new TextureMapping.Params()) : undefined;
1138
1162
  }
1139
1163
  }
1140
1164
  /** Produce a [[RenderGraphic]] from a [glTF](https://www.khronos.org/gltf/) asset suitable for use in [view decorations]($docs/learning/frontend/ViewDecorations).