UNPKG

loaders.gl

Version:

Framework-independent loaders for 3D graphics formats

217 lines (175 loc) 8.43 kB
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } /* eslint-disable camelcase, max-statements */ import unpackGLBBuffers from './unpack-glb-buffers'; import unpackBinaryJson from './unpack-binary-json'; import { padTo4Bytes } from '../common/loader-utils/array-utils'; import TextDecoder from '../common/loader-utils/text-decoder'; import assert from '../common/loader-utils/assert'; // glTF CONSTANTS var MAGIC_glTF = 0x676c5446; // glTF in Big-Endian ASCII var GLB_FILE_HEADER_SIZE = 12; var GLB_CHUNK_HEADER_SIZE = 8; var GLB_CHUNK_TYPE_JSON = 0x4E4F534A; var GLB_CHUNK_TYPE_BIN = 0x004E4942; var LE = true; // Binary GLTF is little endian. var BE = false; // Magic needs to be written as BE // glTF ACCESSOR CONSTANTS /* const TYPE_COMPONENTS = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 }; const COMPONENT_TYPE_BYTE_SIZE = { 5120: 1, 5121: 1, 5122: 2, 5123: 2, 5125: 4, 5126: 4 }; const COMPONENT_TYPE_ARRAY = { 5120: Int8Array, 5121: Uint8Array, 5122: Int16Array, 5123: Uint16Array, 5125: Uint32Array, 5126: Float32Array }; */ function getMagicString(dataView) { return "".concat(String.fromCharCode(dataView.getUint8(0))).concat(String.fromCharCode(dataView.getUint8(1))).concat(String.fromCharCode(dataView.getUint8(2))).concat(String.fromCharCode(dataView.getUint8(3))); } // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#glb-file-format-specification var GLBParser = /*#__PURE__*/ function () { function GLBParser(glbArrayBuffer) { _classCallCheck(this, GLBParser); this.glbArrayBuffer = glbArrayBuffer; } // Only returns application JSON _createClass(GLBParser, [{ key: "parse", value: function parse() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var _this$_parseBinary = this._parseBinary(this.glbArrayBuffer, options), json = _this$_parseBinary.json, binaryByteOffset = _this$_parseBinary.binaryByteOffset; var unpackedBuffers = unpackGLBBuffers(this.glbArrayBuffer, json, binaryByteOffset); var unpackedJson = unpackBinaryJson(json, unpackedBuffers); return this._getApplicationJSON(unpackedJson, options); } // Returns both application JSON and glTF JSON, separated }, { key: "parseWithMetadata", value: function parseWithMetadata() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var _this$_parseBinary2 = this._parseBinary(this.glbArrayBuffer, options), json = _this$_parseBinary2.json, binaryByteOffset = _this$_parseBinary2.binaryByteOffset; var unpackedBuffers = unpackGLBBuffers(this.glbArrayBuffer, json, binaryByteOffset); var unpackedJson = unpackBinaryJson(json, unpackedBuffers); return unpackedJson; } // PRIVATE // Get JSON from json key }, { key: "_getApplicationJSON", value: function _getApplicationJSON(json, options) { var jsonKey = options.jsonKey || 'json'; // Create glTF metadata object, with deleted application json key var glTF = Object.assign({}, json); delete glTF[jsonKey]; return { json: json[jsonKey], glTF: glTF }; } }, { key: "_parseBinary", value: function _parseBinary() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var _options$magic = options.magic, magic = _options$magic === void 0 ? MAGIC_glTF : _options$magic; // GLB Header var dataView = new DataView(this.glbArrayBuffer); var magic1 = dataView.getUint32(0, BE); // Magic number (the ASCII string 'glTF'). var version = dataView.getUint32(4, LE); // Version 2 of binary glTF container format var fileLength = dataView.getUint32(8, LE); // Total byte length of generated file var valid = magic1 === MAGIC_glTF || magic1 === magic; if (!valid) { console.warn("Invalid GLB magic string ".concat(getMagicString(dataView))); // eslint-disable-line } assert(version === 2, "Invalid GLB version ".concat(version, ". Only .glb v2 supported")); assert(fileLength > 20); // Write the JSON chunk var jsonChunkLength = dataView.getUint32(12, LE); // Byte length of json chunk var jsonChunkFormat = dataView.getUint32(16, LE); // Chunk format as uint32 valid = jsonChunkFormat === GLB_CHUNK_TYPE_JSON || jsonChunkFormat === 0; // Back compat assert(valid, "JSON chunk format ".concat(jsonChunkFormat)); // Create a "view" of the binary encoded JSON data var jsonChunkOffset = GLB_FILE_HEADER_SIZE + GLB_CHUNK_HEADER_SIZE; // First headers: 20 bytes var jsonChunk = new Uint8Array(this.glbArrayBuffer, jsonChunkOffset, jsonChunkLength); // Decode the JSON binary array into clear text var textDecoder = new TextDecoder('utf8'); var jsonText = textDecoder.decode(jsonChunk); // Parse the JSON text into a JavaScript data structure var json = JSON.parse(jsonText); // TODO - BIN chunk can be optional var binaryChunkStart = jsonChunkOffset + padTo4Bytes(jsonChunkLength); var binaryByteOffset = binaryChunkStart + GLB_CHUNK_HEADER_SIZE; var binChunkFormat = dataView.getUint32(binaryChunkStart + 4, LE); // Chunk format as uint32 valid = binChunkFormat === GLB_CHUNK_TYPE_BIN || binChunkFormat === 1; // Back compat assert(valid, "BIN chunk format ".concat(binChunkFormat)); return { arrayBuffer: this.glbArrayBuffer, binaryByteOffset: binaryByteOffset, json: json }; } /* unpackBinaryObjects() { const unpackedBinaryObjects = { images: [], accessors: [] }; const images = this.json.images || []; for (const glTFImage of images) { unpackedBinaryObjects.images.push(this.unpackImage(glTFImage)); } const accessors = this.json.accessors || []; for (const glTFAccessor of accessors) { unpackedBinaryObjects.accessors.push(this.unpackAccessor(glTFAccessor)); } return unpackedBinaryObjects; } unpackImage(glTFImage) { /* global window, Blob, Image * const arrayBufferView = this.unpackBufferView(glTFImage.bufferView); const mimeType = glTFImage.mimeType || 'image/jpeg'; const blob = new Blob([arrayBufferView], {type: mimeType}); const urlCreator = window.URL || window.webkitURL; const imageUrl = urlCreator.createObjectURL(blob); const img = new Image(); img.src = imageUrl; return img; } unpackAccessor(glTFAccessor) { // Decode the glTF accessor format const ArrayType = COMPONENT_TYPE_ARRAY[glTFAccessor.componentType]; const components = TYPE_COMPONENTS[glTFAccessor.type]; const bytesPerComponent = COMPONENT_TYPE_BYTE_SIZE[glTFAccessor.componentType]; const length = glTFAccessor.count * components; const byteLength = glTFAccessor.count * components * bytesPerComponent; // Get the boundaries of the binary sub-chunk for this bufferView const glTFBufferView = this.json.bufferViews[glTFAccessor.bufferView]; assert(byteLength >= 0 && byteLength <= glTFBufferView.byteLength); const byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset; return new ArrayType(this.arrayBuffer, byteOffset, length); } // Create a new typed array as a view into the binary chunk unpackBufferView(glTFBufferView) { const byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset; return new Uint8Array(byteOffset, glTFBufferView.byteLength); } */ }]); return GLBParser; }(); export { GLBParser as default }; //# sourceMappingURL=glb-parser.js.map