Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@loaders.gl/gltf

Package Overview
Dependencies
Maintainers
5
Versions
343
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@loaders.gl/gltf - npm Package Compare versions

Comparing version 0.4.8 to 0.5.0

dist/scripts/glbdump.js

90

dist/es5/glb/glb-builder.js

@@ -55,4 +55,5 @@ "use strict";

this.sourceBuffers = [];
}
} // ACCESSORS
_createClass(GLBBuilder, [{

@@ -62,2 +63,17 @@ key: "getByteLength",

return this.byteLength;
} // Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
}, {
key: "isImage",
value: function isImage(imageData) {
return (0, _core.isImage)(imageData);
} // MODIFERS
// Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
}, {
key: "encodeAsGLB",
value: function encodeAsGLB() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._createGLBBuffer(options);
} // Add an extra application-defined key to the top-level data structure

@@ -73,23 +89,22 @@ // By default packs JSON by extracting binary data and replacing it with JSON pointers

return this;
} // Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
} // Add one untyped source buffer, create a matching glTF `bufferView`, and return its index
}, {
key: "encodeAsGLB",
value: function encodeAsGLB() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._createGlbBuffer(options);
} // Returns an arrayBuffer together with JSON etc data.
key: "addBufferView",
value: function addBufferView(buffer) {
var byteLength = buffer.byteLength || buffer.length; // Add a bufferView indicating start and length of this binary sub-chunk
}, {
key: "encodeAsGLBWithMetadata",
value: function encodeAsGLBWithMetadata() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength: byteLength
}); // We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
var arrayBuffer = this._createGlbBuffer(options);
this.byteLength += (0, _core.padTo4Bytes)(byteLength); // Add this buffer to the list of buffers to be written to the body.
return {
arrayBuffer: arrayBuffer,
json: this.json
};
this.sourceBuffers.push(buffer); // Return the index to the just created bufferView
return this.json.bufferViews.length - 1;
} // Add a binary buffer. Builds glTF "JSON metadata" and saves buffer reference

@@ -104,6 +119,4 @@ // Buffer will be copied into BIN chunk during "pack"

};
var bufferViewIndex = this.addBufferView(sourceBuffer); // Add an accessor pointing to the new buffer view
var bufferViewIndex = this._addBufferView(sourceBuffer); // Add an accessor pointing to the new buffer view
var glTFAccessor = {

@@ -117,8 +130,2 @@ bufferView: bufferViewIndex,

return this.json.accessors.length - 1;
} // Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
}, {
key: "isImage",
value: function isImage(imageData) {
return (0, _core.isImage)(imageData);
} // Adds a binary image. Builds glTF "JSON metadata" and saves buffer reference

@@ -130,4 +137,3 @@ // Buffer will be copied into BIN chunk during "pack"

value: function addImage(imageData) {
var bufferViewIndex = this._addBufferView(imageData);
var bufferViewIndex = this.addBufferView(imageData);
var glTFImage = {

@@ -152,3 +158,4 @@ bufferView: bufferViewIndex

return this.json.images.length - 1;
} // For testing
} // PRIVATE
// For testing

@@ -164,23 +171,2 @@ }, {

};
} // PRIVATE
// Add one source buffer, create a matchibng glTF `bufferView`, and return its index
}, {
key: "_addBufferView",
value: function _addBufferView(buffer) {
var byteLength = buffer.byteLength || buffer.length; // Add a bufferView indicating start and length of this binary sub-chunk
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength: byteLength
}); // We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
this.byteLength += (0, _core.padTo4Bytes)(byteLength); // Add this buffer to the list of buffers to be written to the body.
this.sourceBuffers.push(buffer); // Return the index to the just created bufferView
return this.json.bufferViews.length - 1;
} // Pack the binary chunk

@@ -231,4 +217,4 @@

}, {
key: "_createGlbBuffer",
value: function _createGlbBuffer() {
key: "_createGLBBuffer",
value: function _createGLBBuffer() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

@@ -235,0 +221,0 @@

@@ -55,12 +55,8 @@ "use strict";

function GLBParser(glbArrayBuffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
function GLBParser() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, GLBParser);
// Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder; // Input
this.glbArrayBuffer = glbArrayBuffer; // Result
// Result
this.binaryByteOffset = null;

@@ -74,6 +70,7 @@ this.packedJson = null;

key: "parse",
value: function parse() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
value: function parse(glbArrayBuffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Input
this.glbArrayBuffer = glbArrayBuffer; // Only parse once
// Only parse once
if (this.json === null && this.binaryByteOffset === null) {

@@ -108,2 +105,41 @@ this.result = this._parse(options);

return this.binaryByteOffset;
} // Unpacks a bufferview into a new Uint8Array that is a view into the binary chunk
}, {
key: "getBufferView",
value: function getBufferView(glTFBufferView) {
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new Uint8Array(byteOffset, glTFBufferView.byteLength);
} // Unpacks a glTF accessor into a new typed array that is a view into the binary chunk
}, {
key: "getBuffer",
value: function getBuffer(glTFAccessor) {
// Decode the glTF accessor format
var ArrayType = _gltfTypeUtils.ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
var components = _gltfTypeUtils.ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
var bytesPerComponent = _gltfTypeUtils.ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[glTFAccessor.componentType];
var length = glTFAccessor.count * components;
var byteLength = glTFAccessor.count * components * bytesPerComponent; // Get the boundaries of the binary sub-chunk for this bufferView
var glTFBufferView = this.json.bufferViews[glTFAccessor.bufferView];
(0, _core.assert)(byteLength >= 0 && byteLength <= glTFBufferView.byteLength);
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new ArrayType(this.arrayBuffer, byteOffset, length);
} // Unpacks an image into an HTML image
}, {
key: "getImage",
value: function getImage(glTFImage) {
/* global window, Blob, Image */
var arrayBufferView = this.unpackBufferView(glTFImage.bufferView);
var mimeType = glTFImage.mimeType || 'image/jpeg';
var blob = new Blob([arrayBufferView], {
type: mimeType
});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
var img = new Image();
img.src = imageUrl;
return img;
} // PRIVATE

@@ -172,184 +208,2 @@

}
}, {
key: "unpackBinaryObjects",
value: function unpackBinaryObjects() {
var unpackedBinaryObjects = {
images: [],
accessors: [],
meshes: []
};
var images = this.json.images || [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = images[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var glTFImage = _step.value;
unpackedBinaryObjects.images.push(this._unpackImage(glTFImage));
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var accessors = this.json.accessors || [];
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = accessors[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var glTFAccessor = _step2.value;
unpackedBinaryObjects.accessors.push(this._unpackAccessor(glTFAccessor));
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
var meshes = this.json.meshes || [];
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = meshes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var glTFMesh = _step3.value;
unpackedBinaryObjects.meshes.push(this._unpackMesh(glTFMesh));
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
return unpackedBinaryObjects;
}
}, {
key: "_unpackImage",
value: function _unpackImage(glTFImage) {
/* global window, Blob, Image */
var arrayBufferView = this.unpackBufferView(glTFImage.bufferView);
var mimeType = glTFImage.mimeType || 'image/jpeg';
var blob = new Blob([arrayBufferView], {
type: mimeType
});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
var img = new Image();
img.src = imageUrl;
return img;
}
}, {
key: "_unpackAccessor",
value: function _unpackAccessor(glTFAccessor) {
// Decode the glTF accessor format
var ArrayType = _gltfTypeUtils.ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
var components = _gltfTypeUtils.ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
var bytesPerComponent = _gltfTypeUtils.ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[glTFAccessor.componentType];
var length = glTFAccessor.count * components;
var byteLength = glTFAccessor.count * components * bytesPerComponent; // Get the boundaries of the binary sub-chunk for this bufferView
var glTFBufferView = this.json.bufferViews[glTFAccessor.bufferView];
(0, _core.assert)(byteLength >= 0 && byteLength <= glTFBufferView.byteLength);
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new ArrayType(this.arrayBuffer, byteOffset, length);
} // Create a new typed array as a view into the binary chunk
}, {
key: "_unpackBufferView",
value: function _unpackBufferView(glTFBufferView) {
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new Uint8Array(byteOffset, glTFBufferView.byteLength);
}
}, {
key: "_unpackMesh",
value: function _unpackMesh(mesh) {
var unpackedPrimitives = [];
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = mesh.primitives[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var primitive = _step4.value;
var compressedMesh = primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
var compressedPointCloud = primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
var unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
var dracoDecoder = new this.DracoDecoder();
var decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
var _dracoDecoder = new this.DracoDecoder();
var _decodedData = _dracoDecoder.decodePointCloud(compressedPointCloud);
_dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: _decodedData.attributes
});
} else {// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
unpackedPrimitives.push(unpackedPrimitive);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
return unpackedPrimitives.length === 1 ? unpackedPrimitives[0] : unpackedPrimitives;
}
}]);

@@ -356,0 +210,0 @@

@@ -60,3 +60,4 @@ "use strict";

return _this;
} // Encode as a textual JSON file with binary data in base64 data URLs.
} // TODO - support encoding to non-GLB versions of glTF format
// Encode as a textual JSON file with binary data in base64 data URLs.
// encodeAsDataURLs(options) {

@@ -63,0 +64,0 @@ // throw new Error('Not yet implemented');

@@ -23,14 +23,13 @@ "use strict";

function () {
function GLTFParser(gltf) {
function GLTFParser() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, GLTFParser);
if (gltf instanceof ArrayBuffer) {
gltf = new _glbParser.default(gltf).parse().json;
}
this.gltf = gltf;
this.json = gltf;
// TODO - move parsing to parse
this.log = console; // eslint-disable-line
this.out = {};
this.out = {}; // Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder || null;
}

@@ -40,20 +39,21 @@

key: "parse",
value: function parse() {
var _this = this;
value: function parse(gltf) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
this.glbParser = new _glbParser.default(); // GLTF can be JSON or binary (GLB)
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Load all images
this.out.images = (this.gltf.images || []).map(function (image) {
return _this.parseImage(image);
}).filter(Boolean); // Parse all scenes
if (gltf instanceof ArrayBuffer) {
this.gltf = this.glbParser.parse(gltf).json;
this.json = this.gltf;
} else {
this.gltf = gltf;
this.json = gltf;
}
this.out.scenes = (this.gltf.scenes || []).map(function (scene) {
return _this.parseImage(scene);
}).filter(Boolean);
this._loadLinkedAssets(options); // TODO - not implemented
// this._postProcessGLTF(options); TODO - remove done differently now
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
}
return this;
this._resolveToTree(options);
return this.gltf;
} // Accessors

@@ -90,4 +90,46 @@

return this.json.extensionsUsed;
}
} // DATA UNPACKING
// Unpacks all the primitives in a mesh
}, {
key: "unpackMesh",
value: function unpackMesh(mesh) {
return mesh.primitives.map(this.unpackPrimitive.bind(this));
} // Unpacks one mesh primitive
}, {
key: "unpackPrimitive",
value: function unpackPrimitive(primitive) {
var compressedMesh = primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
var compressedPointCloud = primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
var unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
var dracoDecoder = new this.DracoDecoder();
var decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
var _dracoDecoder = new this.DracoDecoder();
var _decodedData = _dracoDecoder.decodePointCloud(compressedPointCloud);
_dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: _decodedData.attributes
});
} else {// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
} // PRIVATE
}, {
key: "getScene",

@@ -146,4 +188,3 @@ value: function getScene(index) {

return this._get('buffers', index);
} // PRIVATE
}
}, {

@@ -155,3 +196,3 @@ key: "_get",

if (!object) {
console.warn("glTF file error: Could not resolve ".concat(array, "[").concat(index, "]")); // eslint-disable-line
console.warn("glTF file error: Could not find ".concat(array, "[").concat(index, "]")); // eslint-disable-line
}

@@ -161,43 +202,38 @@

} // PARSING HELPERS
// Start loading linked assets
}, {
key: "parseScene",
value: function parseScene() {}
}, {
key: "parseImage",
value: function parseImage(image) {
return this.config.createImage(image);
key: "_loadLinkedAssets",
value: function _loadLinkedAssets(options) {// TODO: Not implemented
// TODO: Return a promise?
}
}, {
key: "parseMesh",
value: function parseMesh(mesh) {
var _this2 = this;
key: "_postProcessGLTF",
value: function _postProcessGLTF() {
var _this = this;
// Each primitive is intended to correspond to a draw call
var primitives = (mesh.primitives || []).map(function (primitive) {
return _this2.parseMeshPrimitive(primitive);
});
return primitives.length === 1 ? primitives[0] : this.config.createGroup(primitives);
}
}, {
key: "parseMeshPrimitive",
value: function parseMeshPrimitive(primitive) {
// if (!primitive.attributes)
// this.log.warn(primitive without attributes`)
var attributes = primitive.attributes || {};
attributes = this.config.mapAttributes(attributes);
return attributes;
}
}, {
key: "parseAccessor",
value: function parseAccessor(accessor) {
return this.config.createBuffer(accessor);
} // PREPARATION STEP: CROSS-LINK INDEX RESOLUTION, ENUM LOOKUP, CONVENIENCE CALCULATIONS
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Create all images (if requested)
this.out.images = (this.gltf.images || []).map(function (image) {
return _this.parseImage(image, options);
}).filter(Boolean); // Normalize all scenes
this.out.scenes = (this.gltf.scenes || []).map(function (scene) {
return _this.parseScene(scene, options);
}).filter(Boolean);
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
}
return this;
} // Convert indexed glTF structure into tree structure
// PREPARATION STEP: CROSS-LINK INDEX RESOLUTION, ENUM LOOKUP, CONVENIENCE CALCULATIONS
/* eslint-disable complexity */
}, {
key: "resolve",
value: function resolve() {
var _this3 = this;
key: "_resolveToTree",
value: function _resolveToTree() {
var _this2 = this;

@@ -207,30 +243,30 @@ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

(gltf.bufferViews || []).forEach(function (bufView, i) {
return _this3.resolveBufferView(bufView, i);
return _this2._resolveBufferView(bufView, i);
});
(gltf.images || []).forEach(function (image, i) {
return _this3.resolveImage(image, i);
return _this2._resolveImage(image, i, options);
});
(gltf.samplers || []).forEach(function (sampler, i) {
return _this3.resolveSampler(sampler, i);
return _this2._resolveSampler(sampler, i);
});
(gltf.textures || []).forEach(function (texture, i) {
return _this3.resolveTexture(texture, i);
return _this2._resolveTexture(texture, i);
});
(gltf.accessors || []).forEach(function (accessor, i) {
return _this3.resolveAccessor(accessor, i);
return _this2._resolveAccessor(accessor, i);
});
(gltf.materials || []).forEach(function (material, i) {
return _this3.resolveMaterial(material, i);
return _this2._resolveMaterial(material, i);
});
(gltf.meshes || []).forEach(function (mesh, i) {
return _this3.resolveMesh(mesh, i);
return _this2._resolveMesh(mesh, i);
});
(gltf.nodes || []).forEach(function (node, i) {
return _this3.resolveNode(node, i);
return _this2._resolveNode(node, i);
});
(gltf.skins || []).forEach(function (skin, i) {
return _this3.resolveSkin(skin, i);
return _this2._resolveSkin(skin, i);
});
(gltf.scenes || []).forEach(function (scene, i) {
return _this3.resolveScene(scene, i);
return _this2._resolveScene(scene, i);
});

@@ -247,19 +283,19 @@

}, {
key: "resolveScene",
value: function resolveScene(scene, index) {
var _this4 = this;
key: "_resolveScene",
value: function _resolveScene(scene, index) {
var _this3 = this;
scene.id = "scene-".concat(index);
scene.nodes = (scene.nodes || []).map(function (node) {
return _this4.getNode(node);
return _this3.getNode(node);
});
}
}, {
key: "resolveNode",
value: function resolveNode(node, index) {
var _this5 = this;
key: "_resolveNode",
value: function _resolveNode(node, index) {
var _this4 = this;
node.id = "node-".concat(index);
node.children = (node.children || []).map(function (child) {
return _this5.getNode(child);
return _this4.getNode(child);
});

@@ -280,4 +316,4 @@

}, {
key: "resolveSkin",
value: function resolveSkin(skin, index) {
key: "_resolveSkin",
value: function _resolveSkin(skin, index) {
skin.id = "skin-".concat(index);

@@ -287,4 +323,4 @@ skin.inverseBindMatrices = this.getAccessor(skin.inverseBindMatrices);

}, {
key: "resolveMesh",
value: function resolveMesh(mesh, index) {
key: "_resolveMesh",
value: function _resolveMesh(mesh, index) {
mesh.id = "mesh-".concat(index);

@@ -327,4 +363,4 @@ var _iteratorNormalCompletion = true;

}, {
key: "resolveMaterial",
value: function resolveMaterial(material, index) {
key: "_resolveMaterial",
value: function _resolveMaterial(material, index) {
material.id = "material-".concat(index);

@@ -357,4 +393,4 @@

}, {
key: "resolveAccessor",
value: function resolveAccessor(accessor, index) {
key: "_resolveAccessor",
value: function _resolveAccessor(accessor, index) {
accessor.id = "accessor-".concat(index);

@@ -368,4 +404,4 @@ accessor.bufferView = this.getBufferView(accessor.bufferView); // Look up enums

}, {
key: "resolveTexture",
value: function resolveTexture(texture, index) {
key: "_resolveTexture",
value: function _resolveTexture(texture, index) {
texture.id = "texture-".concat(index);

@@ -376,4 +412,4 @@ texture.sampler = this.getSampler(texture.sampler);

}, {
key: "resolveSampler",
value: function resolveSampler(sampler, index) {
key: "_resolveSampler",
value: function _resolveSampler(sampler, index) {
sampler.id = "sampler-".concat(index); // Map textual parameters to GL parameter values

@@ -389,4 +425,4 @@

}, {
key: "resolveImage",
value: function resolveImage(image, index) {
key: "_resolveImage",
value: function _resolveImage(image, index, options) {
image.id = "image-".concat(index);

@@ -396,8 +432,16 @@

image.bufferView = this.getBufferView(image.bufferView);
} // TODO - Handle URIs etc
} // TODO - Handle non-binary-chunk images, data URIs, URLs etc
// TODO - Image creation could be done on getImage instead of during load
var _options$createImages = options.createImages,
createImages = _options$createImages === void 0 ? true : _options$createImages;
if (createImages) {
image.image = this.glbParser.unpackImage(image);
}
}
}, {
key: "resolveBufferView",
value: function resolveBufferView(bufferView, index) {
key: "_resolveBufferView",
value: function _resolveBufferView(bufferView, index) {
bufferView.id = "bufferView-".concat(index);

@@ -408,11 +452,9 @@ bufferView.buffer = this.getBuffer(bufferView.buffer);

}, {
key: "resolveCamera",
value: function resolveCamera(camera) {
// TODO - resolve step should not create
if (camera.perspective) {
camera.matrix = this.config.createPerspectiveMatrix(camera.perspective);
key: "_resolveCamera",
value: function _resolveCamera(camera) {
// TODO - create 4x4 matrices
if (camera.perspective) {// camera.matrix = createPerspectiveMatrix(camera.perspective);
}
if (camera.orthographic) {
camera.matrix = this.config.createOrthographicMatrix(camera.orthographic);
if (camera.orthographic) {// camera.matrix = createOrthographicMatrix(camera.orthographic);
}

@@ -419,0 +461,0 @@ }

@@ -33,6 +33,20 @@ /* eslint-disable camelcase, max-statements */

this.sourceBuffers = [];
}
} // ACCESSORS
getByteLength() {
return this.byteLength;
} // Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
isImage(imageData) {
return isImage(imageData);
} // MODIFERS
// Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
encodeAsGLB() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._createGLBBuffer(options);
} // Add an extra application-defined key to the top-level data structure

@@ -47,21 +61,21 @@ // By default packs JSON by extracting binary data and replacing it with JSON pointers

return this;
} // Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
} // Add one untyped source buffer, create a matching glTF `bufferView`, and return its index
encodeAsGLB() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._createGlbBuffer(options);
} // Returns an arrayBuffer together with JSON etc data.
addBufferView(buffer) {
const byteLength = buffer.byteLength || buffer.length; // Add a bufferView indicating start and length of this binary sub-chunk
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength
}); // We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
encodeAsGLBWithMetadata() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.byteLength += padTo4Bytes(byteLength); // Add this buffer to the list of buffers to be written to the body.
const arrayBuffer = this._createGlbBuffer(options);
this.sourceBuffers.push(buffer); // Return the index to the just created bufferView
return {
arrayBuffer,
json: this.json
};
return this.json.bufferViews.length - 1;
} // Add a binary buffer. Builds glTF "JSON metadata" and saves buffer reference

@@ -75,6 +89,4 @@ // Buffer will be copied into BIN chunk during "pack"

};
const bufferViewIndex = this.addBufferView(sourceBuffer); // Add an accessor pointing to the new buffer view
const bufferViewIndex = this._addBufferView(sourceBuffer); // Add an accessor pointing to the new buffer view
const glTFAccessor = {

@@ -88,7 +100,2 @@ bufferView: bufferViewIndex,

return this.json.accessors.length - 1;
} // Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
isImage(imageData) {
return isImage(imageData);
} // Adds a binary image. Builds glTF "JSON metadata" and saves buffer reference

@@ -99,4 +106,3 @@ // Buffer will be copied into BIN chunk during "pack"

addImage(imageData) {
const bufferViewIndex = this._addBufferView(imageData);
const bufferViewIndex = this.addBufferView(imageData);
const glTFImage = {

@@ -121,3 +127,4 @@ bufferView: bufferViewIndex

return this.json.images.length - 1;
} // For testing
} // PRIVATE
// For testing

@@ -132,22 +139,2 @@

};
} // PRIVATE
// Add one source buffer, create a matchibng glTF `bufferView`, and return its index
_addBufferView(buffer) {
const byteLength = buffer.byteLength || buffer.length; // Add a bufferView indicating start and length of this binary sub-chunk
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength
}); // We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
this.byteLength += padTo4Bytes(byteLength); // Add this buffer to the list of buffers to be written to the body.
this.sourceBuffers.push(buffer); // Return the index to the just created bufferView
return this.json.bufferViews.length - 1;
} // Pack the binary chunk

@@ -197,3 +184,3 @@

_createGlbBuffer() {
_createGLBBuffer() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

@@ -200,0 +187,0 @@

@@ -36,9 +36,5 @@ /* eslint-disable camelcase, max-statements */

constructor(glbArrayBuffer) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder; // Input
this.glbArrayBuffer = glbArrayBuffer; // Result
constructor() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Result
this.binaryByteOffset = null;

@@ -50,6 +46,7 @@ this.packedJson = null;

parse() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
parse(glbArrayBuffer) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Input
this.glbArrayBuffer = glbArrayBuffer; // Only parse once
// Only parse once
if (this.json === null && this.binaryByteOffset === null) {

@@ -80,2 +77,38 @@ this.result = this._parse(options);

return this.binaryByteOffset;
} // Unpacks a bufferview into a new Uint8Array that is a view into the binary chunk
getBufferView(glTFBufferView) {
const byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new Uint8Array(byteOffset, glTFBufferView.byteLength);
} // Unpacks a glTF accessor into a new typed array that is a view into the binary chunk
getBuffer(glTFAccessor) {
// Decode the glTF accessor format
const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
const components = ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
const bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_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);
} // Unpacks an image into an HTML image
getImage(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;
} // PRIVATE

@@ -143,101 +176,3 @@

unpackBinaryObjects() {
const unpackedBinaryObjects = {
images: [],
accessors: [],
meshes: []
};
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));
}
const meshes = this.json.meshes || [];
for (const glTFMesh of meshes) {
unpackedBinaryObjects.meshes.push(this._unpackMesh(glTFMesh));
}
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 = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
const components = ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
const bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_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);
}
_unpackMesh(mesh) {
const unpackedPrimitives = [];
for (const primitive of mesh.primitives) {
const compressedMesh = primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
const compressedPointCloud = primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
const unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodePointCloud(compressedPointCloud);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: decodedData.attributes
});
} else {// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
unpackedPrimitives.push(unpackedPrimitive);
}
return unpackedPrimitives.length === 1 ? unpackedPrimitives[0] : unpackedPrimitives;
}
}
//# sourceMappingURL=glb-parser.js.map

@@ -18,3 +18,4 @@ /* eslint-disable camelcase, max-statements */

});
} // Encode as a textual JSON file with binary data in base64 data URLs.
} // TODO - support encoding to non-GLB versions of glTF format
// Encode as a textual JSON file with binary data in base64 data URLs.
// encodeAsDataURLs(options) {

@@ -21,0 +22,0 @@ // throw new Error('Not yet implemented');

import { getBytesFromComponentType, getSizeFromAccessorType } from '../utils/gltf-type-utils';
import GLBParser from '../glb/glb-parser';
export default class GLTFParser {
constructor(gltf) {
if (gltf instanceof ArrayBuffer) {
gltf = new GLBParser(gltf).parse().json;
}
this.gltf = gltf;
this.json = gltf;
constructor() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// TODO - move parsing to parse
this.log = console; // eslint-disable-line
this.out = {};
this.out = {}; // Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder || null;
}
parse() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Load all images
this.out.images = (this.gltf.images || []).map(image => this.parseImage(image)).filter(Boolean); // Parse all scenes
parse(gltf) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
this.glbParser = new GLBParser(); // GLTF can be JSON or binary (GLB)
this.out.scenes = (this.gltf.scenes || []).map(scene => this.parseImage(scene)).filter(Boolean);
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
if (gltf instanceof ArrayBuffer) {
this.gltf = this.glbParser.parse(gltf).json;
this.json = this.gltf;
} else {
this.gltf = gltf;
this.json = gltf;
}
return this;
this._loadLinkedAssets(options); // TODO - not implemented
// this._postProcessGLTF(options); TODO - remove done differently now
this._resolveToTree(options);
return this.gltf;
} // Accessors

@@ -54,4 +59,41 @@

return this.json.extensionsUsed;
}
} // DATA UNPACKING
// Unpacks all the primitives in a mesh
unpackMesh(mesh) {
return mesh.primitives.map(this.unpackPrimitive.bind(this));
} // Unpacks one mesh primitive
unpackPrimitive(primitive) {
const compressedMesh = primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
const compressedPointCloud = primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
const unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodePointCloud(compressedPointCloud);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: decodedData.attributes
});
} else {// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
} // PRIVATE
getScene(index) {

@@ -99,5 +141,4 @@ return this._get('scenes', index);

return this._get('buffers', index);
} // PRIVATE
}
_get(array, index) {

@@ -107,3 +148,3 @@ const object = this.gltf[array] && this.gltf[array][index];

if (!object) {
console.warn(`glTF file error: Could not resolve ${array}[${index}]`); // eslint-disable-line
console.warn(`glTF file error: Could not find ${array}[${index}]`); // eslint-disable-line
}

@@ -113,44 +154,40 @@

} // PARSING HELPERS
// Start loading linked assets
parseScene() {}
parseImage(image) {
return this.config.createImage(image);
_loadLinkedAssets(options) {// TODO: Not implemented
// TODO: Return a promise?
}
parseMesh(mesh) {
// Each primitive is intended to correspond to a draw call
const primitives = (mesh.primitives || []).map(primitive => this.parseMeshPrimitive(primitive));
return primitives.length === 1 ? primitives[0] : this.config.createGroup(primitives);
}
_postProcessGLTF() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Create all images (if requested)
this.out.images = (this.gltf.images || []).map(image => this.parseImage(image, options)).filter(Boolean); // Normalize all scenes
parseMeshPrimitive(primitive) {
// if (!primitive.attributes)
// this.log.warn(primitive without attributes`)
let attributes = primitive.attributes || {};
attributes = this.config.mapAttributes(attributes);
return attributes;
}
this.out.scenes = (this.gltf.scenes || []).map(scene => this.parseScene(scene, options)).filter(Boolean);
parseAccessor(accessor) {
return this.config.createBuffer(accessor);
} // PREPARATION STEP: CROSS-LINK INDEX RESOLUTION, ENUM LOOKUP, CONVENIENCE CALCULATIONS
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
}
return this;
} // Convert indexed glTF structure into tree structure
// PREPARATION STEP: CROSS-LINK INDEX RESOLUTION, ENUM LOOKUP, CONVENIENCE CALCULATIONS
/* eslint-disable complexity */
resolve() {
_resolveToTree() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
const gltf = this.gltf;
(gltf.bufferViews || []).forEach((bufView, i) => this.resolveBufferView(bufView, i));
(gltf.images || []).forEach((image, i) => this.resolveImage(image, i));
(gltf.samplers || []).forEach((sampler, i) => this.resolveSampler(sampler, i));
(gltf.textures || []).forEach((texture, i) => this.resolveTexture(texture, i));
(gltf.accessors || []).forEach((accessor, i) => this.resolveAccessor(accessor, i));
(gltf.materials || []).forEach((material, i) => this.resolveMaterial(material, i));
(gltf.meshes || []).forEach((mesh, i) => this.resolveMesh(mesh, i));
(gltf.nodes || []).forEach((node, i) => this.resolveNode(node, i));
(gltf.skins || []).forEach((skin, i) => this.resolveSkin(skin, i));
(gltf.scenes || []).forEach((scene, i) => this.resolveScene(scene, i));
(gltf.bufferViews || []).forEach((bufView, i) => this._resolveBufferView(bufView, i));
(gltf.images || []).forEach((image, i) => this._resolveImage(image, i, options));
(gltf.samplers || []).forEach((sampler, i) => this._resolveSampler(sampler, i));
(gltf.textures || []).forEach((texture, i) => this._resolveTexture(texture, i));
(gltf.accessors || []).forEach((accessor, i) => this._resolveAccessor(accessor, i));
(gltf.materials || []).forEach((material, i) => this._resolveMaterial(material, i));
(gltf.meshes || []).forEach((mesh, i) => this._resolveMesh(mesh, i));
(gltf.nodes || []).forEach((node, i) => this._resolveNode(node, i));
(gltf.skins || []).forEach((skin, i) => this._resolveSkin(skin, i));
(gltf.scenes || []).forEach((scene, i) => this._resolveScene(scene, i));

@@ -166,3 +203,3 @@ if (gltf.scene) {

resolveScene(scene, index) {
_resolveScene(scene, index) {
scene.id = `scene-${index}`;

@@ -172,3 +209,3 @@ scene.nodes = (scene.nodes || []).map(node => this.getNode(node));

resolveNode(node, index) {
_resolveNode(node, index) {
node.id = `node-${index}`;

@@ -190,3 +227,3 @@ node.children = (node.children || []).map(child => this.getNode(child));

resolveSkin(skin, index) {
_resolveSkin(skin, index) {
skin.id = `skin-${index}`;

@@ -196,3 +233,3 @@ skin.inverseBindMatrices = this.getAccessor(skin.inverseBindMatrices);

resolveMesh(mesh, index) {
_resolveMesh(mesh, index) {
mesh.id = `mesh-${index}`;

@@ -215,3 +252,3 @@

resolveMaterial(material, index) {
_resolveMaterial(material, index) {
material.id = `material-${index}`;

@@ -244,3 +281,3 @@

resolveAccessor(accessor, index) {
_resolveAccessor(accessor, index) {
accessor.id = `accessor-${index}`;

@@ -254,3 +291,3 @@ accessor.bufferView = this.getBufferView(accessor.bufferView); // Look up enums

resolveTexture(texture, index) {
_resolveTexture(texture, index) {
texture.id = `texture-${index}`;

@@ -261,3 +298,3 @@ texture.sampler = this.getSampler(texture.sampler);

resolveSampler(sampler, index) {
_resolveSampler(sampler, index) {
sampler.id = `sampler-${index}`; // Map textual parameters to GL parameter values

@@ -273,3 +310,3 @@

resolveImage(image, index) {
_resolveImage(image, index, options) {
image.id = `image-${index}`;

@@ -279,7 +316,15 @@

image.bufferView = this.getBufferView(image.bufferView);
} // TODO - Handle URIs etc
} // TODO - Handle non-binary-chunk images, data URIs, URLs etc
// TODO - Image creation could be done on getImage instead of during load
const _options$createImages = options.createImages,
createImages = _options$createImages === void 0 ? true : _options$createImages;
if (createImages) {
image.image = this.glbParser.unpackImage(image);
}
}
resolveBufferView(bufferView, index) {
_resolveBufferView(bufferView, index) {
bufferView.id = `bufferView-${index}`;

@@ -290,10 +335,8 @@ bufferView.buffer = this.getBuffer(bufferView.buffer);

resolveCamera(camera) {
// TODO - resolve step should not create
if (camera.perspective) {
camera.matrix = this.config.createPerspectiveMatrix(camera.perspective);
_resolveCamera(camera) {
// TODO - create 4x4 matrices
if (camera.perspective) {// camera.matrix = createPerspectiveMatrix(camera.perspective);
}
if (camera.orthographic) {
camera.matrix = this.config.createOrthographicMatrix(camera.orthographic);
if (camera.orthographic) {// camera.matrix = createOrthographicMatrix(camera.orthographic);
}

@@ -300,0 +343,0 @@ }

@@ -45,4 +45,5 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

this.sourceBuffers = [];
}
} // ACCESSORS
_createClass(GLBBuilder, [{

@@ -52,2 +53,17 @@ key: "getByteLength",

return this.byteLength;
} // Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
}, {
key: "isImage",
value: function isImage(imageData) {
return _isImage(imageData);
} // MODIFERS
// Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
}, {
key: "encodeAsGLB",
value: function encodeAsGLB() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._createGLBBuffer(options);
} // Add an extra application-defined key to the top-level data structure

@@ -63,23 +79,22 @@ // By default packs JSON by extracting binary data and replacing it with JSON pointers

return this;
} // Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
} // Add one untyped source buffer, create a matching glTF `bufferView`, and return its index
}, {
key: "encodeAsGLB",
value: function encodeAsGLB() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return this._createGlbBuffer(options);
} // Returns an arrayBuffer together with JSON etc data.
key: "addBufferView",
value: function addBufferView(buffer) {
var byteLength = buffer.byteLength || buffer.length; // Add a bufferView indicating start and length of this binary sub-chunk
}, {
key: "encodeAsGLBWithMetadata",
value: function encodeAsGLBWithMetadata() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength: byteLength
}); // We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
var arrayBuffer = this._createGlbBuffer(options);
this.byteLength += padTo4Bytes(byteLength); // Add this buffer to the list of buffers to be written to the body.
return {
arrayBuffer: arrayBuffer,
json: this.json
};
this.sourceBuffers.push(buffer); // Return the index to the just created bufferView
return this.json.bufferViews.length - 1;
} // Add a binary buffer. Builds glTF "JSON metadata" and saves buffer reference

@@ -94,6 +109,4 @@ // Buffer will be copied into BIN chunk during "pack"

};
var bufferViewIndex = this.addBufferView(sourceBuffer); // Add an accessor pointing to the new buffer view
var bufferViewIndex = this._addBufferView(sourceBuffer); // Add an accessor pointing to the new buffer view
var glTFAccessor = {

@@ -107,8 +120,2 @@ bufferView: bufferViewIndex,

return this.json.accessors.length - 1;
} // Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
}, {
key: "isImage",
value: function isImage(imageData) {
return _isImage(imageData);
} // Adds a binary image. Builds glTF "JSON metadata" and saves buffer reference

@@ -120,4 +127,3 @@ // Buffer will be copied into BIN chunk during "pack"

value: function addImage(imageData) {
var bufferViewIndex = this._addBufferView(imageData);
var bufferViewIndex = this.addBufferView(imageData);
var glTFImage = {

@@ -142,3 +148,4 @@ bufferView: bufferViewIndex

return this.json.images.length - 1;
} // For testing
} // PRIVATE
// For testing

@@ -154,23 +161,2 @@ }, {

};
} // PRIVATE
// Add one source buffer, create a matchibng glTF `bufferView`, and return its index
}, {
key: "_addBufferView",
value: function _addBufferView(buffer) {
var byteLength = buffer.byteLength || buffer.length; // Add a bufferView indicating start and length of this binary sub-chunk
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength: byteLength
}); // We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
this.byteLength += padTo4Bytes(byteLength); // Add this buffer to the list of buffers to be written to the body.
this.sourceBuffers.push(buffer); // Return the index to the just created bufferView
return this.json.bufferViews.length - 1;
} // Pack the binary chunk

@@ -221,4 +207,4 @@

}, {
key: "_createGlbBuffer",
value: function _createGlbBuffer() {
key: "_createGLBBuffer",
value: function _createGLBBuffer() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

@@ -225,0 +211,0 @@

@@ -43,12 +43,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function GLBParser(glbArrayBuffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
function GLBParser() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, GLBParser);
// Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder; // Input
this.glbArrayBuffer = glbArrayBuffer; // Result
// Result
this.binaryByteOffset = null;

@@ -62,6 +58,7 @@ this.packedJson = null;

key: "parse",
value: function parse() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
value: function parse(glbArrayBuffer) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Input
this.glbArrayBuffer = glbArrayBuffer; // Only parse once
// Only parse once
if (this.json === null && this.binaryByteOffset === null) {

@@ -96,2 +93,41 @@ this.result = this._parse(options);

return this.binaryByteOffset;
} // Unpacks a bufferview into a new Uint8Array that is a view into the binary chunk
}, {
key: "getBufferView",
value: function getBufferView(glTFBufferView) {
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new Uint8Array(byteOffset, glTFBufferView.byteLength);
} // Unpacks a glTF accessor into a new typed array that is a view into the binary chunk
}, {
key: "getBuffer",
value: function getBuffer(glTFAccessor) {
// Decode the glTF accessor format
var ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
var components = ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
var bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[glTFAccessor.componentType];
var length = glTFAccessor.count * components;
var byteLength = glTFAccessor.count * components * bytesPerComponent; // Get the boundaries of the binary sub-chunk for this bufferView
var glTFBufferView = this.json.bufferViews[glTFAccessor.bufferView];
assert(byteLength >= 0 && byteLength <= glTFBufferView.byteLength);
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new ArrayType(this.arrayBuffer, byteOffset, length);
} // Unpacks an image into an HTML image
}, {
key: "getImage",
value: function getImage(glTFImage) {
/* global window, Blob, Image */
var arrayBufferView = this.unpackBufferView(glTFImage.bufferView);
var mimeType = glTFImage.mimeType || 'image/jpeg';
var blob = new Blob([arrayBufferView], {
type: mimeType
});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
var img = new Image();
img.src = imageUrl;
return img;
} // PRIVATE

@@ -160,184 +196,2 @@

}
}, {
key: "unpackBinaryObjects",
value: function unpackBinaryObjects() {
var unpackedBinaryObjects = {
images: [],
accessors: [],
meshes: []
};
var images = this.json.images || [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = images[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var glTFImage = _step.value;
unpackedBinaryObjects.images.push(this._unpackImage(glTFImage));
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var accessors = this.json.accessors || [];
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = accessors[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var glTFAccessor = _step2.value;
unpackedBinaryObjects.accessors.push(this._unpackAccessor(glTFAccessor));
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
var meshes = this.json.meshes || [];
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = meshes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var glTFMesh = _step3.value;
unpackedBinaryObjects.meshes.push(this._unpackMesh(glTFMesh));
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
return unpackedBinaryObjects;
}
}, {
key: "_unpackImage",
value: function _unpackImage(glTFImage) {
/* global window, Blob, Image */
var arrayBufferView = this.unpackBufferView(glTFImage.bufferView);
var mimeType = glTFImage.mimeType || 'image/jpeg';
var blob = new Blob([arrayBufferView], {
type: mimeType
});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
var img = new Image();
img.src = imageUrl;
return img;
}
}, {
key: "_unpackAccessor",
value: function _unpackAccessor(glTFAccessor) {
// Decode the glTF accessor format
var ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
var components = ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
var bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[glTFAccessor.componentType];
var length = glTFAccessor.count * components;
var byteLength = glTFAccessor.count * components * bytesPerComponent; // Get the boundaries of the binary sub-chunk for this bufferView
var glTFBufferView = this.json.bufferViews[glTFAccessor.bufferView];
assert(byteLength >= 0 && byteLength <= glTFBufferView.byteLength);
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new ArrayType(this.arrayBuffer, byteOffset, length);
} // Create a new typed array as a view into the binary chunk
}, {
key: "_unpackBufferView",
value: function _unpackBufferView(glTFBufferView) {
var byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new Uint8Array(byteOffset, glTFBufferView.byteLength);
}
}, {
key: "_unpackMesh",
value: function _unpackMesh(mesh) {
var unpackedPrimitives = [];
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = mesh.primitives[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var primitive = _step4.value;
var compressedMesh = primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
var compressedPointCloud = primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
var unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
var dracoDecoder = new this.DracoDecoder();
var decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
var _dracoDecoder = new this.DracoDecoder();
var _decodedData = _dracoDecoder.decodePointCloud(compressedPointCloud);
_dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: _decodedData.attributes
});
} else {// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
unpackedPrimitives.push(unpackedPrimitive);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
return unpackedPrimitives.length === 1 ? unpackedPrimitives[0] : unpackedPrimitives;
}
}]);

@@ -344,0 +198,0 @@

@@ -49,3 +49,4 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

return _this;
} // Encode as a textual JSON file with binary data in base64 data URLs.
} // TODO - support encoding to non-GLB versions of glTF format
// Encode as a textual JSON file with binary data in base64 data URLs.
// encodeAsDataURLs(options) {

@@ -52,0 +53,0 @@ // throw new Error('Not yet implemented');

@@ -13,14 +13,13 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function () {
function GLTFParser(gltf) {
function GLTFParser() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, GLTFParser);
if (gltf instanceof ArrayBuffer) {
gltf = new GLBParser(gltf).parse().json;
}
this.gltf = gltf;
this.json = gltf;
// TODO - move parsing to parse
this.log = console; // eslint-disable-line
this.out = {};
this.out = {}; // Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder || null;
}

@@ -30,20 +29,21 @@

key: "parse",
value: function parse() {
var _this = this;
value: function parse(gltf) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
this.glbParser = new GLBParser(); // GLTF can be JSON or binary (GLB)
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Load all images
this.out.images = (this.gltf.images || []).map(function (image) {
return _this.parseImage(image);
}).filter(Boolean); // Parse all scenes
if (gltf instanceof ArrayBuffer) {
this.gltf = this.glbParser.parse(gltf).json;
this.json = this.gltf;
} else {
this.gltf = gltf;
this.json = gltf;
}
this.out.scenes = (this.gltf.scenes || []).map(function (scene) {
return _this.parseImage(scene);
}).filter(Boolean);
this._loadLinkedAssets(options); // TODO - not implemented
// this._postProcessGLTF(options); TODO - remove done differently now
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
}
return this;
this._resolveToTree(options);
return this.gltf;
} // Accessors

@@ -80,4 +80,46 @@

return this.json.extensionsUsed;
}
} // DATA UNPACKING
// Unpacks all the primitives in a mesh
}, {
key: "unpackMesh",
value: function unpackMesh(mesh) {
return mesh.primitives.map(this.unpackPrimitive.bind(this));
} // Unpacks one mesh primitive
}, {
key: "unpackPrimitive",
value: function unpackPrimitive(primitive) {
var compressedMesh = primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
var compressedPointCloud = primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
var unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
var dracoDecoder = new this.DracoDecoder();
var decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
var _dracoDecoder = new this.DracoDecoder();
var _decodedData = _dracoDecoder.decodePointCloud(compressedPointCloud);
_dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: _decodedData.attributes
});
} else {// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
} // PRIVATE
}, {
key: "getScene",

@@ -136,4 +178,3 @@ value: function getScene(index) {

return this._get('buffers', index);
} // PRIVATE
}
}, {

@@ -145,3 +186,3 @@ key: "_get",

if (!object) {
console.warn("glTF file error: Could not resolve ".concat(array, "[").concat(index, "]")); // eslint-disable-line
console.warn("glTF file error: Could not find ".concat(array, "[").concat(index, "]")); // eslint-disable-line
}

@@ -151,43 +192,38 @@

} // PARSING HELPERS
// Start loading linked assets
}, {
key: "parseScene",
value: function parseScene() {}
}, {
key: "parseImage",
value: function parseImage(image) {
return this.config.createImage(image);
key: "_loadLinkedAssets",
value: function _loadLinkedAssets(options) {// TODO: Not implemented
// TODO: Return a promise?
}
}, {
key: "parseMesh",
value: function parseMesh(mesh) {
var _this2 = this;
key: "_postProcessGLTF",
value: function _postProcessGLTF() {
var _this = this;
// Each primitive is intended to correspond to a draw call
var primitives = (mesh.primitives || []).map(function (primitive) {
return _this2.parseMeshPrimitive(primitive);
});
return primitives.length === 1 ? primitives[0] : this.config.createGroup(primitives);
}
}, {
key: "parseMeshPrimitive",
value: function parseMeshPrimitive(primitive) {
// if (!primitive.attributes)
// this.log.warn(primitive without attributes`)
var attributes = primitive.attributes || {};
attributes = this.config.mapAttributes(attributes);
return attributes;
}
}, {
key: "parseAccessor",
value: function parseAccessor(accessor) {
return this.config.createBuffer(accessor);
} // PREPARATION STEP: CROSS-LINK INDEX RESOLUTION, ENUM LOOKUP, CONVENIENCE CALCULATIONS
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Create all images (if requested)
this.out.images = (this.gltf.images || []).map(function (image) {
return _this.parseImage(image, options);
}).filter(Boolean); // Normalize all scenes
this.out.scenes = (this.gltf.scenes || []).map(function (scene) {
return _this.parseScene(scene, options);
}).filter(Boolean);
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
}
return this;
} // Convert indexed glTF structure into tree structure
// PREPARATION STEP: CROSS-LINK INDEX RESOLUTION, ENUM LOOKUP, CONVENIENCE CALCULATIONS
/* eslint-disable complexity */
}, {
key: "resolve",
value: function resolve() {
var _this3 = this;
key: "_resolveToTree",
value: function _resolveToTree() {
var _this2 = this;

@@ -197,30 +233,30 @@ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

(gltf.bufferViews || []).forEach(function (bufView, i) {
return _this3.resolveBufferView(bufView, i);
return _this2._resolveBufferView(bufView, i);
});
(gltf.images || []).forEach(function (image, i) {
return _this3.resolveImage(image, i);
return _this2._resolveImage(image, i, options);
});
(gltf.samplers || []).forEach(function (sampler, i) {
return _this3.resolveSampler(sampler, i);
return _this2._resolveSampler(sampler, i);
});
(gltf.textures || []).forEach(function (texture, i) {
return _this3.resolveTexture(texture, i);
return _this2._resolveTexture(texture, i);
});
(gltf.accessors || []).forEach(function (accessor, i) {
return _this3.resolveAccessor(accessor, i);
return _this2._resolveAccessor(accessor, i);
});
(gltf.materials || []).forEach(function (material, i) {
return _this3.resolveMaterial(material, i);
return _this2._resolveMaterial(material, i);
});
(gltf.meshes || []).forEach(function (mesh, i) {
return _this3.resolveMesh(mesh, i);
return _this2._resolveMesh(mesh, i);
});
(gltf.nodes || []).forEach(function (node, i) {
return _this3.resolveNode(node, i);
return _this2._resolveNode(node, i);
});
(gltf.skins || []).forEach(function (skin, i) {
return _this3.resolveSkin(skin, i);
return _this2._resolveSkin(skin, i);
});
(gltf.scenes || []).forEach(function (scene, i) {
return _this3.resolveScene(scene, i);
return _this2._resolveScene(scene, i);
});

@@ -237,19 +273,19 @@

}, {
key: "resolveScene",
value: function resolveScene(scene, index) {
var _this4 = this;
key: "_resolveScene",
value: function _resolveScene(scene, index) {
var _this3 = this;
scene.id = "scene-".concat(index);
scene.nodes = (scene.nodes || []).map(function (node) {
return _this4.getNode(node);
return _this3.getNode(node);
});
}
}, {
key: "resolveNode",
value: function resolveNode(node, index) {
var _this5 = this;
key: "_resolveNode",
value: function _resolveNode(node, index) {
var _this4 = this;
node.id = "node-".concat(index);
node.children = (node.children || []).map(function (child) {
return _this5.getNode(child);
return _this4.getNode(child);
});

@@ -270,4 +306,4 @@

}, {
key: "resolveSkin",
value: function resolveSkin(skin, index) {
key: "_resolveSkin",
value: function _resolveSkin(skin, index) {
skin.id = "skin-".concat(index);

@@ -277,4 +313,4 @@ skin.inverseBindMatrices = this.getAccessor(skin.inverseBindMatrices);

}, {
key: "resolveMesh",
value: function resolveMesh(mesh, index) {
key: "_resolveMesh",
value: function _resolveMesh(mesh, index) {
mesh.id = "mesh-".concat(index);

@@ -317,4 +353,4 @@ var _iteratorNormalCompletion = true;

}, {
key: "resolveMaterial",
value: function resolveMaterial(material, index) {
key: "_resolveMaterial",
value: function _resolveMaterial(material, index) {
material.id = "material-".concat(index);

@@ -347,4 +383,4 @@

}, {
key: "resolveAccessor",
value: function resolveAccessor(accessor, index) {
key: "_resolveAccessor",
value: function _resolveAccessor(accessor, index) {
accessor.id = "accessor-".concat(index);

@@ -358,4 +394,4 @@ accessor.bufferView = this.getBufferView(accessor.bufferView); // Look up enums

}, {
key: "resolveTexture",
value: function resolveTexture(texture, index) {
key: "_resolveTexture",
value: function _resolveTexture(texture, index) {
texture.id = "texture-".concat(index);

@@ -366,4 +402,4 @@ texture.sampler = this.getSampler(texture.sampler);

}, {
key: "resolveSampler",
value: function resolveSampler(sampler, index) {
key: "_resolveSampler",
value: function _resolveSampler(sampler, index) {
sampler.id = "sampler-".concat(index); // Map textual parameters to GL parameter values

@@ -379,4 +415,4 @@

}, {
key: "resolveImage",
value: function resolveImage(image, index) {
key: "_resolveImage",
value: function _resolveImage(image, index, options) {
image.id = "image-".concat(index);

@@ -386,8 +422,16 @@

image.bufferView = this.getBufferView(image.bufferView);
} // TODO - Handle URIs etc
} // TODO - Handle non-binary-chunk images, data URIs, URLs etc
// TODO - Image creation could be done on getImage instead of during load
var _options$createImages = options.createImages,
createImages = _options$createImages === void 0 ? true : _options$createImages;
if (createImages) {
image.image = this.glbParser.unpackImage(image);
}
}
}, {
key: "resolveBufferView",
value: function resolveBufferView(bufferView, index) {
key: "_resolveBufferView",
value: function _resolveBufferView(bufferView, index) {
bufferView.id = "bufferView-".concat(index);

@@ -398,11 +442,9 @@ bufferView.buffer = this.getBuffer(bufferView.buffer);

}, {
key: "resolveCamera",
value: function resolveCamera(camera) {
// TODO - resolve step should not create
if (camera.perspective) {
camera.matrix = this.config.createPerspectiveMatrix(camera.perspective);
key: "_resolveCamera",
value: function _resolveCamera(camera) {
// TODO - create 4x4 matrices
if (camera.perspective) {// camera.matrix = createPerspectiveMatrix(camera.perspective);
}
if (camera.orthographic) {
camera.matrix = this.config.createOrthographicMatrix(camera.orthographic);
if (camera.orthographic) {// camera.matrix = createOrthographicMatrix(camera.orthographic);
}

@@ -409,0 +451,0 @@ }

{
"name": "@loaders.gl/gltf",
"version": "0.4.8",
"version": "0.5.0",
"description": "Framework-independent loader for the glTF format",

@@ -28,19 +28,19 @@ "license": "MIT",

"dist",
".bin",
"README.md"
],
"bin": {
"glbdump": "./.bin/glbdump"
"glbdump": "./bin/glbdump.js"
},
"scripts": {
"clean": "rm -fr dist && mkdir -p dist",
"build": "npm run clean && npm run build-es6 && npm run build-esm && npm run build-es5",
"build": "npm run clean && npm run build-es6 && npm run build-esm && npm run build-es5 && npm run build-bin",
"build-es6": "BABEL_ENV=es6 babel src --config-file ../../babel.config.js --out-dir dist/es6 --source-maps --ignore 'node_modules/'",
"build-esm": "BABEL_ENV=esm babel src --config-file ../../babel.config.js --out-dir dist/esm --source-maps --ignore 'node_modules/'",
"build-es5": "BABEL_ENV=es5 babel src --config-file ../../babel.config.js --out-dir dist/es5 --source-maps --ignore 'node_modules/'"
"build-es5": "BABEL_ENV=es5 babel src --config-file ../../babel.config.js --out-dir dist/es5 --source-maps --ignore 'node_modules/'",
"build-bin": "BABEL_ENV=es5 babel scripts --config-file ../../babel.config.js --out-dir dist/scripts --source-maps --ignore 'node_modules/'"
},
"sideEffects": false,
"dependencies": {
"@loaders.gl/core": "^0.4.6"
"@loaders.gl/core": "^0.5.0"
}
}

@@ -48,2 +48,4 @@ /* eslint-disable camelcase, max-statements */

// ACCESSORS
getByteLength() {

@@ -53,2 +55,15 @@ return this.byteLength;

// Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
isImage(imageData) {
return isImage(imageData);
}
// MODIFERS
// Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
encodeAsGLB(options = {}) {
return this._createGLBBuffer(options);
}
// Add an extra application-defined key to the top-level data structure

@@ -62,12 +77,23 @@ // By default packs JSON by extracting binary data and replacing it with JSON pointers

// Encode the full glTF file as a binary GLB file
// Returns an ArrayBuffer that represents the complete GLB image that can be saved to file
encodeAsGLB(options = {}) {
return this._createGlbBuffer(options);
}
// Add one untyped source buffer, create a matching glTF `bufferView`, and return its index
addBufferView(buffer) {
const byteLength = buffer.byteLength || buffer.length;
// Returns an arrayBuffer together with JSON etc data.
encodeAsGLBWithMetadata(options = {}) {
const arrayBuffer = this._createGlbBuffer(options);
return {arrayBuffer, json: this.json};
// Add a bufferView indicating start and length of this binary sub-chunk
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength
});
// We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
this.byteLength += padTo4Bytes(byteLength);
// Add this buffer to the list of buffers to be written to the body.
this.sourceBuffers.push(buffer);
// Return the index to the just created bufferView
return this.json.bufferViews.length - 1;
}

@@ -78,3 +104,3 @@

addBuffer(sourceBuffer, accessor = {size: 3}) {
const bufferViewIndex = this._addBufferView(sourceBuffer);
const bufferViewIndex = this.addBufferView(sourceBuffer);

@@ -94,11 +120,6 @@ // Add an accessor pointing to the new buffer view

// Checks if a binary buffer is a recognized image format (PNG, JPG, GIF, ...)
isImage(imageData) {
return isImage(imageData);
}
// Adds a binary image. Builds glTF "JSON metadata" and saves buffer reference
// Buffer will be copied into BIN chunk during "pack"
addImage(imageData) {
const bufferViewIndex = this._addBufferView(imageData);
const bufferViewIndex = this.addBufferView(imageData);

@@ -121,4 +142,5 @@ const glTFImage = {

// PRIVATE
// For testing
_pack() {

@@ -129,27 +151,2 @@ this._packBinaryChunk();

// PRIVATE
// Add one source buffer, create a matchibng glTF `bufferView`, and return its index
_addBufferView(buffer) {
const byteLength = buffer.byteLength || buffer.length;
// Add a bufferView indicating start and length of this binary sub-chunk
this.json.bufferViews.push({
buffer: 0,
// Write offset from the start of the binary body
byteOffset: this.byteLength,
byteLength
});
// We've now written the contents to the body, so update the total length
// Every sub-chunk needs to be 4-byte aligned
this.byteLength += padTo4Bytes(byteLength);
// Add this buffer to the list of buffers to be written to the body.
this.sourceBuffers.push(buffer);
// Return the index to the just created bufferView
return this.json.bufferViews.length - 1;
}
// Pack the binary chunk

@@ -202,3 +199,3 @@ _packBinaryChunk() {

// glb-file-format-specification
_createGlbBuffer(options = {}) {
_createGLBBuffer(options = {}) {
// TODO - avoid double array buffer creation

@@ -205,0 +202,0 @@ this._packBinaryChunk();

@@ -43,9 +43,3 @@ /* eslint-disable camelcase, max-statements */

constructor(glbArrayBuffer, options = {}) {
// Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder;
// Input
this.glbArrayBuffer = glbArrayBuffer;
constructor(options = {}) {
// Result

@@ -58,3 +52,6 @@ this.binaryByteOffset = null;

// Return the gltf JSON and the original arrayBuffer
parse(options = {}) {
parse(glbArrayBuffer, options = {}) {
// Input
this.glbArrayBuffer = glbArrayBuffer;
// Only parse once

@@ -87,2 +84,38 @@ if (this.json === null && this.binaryByteOffset === null) {

// Unpacks a bufferview into a new Uint8Array that is a view into the binary chunk
getBufferView(glTFBufferView) {
const byteOffset = glTFBufferView.byteOffset + this.binaryByteOffset;
return new Uint8Array(byteOffset, glTFBufferView.byteLength);
}
// Unpacks a glTF accessor into a new typed array that is a view into the binary chunk
getBuffer(glTFAccessor) {
// Decode the glTF accessor format
const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
const components = ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
const bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_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);
}
// Unpacks an image into an HTML image
getImage(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;
}
// PRIVATE

@@ -147,106 +180,2 @@

}
unpackBinaryObjects() {
const unpackedBinaryObjects = {
images: [],
accessors: [],
meshes: []
};
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));
}
const meshes = this.json.meshes || [];
for (const glTFMesh of meshes) {
unpackedBinaryObjects.meshes.push(this._unpackMesh(glTFMesh));
}
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 = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[glTFAccessor.componentType];
const components = ATTRIBUTE_TYPE_TO_COMPONENTS[glTFAccessor.type];
const bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_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);
}
_unpackMesh(mesh) {
const unpackedPrimitives = [];
for (const primitive of mesh.primitives) {
const compressedMesh =
primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
const compressedPointCloud =
primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
const unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodePointCloud(compressedPointCloud);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: decodedData.attributes
});
} else {
// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
unpackedPrimitives.push(unpackedPrimitive);
}
return unpackedPrimitives.length === 1 ? unpackedPrimitives[0] : unpackedPrimitives;
}
}

@@ -23,2 +23,4 @@ /* eslint-disable camelcase, max-statements */

// TODO - support encoding to non-GLB versions of glTF format
// Encode as a textual JSON file with binary data in base64 data URLs.

@@ -25,0 +27,0 @@ // encodeAsDataURLs(options) {

@@ -5,28 +5,28 @@ import {getBytesFromComponentType, getSizeFromAccessorType} from '../utils/gltf-type-utils';

export default class GLTFParser {
constructor(gltf) {
if (gltf instanceof ArrayBuffer) {
gltf = new GLBParser(gltf).parse().json;
}
this.gltf = gltf;
this.json = gltf;
constructor(options = {}) {
// TODO - move parsing to parse
this.log = console; // eslint-disable-line
this.out = {};
// Soft dependency on Draco, needs to be imported and supplied by app
this.DracoDecoder = options.DracoDecoder || null;
}
parse(options = {}) {
// Load all images
this.out.images = (this.gltf.images || [])
.map(image => this.parseImage(image))
.filter(Boolean);
parse(gltf, options = {}) {
this.glbParser = new GLBParser();
// Parse all scenes
this.out.scenes = (this.gltf.scenes || [])
.map(scene => this.parseImage(scene))
.filter(Boolean);
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
// GLTF can be JSON or binary (GLB)
if (gltf instanceof ArrayBuffer) {
this.gltf = this.glbParser.parse(gltf).json;
this.json = this.gltf;
} else {
this.gltf = gltf;
this.json = gltf;
}
return this;
this._loadLinkedAssets(options); // TODO - not implemented
// this._postProcessGLTF(options); TODO - remove done differently now
this._resolveToTree(options);
return this.gltf;
}

@@ -61,2 +61,48 @@

// DATA UNPACKING
// Unpacks all the primitives in a mesh
unpackMesh(mesh) {
return mesh.primitives.map(this.unpackPrimitive.bind(this));
}
// Unpacks one mesh primitive
unpackPrimitive(primitive) {
const compressedMesh =
primitive.extensions && primitive.extensions.UBER_draco_mesh_compression;
const compressedPointCloud =
primitive.extensions && primitive.extensions.UBER_draco_point_cloud_compression;
const unpackedPrimitive = {
mode: primitive.mode,
material: primitive.material
};
if (compressedMesh) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodeMesh(compressedMesh);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
indices: decodedData.indices,
attributes: decodedData.attributes
});
} else if (compressedPointCloud) {
const dracoDecoder = new this.DracoDecoder();
const decodedData = dracoDecoder.decodePointCloud(compressedPointCloud);
dracoDecoder.destroy();
Object.assign(unpackedPrimitive, {
mode: 0,
attributes: decodedData.attributes
});
} else {
// No compression - just a glTF mesh primitive
// TODO - Resolve all accessors
}
}
// PRIVATE
getScene(index) {

@@ -106,8 +152,6 @@ return this._get('scenes', index);

// PRIVATE
_get(array, index) {
const object = this.gltf[array] && this.gltf[array][index];
if (!object) {
console.warn(`glTF file error: Could not resolve ${array}[${index}]`); // eslint-disable-line
console.warn(`glTF file error: Could not find ${array}[${index}]`); // eslint-disable-line
}

@@ -119,50 +163,47 @@ return object;

parseScene() {
// Start loading linked assets
_loadLinkedAssets(options) {
// TODO: Not implemented
// TODO: Return a promise?
}
parseImage(image) {
return this.config.createImage(image);
}
_postProcessGLTF(options = {}) {
// Create all images (if requested)
this.out.images = (this.gltf.images || [])
.map(image => this.parseImage(image, options))
.filter(Boolean);
parseMesh(mesh) {
// Each primitive is intended to correspond to a draw call
const primitives = (mesh.primitives || []).map(primitive => this.parseMeshPrimitive(primitive));
// Normalize all scenes
this.out.scenes = (this.gltf.scenes || [])
.map(scene => this.parseScene(scene, options))
.filter(Boolean);
return primitives.length === 1 ? primitives[0] : this.config.createGroup(primitives);
}
if (this.gltf.scene) {
this.out.scene = this.gltf.scenes[this.gltf.scene];
}
parseMeshPrimitive(primitive) {
// if (!primitive.attributes)
// this.log.warn(primitive without attributes`)
let attributes = primitive.attributes || {};
attributes = this.config.mapAttributes(attributes);
return attributes;
return this;
}
parseAccessor(accessor) {
return this.config.createBuffer(accessor);
}
// Convert indexed glTF structure into tree structure
// PREPARATION STEP: CROSS-LINK INDEX RESOLUTION, ENUM LOOKUP, CONVENIENCE CALCULATIONS
/* eslint-disable complexity */
resolve(options = {}) {
_resolveToTree(options = {}) {
const {gltf} = this;
(gltf.bufferViews || []).forEach((bufView, i) => this.resolveBufferView(bufView, i));
(gltf.bufferViews || []).forEach((bufView, i) => this._resolveBufferView(bufView, i));
(gltf.images || []).forEach((image, i) => this.resolveImage(image, i));
(gltf.samplers || []).forEach((sampler, i) => this.resolveSampler(sampler, i));
(gltf.textures || []).forEach((texture, i) => this.resolveTexture(texture, i));
(gltf.images || []).forEach((image, i) => this._resolveImage(image, i, options));
(gltf.samplers || []).forEach((sampler, i) => this._resolveSampler(sampler, i));
(gltf.textures || []).forEach((texture, i) => this._resolveTexture(texture, i));
(gltf.accessors || []).forEach((accessor, i) => this.resolveAccessor(accessor, i));
(gltf.materials || []).forEach((material, i) => this.resolveMaterial(material, i));
(gltf.meshes || []).forEach((mesh, i) => this.resolveMesh(mesh, i));
(gltf.accessors || []).forEach((accessor, i) => this._resolveAccessor(accessor, i));
(gltf.materials || []).forEach((material, i) => this._resolveMaterial(material, i));
(gltf.meshes || []).forEach((mesh, i) => this._resolveMesh(mesh, i));
(gltf.nodes || []).forEach((node, i) => this.resolveNode(node, i));
(gltf.nodes || []).forEach((node, i) => this._resolveNode(node, i));
(gltf.skins || []).forEach((skin, i) => this.resolveSkin(skin, i));
(gltf.skins || []).forEach((skin, i) => this._resolveSkin(skin, i));
(gltf.scenes || []).forEach((scene, i) => this.resolveScene(scene, i));
(gltf.scenes || []).forEach((scene, i) => this._resolveScene(scene, i));

@@ -177,3 +218,3 @@ if (gltf.scene) {

resolveScene(scene, index) {
_resolveScene(scene, index) {
scene.id = `scene-${index}`;

@@ -183,3 +224,3 @@ scene.nodes = (scene.nodes || []).map(node => this.getNode(node));

resolveNode(node, index) {
_resolveNode(node, index) {
node.id = `node-${index}`;

@@ -198,3 +239,3 @@ node.children = (node.children || []).map(child => this.getNode(child));

resolveSkin(skin, index) {
_resolveSkin(skin, index) {
skin.id = `skin-${index}`;

@@ -204,3 +245,3 @@ skin.inverseBindMatrices = this.getAccessor(skin.inverseBindMatrices);

resolveMesh(mesh, index) {
_resolveMesh(mesh, index) {
mesh.id = `mesh-${index}`;

@@ -220,3 +261,3 @@ for (const primitive of mesh.primitives) {

resolveMaterial(material, index) {
_resolveMaterial(material, index) {
material.id = `material-${index}`;

@@ -244,6 +285,5 @@ if (material.normalTexture) {

resolveAccessor(accessor, index) {
_resolveAccessor(accessor, index) {
accessor.id = `accessor-${index}`;
accessor.bufferView = this.getBufferView(accessor.bufferView);
// Look up enums

@@ -255,3 +295,3 @@ accessor.bytesPerComponent = getBytesFromComponentType(accessor);

resolveTexture(texture, index) {
_resolveTexture(texture, index) {
texture.id = `texture-${index}`;

@@ -262,3 +302,3 @@ texture.sampler = this.getSampler(texture.sampler);

resolveSampler(sampler, index) {
_resolveSampler(sampler, index) {
sampler.id = `sampler-${index}`;

@@ -273,3 +313,3 @@ // Map textual parameters to GL parameter values

resolveImage(image, index) {
_resolveImage(image, index, options) {
image.id = `image-${index}`;

@@ -279,6 +319,12 @@ if (image.bufferView) {

}
// TODO - Handle URIs etc
// TODO - Handle non-binary-chunk images, data URIs, URLs etc
// TODO - Image creation could be done on getImage instead of during load
const {createImages = true} = options;
if (createImages) {
image.image = this.glbParser.unpackImage(image);
}
}
resolveBufferView(bufferView, index) {
_resolveBufferView(bufferView, index) {
bufferView.id = `bufferView-${index}`;

@@ -290,11 +336,12 @@ bufferView.buffer = this.getBuffer(bufferView.buffer);

resolveCamera(camera) {
// TODO - resolve step should not create
_resolveCamera(camera) {
// TODO - create 4x4 matrices
if (camera.perspective) {
camera.matrix = this.config.createPerspectiveMatrix(camera.perspective);
// camera.matrix = createPerspectiveMatrix(camera.perspective);
}
if (camera.orthographic) {
camera.matrix = this.config.createOrthographicMatrix(camera.orthographic);
// camera.matrix = createOrthographicMatrix(camera.orthographic);
}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc