Преглед изворни кода

Added ScatterPanel to GUI3d

David Catuhe пре 7 година
родитељ
комит
cd6aaa3b62
25 измењених фајлова са 13483 додато и 14043 уклоњено
  1. 1 0
      Tools/Gulp/config.json
  2. 12287 12287
      dist/preview release/babylon.d.ts
  3. 21 0
      dist/preview release/gui/babylon.gui.d.ts
  4. 126 10
      dist/preview release/gui/babylon.gui.js
  5. 2 2
      dist/preview release/gui/babylon.gui.min.js
  6. 21 0
      dist/preview release/gui/babylon.gui.module.d.ts
  7. 7 4
      dist/preview release/inspector/babylon.inspector.d.ts
  8. 90 55
      dist/preview release/inspector/babylon.inspector.js
  9. 2 2
      dist/preview release/inspector/babylon.inspector.min.js
  10. 27 98
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  11. 66 53
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  12. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  13. 30 187
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  14. 185 226
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  15. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  16. 30 202
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  17. 188 244
      dist/preview release/loaders/babylon.glTFFileLoader.js
  18. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  19. 30 202
      dist/preview release/loaders/babylonjs.loaders.d.ts
  20. 187 243
      dist/preview release/loaders/babylonjs.loaders.js
  21. 4 4
      dist/preview release/loaders/babylonjs.loaders.min.js
  22. 30 202
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  23. 5 5
      dist/preview release/serializers/babylon.glTF2Serializer.js
  24. 117 0
      gui/src/3D/controls/scatterPanel.ts
  25. 20 10
      gui/src/3D/controls/volumeBasedPanel.ts

+ 1 - 0
Tools/Gulp/config.json

@@ -1755,6 +1755,7 @@
                     "../../gui/src/3D/controls/volumeBasedPanel.ts",
                     "../../gui/src/3D/controls/spherePanel.ts",
                     "../../gui/src/3D/controls/planePanel.ts",
+                    "../../gui/src/3D/controls/scatterPanel.ts",
                     "../../gui/src/3D/controls/cylinderPanel.ts"
                 ],
                 "shaderFiles": [

Разлика између датотеке није приказан због своје велике величине
+ 12287 - 12287
dist/preview release/babylon.d.ts


+ 21 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -2491,6 +2491,8 @@ declare module BABYLON.GUI {
         private _rows;
         private _rowThenColum;
         private _orientation;
+        protected _cellWidth: number;
+        protected _cellHeight: number;
         /**
          * Gets or sets the distance between elements
          */
@@ -2523,6 +2525,8 @@ declare module BABYLON.GUI {
         protected _arrangeChildren(): void;
         /** Child classes must implement this function to provide correct control positioning */
         protected abstract _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+        /** Child classes can implement this function to provide additional processing */
+        protected _finalProcessing(): void;
     }
 }
 
@@ -2555,6 +2559,23 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     /**
+     * Class used to create a container panel where items get randomized planar mapping
+     */
+    class ScatterPanel extends VolumeBasedPanel {
+        private _iteration;
+        /**
+         * Gets or sets the number of iteration to use to scatter the controls (100 by default)
+         */
+        iteration: float;
+        protected _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+        private _scatterMapping(source);
+        protected _finalProcessing(): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
      * Class used to create a container panel deployed on the surface of a cylinder
      */
     class CylinderPanel extends VolumeBasedPanel {

+ 126 - 10
dist/preview release/gui/babylon.gui.js

@@ -8427,8 +8427,8 @@ var BABYLON;
                 configurable: true
             });
             VolumeBasedPanel.prototype._arrangeChildren = function () {
-                var cellWidth = 0;
-                var cellHeight = 0;
+                this._cellWidth = 0;
+                this._cellHeight = 0;
                 var rows = 0;
                 var columns = 0;
                 var controlCount = 0;
@@ -8444,11 +8444,11 @@ var BABYLON;
                     child.mesh.getWorldMatrix().multiplyToRef(currentInverseWorld, BABYLON.Tmp.Matrix[0]);
                     var boundingBox = child.mesh.getBoundingInfo().boundingBox;
                     var extendSize = BABYLON.Vector3.TransformNormal(boundingBox.extendSize, BABYLON.Tmp.Matrix[0]);
-                    cellWidth = Math.max(cellWidth, extendSize.x * 2);
-                    cellHeight = Math.max(cellHeight, extendSize.y * 2);
+                    this._cellWidth = Math.max(this._cellWidth, extendSize.x * 2);
+                    this._cellHeight = Math.max(this._cellHeight, extendSize.y * 2);
                 }
-                cellWidth += this.margin * 2;
-                cellHeight += this.margin * 2;
+                this._cellWidth += this.margin * 2;
+                this._cellHeight += this.margin * 2;
                 // Arrange
                 if (this._rowThenColum) {
                     columns = this._columns;
@@ -8458,14 +8458,14 @@ var BABYLON;
                     rows = this._rows;
                     columns = Math.ceil(controlCount / this._rows);
                 }
-                var startOffsetX = (columns * 0.5) * cellWidth;
-                var startOffsetY = (rows * 0.5) * cellHeight;
+                var startOffsetX = (columns * 0.5) * this._cellWidth;
+                var startOffsetY = (rows * 0.5) * this._cellHeight;
                 var nodeGrid = [];
                 var cellCounter = 0;
                 if (this._rowThenColum) {
                     for (var r = 0; r < rows; r++) {
                         for (var c = 0; c < columns; c++) {
-                            nodeGrid.push(new BABYLON.Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                            nodeGrid.push(new BABYLON.Vector3((c * this._cellWidth) - startOffsetX + this._cellWidth / 2, (r * this._cellHeight) - startOffsetY + this._cellHeight / 2, 0));
                             cellCounter++;
                             if (cellCounter > controlCount) {
                                 break;
@@ -8476,7 +8476,7 @@ var BABYLON;
                 else {
                     for (var c = 0; c < columns; c++) {
                         for (var r = 0; r < rows; r++) {
-                            nodeGrid.push(new BABYLON.Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                            nodeGrid.push(new BABYLON.Vector3((c * this._cellWidth) - startOffsetX + this._cellWidth / 2, (r * this._cellHeight) - startOffsetY + this._cellHeight / 2, 0));
                             cellCounter++;
                             if (cellCounter > controlCount) {
                                 break;
@@ -8493,6 +8493,10 @@ var BABYLON;
                     this._mapGridNode(child, nodeGrid[cellCounter]);
                     cellCounter++;
                 }
+                this._finalProcessing();
+            };
+            /** Child classes can implement this function to provide additional processing */
+            VolumeBasedPanel.prototype._finalProcessing = function () {
             };
             return VolumeBasedPanel;
         }(GUI.Container3D));
@@ -8615,6 +8619,118 @@ var BABYLON;
     var GUI;
     (function (GUI) {
         /**
+         * Class used to create a container panel where items get randomized planar mapping
+         */
+        var ScatterPanel = /** @class */ (function (_super) {
+            __extends(ScatterPanel, _super);
+            function ScatterPanel() {
+                var _this = _super !== null && _super.apply(this, arguments) || this;
+                _this._iteration = 100.0;
+                return _this;
+            }
+            Object.defineProperty(ScatterPanel.prototype, "iteration", {
+                /**
+                 * Gets or sets the number of iteration to use to scatter the controls (100 by default)
+                 */
+                get: function () {
+                    return this._iteration;
+                },
+                set: function (value) {
+                    var _this = this;
+                    if (this._iteration === value) {
+                        return;
+                    }
+                    this._iteration = value;
+                    BABYLON.Tools.SetImmediate(function () {
+                        _this._arrangeChildren();
+                    });
+                },
+                enumerable: true,
+                configurable: true
+            });
+            ScatterPanel.prototype._mapGridNode = function (control, nodePosition) {
+                var mesh = control.mesh;
+                var newPos = this._scatterMapping(nodePosition);
+                if (!mesh) {
+                    return;
+                }
+                switch (this.orientation) {
+                    case GUI.Container3D.FACEORIGIN_ORIENTATION:
+                    case GUI.Container3D.FACEFORWARD_ORIENTATION:
+                        mesh.lookAt(new BABYLON.Vector3(0, 0, -1));
+                        break;
+                    case GUI.Container3D.FACEFORWARDREVERSED_ORIENTATION:
+                    case GUI.Container3D.FACEORIGINREVERSED_ORIENTATION:
+                        mesh.lookAt(new BABYLON.Vector3(0, 0, 1));
+                        break;
+                }
+                control.position = newPos;
+            };
+            ScatterPanel.prototype._scatterMapping = function (source) {
+                source.x = (1.0 - Math.random() * 2.0) * this._cellWidth;
+                source.y = (1.0 - Math.random() * 2.0) * this._cellHeight;
+                return source;
+            };
+            ScatterPanel.prototype._finalProcessing = function () {
+                var meshes = [];
+                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                    var child = _a[_i];
+                    if (!child.mesh) {
+                        continue;
+                    }
+                    meshes.push(child.mesh);
+                }
+                for (var count = 0; count < this._iteration; count++) {
+                    meshes.sort(function (a, b) {
+                        var distance1 = a.position.lengthSquared();
+                        var distance2 = b.position.lengthSquared();
+                        if (distance1 < distance2) {
+                            return 1;
+                        }
+                        else if (distance1 > distance2) {
+                            return -1;
+                        }
+                        return 0;
+                    });
+                    var radiusPaddingSquared = Math.pow(this.margin, 2.0);
+                    var cellSize = Math.max(this._cellWidth, this._cellHeight);
+                    var difference2D = BABYLON.Tmp.Vector2[0];
+                    var difference = BABYLON.Tmp.Vector3[0];
+                    for (var i = 0; i < meshes.length - 1; i++) {
+                        for (var j = i + 1; j < meshes.length; j++) {
+                            if (i != j) {
+                                meshes[j].position.subtractToRef(meshes[i].position, difference);
+                                // Ignore Z axis
+                                difference2D.x = difference.x;
+                                difference2D.y = difference.y;
+                                var combinedRadius = cellSize;
+                                var distance = difference2D.lengthSquared() - radiusPaddingSquared;
+                                var minSeparation = Math.min(distance, radiusPaddingSquared);
+                                distance -= minSeparation;
+                                if (distance < (Math.pow(combinedRadius, 2.0))) {
+                                    difference2D.normalize();
+                                    difference.scaleInPlace((combinedRadius - Math.sqrt(distance)) * 0.5);
+                                    meshes[j].position.addInPlace(difference);
+                                    meshes[i].position.subtractInPlace(difference);
+                                }
+                            }
+                        }
+                    }
+                }
+            };
+            return ScatterPanel;
+        }(GUI.VolumeBasedPanel));
+        GUI.ScatterPanel = ScatterPanel;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        /**
          * Class used to create a container panel deployed on the surface of a cylinder
          */
         var CylinderPanel = /** @class */ (function (_super) {

Разлика између датотеке није приказан због своје велике величине
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


+ 21 - 0
dist/preview release/gui/babylon.gui.module.d.ts

@@ -2496,6 +2496,8 @@ declare module BABYLON.GUI {
         private _rows;
         private _rowThenColum;
         private _orientation;
+        protected _cellWidth: number;
+        protected _cellHeight: number;
         /**
          * Gets or sets the distance between elements
          */
@@ -2528,6 +2530,8 @@ declare module BABYLON.GUI {
         protected _arrangeChildren(): void;
         /** Child classes must implement this function to provide correct control positioning */
         protected abstract _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+        /** Child classes can implement this function to provide additional processing */
+        protected _finalProcessing(): void;
     }
 }
 
@@ -2560,6 +2564,23 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     /**
+     * Class used to create a container panel where items get randomized planar mapping
+     */
+    class ScatterPanel extends VolumeBasedPanel {
+        private _iteration;
+        /**
+         * Gets or sets the number of iteration to use to scatter the controls (100 by default)
+         */
+        iteration: float;
+        protected _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+        private _scatterMapping(source);
+        protected _finalProcessing(): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
      * Class used to create a container panel deployed on the surface of a cylinder
      */
     class CylinderPanel extends VolumeBasedPanel {

+ 7 - 4
dist/preview release/inspector/babylon.inspector.d.ts

@@ -473,7 +473,7 @@ declare module INSPECTOR {
         private _obj;
         /** The obj parent  */
         private _parentObj;
-        constructor(prop: string, obj: any, parentObj?: PropertyLine);
+        constructor(prop: string, obj: any, parentObj?: any);
         readonly name: string;
         value: any;
         readonly type: string;
@@ -1034,7 +1034,7 @@ declare module INSPECTOR {
 declare function Split(elements: HTMLElement[], options: any): any;
 declare module INSPECTOR {
     class GLTFTab extends Tab {
-        private static _LoaderExtensionSettings;
+        private static _LoaderDefaults;
         private _inspector;
         private _actions;
         private _detailsPanel;
@@ -1045,9 +1045,12 @@ declare module INSPECTOR {
         constructor(tabbar: TabBar, inspector: Inspector);
         dispose(): void;
         private _addImport();
-        private _getLoaderExtensionOverridesAsync();
-        private _updateLoaderExtensionDetails(settings);
+        private static _EnumeratePublic(obj, callback);
+        private _getLoaderDefaultsAsync();
+        private _openDetailsPanel();
         private _closeDetailsPanel();
+        private _showLoaderDefaults(defaults);
+        private _showLoaderExtensionDefaults(defaults);
         private _addExport();
         private static _IsSkyBox(transformNode);
     }

+ 90 - 55
dist/preview release/inspector/babylon.inspector.js

@@ -4083,7 +4083,7 @@ var INSPECTOR;
     INSPECTOR.StatsTab = StatsTab;
 })(INSPECTOR || (INSPECTOR = {}));
 
-/// <reference path="../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 /// <reference path="../../../dist/preview release/loaders/babylon.glTF2FileLoader.d.ts"/>
 /// <reference path="../../../dist/preview release/serializers/babylon.glTF2Serializer.d.ts"/>
 var __extends = (this && this.__extends) || (function () {
@@ -4098,7 +4098,6 @@ var __extends = (this && this.__extends) || (function () {
 })();
 var INSPECTOR;
 (function (INSPECTOR) {
-    ;
     var GLTFTab = /** @class */ (function (_super) {
         __extends(GLTFTab, _super);
         function GLTFTab(tabbar, inspector) {
@@ -4127,14 +4126,19 @@ var INSPECTOR;
         });
         /** @hidden */
         GLTFTab._Initialize = function () {
-            // Must register with OnPluginActivatedObservable as early as possible to
-            // override the default settings for each extension.
+            // Must register with OnPluginActivatedObservable as early as possible to override the loader defaults.
             BABYLON.SceneLoader.OnPluginActivatedObservable.add(function (loader) {
-                if (loader.name === "gltf" && GLTFTab._LoaderExtensionSettings) {
+                if (loader.name === "gltf" && GLTFTab._LoaderDefaults) {
+                    var defaults_1 = GLTFTab._LoaderDefaults;
+                    for (var key in defaults_1) {
+                        if (key !== "extensions") {
+                            loader[key] = GLTFTab._LoaderDefaults[key];
+                        }
+                    }
                     loader.onExtensionLoadedObservable.add(function (extension) {
-                        var settings = GLTFTab._LoaderExtensionSettings[extension.name];
-                        for (var settingName in settings) {
-                            extension[settingName] = settings[settingName];
+                        var extensionDefaults = defaults_1.extensions[extension.name];
+                        for (var key in extensionDefaults) {
+                            extension[key] = extensionDefaults[key];
                         }
                     });
                 }
@@ -4147,69 +4151,83 @@ var INSPECTOR;
         };
         GLTFTab.prototype._addImport = function () {
             var _this = this;
-            var importActions = INSPECTOR.Helpers.CreateDiv(null, this._actions);
-            this._getLoaderExtensionOverridesAsync().then(function (loaderExtensionSettings) {
-                var title = INSPECTOR.Helpers.CreateDiv('gltf-title', importActions);
-                title.textContent = 'Import';
-                var extensionActions = INSPECTOR.Helpers.CreateDiv('gltf-actions', importActions);
-                var extensionsTitle = INSPECTOR.Helpers.CreateDiv('gltf-title', extensionActions);
+            var importTitle = INSPECTOR.Helpers.CreateDiv('gltf-title', this._actions);
+            importTitle.textContent = 'Import';
+            var importActions = INSPECTOR.Helpers.CreateDiv('gltf-actions', this._actions);
+            this._getLoaderDefaultsAsync().then(function (defaults) {
+                importTitle.addEventListener('click', function (event) {
+                    _this._showLoaderDefaults(defaults);
+                    event.stopPropagation();
+                });
+                importActions.addEventListener('click', function (event) {
+                    _this._showLoaderDefaults(defaults);
+                    event.stopPropagation();
+                });
+                var extensionsTitle = INSPECTOR.Helpers.CreateDiv('gltf-title', importActions);
                 extensionsTitle.textContent = "Extensions";
                 var _loop_1 = function (extensionName) {
-                    var settings = loaderExtensionSettings[extensionName];
-                    var extensionAction = INSPECTOR.Helpers.CreateDiv('gltf-action', extensionActions);
+                    var extensionDefaults = defaults.extensions[extensionName];
+                    var extensionAction = INSPECTOR.Helpers.CreateDiv('gltf-action', importActions);
                     extensionAction.addEventListener('click', function (event) {
-                        if (_this._updateLoaderExtensionDetails(settings)) {
+                        if (_this._showLoaderExtensionDefaults(extensionDefaults)) {
                             event.stopPropagation();
                         }
                     });
                     var checkbox = INSPECTOR.Helpers.CreateElement('span', 'gltf-checkbox', extensionAction);
-                    if (settings.enabled) {
+                    if (extensionDefaults.enabled) {
                         checkbox.classList.add('action', 'active');
                     }
                     checkbox.addEventListener('click', function () {
                         checkbox.classList.toggle('active');
-                        settings.enabled = checkbox.classList.contains('active');
+                        extensionDefaults.enabled = checkbox.classList.contains('active');
                     });
                     var label = INSPECTOR.Helpers.CreateElement('span', null, extensionAction);
                     label.textContent = extensionName;
                 };
-                for (var extensionName in loaderExtensionSettings) {
+                for (var extensionName in defaults.extensions) {
                     _loop_1(extensionName);
                 }
             });
         };
-        GLTFTab.prototype._getLoaderExtensionOverridesAsync = function () {
-            if (GLTFTab._LoaderExtensionSettings) {
-                return Promise.resolve(GLTFTab._LoaderExtensionSettings);
+        GLTFTab._EnumeratePublic = function (obj, callback) {
+            for (var key in obj) {
+                if (key !== "name" && key[0] !== '_') {
+                    var value = obj[key];
+                    var type = typeof value;
+                    if (type !== "object" && type !== "function" && type !== "undefined") {
+                        callback(key, value);
+                    }
+                }
+            }
+        };
+        GLTFTab.prototype._getLoaderDefaultsAsync = function () {
+            if (GLTFTab._LoaderDefaults) {
+                return Promise.resolve(GLTFTab._LoaderDefaults);
             }
-            var loaderExtensionSettings = {};
+            var defaults = {
+                extensions: {}
+            };
             var engine = new BABYLON.NullEngine();
             var scene = new BABYLON.Scene(engine);
-            var loader = new BABYLON.GLTF2.GLTFLoader();
+            var loader = new BABYLON.GLTFFileLoader();
+            GLTFTab._EnumeratePublic(loader, function (key, value) {
+                defaults[key] = value;
+            });
             loader.onExtensionLoadedObservable.add(function (extension) {
-                loaderExtensionSettings[extension.name] = {};
-                var settings = loaderExtensionSettings[extension.name];
-                for (var _i = 0, _a = Object.keys(extension); _i < _a.length; _i++) {
-                    var key = _a[_i];
-                    if (key !== "name" && key[0] !== '_') {
-                        var value = extension[key];
-                        if (typeof value !== "object") {
-                            settings[key] = value;
-                        }
-                    }
-                }
+                var extensionDefaults = {};
+                GLTFTab._EnumeratePublic(extension, function (key, value) {
+                    extensionDefaults[key] = value;
+                });
+                defaults.extensions[extension.name] = extensionDefaults;
             });
-            var data = { json: {}, bin: null };
-            return loader.importMeshAsync([], scene, data, "").then(function () {
+            var data = '{ "asset": { "version": "2.0" }, "scenes": [ { } ] }';
+            return loader.loadAsync(scene, data, "").then(function () {
                 scene.dispose();
                 engine.dispose();
-                return (GLTFTab._LoaderExtensionSettings = loaderExtensionSettings);
+                return (GLTFTab._LoaderDefaults = defaults);
             });
         };
-        GLTFTab.prototype._updateLoaderExtensionDetails = function (settings) {
-            if (Object.keys(settings).length === 1) {
-                return false;
-            }
+        GLTFTab.prototype._openDetailsPanel = function () {
             if (!this._detailsPanel) {
                 this._detailsPanel = new INSPECTOR.DetailPanel();
                 this._panel.appendChild(this._detailsPanel.toHtml());
@@ -4220,14 +4238,7 @@ var INSPECTOR;
                 });
             }
             this._detailsPanel.clean();
-            var details = new Array();
-            for (var key in settings) {
-                if (key !== "enabled") {
-                    details.push(new INSPECTOR.PropertyLine(new INSPECTOR.Property(key, settings)));
-                }
-            }
-            this._detailsPanel.details = details;
-            return true;
+            return this._detailsPanel;
         };
         GLTFTab.prototype._closeDetailsPanel = function () {
             if (this._detailsPanel) {
@@ -4240,11 +4251,35 @@ var INSPECTOR;
                 delete this._split;
             }
         };
+        GLTFTab.prototype._showLoaderDefaults = function (defaults) {
+            var detailsPanel = this._openDetailsPanel();
+            var details = new Array();
+            for (var key in defaults) {
+                if (key !== "extensions") {
+                    details.push(new INSPECTOR.PropertyLine(new INSPECTOR.Property(key, defaults, this._inspector.scene)));
+                }
+            }
+            detailsPanel.details = details;
+        };
+        GLTFTab.prototype._showLoaderExtensionDefaults = function (defaults) {
+            if (Object.keys(defaults).length === 1) {
+                return false;
+            }
+            var detailsPanel = this._openDetailsPanel();
+            var details = new Array();
+            for (var key in defaults) {
+                if (key !== "enabled") {
+                    details.push(new INSPECTOR.PropertyLine(new INSPECTOR.Property(key, defaults, this._inspector.scene)));
+                }
+            }
+            detailsPanel.details = details;
+            return true;
+        };
         GLTFTab.prototype._addExport = function () {
             var _this = this;
-            var exportActions = INSPECTOR.Helpers.CreateDiv(null, this._actions);
-            var title = INSPECTOR.Helpers.CreateDiv('gltf-title', exportActions);
-            title.textContent = 'Export';
+            var exportTitle = INSPECTOR.Helpers.CreateDiv('gltf-title', this._actions);
+            exportTitle.textContent = 'Export';
+            var exportActions = INSPECTOR.Helpers.CreateDiv('gltf-actions', this._actions);
             var name = INSPECTOR.Helpers.CreateInput('gltf-input', exportActions);
             name.placeholder = "File name...";
             var button = INSPECTOR.Helpers.CreateElement('button', 'gltf-button', exportActions);
@@ -4269,7 +4304,7 @@ var INSPECTOR;
             }
             return false;
         };
-        GLTFTab._LoaderExtensionSettings = null;
+        GLTFTab._LoaderDefaults = null;
         return GLTFTab;
     }(INSPECTOR.Tab));
     INSPECTOR.GLTFTab = GLTFTab;

Разлика између датотеке није приказан због своје велике величине
+ 2 - 2
dist/preview release/inspector/babylon.inspector.min.js


+ 27 - 98
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -73,89 +73,15 @@ declare module BABYLON {
          */
         COMPLETE = 2,
     }
-    /**
-     * Loader interface.
-     */
+    /** @hidden */
     interface IGLTFLoader extends IDisposable {
-        /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
-         * Loader state or null if the loader is not active.
-         */
-        state: Nullable<GLTFLoaderState>;
-        /**
-         * Imports meshes from the given data and adds them to the scene.
-         */
+        readonly state: Nullable<GLTFLoaderState>;
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Loads all objects from the given data and adds them to the scene.
-         */
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     /**
@@ -163,9 +89,9 @@ declare module BABYLON {
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         /** @hidden */
-        static _CreateGLTFLoaderV1: () => IGLTFLoader;
+        static _CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         /** @hidden */
-        static _CreateGLTFLoaderV2: () => IGLTFLoader;
+        static _CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
          */
@@ -217,6 +143,22 @@ declare module BABYLON {
         /** @hidden */
         _normalizeAnimationGroupsToBeginAtZero: boolean;
         /**
+         * Defines if the loader logging is enabled.
+         */
+        loggingEnabled: boolean;
+        /**
+         * Observable raised when the loader logs a message.
+         */
+        readonly onLogObservable: Observable<string>;
+        private _logIndentLevel;
+        private static readonly _logSpaces;
+        /** @hidden */
+        _log(message: string): void;
+        /** @hidden */
+        _logOpen(message: string): void;
+        /** @hidden */
+        _logClose(): void;
+        /**
          * Function called before loading a url referenced by the asset.
          */
         preprocessUrlAsync: (url: string) => Promise<string>;
@@ -261,7 +203,7 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
          */
-        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<void>;
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately before the loader is disposed.
@@ -270,7 +212,7 @@ declare module BABYLON {
         /**
          * Observable raised after the loader is disposed.
          */
-        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<void>;
         private _onDisposeObserver;
         /**
          * Callback raised after the loader is disposed.
@@ -308,6 +250,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
+        /** @hidden */
+        _clear(): void;
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
          * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
@@ -358,9 +302,9 @@ declare module BABYLON {
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         private _parse(data);
         private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private _parseBinary(data);
+        private _parseV1(binaryReader);
+        private _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -760,21 +704,6 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        compileMaterials: boolean;
-        useClipPlane: boolean;
-        compileShadowGenerators: boolean;
-        transparencyAsCoverage: boolean;
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         state: Nullable<GLTFLoaderState>;
         dispose(): void;
         private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress?, onError?);

+ 66 - 53
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -92,6 +92,15 @@ var BABYLON;
             /** @hidden */
             this._normalizeAnimationGroupsToBeginAtZero = true;
             /**
+             * Defines if the loader logging is enabled.
+             */
+            this.loggingEnabled = false;
+            /**
+             * Observable raised when the loader logs a message.
+             */
+            this.onLogObservable = new BABYLON.Observable();
+            this._logIndentLevel = 0;
+            /**
              * Function called before loading a url referenced by the asset.
              */
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
@@ -153,6 +162,23 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /** @hidden */
+        GLTFFileLoader.prototype._log = function (message) {
+            if (this.loggingEnabled) {
+                var spaces = GLTFFileLoader._logSpaces.substr(0, this._logIndentLevel * 2);
+                this.onLogObservable.notifyObservers("" + spaces + message);
+                BABYLON.Tools.Log("" + spaces + message);
+            }
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logOpen = function (message) {
+            this._log(message);
+            this._logIndentLevel++;
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logClose = function () {
+            --this._logIndentLevel;
+        };
         Object.defineProperty(GLTFFileLoader.prototype, "onMeshLoaded", {
             /**
              * Callback raised when the loader creates a mesh after parsing the glTF properties of the mesh.
@@ -274,6 +300,12 @@ var BABYLON;
                 this._loader.dispose();
                 this._loader = null;
             }
+            this._clear();
+            this.onDisposeObservable.notifyObservers(undefined);
+            this.onDisposeObservable.clear();
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._clear = function () {
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
@@ -281,8 +313,6 @@ var BABYLON;
             this.onCameraLoadedObservable.clear();
             this.onCompleteObservable.clear();
             this.onExtensionLoadedObservable.clear();
-            this.onDisposeObservable.notifyObservers(this);
-            this.onDisposeObservable.clear();
         };
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
@@ -359,9 +389,16 @@ var BABYLON;
         GLTFFileLoader.prototype._parse = function (data) {
             var parsedData;
             if (data instanceof ArrayBuffer) {
-                parsedData = GLTFFileLoader._parseBinary(data);
+                if (this.loggingEnabled) {
+                    this._log("Parsing binary");
+                }
+                parsedData = this._parseBinary(data);
             }
             else {
+                if (this.loggingEnabled) {
+                    this._log("Parsing JSON");
+                    this._log("JSON length: " + data.length);
+                }
                 parsedData = {
                     json: JSON.parse(data),
                     bin: null
@@ -372,9 +409,16 @@ var BABYLON;
             return parsedData;
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
-            var _this = this;
-            var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
+            if (this.loggingEnabled) {
+                this._log("Asset version: " + asset.version);
+                if (asset.minVersion) {
+                    this._log("Asset minimum version: " + asset.minVersion);
+                }
+                if (asset.generator) {
+                    this._log("Asset generator: " + asset.generator);
+                }
+            }
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
                 throw new Error("Invalid version: " + asset.version);
@@ -384,7 +428,7 @@ var BABYLON;
                 if (!minVersion) {
                     throw new Error("Invalid minimum version: " + asset.minVersion);
                 }
-                if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
+                if (GLTFFileLoader._compareVersion(minVersion, { major: 2, minor: 0 }) > 0) {
                     throw new Error("Incompatible minimum version: " + asset.minVersion);
                 }
             }
@@ -396,48 +440,31 @@ var BABYLON;
             if (!createLoader) {
                 throw new Error("Unsupported version: " + asset.version);
             }
-            var loader = createLoader();
-            loader.coordinateSystemMode = this.coordinateSystemMode;
-            loader.animationStartMode = this.animationStartMode;
-            loader.compileMaterials = this.compileMaterials;
-            loader.useClipPlane = this.useClipPlane;
-            loader.compileShadowGenerators = this.compileShadowGenerators;
-            loader.transparencyAsCoverage = this.transparencyAsCoverage;
-            loader._normalizeAnimationGroupsToBeginAtZero = this._normalizeAnimationGroupsToBeginAtZero;
-            loader.preprocessUrlAsync = this.preprocessUrlAsync;
-            loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
-            loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
-            loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
-            loader.onCameraLoadedObservable.add(function (camera) { return _this.onCameraLoadedObservable.notifyObservers(camera); });
-            loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onCompleteObservable.add(function () {
-                _this.onMeshLoadedObservable.clear();
-                _this.onTextureLoadedObservable.clear();
-                _this.onMaterialLoadedObservable.clear();
-                _this.onCameraLoadedObservable.clear();
-                _this.onExtensionLoadedObservable.clear();
-                _this.onCompleteObservable.notifyObservers(_this);
-                _this.onCompleteObservable.clear();
-            });
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader.prototype._parseBinary = function (data) {
             var Binary = {
                 Magic: 0x46546C67
             };
+            if (this.loggingEnabled) {
+                this._log("Binary length: " + data.byteLength);
+            }
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
                 throw new Error("Unexpected magic: " + magic);
             }
             var version = binaryReader.readUint32();
+            if (this.loggingEnabled) {
+                this._log("Binary version: " + version);
+            }
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return this._parseV1(binaryReader);
+                case 2: return this._parseV2(binaryReader);
             }
             throw new Error("Unsupported version: " + version);
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV1 = function (binaryReader) {
             var ContentFormat = {
                 JSON: 0
             };
@@ -464,7 +491,7 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV2 = function (binaryReader) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
@@ -555,6 +582,7 @@ var BABYLON;
          * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
+        GLTFFileLoader._logSpaces = "                                ";
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -1978,22 +2006,6 @@ var BABYLON;
         */
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader() {
-                // #region Stubs for IGLTFLoader interface
-                this.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.AUTO;
-                this.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.FIRST;
-                this.compileMaterials = false;
-                this.useClipPlane = false;
-                this.compileShadowGenerators = false;
-                this.transparencyAsCoverage = false;
-                this._normalizeAnimationGroupsToBeginAtZero = true;
-                this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
-                this.onMeshLoadedObservable = new BABYLON.Observable();
-                this.onTextureLoadedObservable = new BABYLON.Observable();
-                this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onCameraLoadedObservable = new BABYLON.Observable();
-                this.onCompleteObservable = new BABYLON.Observable();
-                this.onDisposeObservable = new BABYLON.Observable();
-                this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.state = null;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -2003,8 +2015,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
-            GLTFLoader.prototype.dispose = function () { };
-            // #endregion
+            GLTFLoader.prototype.dispose = function () {
+                // do nothing
+            };
             GLTFLoader.prototype._importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;

Разлика између датотеке није приказан због своје велике величине
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 30 - 187
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -73,89 +73,15 @@ declare module BABYLON {
          */
         COMPLETE = 2,
     }
-    /**
-     * Loader interface.
-     */
+    /** @hidden */
     interface IGLTFLoader extends IDisposable {
-        /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
-         * Loader state or null if the loader is not active.
-         */
-        state: Nullable<GLTFLoaderState>;
-        /**
-         * Imports meshes from the given data and adds them to the scene.
-         */
+        readonly state: Nullable<GLTFLoaderState>;
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Loads all objects from the given data and adds them to the scene.
-         */
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     /**
@@ -163,9 +89,9 @@ declare module BABYLON {
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         /** @hidden */
-        static _CreateGLTFLoaderV1: () => IGLTFLoader;
+        static _CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         /** @hidden */
-        static _CreateGLTFLoaderV2: () => IGLTFLoader;
+        static _CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
          */
@@ -217,6 +143,22 @@ declare module BABYLON {
         /** @hidden */
         _normalizeAnimationGroupsToBeginAtZero: boolean;
         /**
+         * Defines if the loader logging is enabled.
+         */
+        loggingEnabled: boolean;
+        /**
+         * Observable raised when the loader logs a message.
+         */
+        readonly onLogObservable: Observable<string>;
+        private _logIndentLevel;
+        private static readonly _logSpaces;
+        /** @hidden */
+        _log(message: string): void;
+        /** @hidden */
+        _logOpen(message: string): void;
+        /** @hidden */
+        _logClose(): void;
+        /**
          * Function called before loading a url referenced by the asset.
          */
         preprocessUrlAsync: (url: string) => Promise<string>;
@@ -261,7 +203,7 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
          */
-        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<void>;
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately before the loader is disposed.
@@ -270,7 +212,7 @@ declare module BABYLON {
         /**
          * Observable raised after the loader is disposed.
          */
-        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<void>;
         private _onDisposeObserver;
         /**
          * Callback raised after the loader is disposed.
@@ -308,6 +250,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
+        /** @hidden */
+        _clear(): void;
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
          * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
@@ -358,9 +302,9 @@ declare module BABYLON {
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         private _parse(data);
         private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private _parseBinary(data);
+        private _parseV1(binaryReader);
+        private _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -484,17 +428,12 @@ declare module BABYLON.GLTF2 {
  * Defines the module used to import/export glTF 2.0 assets
  */
 declare module BABYLON.GLTF2 {
-    /**
-     * Loader for loading a glTF 2.0 asset
-     */
+    /** @hidden */
     class GLTFLoader implements IGLTFLoader {
-        /** @hidden */
+        _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
-        /** @hidden */
         _babylonScene: Scene;
-        /** @hidden */
         _completePromises: Promise<void>[];
-        /** @hidden */
         _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
@@ -507,102 +446,19 @@ declare module BABYLON.GLTF2 {
         private _requests;
         private static _ExtensionNames;
         private static _ExtensionFactories;
-        /** @hidden */
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
          * Loader state or null if the loader is not active.
          */
         readonly state: Nullable<GLTFLoaderState>;
-        /**
-         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
-         */
+        constructor(parent: GLTFFileLoader);
         dispose(): void;
-        /**
-         * Imports one or more meshes from the loaded glTF data and adds them to the scene
-         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-         * @param scene the scene the meshes should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise containg the loaded meshes, particles, skeletons and animations
-         */
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Imports all objects from the loaded glTF data and adds them to the scene
-         * @param scene the scene the objects should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise which completes when objects have been loaded to the scene
-         */
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadAsync(nodes);
         private _loadData(data);
@@ -611,14 +467,12 @@ declare module BABYLON.GLTF2 {
         private _checkExtensions();
         private _createRootNode();
         private _loadNodesAsync(nodes);
-        /** @hidden */
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
         private _getAnimationGroups();
         private _startAnimations();
-        /** @hidden */
         _loadNodeAsync(context: string, node: _ILoaderNode): Promise<void>;
         private _loadMeshAsync(context, node, mesh, babylonMesh);
         private _loadPrimitiveAsync(context, node, mesh, primitive, babylonMesh);
@@ -639,31 +493,22 @@ declare module BABYLON.GLTF2 {
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
-        /** @hidden */
         _loadBufferViewAsync(context: string, bufferView: _ILoaderBufferView): Promise<ArrayBufferView>;
         private _loadIndicesAccessorAsync(context, accessor);
         private _loadFloatAccessorAsync(context, accessor);
-        /** @hidden */
         _loadVertexBufferViewAsync(context: string, bufferView: _ILoaderBufferView, kind: string): Promise<Buffer>;
         private _loadVertexAccessorAsync(context, accessor, kind);
         private _getDefaultMaterial(drawMode);
         private _loadMaterialMetallicRoughnessPropertiesAsync(context, material, babylonMaterial);
-        /** @hidden */
         _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Promise<void>;
-        /** @hidden */
         _createMaterial(name: string, drawMode: number): PBRMaterial;
-        /** @hidden */
         _loadMaterialBasePropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void>;
-        /** @hidden */
         _loadMaterialAlphaProperties(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): void;
-        /** @hidden */
         _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
         private _loadImageAsync(context, image);
-        /** @hidden */
         _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
         private _onProgress();
-        /** @hidden */
         static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
         private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
@@ -673,8 +518,6 @@ declare module BABYLON.GLTF2 {
         private static _GetDrawMode(context, mode);
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
-        private _clear();
-        /** @hidden */
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
 }

+ 185 - 226
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -92,6 +92,15 @@ var BABYLON;
             /** @hidden */
             this._normalizeAnimationGroupsToBeginAtZero = true;
             /**
+             * Defines if the loader logging is enabled.
+             */
+            this.loggingEnabled = false;
+            /**
+             * Observable raised when the loader logs a message.
+             */
+            this.onLogObservable = new BABYLON.Observable();
+            this._logIndentLevel = 0;
+            /**
              * Function called before loading a url referenced by the asset.
              */
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
@@ -153,6 +162,23 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /** @hidden */
+        GLTFFileLoader.prototype._log = function (message) {
+            if (this.loggingEnabled) {
+                var spaces = GLTFFileLoader._logSpaces.substr(0, this._logIndentLevel * 2);
+                this.onLogObservable.notifyObservers("" + spaces + message);
+                BABYLON.Tools.Log("" + spaces + message);
+            }
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logOpen = function (message) {
+            this._log(message);
+            this._logIndentLevel++;
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logClose = function () {
+            --this._logIndentLevel;
+        };
         Object.defineProperty(GLTFFileLoader.prototype, "onMeshLoaded", {
             /**
              * Callback raised when the loader creates a mesh after parsing the glTF properties of the mesh.
@@ -274,6 +300,12 @@ var BABYLON;
                 this._loader.dispose();
                 this._loader = null;
             }
+            this._clear();
+            this.onDisposeObservable.notifyObservers(undefined);
+            this.onDisposeObservable.clear();
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._clear = function () {
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
@@ -281,8 +313,6 @@ var BABYLON;
             this.onCameraLoadedObservable.clear();
             this.onCompleteObservable.clear();
             this.onExtensionLoadedObservable.clear();
-            this.onDisposeObservable.notifyObservers(this);
-            this.onDisposeObservable.clear();
         };
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
@@ -359,9 +389,16 @@ var BABYLON;
         GLTFFileLoader.prototype._parse = function (data) {
             var parsedData;
             if (data instanceof ArrayBuffer) {
-                parsedData = GLTFFileLoader._parseBinary(data);
+                if (this.loggingEnabled) {
+                    this._log("Parsing binary");
+                }
+                parsedData = this._parseBinary(data);
             }
             else {
+                if (this.loggingEnabled) {
+                    this._log("Parsing JSON");
+                    this._log("JSON length: " + data.length);
+                }
                 parsedData = {
                     json: JSON.parse(data),
                     bin: null
@@ -372,9 +409,16 @@ var BABYLON;
             return parsedData;
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
-            var _this = this;
-            var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
+            if (this.loggingEnabled) {
+                this._log("Asset version: " + asset.version);
+                if (asset.minVersion) {
+                    this._log("Asset minimum version: " + asset.minVersion);
+                }
+                if (asset.generator) {
+                    this._log("Asset generator: " + asset.generator);
+                }
+            }
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
                 throw new Error("Invalid version: " + asset.version);
@@ -384,7 +428,7 @@ var BABYLON;
                 if (!minVersion) {
                     throw new Error("Invalid minimum version: " + asset.minVersion);
                 }
-                if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
+                if (GLTFFileLoader._compareVersion(minVersion, { major: 2, minor: 0 }) > 0) {
                     throw new Error("Incompatible minimum version: " + asset.minVersion);
                 }
             }
@@ -396,48 +440,31 @@ var BABYLON;
             if (!createLoader) {
                 throw new Error("Unsupported version: " + asset.version);
             }
-            var loader = createLoader();
-            loader.coordinateSystemMode = this.coordinateSystemMode;
-            loader.animationStartMode = this.animationStartMode;
-            loader.compileMaterials = this.compileMaterials;
-            loader.useClipPlane = this.useClipPlane;
-            loader.compileShadowGenerators = this.compileShadowGenerators;
-            loader.transparencyAsCoverage = this.transparencyAsCoverage;
-            loader._normalizeAnimationGroupsToBeginAtZero = this._normalizeAnimationGroupsToBeginAtZero;
-            loader.preprocessUrlAsync = this.preprocessUrlAsync;
-            loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
-            loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
-            loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
-            loader.onCameraLoadedObservable.add(function (camera) { return _this.onCameraLoadedObservable.notifyObservers(camera); });
-            loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onCompleteObservable.add(function () {
-                _this.onMeshLoadedObservable.clear();
-                _this.onTextureLoadedObservable.clear();
-                _this.onMaterialLoadedObservable.clear();
-                _this.onCameraLoadedObservable.clear();
-                _this.onExtensionLoadedObservable.clear();
-                _this.onCompleteObservable.notifyObservers(_this);
-                _this.onCompleteObservable.clear();
-            });
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader.prototype._parseBinary = function (data) {
             var Binary = {
                 Magic: 0x46546C67
             };
+            if (this.loggingEnabled) {
+                this._log("Binary length: " + data.byteLength);
+            }
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
                 throw new Error("Unexpected magic: " + magic);
             }
             var version = binaryReader.readUint32();
+            if (this.loggingEnabled) {
+                this._log("Binary version: " + version);
+            }
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return this._parseV1(binaryReader);
+                case 2: return this._parseV2(binaryReader);
             }
             throw new Error("Unsupported version: " + version);
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV1 = function (binaryReader) {
             var ContentFormat = {
                 JSON: 0
             };
@@ -464,7 +491,7 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV2 = function (binaryReader) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
@@ -555,6 +582,7 @@ var BABYLON;
          * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
+        GLTFFileLoader._logSpaces = "                                ";
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -593,7 +621,7 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFFileLoader.js.map
 
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
-/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 
 //# sourceMappingURL=babylon.glTFLoaderInterfaces.js.map
 
@@ -617,14 +645,10 @@ var BABYLON;
             };
             return _ArrayItem;
         }());
-        /**
-         * Loader for loading a glTF 2.0 asset
-         */
+        /** @hidden */
         var GLTFLoader = /** @class */ (function () {
-            function GLTFLoader() {
-                /** @hidden */
+            function GLTFLoader(parent) {
                 this._completePromises = new Array();
-                /** @hidden */
                 this._onReadyObservable = new BABYLON.Observable();
                 this._disposed = false;
                 this._state = null;
@@ -632,71 +656,8 @@ var BABYLON;
                 this._defaultSampler = {};
                 this._defaultBabylonMaterials = {};
                 this._requests = new Array();
-                /**
-                 * Mode that determines the coordinate system to use.
-                 */
-                this.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.AUTO;
-                /**
-                 * Mode that determines what animations will start.
-                 */
-                this.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.FIRST;
-                /**
-                 * Defines if the loader should compile materials.
-                 */
-                this.compileMaterials = false;
-                /**
-                 * Defines if the loader should also compile materials with clip planes.
-                 */
-                this.useClipPlane = false;
-                /**
-                 * Defines if the loader should compile shadow generators.
-                 */
-                this.compileShadowGenerators = false;
-                /**
-                 * Defines if the Alpha blended materials are only applied as coverage.
-                 * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-                 * If true, no extra effects are applied to transparent pixels.
-                 */
-                this.transparencyAsCoverage = false;
-                /** @hidden */
-                this._normalizeAnimationGroupsToBeginAtZero = true;
-                /**
-                 * Function called before loading a url referenced by the asset.
-                 */
-                this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
-                /**
-                 * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-                 */
-                this.onMeshLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-                 */
-                this.onTextureLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-                 */
-                this.onMaterialLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-                 */
-                this.onCameraLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-                 * For assets with LODs, raised when all of the LODs are complete.
-                 * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-                 */
-                this.onCompleteObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised after the loader is disposed.
-                 */
-                this.onDisposeObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised after a loader extension is created.
-                 * Set additional options for a loader extension in this event.
-                 */
-                this.onExtensionLoadedObservable = new BABYLON.Observable();
+                this._parent = parent;
             }
-            /** @hidden */
             GLTFLoader._Register = function (name, factory) {
                 if (GLTFLoader._ExtensionFactories[name]) {
                     BABYLON.Tools.Error("Extension with the name '" + name + "' already exists");
@@ -716,27 +677,28 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
-            /**
-             * Disposes the loader, releases resources during load, and cancels any outstanding requests.
-             */
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
                 }
                 this._disposed = true;
-                this.onDisposeObservable.notifyObservers(this);
-                this.onDisposeObservable.clear();
-                this._clear();
+                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
+                    var request = _a[_i];
+                    request.abort();
+                }
+                this._requests.length = 0;
+                delete this._gltf;
+                delete this._babylonScene;
+                this._completePromises.length = 0;
+                this._onReadyObservable.clear();
+                for (var name_1 in this._extensions) {
+                    this._extensions[name_1].dispose();
+                }
+                this._extensions = {};
+                delete this._rootBabylonMesh;
+                delete this._progressCallback;
+                this._parent._clear();
             };
-            /**
-             * Imports one or more meshes from the loaded glTF data and adds them to the scene
-             * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-             * @param scene the scene the meshes should be added to
-             * @param data the glTF data to load
-             * @param rootUrl root url to load from
-             * @param onProgress event that fires when loading progress has occured
-             * @returns a promise containg the loaded meshes, particles, skeletons and animations
-             */
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return Promise.resolve().then(function () {
@@ -774,14 +736,6 @@ var BABYLON;
                     });
                 });
             };
-            /**
-             * Imports all objects from the loaded glTF data and adds them to the scene
-             * @param scene the scene the objects should be added to
-             * @param data the glTF data to load
-             * @param rootUrl root url to load from
-             * @param onProgress event that fires when loading progress has occured
-             * @returns a promise which completes when objects have been loaded to the scene
-             */
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return Promise.resolve().then(function () {
@@ -796,6 +750,7 @@ var BABYLON;
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this._state = BABYLON.GLTFLoaderState.LOADING;
+                    _this._parent._log("Loading");
                     _this._loadExtensions();
                     _this._checkExtensions();
                     var promises = new Array();
@@ -806,14 +761,15 @@ var BABYLON;
                         var scene = GLTFLoader._GetProperty("#/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                         promises.push(_this._loadSceneAsync("#/scenes/" + scene._index, scene));
                     }
-                    if (_this.compileMaterials) {
+                    if (_this._parent.compileMaterials) {
                         promises.push(_this._compileMaterialsAsync());
                     }
-                    if (_this.compileShadowGenerators) {
+                    if (_this._parent.compileShadowGenerators) {
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
                         _this._state = BABYLON.GLTFLoaderState.READY;
+                        _this._parent._log("Ready");
                         _this._onReadyObservable.notifyObservers(_this);
                         _this._startAnimations();
                     });
@@ -825,12 +781,13 @@ var BABYLON;
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
                                     _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this.onCompleteObservable.notifyObservers(_this);
-                                    _this.onCompleteObservable.clear();
-                                    _this._clear();
+                                    _this._parent._log("Complete");
+                                    _this._parent.onCompleteObservable.notifyObservers(undefined);
+                                    _this._parent.onCompleteObservable.clear();
+                                    _this.dispose();
                                 }).catch(function (error) {
                                     BABYLON.Tools.Error("glTF Loader: " + error.message);
-                                    _this._clear();
+                                    _this.dispose();
                                 });
                             }
                         });
@@ -839,7 +796,7 @@ var BABYLON;
                 }).catch(function (error) {
                     if (!_this._disposed) {
                         BABYLON.Tools.Error("glTF Loader: " + error.message);
-                        _this._clear();
+                        _this.dispose();
                         throw error;
                     }
                 });
@@ -896,20 +853,20 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadExtensions = function () {
                 for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
-                    var name_1 = _a[_i];
-                    var extension = GLTFLoader._ExtensionFactories[name_1](this);
-                    this._extensions[name_1] = extension;
-                    this.onExtensionLoadedObservable.notifyObservers(extension);
+                    var name_2 = _a[_i];
+                    var extension = GLTFLoader._ExtensionFactories[name_2](this);
+                    this._extensions[name_2] = extension;
+                    this._parent.onExtensionLoadedObservable.notifyObservers(extension);
                 }
-                this.onExtensionLoadedObservable.clear();
+                this._parent.onExtensionLoadedObservable.clear();
             };
             GLTFLoader.prototype._checkExtensions = function () {
                 if (this._gltf.extensionsRequired) {
                     for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
-                        var name_2 = _a[_i];
-                        var extension = this._extensions[name_2];
+                        var name_3 = _a[_i];
+                        var extension = this._extensions[name_3];
                         if (!extension || !extension.enabled) {
-                            throw new Error("Require extension " + name_2 + " is not available");
+                            throw new Error("Require extension " + name_3 + " is not available");
                         }
                     }
                 }
@@ -918,7 +875,7 @@ var BABYLON;
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 this._rootBabylonMesh.setEnabled(false);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
-                switch (this.coordinateSystemMode) {
+                switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                         if (!this._babylonScene.useRightHandedSystem) {
                             rootNode.rotation = [0, 1, 0, 0];
@@ -932,10 +889,10 @@ var BABYLON;
                         break;
                     }
                     default: {
-                        throw new Error("Invalid coordinate system mode (" + this.coordinateSystemMode + ")");
+                        throw new Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
                     }
                 }
-                this.onMeshLoadedObservable.notifyObservers(this._rootBabylonMesh);
+                this._parent.onMeshLoadedObservable.notifyObservers(this._rootBabylonMesh);
                 return rootNode;
             };
             GLTFLoader.prototype._loadNodesAsync = function (nodes) {
@@ -947,19 +904,22 @@ var BABYLON;
                 promises.push(this._loadAnimationsAsync());
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadSceneAsync = function (context, scene) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
                 if (promise) {
                     return promise;
                 }
                 var promises = new Array();
-                for (var _i = 0, _a = scene.nodes; _i < _a.length; _i++) {
-                    var index = _a[_i];
-                    var node = GLTFLoader._GetProperty(context + "/nodes/" + index, this._gltf.nodes, index);
-                    promises.push(this._loadNodeAsync("#/nodes/" + node._index, node));
+                this._parent._logOpen(context + " " + (scene.name || ""));
+                if (scene.nodes) {
+                    for (var _i = 0, _a = scene.nodes; _i < _a.length; _i++) {
+                        var index = _a[_i];
+                        var node = GLTFLoader._GetProperty(context + "/nodes/" + index, this._gltf.nodes, index);
+                        promises.push(this._loadNodeAsync("#/nodes/" + node._index, node));
+                    }
                 }
                 promises.push(this._loadAnimationsAsync());
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._forEachPrimitive = function (node, callback) {
@@ -1021,7 +981,7 @@ var BABYLON;
                 return animationGroups;
             };
             GLTFLoader.prototype._startAnimations = function () {
-                switch (this.animationStartMode) {
+                switch (this._parent.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
                         break;
@@ -1042,12 +1002,11 @@ var BABYLON;
                         break;
                     }
                     default: {
-                        BABYLON.Tools.Error("Invalid animation start mode (" + this.animationStartMode + ")");
+                        BABYLON.Tools.Error("Invalid animation start mode (" + this._parent.animationStartMode + ")");
                         return;
                     }
                 }
             };
-            /** @hidden */
             GLTFLoader.prototype._loadNodeAsync = function (context, node) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadNodeAsync(this, context, node);
                 if (promise) {
@@ -1057,6 +1016,7 @@ var BABYLON;
                     throw new Error(context + ": Invalid recursive node hierarchy");
                 }
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (node.name || ""));
                 var babylonMesh = new BABYLON.Mesh(node.name || "node" + node._index, this._babylonScene, node._parent ? node._parent._babylonMesh : null);
                 node._babylonMesh = babylonMesh;
                 GLTFLoader._LoadTransform(node, babylonMesh);
@@ -1075,12 +1035,14 @@ var BABYLON;
                         promises.push(this._loadNodeAsync("#/nodes/" + index, childNode));
                     }
                 }
-                this.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, babylonMesh) {
                 var _this = this;
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (mesh.name || ""));
                 var primitives = mesh.primitives;
                 if (!primitives || primitives.length === 0) {
                     throw new Error(context + ": Primitives are missing");
@@ -1097,13 +1059,14 @@ var BABYLON;
                         var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive._index, this._babylonScene, babylonMesh);
                         node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                         promises.push(this._loadPrimitiveAsync(context + "/primitives/" + primitive._index, node, mesh, primitive, primitiveBabylonMesh));
-                        this.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                        this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
                     }
                 }
                 if (node.skin != undefined) {
                     var skin = GLTFLoader._GetProperty(context + "/skin", this._gltf.skins, node.skin);
                     promises.push(this._loadSkinAsync("#/skins/" + skin._index, node, mesh, skin));
                 }
+                this._parent._logClose();
                 return Promise.all(promises).then(function () {
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh._refreshBoundingInfo(true);
@@ -1113,6 +1076,7 @@ var BABYLON;
             GLTFLoader.prototype._loadPrimitiveAsync = function (context, node, mesh, primitive, babylonMesh) {
                 var _this = this;
                 var promises = new Array();
+                this._parent._logOpen("" + context);
                 this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
                 promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then(function (babylonGeometry) {
                     return _this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonGeometry).then(function () {
@@ -1129,6 +1093,7 @@ var BABYLON;
                         babylonMesh.material = babylonMaterial;
                     }));
                 }
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
@@ -1387,7 +1352,7 @@ var BABYLON;
                         throw new Error(context + ": Invalid camera type (" + camera.type + ")");
                     }
                 }
-                this.onCameraLoadedObservable.notifyObservers(babylonCamera);
+                this._parent.onCameraLoadedObservable.notifyObservers(babylonCamera);
             };
             GLTFLoader.prototype._loadAnimationsAsync = function () {
                 var animations = this._gltf.animations;
@@ -1413,7 +1378,7 @@ var BABYLON;
                     promises.push(this._loadAnimationChannelAsync(context + "/channels/" + channel._index, context, animation, channel, babylonAnimationGroup));
                 }
                 return Promise.all(promises).then(function () {
-                    babylonAnimationGroup.normalize(_this._normalizeAnimationGroupsToBeginAtZero ? 0 : null);
+                    babylonAnimationGroup.normalize(_this._parent._normalizeAnimationGroupsToBeginAtZero ? 0 : null);
                 });
             };
             GLTFLoader.prototype._loadAnimationChannelAsync = function (context, animationContext, animation, channel, babylonAnimationGroup) {
@@ -1607,7 +1572,6 @@ var BABYLON;
                 buffer._data = this._loadUriAsync(context, buffer.uri);
                 return buffer._data;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadBufferViewAsync = function (context, bufferView) {
                 if (bufferView._data) {
                     return bufferView._data;
@@ -1686,7 +1650,6 @@ var BABYLON;
                 }
                 return accessor._data;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadVertexBufferViewAsync = function (context, bufferView, kind) {
                 var _this = this;
                 if (bufferView._babylonBuffer) {
@@ -1723,7 +1686,7 @@ var BABYLON;
                     babylonMaterial.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE;
                     babylonMaterial.metallic = 1;
                     babylonMaterial.roughness = 1;
-                    this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                    this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                 }
                 return babylonMaterial;
             };
@@ -1760,7 +1723,6 @@ var BABYLON;
                 this._loadMaterialAlphaProperties(context, material, babylonMaterial);
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadMaterialAsync(this, context, material, mesh, babylonMesh, babylonDrawMode, assign);
                 if (promise) {
@@ -1770,33 +1732,33 @@ var BABYLON;
                 var babylonData = material._babylonData[babylonDrawMode];
                 if (!babylonData) {
                     var promises = new Array();
-                    var name_3 = material.name || "material_" + material._index;
-                    var babylonMaterial = this._createMaterial(name_3, babylonDrawMode);
+                    this._parent._logOpen(context + " " + (material.name || ""));
+                    var name_4 = material.name || "material_" + material._index;
+                    var babylonMaterial = this._createMaterial(name_4, babylonDrawMode);
                     promises.push(this._loadMaterialBasePropertiesAsync(context, material, babylonMaterial));
                     promises.push(this._loadMaterialMetallicRoughnessPropertiesAsync(context, material, babylonMaterial));
-                    this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                    this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                     babylonData = {
                         material: babylonMaterial,
                         meshes: [],
                         loaded: Promise.all(promises).then(function () { })
                     };
                     material._babylonData[babylonDrawMode] = babylonData;
+                    this._parent._logClose();
                 }
                 babylonData.meshes.push(babylonMesh);
                 assign(babylonData.material);
                 return babylonData.loaded;
             };
-            /** @hidden */
             GLTFLoader.prototype._createMaterial = function (name, drawMode) {
                 var babylonMaterial = new BABYLON.PBRMaterial(name, this._babylonScene);
                 babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? BABYLON.Material.CounterClockWiseSideOrientation : BABYLON.Material.ClockWiseSideOrientation;
                 babylonMaterial.fillMode = drawMode;
                 babylonMaterial.enableSpecularAntiAliasing = true;
-                babylonMaterial.useRadianceOverAlpha = !this.transparencyAsCoverage;
-                babylonMaterial.useSpecularOverAlpha = !this.transparencyAsCoverage;
+                babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage;
+                babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage;
                 return babylonMaterial;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialBasePropertiesAsync = function (context, material, babylonMaterial) {
                 var promises = new Array();
                 babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
@@ -1830,7 +1792,6 @@ var BABYLON;
                 }
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialAlphaProperties = function (context, material, babylonMaterial) {
                 var alphaMode = material.alphaMode || "OPAQUE" /* OPAQUE */;
                 switch (alphaMode) {
@@ -1859,16 +1820,17 @@ var BABYLON;
                     }
                 }
             };
-            /** @hidden */
             GLTFLoader.prototype._loadTextureAsync = function (context, textureInfo, assign) {
                 var _this = this;
                 var promise = GLTF2.GLTFLoaderExtension._LoadTextureAsync(this, context, textureInfo, assign);
                 if (promise) {
                     return promise;
                 }
+                this._parent._logOpen("" + context);
                 var texture = GLTFLoader._GetProperty(context + "/index", this._gltf.textures, textureInfo.index);
                 context = "#/textures/" + textureInfo.index;
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (texture.name || ""));
                 var sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(context + "/sampler", this._gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("#/samplers/" + sampler._index, sampler);
                 var deferred = new BABYLON.Deferred();
@@ -1892,7 +1854,9 @@ var BABYLON;
                     babylonTexture.updateURL(dataUrl, blob);
                 }));
                 assign(babylonTexture);
-                this.onTextureLoadedObservable.notifyObservers(babylonTexture);
+                this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
+                this._parent._logClose();
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadSampler = function (context, sampler) {
@@ -1908,23 +1872,23 @@ var BABYLON;
                 return sampler._data;
             };
             GLTFLoader.prototype._loadImageAsync = function (context, image) {
-                if (image._blob) {
-                    return image._blob;
-                }
-                var promise;
-                if (image.uri) {
-                    promise = this._loadUriAsync(context, image.uri);
-                }
-                else {
-                    var bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, image.bufferView);
-                    promise = this._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                if (!image._blob) {
+                    this._parent._logOpen(context + " " + (image.name || ""));
+                    var promise = void 0;
+                    if (image.uri) {
+                        promise = this._loadUriAsync(context, image.uri);
+                    }
+                    else {
+                        var bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, image.bufferView);
+                        promise = this._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                    }
+                    image._blob = promise.then(function (data) {
+                        return new Blob([data], { type: image.mimeType });
+                    });
+                    this._parent._logClose();
                 }
-                image._blob = promise.then(function (data) {
-                    return new Blob([data], { type: image.mimeType });
-                });
                 return image._blob;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadUriAsync = function (context, uri) {
                 var _this = this;
                 var promise = GLTF2.GLTFLoaderExtension._LoadUriAsync(this, context, uri);
@@ -1935,27 +1899,34 @@ var BABYLON;
                     throw new Error(context + ": Uri '" + uri + "' is invalid");
                 }
                 if (BABYLON.Tools.IsBase64(uri)) {
-                    return Promise.resolve(new Uint8Array(BABYLON.Tools.DecodeBase64(uri)));
+                    var data = new Uint8Array(BABYLON.Tools.DecodeBase64(uri));
+                    this._parent._log("Decoded " + uri.substr(0, 64) + "... (" + data.length + " bytes)");
+                    return Promise.resolve(data);
                 }
-                return this.preprocessUrlAsync(this._rootUrl + uri).then(function (url) {
+                this._parent._log("Loading " + uri);
+                return this._parent.preprocessUrlAsync(this._rootUrl + uri).then(function (url) {
                     return new Promise(function (resolve, reject) {
                         if (!_this._disposed) {
-                            var request_1 = BABYLON.Tools.LoadFile(url, function (data) {
+                            var request_1 = BABYLON.Tools.LoadFile(url, function (fileData) {
                                 if (!_this._disposed) {
-                                    resolve(new Uint8Array(data));
+                                    var data = new Uint8Array(fileData);
+                                    _this._parent._log("Loaded " + uri + " (" + data.length + " bytes)");
+                                    resolve(data);
                                 }
                             }, function (event) {
                                 if (!_this._disposed) {
-                                    try {
-                                        if (request_1 && _this._state === BABYLON.GLTFLoaderState.LOADING) {
-                                            request_1._lengthComputable = event.lengthComputable;
-                                            request_1._loaded = event.loaded;
-                                            request_1._total = event.total;
+                                    if (request_1) {
+                                        request_1._lengthComputable = event.lengthComputable;
+                                        request_1._loaded = event.loaded;
+                                        request_1._total = event.total;
+                                    }
+                                    if (_this._state === BABYLON.GLTFLoaderState.LOADING) {
+                                        try {
                                             _this._onProgress();
                                         }
-                                    }
-                                    catch (e) {
-                                        reject(e);
+                                        catch (e) {
+                                            reject(e);
+                                        }
                                     }
                                 }
                             }, _this._babylonScene.database, true, function (request, exception) {
@@ -1986,7 +1957,6 @@ var BABYLON;
                 }
                 this._progressCallback(new BABYLON.SceneLoaderProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
             };
-            /** @hidden */
             GLTFLoader._GetProperty = function (context, array, index) {
                 if (!array || index == undefined || !array[index]) {
                     throw new Error(context + ": Failed to find index (" + index + ")");
@@ -2101,7 +2071,7 @@ var BABYLON;
                                     babylonMesh.computeWorldMatrix(true);
                                     var babylonMaterial = babylonData.material;
                                     promises.push(babylonMaterial.forceCompilationAsync(babylonMesh));
-                                    if (this.useClipPlane) {
+                                    if (this._parent.useClipPlane) {
                                         promises.push(babylonMaterial.forceCompilationAsync(babylonMesh, { clipPlane: true }));
                                     }
                                 }
@@ -2123,28 +2093,6 @@ var BABYLON;
                 }
                 return Promise.all(promises).then(function () { });
             };
-            GLTFLoader.prototype._clear = function () {
-                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
-                    var request = _a[_i];
-                    request.abort();
-                }
-                this._requests.length = 0;
-                delete this._gltf;
-                delete this._babylonScene;
-                this._completePromises.length = 0;
-                this._onReadyObservable.clear();
-                for (var name_4 in this._extensions) {
-                    this._extensions[name_4].dispose();
-                }
-                this._extensions = {};
-                delete this._rootBabylonMesh;
-                delete this._progressCallback;
-                this.onMeshLoadedObservable.clear();
-                this.onTextureLoadedObservable.clear();
-                this.onMaterialLoadedObservable.clear();
-                this.onCameraLoadedObservable.clear();
-            };
-            /** @hidden */
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
                     var name_5 = _a[_i];
@@ -2163,7 +2111,7 @@ var BABYLON;
             return GLTFLoader;
         }());
         GLTF2.GLTFLoader = GLTFLoader;
-        BABYLON.GLTFFileLoader._CreateGLTFLoaderV2 = function () { return new GLTFLoader(); };
+        BABYLON.GLTFFileLoader._CreateGLTFLoaderV2 = function (parent) { return new GLTFLoader(parent); };
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
@@ -2374,6 +2322,7 @@ var BABYLON;
                     _this._loader._onReadyObservable.addOnce(function () {
                         var _loop_1 = function (indexLOD) {
                             Promise.all(_this._loadNodePromises[indexLOD]).then(function () {
+                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
                                 _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
                             });
                         };
@@ -2382,6 +2331,7 @@ var BABYLON;
                         }
                         var _loop_2 = function (indexLOD) {
                             Promise.all(_this._loadMaterialPromises[indexLOD]).then(function () {
+                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
                                 _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
                             });
                         };
@@ -2405,6 +2355,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
                         var firstPromise;
                         var nodeLODs = _this._getLODs(extensionContext, node, _this._loader._gltf.nodes, extension.ids);
+                        _this._loader._parent._logOpen("" + extensionContext);
                         var _loop_3 = function (indexLOD) {
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
@@ -2442,6 +2393,7 @@ var BABYLON;
                         for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
                             _loop_3(indexLOD);
                         }
+                        _this._loader._parent._logClose();
                         return firstPromise;
                     });
                 };
@@ -2454,6 +2406,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {
                         var firstPromise;
                         var materialLODs = _this._getLODs(extensionContext, material, _this._loader._gltf.materials, extension.ids);
+                        _this._loader._parent._logOpen("" + extensionContext);
                         var _loop_4 = function (indexLOD) {
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
@@ -2493,11 +2446,17 @@ var BABYLON;
                         for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
                             _loop_4(indexLOD);
                         }
+                        _this._loader._parent._logClose();
                         return firstPromise;
                     });
                 };
                 MSFT_lod.prototype._loadUriAsync = function (context, uri) {
                     var _this = this;
+                    if (this._loadingMaterialLOD || this._loadingNodeLOD) {
+                        if (this._loader._parent.loggingEnabled) {
+                            this._loader._parent._log("deferred");
+                        }
+                    }
                     // Defer the loading of uris if loading a material or node LOD.
                     if (this._loadingMaterialLOD) {
                         var index = this._loadingMaterialLOD._index;
@@ -2785,7 +2744,7 @@ var BABYLON;
                             var babylonMaterial = _this._loader._createMaterial(name_1, babylonDrawMode);
                             promises.push(_this._loader._loadMaterialBasePropertiesAsync(context, material, babylonMaterial));
                             promises.push(_this._loadSpecularGlossinessPropertiesAsync(extensionContext, material, extension, babylonMaterial));
-                            _this._loader.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            _this._loader._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                             babylonData = {
                                 material: babylonMaterial,
                                 meshes: [],
@@ -2872,7 +2831,7 @@ var BABYLON;
                             var babylonMaterial = _this._loader._createMaterial(name_1, babylonDrawMode);
                             babylonMaterial.unlit = true;
                             var promise = _this._loadUnlitPropertiesAsync(context, material, babylonMaterial);
-                            _this._loader.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            _this._loader._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                             babylonData = {
                                 material: babylonMaterial,
                                 meshes: [],

Разлика између датотеке није приказан због своје велике величине
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 30 - 202
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -73,89 +73,15 @@ declare module BABYLON {
          */
         COMPLETE = 2,
     }
-    /**
-     * Loader interface.
-     */
+    /** @hidden */
     interface IGLTFLoader extends IDisposable {
-        /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
-         * Loader state or null if the loader is not active.
-         */
-        state: Nullable<GLTFLoaderState>;
-        /**
-         * Imports meshes from the given data and adds them to the scene.
-         */
+        readonly state: Nullable<GLTFLoaderState>;
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Loads all objects from the given data and adds them to the scene.
-         */
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     /**
@@ -163,9 +89,9 @@ declare module BABYLON {
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         /** @hidden */
-        static _CreateGLTFLoaderV1: () => IGLTFLoader;
+        static _CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         /** @hidden */
-        static _CreateGLTFLoaderV2: () => IGLTFLoader;
+        static _CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
          */
@@ -217,6 +143,22 @@ declare module BABYLON {
         /** @hidden */
         _normalizeAnimationGroupsToBeginAtZero: boolean;
         /**
+         * Defines if the loader logging is enabled.
+         */
+        loggingEnabled: boolean;
+        /**
+         * Observable raised when the loader logs a message.
+         */
+        readonly onLogObservable: Observable<string>;
+        private _logIndentLevel;
+        private static readonly _logSpaces;
+        /** @hidden */
+        _log(message: string): void;
+        /** @hidden */
+        _logOpen(message: string): void;
+        /** @hidden */
+        _logClose(): void;
+        /**
          * Function called before loading a url referenced by the asset.
          */
         preprocessUrlAsync: (url: string) => Promise<string>;
@@ -261,7 +203,7 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
          */
-        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<void>;
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately before the loader is disposed.
@@ -270,7 +212,7 @@ declare module BABYLON {
         /**
          * Observable raised after the loader is disposed.
          */
-        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<void>;
         private _onDisposeObserver;
         /**
          * Callback raised after the loader is disposed.
@@ -308,6 +250,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
+        /** @hidden */
+        _clear(): void;
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
          * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
@@ -358,9 +302,9 @@ declare module BABYLON {
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         private _parse(data);
         private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private _parseBinary(data);
+        private _parseV1(binaryReader);
+        private _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -760,21 +704,6 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        compileMaterials: boolean;
-        useClipPlane: boolean;
-        compileShadowGenerators: boolean;
-        transparencyAsCoverage: boolean;
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         state: Nullable<GLTFLoaderState>;
         dispose(): void;
         private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress?, onError?);
@@ -1061,17 +990,12 @@ declare module BABYLON.GLTF2 {
  * Defines the module used to import/export glTF 2.0 assets
  */
 declare module BABYLON.GLTF2 {
-    /**
-     * Loader for loading a glTF 2.0 asset
-     */
+    /** @hidden */
     class GLTFLoader implements IGLTFLoader {
-        /** @hidden */
+        _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
-        /** @hidden */
         _babylonScene: Scene;
-        /** @hidden */
         _completePromises: Promise<void>[];
-        /** @hidden */
         _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
@@ -1084,102 +1008,19 @@ declare module BABYLON.GLTF2 {
         private _requests;
         private static _ExtensionNames;
         private static _ExtensionFactories;
-        /** @hidden */
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
          * Loader state or null if the loader is not active.
          */
         readonly state: Nullable<GLTFLoaderState>;
-        /**
-         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
-         */
+        constructor(parent: GLTFFileLoader);
         dispose(): void;
-        /**
-         * Imports one or more meshes from the loaded glTF data and adds them to the scene
-         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-         * @param scene the scene the meshes should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise containg the loaded meshes, particles, skeletons and animations
-         */
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Imports all objects from the loaded glTF data and adds them to the scene
-         * @param scene the scene the objects should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise which completes when objects have been loaded to the scene
-         */
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadAsync(nodes);
         private _loadData(data);
@@ -1188,14 +1029,12 @@ declare module BABYLON.GLTF2 {
         private _checkExtensions();
         private _createRootNode();
         private _loadNodesAsync(nodes);
-        /** @hidden */
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
         private _getAnimationGroups();
         private _startAnimations();
-        /** @hidden */
         _loadNodeAsync(context: string, node: _ILoaderNode): Promise<void>;
         private _loadMeshAsync(context, node, mesh, babylonMesh);
         private _loadPrimitiveAsync(context, node, mesh, primitive, babylonMesh);
@@ -1216,31 +1055,22 @@ declare module BABYLON.GLTF2 {
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
-        /** @hidden */
         _loadBufferViewAsync(context: string, bufferView: _ILoaderBufferView): Promise<ArrayBufferView>;
         private _loadIndicesAccessorAsync(context, accessor);
         private _loadFloatAccessorAsync(context, accessor);
-        /** @hidden */
         _loadVertexBufferViewAsync(context: string, bufferView: _ILoaderBufferView, kind: string): Promise<Buffer>;
         private _loadVertexAccessorAsync(context, accessor, kind);
         private _getDefaultMaterial(drawMode);
         private _loadMaterialMetallicRoughnessPropertiesAsync(context, material, babylonMaterial);
-        /** @hidden */
         _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Promise<void>;
-        /** @hidden */
         _createMaterial(name: string, drawMode: number): PBRMaterial;
-        /** @hidden */
         _loadMaterialBasePropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void>;
-        /** @hidden */
         _loadMaterialAlphaProperties(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): void;
-        /** @hidden */
         _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
         private _loadImageAsync(context, image);
-        /** @hidden */
         _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
         private _onProgress();
-        /** @hidden */
         static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
         private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
@@ -1250,8 +1080,6 @@ declare module BABYLON.GLTF2 {
         private static _GetDrawMode(context, mode);
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
-        private _clear();
-        /** @hidden */
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
 }

+ 188 - 244
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -92,6 +92,15 @@ var BABYLON;
             /** @hidden */
             this._normalizeAnimationGroupsToBeginAtZero = true;
             /**
+             * Defines if the loader logging is enabled.
+             */
+            this.loggingEnabled = false;
+            /**
+             * Observable raised when the loader logs a message.
+             */
+            this.onLogObservable = new BABYLON.Observable();
+            this._logIndentLevel = 0;
+            /**
              * Function called before loading a url referenced by the asset.
              */
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
@@ -153,6 +162,23 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /** @hidden */
+        GLTFFileLoader.prototype._log = function (message) {
+            if (this.loggingEnabled) {
+                var spaces = GLTFFileLoader._logSpaces.substr(0, this._logIndentLevel * 2);
+                this.onLogObservable.notifyObservers("" + spaces + message);
+                BABYLON.Tools.Log("" + spaces + message);
+            }
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logOpen = function (message) {
+            this._log(message);
+            this._logIndentLevel++;
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logClose = function () {
+            --this._logIndentLevel;
+        };
         Object.defineProperty(GLTFFileLoader.prototype, "onMeshLoaded", {
             /**
              * Callback raised when the loader creates a mesh after parsing the glTF properties of the mesh.
@@ -274,6 +300,12 @@ var BABYLON;
                 this._loader.dispose();
                 this._loader = null;
             }
+            this._clear();
+            this.onDisposeObservable.notifyObservers(undefined);
+            this.onDisposeObservable.clear();
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._clear = function () {
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
@@ -281,8 +313,6 @@ var BABYLON;
             this.onCameraLoadedObservable.clear();
             this.onCompleteObservable.clear();
             this.onExtensionLoadedObservable.clear();
-            this.onDisposeObservable.notifyObservers(this);
-            this.onDisposeObservable.clear();
         };
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
@@ -359,9 +389,16 @@ var BABYLON;
         GLTFFileLoader.prototype._parse = function (data) {
             var parsedData;
             if (data instanceof ArrayBuffer) {
-                parsedData = GLTFFileLoader._parseBinary(data);
+                if (this.loggingEnabled) {
+                    this._log("Parsing binary");
+                }
+                parsedData = this._parseBinary(data);
             }
             else {
+                if (this.loggingEnabled) {
+                    this._log("Parsing JSON");
+                    this._log("JSON length: " + data.length);
+                }
                 parsedData = {
                     json: JSON.parse(data),
                     bin: null
@@ -372,9 +409,16 @@ var BABYLON;
             return parsedData;
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
-            var _this = this;
-            var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
+            if (this.loggingEnabled) {
+                this._log("Asset version: " + asset.version);
+                if (asset.minVersion) {
+                    this._log("Asset minimum version: " + asset.minVersion);
+                }
+                if (asset.generator) {
+                    this._log("Asset generator: " + asset.generator);
+                }
+            }
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
                 throw new Error("Invalid version: " + asset.version);
@@ -384,7 +428,7 @@ var BABYLON;
                 if (!minVersion) {
                     throw new Error("Invalid minimum version: " + asset.minVersion);
                 }
-                if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
+                if (GLTFFileLoader._compareVersion(minVersion, { major: 2, minor: 0 }) > 0) {
                     throw new Error("Incompatible minimum version: " + asset.minVersion);
                 }
             }
@@ -396,48 +440,31 @@ var BABYLON;
             if (!createLoader) {
                 throw new Error("Unsupported version: " + asset.version);
             }
-            var loader = createLoader();
-            loader.coordinateSystemMode = this.coordinateSystemMode;
-            loader.animationStartMode = this.animationStartMode;
-            loader.compileMaterials = this.compileMaterials;
-            loader.useClipPlane = this.useClipPlane;
-            loader.compileShadowGenerators = this.compileShadowGenerators;
-            loader.transparencyAsCoverage = this.transparencyAsCoverage;
-            loader._normalizeAnimationGroupsToBeginAtZero = this._normalizeAnimationGroupsToBeginAtZero;
-            loader.preprocessUrlAsync = this.preprocessUrlAsync;
-            loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
-            loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
-            loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
-            loader.onCameraLoadedObservable.add(function (camera) { return _this.onCameraLoadedObservable.notifyObservers(camera); });
-            loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onCompleteObservable.add(function () {
-                _this.onMeshLoadedObservable.clear();
-                _this.onTextureLoadedObservable.clear();
-                _this.onMaterialLoadedObservable.clear();
-                _this.onCameraLoadedObservable.clear();
-                _this.onExtensionLoadedObservable.clear();
-                _this.onCompleteObservable.notifyObservers(_this);
-                _this.onCompleteObservable.clear();
-            });
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader.prototype._parseBinary = function (data) {
             var Binary = {
                 Magic: 0x46546C67
             };
+            if (this.loggingEnabled) {
+                this._log("Binary length: " + data.byteLength);
+            }
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
                 throw new Error("Unexpected magic: " + magic);
             }
             var version = binaryReader.readUint32();
+            if (this.loggingEnabled) {
+                this._log("Binary version: " + version);
+            }
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return this._parseV1(binaryReader);
+                case 2: return this._parseV2(binaryReader);
             }
             throw new Error("Unsupported version: " + version);
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV1 = function (binaryReader) {
             var ContentFormat = {
                 JSON: 0
             };
@@ -464,7 +491,7 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV2 = function (binaryReader) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
@@ -555,6 +582,7 @@ var BABYLON;
          * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
+        GLTFFileLoader._logSpaces = "                                ";
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -1978,22 +2006,6 @@ var BABYLON;
         */
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader() {
-                // #region Stubs for IGLTFLoader interface
-                this.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.AUTO;
-                this.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.FIRST;
-                this.compileMaterials = false;
-                this.useClipPlane = false;
-                this.compileShadowGenerators = false;
-                this.transparencyAsCoverage = false;
-                this._normalizeAnimationGroupsToBeginAtZero = true;
-                this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
-                this.onMeshLoadedObservable = new BABYLON.Observable();
-                this.onTextureLoadedObservable = new BABYLON.Observable();
-                this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onCameraLoadedObservable = new BABYLON.Observable();
-                this.onCompleteObservable = new BABYLON.Observable();
-                this.onDisposeObservable = new BABYLON.Observable();
-                this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.state = null;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -2003,8 +2015,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
-            GLTFLoader.prototype.dispose = function () { };
-            // #endregion
+            GLTFLoader.prototype.dispose = function () {
+                // do nothing
+            };
             GLTFLoader.prototype._importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
@@ -2809,7 +2822,7 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFMaterialsCommonExtension.js.map
 
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
-/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 
 //# sourceMappingURL=babylon.glTFLoaderInterfaces.js.map
 
@@ -2833,14 +2846,10 @@ var BABYLON;
             };
             return _ArrayItem;
         }());
-        /**
-         * Loader for loading a glTF 2.0 asset
-         */
+        /** @hidden */
         var GLTFLoader = /** @class */ (function () {
-            function GLTFLoader() {
-                /** @hidden */
+            function GLTFLoader(parent) {
                 this._completePromises = new Array();
-                /** @hidden */
                 this._onReadyObservable = new BABYLON.Observable();
                 this._disposed = false;
                 this._state = null;
@@ -2848,71 +2857,8 @@ var BABYLON;
                 this._defaultSampler = {};
                 this._defaultBabylonMaterials = {};
                 this._requests = new Array();
-                /**
-                 * Mode that determines the coordinate system to use.
-                 */
-                this.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.AUTO;
-                /**
-                 * Mode that determines what animations will start.
-                 */
-                this.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.FIRST;
-                /**
-                 * Defines if the loader should compile materials.
-                 */
-                this.compileMaterials = false;
-                /**
-                 * Defines if the loader should also compile materials with clip planes.
-                 */
-                this.useClipPlane = false;
-                /**
-                 * Defines if the loader should compile shadow generators.
-                 */
-                this.compileShadowGenerators = false;
-                /**
-                 * Defines if the Alpha blended materials are only applied as coverage.
-                 * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-                 * If true, no extra effects are applied to transparent pixels.
-                 */
-                this.transparencyAsCoverage = false;
-                /** @hidden */
-                this._normalizeAnimationGroupsToBeginAtZero = true;
-                /**
-                 * Function called before loading a url referenced by the asset.
-                 */
-                this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
-                /**
-                 * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-                 */
-                this.onMeshLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-                 */
-                this.onTextureLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-                 */
-                this.onMaterialLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-                 */
-                this.onCameraLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-                 * For assets with LODs, raised when all of the LODs are complete.
-                 * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-                 */
-                this.onCompleteObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised after the loader is disposed.
-                 */
-                this.onDisposeObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised after a loader extension is created.
-                 * Set additional options for a loader extension in this event.
-                 */
-                this.onExtensionLoadedObservable = new BABYLON.Observable();
+                this._parent = parent;
             }
-            /** @hidden */
             GLTFLoader._Register = function (name, factory) {
                 if (GLTFLoader._ExtensionFactories[name]) {
                     BABYLON.Tools.Error("Extension with the name '" + name + "' already exists");
@@ -2932,27 +2878,28 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
-            /**
-             * Disposes the loader, releases resources during load, and cancels any outstanding requests.
-             */
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
                 }
                 this._disposed = true;
-                this.onDisposeObservable.notifyObservers(this);
-                this.onDisposeObservable.clear();
-                this._clear();
+                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
+                    var request = _a[_i];
+                    request.abort();
+                }
+                this._requests.length = 0;
+                delete this._gltf;
+                delete this._babylonScene;
+                this._completePromises.length = 0;
+                this._onReadyObservable.clear();
+                for (var name_1 in this._extensions) {
+                    this._extensions[name_1].dispose();
+                }
+                this._extensions = {};
+                delete this._rootBabylonMesh;
+                delete this._progressCallback;
+                this._parent._clear();
             };
-            /**
-             * Imports one or more meshes from the loaded glTF data and adds them to the scene
-             * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-             * @param scene the scene the meshes should be added to
-             * @param data the glTF data to load
-             * @param rootUrl root url to load from
-             * @param onProgress event that fires when loading progress has occured
-             * @returns a promise containg the loaded meshes, particles, skeletons and animations
-             */
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return Promise.resolve().then(function () {
@@ -2990,14 +2937,6 @@ var BABYLON;
                     });
                 });
             };
-            /**
-             * Imports all objects from the loaded glTF data and adds them to the scene
-             * @param scene the scene the objects should be added to
-             * @param data the glTF data to load
-             * @param rootUrl root url to load from
-             * @param onProgress event that fires when loading progress has occured
-             * @returns a promise which completes when objects have been loaded to the scene
-             */
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return Promise.resolve().then(function () {
@@ -3012,6 +2951,7 @@ var BABYLON;
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this._state = BABYLON.GLTFLoaderState.LOADING;
+                    _this._parent._log("Loading");
                     _this._loadExtensions();
                     _this._checkExtensions();
                     var promises = new Array();
@@ -3022,14 +2962,15 @@ var BABYLON;
                         var scene = GLTFLoader._GetProperty("#/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                         promises.push(_this._loadSceneAsync("#/scenes/" + scene._index, scene));
                     }
-                    if (_this.compileMaterials) {
+                    if (_this._parent.compileMaterials) {
                         promises.push(_this._compileMaterialsAsync());
                     }
-                    if (_this.compileShadowGenerators) {
+                    if (_this._parent.compileShadowGenerators) {
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
                         _this._state = BABYLON.GLTFLoaderState.READY;
+                        _this._parent._log("Ready");
                         _this._onReadyObservable.notifyObservers(_this);
                         _this._startAnimations();
                     });
@@ -3041,12 +2982,13 @@ var BABYLON;
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
                                     _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this.onCompleteObservable.notifyObservers(_this);
-                                    _this.onCompleteObservable.clear();
-                                    _this._clear();
+                                    _this._parent._log("Complete");
+                                    _this._parent.onCompleteObservable.notifyObservers(undefined);
+                                    _this._parent.onCompleteObservable.clear();
+                                    _this.dispose();
                                 }).catch(function (error) {
                                     BABYLON.Tools.Error("glTF Loader: " + error.message);
-                                    _this._clear();
+                                    _this.dispose();
                                 });
                             }
                         });
@@ -3055,7 +2997,7 @@ var BABYLON;
                 }).catch(function (error) {
                     if (!_this._disposed) {
                         BABYLON.Tools.Error("glTF Loader: " + error.message);
-                        _this._clear();
+                        _this.dispose();
                         throw error;
                     }
                 });
@@ -3112,20 +3054,20 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadExtensions = function () {
                 for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
-                    var name_1 = _a[_i];
-                    var extension = GLTFLoader._ExtensionFactories[name_1](this);
-                    this._extensions[name_1] = extension;
-                    this.onExtensionLoadedObservable.notifyObservers(extension);
+                    var name_2 = _a[_i];
+                    var extension = GLTFLoader._ExtensionFactories[name_2](this);
+                    this._extensions[name_2] = extension;
+                    this._parent.onExtensionLoadedObservable.notifyObservers(extension);
                 }
-                this.onExtensionLoadedObservable.clear();
+                this._parent.onExtensionLoadedObservable.clear();
             };
             GLTFLoader.prototype._checkExtensions = function () {
                 if (this._gltf.extensionsRequired) {
                     for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
-                        var name_2 = _a[_i];
-                        var extension = this._extensions[name_2];
+                        var name_3 = _a[_i];
+                        var extension = this._extensions[name_3];
                         if (!extension || !extension.enabled) {
-                            throw new Error("Require extension " + name_2 + " is not available");
+                            throw new Error("Require extension " + name_3 + " is not available");
                         }
                     }
                 }
@@ -3134,7 +3076,7 @@ var BABYLON;
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 this._rootBabylonMesh.setEnabled(false);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
-                switch (this.coordinateSystemMode) {
+                switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                         if (!this._babylonScene.useRightHandedSystem) {
                             rootNode.rotation = [0, 1, 0, 0];
@@ -3148,10 +3090,10 @@ var BABYLON;
                         break;
                     }
                     default: {
-                        throw new Error("Invalid coordinate system mode (" + this.coordinateSystemMode + ")");
+                        throw new Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
                     }
                 }
-                this.onMeshLoadedObservable.notifyObservers(this._rootBabylonMesh);
+                this._parent.onMeshLoadedObservable.notifyObservers(this._rootBabylonMesh);
                 return rootNode;
             };
             GLTFLoader.prototype._loadNodesAsync = function (nodes) {
@@ -3163,19 +3105,22 @@ var BABYLON;
                 promises.push(this._loadAnimationsAsync());
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadSceneAsync = function (context, scene) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
                 if (promise) {
                     return promise;
                 }
                 var promises = new Array();
-                for (var _i = 0, _a = scene.nodes; _i < _a.length; _i++) {
-                    var index = _a[_i];
-                    var node = GLTFLoader._GetProperty(context + "/nodes/" + index, this._gltf.nodes, index);
-                    promises.push(this._loadNodeAsync("#/nodes/" + node._index, node));
+                this._parent._logOpen(context + " " + (scene.name || ""));
+                if (scene.nodes) {
+                    for (var _i = 0, _a = scene.nodes; _i < _a.length; _i++) {
+                        var index = _a[_i];
+                        var node = GLTFLoader._GetProperty(context + "/nodes/" + index, this._gltf.nodes, index);
+                        promises.push(this._loadNodeAsync("#/nodes/" + node._index, node));
+                    }
                 }
                 promises.push(this._loadAnimationsAsync());
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._forEachPrimitive = function (node, callback) {
@@ -3237,7 +3182,7 @@ var BABYLON;
                 return animationGroups;
             };
             GLTFLoader.prototype._startAnimations = function () {
-                switch (this.animationStartMode) {
+                switch (this._parent.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
                         break;
@@ -3258,12 +3203,11 @@ var BABYLON;
                         break;
                     }
                     default: {
-                        BABYLON.Tools.Error("Invalid animation start mode (" + this.animationStartMode + ")");
+                        BABYLON.Tools.Error("Invalid animation start mode (" + this._parent.animationStartMode + ")");
                         return;
                     }
                 }
             };
-            /** @hidden */
             GLTFLoader.prototype._loadNodeAsync = function (context, node) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadNodeAsync(this, context, node);
                 if (promise) {
@@ -3273,6 +3217,7 @@ var BABYLON;
                     throw new Error(context + ": Invalid recursive node hierarchy");
                 }
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (node.name || ""));
                 var babylonMesh = new BABYLON.Mesh(node.name || "node" + node._index, this._babylonScene, node._parent ? node._parent._babylonMesh : null);
                 node._babylonMesh = babylonMesh;
                 GLTFLoader._LoadTransform(node, babylonMesh);
@@ -3291,12 +3236,14 @@ var BABYLON;
                         promises.push(this._loadNodeAsync("#/nodes/" + index, childNode));
                     }
                 }
-                this.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, babylonMesh) {
                 var _this = this;
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (mesh.name || ""));
                 var primitives = mesh.primitives;
                 if (!primitives || primitives.length === 0) {
                     throw new Error(context + ": Primitives are missing");
@@ -3313,13 +3260,14 @@ var BABYLON;
                         var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive._index, this._babylonScene, babylonMesh);
                         node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                         promises.push(this._loadPrimitiveAsync(context + "/primitives/" + primitive._index, node, mesh, primitive, primitiveBabylonMesh));
-                        this.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                        this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
                     }
                 }
                 if (node.skin != undefined) {
                     var skin = GLTFLoader._GetProperty(context + "/skin", this._gltf.skins, node.skin);
                     promises.push(this._loadSkinAsync("#/skins/" + skin._index, node, mesh, skin));
                 }
+                this._parent._logClose();
                 return Promise.all(promises).then(function () {
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh._refreshBoundingInfo(true);
@@ -3329,6 +3277,7 @@ var BABYLON;
             GLTFLoader.prototype._loadPrimitiveAsync = function (context, node, mesh, primitive, babylonMesh) {
                 var _this = this;
                 var promises = new Array();
+                this._parent._logOpen("" + context);
                 this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
                 promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then(function (babylonGeometry) {
                     return _this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonGeometry).then(function () {
@@ -3345,6 +3294,7 @@ var BABYLON;
                         babylonMesh.material = babylonMaterial;
                     }));
                 }
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
@@ -3603,7 +3553,7 @@ var BABYLON;
                         throw new Error(context + ": Invalid camera type (" + camera.type + ")");
                     }
                 }
-                this.onCameraLoadedObservable.notifyObservers(babylonCamera);
+                this._parent.onCameraLoadedObservable.notifyObservers(babylonCamera);
             };
             GLTFLoader.prototype._loadAnimationsAsync = function () {
                 var animations = this._gltf.animations;
@@ -3629,7 +3579,7 @@ var BABYLON;
                     promises.push(this._loadAnimationChannelAsync(context + "/channels/" + channel._index, context, animation, channel, babylonAnimationGroup));
                 }
                 return Promise.all(promises).then(function () {
-                    babylonAnimationGroup.normalize(_this._normalizeAnimationGroupsToBeginAtZero ? 0 : null);
+                    babylonAnimationGroup.normalize(_this._parent._normalizeAnimationGroupsToBeginAtZero ? 0 : null);
                 });
             };
             GLTFLoader.prototype._loadAnimationChannelAsync = function (context, animationContext, animation, channel, babylonAnimationGroup) {
@@ -3823,7 +3773,6 @@ var BABYLON;
                 buffer._data = this._loadUriAsync(context, buffer.uri);
                 return buffer._data;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadBufferViewAsync = function (context, bufferView) {
                 if (bufferView._data) {
                     return bufferView._data;
@@ -3902,7 +3851,6 @@ var BABYLON;
                 }
                 return accessor._data;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadVertexBufferViewAsync = function (context, bufferView, kind) {
                 var _this = this;
                 if (bufferView._babylonBuffer) {
@@ -3939,7 +3887,7 @@ var BABYLON;
                     babylonMaterial.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE;
                     babylonMaterial.metallic = 1;
                     babylonMaterial.roughness = 1;
-                    this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                    this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                 }
                 return babylonMaterial;
             };
@@ -3976,7 +3924,6 @@ var BABYLON;
                 this._loadMaterialAlphaProperties(context, material, babylonMaterial);
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadMaterialAsync(this, context, material, mesh, babylonMesh, babylonDrawMode, assign);
                 if (promise) {
@@ -3986,33 +3933,33 @@ var BABYLON;
                 var babylonData = material._babylonData[babylonDrawMode];
                 if (!babylonData) {
                     var promises = new Array();
-                    var name_3 = material.name || "material_" + material._index;
-                    var babylonMaterial = this._createMaterial(name_3, babylonDrawMode);
+                    this._parent._logOpen(context + " " + (material.name || ""));
+                    var name_4 = material.name || "material_" + material._index;
+                    var babylonMaterial = this._createMaterial(name_4, babylonDrawMode);
                     promises.push(this._loadMaterialBasePropertiesAsync(context, material, babylonMaterial));
                     promises.push(this._loadMaterialMetallicRoughnessPropertiesAsync(context, material, babylonMaterial));
-                    this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                    this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                     babylonData = {
                         material: babylonMaterial,
                         meshes: [],
                         loaded: Promise.all(promises).then(function () { })
                     };
                     material._babylonData[babylonDrawMode] = babylonData;
+                    this._parent._logClose();
                 }
                 babylonData.meshes.push(babylonMesh);
                 assign(babylonData.material);
                 return babylonData.loaded;
             };
-            /** @hidden */
             GLTFLoader.prototype._createMaterial = function (name, drawMode) {
                 var babylonMaterial = new BABYLON.PBRMaterial(name, this._babylonScene);
                 babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? BABYLON.Material.CounterClockWiseSideOrientation : BABYLON.Material.ClockWiseSideOrientation;
                 babylonMaterial.fillMode = drawMode;
                 babylonMaterial.enableSpecularAntiAliasing = true;
-                babylonMaterial.useRadianceOverAlpha = !this.transparencyAsCoverage;
-                babylonMaterial.useSpecularOverAlpha = !this.transparencyAsCoverage;
+                babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage;
+                babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage;
                 return babylonMaterial;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialBasePropertiesAsync = function (context, material, babylonMaterial) {
                 var promises = new Array();
                 babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
@@ -4046,7 +3993,6 @@ var BABYLON;
                 }
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialAlphaProperties = function (context, material, babylonMaterial) {
                 var alphaMode = material.alphaMode || "OPAQUE" /* OPAQUE */;
                 switch (alphaMode) {
@@ -4075,16 +4021,17 @@ var BABYLON;
                     }
                 }
             };
-            /** @hidden */
             GLTFLoader.prototype._loadTextureAsync = function (context, textureInfo, assign) {
                 var _this = this;
                 var promise = GLTF2.GLTFLoaderExtension._LoadTextureAsync(this, context, textureInfo, assign);
                 if (promise) {
                     return promise;
                 }
+                this._parent._logOpen("" + context);
                 var texture = GLTFLoader._GetProperty(context + "/index", this._gltf.textures, textureInfo.index);
                 context = "#/textures/" + textureInfo.index;
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (texture.name || ""));
                 var sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(context + "/sampler", this._gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("#/samplers/" + sampler._index, sampler);
                 var deferred = new BABYLON.Deferred();
@@ -4108,7 +4055,9 @@ var BABYLON;
                     babylonTexture.updateURL(dataUrl, blob);
                 }));
                 assign(babylonTexture);
-                this.onTextureLoadedObservable.notifyObservers(babylonTexture);
+                this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
+                this._parent._logClose();
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadSampler = function (context, sampler) {
@@ -4124,23 +4073,23 @@ var BABYLON;
                 return sampler._data;
             };
             GLTFLoader.prototype._loadImageAsync = function (context, image) {
-                if (image._blob) {
-                    return image._blob;
-                }
-                var promise;
-                if (image.uri) {
-                    promise = this._loadUriAsync(context, image.uri);
-                }
-                else {
-                    var bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, image.bufferView);
-                    promise = this._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                if (!image._blob) {
+                    this._parent._logOpen(context + " " + (image.name || ""));
+                    var promise = void 0;
+                    if (image.uri) {
+                        promise = this._loadUriAsync(context, image.uri);
+                    }
+                    else {
+                        var bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, image.bufferView);
+                        promise = this._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                    }
+                    image._blob = promise.then(function (data) {
+                        return new Blob([data], { type: image.mimeType });
+                    });
+                    this._parent._logClose();
                 }
-                image._blob = promise.then(function (data) {
-                    return new Blob([data], { type: image.mimeType });
-                });
                 return image._blob;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadUriAsync = function (context, uri) {
                 var _this = this;
                 var promise = GLTF2.GLTFLoaderExtension._LoadUriAsync(this, context, uri);
@@ -4151,27 +4100,34 @@ var BABYLON;
                     throw new Error(context + ": Uri '" + uri + "' is invalid");
                 }
                 if (BABYLON.Tools.IsBase64(uri)) {
-                    return Promise.resolve(new Uint8Array(BABYLON.Tools.DecodeBase64(uri)));
+                    var data = new Uint8Array(BABYLON.Tools.DecodeBase64(uri));
+                    this._parent._log("Decoded " + uri.substr(0, 64) + "... (" + data.length + " bytes)");
+                    return Promise.resolve(data);
                 }
-                return this.preprocessUrlAsync(this._rootUrl + uri).then(function (url) {
+                this._parent._log("Loading " + uri);
+                return this._parent.preprocessUrlAsync(this._rootUrl + uri).then(function (url) {
                     return new Promise(function (resolve, reject) {
                         if (!_this._disposed) {
-                            var request_1 = BABYLON.Tools.LoadFile(url, function (data) {
+                            var request_1 = BABYLON.Tools.LoadFile(url, function (fileData) {
                                 if (!_this._disposed) {
-                                    resolve(new Uint8Array(data));
+                                    var data = new Uint8Array(fileData);
+                                    _this._parent._log("Loaded " + uri + " (" + data.length + " bytes)");
+                                    resolve(data);
                                 }
                             }, function (event) {
                                 if (!_this._disposed) {
-                                    try {
-                                        if (request_1 && _this._state === BABYLON.GLTFLoaderState.LOADING) {
-                                            request_1._lengthComputable = event.lengthComputable;
-                                            request_1._loaded = event.loaded;
-                                            request_1._total = event.total;
+                                    if (request_1) {
+                                        request_1._lengthComputable = event.lengthComputable;
+                                        request_1._loaded = event.loaded;
+                                        request_1._total = event.total;
+                                    }
+                                    if (_this._state === BABYLON.GLTFLoaderState.LOADING) {
+                                        try {
                                             _this._onProgress();
                                         }
-                                    }
-                                    catch (e) {
-                                        reject(e);
+                                        catch (e) {
+                                            reject(e);
+                                        }
                                     }
                                 }
                             }, _this._babylonScene.database, true, function (request, exception) {
@@ -4202,7 +4158,6 @@ var BABYLON;
                 }
                 this._progressCallback(new BABYLON.SceneLoaderProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
             };
-            /** @hidden */
             GLTFLoader._GetProperty = function (context, array, index) {
                 if (!array || index == undefined || !array[index]) {
                     throw new Error(context + ": Failed to find index (" + index + ")");
@@ -4317,7 +4272,7 @@ var BABYLON;
                                     babylonMesh.computeWorldMatrix(true);
                                     var babylonMaterial = babylonData.material;
                                     promises.push(babylonMaterial.forceCompilationAsync(babylonMesh));
-                                    if (this.useClipPlane) {
+                                    if (this._parent.useClipPlane) {
                                         promises.push(babylonMaterial.forceCompilationAsync(babylonMesh, { clipPlane: true }));
                                     }
                                 }
@@ -4339,28 +4294,6 @@ var BABYLON;
                 }
                 return Promise.all(promises).then(function () { });
             };
-            GLTFLoader.prototype._clear = function () {
-                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
-                    var request = _a[_i];
-                    request.abort();
-                }
-                this._requests.length = 0;
-                delete this._gltf;
-                delete this._babylonScene;
-                this._completePromises.length = 0;
-                this._onReadyObservable.clear();
-                for (var name_4 in this._extensions) {
-                    this._extensions[name_4].dispose();
-                }
-                this._extensions = {};
-                delete this._rootBabylonMesh;
-                delete this._progressCallback;
-                this.onMeshLoadedObservable.clear();
-                this.onTextureLoadedObservable.clear();
-                this.onMaterialLoadedObservable.clear();
-                this.onCameraLoadedObservable.clear();
-            };
-            /** @hidden */
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
                     var name_5 = _a[_i];
@@ -4379,7 +4312,7 @@ var BABYLON;
             return GLTFLoader;
         }());
         GLTF2.GLTFLoader = GLTFLoader;
-        BABYLON.GLTFFileLoader._CreateGLTFLoaderV2 = function () { return new GLTFLoader(); };
+        BABYLON.GLTFFileLoader._CreateGLTFLoaderV2 = function (parent) { return new GLTFLoader(parent); };
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
@@ -4590,6 +4523,7 @@ var BABYLON;
                     _this._loader._onReadyObservable.addOnce(function () {
                         var _loop_1 = function (indexLOD) {
                             Promise.all(_this._loadNodePromises[indexLOD]).then(function () {
+                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
                                 _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
                             });
                         };
@@ -4598,6 +4532,7 @@ var BABYLON;
                         }
                         var _loop_2 = function (indexLOD) {
                             Promise.all(_this._loadMaterialPromises[indexLOD]).then(function () {
+                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
                                 _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
                             });
                         };
@@ -4621,6 +4556,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
                         var firstPromise;
                         var nodeLODs = _this._getLODs(extensionContext, node, _this._loader._gltf.nodes, extension.ids);
+                        _this._loader._parent._logOpen("" + extensionContext);
                         var _loop_3 = function (indexLOD) {
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
@@ -4658,6 +4594,7 @@ var BABYLON;
                         for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
                             _loop_3(indexLOD);
                         }
+                        _this._loader._parent._logClose();
                         return firstPromise;
                     });
                 };
@@ -4670,6 +4607,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {
                         var firstPromise;
                         var materialLODs = _this._getLODs(extensionContext, material, _this._loader._gltf.materials, extension.ids);
+                        _this._loader._parent._logOpen("" + extensionContext);
                         var _loop_4 = function (indexLOD) {
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
@@ -4709,11 +4647,17 @@ var BABYLON;
                         for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
                             _loop_4(indexLOD);
                         }
+                        _this._loader._parent._logClose();
                         return firstPromise;
                     });
                 };
                 MSFT_lod.prototype._loadUriAsync = function (context, uri) {
                     var _this = this;
+                    if (this._loadingMaterialLOD || this._loadingNodeLOD) {
+                        if (this._loader._parent.loggingEnabled) {
+                            this._loader._parent._log("deferred");
+                        }
+                    }
                     // Defer the loading of uris if loading a material or node LOD.
                     if (this._loadingMaterialLOD) {
                         var index = this._loadingMaterialLOD._index;
@@ -5001,7 +4945,7 @@ var BABYLON;
                             var babylonMaterial = _this._loader._createMaterial(name_1, babylonDrawMode);
                             promises.push(_this._loader._loadMaterialBasePropertiesAsync(context, material, babylonMaterial));
                             promises.push(_this._loadSpecularGlossinessPropertiesAsync(extensionContext, material, extension, babylonMaterial));
-                            _this._loader.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            _this._loader._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                             babylonData = {
                                 material: babylonMaterial,
                                 meshes: [],
@@ -5088,7 +5032,7 @@ var BABYLON;
                             var babylonMaterial = _this._loader._createMaterial(name_1, babylonDrawMode);
                             babylonMaterial.unlit = true;
                             var promise = _this._loadUnlitPropertiesAsync(context, material, babylonMaterial);
-                            _this._loader.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            _this._loader._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                             babylonData = {
                                 material: babylonMaterial,
                                 meshes: [],

Разлика између датотеке није приказан због своје велике величине
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 30 - 202
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -169,89 +169,15 @@ declare module BABYLON {
          */
         COMPLETE = 2,
     }
-    /**
-     * Loader interface.
-     */
+    /** @hidden */
     interface IGLTFLoader extends IDisposable {
-        /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
-         * Loader state or null if the loader is not active.
-         */
-        state: Nullable<GLTFLoaderState>;
-        /**
-         * Imports meshes from the given data and adds them to the scene.
-         */
+        readonly state: Nullable<GLTFLoaderState>;
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Loads all objects from the given data and adds them to the scene.
-         */
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     /**
@@ -259,9 +185,9 @@ declare module BABYLON {
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         /** @hidden */
-        static _CreateGLTFLoaderV1: () => IGLTFLoader;
+        static _CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         /** @hidden */
-        static _CreateGLTFLoaderV2: () => IGLTFLoader;
+        static _CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
          */
@@ -313,6 +239,22 @@ declare module BABYLON {
         /** @hidden */
         _normalizeAnimationGroupsToBeginAtZero: boolean;
         /**
+         * Defines if the loader logging is enabled.
+         */
+        loggingEnabled: boolean;
+        /**
+         * Observable raised when the loader logs a message.
+         */
+        readonly onLogObservable: Observable<string>;
+        private _logIndentLevel;
+        private static readonly _logSpaces;
+        /** @hidden */
+        _log(message: string): void;
+        /** @hidden */
+        _logOpen(message: string): void;
+        /** @hidden */
+        _logClose(): void;
+        /**
          * Function called before loading a url referenced by the asset.
          */
         preprocessUrlAsync: (url: string) => Promise<string>;
@@ -357,7 +299,7 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
          */
-        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<void>;
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately before the loader is disposed.
@@ -366,7 +308,7 @@ declare module BABYLON {
         /**
          * Observable raised after the loader is disposed.
          */
-        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<void>;
         private _onDisposeObserver;
         /**
          * Callback raised after the loader is disposed.
@@ -404,6 +346,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
+        /** @hidden */
+        _clear(): void;
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
          * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
@@ -454,9 +398,9 @@ declare module BABYLON {
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         private _parse(data);
         private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private _parseBinary(data);
+        private _parseV1(binaryReader);
+        private _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -856,21 +800,6 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        compileMaterials: boolean;
-        useClipPlane: boolean;
-        compileShadowGenerators: boolean;
-        transparencyAsCoverage: boolean;
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         state: Nullable<GLTFLoaderState>;
         dispose(): void;
         private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress?, onError?);
@@ -1157,17 +1086,12 @@ declare module BABYLON.GLTF2 {
  * Defines the module used to import/export glTF 2.0 assets
  */
 declare module BABYLON.GLTF2 {
-    /**
-     * Loader for loading a glTF 2.0 asset
-     */
+    /** @hidden */
     class GLTFLoader implements IGLTFLoader {
-        /** @hidden */
+        _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
-        /** @hidden */
         _babylonScene: Scene;
-        /** @hidden */
         _completePromises: Promise<void>[];
-        /** @hidden */
         _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
@@ -1180,102 +1104,19 @@ declare module BABYLON.GLTF2 {
         private _requests;
         private static _ExtensionNames;
         private static _ExtensionFactories;
-        /** @hidden */
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
          * Loader state or null if the loader is not active.
          */
         readonly state: Nullable<GLTFLoaderState>;
-        /**
-         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
-         */
+        constructor(parent: GLTFFileLoader);
         dispose(): void;
-        /**
-         * Imports one or more meshes from the loaded glTF data and adds them to the scene
-         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-         * @param scene the scene the meshes should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise containg the loaded meshes, particles, skeletons and animations
-         */
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Imports all objects from the loaded glTF data and adds them to the scene
-         * @param scene the scene the objects should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise which completes when objects have been loaded to the scene
-         */
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadAsync(nodes);
         private _loadData(data);
@@ -1284,14 +1125,12 @@ declare module BABYLON.GLTF2 {
         private _checkExtensions();
         private _createRootNode();
         private _loadNodesAsync(nodes);
-        /** @hidden */
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
         private _getAnimationGroups();
         private _startAnimations();
-        /** @hidden */
         _loadNodeAsync(context: string, node: _ILoaderNode): Promise<void>;
         private _loadMeshAsync(context, node, mesh, babylonMesh);
         private _loadPrimitiveAsync(context, node, mesh, primitive, babylonMesh);
@@ -1312,31 +1151,22 @@ declare module BABYLON.GLTF2 {
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
-        /** @hidden */
         _loadBufferViewAsync(context: string, bufferView: _ILoaderBufferView): Promise<ArrayBufferView>;
         private _loadIndicesAccessorAsync(context, accessor);
         private _loadFloatAccessorAsync(context, accessor);
-        /** @hidden */
         _loadVertexBufferViewAsync(context: string, bufferView: _ILoaderBufferView, kind: string): Promise<Buffer>;
         private _loadVertexAccessorAsync(context, accessor, kind);
         private _getDefaultMaterial(drawMode);
         private _loadMaterialMetallicRoughnessPropertiesAsync(context, material, babylonMaterial);
-        /** @hidden */
         _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Promise<void>;
-        /** @hidden */
         _createMaterial(name: string, drawMode: number): PBRMaterial;
-        /** @hidden */
         _loadMaterialBasePropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void>;
-        /** @hidden */
         _loadMaterialAlphaProperties(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): void;
-        /** @hidden */
         _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
         private _loadImageAsync(context, image);
-        /** @hidden */
         _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
         private _onProgress();
-        /** @hidden */
         static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
         private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
@@ -1346,8 +1176,6 @@ declare module BABYLON.GLTF2 {
         private static _GetDrawMode(context, mode);
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
-        private _clear();
-        /** @hidden */
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
 }

+ 187 - 243
dist/preview release/loaders/babylonjs.loaders.js

@@ -1092,6 +1092,15 @@ var BABYLON;
             /** @hidden */
             this._normalizeAnimationGroupsToBeginAtZero = true;
             /**
+             * Defines if the loader logging is enabled.
+             */
+            this.loggingEnabled = false;
+            /**
+             * Observable raised when the loader logs a message.
+             */
+            this.onLogObservable = new BABYLON.Observable();
+            this._logIndentLevel = 0;
+            /**
              * Function called before loading a url referenced by the asset.
              */
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
@@ -1153,6 +1162,23 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /** @hidden */
+        GLTFFileLoader.prototype._log = function (message) {
+            if (this.loggingEnabled) {
+                var spaces = GLTFFileLoader._logSpaces.substr(0, this._logIndentLevel * 2);
+                this.onLogObservable.notifyObservers("" + spaces + message);
+                BABYLON.Tools.Log("" + spaces + message);
+            }
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logOpen = function (message) {
+            this._log(message);
+            this._logIndentLevel++;
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._logClose = function () {
+            --this._logIndentLevel;
+        };
         Object.defineProperty(GLTFFileLoader.prototype, "onMeshLoaded", {
             /**
              * Callback raised when the loader creates a mesh after parsing the glTF properties of the mesh.
@@ -1274,6 +1300,12 @@ var BABYLON;
                 this._loader.dispose();
                 this._loader = null;
             }
+            this._clear();
+            this.onDisposeObservable.notifyObservers(undefined);
+            this.onDisposeObservable.clear();
+        };
+        /** @hidden */
+        GLTFFileLoader.prototype._clear = function () {
             this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
@@ -1281,8 +1313,6 @@ var BABYLON;
             this.onCameraLoadedObservable.clear();
             this.onCompleteObservable.clear();
             this.onExtensionLoadedObservable.clear();
-            this.onDisposeObservable.notifyObservers(this);
-            this.onDisposeObservable.clear();
         };
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
@@ -1359,9 +1389,16 @@ var BABYLON;
         GLTFFileLoader.prototype._parse = function (data) {
             var parsedData;
             if (data instanceof ArrayBuffer) {
-                parsedData = GLTFFileLoader._parseBinary(data);
+                if (this.loggingEnabled) {
+                    this._log("Parsing binary");
+                }
+                parsedData = this._parseBinary(data);
             }
             else {
+                if (this.loggingEnabled) {
+                    this._log("Parsing JSON");
+                    this._log("JSON length: " + data.length);
+                }
                 parsedData = {
                     json: JSON.parse(data),
                     bin: null
@@ -1372,9 +1409,16 @@ var BABYLON;
             return parsedData;
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
-            var _this = this;
-            var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
+            if (this.loggingEnabled) {
+                this._log("Asset version: " + asset.version);
+                if (asset.minVersion) {
+                    this._log("Asset minimum version: " + asset.minVersion);
+                }
+                if (asset.generator) {
+                    this._log("Asset generator: " + asset.generator);
+                }
+            }
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
                 throw new Error("Invalid version: " + asset.version);
@@ -1384,7 +1428,7 @@ var BABYLON;
                 if (!minVersion) {
                     throw new Error("Invalid minimum version: " + asset.minVersion);
                 }
-                if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
+                if (GLTFFileLoader._compareVersion(minVersion, { major: 2, minor: 0 }) > 0) {
                     throw new Error("Incompatible minimum version: " + asset.minVersion);
                 }
             }
@@ -1396,48 +1440,31 @@ var BABYLON;
             if (!createLoader) {
                 throw new Error("Unsupported version: " + asset.version);
             }
-            var loader = createLoader();
-            loader.coordinateSystemMode = this.coordinateSystemMode;
-            loader.animationStartMode = this.animationStartMode;
-            loader.compileMaterials = this.compileMaterials;
-            loader.useClipPlane = this.useClipPlane;
-            loader.compileShadowGenerators = this.compileShadowGenerators;
-            loader.transparencyAsCoverage = this.transparencyAsCoverage;
-            loader._normalizeAnimationGroupsToBeginAtZero = this._normalizeAnimationGroupsToBeginAtZero;
-            loader.preprocessUrlAsync = this.preprocessUrlAsync;
-            loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
-            loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
-            loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
-            loader.onCameraLoadedObservable.add(function (camera) { return _this.onCameraLoadedObservable.notifyObservers(camera); });
-            loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onCompleteObservable.add(function () {
-                _this.onMeshLoadedObservable.clear();
-                _this.onTextureLoadedObservable.clear();
-                _this.onMaterialLoadedObservable.clear();
-                _this.onCameraLoadedObservable.clear();
-                _this.onExtensionLoadedObservable.clear();
-                _this.onCompleteObservable.notifyObservers(_this);
-                _this.onCompleteObservable.clear();
-            });
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader.prototype._parseBinary = function (data) {
             var Binary = {
                 Magic: 0x46546C67
             };
+            if (this.loggingEnabled) {
+                this._log("Binary length: " + data.byteLength);
+            }
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
                 throw new Error("Unexpected magic: " + magic);
             }
             var version = binaryReader.readUint32();
+            if (this.loggingEnabled) {
+                this._log("Binary version: " + version);
+            }
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return this._parseV1(binaryReader);
+                case 2: return this._parseV2(binaryReader);
             }
             throw new Error("Unsupported version: " + version);
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV1 = function (binaryReader) {
             var ContentFormat = {
                 JSON: 0
             };
@@ -1464,7 +1491,7 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader.prototype._parseV2 = function (binaryReader) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
@@ -1555,6 +1582,7 @@ var BABYLON;
          * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
+        GLTFFileLoader._logSpaces = "                                ";
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -2978,22 +3006,6 @@ var BABYLON;
         */
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader() {
-                // #region Stubs for IGLTFLoader interface
-                this.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.AUTO;
-                this.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.FIRST;
-                this.compileMaterials = false;
-                this.useClipPlane = false;
-                this.compileShadowGenerators = false;
-                this.transparencyAsCoverage = false;
-                this._normalizeAnimationGroupsToBeginAtZero = true;
-                this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
-                this.onMeshLoadedObservable = new BABYLON.Observable();
-                this.onTextureLoadedObservable = new BABYLON.Observable();
-                this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onCameraLoadedObservable = new BABYLON.Observable();
-                this.onCompleteObservable = new BABYLON.Observable();
-                this.onDisposeObservable = new BABYLON.Observable();
-                this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.state = null;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -3003,8 +3015,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
-            GLTFLoader.prototype.dispose = function () { };
-            // #endregion
+            GLTFLoader.prototype.dispose = function () {
+                // do nothing
+            };
             GLTFLoader.prototype._importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
@@ -3815,14 +3828,10 @@ var BABYLON;
             };
             return _ArrayItem;
         }());
-        /**
-         * Loader for loading a glTF 2.0 asset
-         */
+        /** @hidden */
         var GLTFLoader = /** @class */ (function () {
-            function GLTFLoader() {
-                /** @hidden */
+            function GLTFLoader(parent) {
                 this._completePromises = new Array();
-                /** @hidden */
                 this._onReadyObservable = new BABYLON.Observable();
                 this._disposed = false;
                 this._state = null;
@@ -3830,71 +3839,8 @@ var BABYLON;
                 this._defaultSampler = {};
                 this._defaultBabylonMaterials = {};
                 this._requests = new Array();
-                /**
-                 * Mode that determines the coordinate system to use.
-                 */
-                this.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.AUTO;
-                /**
-                 * Mode that determines what animations will start.
-                 */
-                this.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.FIRST;
-                /**
-                 * Defines if the loader should compile materials.
-                 */
-                this.compileMaterials = false;
-                /**
-                 * Defines if the loader should also compile materials with clip planes.
-                 */
-                this.useClipPlane = false;
-                /**
-                 * Defines if the loader should compile shadow generators.
-                 */
-                this.compileShadowGenerators = false;
-                /**
-                 * Defines if the Alpha blended materials are only applied as coverage.
-                 * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-                 * If true, no extra effects are applied to transparent pixels.
-                 */
-                this.transparencyAsCoverage = false;
-                /** @hidden */
-                this._normalizeAnimationGroupsToBeginAtZero = true;
-                /**
-                 * Function called before loading a url referenced by the asset.
-                 */
-                this.preprocessUrlAsync = function (url) { return Promise.resolve(url); };
-                /**
-                 * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-                 */
-                this.onMeshLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-                 */
-                this.onTextureLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-                 */
-                this.onMaterialLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-                 */
-                this.onCameraLoadedObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-                 * For assets with LODs, raised when all of the LODs are complete.
-                 * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-                 */
-                this.onCompleteObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised after the loader is disposed.
-                 */
-                this.onDisposeObservable = new BABYLON.Observable();
-                /**
-                 * Observable raised after a loader extension is created.
-                 * Set additional options for a loader extension in this event.
-                 */
-                this.onExtensionLoadedObservable = new BABYLON.Observable();
+                this._parent = parent;
             }
-            /** @hidden */
             GLTFLoader._Register = function (name, factory) {
                 if (GLTFLoader._ExtensionFactories[name]) {
                     BABYLON.Tools.Error("Extension with the name '" + name + "' already exists");
@@ -3914,27 +3860,28 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
-            /**
-             * Disposes the loader, releases resources during load, and cancels any outstanding requests.
-             */
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
                 }
                 this._disposed = true;
-                this.onDisposeObservable.notifyObservers(this);
-                this.onDisposeObservable.clear();
-                this._clear();
+                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
+                    var request = _a[_i];
+                    request.abort();
+                }
+                this._requests.length = 0;
+                delete this._gltf;
+                delete this._babylonScene;
+                this._completePromises.length = 0;
+                this._onReadyObservable.clear();
+                for (var name_1 in this._extensions) {
+                    this._extensions[name_1].dispose();
+                }
+                this._extensions = {};
+                delete this._rootBabylonMesh;
+                delete this._progressCallback;
+                this._parent._clear();
             };
-            /**
-             * Imports one or more meshes from the loaded glTF data and adds them to the scene
-             * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-             * @param scene the scene the meshes should be added to
-             * @param data the glTF data to load
-             * @param rootUrl root url to load from
-             * @param onProgress event that fires when loading progress has occured
-             * @returns a promise containg the loaded meshes, particles, skeletons and animations
-             */
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return Promise.resolve().then(function () {
@@ -3972,14 +3919,6 @@ var BABYLON;
                     });
                 });
             };
-            /**
-             * Imports all objects from the loaded glTF data and adds them to the scene
-             * @param scene the scene the objects should be added to
-             * @param data the glTF data to load
-             * @param rootUrl root url to load from
-             * @param onProgress event that fires when loading progress has occured
-             * @returns a promise which completes when objects have been loaded to the scene
-             */
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return Promise.resolve().then(function () {
@@ -3994,6 +3933,7 @@ var BABYLON;
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this._state = BABYLON.GLTFLoaderState.LOADING;
+                    _this._parent._log("Loading");
                     _this._loadExtensions();
                     _this._checkExtensions();
                     var promises = new Array();
@@ -4004,14 +3944,15 @@ var BABYLON;
                         var scene = GLTFLoader._GetProperty("#/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                         promises.push(_this._loadSceneAsync("#/scenes/" + scene._index, scene));
                     }
-                    if (_this.compileMaterials) {
+                    if (_this._parent.compileMaterials) {
                         promises.push(_this._compileMaterialsAsync());
                     }
-                    if (_this.compileShadowGenerators) {
+                    if (_this._parent.compileShadowGenerators) {
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
                         _this._state = BABYLON.GLTFLoaderState.READY;
+                        _this._parent._log("Ready");
                         _this._onReadyObservable.notifyObservers(_this);
                         _this._startAnimations();
                     });
@@ -4023,12 +3964,13 @@ var BABYLON;
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
                                     _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this.onCompleteObservable.notifyObservers(_this);
-                                    _this.onCompleteObservable.clear();
-                                    _this._clear();
+                                    _this._parent._log("Complete");
+                                    _this._parent.onCompleteObservable.notifyObservers(undefined);
+                                    _this._parent.onCompleteObservable.clear();
+                                    _this.dispose();
                                 }).catch(function (error) {
                                     BABYLON.Tools.Error("glTF Loader: " + error.message);
-                                    _this._clear();
+                                    _this.dispose();
                                 });
                             }
                         });
@@ -4037,7 +3979,7 @@ var BABYLON;
                 }).catch(function (error) {
                     if (!_this._disposed) {
                         BABYLON.Tools.Error("glTF Loader: " + error.message);
-                        _this._clear();
+                        _this.dispose();
                         throw error;
                     }
                 });
@@ -4094,20 +4036,20 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadExtensions = function () {
                 for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
-                    var name_1 = _a[_i];
-                    var extension = GLTFLoader._ExtensionFactories[name_1](this);
-                    this._extensions[name_1] = extension;
-                    this.onExtensionLoadedObservable.notifyObservers(extension);
+                    var name_2 = _a[_i];
+                    var extension = GLTFLoader._ExtensionFactories[name_2](this);
+                    this._extensions[name_2] = extension;
+                    this._parent.onExtensionLoadedObservable.notifyObservers(extension);
                 }
-                this.onExtensionLoadedObservable.clear();
+                this._parent.onExtensionLoadedObservable.clear();
             };
             GLTFLoader.prototype._checkExtensions = function () {
                 if (this._gltf.extensionsRequired) {
                     for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
-                        var name_2 = _a[_i];
-                        var extension = this._extensions[name_2];
+                        var name_3 = _a[_i];
+                        var extension = this._extensions[name_3];
                         if (!extension || !extension.enabled) {
-                            throw new Error("Require extension " + name_2 + " is not available");
+                            throw new Error("Require extension " + name_3 + " is not available");
                         }
                     }
                 }
@@ -4116,7 +4058,7 @@ var BABYLON;
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 this._rootBabylonMesh.setEnabled(false);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
-                switch (this.coordinateSystemMode) {
+                switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                         if (!this._babylonScene.useRightHandedSystem) {
                             rootNode.rotation = [0, 1, 0, 0];
@@ -4130,10 +4072,10 @@ var BABYLON;
                         break;
                     }
                     default: {
-                        throw new Error("Invalid coordinate system mode (" + this.coordinateSystemMode + ")");
+                        throw new Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
                     }
                 }
-                this.onMeshLoadedObservable.notifyObservers(this._rootBabylonMesh);
+                this._parent.onMeshLoadedObservable.notifyObservers(this._rootBabylonMesh);
                 return rootNode;
             };
             GLTFLoader.prototype._loadNodesAsync = function (nodes) {
@@ -4145,19 +4087,22 @@ var BABYLON;
                 promises.push(this._loadAnimationsAsync());
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadSceneAsync = function (context, scene) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
                 if (promise) {
                     return promise;
                 }
                 var promises = new Array();
-                for (var _i = 0, _a = scene.nodes; _i < _a.length; _i++) {
-                    var index = _a[_i];
-                    var node = GLTFLoader._GetProperty(context + "/nodes/" + index, this._gltf.nodes, index);
-                    promises.push(this._loadNodeAsync("#/nodes/" + node._index, node));
+                this._parent._logOpen(context + " " + (scene.name || ""));
+                if (scene.nodes) {
+                    for (var _i = 0, _a = scene.nodes; _i < _a.length; _i++) {
+                        var index = _a[_i];
+                        var node = GLTFLoader._GetProperty(context + "/nodes/" + index, this._gltf.nodes, index);
+                        promises.push(this._loadNodeAsync("#/nodes/" + node._index, node));
+                    }
                 }
                 promises.push(this._loadAnimationsAsync());
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._forEachPrimitive = function (node, callback) {
@@ -4219,7 +4164,7 @@ var BABYLON;
                 return animationGroups;
             };
             GLTFLoader.prototype._startAnimations = function () {
-                switch (this.animationStartMode) {
+                switch (this._parent.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
                         break;
@@ -4240,12 +4185,11 @@ var BABYLON;
                         break;
                     }
                     default: {
-                        BABYLON.Tools.Error("Invalid animation start mode (" + this.animationStartMode + ")");
+                        BABYLON.Tools.Error("Invalid animation start mode (" + this._parent.animationStartMode + ")");
                         return;
                     }
                 }
             };
-            /** @hidden */
             GLTFLoader.prototype._loadNodeAsync = function (context, node) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadNodeAsync(this, context, node);
                 if (promise) {
@@ -4255,6 +4199,7 @@ var BABYLON;
                     throw new Error(context + ": Invalid recursive node hierarchy");
                 }
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (node.name || ""));
                 var babylonMesh = new BABYLON.Mesh(node.name || "node" + node._index, this._babylonScene, node._parent ? node._parent._babylonMesh : null);
                 node._babylonMesh = babylonMesh;
                 GLTFLoader._LoadTransform(node, babylonMesh);
@@ -4273,12 +4218,14 @@ var BABYLON;
                         promises.push(this._loadNodeAsync("#/nodes/" + index, childNode));
                     }
                 }
-                this.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, babylonMesh) {
                 var _this = this;
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (mesh.name || ""));
                 var primitives = mesh.primitives;
                 if (!primitives || primitives.length === 0) {
                     throw new Error(context + ": Primitives are missing");
@@ -4295,13 +4242,14 @@ var BABYLON;
                         var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive._index, this._babylonScene, babylonMesh);
                         node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                         promises.push(this._loadPrimitiveAsync(context + "/primitives/" + primitive._index, node, mesh, primitive, primitiveBabylonMesh));
-                        this.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                        this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
                     }
                 }
                 if (node.skin != undefined) {
                     var skin = GLTFLoader._GetProperty(context + "/skin", this._gltf.skins, node.skin);
                     promises.push(this._loadSkinAsync("#/skins/" + skin._index, node, mesh, skin));
                 }
+                this._parent._logClose();
                 return Promise.all(promises).then(function () {
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh._refreshBoundingInfo(true);
@@ -4311,6 +4259,7 @@ var BABYLON;
             GLTFLoader.prototype._loadPrimitiveAsync = function (context, node, mesh, primitive, babylonMesh) {
                 var _this = this;
                 var promises = new Array();
+                this._parent._logOpen("" + context);
                 this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
                 promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then(function (babylonGeometry) {
                     return _this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonGeometry).then(function () {
@@ -4327,6 +4276,7 @@ var BABYLON;
                         babylonMesh.material = babylonMaterial;
                     }));
                 }
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
@@ -4585,7 +4535,7 @@ var BABYLON;
                         throw new Error(context + ": Invalid camera type (" + camera.type + ")");
                     }
                 }
-                this.onCameraLoadedObservable.notifyObservers(babylonCamera);
+                this._parent.onCameraLoadedObservable.notifyObservers(babylonCamera);
             };
             GLTFLoader.prototype._loadAnimationsAsync = function () {
                 var animations = this._gltf.animations;
@@ -4611,7 +4561,7 @@ var BABYLON;
                     promises.push(this._loadAnimationChannelAsync(context + "/channels/" + channel._index, context, animation, channel, babylonAnimationGroup));
                 }
                 return Promise.all(promises).then(function () {
-                    babylonAnimationGroup.normalize(_this._normalizeAnimationGroupsToBeginAtZero ? 0 : null);
+                    babylonAnimationGroup.normalize(_this._parent._normalizeAnimationGroupsToBeginAtZero ? 0 : null);
                 });
             };
             GLTFLoader.prototype._loadAnimationChannelAsync = function (context, animationContext, animation, channel, babylonAnimationGroup) {
@@ -4805,7 +4755,6 @@ var BABYLON;
                 buffer._data = this._loadUriAsync(context, buffer.uri);
                 return buffer._data;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadBufferViewAsync = function (context, bufferView) {
                 if (bufferView._data) {
                     return bufferView._data;
@@ -4884,7 +4833,6 @@ var BABYLON;
                 }
                 return accessor._data;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadVertexBufferViewAsync = function (context, bufferView, kind) {
                 var _this = this;
                 if (bufferView._babylonBuffer) {
@@ -4921,7 +4869,7 @@ var BABYLON;
                     babylonMaterial.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE;
                     babylonMaterial.metallic = 1;
                     babylonMaterial.roughness = 1;
-                    this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                    this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                 }
                 return babylonMaterial;
             };
@@ -4958,7 +4906,6 @@ var BABYLON;
                 this._loadMaterialAlphaProperties(context, material, babylonMaterial);
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
                 var promise = GLTF2.GLTFLoaderExtension._LoadMaterialAsync(this, context, material, mesh, babylonMesh, babylonDrawMode, assign);
                 if (promise) {
@@ -4968,33 +4915,33 @@ var BABYLON;
                 var babylonData = material._babylonData[babylonDrawMode];
                 if (!babylonData) {
                     var promises = new Array();
-                    var name_3 = material.name || "material_" + material._index;
-                    var babylonMaterial = this._createMaterial(name_3, babylonDrawMode);
+                    this._parent._logOpen(context + " " + (material.name || ""));
+                    var name_4 = material.name || "material_" + material._index;
+                    var babylonMaterial = this._createMaterial(name_4, babylonDrawMode);
                     promises.push(this._loadMaterialBasePropertiesAsync(context, material, babylonMaterial));
                     promises.push(this._loadMaterialMetallicRoughnessPropertiesAsync(context, material, babylonMaterial));
-                    this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                    this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                     babylonData = {
                         material: babylonMaterial,
                         meshes: [],
                         loaded: Promise.all(promises).then(function () { })
                     };
                     material._babylonData[babylonDrawMode] = babylonData;
+                    this._parent._logClose();
                 }
                 babylonData.meshes.push(babylonMesh);
                 assign(babylonData.material);
                 return babylonData.loaded;
             };
-            /** @hidden */
             GLTFLoader.prototype._createMaterial = function (name, drawMode) {
                 var babylonMaterial = new BABYLON.PBRMaterial(name, this._babylonScene);
                 babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? BABYLON.Material.CounterClockWiseSideOrientation : BABYLON.Material.ClockWiseSideOrientation;
                 babylonMaterial.fillMode = drawMode;
                 babylonMaterial.enableSpecularAntiAliasing = true;
-                babylonMaterial.useRadianceOverAlpha = !this.transparencyAsCoverage;
-                babylonMaterial.useSpecularOverAlpha = !this.transparencyAsCoverage;
+                babylonMaterial.useRadianceOverAlpha = !this._parent.transparencyAsCoverage;
+                babylonMaterial.useSpecularOverAlpha = !this._parent.transparencyAsCoverage;
                 return babylonMaterial;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialBasePropertiesAsync = function (context, material, babylonMaterial) {
                 var promises = new Array();
                 babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
@@ -5028,7 +4975,6 @@ var BABYLON;
                 }
                 return Promise.all(promises).then(function () { });
             };
-            /** @hidden */
             GLTFLoader.prototype._loadMaterialAlphaProperties = function (context, material, babylonMaterial) {
                 var alphaMode = material.alphaMode || "OPAQUE" /* OPAQUE */;
                 switch (alphaMode) {
@@ -5057,16 +5003,17 @@ var BABYLON;
                     }
                 }
             };
-            /** @hidden */
             GLTFLoader.prototype._loadTextureAsync = function (context, textureInfo, assign) {
                 var _this = this;
                 var promise = GLTF2.GLTFLoaderExtension._LoadTextureAsync(this, context, textureInfo, assign);
                 if (promise) {
                     return promise;
                 }
+                this._parent._logOpen("" + context);
                 var texture = GLTFLoader._GetProperty(context + "/index", this._gltf.textures, textureInfo.index);
                 context = "#/textures/" + textureInfo.index;
                 var promises = new Array();
+                this._parent._logOpen(context + " " + (texture.name || ""));
                 var sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(context + "/sampler", this._gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("#/samplers/" + sampler._index, sampler);
                 var deferred = new BABYLON.Deferred();
@@ -5090,7 +5037,9 @@ var BABYLON;
                     babylonTexture.updateURL(dataUrl, blob);
                 }));
                 assign(babylonTexture);
-                this.onTextureLoadedObservable.notifyObservers(babylonTexture);
+                this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
+                this._parent._logClose();
+                this._parent._logClose();
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader.prototype._loadSampler = function (context, sampler) {
@@ -5106,23 +5055,23 @@ var BABYLON;
                 return sampler._data;
             };
             GLTFLoader.prototype._loadImageAsync = function (context, image) {
-                if (image._blob) {
-                    return image._blob;
-                }
-                var promise;
-                if (image.uri) {
-                    promise = this._loadUriAsync(context, image.uri);
-                }
-                else {
-                    var bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, image.bufferView);
-                    promise = this._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                if (!image._blob) {
+                    this._parent._logOpen(context + " " + (image.name || ""));
+                    var promise = void 0;
+                    if (image.uri) {
+                        promise = this._loadUriAsync(context, image.uri);
+                    }
+                    else {
+                        var bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, image.bufferView);
+                        promise = this._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                    }
+                    image._blob = promise.then(function (data) {
+                        return new Blob([data], { type: image.mimeType });
+                    });
+                    this._parent._logClose();
                 }
-                image._blob = promise.then(function (data) {
-                    return new Blob([data], { type: image.mimeType });
-                });
                 return image._blob;
             };
-            /** @hidden */
             GLTFLoader.prototype._loadUriAsync = function (context, uri) {
                 var _this = this;
                 var promise = GLTF2.GLTFLoaderExtension._LoadUriAsync(this, context, uri);
@@ -5133,27 +5082,34 @@ var BABYLON;
                     throw new Error(context + ": Uri '" + uri + "' is invalid");
                 }
                 if (BABYLON.Tools.IsBase64(uri)) {
-                    return Promise.resolve(new Uint8Array(BABYLON.Tools.DecodeBase64(uri)));
+                    var data = new Uint8Array(BABYLON.Tools.DecodeBase64(uri));
+                    this._parent._log("Decoded " + uri.substr(0, 64) + "... (" + data.length + " bytes)");
+                    return Promise.resolve(data);
                 }
-                return this.preprocessUrlAsync(this._rootUrl + uri).then(function (url) {
+                this._parent._log("Loading " + uri);
+                return this._parent.preprocessUrlAsync(this._rootUrl + uri).then(function (url) {
                     return new Promise(function (resolve, reject) {
                         if (!_this._disposed) {
-                            var request_1 = BABYLON.Tools.LoadFile(url, function (data) {
+                            var request_1 = BABYLON.Tools.LoadFile(url, function (fileData) {
                                 if (!_this._disposed) {
-                                    resolve(new Uint8Array(data));
+                                    var data = new Uint8Array(fileData);
+                                    _this._parent._log("Loaded " + uri + " (" + data.length + " bytes)");
+                                    resolve(data);
                                 }
                             }, function (event) {
                                 if (!_this._disposed) {
-                                    try {
-                                        if (request_1 && _this._state === BABYLON.GLTFLoaderState.LOADING) {
-                                            request_1._lengthComputable = event.lengthComputable;
-                                            request_1._loaded = event.loaded;
-                                            request_1._total = event.total;
+                                    if (request_1) {
+                                        request_1._lengthComputable = event.lengthComputable;
+                                        request_1._loaded = event.loaded;
+                                        request_1._total = event.total;
+                                    }
+                                    if (_this._state === BABYLON.GLTFLoaderState.LOADING) {
+                                        try {
                                             _this._onProgress();
                                         }
-                                    }
-                                    catch (e) {
-                                        reject(e);
+                                        catch (e) {
+                                            reject(e);
+                                        }
                                     }
                                 }
                             }, _this._babylonScene.database, true, function (request, exception) {
@@ -5184,7 +5140,6 @@ var BABYLON;
                 }
                 this._progressCallback(new BABYLON.SceneLoaderProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
             };
-            /** @hidden */
             GLTFLoader._GetProperty = function (context, array, index) {
                 if (!array || index == undefined || !array[index]) {
                     throw new Error(context + ": Failed to find index (" + index + ")");
@@ -5299,7 +5254,7 @@ var BABYLON;
                                     babylonMesh.computeWorldMatrix(true);
                                     var babylonMaterial = babylonData.material;
                                     promises.push(babylonMaterial.forceCompilationAsync(babylonMesh));
-                                    if (this.useClipPlane) {
+                                    if (this._parent.useClipPlane) {
                                         promises.push(babylonMaterial.forceCompilationAsync(babylonMesh, { clipPlane: true }));
                                     }
                                 }
@@ -5321,28 +5276,6 @@ var BABYLON;
                 }
                 return Promise.all(promises).then(function () { });
             };
-            GLTFLoader.prototype._clear = function () {
-                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
-                    var request = _a[_i];
-                    request.abort();
-                }
-                this._requests.length = 0;
-                delete this._gltf;
-                delete this._babylonScene;
-                this._completePromises.length = 0;
-                this._onReadyObservable.clear();
-                for (var name_4 in this._extensions) {
-                    this._extensions[name_4].dispose();
-                }
-                this._extensions = {};
-                delete this._rootBabylonMesh;
-                delete this._progressCallback;
-                this.onMeshLoadedObservable.clear();
-                this.onTextureLoadedObservable.clear();
-                this.onMaterialLoadedObservable.clear();
-                this.onCameraLoadedObservable.clear();
-            };
-            /** @hidden */
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
                     var name_5 = _a[_i];
@@ -5361,7 +5294,7 @@ var BABYLON;
             return GLTFLoader;
         }());
         GLTF2.GLTFLoader = GLTFLoader;
-        BABYLON.GLTFFileLoader._CreateGLTFLoaderV2 = function () { return new GLTFLoader(); };
+        BABYLON.GLTFFileLoader._CreateGLTFLoaderV2 = function (parent) { return new GLTFLoader(parent); };
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
@@ -5563,6 +5496,7 @@ var BABYLON;
                     _this._loader._onReadyObservable.addOnce(function () {
                         var _loop_1 = function (indexLOD) {
                             Promise.all(_this._loadNodePromises[indexLOD]).then(function () {
+                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
                                 _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
                             });
                         };
@@ -5571,6 +5505,7 @@ var BABYLON;
                         }
                         var _loop_2 = function (indexLOD) {
                             Promise.all(_this._loadMaterialPromises[indexLOD]).then(function () {
+                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
                                 _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
                             });
                         };
@@ -5594,6 +5529,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
                         var firstPromise;
                         var nodeLODs = _this._getLODs(extensionContext, node, _this._loader._gltf.nodes, extension.ids);
+                        _this._loader._parent._logOpen("" + extensionContext);
                         var _loop_3 = function (indexLOD) {
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
@@ -5631,6 +5567,7 @@ var BABYLON;
                         for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
                             _loop_3(indexLOD);
                         }
+                        _this._loader._parent._logClose();
                         return firstPromise;
                     });
                 };
@@ -5643,6 +5580,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {
                         var firstPromise;
                         var materialLODs = _this._getLODs(extensionContext, material, _this._loader._gltf.materials, extension.ids);
+                        _this._loader._parent._logOpen("" + extensionContext);
                         var _loop_4 = function (indexLOD) {
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
@@ -5682,11 +5620,17 @@ var BABYLON;
                         for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
                             _loop_4(indexLOD);
                         }
+                        _this._loader._parent._logClose();
                         return firstPromise;
                     });
                 };
                 MSFT_lod.prototype._loadUriAsync = function (context, uri) {
                     var _this = this;
+                    if (this._loadingMaterialLOD || this._loadingNodeLOD) {
+                        if (this._loader._parent.loggingEnabled) {
+                            this._loader._parent._log("deferred");
+                        }
+                    }
                     // Defer the loading of uris if loading a material or node LOD.
                     if (this._loadingMaterialLOD) {
                         var index = this._loadingMaterialLOD._index;
@@ -5938,7 +5882,7 @@ var BABYLON;
                             var babylonMaterial = _this._loader._createMaterial(name_1, babylonDrawMode);
                             promises.push(_this._loader._loadMaterialBasePropertiesAsync(context, material, babylonMaterial));
                             promises.push(_this._loadSpecularGlossinessPropertiesAsync(extensionContext, material, extension, babylonMaterial));
-                            _this._loader.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            _this._loader._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                             babylonData = {
                                 material: babylonMaterial,
                                 meshes: [],
@@ -6016,7 +5960,7 @@ var BABYLON;
                             var babylonMaterial = _this._loader._createMaterial(name_1, babylonDrawMode);
                             babylonMaterial.unlit = true;
                             var promise = _this._loadUnlitPropertiesAsync(context, material, babylonMaterial);
-                            _this._loader.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            _this._loader._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                             babylonData = {
                                 material: babylonMaterial,
                                 meshes: [],

Разлика између датотеке није приказан због своје велике величине
+ 4 - 4
dist/preview release/loaders/babylonjs.loaders.min.js


+ 30 - 202
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -176,89 +176,15 @@ declare module BABYLON {
          */
         COMPLETE = 2,
     }
-    /**
-     * Loader interface.
-     */
+    /** @hidden */
     interface IGLTFLoader extends IDisposable {
-        /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
-         * Loader state or null if the loader is not active.
-         */
-        state: Nullable<GLTFLoaderState>;
-        /**
-         * Imports meshes from the given data and adds them to the scene.
-         */
+        readonly state: Nullable<GLTFLoaderState>;
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Loads all objects from the given data and adds them to the scene.
-         */
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     /**
@@ -266,9 +192,9 @@ declare module BABYLON {
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         /** @hidden */
-        static _CreateGLTFLoaderV1: () => IGLTFLoader;
+        static _CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         /** @hidden */
-        static _CreateGLTFLoaderV2: () => IGLTFLoader;
+        static _CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
          */
@@ -320,6 +246,22 @@ declare module BABYLON {
         /** @hidden */
         _normalizeAnimationGroupsToBeginAtZero: boolean;
         /**
+         * Defines if the loader logging is enabled.
+         */
+        loggingEnabled: boolean;
+        /**
+         * Observable raised when the loader logs a message.
+         */
+        readonly onLogObservable: Observable<string>;
+        private _logIndentLevel;
+        private static readonly _logSpaces;
+        /** @hidden */
+        _log(message: string): void;
+        /** @hidden */
+        _logOpen(message: string): void;
+        /** @hidden */
+        _logClose(): void;
+        /**
          * Function called before loading a url referenced by the asset.
          */
         preprocessUrlAsync: (url: string) => Promise<string>;
@@ -364,7 +306,7 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
          */
-        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<void>;
         private _onCompleteObserver;
         /**
          * Callback raised when the asset is completely loaded, immediately before the loader is disposed.
@@ -373,7 +315,7 @@ declare module BABYLON {
         /**
          * Observable raised after the loader is disposed.
          */
-        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<void>;
         private _onDisposeObserver;
         /**
          * Callback raised after the loader is disposed.
@@ -411,6 +353,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
+        /** @hidden */
+        _clear(): void;
         /**
          * Imports one or more meshes from the loaded glTF data and adds them to the scene
          * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
@@ -461,9 +405,9 @@ declare module BABYLON {
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         private _parse(data);
         private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private _parseBinary(data);
+        private _parseV1(binaryReader);
+        private _parseV2(binaryReader);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(buffer);
@@ -863,21 +807,6 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        compileMaterials: boolean;
-        useClipPlane: boolean;
-        compileShadowGenerators: boolean;
-        transparencyAsCoverage: boolean;
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         state: Nullable<GLTFLoaderState>;
         dispose(): void;
         private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress?, onError?);
@@ -1164,17 +1093,12 @@ declare module BABYLON.GLTF2 {
  * Defines the module used to import/export glTF 2.0 assets
  */
 declare module BABYLON.GLTF2 {
-    /**
-     * Loader for loading a glTF 2.0 asset
-     */
+    /** @hidden */
     class GLTFLoader implements IGLTFLoader {
-        /** @hidden */
+        _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
-        /** @hidden */
         _babylonScene: Scene;
-        /** @hidden */
         _completePromises: Promise<void>[];
-        /** @hidden */
         _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
@@ -1187,102 +1111,19 @@ declare module BABYLON.GLTF2 {
         private _requests;
         private static _ExtensionNames;
         private static _ExtensionFactories;
-        /** @hidden */
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         /**
-         * Mode that determines the coordinate system to use.
-         */
-        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
-        /**
-         * Mode that determines what animations will start.
-         */
-        animationStartMode: GLTFLoaderAnimationStartMode;
-        /**
-         * Defines if the loader should compile materials.
-         */
-        compileMaterials: boolean;
-        /**
-         * Defines if the loader should also compile materials with clip planes.
-         */
-        useClipPlane: boolean;
-        /**
-         * Defines if the loader should compile shadow generators.
-         */
-        compileShadowGenerators: boolean;
-        /**
-         * Defines if the Alpha blended materials are only applied as coverage.
-         * If false, (default) The luminance of each pixel will reduce its opacity to simulate the behaviour of most physical materials.
-         * If true, no extra effects are applied to transparent pixels.
-         */
-        transparencyAsCoverage: boolean;
-        /** @hidden */
-        _normalizeAnimationGroupsToBeginAtZero: boolean;
-        /**
-         * Function called before loading a url referenced by the asset.
-         */
-        preprocessUrlAsync: (url: string) => Promise<string>;
-        /**
-         * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
-         */
-        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
-        /**
-         * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
-         */
-        readonly onTextureLoadedObservable: Observable<BaseTexture>;
-        /**
-         * Observable raised when the loader creates a material after parsing the glTF properties of the material.
-         */
-        readonly onMaterialLoadedObservable: Observable<Material>;
-        /**
-         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
-         */
-        readonly onCameraLoadedObservable: Observable<Camera>;
-        /**
-         * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
-         * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
-         */
-        readonly onCompleteObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after the loader is disposed.
-         */
-        readonly onDisposeObservable: Observable<IGLTFLoader>;
-        /**
-         * Observable raised after a loader extension is created.
-         * Set additional options for a loader extension in this event.
-         */
-        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
-        /**
          * Loader state or null if the loader is not active.
          */
         readonly state: Nullable<GLTFLoaderState>;
-        /**
-         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
-         */
+        constructor(parent: GLTFFileLoader);
         dispose(): void;
-        /**
-         * Imports one or more meshes from the loaded glTF data and adds them to the scene
-         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
-         * @param scene the scene the meshes should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise containg the loaded meshes, particles, skeletons and animations
-         */
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        /**
-         * Imports all objects from the loaded glTF data and adds them to the scene
-         * @param scene the scene the objects should be added to
-         * @param data the glTF data to load
-         * @param rootUrl root url to load from
-         * @param onProgress event that fires when loading progress has occured
-         * @returns a promise which completes when objects have been loaded to the scene
-         */
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadAsync(nodes);
         private _loadData(data);
@@ -1291,14 +1132,12 @@ declare module BABYLON.GLTF2 {
         private _checkExtensions();
         private _createRootNode();
         private _loadNodesAsync(nodes);
-        /** @hidden */
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
         private _getAnimationGroups();
         private _startAnimations();
-        /** @hidden */
         _loadNodeAsync(context: string, node: _ILoaderNode): Promise<void>;
         private _loadMeshAsync(context, node, mesh, babylonMesh);
         private _loadPrimitiveAsync(context, node, mesh, primitive, babylonMesh);
@@ -1319,31 +1158,22 @@ declare module BABYLON.GLTF2 {
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
-        /** @hidden */
         _loadBufferViewAsync(context: string, bufferView: _ILoaderBufferView): Promise<ArrayBufferView>;
         private _loadIndicesAccessorAsync(context, accessor);
         private _loadFloatAccessorAsync(context, accessor);
-        /** @hidden */
         _loadVertexBufferViewAsync(context: string, bufferView: _ILoaderBufferView, kind: string): Promise<Buffer>;
         private _loadVertexAccessorAsync(context, accessor, kind);
         private _getDefaultMaterial(drawMode);
         private _loadMaterialMetallicRoughnessPropertiesAsync(context, material, babylonMaterial);
-        /** @hidden */
         _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Promise<void>;
-        /** @hidden */
         _createMaterial(name: string, drawMode: number): PBRMaterial;
-        /** @hidden */
         _loadMaterialBasePropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void>;
-        /** @hidden */
         _loadMaterialAlphaProperties(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): void;
-        /** @hidden */
         _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
         private _loadImageAsync(context, image);
-        /** @hidden */
         _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
         private _onProgress();
-        /** @hidden */
         static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
         private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
@@ -1353,8 +1183,6 @@ declare module BABYLON.GLTF2 {
         private static _GetDrawMode(context, mode);
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
-        private _clear();
-        /** @hidden */
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
 }

+ 5 - 5
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -46,7 +46,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFSerializer.js.map
 
-/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;
@@ -1245,7 +1245,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFExporter.js.map
 
-/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     /**
@@ -1304,7 +1304,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFData.js.map
 
-/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;
@@ -2410,7 +2410,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFMaterial.js.map
 
-/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;
@@ -3066,7 +3066,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFAnimation.js.map
 
-/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;

+ 117 - 0
gui/src/3D/controls/scatterPanel.ts

@@ -0,0 +1,117 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    /**
+     * Class used to create a container panel where items get randomized planar mapping
+     */
+    export class ScatterPanel extends VolumeBasedPanel {    
+        private _iteration = 100.0;
+
+        /**
+         * Gets or sets the number of iteration to use to scatter the controls (100 by default)
+         */
+        public get iteration(): float {
+            return this._iteration;
+        }
+
+        public set iteration(value: float) {
+            if (this._iteration === value) {
+                return;
+            }
+
+            this._iteration = value;
+
+            Tools.SetImmediate(() => {
+                this._arrangeChildren();               
+            });
+        }    
+
+        protected _mapGridNode(control: Control3D, nodePosition: Vector3) {            
+            let mesh = control.mesh;
+            let newPos = this._scatterMapping(nodePosition);
+
+            if (!mesh) {
+                return;
+            }
+
+            switch (this.orientation) {
+                case Container3D.FACEORIGIN_ORIENTATION:
+                case Container3D.FACEFORWARD_ORIENTATION:
+                    mesh.lookAt(new BABYLON.Vector3(0, 0, -1));
+                    break;
+                case Container3D.FACEFORWARDREVERSED_ORIENTATION:
+                case Container3D.FACEORIGINREVERSED_ORIENTATION:
+                    mesh.lookAt(new BABYLON.Vector3(0, 0, 1));
+                    break;
+            }
+            
+            control.position = newPos;
+        }
+
+        private _scatterMapping(source: Vector3): Vector3
+        {
+            source.x = (1.0 - Math.random() * 2.0) * this._cellWidth;
+            source.y = (1.0 - Math.random() * 2.0) * this._cellHeight;
+
+            return source;
+        }   
+        
+        protected _finalProcessing() {
+            var meshes = [];
+            for (var child of this._children) {
+                if (!child.mesh) {
+                    continue;
+                }                
+
+                meshes.push(child.mesh);
+            }
+
+            for (var count = 0; count < this._iteration; count++) {
+                meshes.sort((a, b) => {
+                    let distance1 = a.position.lengthSquared();
+                    let distance2 = b.position.lengthSquared();
+
+                    if (distance1 < distance2) {
+                        return 1;
+                    } else if (distance1 > distance2) {
+                        return -1;
+                    }
+
+                    return 0;
+                });
+
+                let radiusPaddingSquared = Math.pow(this.margin, 2.0);
+                let cellSize = Math.max(this._cellWidth, this._cellHeight);
+                let difference2D = Tmp.Vector2[0];
+                let difference = Tmp.Vector3[0];
+
+                for (let i = 0; i < meshes.length - 1; i++)
+                {
+                    for (let j = i + 1; j < meshes.length; j++)
+                    {
+                        if (i != j)
+                        {
+                            meshes[j].position.subtractToRef(meshes[i].position, difference);
+
+                            // Ignore Z axis
+                            difference2D.x = difference.x;
+                            difference2D.y = difference.y;
+                            let combinedRadius = cellSize;
+                            let distance = difference2D.lengthSquared()- radiusPaddingSquared;
+                            let minSeparation = Math.min(distance, radiusPaddingSquared);
+                            distance -= minSeparation;
+
+                            if (distance < (Math.pow(combinedRadius, 2.0)))
+                            {
+                                difference2D.normalize();
+                                difference.scaleInPlace((combinedRadius - Math.sqrt(distance)) * 0.5);
+                                meshes[j].position.addInPlace(difference);
+                                meshes[i].position.subtractInPlace(difference);
+                            }
+                        }
+                    }
+                }
+            }        
+        }
+    }
+}

+ 20 - 10
gui/src/3D/controls/volumeBasedPanel.ts

@@ -11,6 +11,9 @@ module BABYLON.GUI {
         
         private _orientation = Container3D.FACEORIGIN_ORIENTATION;
 
+        protected _cellWidth: number;
+        protected _cellHeight: number;
+
         /**
          * Gets or sets the distance between elements
          */
@@ -92,8 +95,8 @@ module BABYLON.GUI {
         }        
 
         protected _arrangeChildren() {
-            let cellWidth = 0;
-            let cellHeight = 0;
+            this._cellWidth = 0;
+            this._cellHeight = 0;
             let rows = 0;
             let columns = 0;
             let controlCount = 0;
@@ -113,12 +116,12 @@ module BABYLON.GUI {
                 let boundingBox = child.mesh.getBoundingInfo().boundingBox;
                 let extendSize = Vector3.TransformNormal(boundingBox.extendSize, Tmp.Matrix[0]);
 
-                cellWidth = Math.max(cellWidth, extendSize.x * 2);
-                cellHeight = Math.max(cellHeight, extendSize.y * 2);
+                this._cellWidth = Math.max(this._cellWidth, extendSize.x * 2);
+                this._cellHeight = Math.max(this._cellHeight, extendSize.y * 2);
             }
 
-            cellWidth += this.margin * 2;
-            cellHeight += this.margin * 2;
+            this._cellWidth += this.margin * 2;
+            this._cellHeight += this.margin * 2;
 
             // Arrange
             if (this._rowThenColum) {
@@ -129,8 +132,8 @@ module BABYLON.GUI {
                 columns = Math.ceil(controlCount / this._rows);
             }
 
-            let startOffsetX = (columns * 0.5) * cellWidth;
-            let startOffsetY = (rows * 0.5) * cellHeight;
+            let startOffsetX = (columns * 0.5) * this._cellWidth;
+            let startOffsetY = (rows * 0.5) * this._cellHeight;
             let nodeGrid = [];
             let cellCounter = 0;
 
@@ -139,7 +142,7 @@ module BABYLON.GUI {
                 {
                     for (var c = 0; c < columns; c++)
                     {
-                        nodeGrid.push(new Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                        nodeGrid.push(new Vector3((c * this._cellWidth) - startOffsetX + this._cellWidth / 2, (r * this._cellHeight) - startOffsetY + this._cellHeight / 2, 0));
                         cellCounter++;
                         if (cellCounter > controlCount)
                         {
@@ -152,7 +155,7 @@ module BABYLON.GUI {
                 {
                     for (var r = 0; r < rows; r++)
                     {
-                        nodeGrid.push(new Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                        nodeGrid.push(new Vector3((c * this._cellWidth) - startOffsetX + this._cellWidth / 2, (r * this._cellHeight) - startOffsetY + this._cellHeight / 2, 0));
                         cellCounter++;
                         if (cellCounter > controlCount)
                         {
@@ -172,9 +175,16 @@ module BABYLON.GUI {
 
                 cellCounter++;
             }
+
+            this._finalProcessing();
         }
 
         /** Child classes must implement this function to provide correct control positioning */
         protected abstract _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+
+        /** Child classes can implement this function to provide additional processing */
+        protected _finalProcessing() {
+
+        }
     }
 }