I3dmParser.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import Check from "../Core/Check.js";
  2. import defaultValue from "../Core/defaultValue.js";
  3. import deprecationWarning from "../Core/deprecationWarning.js";
  4. import getJsonFromTypedArray from "../Core/getJsonFromTypedArray.js";
  5. import RuntimeError from "../Core/RuntimeError.js";
  6. /**
  7. * Handles parsing of an Instanced 3D Model.
  8. *
  9. * @namespace I3dmParser
  10. * @private
  11. */
  12. const I3dmParser = {};
  13. I3dmParser._deprecationWarning = deprecationWarning;
  14. const sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
  15. /**
  16. * Parses the contents of a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/Instanced3DModel|Instanced 3D Model}.
  17. *
  18. * @private
  19. *
  20. * @param {ArrayBuffer} arrayBuffer The array buffer containing the I3DM.
  21. * @param {Number} [byteOffset=0] The byte offset of the beginning of the I3DM in the array buffer.
  22. * @returns {Object} Returns an object with the glTF format, feature table (binary and json), batch table (binary and json) and glTF parts of the I3DM.
  23. */
  24. I3dmParser.parse = function (arrayBuffer, byteOffset) {
  25. //>>includeStart('debug', pragmas.debug);
  26. Check.defined("arrayBuffer", arrayBuffer);
  27. //>>includeEnd('debug');
  28. const byteStart = defaultValue(byteOffset, 0);
  29. byteOffset = byteStart;
  30. const uint8Array = new Uint8Array(arrayBuffer);
  31. const view = new DataView(arrayBuffer);
  32. byteOffset += sizeOfUint32; // Skip magic
  33. const version = view.getUint32(byteOffset, true);
  34. if (version !== 1) {
  35. throw new RuntimeError(
  36. `Only Instanced 3D Model version 1 is supported. Version ${version} is not.`
  37. );
  38. }
  39. byteOffset += sizeOfUint32;
  40. const byteLength = view.getUint32(byteOffset, true);
  41. byteOffset += sizeOfUint32;
  42. const featureTableJsonByteLength = view.getUint32(byteOffset, true);
  43. if (featureTableJsonByteLength === 0) {
  44. throw new RuntimeError(
  45. "featureTableJsonByteLength is zero, the feature table must be defined."
  46. );
  47. }
  48. byteOffset += sizeOfUint32;
  49. const featureTableBinaryByteLength = view.getUint32(byteOffset, true);
  50. byteOffset += sizeOfUint32;
  51. const batchTableJsonByteLength = view.getUint32(byteOffset, true);
  52. byteOffset += sizeOfUint32;
  53. const batchTableBinaryByteLength = view.getUint32(byteOffset, true);
  54. byteOffset += sizeOfUint32;
  55. const gltfFormat = view.getUint32(byteOffset, true);
  56. if (gltfFormat !== 1 && gltfFormat !== 0) {
  57. throw new RuntimeError(
  58. `Only glTF format 0 (uri) or 1 (embedded) are supported. Format ${gltfFormat} is not.`
  59. );
  60. }
  61. byteOffset += sizeOfUint32;
  62. const featureTableJson = getJsonFromTypedArray(
  63. uint8Array,
  64. byteOffset,
  65. featureTableJsonByteLength
  66. );
  67. byteOffset += featureTableJsonByteLength;
  68. const featureTableBinary = new Uint8Array(
  69. arrayBuffer,
  70. byteOffset,
  71. featureTableBinaryByteLength
  72. );
  73. byteOffset += featureTableBinaryByteLength;
  74. let batchTableJson;
  75. let batchTableBinary;
  76. if (batchTableJsonByteLength > 0) {
  77. batchTableJson = getJsonFromTypedArray(
  78. uint8Array,
  79. byteOffset,
  80. batchTableJsonByteLength
  81. );
  82. byteOffset += batchTableJsonByteLength;
  83. if (batchTableBinaryByteLength > 0) {
  84. // Has a batch table binary
  85. batchTableBinary = new Uint8Array(
  86. arrayBuffer,
  87. byteOffset,
  88. batchTableBinaryByteLength
  89. );
  90. // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed
  91. batchTableBinary = new Uint8Array(batchTableBinary);
  92. byteOffset += batchTableBinaryByteLength;
  93. }
  94. }
  95. const gltfByteLength = byteStart + byteLength - byteOffset;
  96. if (gltfByteLength === 0) {
  97. throw new RuntimeError("glTF byte length must be greater than 0.");
  98. }
  99. let gltfView;
  100. if (byteOffset % 4 === 0) {
  101. gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength);
  102. } else {
  103. // Create a copy of the glb so that it is 4-byte aligned
  104. I3dmParser._deprecationWarning(
  105. "i3dm-glb-unaligned",
  106. "The embedded glb is not aligned to a 4-byte boundary."
  107. );
  108. gltfView = new Uint8Array(
  109. uint8Array.subarray(byteOffset, byteOffset + gltfByteLength)
  110. );
  111. }
  112. return {
  113. gltfFormat: gltfFormat,
  114. featureTableJson: featureTableJson,
  115. featureTableBinary: featureTableBinary,
  116. batchTableJson: batchTableJson,
  117. batchTableBinary: batchTableBinary,
  118. gltf: gltfView,
  119. };
  120. };
  121. export default I3dmParser;