@kitware/vtk.js
Version:
Visualization Toolkit for the Web
84 lines (78 loc) • 2.79 kB
JavaScript
import BinaryHelper from '../../Core/BinaryHelper.js';
import { BINARY_HEADER_LENGTH, BINARY_HEADER_MAGIC, BINARY_CHUNK_TYPES, BINARY_CHUNK_HEADER_INTS, BINARY_HEADER_INTS } from './Constants.js';
function getChunkInfo(headerStart, data) {
// Cache array view
const header = new Uint32Array(data, headerStart, BINARY_CHUNK_HEADER_INTS);
const chunkStart = headerStart + BINARY_CHUNK_HEADER_INTS * 4;
return {
start: chunkStart,
length: header[0],
type: header[1]
};
}
function getAllChunkInfos(data) {
// Pre-calculate array size
const maxChunks = Math.floor((data.byteLength - BINARY_HEADER_LENGTH) / 8);
const infos = new Array(maxChunks);
let chunkStart = BINARY_HEADER_INTS * 4;
let chunkCount = 0;
while (chunkStart < data.byteLength) {
const chunkInfo = getChunkInfo(chunkStart, data);
infos[chunkCount++] = chunkInfo;
chunkStart += chunkInfo.length + BINARY_CHUNK_HEADER_INTS * 4;
}
// Trim array to actual size
return infos.slice(0, chunkCount);
}
function getJsonFromChunk(chunkInfo, data) {
const jsonStart = (BINARY_HEADER_INTS + BINARY_CHUNK_HEADER_INTS) * 4;
const jsonView = new Uint8Array(data, jsonStart, chunkInfo.length);
const decoder = new TextDecoder('utf-8');
const jsonString = decoder.decode(jsonView);
return JSON.parse(jsonString);
}
function getBufferFromChunk(chunkInfo, data) {
return data.slice(chunkInfo.start, chunkInfo.start + chunkInfo.length);
}
function parseGLB(data) {
if (data.byteLength < BINARY_HEADER_LENGTH) {
throw new Error('Invalid GLB: File too small');
}
// Cache DataView
const headerView = new DataView(data, 0, BINARY_HEADER_LENGTH);
const magic = new Uint8Array(data, 0, 4);
const header = {
magic: BinaryHelper.arrayBufferToString(magic),
version: headerView.getUint32(4, true),
length: headerView.getUint32(8, true)
};
if (header.magic !== BINARY_HEADER_MAGIC) {
throw new Error('Unsupported glTF-Binary header.');
}
if (header.version < 2.0) {
throw new Error('Unsupported legacy binary file detected.');
}
if (header.length > data.byteLength) {
throw new Error('Invalid GLB: Declared length exceeds file size');
}
const chunkInfos = getAllChunkInfos(data);
let json = null;
const buffers = [];
// Process chunks sequentially
for (let i = 0; i < chunkInfos.length; i++) {
const chunkInfo = chunkInfos[i];
if (chunkInfo.type === BINARY_CHUNK_TYPES.JSON && !json) {
json = getJsonFromChunk(chunkInfo, data);
} else if (chunkInfo.type === BINARY_CHUNK_TYPES.BIN) {
buffers.push(getBufferFromChunk(chunkInfo, data));
}
}
if (!json) {
throw new Error('glTF-Binary: JSON content not found.');
}
return {
json,
buffers
};
}
export { parseGLB as default };