Преглед на файлове

Fix bug with texture atlas and dynamic textures

David Catuhe преди 7 години
родител
ревизия
be3acc46b4
променени са 27 файла, в които са добавени 19252 реда и са изтрити 19106 реда
  1. 7669 7645
      Playground/babylon.d.txt
  2. 9995 9966
      dist/preview release/babylon.d.ts
  3. 27 27
      dist/preview release/babylon.js
  4. 108 66
      dist/preview release/babylon.max.js
  5. 27 27
      dist/preview release/babylon.worker.js
  6. 858 829
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  7. 29 29
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  8. 121 83
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  9. 121 83
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  10. 108 66
      dist/preview release/es6.js
  11. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  12. 13 17
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  13. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  14. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  15. 13 17
      dist/preview release/loaders/babylon.glTFFileLoader.js
  16. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  17. 13 17
      dist/preview release/loaders/babylonjs.loaders.js
  18. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  19. 1 1
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  20. 2 100
      dist/preview release/typedocValidationBaseline.json
  21. 19 19
      dist/preview release/viewer/babylon.viewer.js
  22. 2 2
      dist/preview release/what's new.md
  23. 23 23
      src/Debug/babylon.rayHelper.ts
  24. 80 70
      src/Engine/babylon.engine.ts
  25. 1 1
      src/Engine/babylon.nullEngine.ts
  26. 5 1
      src/babylon.mixins.ts
  27. 8 8
      tests/validation/validation.js

Файловите разлики са ограничени, защото са твърде много
+ 7669 - 7645
Playground/babylon.d.txt


Файловите разлики са ограничени, защото са твърде много
+ 9995 - 9966
dist/preview release/babylon.d.ts


Файловите разлики са ограничени, защото са твърде много
+ 27 - 27
dist/preview release/babylon.js


+ 108 - 66
dist/preview release/babylon.max.js

@@ -7483,6 +7483,26 @@ var BABYLON;
             }
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
         };
+        /**
+         * Generates an image screenshot from the specified camera.
+         *
+         * @param engine The engine to use for rendering
+         * @param camera The camera to use for rendering
+         * @param size This parameter can be set to a single number or to an object with the
+         * following (optional) properties: precision, width, height. If a single number is passed,
+         * it will be used for both width and height. If an object is passed, the screenshot size
+         * will be derived from the parameters. The precision property is a multiplier allowing
+         * rendering at a higher or lower resolution.
+         * @param successCallback The callback receives a single parameter which contains the
+         * screenshot as a string of base64-encoded characters. This string can be assigned to the
+         * src parameter of an <img> to display it.
+         * @param mimeType The MIME type of the screenshot image (default: image/png).
+         * Check your browser for supported MIME types.
+         * @param samples Texture samples (default: 1)
+         * @param antialiasing Whether antialiasing should be turned on or not (default: false)
+         * @param fileName A name for for the downloaded file.
+         * @constructor
+         */
         Tools.CreateScreenshotUsingRenderTarget = function (engine, camera, size, successCallback, mimeType, samples, antialiasing, fileName) {
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (samples === void 0) { samples = 1; }
@@ -8885,9 +8905,10 @@ var BABYLON;
     var Engine = /** @class */ (function () {
         /**
          * @constructor
-         * @param {HTMLCanvasElement | WebGLRenderingContext} canvasOrContext - the canvas or the webgl context to be used for rendering
-         * @param {boolean} [antialias] - enable antialias
-         * @param options - further options to be sent to the getContext function
+         * @param canvasOrContext defines the canvas or WebGL context to use for rendering
+         * @param antialias defines enable antialiasing (default: false)
+         * @param options defines further options to be sent to the getContext() function
+         * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
         function Engine(canvasOrContext, antialias, options, adaptToDeviceRatio) {
             if (adaptToDeviceRatio === void 0) { adaptToDeviceRatio = false; }
@@ -8989,6 +9010,8 @@ var BABYLON;
             this._alphaMode = Engine.ALPHA_DISABLE;
             // Cache
             this._internalTexturesCache = new Array();
+            this._activeChannel = 0;
+            this._currentTextureChannel = -1;
             this._boundTexturesCache = {};
             this._boundTexturesStack = new Array();
             this._compiledEffects = {};
@@ -9904,7 +9927,7 @@ var BABYLON;
             for (var slot = 0; slot < this._maxSimultaneousTextures; slot++) {
                 this._nextFreeTextureSlots.push(slot);
             }
-            this._activeChannel = -1;
+            this._currentTextureChannel = -1;
         };
         Engine.prototype.isDeterministicLockStep = function () {
             return this._deterministicLockstep;
@@ -12687,12 +12710,6 @@ var BABYLON;
             }
             this._currentEffect = null;
         };
-        Engine.prototype._activateTextureChannel = function (channel) {
-            if (this._activeChannel !== channel && channel > -1) {
-                this._gl.activeTexture(this._gl.TEXTURE0 + channel);
-                this._activeChannel = channel;
-            }
-        };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
             var index = this._boundTexturesStack.indexOf(internalTexture);
             if (index > -1 && index !== this._boundTexturesStack.length - 1) {
@@ -12700,6 +12717,34 @@ var BABYLON;
                 this._boundTexturesStack.push(internalTexture);
             }
         };
+        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
+            if (!internalTexture) {
+                return -1;
+            }
+            internalTexture._initialSlot = channel;
+            if (this.disableTextureBindingOptimization) {
+                if (channel !== internalTexture._designatedSlot) {
+                    this._textureCollisions.addCount(1, false);
+                }
+            }
+            else {
+                if (channel !== internalTexture._designatedSlot) {
+                    if (internalTexture._designatedSlot > -1) {
+                        return internalTexture._designatedSlot;
+                    }
+                    else {
+                        // No slot for this texture, let's pick a new one (if we find a free slot)
+                        if (this._nextFreeTextureSlots.length) {
+                            return this._nextFreeTextureSlots[0];
+                        }
+                        // We need to recycle the oldest bound texture, sorry.
+                        this._textureCollisions.addCount(1, false);
+                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
+                    }
+                }
+            }
+            return channel;
+        };
         Engine.prototype._removeDesignatedSlot = function (internalTexture) {
             var currentSlot = internalTexture._designatedSlot;
             internalTexture._designatedSlot = -1;
@@ -12713,31 +12758,42 @@ var BABYLON;
             }
             return currentSlot;
         };
-        Engine.prototype._bindTextureDirectly = function (target, texture, doNotBindUniformToTextureChannel) {
-            if (doNotBindUniformToTextureChannel === void 0) { doNotBindUniformToTextureChannel = false; }
+        Engine.prototype._activateCurrentTexture = function () {
+            if (this._currentTextureChannel !== this._activeChannel) {
+                this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
+                this._currentTextureChannel = this._activeChannel;
+            }
+        };
+        Engine.prototype._bindTextureDirectly = function (target, texture, forTextureDataUpdate) {
+            if (forTextureDataUpdate === void 0) { forTextureDataUpdate = false; }
+            if (forTextureDataUpdate && texture && texture._designatedSlot > -1) {
+                this._activeChannel = texture._designatedSlot;
+            }
             var currentTextureBound = this._boundTexturesCache[this._activeChannel];
             var isTextureForRendering = texture && texture._initialSlot > -1;
             if (currentTextureBound !== texture) {
                 if (currentTextureBound && !this.disableTextureBindingOptimization) {
                     this._removeDesignatedSlot(currentTextureBound);
                 }
+                this._activateCurrentTexture();
                 this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
-                if (this._activeChannel >= 0) {
-                    this._boundTexturesCache[this._activeChannel] = texture;
-                    if (isTextureForRendering && !this.disableTextureBindingOptimization) {
+                this._boundTexturesCache[this._activeChannel] = texture;
+                if (texture) {
+                    if (!this.disableTextureBindingOptimization) {
                         var slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
                         if (slotIndex > -1) {
                             this._nextFreeTextureSlots.splice(slotIndex, 1);
                         }
                         this._boundTexturesStack.push(texture);
                     }
+                    texture._designatedSlot = this._activeChannel;
                 }
             }
-            if (isTextureForRendering && this._activeChannel > -1) {
-                texture._designatedSlot = this._activeChannel;
-                if (!doNotBindUniformToTextureChannel) {
-                    this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
-                }
+            else if (forTextureDataUpdate) {
+                this._activateCurrentTexture();
+            }
+            if (isTextureForRendering && !forTextureDataUpdate) {
+                this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
             }
         };
         Engine.prototype._bindTexture = function (channel, texture) {
@@ -12747,7 +12803,7 @@ var BABYLON;
             if (texture) {
                 channel = this._getCorrectTextureChannel(channel, texture);
             }
-            this._activateTextureChannel(channel);
+            this._activeChannel = channel;
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
         };
         Engine.prototype.setTextureFromPostProcess = function (channel, postProcess) {
@@ -12755,7 +12811,7 @@ var BABYLON;
         };
         Engine.prototype.unbindAllTextures = function () {
             for (var channel = 0; channel < this._maxSimultaneousTextures; channel++) {
-                this._activateTextureChannel(channel);
+                this._activeChannel = channel;
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                 if (this.webGLVersion > 1) {
@@ -12772,44 +12828,20 @@ var BABYLON;
             }
             this._setTexture(channel, texture);
         };
-        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
-            if (!internalTexture) {
-                return -1;
-            }
-            internalTexture._initialSlot = channel;
-            if (this.disableTextureBindingOptimization) {
-                if (channel !== internalTexture._designatedSlot) {
-                    this._textureCollisions.addCount(1, false);
-                }
-            }
-            else {
-                if (channel !== internalTexture._designatedSlot) {
-                    if (internalTexture._designatedSlot > -1) {
-                        return internalTexture._designatedSlot;
-                    }
-                    else {
-                        // No slot for this texture, let's pick a new one (if we find a free slot)
-                        if (this._nextFreeTextureSlots.length) {
-                            return this._nextFreeTextureSlots[0];
-                        }
-                        // We need to recycle the oldest bound texture, sorry.
-                        this._textureCollisions.addCount(1, false);
-                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                    }
-                }
-            }
-            return channel;
-        };
         Engine.prototype._bindSamplerUniformToChannel = function (sourceSlot, destination) {
             var uniform = this._boundUniforms[sourceSlot];
+            if (uniform._currentState === destination) {
+                return;
+            }
             this._gl.uniform1i(uniform, destination);
+            uniform._currentState = destination;
         };
         Engine.prototype._setTexture = function (channel, texture, isPartOfTextureArray) {
             if (isPartOfTextureArray === void 0) { isPartOfTextureArray = false; }
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
-                    this._activateTextureChannel(channel);
+                    this._activeChannel = channel;
                     this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                     this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                     if (this.webGLVersion > 1) {
@@ -12819,10 +12851,8 @@ var BABYLON;
                 return false;
             }
             // Video
-            var alreadyActivated = false;
             if (texture.video) {
-                this._activateTextureChannel(channel);
-                alreadyActivated = true;
+                this._activeChannel = channel;
                 texture.update();
             }
             else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
@@ -12852,9 +12882,7 @@ var BABYLON;
                 }
                 return false;
             }
-            if (!alreadyActivated) {
-                this._activateTextureChannel(channel);
-            }
+            this._activeChannel = channel;
             if (internalTexture && internalTexture.is3D) {
                 this._bindTextureDirectly(this._gl.TEXTURE_3D, internalTexture, isPartOfTextureArray);
                 if (internalTexture && internalTexture._cachedWrapU !== texture.wrapU) {
@@ -13132,7 +13160,7 @@ var BABYLON;
             // Remove from Instances
             var index = Engine.Instances.indexOf(this);
             if (index >= 0) {
-                Engine.Instances.splice(index, 1);
+                delete Engine.Instances[index];
             }
             this._workingCanvas = null;
             this._workingContext = null;
@@ -13527,7 +13555,7 @@ var BABYLON;
             var request = BABYLON.Tools.LoadFile(url, onSuccess, onProgress, database, useArrayBuffer, onError);
             this._activeRequests.push(request);
             request.onCompleteObservable.add(function (request) {
-                _this._activeRequests.splice(_this._activeRequests.indexOf(request), 1);
+                delete _this._activeRequests[_this._activeRequests.indexOf(request)];
             });
             return request;
         };
@@ -42677,7 +42705,7 @@ var BABYLON;
             this._targetedAnimations = new Array();
             this._animatables = new Array();
             this._from = Number.MAX_VALUE;
-            this._to = Number.MIN_VALUE;
+            this._to = -Number.MAX_VALUE;
             this._speedRatio = 1;
             this.onAnimationEndObservable = new BABYLON.Observable();
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
@@ -42716,6 +42744,16 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(AnimationGroup.prototype, "targetedAnimations", {
+            /**
+             * Gets the targeted animations for this animation group
+             */
+            get: function () {
+                return this._targetedAnimations;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
          * Add an animation (with its target) in the group
          * @param animation defines the animation we want to add
@@ -42740,11 +42778,13 @@ var BABYLON;
         /**
          * This function will normalize every animation in the group to make sure they all go from beginFrame to endFrame
          * It can add constant keys at begin or end
-         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smaller begin frame of all animations
-         * @param endFrame defines the new end frame for all animations. It can't be smaller than the larger end frame of all animations
+         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smallest begin frame of all animations
+         * @param endFrame defines the new end frame for all animations. It can't be smaller than the largest end frame of all animations
          */
         AnimationGroup.prototype.normalize = function (beginFrame, endFrame) {
-            beginFrame = Math.min(beginFrame, this._from);
+            if (beginFrame === void 0) { beginFrame = -Number.MAX_VALUE; }
+            if (endFrame === void 0) { endFrame = Number.MAX_VALUE; }
+            beginFrame = Math.max(beginFrame, this._from);
             endFrame = Math.min(endFrame, this._to);
             for (var index = 0; index < this._targetedAnimations.length; index++) {
                 var targetedAnimation = this._targetedAnimations[index];
@@ -42756,7 +42796,8 @@ var BABYLON;
                         frame: beginFrame,
                         value: startKey.value,
                         inTangent: startKey.inTangent,
-                        outTangent: startKey.outTangent
+                        outTangent: startKey.outTangent,
+                        interpolation: startKey.interpolation
                     };
                     keys.splice(0, 0, newKey);
                 }
@@ -42764,8 +42805,9 @@ var BABYLON;
                     var newKey = {
                         frame: endFrame,
                         value: endKey.value,
-                        inTangent: startKey.outTangent,
-                        outTangent: startKey.outTangent
+                        inTangent: endKey.outTangent,
+                        outTangent: endKey.outTangent,
+                        interpolation: endKey.interpolation
                     };
                     keys.push(newKey);
                 }

Файловите разлики са ограничени, защото са твърде много
+ 27 - 27
dist/preview release/babylon.worker.js


Файловите разлики са ограничени, защото са твърде много
+ 858 - 829
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Файловите разлики са ограничени, защото са твърде много
+ 29 - 29
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 121 - 83
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -7483,6 +7483,26 @@ var BABYLON;
             }
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
         };
+        /**
+         * Generates an image screenshot from the specified camera.
+         *
+         * @param engine The engine to use for rendering
+         * @param camera The camera to use for rendering
+         * @param size This parameter can be set to a single number or to an object with the
+         * following (optional) properties: precision, width, height. If a single number is passed,
+         * it will be used for both width and height. If an object is passed, the screenshot size
+         * will be derived from the parameters. The precision property is a multiplier allowing
+         * rendering at a higher or lower resolution.
+         * @param successCallback The callback receives a single parameter which contains the
+         * screenshot as a string of base64-encoded characters. This string can be assigned to the
+         * src parameter of an <img> to display it.
+         * @param mimeType The MIME type of the screenshot image (default: image/png).
+         * Check your browser for supported MIME types.
+         * @param samples Texture samples (default: 1)
+         * @param antialiasing Whether antialiasing should be turned on or not (default: false)
+         * @param fileName A name for for the downloaded file.
+         * @constructor
+         */
         Tools.CreateScreenshotUsingRenderTarget = function (engine, camera, size, successCallback, mimeType, samples, antialiasing, fileName) {
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (samples === void 0) { samples = 1; }
@@ -8885,9 +8905,10 @@ var BABYLON;
     var Engine = /** @class */ (function () {
         /**
          * @constructor
-         * @param {HTMLCanvasElement | WebGLRenderingContext} canvasOrContext - the canvas or the webgl context to be used for rendering
-         * @param {boolean} [antialias] - enable antialias
-         * @param options - further options to be sent to the getContext function
+         * @param canvasOrContext defines the canvas or WebGL context to use for rendering
+         * @param antialias defines enable antialiasing (default: false)
+         * @param options defines further options to be sent to the getContext() function
+         * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
         function Engine(canvasOrContext, antialias, options, adaptToDeviceRatio) {
             if (adaptToDeviceRatio === void 0) { adaptToDeviceRatio = false; }
@@ -8989,6 +9010,8 @@ var BABYLON;
             this._alphaMode = Engine.ALPHA_DISABLE;
             // Cache
             this._internalTexturesCache = new Array();
+            this._activeChannel = 0;
+            this._currentTextureChannel = -1;
             this._boundTexturesCache = {};
             this._boundTexturesStack = new Array();
             this._compiledEffects = {};
@@ -9904,7 +9927,7 @@ var BABYLON;
             for (var slot = 0; slot < this._maxSimultaneousTextures; slot++) {
                 this._nextFreeTextureSlots.push(slot);
             }
-            this._activeChannel = -1;
+            this._currentTextureChannel = -1;
         };
         Engine.prototype.isDeterministicLockStep = function () {
             return this._deterministicLockstep;
@@ -12687,12 +12710,6 @@ var BABYLON;
             }
             this._currentEffect = null;
         };
-        Engine.prototype._activateTextureChannel = function (channel) {
-            if (this._activeChannel !== channel && channel > -1) {
-                this._gl.activeTexture(this._gl.TEXTURE0 + channel);
-                this._activeChannel = channel;
-            }
-        };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
             var index = this._boundTexturesStack.indexOf(internalTexture);
             if (index > -1 && index !== this._boundTexturesStack.length - 1) {
@@ -12700,6 +12717,34 @@ var BABYLON;
                 this._boundTexturesStack.push(internalTexture);
             }
         };
+        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
+            if (!internalTexture) {
+                return -1;
+            }
+            internalTexture._initialSlot = channel;
+            if (this.disableTextureBindingOptimization) {
+                if (channel !== internalTexture._designatedSlot) {
+                    this._textureCollisions.addCount(1, false);
+                }
+            }
+            else {
+                if (channel !== internalTexture._designatedSlot) {
+                    if (internalTexture._designatedSlot > -1) {
+                        return internalTexture._designatedSlot;
+                    }
+                    else {
+                        // No slot for this texture, let's pick a new one (if we find a free slot)
+                        if (this._nextFreeTextureSlots.length) {
+                            return this._nextFreeTextureSlots[0];
+                        }
+                        // We need to recycle the oldest bound texture, sorry.
+                        this._textureCollisions.addCount(1, false);
+                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
+                    }
+                }
+            }
+            return channel;
+        };
         Engine.prototype._removeDesignatedSlot = function (internalTexture) {
             var currentSlot = internalTexture._designatedSlot;
             internalTexture._designatedSlot = -1;
@@ -12713,31 +12758,42 @@ var BABYLON;
             }
             return currentSlot;
         };
-        Engine.prototype._bindTextureDirectly = function (target, texture, doNotBindUniformToTextureChannel) {
-            if (doNotBindUniformToTextureChannel === void 0) { doNotBindUniformToTextureChannel = false; }
+        Engine.prototype._activateCurrentTexture = function () {
+            if (this._currentTextureChannel !== this._activeChannel) {
+                this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
+                this._currentTextureChannel = this._activeChannel;
+            }
+        };
+        Engine.prototype._bindTextureDirectly = function (target, texture, forTextureDataUpdate) {
+            if (forTextureDataUpdate === void 0) { forTextureDataUpdate = false; }
+            if (forTextureDataUpdate && texture && texture._designatedSlot > -1) {
+                this._activeChannel = texture._designatedSlot;
+            }
             var currentTextureBound = this._boundTexturesCache[this._activeChannel];
             var isTextureForRendering = texture && texture._initialSlot > -1;
             if (currentTextureBound !== texture) {
                 if (currentTextureBound && !this.disableTextureBindingOptimization) {
                     this._removeDesignatedSlot(currentTextureBound);
                 }
+                this._activateCurrentTexture();
                 this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
-                if (this._activeChannel >= 0) {
-                    this._boundTexturesCache[this._activeChannel] = texture;
-                    if (isTextureForRendering && !this.disableTextureBindingOptimization) {
+                this._boundTexturesCache[this._activeChannel] = texture;
+                if (texture) {
+                    if (!this.disableTextureBindingOptimization) {
                         var slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
                         if (slotIndex > -1) {
                             this._nextFreeTextureSlots.splice(slotIndex, 1);
                         }
                         this._boundTexturesStack.push(texture);
                     }
+                    texture._designatedSlot = this._activeChannel;
                 }
             }
-            if (isTextureForRendering && this._activeChannel > -1) {
-                texture._designatedSlot = this._activeChannel;
-                if (!doNotBindUniformToTextureChannel) {
-                    this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
-                }
+            else if (forTextureDataUpdate) {
+                this._activateCurrentTexture();
+            }
+            if (isTextureForRendering && !forTextureDataUpdate) {
+                this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
             }
         };
         Engine.prototype._bindTexture = function (channel, texture) {
@@ -12747,7 +12803,7 @@ var BABYLON;
             if (texture) {
                 channel = this._getCorrectTextureChannel(channel, texture);
             }
-            this._activateTextureChannel(channel);
+            this._activeChannel = channel;
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
         };
         Engine.prototype.setTextureFromPostProcess = function (channel, postProcess) {
@@ -12755,7 +12811,7 @@ var BABYLON;
         };
         Engine.prototype.unbindAllTextures = function () {
             for (var channel = 0; channel < this._maxSimultaneousTextures; channel++) {
-                this._activateTextureChannel(channel);
+                this._activeChannel = channel;
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                 if (this.webGLVersion > 1) {
@@ -12772,44 +12828,20 @@ var BABYLON;
             }
             this._setTexture(channel, texture);
         };
-        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
-            if (!internalTexture) {
-                return -1;
-            }
-            internalTexture._initialSlot = channel;
-            if (this.disableTextureBindingOptimization) {
-                if (channel !== internalTexture._designatedSlot) {
-                    this._textureCollisions.addCount(1, false);
-                }
-            }
-            else {
-                if (channel !== internalTexture._designatedSlot) {
-                    if (internalTexture._designatedSlot > -1) {
-                        return internalTexture._designatedSlot;
-                    }
-                    else {
-                        // No slot for this texture, let's pick a new one (if we find a free slot)
-                        if (this._nextFreeTextureSlots.length) {
-                            return this._nextFreeTextureSlots[0];
-                        }
-                        // We need to recycle the oldest bound texture, sorry.
-                        this._textureCollisions.addCount(1, false);
-                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                    }
-                }
-            }
-            return channel;
-        };
         Engine.prototype._bindSamplerUniformToChannel = function (sourceSlot, destination) {
             var uniform = this._boundUniforms[sourceSlot];
+            if (uniform._currentState === destination) {
+                return;
+            }
             this._gl.uniform1i(uniform, destination);
+            uniform._currentState = destination;
         };
         Engine.prototype._setTexture = function (channel, texture, isPartOfTextureArray) {
             if (isPartOfTextureArray === void 0) { isPartOfTextureArray = false; }
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
-                    this._activateTextureChannel(channel);
+                    this._activeChannel = channel;
                     this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                     this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                     if (this.webGLVersion > 1) {
@@ -12819,10 +12851,8 @@ var BABYLON;
                 return false;
             }
             // Video
-            var alreadyActivated = false;
             if (texture.video) {
-                this._activateTextureChannel(channel);
-                alreadyActivated = true;
+                this._activeChannel = channel;
                 texture.update();
             }
             else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
@@ -12852,9 +12882,7 @@ var BABYLON;
                 }
                 return false;
             }
-            if (!alreadyActivated) {
-                this._activateTextureChannel(channel);
-            }
+            this._activeChannel = channel;
             if (internalTexture && internalTexture.is3D) {
                 this._bindTextureDirectly(this._gl.TEXTURE_3D, internalTexture, isPartOfTextureArray);
                 if (internalTexture && internalTexture._cachedWrapU !== texture.wrapU) {
@@ -13132,7 +13160,7 @@ var BABYLON;
             // Remove from Instances
             var index = Engine.Instances.indexOf(this);
             if (index >= 0) {
-                Engine.Instances.splice(index, 1);
+                delete Engine.Instances[index];
             }
             this._workingCanvas = null;
             this._workingContext = null;
@@ -13527,7 +13555,7 @@ var BABYLON;
             var request = BABYLON.Tools.LoadFile(url, onSuccess, onProgress, database, useArrayBuffer, onError);
             this._activeRequests.push(request);
             request.onCompleteObservable.add(function (request) {
-                _this._activeRequests.splice(_this._activeRequests.indexOf(request), 1);
+                delete _this._activeRequests[_this._activeRequests.indexOf(request)];
             });
             return request;
         };
@@ -42677,7 +42705,7 @@ var BABYLON;
             this._targetedAnimations = new Array();
             this._animatables = new Array();
             this._from = Number.MAX_VALUE;
-            this._to = Number.MIN_VALUE;
+            this._to = -Number.MAX_VALUE;
             this._speedRatio = 1;
             this.onAnimationEndObservable = new BABYLON.Observable();
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
@@ -42716,6 +42744,16 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(AnimationGroup.prototype, "targetedAnimations", {
+            /**
+             * Gets the targeted animations for this animation group
+             */
+            get: function () {
+                return this._targetedAnimations;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
          * Add an animation (with its target) in the group
          * @param animation defines the animation we want to add
@@ -42740,11 +42778,13 @@ var BABYLON;
         /**
          * This function will normalize every animation in the group to make sure they all go from beginFrame to endFrame
          * It can add constant keys at begin or end
-         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smaller begin frame of all animations
-         * @param endFrame defines the new end frame for all animations. It can't be smaller than the larger end frame of all animations
+         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smallest begin frame of all animations
+         * @param endFrame defines the new end frame for all animations. It can't be smaller than the largest end frame of all animations
          */
         AnimationGroup.prototype.normalize = function (beginFrame, endFrame) {
-            beginFrame = Math.min(beginFrame, this._from);
+            if (beginFrame === void 0) { beginFrame = -Number.MAX_VALUE; }
+            if (endFrame === void 0) { endFrame = Number.MAX_VALUE; }
+            beginFrame = Math.max(beginFrame, this._from);
             endFrame = Math.min(endFrame, this._to);
             for (var index = 0; index < this._targetedAnimations.length; index++) {
                 var targetedAnimation = this._targetedAnimations[index];
@@ -42756,7 +42796,8 @@ var BABYLON;
                         frame: beginFrame,
                         value: startKey.value,
                         inTangent: startKey.inTangent,
-                        outTangent: startKey.outTangent
+                        outTangent: startKey.outTangent,
+                        interpolation: startKey.interpolation
                     };
                     keys.splice(0, 0, newKey);
                 }
@@ -42764,8 +42805,9 @@ var BABYLON;
                     var newKey = {
                         frame: endFrame,
                         value: endKey.value,
-                        inTangent: startKey.outTangent,
-                        outTangent: startKey.outTangent
+                        inTangent: endKey.outTangent,
+                        outTangent: endKey.outTangent,
+                        interpolation: endKey.interpolation
                     };
                     keys.push(newKey);
                 }
@@ -85377,6 +85419,10 @@ var BABYLON;
                 if (!animations) {
                     return;
                 }
+                for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                    var animation = animations_1[_i];
+                    animation.babylonAnimationGroup.normalize();
+                }
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
@@ -85384,19 +85430,13 @@ var BABYLON;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
                         var animation = animations[0];
-                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
-                            var target = _a[_i];
-                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                        }
+                        animation.babylonAnimationGroup.start(true);
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
-                            var animation = animations_1[_b];
-                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
-                                var target = _d[_c];
-                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                            }
+                        for (var _a = 0, animations_2 = animations; _a < animations_2.length; _a++) {
+                            var animation = animations_2[_a];
+                            animation.babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -86008,7 +86048,7 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadAnimation = function (context, animation) {
-                animation.targets = [];
+                animation.babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation.index, this._babylonScene);
                 for (var index = 0; index < animation.channels.length; index++) {
                     var channel = GLTFLoader._GetProperty(animation.channels, index);
                     if (!channel) {
@@ -86148,7 +86188,7 @@ var BABYLON;
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
                         var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
-                            var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
+                            var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
                                 frame: key.frame,
@@ -86156,22 +86196,20 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            morphTarget.animations.push(babylonAnimation);
-                            animation.targets.push(morphTarget);
+                            animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                         };
                         for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
                             _loop_7(targetIndex);
                         }
                     }
                     else {
-                        var animationName = animation.name || "anim" + animation.index;
+                        var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode.babylonAnimationTargets) {
                             for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                target.animations.push(babylonAnimation.clone());
-                                animation.targets.push(target);
+                                animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
                             }
                         }
                     }

+ 121 - 83
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js

@@ -7469,6 +7469,26 @@ var BABYLON;
             }
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
         };
+        /**
+         * Generates an image screenshot from the specified camera.
+         *
+         * @param engine The engine to use for rendering
+         * @param camera The camera to use for rendering
+         * @param size This parameter can be set to a single number or to an object with the
+         * following (optional) properties: precision, width, height. If a single number is passed,
+         * it will be used for both width and height. If an object is passed, the screenshot size
+         * will be derived from the parameters. The precision property is a multiplier allowing
+         * rendering at a higher or lower resolution.
+         * @param successCallback The callback receives a single parameter which contains the
+         * screenshot as a string of base64-encoded characters. This string can be assigned to the
+         * src parameter of an <img> to display it.
+         * @param mimeType The MIME type of the screenshot image (default: image/png).
+         * Check your browser for supported MIME types.
+         * @param samples Texture samples (default: 1)
+         * @param antialiasing Whether antialiasing should be turned on or not (default: false)
+         * @param fileName A name for for the downloaded file.
+         * @constructor
+         */
         Tools.CreateScreenshotUsingRenderTarget = function (engine, camera, size, successCallback, mimeType, samples, antialiasing, fileName) {
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (samples === void 0) { samples = 1; }
@@ -8871,9 +8891,10 @@ var BABYLON;
     var Engine = /** @class */ (function () {
         /**
          * @constructor
-         * @param {HTMLCanvasElement | WebGLRenderingContext} canvasOrContext - the canvas or the webgl context to be used for rendering
-         * @param {boolean} [antialias] - enable antialias
-         * @param options - further options to be sent to the getContext function
+         * @param canvasOrContext defines the canvas or WebGL context to use for rendering
+         * @param antialias defines enable antialiasing (default: false)
+         * @param options defines further options to be sent to the getContext() function
+         * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
         function Engine(canvasOrContext, antialias, options, adaptToDeviceRatio) {
             if (adaptToDeviceRatio === void 0) { adaptToDeviceRatio = false; }
@@ -8975,6 +8996,8 @@ var BABYLON;
             this._alphaMode = Engine.ALPHA_DISABLE;
             // Cache
             this._internalTexturesCache = new Array();
+            this._activeChannel = 0;
+            this._currentTextureChannel = -1;
             this._boundTexturesCache = {};
             this._boundTexturesStack = new Array();
             this._compiledEffects = {};
@@ -9890,7 +9913,7 @@ var BABYLON;
             for (var slot = 0; slot < this._maxSimultaneousTextures; slot++) {
                 this._nextFreeTextureSlots.push(slot);
             }
-            this._activeChannel = -1;
+            this._currentTextureChannel = -1;
         };
         Engine.prototype.isDeterministicLockStep = function () {
             return this._deterministicLockstep;
@@ -12673,12 +12696,6 @@ var BABYLON;
             }
             this._currentEffect = null;
         };
-        Engine.prototype._activateTextureChannel = function (channel) {
-            if (this._activeChannel !== channel && channel > -1) {
-                this._gl.activeTexture(this._gl.TEXTURE0 + channel);
-                this._activeChannel = channel;
-            }
-        };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
             var index = this._boundTexturesStack.indexOf(internalTexture);
             if (index > -1 && index !== this._boundTexturesStack.length - 1) {
@@ -12686,6 +12703,34 @@ var BABYLON;
                 this._boundTexturesStack.push(internalTexture);
             }
         };
+        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
+            if (!internalTexture) {
+                return -1;
+            }
+            internalTexture._initialSlot = channel;
+            if (this.disableTextureBindingOptimization) {
+                if (channel !== internalTexture._designatedSlot) {
+                    this._textureCollisions.addCount(1, false);
+                }
+            }
+            else {
+                if (channel !== internalTexture._designatedSlot) {
+                    if (internalTexture._designatedSlot > -1) {
+                        return internalTexture._designatedSlot;
+                    }
+                    else {
+                        // No slot for this texture, let's pick a new one (if we find a free slot)
+                        if (this._nextFreeTextureSlots.length) {
+                            return this._nextFreeTextureSlots[0];
+                        }
+                        // We need to recycle the oldest bound texture, sorry.
+                        this._textureCollisions.addCount(1, false);
+                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
+                    }
+                }
+            }
+            return channel;
+        };
         Engine.prototype._removeDesignatedSlot = function (internalTexture) {
             var currentSlot = internalTexture._designatedSlot;
             internalTexture._designatedSlot = -1;
@@ -12699,31 +12744,42 @@ var BABYLON;
             }
             return currentSlot;
         };
-        Engine.prototype._bindTextureDirectly = function (target, texture, doNotBindUniformToTextureChannel) {
-            if (doNotBindUniformToTextureChannel === void 0) { doNotBindUniformToTextureChannel = false; }
+        Engine.prototype._activateCurrentTexture = function () {
+            if (this._currentTextureChannel !== this._activeChannel) {
+                this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
+                this._currentTextureChannel = this._activeChannel;
+            }
+        };
+        Engine.prototype._bindTextureDirectly = function (target, texture, forTextureDataUpdate) {
+            if (forTextureDataUpdate === void 0) { forTextureDataUpdate = false; }
+            if (forTextureDataUpdate && texture && texture._designatedSlot > -1) {
+                this._activeChannel = texture._designatedSlot;
+            }
             var currentTextureBound = this._boundTexturesCache[this._activeChannel];
             var isTextureForRendering = texture && texture._initialSlot > -1;
             if (currentTextureBound !== texture) {
                 if (currentTextureBound && !this.disableTextureBindingOptimization) {
                     this._removeDesignatedSlot(currentTextureBound);
                 }
+                this._activateCurrentTexture();
                 this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
-                if (this._activeChannel >= 0) {
-                    this._boundTexturesCache[this._activeChannel] = texture;
-                    if (isTextureForRendering && !this.disableTextureBindingOptimization) {
+                this._boundTexturesCache[this._activeChannel] = texture;
+                if (texture) {
+                    if (!this.disableTextureBindingOptimization) {
                         var slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
                         if (slotIndex > -1) {
                             this._nextFreeTextureSlots.splice(slotIndex, 1);
                         }
                         this._boundTexturesStack.push(texture);
                     }
+                    texture._designatedSlot = this._activeChannel;
                 }
             }
-            if (isTextureForRendering && this._activeChannel > -1) {
-                texture._designatedSlot = this._activeChannel;
-                if (!doNotBindUniformToTextureChannel) {
-                    this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
-                }
+            else if (forTextureDataUpdate) {
+                this._activateCurrentTexture();
+            }
+            if (isTextureForRendering && !forTextureDataUpdate) {
+                this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
             }
         };
         Engine.prototype._bindTexture = function (channel, texture) {
@@ -12733,7 +12789,7 @@ var BABYLON;
             if (texture) {
                 channel = this._getCorrectTextureChannel(channel, texture);
             }
-            this._activateTextureChannel(channel);
+            this._activeChannel = channel;
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
         };
         Engine.prototype.setTextureFromPostProcess = function (channel, postProcess) {
@@ -12741,7 +12797,7 @@ var BABYLON;
         };
         Engine.prototype.unbindAllTextures = function () {
             for (var channel = 0; channel < this._maxSimultaneousTextures; channel++) {
-                this._activateTextureChannel(channel);
+                this._activeChannel = channel;
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                 if (this.webGLVersion > 1) {
@@ -12758,44 +12814,20 @@ var BABYLON;
             }
             this._setTexture(channel, texture);
         };
-        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
-            if (!internalTexture) {
-                return -1;
-            }
-            internalTexture._initialSlot = channel;
-            if (this.disableTextureBindingOptimization) {
-                if (channel !== internalTexture._designatedSlot) {
-                    this._textureCollisions.addCount(1, false);
-                }
-            }
-            else {
-                if (channel !== internalTexture._designatedSlot) {
-                    if (internalTexture._designatedSlot > -1) {
-                        return internalTexture._designatedSlot;
-                    }
-                    else {
-                        // No slot for this texture, let's pick a new one (if we find a free slot)
-                        if (this._nextFreeTextureSlots.length) {
-                            return this._nextFreeTextureSlots[0];
-                        }
-                        // We need to recycle the oldest bound texture, sorry.
-                        this._textureCollisions.addCount(1, false);
-                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                    }
-                }
-            }
-            return channel;
-        };
         Engine.prototype._bindSamplerUniformToChannel = function (sourceSlot, destination) {
             var uniform = this._boundUniforms[sourceSlot];
+            if (uniform._currentState === destination) {
+                return;
+            }
             this._gl.uniform1i(uniform, destination);
+            uniform._currentState = destination;
         };
         Engine.prototype._setTexture = function (channel, texture, isPartOfTextureArray) {
             if (isPartOfTextureArray === void 0) { isPartOfTextureArray = false; }
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
-                    this._activateTextureChannel(channel);
+                    this._activeChannel = channel;
                     this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                     this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                     if (this.webGLVersion > 1) {
@@ -12805,10 +12837,8 @@ var BABYLON;
                 return false;
             }
             // Video
-            var alreadyActivated = false;
             if (texture.video) {
-                this._activateTextureChannel(channel);
-                alreadyActivated = true;
+                this._activeChannel = channel;
                 texture.update();
             }
             else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
@@ -12838,9 +12868,7 @@ var BABYLON;
                 }
                 return false;
             }
-            if (!alreadyActivated) {
-                this._activateTextureChannel(channel);
-            }
+            this._activeChannel = channel;
             if (internalTexture && internalTexture.is3D) {
                 this._bindTextureDirectly(this._gl.TEXTURE_3D, internalTexture, isPartOfTextureArray);
                 if (internalTexture && internalTexture._cachedWrapU !== texture.wrapU) {
@@ -13118,7 +13146,7 @@ var BABYLON;
             // Remove from Instances
             var index = Engine.Instances.indexOf(this);
             if (index >= 0) {
-                Engine.Instances.splice(index, 1);
+                delete Engine.Instances[index];
             }
             this._workingCanvas = null;
             this._workingContext = null;
@@ -13513,7 +13541,7 @@ var BABYLON;
             var request = BABYLON.Tools.LoadFile(url, onSuccess, onProgress, database, useArrayBuffer, onError);
             this._activeRequests.push(request);
             request.onCompleteObservable.add(function (request) {
-                _this._activeRequests.splice(_this._activeRequests.indexOf(request), 1);
+                delete _this._activeRequests[_this._activeRequests.indexOf(request)];
             });
             return request;
         };
@@ -42663,7 +42691,7 @@ var BABYLON;
             this._targetedAnimations = new Array();
             this._animatables = new Array();
             this._from = Number.MAX_VALUE;
-            this._to = Number.MIN_VALUE;
+            this._to = -Number.MAX_VALUE;
             this._speedRatio = 1;
             this.onAnimationEndObservable = new BABYLON.Observable();
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
@@ -42702,6 +42730,16 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(AnimationGroup.prototype, "targetedAnimations", {
+            /**
+             * Gets the targeted animations for this animation group
+             */
+            get: function () {
+                return this._targetedAnimations;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
          * Add an animation (with its target) in the group
          * @param animation defines the animation we want to add
@@ -42726,11 +42764,13 @@ var BABYLON;
         /**
          * This function will normalize every animation in the group to make sure they all go from beginFrame to endFrame
          * It can add constant keys at begin or end
-         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smaller begin frame of all animations
-         * @param endFrame defines the new end frame for all animations. It can't be smaller than the larger end frame of all animations
+         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smallest begin frame of all animations
+         * @param endFrame defines the new end frame for all animations. It can't be smaller than the largest end frame of all animations
          */
         AnimationGroup.prototype.normalize = function (beginFrame, endFrame) {
-            beginFrame = Math.min(beginFrame, this._from);
+            if (beginFrame === void 0) { beginFrame = -Number.MAX_VALUE; }
+            if (endFrame === void 0) { endFrame = Number.MAX_VALUE; }
+            beginFrame = Math.max(beginFrame, this._from);
             endFrame = Math.min(endFrame, this._to);
             for (var index = 0; index < this._targetedAnimations.length; index++) {
                 var targetedAnimation = this._targetedAnimations[index];
@@ -42742,7 +42782,8 @@ var BABYLON;
                         frame: beginFrame,
                         value: startKey.value,
                         inTangent: startKey.inTangent,
-                        outTangent: startKey.outTangent
+                        outTangent: startKey.outTangent,
+                        interpolation: startKey.interpolation
                     };
                     keys.splice(0, 0, newKey);
                 }
@@ -42750,8 +42791,9 @@ var BABYLON;
                     var newKey = {
                         frame: endFrame,
                         value: endKey.value,
-                        inTangent: startKey.outTangent,
-                        outTangent: startKey.outTangent
+                        inTangent: endKey.outTangent,
+                        outTangent: endKey.outTangent,
+                        interpolation: endKey.interpolation
                     };
                     keys.push(newKey);
                 }
@@ -85363,6 +85405,10 @@ var BABYLON;
                 if (!animations) {
                     return;
                 }
+                for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                    var animation = animations_1[_i];
+                    animation.babylonAnimationGroup.normalize();
+                }
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
@@ -85370,19 +85416,13 @@ var BABYLON;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
                         var animation = animations[0];
-                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
-                            var target = _a[_i];
-                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                        }
+                        animation.babylonAnimationGroup.start(true);
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
-                            var animation = animations_1[_b];
-                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
-                                var target = _d[_c];
-                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                            }
+                        for (var _a = 0, animations_2 = animations; _a < animations_2.length; _a++) {
+                            var animation = animations_2[_a];
+                            animation.babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -85994,7 +86034,7 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadAnimation = function (context, animation) {
-                animation.targets = [];
+                animation.babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation.index, this._babylonScene);
                 for (var index = 0; index < animation.channels.length; index++) {
                     var channel = GLTFLoader._GetProperty(animation.channels, index);
                     if (!channel) {
@@ -86134,7 +86174,7 @@ var BABYLON;
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
                         var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
-                            var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
+                            var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
                                 frame: key.frame,
@@ -86142,22 +86182,20 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            morphTarget.animations.push(babylonAnimation);
-                            animation.targets.push(morphTarget);
+                            animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                         };
                         for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
                             _loop_7(targetIndex);
                         }
                     }
                     else {
-                        var animationName = animation.name || "anim" + animation.index;
+                        var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode.babylonAnimationTargets) {
                             for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                target.animations.push(babylonAnimation.clone());
-                                animation.targets.push(target);
+                                animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
                             }
                         }
                     }

+ 108 - 66
dist/preview release/es6.js

@@ -7469,6 +7469,26 @@ var BABYLON;
             }
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
         };
+        /**
+         * Generates an image screenshot from the specified camera.
+         *
+         * @param engine The engine to use for rendering
+         * @param camera The camera to use for rendering
+         * @param size This parameter can be set to a single number or to an object with the
+         * following (optional) properties: precision, width, height. If a single number is passed,
+         * it will be used for both width and height. If an object is passed, the screenshot size
+         * will be derived from the parameters. The precision property is a multiplier allowing
+         * rendering at a higher or lower resolution.
+         * @param successCallback The callback receives a single parameter which contains the
+         * screenshot as a string of base64-encoded characters. This string can be assigned to the
+         * src parameter of an <img> to display it.
+         * @param mimeType The MIME type of the screenshot image (default: image/png).
+         * Check your browser for supported MIME types.
+         * @param samples Texture samples (default: 1)
+         * @param antialiasing Whether antialiasing should be turned on or not (default: false)
+         * @param fileName A name for for the downloaded file.
+         * @constructor
+         */
         Tools.CreateScreenshotUsingRenderTarget = function (engine, camera, size, successCallback, mimeType, samples, antialiasing, fileName) {
             if (mimeType === void 0) { mimeType = "image/png"; }
             if (samples === void 0) { samples = 1; }
@@ -8871,9 +8891,10 @@ var BABYLON;
     var Engine = /** @class */ (function () {
         /**
          * @constructor
-         * @param {HTMLCanvasElement | WebGLRenderingContext} canvasOrContext - the canvas or the webgl context to be used for rendering
-         * @param {boolean} [antialias] - enable antialias
-         * @param options - further options to be sent to the getContext function
+         * @param canvasOrContext defines the canvas or WebGL context to use for rendering
+         * @param antialias defines enable antialiasing (default: false)
+         * @param options defines further options to be sent to the getContext() function
+         * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
         function Engine(canvasOrContext, antialias, options, adaptToDeviceRatio) {
             if (adaptToDeviceRatio === void 0) { adaptToDeviceRatio = false; }
@@ -8975,6 +8996,8 @@ var BABYLON;
             this._alphaMode = Engine.ALPHA_DISABLE;
             // Cache
             this._internalTexturesCache = new Array();
+            this._activeChannel = 0;
+            this._currentTextureChannel = -1;
             this._boundTexturesCache = {};
             this._boundTexturesStack = new Array();
             this._compiledEffects = {};
@@ -9890,7 +9913,7 @@ var BABYLON;
             for (var slot = 0; slot < this._maxSimultaneousTextures; slot++) {
                 this._nextFreeTextureSlots.push(slot);
             }
-            this._activeChannel = -1;
+            this._currentTextureChannel = -1;
         };
         Engine.prototype.isDeterministicLockStep = function () {
             return this._deterministicLockstep;
@@ -12673,12 +12696,6 @@ var BABYLON;
             }
             this._currentEffect = null;
         };
-        Engine.prototype._activateTextureChannel = function (channel) {
-            if (this._activeChannel !== channel && channel > -1) {
-                this._gl.activeTexture(this._gl.TEXTURE0 + channel);
-                this._activeChannel = channel;
-            }
-        };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
             var index = this._boundTexturesStack.indexOf(internalTexture);
             if (index > -1 && index !== this._boundTexturesStack.length - 1) {
@@ -12686,6 +12703,34 @@ var BABYLON;
                 this._boundTexturesStack.push(internalTexture);
             }
         };
+        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
+            if (!internalTexture) {
+                return -1;
+            }
+            internalTexture._initialSlot = channel;
+            if (this.disableTextureBindingOptimization) {
+                if (channel !== internalTexture._designatedSlot) {
+                    this._textureCollisions.addCount(1, false);
+                }
+            }
+            else {
+                if (channel !== internalTexture._designatedSlot) {
+                    if (internalTexture._designatedSlot > -1) {
+                        return internalTexture._designatedSlot;
+                    }
+                    else {
+                        // No slot for this texture, let's pick a new one (if we find a free slot)
+                        if (this._nextFreeTextureSlots.length) {
+                            return this._nextFreeTextureSlots[0];
+                        }
+                        // We need to recycle the oldest bound texture, sorry.
+                        this._textureCollisions.addCount(1, false);
+                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
+                    }
+                }
+            }
+            return channel;
+        };
         Engine.prototype._removeDesignatedSlot = function (internalTexture) {
             var currentSlot = internalTexture._designatedSlot;
             internalTexture._designatedSlot = -1;
@@ -12699,31 +12744,42 @@ var BABYLON;
             }
             return currentSlot;
         };
-        Engine.prototype._bindTextureDirectly = function (target, texture, doNotBindUniformToTextureChannel) {
-            if (doNotBindUniformToTextureChannel === void 0) { doNotBindUniformToTextureChannel = false; }
+        Engine.prototype._activateCurrentTexture = function () {
+            if (this._currentTextureChannel !== this._activeChannel) {
+                this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
+                this._currentTextureChannel = this._activeChannel;
+            }
+        };
+        Engine.prototype._bindTextureDirectly = function (target, texture, forTextureDataUpdate) {
+            if (forTextureDataUpdate === void 0) { forTextureDataUpdate = false; }
+            if (forTextureDataUpdate && texture && texture._designatedSlot > -1) {
+                this._activeChannel = texture._designatedSlot;
+            }
             var currentTextureBound = this._boundTexturesCache[this._activeChannel];
             var isTextureForRendering = texture && texture._initialSlot > -1;
             if (currentTextureBound !== texture) {
                 if (currentTextureBound && !this.disableTextureBindingOptimization) {
                     this._removeDesignatedSlot(currentTextureBound);
                 }
+                this._activateCurrentTexture();
                 this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
-                if (this._activeChannel >= 0) {
-                    this._boundTexturesCache[this._activeChannel] = texture;
-                    if (isTextureForRendering && !this.disableTextureBindingOptimization) {
+                this._boundTexturesCache[this._activeChannel] = texture;
+                if (texture) {
+                    if (!this.disableTextureBindingOptimization) {
                         var slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
                         if (slotIndex > -1) {
                             this._nextFreeTextureSlots.splice(slotIndex, 1);
                         }
                         this._boundTexturesStack.push(texture);
                     }
+                    texture._designatedSlot = this._activeChannel;
                 }
             }
-            if (isTextureForRendering && this._activeChannel > -1) {
-                texture._designatedSlot = this._activeChannel;
-                if (!doNotBindUniformToTextureChannel) {
-                    this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
-                }
+            else if (forTextureDataUpdate) {
+                this._activateCurrentTexture();
+            }
+            if (isTextureForRendering && !forTextureDataUpdate) {
+                this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
             }
         };
         Engine.prototype._bindTexture = function (channel, texture) {
@@ -12733,7 +12789,7 @@ var BABYLON;
             if (texture) {
                 channel = this._getCorrectTextureChannel(channel, texture);
             }
-            this._activateTextureChannel(channel);
+            this._activeChannel = channel;
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
         };
         Engine.prototype.setTextureFromPostProcess = function (channel, postProcess) {
@@ -12741,7 +12797,7 @@ var BABYLON;
         };
         Engine.prototype.unbindAllTextures = function () {
             for (var channel = 0; channel < this._maxSimultaneousTextures; channel++) {
-                this._activateTextureChannel(channel);
+                this._activeChannel = channel;
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                 if (this.webGLVersion > 1) {
@@ -12758,44 +12814,20 @@ var BABYLON;
             }
             this._setTexture(channel, texture);
         };
-        Engine.prototype._getCorrectTextureChannel = function (channel, internalTexture) {
-            if (!internalTexture) {
-                return -1;
-            }
-            internalTexture._initialSlot = channel;
-            if (this.disableTextureBindingOptimization) {
-                if (channel !== internalTexture._designatedSlot) {
-                    this._textureCollisions.addCount(1, false);
-                }
-            }
-            else {
-                if (channel !== internalTexture._designatedSlot) {
-                    if (internalTexture._designatedSlot > -1) {
-                        return internalTexture._designatedSlot;
-                    }
-                    else {
-                        // No slot for this texture, let's pick a new one (if we find a free slot)
-                        if (this._nextFreeTextureSlots.length) {
-                            return this._nextFreeTextureSlots[0];
-                        }
-                        // We need to recycle the oldest bound texture, sorry.
-                        this._textureCollisions.addCount(1, false);
-                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                    }
-                }
-            }
-            return channel;
-        };
         Engine.prototype._bindSamplerUniformToChannel = function (sourceSlot, destination) {
             var uniform = this._boundUniforms[sourceSlot];
+            if (uniform._currentState === destination) {
+                return;
+            }
             this._gl.uniform1i(uniform, destination);
+            uniform._currentState = destination;
         };
         Engine.prototype._setTexture = function (channel, texture, isPartOfTextureArray) {
             if (isPartOfTextureArray === void 0) { isPartOfTextureArray = false; }
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
-                    this._activateTextureChannel(channel);
+                    this._activeChannel = channel;
                     this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                     this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                     if (this.webGLVersion > 1) {
@@ -12805,10 +12837,8 @@ var BABYLON;
                 return false;
             }
             // Video
-            var alreadyActivated = false;
             if (texture.video) {
-                this._activateTextureChannel(channel);
-                alreadyActivated = true;
+                this._activeChannel = channel;
                 texture.update();
             }
             else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
@@ -12838,9 +12868,7 @@ var BABYLON;
                 }
                 return false;
             }
-            if (!alreadyActivated) {
-                this._activateTextureChannel(channel);
-            }
+            this._activeChannel = channel;
             if (internalTexture && internalTexture.is3D) {
                 this._bindTextureDirectly(this._gl.TEXTURE_3D, internalTexture, isPartOfTextureArray);
                 if (internalTexture && internalTexture._cachedWrapU !== texture.wrapU) {
@@ -13118,7 +13146,7 @@ var BABYLON;
             // Remove from Instances
             var index = Engine.Instances.indexOf(this);
             if (index >= 0) {
-                Engine.Instances.splice(index, 1);
+                delete Engine.Instances[index];
             }
             this._workingCanvas = null;
             this._workingContext = null;
@@ -13513,7 +13541,7 @@ var BABYLON;
             var request = BABYLON.Tools.LoadFile(url, onSuccess, onProgress, database, useArrayBuffer, onError);
             this._activeRequests.push(request);
             request.onCompleteObservable.add(function (request) {
-                _this._activeRequests.splice(_this._activeRequests.indexOf(request), 1);
+                delete _this._activeRequests[_this._activeRequests.indexOf(request)];
             });
             return request;
         };
@@ -42663,7 +42691,7 @@ var BABYLON;
             this._targetedAnimations = new Array();
             this._animatables = new Array();
             this._from = Number.MAX_VALUE;
-            this._to = Number.MIN_VALUE;
+            this._to = -Number.MAX_VALUE;
             this._speedRatio = 1;
             this.onAnimationEndObservable = new BABYLON.Observable();
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
@@ -42702,6 +42730,16 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(AnimationGroup.prototype, "targetedAnimations", {
+            /**
+             * Gets the targeted animations for this animation group
+             */
+            get: function () {
+                return this._targetedAnimations;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
          * Add an animation (with its target) in the group
          * @param animation defines the animation we want to add
@@ -42726,11 +42764,13 @@ var BABYLON;
         /**
          * This function will normalize every animation in the group to make sure they all go from beginFrame to endFrame
          * It can add constant keys at begin or end
-         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smaller begin frame of all animations
-         * @param endFrame defines the new end frame for all animations. It can't be smaller than the larger end frame of all animations
+         * @param beginFrame defines the new begin frame for all animations. It can't be bigger than the smallest begin frame of all animations
+         * @param endFrame defines the new end frame for all animations. It can't be smaller than the largest end frame of all animations
          */
         AnimationGroup.prototype.normalize = function (beginFrame, endFrame) {
-            beginFrame = Math.min(beginFrame, this._from);
+            if (beginFrame === void 0) { beginFrame = -Number.MAX_VALUE; }
+            if (endFrame === void 0) { endFrame = Number.MAX_VALUE; }
+            beginFrame = Math.max(beginFrame, this._from);
             endFrame = Math.min(endFrame, this._to);
             for (var index = 0; index < this._targetedAnimations.length; index++) {
                 var targetedAnimation = this._targetedAnimations[index];
@@ -42742,7 +42782,8 @@ var BABYLON;
                         frame: beginFrame,
                         value: startKey.value,
                         inTangent: startKey.inTangent,
-                        outTangent: startKey.outTangent
+                        outTangent: startKey.outTangent,
+                        interpolation: startKey.interpolation
                     };
                     keys.splice(0, 0, newKey);
                 }
@@ -42750,8 +42791,9 @@ var BABYLON;
                     var newKey = {
                         frame: endFrame,
                         value: endKey.value,
-                        inTangent: startKey.outTangent,
-                        outTangent: startKey.outTangent
+                        inTangent: endKey.outTangent,
+                        outTangent: endKey.outTangent,
+                        interpolation: endKey.interpolation
                     };
                     keys.push(newKey);
                 }

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

@@ -225,7 +225,7 @@ declare module BABYLON.GLTF2 {
         channels: IGLTFAnimationChannel[];
         samplers: IGLTFAnimationSampler[];
         index: number;
-        targets: any[];
+        babylonAnimationGroup: AnimationGroup;
     }
     interface IGLTFAsset extends IGLTFChildRootProperty {
         copyright?: string;

+ 13 - 17
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -673,6 +673,10 @@ var BABYLON;
                 if (!animations) {
                     return;
                 }
+                for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                    var animation = animations_1[_i];
+                    animation.babylonAnimationGroup.normalize();
+                }
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
@@ -680,19 +684,13 @@ var BABYLON;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
                         var animation = animations[0];
-                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
-                            var target = _a[_i];
-                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                        }
+                        animation.babylonAnimationGroup.start(true);
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
-                            var animation = animations_1[_b];
-                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
-                                var target = _d[_c];
-                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                            }
+                        for (var _a = 0, animations_2 = animations; _a < animations_2.length; _a++) {
+                            var animation = animations_2[_a];
+                            animation.babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -1304,7 +1302,7 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadAnimation = function (context, animation) {
-                animation.targets = [];
+                animation.babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation.index, this._babylonScene);
                 for (var index = 0; index < animation.channels.length; index++) {
                     var channel = GLTFLoader._GetProperty(animation.channels, index);
                     if (!channel) {
@@ -1444,7 +1442,7 @@ var BABYLON;
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
                         var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
-                            var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
+                            var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
                                 frame: key.frame,
@@ -1452,22 +1450,20 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            morphTarget.animations.push(babylonAnimation);
-                            animation.targets.push(morphTarget);
+                            animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                         };
                         for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
                             _loop_7(targetIndex);
                         }
                     }
                     else {
-                        var animationName = animation.name || "anim" + animation.index;
+                        var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode.babylonAnimationTargets) {
                             for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                target.animations.push(babylonAnimation.clone());
-                                animation.targets.push(target);
+                                animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
                             }
                         }
                     }

Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -782,7 +782,7 @@ declare module BABYLON.GLTF2 {
         channels: IGLTFAnimationChannel[];
         samplers: IGLTFAnimationSampler[];
         index: number;
-        targets: any[];
+        babylonAnimationGroup: AnimationGroup;
     }
     interface IGLTFAsset extends IGLTFChildRootProperty {
         copyright?: string;

+ 13 - 17
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2839,6 +2839,10 @@ var BABYLON;
                 if (!animations) {
                     return;
                 }
+                for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                    var animation = animations_1[_i];
+                    animation.babylonAnimationGroup.normalize();
+                }
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
@@ -2846,19 +2850,13 @@ var BABYLON;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
                         var animation = animations[0];
-                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
-                            var target = _a[_i];
-                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                        }
+                        animation.babylonAnimationGroup.start(true);
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
-                            var animation = animations_1[_b];
-                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
-                                var target = _d[_c];
-                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                            }
+                        for (var _a = 0, animations_2 = animations; _a < animations_2.length; _a++) {
+                            var animation = animations_2[_a];
+                            animation.babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -3470,7 +3468,7 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadAnimation = function (context, animation) {
-                animation.targets = [];
+                animation.babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation.index, this._babylonScene);
                 for (var index = 0; index < animation.channels.length; index++) {
                     var channel = GLTFLoader._GetProperty(animation.channels, index);
                     if (!channel) {
@@ -3610,7 +3608,7 @@ var BABYLON;
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
                         var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
-                            var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
+                            var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
                                 frame: key.frame,
@@ -3618,22 +3616,20 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            morphTarget.animations.push(babylonAnimation);
-                            animation.targets.push(morphTarget);
+                            animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                         };
                         for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
                             _loop_7(targetIndex);
                         }
                     }
                     else {
-                        var animationName = animation.name || "anim" + animation.index;
+                        var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode.babylonAnimationTargets) {
                             for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                target.animations.push(babylonAnimation.clone());
-                                animation.targets.push(target);
+                                animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
                             }
                         }
                     }

Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 13 - 17
dist/preview release/loaders/babylonjs.loaders.js

@@ -3813,6 +3813,10 @@ var BABYLON;
                 if (!animations) {
                     return;
                 }
+                for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                    var animation = animations_1[_i];
+                    animation.babylonAnimationGroup.normalize();
+                }
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
@@ -3820,19 +3824,13 @@ var BABYLON;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
                         var animation = animations[0];
-                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
-                            var target = _a[_i];
-                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                        }
+                        animation.babylonAnimationGroup.start(true);
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
-                            var animation = animations_1[_b];
-                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
-                                var target = _d[_c];
-                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
-                            }
+                        for (var _a = 0, animations_2 = animations; _a < animations_2.length; _a++) {
+                            var animation = animations_2[_a];
+                            animation.babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -4444,7 +4442,7 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadAnimation = function (context, animation) {
-                animation.targets = [];
+                animation.babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation.index, this._babylonScene);
                 for (var index = 0; index < animation.channels.length; index++) {
                     var channel = GLTFLoader._GetProperty(animation.channels, index);
                     if (!channel) {
@@ -4584,7 +4582,7 @@ var BABYLON;
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
                         var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
-                            var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
+                            var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
                                 frame: key.frame,
@@ -4592,22 +4590,20 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            morphTarget.animations.push(babylonAnimation);
-                            animation.targets.push(morphTarget);
+                            animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                         };
                         for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
                             _loop_7(targetIndex);
                         }
                     }
                     else {
-                        var animationName = animation.name || "anim" + animation.index;
+                        var animationName = animation.babylonAnimationGroup.name + "_channel" + animation.babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode.babylonAnimationTargets) {
                             for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                target.animations.push(babylonAnimation.clone());
-                                animation.targets.push(target);
+                                animation.babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
                             }
                         }
                     }

Файловите разлики са ограничени, защото са твърде много
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -883,7 +883,7 @@ declare module BABYLON.GLTF2 {
         channels: IGLTFAnimationChannel[];
         samplers: IGLTFAnimationSampler[];
         index: number;
-        targets: any[];
+        babylonAnimationGroup: AnimationGroup;
     }
     interface IGLTFAsset extends IGLTFChildRootProperty {
         copyright?: string;

+ 2 - 100
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 10973,
+  "errors": 10955,
   "babylon.typedoc.json": {
-    "errors": 10973,
+    "errors": 10955,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -13792,18 +13792,6 @@
           "Comments": {
             "MissingText": true,
             "MissingReturn": true
-          },
-          "Parameter": {
-            "antialias": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "adaptToDeviceRatio": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
           }
         }
       },
@@ -14250,28 +14238,6 @@
             }
           }
         },
-        "_bindTextureDirectly": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "target": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "texture": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "doNotBindUniformToTextureChannel": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "_createTexture": {
           "Comments": {
             "MissingText": true
@@ -29864,23 +29830,6 @@
             }
           }
         },
-        "_bindTextureDirectly": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "target": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "texture": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "_createTexture": {
           "Comments": {
             "MissingText": true
@@ -50555,53 +50504,6 @@
             }
           }
         },
-        "CreateScreenshotUsingRenderTarget": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "engine": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "camera": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "size": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "successCallback": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "mimeType": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "samples": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "antialiasing": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "fileName": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "DeepCopy": {
           "Comments": {
             "MissingText": true

Файловите разлики са ограничени, защото са твърде много
+ 19 - 19
dist/preview release/viewer/babylon.viewer.js


+ 2 - 2
dist/preview release/what's new.md

@@ -6,6 +6,7 @@
 
 ## Updates
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adapatability ([deltakosh](https://github.com/deltakosh))
+- Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
 - New watcher configuration for VSCode. Now the task only compiles changed files ([sebavan](https://github.com/sebavan))
 - Added new draw modes to engine (points, lines, linesloop, linestrip, trianglestrip, trianglefan) ([benaadams](https://github.com/benaadams))
 - Added GUI Textblock.lineSpacing setter and getter to configure vertical space between lines in pixels or percentage values when working with text wrapping ([carloslanderas](https://github.com/carloslanderas))
@@ -17,8 +18,7 @@
    ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
    ([carloslanderas](https://github.com/carloslanderas))
-  
-  
+- `AssetsManager` will now clear its `tasks` lsit from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))
 
 ## Bug fixes
 

+ 23 - 23
src/Debug/babylon.rayHelper.ts

@@ -1,19 +1,19 @@
 module BABYLON {
     export class RayHelper {
-        
+
         public ray: Nullable<Ray>;
 
         private _renderPoints: Vector3[];
         private _renderLine: Nullable<LinesMesh>;
         private _renderFunction: Nullable<() => void>;
         private _scene: Nullable<Scene>;
-        
+
         private _updateToMeshFunction: Nullable<() => void>;
         private _attachedToMesh: Nullable<AbstractMesh>;
         private _meshSpaceDirection: Vector3;
         private _meshSpaceOrigin: Vector3;
 
-        public static CreateAndShow(ray: Ray, scene: Scene, color:Color3): RayHelper {
+        public static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper {
             var helper = new RayHelper(ray);
 
             helper.show(scene, color);
@@ -21,13 +21,13 @@ module BABYLON {
             return helper;
         }
 
-        constructor(ray:Ray) {
+        constructor(ray: Ray) {
             this.ray = ray;
         }
 
-        public show(scene:Scene, color:Color3): void{
+        public show(scene: Scene, color: Color3): void {
 
-            if(!this._renderFunction && this.ray){
+            if (!this._renderFunction && this.ray) {
 
                 var ray = this.ray;
 
@@ -47,9 +47,9 @@ module BABYLON {
 
         }
 
-        public hide(): void{
+        public hide(): void {
 
-            if(this._renderFunction && this._scene){
+            if (this._renderFunction && this._scene) {
                 this._scene.unregisterBeforeRender(this._renderFunction);
                 this._scene = null;
                 this._renderFunction = null;
@@ -73,7 +73,7 @@ module BABYLON {
 
             var point = this._renderPoints[1];
             var len = Math.min(ray.length, 1000000);
-            
+
             point.copyFrom(ray.direction);
             point.scaleInPlace(len);
             point.addInPlace(ray.origin);
@@ -82,7 +82,7 @@ module BABYLON {
 
         }
 
-        public attachToMesh(mesh:AbstractMesh, meshSpaceDirection?:Vector3, meshSpaceOrigin?:Vector3, length?:number): void{
+        public attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void {
 
             this._attachedToMesh = mesh;
 
@@ -92,36 +92,36 @@ module BABYLON {
                 return;
             }
 
-            if(!ray.direction){
+            if (!ray.direction) {
                 ray.direction = Vector3.Zero();
             }
 
-            if(!ray.origin){
+            if (!ray.origin) {
                 ray.origin = Vector3.Zero();
             }
 
-            if(length){
+            if (length) {
                 ray.length = length;
             }
 
-            if(!meshSpaceOrigin){
+            if (!meshSpaceOrigin) {
                 meshSpaceOrigin = Vector3.Zero();
             }
 
-            if(!meshSpaceDirection){
+            if (!meshSpaceDirection) {
                 // -1 so that this will work with Mesh.lookAt
                 meshSpaceDirection = new Vector3(0, 0, -1);
             }
 
-            if(!this._meshSpaceDirection){
+            if (!this._meshSpaceDirection) {
                 this._meshSpaceDirection = meshSpaceDirection.clone();
                 this._meshSpaceOrigin = meshSpaceOrigin.clone();
-            }else{
+            } else {
                 this._meshSpaceDirection.copyFrom(meshSpaceDirection);
                 this._meshSpaceOrigin.copyFrom(meshSpaceOrigin);
             }
 
-            if(!this._updateToMeshFunction){
+            if (!this._updateToMeshFunction) {
                 this._updateToMeshFunction = (<() => void>this._updateToMesh.bind(this));
                 this._attachedToMesh.getScene().registerBeforeRender(this._updateToMeshFunction);
             }
@@ -130,9 +130,9 @@ module BABYLON {
 
         }
 
-        public detachFromMesh(): void{
+        public detachFromMesh(): void {
 
-            if(this._attachedToMesh){
+            if (this._attachedToMesh) {
                 if (this._updateToMeshFunction) {
                     this._attachedToMesh.getScene().unregisterBeforeRender(this._updateToMeshFunction);
                 }
@@ -142,7 +142,7 @@ module BABYLON {
 
         }
 
-        private _updateToMesh(): void{
+        private _updateToMesh(): void {
 
             var ray = this.ray;
 
@@ -150,7 +150,7 @@ module BABYLON {
                 return;
             }
 
-            if(this._attachedToMesh._isDisposed){
+            if (this._attachedToMesh._isDisposed) {
                 this.detachFromMesh();
                 return;
             }
@@ -160,7 +160,7 @@ module BABYLON {
 
         }
 
-        public dispose(): void{
+        public dispose(): void {
 
             this.hide();
             this.detachFromMesh();

+ 80 - 70
src/Engine/babylon.engine.ts

@@ -654,7 +654,7 @@
          */
         public disableTextureBindingOptimization = false;
 
-        public static audioEngine: AudioEngine;       
+        public static audioEngine: AudioEngine;
 
         // Focus
         private _onFocus: () => void;
@@ -731,7 +731,8 @@
 
         // Cache
         private _internalTexturesCache = new Array<InternalTexture>();
-        protected _activeChannel: number;
+        protected _activeChannel = 0;
+        private _currentTextureChannel = -1;
         protected _boundTexturesCache: { [key: string]: Nullable<InternalTexture> } = {};
         protected _boundTexturesStack = new Array<InternalTexture>();
         protected _currentEffect: Nullable<Effect>;
@@ -818,12 +819,12 @@
 
         /**
          * @constructor
-         * @param {HTMLCanvasElement | WebGLRenderingContext} canvasOrContext - the canvas or WebGL context to use for rendering
-         * @param {boolean} [antialias] - enable antialiasing (default: false)
-         * @param {EngineOptions} [options] - further options to be sent to the getContext() function
-         * @param {boolean} [adaptToDeviceRatio] - whether to adapt to the device's viewport characteristics (default: false)
+         * @param canvasOrContext defines the canvas or WebGL context to use for rendering
+         * @param antialias defines enable antialiasing (default: false)
+         * @param options defines further options to be sent to the getContext() function
+         * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
-        constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio:boolean = false) {
+        constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio: boolean = false) {
             let canvas: Nullable<HTMLCanvasElement> = null;
             Engine.Instances.push(this);
 
@@ -895,8 +896,8 @@
                                         this.disableUniformBuffers = true;
                                         break;
                                     case "textureBindingOptimization":
-                                        this.disableTextureBindingOptimization = true;    
-                                        break;    
+                                        this.disableTextureBindingOptimization = true;
+                                        break;
                                 }
                             }
                             break;
@@ -1349,7 +1350,7 @@
             for (let slot = 0; slot < this._maxSimultaneousTextures; slot++) {
                 this._nextFreeTextureSlots.push(slot);
             }
-            this._activeChannel = -1;
+            this._currentTextureChannel = -1;
         }
 
         public isDeterministicLockStep(): boolean {
@@ -4747,13 +4748,6 @@
             this._currentEffect = null;
         }
 
-        private _activateTextureChannel(channel: number): void {
-            if (this._activeChannel !== channel && channel > -1) {
-                this._gl.activeTexture(this._gl.TEXTURE0 + channel);
-                this._activeChannel = channel;
-            }
-        }
-
         private _moveBoundTextureOnTop(internalTexture: InternalTexture): void {
             let index = this._boundTexturesStack.indexOf(internalTexture);
 
@@ -4763,8 +4757,42 @@
             }
         }
 
+
+        private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>): number {
+            if (!internalTexture) {
+                return -1;
+            }
+
+            internalTexture._initialSlot = channel;
+
+            if (this.disableTextureBindingOptimization) { // We want texture sampler ID === texture channel
+                if (channel !== internalTexture._designatedSlot) {
+                    this._textureCollisions.addCount(1, false);
+                }
+            } else {
+                if (channel !== internalTexture._designatedSlot) {
+                    if (internalTexture._designatedSlot > -1) { // Texture is already assigned to a slot
+                        return internalTexture._designatedSlot;
+                    } else {
+                        // No slot for this texture, let's pick a new one (if we find a free slot)
+                        if (this._nextFreeTextureSlots.length) {
+                            return this._nextFreeTextureSlots[0];
+                        }
+
+                        // We need to recycle the oldest bound texture, sorry.
+                        this._textureCollisions.addCount(1, false);
+                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
+                    }
+                }
+            }
+
+            return channel;
+        }
+
+
         private _removeDesignatedSlot(internalTexture: InternalTexture): number {
             let currentSlot = internalTexture._designatedSlot;
+
             internalTexture._designatedSlot = -1;
             let index = this._boundTexturesStack.indexOf(internalTexture);
 
@@ -4779,7 +4807,18 @@
             return currentSlot;
         }
 
-        public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, doNotBindUniformToTextureChannel = false): void {
+        private _activateCurrentTexture() {
+            if (this._currentTextureChannel !== this._activeChannel) {
+                this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
+                this._currentTextureChannel = this._activeChannel;
+            }
+        }
+
+        protected _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate = false): void {
+            if (forTextureDataUpdate && texture && texture._designatedSlot > -1) {
+                this._activeChannel = texture._designatedSlot;
+            }
+
             let currentTextureBound = this._boundTexturesCache[this._activeChannel];
             let isTextureForRendering = texture && texture._initialSlot > -1;
 
@@ -4788,26 +4827,28 @@
                     this._removeDesignatedSlot(currentTextureBound);
                 }
 
-                this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
+                this._activateCurrentTexture();
 
-                if (this._activeChannel >= 0) {
-                    this._boundTexturesCache[this._activeChannel] = texture;
+                this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
+                this._boundTexturesCache[this._activeChannel] = texture;
 
-                    if (isTextureForRendering && !this.disableTextureBindingOptimization) {
+                if (texture) {
+                    if (!this.disableTextureBindingOptimization) {
                         let slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
                         if (slotIndex > -1) {
                             this._nextFreeTextureSlots.splice(slotIndex, 1);
                         }
-                        this._boundTexturesStack.push(texture!);
+                        this._boundTexturesStack.push(texture);
                     }
+
+                    texture._designatedSlot = this._activeChannel;
                 }
+            } else if (forTextureDataUpdate) {
+                this._activateCurrentTexture();
             }
 
-            if (isTextureForRendering && this._activeChannel > -1) {
-                texture!._designatedSlot = this._activeChannel;
-                if (!doNotBindUniformToTextureChannel) {
-                    this._bindSamplerUniformToChannel(texture!._initialSlot, this._activeChannel);
-                }
+            if (isTextureForRendering && !forTextureDataUpdate) {
+                this._bindSamplerUniformToChannel(texture!._initialSlot, this._activeChannel);
             }
         }
 
@@ -4820,7 +4861,7 @@
                 channel = this._getCorrectTextureChannel(channel, texture);
             }
 
-            this._activateTextureChannel(channel);
+            this._activeChannel = channel;
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
         }
 
@@ -4830,7 +4871,7 @@
 
         public unbindAllTextures(): void {
             for (var channel = 0; channel < this._maxSimultaneousTextures; channel++) {
-                this._activateTextureChannel(channel);
+                this._activeChannel = channel;
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                 if (this.webGLVersion > 1) {
@@ -4851,47 +4892,20 @@
             this._setTexture(channel, texture);
         }
 
-        private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>): number {
-            if (!internalTexture) {
-                return -1;
-            }
-
-            internalTexture._initialSlot = channel;
-
-            if (this.disableTextureBindingOptimization) { // We want texture sampler ID == texture channel
-                if (channel !== internalTexture._designatedSlot) {              
-                    this._textureCollisions.addCount(1, false);
-                }
-            } else {          
-                if (channel !== internalTexture._designatedSlot) {
-                    if (internalTexture._designatedSlot > -1) { // Texture is already assigned to a slot
-                        return internalTexture._designatedSlot;
-                    } else {
-                        // No slot for this texture, let's pick a new one (if we find a free slot)
-                        if (this._nextFreeTextureSlots.length) {
-                            return this._nextFreeTextureSlots[0];
-                        }
-
-                        // We need to recycle the oldest bound texture, sorry.
-                        this._textureCollisions.addCount(1, false);
-                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                    }
-                }
-            }    
-
-            return channel;
-        }
-
         private _bindSamplerUniformToChannel(sourceSlot: number, destination: number) {
             let uniform = this._boundUniforms[sourceSlot];
+            if (uniform._currentState === destination) {
+                return;
+            }
             this._gl.uniform1i(uniform, destination);
+            uniform._currentState = destination;
         }
 
         private _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false): boolean {
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
-                    this._activateTextureChannel(channel);
+                    this._activeChannel = channel;
                     this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                     this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                     if (this.webGLVersion > 1) {
@@ -4902,10 +4916,8 @@
             }
 
             // Video
-            var alreadyActivated = false;
             if ((<VideoTexture>texture).video) {
-                this._activateTextureChannel(channel);
-                alreadyActivated = true;
+                this._activeChannel = channel;
                 (<VideoTexture>texture).update();
             } else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) { // Delay loading
                 texture.delayLoad();
@@ -4938,9 +4950,7 @@
                 return false;
             }
 
-            if (!alreadyActivated) {
-                this._activateTextureChannel(channel);
-            }
+            this._activeChannel = channel;
 
             if (internalTexture && internalTexture.is3D) {
                 this._bindTextureDirectly(this._gl.TEXTURE_3D, internalTexture, isPartOfTextureArray);
@@ -5268,7 +5278,7 @@
             var index = Engine.Instances.indexOf(this);
 
             if (index >= 0) {
-                Engine.Instances.splice(index, 1);
+                delete Engine.Instances[index];
             }
 
             this._workingCanvas = null;
@@ -5729,7 +5739,7 @@
             let request = Tools.LoadFile(url, onSuccess, onProgress, database, useArrayBuffer, onError);
             this._activeRequests.push(request);
             request.onCompleteObservable.add(request => {
-                this._activeRequests.splice(this._activeRequests.indexOf(request), 1);
+                delete this._activeRequests[this._activeRequests.indexOf(request)];
             });
             return request;
         }

+ 1 - 1
src/Engine/babylon.nullEngine.ts

@@ -392,7 +392,7 @@
         public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: FloatArray, offset?: number, count?: number): void {
         }
 
-        public _bindTextureDirectly(target: number, texture: InternalTexture): void {
+        protected _bindTextureDirectly(target: number, texture: InternalTexture): void {
             if (this._boundTexturesCache[this._activeChannel] !== texture) {
                 this._boundTexturesCache[this._activeChannel] = texture;
             }

+ 5 - 1
src/babylon.mixins.ts

@@ -164,4 +164,8 @@ interface EXT_disjoint_timer_query {
     endQueryEXT(target: number): void;
     getQueryObjectEXT(query: WebGLQuery, target: number): any;
     deleteQueryEXT(query: WebGLQuery): void;
-}
+}
+
+interface WebGLUniformLocation {
+    _currentState: any;
+}

+ 8 - 8
tests/validation/validation.js

@@ -210,11 +210,11 @@ function runTest(index, done) {
             currentScene = newScene;
             processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
         },
-        null,
-        function (loadedScene, msg) {
-            console.error(msg);
-            done(false);
-        });
+            null,
+            function (loadedScene, msg) {
+                console.error(msg);
+                done(false);
+            });
     }
     else if (test.playgroundId) {
         var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
@@ -223,7 +223,7 @@ function runTest(index, done) {
         xmlHttp.onreadystatechange = function () {
             if (xmlHttp.readyState === 4) {
                 try {
-                    request.onreadystatechange = null;
+                    xmlHttp.onreadystatechange = null;
                     var snippet = JSON.parse(xmlHttp.responseText)[0];
                     var code = JSON.parse(snippet.jsonPayload).code.toString();
                     code = code.replace(/\/textures\//g, pgRoot + "/textures/");
@@ -239,7 +239,7 @@ function runTest(index, done) {
                 }
             }
         }
-        xmlHttp.onerror = function() {
+        xmlHttp.onerror = function () {
             console.error("Network error during test load.");
             done(false);
         }
@@ -292,7 +292,7 @@ function runTest(index, done) {
                 }
             }
         };
-        request.onerror = function() {
+        request.onerror = function () {
             console.error("Network error during test load.");
             done(false);
         }