All files / engine/Source/Scene/GltfPipeline parseGlb.js

94.73% Statements 54/57
76.66% Branches 23/30
100% Functions 4/4
94.64% Lines 53/56

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              1x                           1213x 1213x       1213x 1213x 1213x       1213x 2x     1211x       3635x 3635x 3635x 10909x         3635x       2x 2x 2x     2x       2x 2x   2x 2x 2x   2x   2x 2x   2x 2x 1x 1x       2x 2x       1211x 1211x     1211x 2422x 2422x 2422x 2422x 2422x 2422x   2422x 1211x 1211x 1211x     1211x 1211x     1211x 1211x 1211x 1211x 1211x     1211x        
import addPipelineExtras from "./addPipelineExtras.js";
import removeExtensionsUsed from "./removeExtensionsUsed.js";
import defined from "../../Core/defined.js";
import getMagic from "../../Core/getMagic.js";
import getStringFromTypedArray from "../../Core/getStringFromTypedArray.js";
import RuntimeError from "../../Core/RuntimeError.js";
 
const sizeOfUint32 = 4;
 
/**
 * Convert a binary glTF to glTF.
 *
 * The returned glTF has pipeline extras included. The embedded binary data is stored in gltf.buffers[0].extras._pipeline.source.
 *
 * @param {Buffer} glb The glb data to parse.
 * @returns {object} A javascript object containing a glTF asset with pipeline extras included.
 *
 * @private
 */
function parseGlb(glb) {
  // Check that the magic string is present
  const magic = getMagic(glb);
  Iif (magic !== "glTF") {
    throw new RuntimeError("File is not valid binary glTF");
  }
 
  const header = readHeader(glb, 0, 5);
  const version = header[1];
  Iif (version !== 1 && version !== 2) {
    throw new RuntimeError("Binary glTF version is not 1 or 2");
  }
 
  if (version === 1) {
    return parseGlbVersion1(glb, header);
  }
 
  return parseGlbVersion2(glb, header);
}
 
function readHeader(glb, byteOffset, count) {
  const dataView = new DataView(glb.buffer);
  const header = new Array(count);
  for (let i = 0; i < count; ++i) {
    header[i] = dataView.getUint32(
      glb.byteOffset + byteOffset + i * sizeOfUint32,
      true,
    );
  }
  return header;
}
 
function parseGlbVersion1(glb, header) {
  const length = header[2];
  const contentLength = header[3];
  const contentFormat = header[4];
 
  // Check that the content format is 0, indicating that it is JSON
  Iif (contentFormat !== 0) {
    throw new RuntimeError("Binary glTF scene format is not JSON");
  }
 
  const jsonStart = 20;
  const binaryStart = jsonStart + contentLength;
 
  const contentString = getStringFromTypedArray(glb, jsonStart, contentLength);
  const gltf = JSON.parse(contentString);
  addPipelineExtras(gltf);
 
  const binaryBuffer = glb.subarray(binaryStart, length);
 
  const buffers = gltf.buffers;
  Eif (defined(buffers) && Object.keys(buffers).length > 0) {
    // In some older models, the binary glTF buffer is named KHR_binary_glTF
    const binaryGltfBuffer = buffers.binary_glTF ?? buffers.KHR_binary_glTF;
    if (defined(binaryGltfBuffer)) {
      binaryGltfBuffer.extras._pipeline.source = binaryBuffer;
      delete binaryGltfBuffer.uri;
    }
  }
  // Remove the KHR_binary_glTF extension
  removeExtensionsUsed(gltf, "KHR_binary_glTF");
  return gltf;
}
 
function parseGlbVersion2(glb, header) {
  const length = header[2];
  let byteOffset = 12;
  let gltf;
  let binaryBuffer;
  while (byteOffset < length) {
    const chunkHeader = readHeader(glb, byteOffset, 2);
    const chunkLength = chunkHeader[0];
    const chunkType = chunkHeader[1];
    byteOffset += 8;
    const chunkBuffer = glb.subarray(byteOffset, byteOffset + chunkLength);
    byteOffset += chunkLength;
    // Load JSON chunk
    if (chunkType === 0x4e4f534a) {
      const jsonString = getStringFromTypedArray(chunkBuffer);
      gltf = JSON.parse(jsonString);
      addPipelineExtras(gltf);
    }
    // Load Binary chunk
    else Eif (chunkType === 0x004e4942) {
      binaryBuffer = chunkBuffer;
    }
  }
  Eif (defined(gltf) && defined(binaryBuffer)) {
    const buffers = gltf.buffers;
    Eif (defined(buffers) && buffers.length > 0) {
      const buffer = buffers[0];
      buffer.extras._pipeline.source = binaryBuffer;
    }
  }
  return gltf;
}
 
export default parseGlb;