/* eslint-disable camelcase, max-statements */ import { copyPaddedStringToDataView, copyPaddedArrayBufferToDataView } from '@loaders.gl/loader-utils'; // import type {GLB} from '../types/glb-types'; const MAGIC_glTF = 0x46546c67; // glTF in ASCII const MAGIC_JSON = 0x4e4f534a; // JSON in ASCII const MAGIC_BIN = 0x004e4942; // BIN\0 in ASCII const LE = true; // Binary GLTF is little endian. /** * Encode the full GLB buffer with header etc * * @param glb * @param dataView - if `null`, does not encode but just calculates length * @param byteOffset * @param options * @returns * * @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#glb-file-format-specification * @todo type GLB argument */ export function encodeGLBSync(glb, dataView, byteOffset = 0, options = {}) { const { magic = MAGIC_glTF, version = 2, json = {}, binary } = glb; const byteOffsetStart = byteOffset; // Write GLB Header if (dataView) { dataView.setUint32(byteOffset + 0, magic, LE); // Magic number (the ASCII string 'glTF'). dataView.setUint32(byteOffset + 4, version, LE); // Version 2 of binary glTF container format uint32 dataView.setUint32(byteOffset + 8, 0, LE); // Total byte length of generated file (uint32), will be set last } const byteOffsetFileLength = byteOffset + 8; byteOffset += 12; // GLB_FILE_HEADER_SIZE // Write the JSON chunk header const byteOffsetJsonHeader = byteOffset; if (dataView) { dataView.setUint32(byteOffset + 0, 0, LE); // Byte length of json chunk (will be written later) dataView.setUint32(byteOffset + 4, MAGIC_JSON, LE); // Chunk type } byteOffset += 8; // GLB_CHUNK_HEADER_SIZE // Write the JSON chunk const jsonString = JSON.stringify(json); byteOffset = copyPaddedStringToDataView(dataView, byteOffset, jsonString, 4); // Now we know the JSON chunk length so we can write it. if (dataView) { const jsonByteLength = byteOffset - byteOffsetJsonHeader - 8; // GLB_CHUNK_HEADER_SIZE dataView.setUint32(byteOffsetJsonHeader + 0, jsonByteLength, LE); // Byte length of json chunk (uint32) } // Write the BIN chunk if present. The BIN chunk is optional. if (binary) { const byteOffsetBinHeader = byteOffset; // Write the BIN chunk header if (dataView) { dataView.setUint32(byteOffset + 0, 0, LE); // Byte length BIN (uint32) dataView.setUint32(byteOffset + 4, MAGIC_BIN, LE); // Chunk type } byteOffset += 8; // GLB_CHUNK_HEADER_SIZE byteOffset = copyPaddedArrayBufferToDataView(dataView, byteOffset, binary, 4); // Now we know the BIN chunk length so we can write it. if (dataView) { const binByteLength = byteOffset - byteOffsetBinHeader - 8; // GLB_CHUNK_HEADER_SIZE dataView.setUint32(byteOffsetBinHeader + 0, binByteLength, LE); // Byte length BIN (uint32) } } // Now we know the glb file length so we can write it. if (dataView) { const fileByteLength = byteOffset - byteOffsetStart; dataView.setUint32(byteOffsetFileLength, fileByteLength, LE); // Total byte length of generated file (uint32) } return byteOffset; }