All files / engine/Source/Scene I3dmParser.js

100% Statements 49/49
100% Branches 18/18
100% Functions 1/1
100% Lines 49/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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