Explorar o código

SceneOptimizer v0.1
High performance timer
performance log
new isCompletelyInFrustum API

David Catuhe %!s(int64=10) %!d(string=hai) anos
pai
achega
0d77dde14d
Modificáronse 30 ficheiros con 1708 adicións e 179 borrados
  1. 15 0
      Babylon/Culling/babylon.BoundingBox.ts
  2. 15 0
      Babylon/Culling/babylon.boundingBox.js
  3. 4 0
      Babylon/Culling/babylon.boundingInfo.js
  4. 4 0
      Babylon/Culling/babylon.boundingInfo.ts
  5. 28 24
      Babylon/Materials/babylon.standardMaterial.js
  6. 27 23
      Babylon/Materials/babylon.standardMaterial.ts
  7. 23 0
      Babylon/Materials/textures/babylon.baseTexture.js
  8. 19 0
      Babylon/Materials/textures/babylon.baseTexture.ts
  9. 22 0
      Babylon/Materials/textures/babylon.dynamicTexture.js
  10. 18 0
      Babylon/Materials/textures/babylon.dynamicTexture.ts
  11. 14 0
      Babylon/Materials/textures/babylon.renderTargetTexture.js
  12. 11 1
      Babylon/Materials/textures/babylon.renderTargetTexture.ts
  13. 1 1
      Babylon/Materials/textures/babylon.texture.ts
  14. 2 2
      Babylon/Materials/textures/babylon.videoTexture.js
  15. 2 2
      Babylon/Materials/textures/babylon.videoTexture.ts
  16. 14 0
      Babylon/Mesh/babylon.abstractMesh.js
  17. 16 1
      Babylon/Mesh/babylon.abstractMesh.ts
  18. 4 4
      Babylon/Rendering/babylon.renderingManager.js
  19. 4 4
      Babylon/Rendering/babylon.renderingManager.ts
  20. 271 0
      Babylon/Tools/babylon.sceneOptimizer.js
  21. 218 0
      Babylon/Tools/babylon.sceneOptimizer.ts
  22. 116 1
      Babylon/Tools/babylon.tools.js
  23. 93 1
      Babylon/Tools/babylon.tools.ts
  24. 1 1
      Babylon/babylon.engine.js
  25. 1 1
      Babylon/babylon.engine.ts
  26. 53 21
      Babylon/babylon.scene.js
  27. 51 21
      Babylon/babylon.scene.ts
  28. 567 53
      babylon.2.0-alpha.debug.js
  29. 16 16
      babylon.2.0-alpha.js
  30. 78 2
      babylon.2.0.d.ts

+ 15 - 0
Babylon/Culling/babylon.BoundingBox.ts

@@ -91,6 +91,10 @@
             return BoundingBox.IsInFrustum(this.vectorsWorld, frustumPlanes);
         }
 
+        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
+            return BoundingBox.IsCompletelyInFrustum(this.vectorsWorld, frustumPlanes);
+        }
+
         public intersectsPoint(point: Vector3): boolean {
             var delta = Engine.Epsilon;
 
@@ -143,6 +147,17 @@
             return (num <= (sphereRadius * sphereRadius));
         }
 
+        public static IsCompletelyInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean {
+            for (var p = 0; p < 6; p++) {
+                for (var i = 0; i < 8; i++) {
+                    if (frustumPlanes[p].dotCoordinate(boundingVectors[i]) < 0) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
         public static IsInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean {
             for (var p = 0; p < 6; p++) {
                 var inCount = 8;

+ 15 - 0
Babylon/Culling/babylon.boundingBox.js

@@ -84,6 +84,10 @@
             return BoundingBox.IsInFrustum(this.vectorsWorld, frustumPlanes);
         };
 
+        BoundingBox.prototype.isCompletelyInFrustum = function (frustumPlanes) {
+            return BoundingBox.IsCompletelyInFrustum(this.vectorsWorld, frustumPlanes);
+        };
+
         BoundingBox.prototype.intersectsPoint = function (point) {
             var delta = BABYLON.Engine.Epsilon;
 
@@ -136,6 +140,17 @@
             return (num <= (sphereRadius * sphereRadius));
         };
 
+        BoundingBox.IsCompletelyInFrustum = function (boundingVectors, frustumPlanes) {
+            for (var p = 0; p < 6; p++) {
+                for (var i = 0; i < 8; i++) {
+                    if (frustumPlanes[p].dotCoordinate(boundingVectors[i]) < 0) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        };
+
         BoundingBox.IsInFrustum = function (boundingVectors, frustumPlanes) {
             for (var p = 0; p < 6; p++) {
                 var inCount = 8;

+ 4 - 0
Babylon/Culling/babylon.boundingInfo.js

@@ -45,6 +45,10 @@
             return this.boundingBox.isInFrustum(frustumPlanes);
         };
 
+        BoundingInfo.prototype.isCompletelyInFrustum = function (frustumPlanes) {
+            return this.boundingBox.isCompletelyInFrustum(frustumPlanes);
+        };
+
         BoundingInfo.prototype._checkCollision = function (collider) {
             return collider._canDoCollision(this.boundingSphere.centerWorld, this.boundingSphere.radiusWorld, this.boundingBox.minimumWorld, this.boundingBox.maximumWorld);
         };

+ 4 - 0
Babylon/Culling/babylon.boundingInfo.ts

@@ -44,6 +44,10 @@
             return this.boundingBox.isInFrustum(frustumPlanes);
         }
 
+        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
+            return this.boundingBox.isCompletelyInFrustum(frustumPlanes);
+        }
+       
         public _checkCollision(collider: Collider): boolean {
             return collider._canDoCollision(this.boundingSphere.centerWorld, this.boundingSphere.radiusWorld, this.boundingBox.minimumWorld, this.boundingBox.maximumWorld);
         }

+ 28 - 24
Babylon/Materials/babylon.standardMaterial.js

@@ -32,7 +32,7 @@ var BABYLON;
             this.emissiveColor = new BABYLON.Color3(0, 0, 0);
             this.useAlphaFromDiffuseTexture = false;
             this.useSpecularOverAlpha = true;
-			this.fogEnabled = true;
+            this.fogEnabled = true;
             this._cachedDefines = null;
             this._renderTargets = new BABYLON.SmartArray(16);
             this._worldViewProjectionMatrix = BABYLON.Matrix.Zero();
@@ -237,27 +237,29 @@ var BABYLON;
                     }
 
                     // Shadows
-                    var shadowGenerator = light.getShadowGenerator();
-                    if (mesh && mesh.receiveShadows && shadowGenerator) {
-                        defines.push("#define SHADOW" + lightIndex);
-                        fallbacks.addFallback(0, "SHADOW" + lightIndex);
-
-                        if (!shadowsActivated) {
-                            defines.push("#define SHADOWS");
-                            shadowsActivated = true;
-                        }
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh && mesh.receiveShadows && shadowGenerator) {
+                            defines.push("#define SHADOW" + lightIndex);
+                            fallbacks.addFallback(0, "SHADOW" + lightIndex);
+
+                            if (!shadowsActivated) {
+                                defines.push("#define SHADOWS");
+                                shadowsActivated = true;
+                            }
 
-                        if (shadowGenerator.useVarianceShadowMap) {
-                            defines.push("#define SHADOWVSM" + lightIndex);
-                            if (lightIndex > 0) {
-                                fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                            if (shadowGenerator.useVarianceShadowMap) {
+                                defines.push("#define SHADOWVSM" + lightIndex);
+                                if (lightIndex > 0) {
+                                    fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                                }
                             }
-                        }
 
-                        if (shadowGenerator.usePoissonSampling) {
-                            defines.push("#define SHADOWPCF" + lightIndex);
-                            if (lightIndex > 0) {
-                                fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                            if (shadowGenerator.usePoissonSampling) {
+                                defines.push("#define SHADOWPCF" + lightIndex);
+                                if (lightIndex > 0) {
+                                    fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                                }
                             }
                         }
                     }
@@ -509,11 +511,13 @@ var BABYLON;
                     this._effect.setColor3("vLightSpecular" + lightIndex, this._scaledSpecular);
 
                     // Shadows
-                    var shadowGenerator = light.getShadowGenerator();
-                    if (mesh.receiveShadows && shadowGenerator) {
-                        this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
-                        this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
-                        this._effect.setFloat("darkness" + lightIndex, shadowGenerator.getDarkness());
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh.receiveShadows && shadowGenerator) {
+                            this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
+                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
+                            this._effect.setFloat("darkness" + lightIndex, shadowGenerator.getDarkness());
+                        }
                     }
 
                     lightIndex++;

+ 27 - 23
Babylon/Materials/babylon.standardMaterial.ts

@@ -241,27 +241,29 @@
                     }
 
                     // Shadows
-                    var shadowGenerator = light.getShadowGenerator();
-                    if (mesh && mesh.receiveShadows && shadowGenerator) {
-                        defines.push("#define SHADOW" + lightIndex);
-                        fallbacks.addFallback(0, "SHADOW" + lightIndex);
-
-                        if (!shadowsActivated) {
-                            defines.push("#define SHADOWS");
-                            shadowsActivated = true;
-                        }
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh && mesh.receiveShadows && shadowGenerator) {
+                            defines.push("#define SHADOW" + lightIndex);
+                            fallbacks.addFallback(0, "SHADOW" + lightIndex);
+
+                            if (!shadowsActivated) {
+                                defines.push("#define SHADOWS");
+                                shadowsActivated = true;
+                            }
 
-                        if (shadowGenerator.useVarianceShadowMap) {
-                            defines.push("#define SHADOWVSM" + lightIndex);
-                            if (lightIndex > 0) {
-                                fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                            if (shadowGenerator.useVarianceShadowMap) {
+                                defines.push("#define SHADOWVSM" + lightIndex);
+                                if (lightIndex > 0) {
+                                    fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                                }
                             }
-                        }
 
-                        if (shadowGenerator.usePoissonSampling) {
-                            defines.push("#define SHADOWPCF" + lightIndex);
-                            if (lightIndex > 0) {
-                                fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                            if (shadowGenerator.usePoissonSampling) {
+                                defines.push("#define SHADOWPCF" + lightIndex);
+                                if (lightIndex > 0) {
+                                    fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                                }
                             }
                         }
                     }
@@ -521,11 +523,13 @@
                     this._effect.setColor3("vLightSpecular" + lightIndex, this._scaledSpecular);
 
                     // Shadows
-                    var shadowGenerator = light.getShadowGenerator();
-                    if (mesh.receiveShadows && shadowGenerator) {
-                        this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
-                        this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
-                        this._effect.setFloat("darkness" + lightIndex, shadowGenerator.getDarkness());
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh.receiveShadows && shadowGenerator) {
+                            this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
+                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
+                            this._effect.setFloat("darkness" + lightIndex, shadowGenerator.getDarkness());
+                        }
                     }
 
                     lightIndex++;

+ 23 - 0
Babylon/Materials/textures/babylon.baseTexture.js

@@ -68,6 +68,29 @@
             return { width: this._texture._baseWidth, height: this._texture._baseHeight };
         };
 
+        BaseTexture.prototype.scale = function (ratio) {
+        };
+
+        Object.defineProperty(BaseTexture.prototype, "canRescale", {
+            get: function () {
+                return false;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        BaseTexture.prototype._removeFromCache = function (url, noMipmap) {
+            var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
+            for (var index = 0; index < texturesCache.length; index++) {
+                var texturesCacheEntry = texturesCache[index];
+
+                if (texturesCacheEntry.url === url && texturesCacheEntry.noMipmap === noMipmap) {
+                    texturesCache.splice(index, 1);
+                    return;
+                }
+            }
+        };
+
         BaseTexture.prototype._getFromCache = function (url, noMipmap) {
             var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
             for (var index = 0; index < texturesCache.length; index++) {

+ 19 - 0
Babylon/Materials/textures/babylon.baseTexture.ts

@@ -75,6 +75,25 @@
             return { width: this._texture._baseWidth, height: this._texture._baseHeight };
         }
 
+        public scale(ratio: number): void {
+        }
+
+        public get canRescale(): boolean {
+            return false;
+        }
+
+        public _removeFromCache(url: string, noMipmap: boolean): void {
+            var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
+            for (var index = 0; index < texturesCache.length; index++) {
+                var texturesCacheEntry = texturesCache[index];
+
+                if (texturesCacheEntry.url === url && texturesCacheEntry.noMipmap === noMipmap) {
+                    texturesCache.splice(index, 1);
+                    return;
+                }
+            }
+        }
+
         public _getFromCache(url: string, noMipmap: boolean): WebGLTexture {
             var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
             for (var index = 0; index < texturesCache.length; index++) {

+ 22 - 0
Babylon/Materials/textures/babylon.dynamicTexture.js

@@ -38,6 +38,28 @@ var BABYLON;
             this._canvas.height = textureSize.height;
             this._context = this._canvas.getContext("2d");
         }
+        Object.defineProperty(DynamicTexture.prototype, "canRescale", {
+            get: function () {
+                return true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        DynamicTexture.prototype.scale = function (ratio) {
+            var textureSize = this.getSize();
+
+            textureSize.width *= ratio;
+            textureSize.height *= ratio;
+
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+
+            this.releaseInternalTexture();
+
+            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
+        };
+
         DynamicTexture.prototype.getContext = function () {
             return this._context;
         };

+ 18 - 0
Babylon/Materials/textures/babylon.dynamicTexture.ts

@@ -34,6 +34,24 @@
             this._context = this._canvas.getContext("2d");
         }
 
+        public get canRescale(): boolean {
+            return true;
+        }
+
+        public scale(ratio: number): void {
+            var textureSize = this.getSize();
+
+            textureSize.width *= ratio;
+            textureSize.height *= ratio;
+
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+
+            this.releaseInternalTexture();
+
+            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
+        }
+
         public getContext(): CanvasRenderingContext2D {
             return this._context;
         }

+ 14 - 0
Babylon/Materials/textures/babylon.renderTargetTexture.js

@@ -66,6 +66,20 @@ var BABYLON;
             return this._size;
         };
 
+        Object.defineProperty(RenderTargetTexture.prototype, "canRescale", {
+            get: function () {
+                return true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        RenderTargetTexture.prototype.scale = function (ratio) {
+            var newSize = this._size * ratio;
+
+            this.resize(newSize, this._generateMipMaps);
+        };
+
         RenderTargetTexture.prototype.resize = function (size, generateMipMaps) {
             this.releaseInternalTexture();
             this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);

+ 11 - 1
Babylon/Materials/textures/babylon.renderTargetTexture.ts

@@ -65,7 +65,17 @@
             return this._size;
         }
 
-        public resize(size, generateMipMaps) {
+        public get canRescale(): boolean {
+            return true;
+        }
+
+        public scale(ratio: number): void {
+            var newSize = this._size * ratio;
+
+            this.resize(newSize, this._generateMipMaps);
+        }
+
+        public resize(size:any, generateMipMaps?: boolean) {
             this.releaseInternalTexture();
             this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
         }

+ 1 - 1
Babylon/Materials/textures/babylon.texture.ts

@@ -43,7 +43,7 @@
         private _cachedVAng: number;
         private _cachedWAng: number;
         private _cachedCoordinatesMode: number;
-        private _samplingMode: number;
+        public _samplingMode: number;
         private _buffer: any;
         private _deleteBuffer: boolean;
 

+ 2 - 2
Babylon/Materials/textures/babylon.videoTexture.js

@@ -43,7 +43,7 @@ var BABYLON;
                 _this.video.appendChild(source);
             });
 
-            this._lastUpdate = new Date().getTime();
+            this._lastUpdate = BABYLON.Tools.Now;
         }
         VideoTexture.prototype.update = function () {
             if (this._autoLaunch) {
@@ -51,7 +51,7 @@ var BABYLON;
                 this.video.play();
             }
 
-            var now = new Date().getTime();
+            var now = BABYLON.Tools.Now;
 
             if (now - this._lastUpdate < 15) {
                 return false;

+ 2 - 2
Babylon/Materials/textures/babylon.videoTexture.ts

@@ -37,7 +37,7 @@
                 this.video.appendChild(source);
             });
 
-            this._lastUpdate = new Date().getTime();
+            this._lastUpdate = Tools.Now;
         }
 
         public update(): boolean {
@@ -46,7 +46,7 @@
                 this.video.play();
             }
 
-            var now = new Date().getTime();
+            var now = Tools.Now;
 
             if (now - this._lastUpdate < 15) {
                 return false;

+ 14 - 0
Babylon/Mesh/babylon.abstractMesh.js

@@ -440,6 +440,20 @@ var BABYLON;
             return true;
         };
 
+        AbstractMesh.prototype.isCompletelyInFrustum = function (camera) {
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+
+            var transformMatrix = camera.getViewMatrix().multiply(camera.getProjectionMatrix());
+
+            if (!this._boundingInfo.isCompletelyInFrustum(BABYLON.Frustum.GetPlanes(transformMatrix))) {
+                return false;
+            }
+
+            return true;
+        };
+
         AbstractMesh.prototype.intersectsMesh = function (mesh, precise) {
             if (!this._boundingInfo || !mesh._boundingInfo) {
                 return false;

+ 16 - 1
Babylon/Mesh/babylon.abstractMesh.ts

@@ -330,7 +330,8 @@
 
                 var cameraGlobalPosition = new BABYLON.Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
 
-                BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y, this.position.z + cameraGlobalPosition.z, this._localTranslation);
+                BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
+                                                this.position.z + cameraGlobalPosition.z, this._localTranslation);
             } else {
                 BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
             }
@@ -435,6 +436,20 @@
             return true;
         }
 
+        public isCompletelyInFrustum(camera?: Camera): boolean {
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+
+            var transformMatrix = camera.getViewMatrix().multiply(camera.getProjectionMatrix());
+
+            if (!this._boundingInfo.isCompletelyInFrustum(BABYLON.Frustum.GetPlanes(transformMatrix))) {
+                return false;
+            }
+
+            return true;
+        }
+
         public intersectsMesh(mesh: AbstractMesh, precise?: boolean): boolean {
             if (!this._boundingInfo || !mesh._boundingInfo) {
                 return false;

+ 4 - 4
Babylon/Rendering/babylon.renderingManager.js

@@ -11,7 +11,7 @@
             }
 
             // Particles
-            var beforeParticlesDate = new Date().getTime();
+            var beforeParticlesDate = BABYLON.Tools.Now;
             for (var particleIndex = 0; particleIndex < this._scene._activeParticleSystems.length; particleIndex++) {
                 var particleSystem = this._scene._activeParticleSystems.data[particleIndex];
 
@@ -25,7 +25,7 @@
                     this._scene._activeParticles += particleSystem.render();
                 }
             }
-            this._scene._particlesDuration += new Date().getTime() - beforeParticlesDate;
+            this._scene._particlesDuration += BABYLON.Tools.Now - beforeParticlesDate;
         };
 
         RenderingManager.prototype._renderSprites = function (index) {
@@ -34,7 +34,7 @@
             }
 
             // Sprites
-            var beforeSpritessDate = new Date().getTime();
+            var beforeSpritessDate = BABYLON.Tools.Now;
             for (var id = 0; id < this._scene.spriteManagers.length; id++) {
                 var spriteManager = this._scene.spriteManagers[id];
 
@@ -43,7 +43,7 @@
                     spriteManager.render();
                 }
             }
-            this._scene._spritesDuration += new Date().getTime() - beforeSpritessDate;
+            this._scene._spritesDuration += BABYLON.Tools.Now - beforeSpritessDate;
         };
 
         RenderingManager.prototype._clearDepthBuffer = function () {

+ 4 - 4
Babylon/Rendering/babylon.renderingManager.ts

@@ -16,7 +16,7 @@
             }
 
             // Particles
-            var beforeParticlesDate = new Date().getTime();
+            var beforeParticlesDate = Tools.Now;
             for (var particleIndex = 0; particleIndex < this._scene._activeParticleSystems.length; particleIndex++) {
                 var particleSystem = this._scene._activeParticleSystems.data[particleIndex];
 
@@ -30,7 +30,7 @@
                     this._scene._activeParticles += particleSystem.render();
                 }
             }
-            this._scene._particlesDuration += new Date().getTime() - beforeParticlesDate;
+            this._scene._particlesDuration += Tools.Now - beforeParticlesDate;
         }
 
         private _renderSprites(index: number): void {
@@ -39,7 +39,7 @@
             }
 
             // Sprites       
-            var beforeSpritessDate = new Date().getTime();
+            var beforeSpritessDate = Tools.Now;
             for (var id = 0; id < this._scene.spriteManagers.length; id++) {
                 var spriteManager = this._scene.spriteManagers[id];
 
@@ -48,7 +48,7 @@
                     spriteManager.render();
                 }
             }
-            this._scene._spritesDuration += new Date().getTime() - beforeSpritessDate;
+            this._scene._spritesDuration += Tools.Now - beforeSpritessDate;
         }
 
         private _clearDepthBuffer(): void {

+ 271 - 0
Babylon/Tools/babylon.sceneOptimizer.js

@@ -0,0 +1,271 @@
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    // Standard optimizations
+    var SceneOptimization = (function () {
+        function SceneOptimization(priority) {
+            if (typeof priority === "undefined") { priority = 0; }
+            this.priority = priority;
+            this.apply = function (scene) {
+                return true;
+            };
+        }
+        return SceneOptimization;
+    })();
+    BABYLON.SceneOptimization = SceneOptimization;
+
+    var TextureSceneOptimization = (function (_super) {
+        __extends(TextureSceneOptimization, _super);
+        function TextureSceneOptimization(maximumSize, priority) {
+            if (typeof maximumSize === "undefined") { maximumSize = 1024; }
+            if (typeof priority === "undefined") { priority = 0; }
+            var _this = this;
+            _super.call(this, priority);
+            this.maximumSize = maximumSize;
+            this.priority = priority;
+            this.apply = function (scene) {
+                var allDone = true;
+                for (var index = 0; index < scene.textures.length; index++) {
+                    var texture = scene.textures[index];
+
+                    if (!texture.canRescale) {
+                        continue;
+                    }
+
+                    var currentSize = texture.getSize();
+                    var maxDimension = Math.max(currentSize.width, currentSize.height);
+
+                    if (maxDimension > _this.maximumSize) {
+                        texture.scale(0.5);
+                        allDone = false;
+                    }
+                }
+
+                return allDone;
+            };
+        }
+        return TextureSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.TextureSceneOptimization = TextureSceneOptimization;
+
+    var HardwareScalingSceneOptimization = (function (_super) {
+        __extends(HardwareScalingSceneOptimization, _super);
+        function HardwareScalingSceneOptimization(maximumScale, priority) {
+            if (typeof maximumScale === "undefined") { maximumScale = 2; }
+            if (typeof priority === "undefined") { priority = 0; }
+            var _this = this;
+            _super.call(this, priority);
+            this.maximumScale = maximumScale;
+            this.priority = priority;
+            this._currentScale = 1;
+            this.apply = function (scene) {
+                _this._currentScale++;
+
+                scene.getEngine().setHardwareScalingLevel(_this._currentScale);
+
+                return _this._currentScale >= _this.maximumScale;
+            };
+        }
+        return HardwareScalingSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.HardwareScalingSceneOptimization = HardwareScalingSceneOptimization;
+
+    var ShadowsSceneOptimization = (function (_super) {
+        __extends(ShadowsSceneOptimization, _super);
+        function ShadowsSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.shadowsEnabled = false;
+                return true;
+            };
+        }
+        return ShadowsSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.ShadowsSceneOptimization = ShadowsSceneOptimization;
+
+    var PostProcessesSceneOptimization = (function (_super) {
+        __extends(PostProcessesSceneOptimization, _super);
+        function PostProcessesSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.postProcessesEnabled = false;
+                return true;
+            };
+        }
+        return PostProcessesSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.PostProcessesSceneOptimization = PostProcessesSceneOptimization;
+
+    var LensFlaresSceneOptimization = (function (_super) {
+        __extends(LensFlaresSceneOptimization, _super);
+        function LensFlaresSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.lensFlaresEnabled = false;
+                return true;
+            };
+        }
+        return LensFlaresSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.LensFlaresSceneOptimization = LensFlaresSceneOptimization;
+
+    var ParticlesSceneOptimization = (function (_super) {
+        __extends(ParticlesSceneOptimization, _super);
+        function ParticlesSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.particlesEnabled = false;
+                return true;
+            };
+        }
+        return ParticlesSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.ParticlesSceneOptimization = ParticlesSceneOptimization;
+
+    // Options
+    var SceneOptimizerOptions = (function () {
+        function SceneOptimizerOptions(targetFrameRate, trackerDuration) {
+            if (typeof targetFrameRate === "undefined") { targetFrameRate = 60; }
+            if (typeof trackerDuration === "undefined") { trackerDuration = 2000; }
+            this.targetFrameRate = targetFrameRate;
+            this.trackerDuration = trackerDuration;
+            this.optimizations = new Array();
+        }
+        SceneOptimizerOptions.LowDegradationAllowed = function (targetFrameRate) {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 1024));
+
+            return result;
+        };
+
+        SceneOptimizerOptions.ModerateDegradationAllowed = function (targetFrameRate) {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 512));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new HardwareScalingSceneOptimization(priority, 2));
+
+            return result;
+        };
+
+        SceneOptimizerOptions.HighDegradationAllowed = function (targetFrameRate) {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 256));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new HardwareScalingSceneOptimization(priority, 4));
+
+            return result;
+        };
+        return SceneOptimizerOptions;
+    })();
+    BABYLON.SceneOptimizerOptions = SceneOptimizerOptions;
+
+    // Scene optimizer tool
+    var SceneOptimizer = (function () {
+        function SceneOptimizer() {
+        }
+        SceneOptimizer._CheckCurrentState = function (scene, options, currentPriorityLevel, onSuccess, onFailure) {
+            // TODO: add an epsilon
+            if (BABYLON.Tools.GetFps() >= options.targetFrameRate) {
+                if (onSuccess) {
+                    onSuccess();
+                }
+
+                return;
+            }
+
+            // Apply current level of optimizations
+            var allDone = true;
+            var noOptimizationApplied = true;
+            for (var index = 0; index < options.optimizations.length; index++) {
+                var optimization = options.optimizations[index];
+
+                if (optimization.priority === currentPriorityLevel) {
+                    noOptimizationApplied = false;
+                    allDone = allDone && optimization.apply(scene);
+                }
+            }
+
+            // If no optimization was applied, this is a failure :(
+            if (noOptimizationApplied) {
+                if (onFailure) {
+                    onFailure();
+                }
+
+                return;
+            }
+
+            // If all optimizations were done, move to next level
+            if (allDone) {
+                currentPriorityLevel++;
+            }
+
+            // Let's the system running for a specific amount of time before checking FPS
+            scene.executeWhenReady(function () {
+                setTimeout(function () {
+                    SceneOptimizer._CheckCurrentState(scene, options, currentPriorityLevel, onSuccess, onFailure);
+                }, options.trackerDuration);
+            });
+        };
+
+        SceneOptimizer.OptimizeAsync = function (scene, options, onSuccess, onFailure) {
+            if (!options) {
+                options = SceneOptimizerOptions.ModerateDegradationAllowed();
+            }
+
+            // Let's the system running for a specific amount of time before checking FPS
+            scene.executeWhenReady(function () {
+                setTimeout(function () {
+                    SceneOptimizer._CheckCurrentState(scene, options, 0, onSuccess, onFailure);
+                }, options.trackerDuration);
+            });
+        };
+        return SceneOptimizer;
+    })();
+    BABYLON.SceneOptimizer = SceneOptimizer;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.sceneOptimizer.js.map

+ 218 - 0
Babylon/Tools/babylon.sceneOptimizer.ts

@@ -0,0 +1,218 @@
+module BABYLON {
+    // Standard optimizations
+    export class SceneOptimization {
+        public apply = (scene: Scene): boolean => {
+            return true; // Return true if everything that can be done was applied
+        };
+
+        constructor(public priority: number = 0) {
+        }
+    }
+
+    export class TextureSceneOptimization extends SceneOptimization {
+        constructor(public maximumSize: number = 1024, public priority: number = 0) {
+            super(priority);
+        }
+
+        public apply = (scene: Scene): boolean => {
+
+            var allDone = true;
+            for (var index = 0; index < scene.textures.length; index++) {
+                var texture = scene.textures[index];
+
+                if (!texture.canRescale) {
+                    continue;
+                }
+
+                var currentSize = texture.getSize();
+                var maxDimension = Math.max(currentSize.width, currentSize.height);
+
+                if (maxDimension > this.maximumSize) {
+                    texture.scale(0.5);
+                    allDone = false;
+                }
+            }
+
+            return allDone;
+        }
+    }
+
+    export class HardwareScalingSceneOptimization extends SceneOptimization {
+        private _currentScale = 1;
+
+        constructor(public maximumScale: number = 2, public priority: number = 0) {
+            super(priority);
+        }
+
+        public apply = (scene: Scene): boolean => {
+            this._currentScale++;
+
+            scene.getEngine().setHardwareScalingLevel(this._currentScale);
+
+            return this._currentScale >= this.maximumScale;
+        };
+    }
+
+    export class ShadowsSceneOptimization extends SceneOptimization {
+        public apply = (scene: Scene): boolean => {
+            scene.shadowsEnabled = false;
+            return true;
+        };
+    }
+
+    export class PostProcessesSceneOptimization extends SceneOptimization {
+        public apply = (scene: Scene): boolean => {
+            scene.postProcessesEnabled = false;
+            return true;
+        };
+    }
+
+    export class LensFlaresSceneOptimization extends SceneOptimization {
+        public apply = (scene: Scene): boolean => {
+            scene.lensFlaresEnabled = false;
+            return true;
+        };
+    }
+
+    export class ParticlesSceneOptimization extends SceneOptimization {
+        public apply = (scene: Scene): boolean => {
+            scene.particlesEnabled = false;
+            return true;
+        };
+    }
+
+    // Options
+    export class SceneOptimizerOptions {
+        public optimizations = new Array<SceneOptimization>();
+
+        constructor(public targetFrameRate: number = 60, public trackerDuration: number = 2000) {
+        }
+
+        public static LowDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 1024));
+
+            return result;
+        }
+
+        public static ModerateDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 512));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new HardwareScalingSceneOptimization(priority, 2));
+
+            return result;
+        }
+
+        public static HighDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 256));
+
+            // Next priority
+            priority++;
+            result.optimizations.push(new HardwareScalingSceneOptimization(priority, 4));
+
+            return result;
+        }
+    }
+
+
+    // Scene optimizer tool
+    export class SceneOptimizer {
+
+        static _CheckCurrentState(scene: Scene, options: SceneOptimizerOptions, currentPriorityLevel: number, onSuccess?: () => void, onFailure?: () => void) {
+            // TODO: add an epsilon
+            if (Tools.GetFps() >= options.targetFrameRate) {
+                if (onSuccess) {
+                    onSuccess();
+                }
+
+                return;
+            }
+
+            // Apply current level of optimizations
+            var allDone = true;
+            var noOptimizationApplied = true;
+            for (var index = 0; index < options.optimizations.length; index++) {
+                var optimization = options.optimizations[index];
+
+                if (optimization.priority === currentPriorityLevel) {
+                    noOptimizationApplied = false;
+                    allDone = allDone && optimization.apply(scene);
+                }
+            }
+
+            // If no optimization was applied, this is a failure :(
+            if (noOptimizationApplied) {
+                if (onFailure) {
+                    onFailure();
+                }
+
+                return;
+            }
+
+            // If all optimizations were done, move to next level
+            if (allDone) {
+                currentPriorityLevel++;
+            }
+
+            // Let's the system running for a specific amount of time before checking FPS
+            scene.executeWhenReady(() => {
+                setTimeout(() => {
+                    SceneOptimizer._CheckCurrentState(scene, options, currentPriorityLevel, onSuccess, onFailure);
+                }, options.trackerDuration);
+            });
+        }
+
+        public static OptimizeAsync(scene: Scene, options?: SceneOptimizerOptions, onSuccess?: () => void, onFailure?: () => void): void {
+            if (!options) {
+                options = SceneOptimizerOptions.ModerateDegradationAllowed();
+            }
+
+            // Let's the system running for a specific amount of time before checking FPS
+            scene.executeWhenReady(() => {
+                setTimeout(() => {
+                    SceneOptimizer._CheckCurrentState(scene, options, 0, onSuccess, onFailure);
+                }, options.trackerDuration);
+            });
+        }
+    }
+} 

+ 116 - 1
Babylon/Tools/babylon.tools.js

@@ -389,7 +389,7 @@
         };
 
         Tools._MeasureFps = function () {
-            previousFramesDuration.push((new Date).getTime());
+            previousFramesDuration.push(Tools.Now);
             var length = previousFramesDuration.length;
 
             if (length >= 2) {
@@ -650,6 +650,112 @@
             enumerable: true,
             configurable: true
         });
+
+        Object.defineProperty(Tools, "PerformanceNoneLogLevel", {
+            get: function () {
+                return Tools._PerformanceNoneLogLevel;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Tools, "PerformanceUserMarkLogLevel", {
+            get: function () {
+                return Tools._PerformanceUserMarkLogLevel;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Tools, "PerformanceConsoleLogLevel", {
+            get: function () {
+                return Tools._PerformanceConsoleLogLevel;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Tools, "PerformanceLogLevel", {
+            set: function (level) {
+                if ((level & Tools.PerformanceUserMarkLogLevel) === Tools.PerformanceUserMarkLogLevel) {
+                    Tools.StartPerformanceCounter = Tools._StartUserMark;
+                    Tools.EndPerformanceCounter = Tools._EndUserMark;
+                    return;
+                }
+
+                if ((level & Tools.PerformanceConsoleLogLevel) === Tools.PerformanceConsoleLogLevel) {
+                    Tools.StartPerformanceCounter = Tools._StartPerformanceConsole;
+                    Tools.EndPerformanceCounter = Tools._EndPerformanceConsole;
+                    return;
+                }
+
+                Tools.StartPerformanceCounter = Tools._StartPerformanceCounterDisabled;
+                Tools.EndPerformanceCounter = Tools._EndPerformanceCounterDisabled;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Tools._StartPerformanceCounterDisabled = function (counterName, condition) {
+        };
+
+        Tools._EndPerformanceCounterDisabled = function (counterName, condition) {
+        };
+
+        Tools._StartUserMark = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition || !Tools._performance.mark) {
+                return;
+            }
+            Tools._performance.mark(counterName + "-Begin");
+        };
+
+        Tools._EndUserMark = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition || !Tools._performance.mark) {
+                return;
+            }
+            Tools._performance.mark(counterName + "-End");
+            Tools._performance.measure(counterName, counterName + "-Begin", counterName + "-End");
+        };
+
+        Tools._StartPerformanceConsole = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition) {
+                return;
+            }
+
+            Tools._StartUserMark(counterName, condition);
+
+            if (console.time) {
+                console.time(counterName);
+            }
+        };
+
+        Tools._EndPerformanceConsole = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition) {
+                return;
+            }
+
+            Tools._EndUserMark(counterName, condition);
+
+            if (console.time) {
+                console.timeEnd(counterName);
+            }
+        };
+
+        Object.defineProperty(Tools, "Now", {
+            get: function () {
+                if (window.performance.now) {
+                    return window.performance.now();
+                }
+
+                return new Date().getTime();
+            },
+            enumerable: true,
+            configurable: true
+        });
         Tools.BaseUrl = "";
 
         Tools.GetExponantOfTwo = function (value, max) {
@@ -675,6 +781,15 @@
         Tools.Warn = Tools._WarnEnabled;
 
         Tools.Error = Tools._ErrorEnabled;
+
+        Tools._PerformanceNoneLogLevel = 0;
+        Tools._PerformanceUserMarkLogLevel = 1;
+        Tools._PerformanceConsoleLogLevel = 2;
+
+        Tools._performance = window.performance;
+
+        Tools.StartPerformanceCounter = Tools._StartPerformanceCounterDisabled;
+        Tools.EndPerformanceCounter = Tools._EndPerformanceCounterDisabled;
         return Tools;
     })();
     BABYLON.Tools = Tools;

+ 93 - 1
Babylon/Tools/babylon.tools.ts

@@ -424,7 +424,7 @@
         }
 
         public static _MeasureFps(): void {
-            previousFramesDuration.push((new Date).getTime());
+            previousFramesDuration.push(Tools.Now);
             var length = previousFramesDuration.length;
 
             if (length >= 2) {
@@ -689,5 +689,97 @@
                 Tools.Error = Tools._ErrorDisabled;
             }
         }
+
+        // Performances
+        private static _PerformanceNoneLogLevel = 0;
+        private static _PerformanceUserMarkLogLevel = 1;
+        private static _PerformanceConsoleLogLevel = 2;
+
+        private static _performance: Performance = window.performance;
+
+        static get PerformanceNoneLogLevel(): number {
+            return Tools._PerformanceNoneLogLevel;
+        }
+
+        static get PerformanceUserMarkLogLevel(): number {
+            return Tools._PerformanceUserMarkLogLevel;
+        }
+
+        static get PerformanceConsoleLogLevel(): number {
+            return Tools._PerformanceConsoleLogLevel;
+        }
+
+        public static set PerformanceLogLevel(level: number) {
+            if ((level & Tools.PerformanceUserMarkLogLevel) === Tools.PerformanceUserMarkLogLevel) {
+                Tools.StartPerformanceCounter = Tools._StartUserMark;
+                Tools.EndPerformanceCounter = Tools._EndUserMark;
+                return;
+            }
+
+            if ((level & Tools.PerformanceConsoleLogLevel) === Tools.PerformanceConsoleLogLevel) {
+                Tools.StartPerformanceCounter = Tools._StartPerformanceConsole;
+                Tools.EndPerformanceCounter = Tools._EndPerformanceConsole;
+                return;
+            }
+
+            Tools.StartPerformanceCounter = Tools._StartPerformanceCounterDisabled;
+            Tools.EndPerformanceCounter = Tools._EndPerformanceCounterDisabled;
+        }
+
+        static _StartPerformanceCounterDisabled(counterName: string, condition?: boolean): void {
+        }
+
+        static _EndPerformanceCounterDisabled(counterName: string, condition?: boolean): void {
+        }
+
+        static _StartUserMark(counterName: string, condition = true): void {
+            if (!condition || !Tools._performance.mark) {
+                return;
+            }
+            Tools._performance.mark(counterName + "-Begin");
+        }
+
+        static _EndUserMark(counterName: string, condition = true): void {
+            if (!condition || !Tools._performance.mark) {
+                return;
+            }
+            Tools._performance.mark(counterName + "-End");
+            Tools._performance.measure(counterName, counterName + "-Begin", counterName + "-End");
+        }
+
+        static _StartPerformanceConsole(counterName: string, condition = true): void {
+            if (!condition) {
+                return;
+            }
+
+            Tools._StartUserMark(counterName, condition);
+
+            if (console.time) {
+                console.time(counterName);
+            }
+        }
+
+        static _EndPerformanceConsole(counterName: string, condition = true): void {
+            if (!condition) {
+                return;
+            }
+
+            Tools._EndUserMark(counterName, condition);
+
+            if (console.time) {
+                console.timeEnd(counterName);
+            }
+        }
+
+        public static StartPerformanceCounter: (counterName: string, condition?: boolean) => void = Tools._StartPerformanceCounterDisabled;
+        public static EndPerformanceCounter: (counterName: string, condition?: boolean) => void = Tools._EndPerformanceCounterDisabled;
+
+        public static get Now(): number {
+            if (window.performance.now) {
+                return window.performance.now();
+            }
+
+            return new Date().getTime();
+        }
     }
 } 

+ 1 - 1
Babylon/babylon.engine.js

@@ -1242,7 +1242,7 @@
                 else
                     callback(buffer);
             } else if (isDDS) {
-                var callback = function (data) {
+                callback = function (data) {
                     var info = BABYLON.Internals.DDSTools.GetDDSInfo(data);
 
                     var loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && !noMipmap && ((info.width >> (info.mipmapCount - 1)) == 1);

+ 1 - 1
Babylon/babylon.engine.ts

@@ -1254,7 +1254,7 @@
                     callback(buffer);
 
             } else if (isDDS) {
-                var callback = (data) => {
+                callback = (data) => {
                     var info = BABYLON.Internals.DDSTools.GetDDSInfo(data);
 
                     var loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && !noMipmap && ((info.width >> (info.mipmapCount - 1)) == 1);

+ 53 - 21
Babylon/babylon.scene.js

@@ -16,6 +16,7 @@
             this.fogStart = 0;
             this.fogEnd = 1000.0;
             // Lights
+            this.shadowsEnabled = true;
             this.lightsEnabled = true;
             this.lights = new Array();
             // Cameras
@@ -41,6 +42,7 @@
             // Skeletons
             this.skeletons = new Array();
             // Lens flares
+            this.lensFlaresEnabled = true;
             this.lensFlareSystems = new Array();
             // Collisions
             this.collisionsEnabled = true;
@@ -431,11 +433,11 @@
 
         Scene.prototype._animate = function () {
             if (!this._animationStartDate) {
-                this._animationStartDate = new Date().getTime();
+                this._animationStartDate = BABYLON.Tools.Now;
             }
 
             // Getting time
-            var now = new Date().getTime();
+            var now = BABYLON.Tools.Now;
             var delay = now - this._animationStartDate;
 
             for (var index = 0; index < this._activeAnimatables.length; index++) {
@@ -737,8 +739,9 @@
             }
 
             // Particle systems
-            var beforeParticlesDate = new Date().getTime();
+            var beforeParticlesDate = BABYLON.Tools.Now;
             if (this.particlesEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Particles", this.particleSystems.length > 0);
                 for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
                     var particleSystem = this.particleSystems[particleIndex];
 
@@ -751,8 +754,9 @@
                         particleSystem.animate();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Particles", this.particleSystems.length > 0);
             }
-            this._particlesDuration += new Date().getTime() - beforeParticlesDate;
+            this._particlesDuration += BABYLON.Tools.Now - beforeParticlesDate;
         };
 
         Scene.prototype._activeMesh = function (mesh) {
@@ -799,6 +803,8 @@
             if (!this.activeCamera)
                 throw new Error("Active camera not set");
 
+            BABYLON.Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
+
             // Viewport
             engine.setViewport(this.activeCamera.viewport);
 
@@ -811,9 +817,11 @@
             }
 
             // Meshes
-            var beforeEvaluateActiveMeshesDate = new Date().getTime();
+            var beforeEvaluateActiveMeshesDate = BABYLON.Tools.Now;
+            BABYLON.Tools.StartPerformanceCounter("Active meshes evaluation");
             this._evaluateActiveMeshes();
-            this._evaluateActiveMeshesDuration += new Date().getTime() - beforeEvaluateActiveMeshesDate;
+            this._evaluateActiveMeshesDuration += BABYLON.Tools.Now - beforeEvaluateActiveMeshesDate;
+            BABYLON.Tools.EndPerformanceCounter("Active meshes evaluation");
 
             for (var skeletonIndex = 0; skeletonIndex < this._activeSkeletons.length; skeletonIndex++) {
                 var skeleton = this._activeSkeletons.data[skeletonIndex];
@@ -822,8 +830,9 @@
             }
 
             // Render targets
-            var beforeRenderTargetDate = new Date().getTime();
+            var beforeRenderTargetDate = BABYLON.Tools.Now;
             if (this.renderTargetsEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
                 for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
                     var renderTarget = this._renderTargets.data[renderIndex];
                     if (renderTarget._shouldRender()) {
@@ -831,18 +840,19 @@
                         renderTarget.render();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0);
                 this._renderId++;
             }
 
             if (this._renderTargets.length > 0) {
                 engine.restoreDefaultFramebuffer();
             }
-            this._renderTargetsDuration += new Date().getTime() - beforeRenderTargetDate;
+            this._renderTargetsDuration += BABYLON.Tools.Now - beforeRenderTargetDate;
 
             // Prepare Frame
             this.postProcessManager._prepareFrame();
 
-            var beforeRenderDate = new Date().getTime();
+            var beforeRenderDate = BABYLON.Tools.Now;
 
             // Backgrounds
             if (this.layers.length) {
@@ -859,13 +869,20 @@
             }
 
             // Render
+            BABYLON.Tools.StartPerformanceCounter("Main render");
             this._renderingManager.render(null, null, true, true);
+            BABYLON.Tools.EndPerformanceCounter("Main render");
 
             // Bounding boxes
             this._boundingBoxRenderer.render();
 
-            for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
-                this.lensFlareSystems[lensFlareSystemIndex].render();
+            // Lens flares
+            if (this.lensFlaresEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
+                for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
+                    this.lensFlareSystems[lensFlareSystemIndex].render();
+                }
+                BABYLON.Tools.EndPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
             }
 
             // Foregrounds
@@ -880,7 +897,7 @@
                 engine.setDepthBuffer(true);
             }
 
-            this._renderDuration += new Date().getTime() - beforeRenderDate;
+            this._renderDuration += BABYLON.Tools.Now - beforeRenderDate;
 
             // Finalize frame
             this.postProcessManager._finalizeFrame(camera.isIntermediate);
@@ -894,6 +911,8 @@
             if (this.afterCameraRender) {
                 this.afterCameraRender(this.activeCamera);
             }
+
+            BABYLON.Tools.EndPerformanceCounter("Rendering camera " + this.activeCamera.name);
         };
 
         Scene.prototype._processSubCameras = function (camera) {
@@ -944,7 +963,7 @@
         };
 
         Scene.prototype.render = function () {
-            var startDate = new Date().getTime();
+            var startDate = BABYLON.Tools.Now;
             this._particlesDuration = 0;
             this._spritesDuration = 0;
             this._activeParticles = 0;
@@ -954,6 +973,8 @@
             this._activeVertices = 0;
             this._meshesForIntersections.reset();
 
+            BABYLON.Tools.StartPerformanceCounter("Scene rendering");
+
             // Actions
             if (this.actionManager) {
                 this.actionManager.processTrigger(BABYLON.ActionManager.OnEveryFrameTrigger, null);
@@ -975,13 +996,16 @@
 
             // Physics
             if (this._physicsEngine) {
+                BABYLON.Tools.StartPerformanceCounter("Physics");
                 this._physicsEngine._runOneStep(deltaTime / 1000.0);
+                BABYLON.Tools.EndPerformanceCounter("Physics");
             }
 
             // Customs render targets
-            var beforeRenderTargetDate = new Date().getTime();
+            var beforeRenderTargetDate = BABYLON.Tools.Now;
             var engine = this.getEngine();
             if (this.renderTargetsEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
                 for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
                     var renderTarget = this.customRenderTargets[customIndex];
                     if (renderTarget._shouldRender()) {
@@ -1001,33 +1025,40 @@
                         renderTarget.render();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
+
                 this._renderId++;
             }
 
             if (this.customRenderTargets.length > 0) {
                 engine.restoreDefaultFramebuffer();
             }
-            this._renderTargetsDuration += new Date().getTime() - beforeRenderTargetDate;
+            this._renderTargetsDuration += BABYLON.Tools.Now - beforeRenderTargetDate;
 
             // Procedural textures
             if (this.proceduralTexturesEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
                 for (var proceduralIndex = 0; proceduralIndex < this._proceduralTextures.length; proceduralIndex++) {
                     var proceduralTexture = this._proceduralTextures[proceduralIndex];
                     if (proceduralTexture._shouldRender()) {
                         proceduralTexture.render();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
             }
 
             // Clear
             this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe, true);
 
-            for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
-                var light = this.lights[lightIndex];
-                var shadowGenerator = light.getShadowGenerator();
+            // Shadows
+            if (this.shadowsEnabled) {
+                for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
+                    var light = this.lights[lightIndex];
+                    var shadowGenerator = light.getShadowGenerator();
 
-                if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
-                    this._renderTargets.push(shadowGenerator.getShadowMap());
+                    if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
+                        this._renderTargets.push(shadowGenerator.getShadowMap());
+                    }
                 }
             }
 
@@ -1064,7 +1095,8 @@
 
             this._toBeDisposed.reset();
 
-            this._lastFrameDuration = new Date().getTime() - startDate;
+            BABYLON.Tools.EndPerformanceCounter("Scene rendering");
+            this._lastFrameDuration = BABYLON.Tools.Now - startDate;
         };
 
         Scene.prototype.dispose = function () {

+ 51 - 21
Babylon/babylon.scene.ts

@@ -46,6 +46,7 @@
         public fogEnd = 1000.0;
 
         // Lights
+        public shadowsEnabled = true;
         public lightsEnabled = true;
         public lights = new Array<Light>();
 
@@ -82,6 +83,7 @@
         public skeletons = new Array<Skeleton>();
 
         // Lens flares
+        public lensFlaresEnabled = true;
         public lensFlareSystems = new Array<LensFlareSystem>();
 
         // Collisions
@@ -508,10 +510,10 @@
 
         private _animate(): void {
             if (!this._animationStartDate) {
-                this._animationStartDate = new Date().getTime();
+                this._animationStartDate = Tools.Now;
             }
             // Getting time
-            var now = new Date().getTime();
+            var now = Tools.Now;
             var delay = now - this._animationStartDate;
 
             for (var index = 0; index < this._activeAnimatables.length; index++) {
@@ -813,8 +815,9 @@
             }
 
             // Particle systems
-            var beforeParticlesDate = new Date().getTime();
+            var beforeParticlesDate = Tools.Now;
             if (this.particlesEnabled) {
+                Tools.StartPerformanceCounter("Particles", this.particleSystems.length > 0);
                 for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
                     var particleSystem = this.particleSystems[particleIndex];
 
@@ -827,8 +830,9 @@
                         particleSystem.animate();
                     }
                 }
+                Tools.EndPerformanceCounter("Particles", this.particleSystems.length > 0);
             }
-            this._particlesDuration += new Date().getTime() - beforeParticlesDate;
+            this._particlesDuration += Tools.Now - beforeParticlesDate;
         }
 
         private _activeMesh(mesh: AbstractMesh): void {
@@ -875,6 +879,8 @@
             if (!this.activeCamera)
                 throw new Error("Active camera not set");
 
+            Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
+
             // Viewport
             engine.setViewport(this.activeCamera.viewport);
 
@@ -887,9 +893,11 @@
             }
 
             // Meshes
-            var beforeEvaluateActiveMeshesDate = new Date().getTime();
+            var beforeEvaluateActiveMeshesDate = Tools.Now;
+            Tools.StartPerformanceCounter("Active meshes evaluation");
             this._evaluateActiveMeshes();
-            this._evaluateActiveMeshesDuration += new Date().getTime() - beforeEvaluateActiveMeshesDate;
+            this._evaluateActiveMeshesDuration += Tools.Now - beforeEvaluateActiveMeshesDate;
+            Tools.EndPerformanceCounter("Active meshes evaluation");
 
             // Skeletons
             for (var skeletonIndex = 0; skeletonIndex < this._activeSkeletons.length; skeletonIndex++) {
@@ -899,8 +907,9 @@
             }
 
             // Render targets
-            var beforeRenderTargetDate = new Date().getTime();
+            var beforeRenderTargetDate = Tools.Now;
             if (this.renderTargetsEnabled) {
+                Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
                 for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
                     var renderTarget = this._renderTargets.data[renderIndex];
                     if (renderTarget._shouldRender()) {
@@ -908,18 +917,19 @@
                         renderTarget.render();
                     }
                 }
+                Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0);
                 this._renderId++;
             }
 
             if (this._renderTargets.length > 0) { // Restore back buffer
                 engine.restoreDefaultFramebuffer();
             }
-            this._renderTargetsDuration += new Date().getTime() - beforeRenderTargetDate;
+            this._renderTargetsDuration += Tools.Now - beforeRenderTargetDate;
 
             // Prepare Frame
             this.postProcessManager._prepareFrame();
 
-            var beforeRenderDate = new Date().getTime();
+            var beforeRenderDate = Tools.Now;
             // Backgrounds
             if (this.layers.length) {
                 engine.setDepthBuffer(false);
@@ -935,14 +945,20 @@
             }
 
             // Render
+            Tools.StartPerformanceCounter("Main render");
             this._renderingManager.render(null, null, true, true);
+            Tools.EndPerformanceCounter("Main render");
 
             // Bounding boxes
             this._boundingBoxRenderer.render();
 
             // Lens flares
-            for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
-                this.lensFlareSystems[lensFlareSystemIndex].render();
+            if (this.lensFlaresEnabled) {
+                Tools.StartPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
+                for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
+                    this.lensFlareSystems[lensFlareSystemIndex].render();
+                }
+                Tools.EndPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
             }
 
             // Foregrounds
@@ -957,7 +973,7 @@
                 engine.setDepthBuffer(true);
             }
 
-            this._renderDuration += new Date().getTime() - beforeRenderDate;
+            this._renderDuration += Tools.Now - beforeRenderDate;
 
             // Finalize frame
             this.postProcessManager._finalizeFrame(camera.isIntermediate);
@@ -972,6 +988,7 @@
                 this.afterCameraRender(this.activeCamera);
             }
 
+            Tools.EndPerformanceCounter("Rendering camera " + this.activeCamera.name);
         }
 
         private _processSubCameras(camera: Camera): void {
@@ -1024,7 +1041,7 @@
         }
 
         public render(): void {
-            var startDate = new Date().getTime();
+            var startDate = Tools.Now;
             this._particlesDuration = 0;
             this._spritesDuration = 0;
             this._activeParticles = 0;
@@ -1034,6 +1051,8 @@
             this._activeVertices = 0;
             this._meshesForIntersections.reset();
 
+            Tools.StartPerformanceCounter("Scene rendering");
+
             // Actions
             if (this.actionManager) {
                 this.actionManager.processTrigger(ActionManager.OnEveryFrameTrigger, null);
@@ -1055,13 +1074,16 @@
 
             // Physics
             if (this._physicsEngine) {
+                Tools.StartPerformanceCounter("Physics");
                 this._physicsEngine._runOneStep(deltaTime / 1000.0);
+                Tools.EndPerformanceCounter("Physics");
             }
 
             // Customs render targets
-            var beforeRenderTargetDate = new Date().getTime();
+            var beforeRenderTargetDate = Tools.Now;
             var engine = this.getEngine();
             if (this.renderTargetsEnabled) {
+                Tools.StartPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
                 for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
                     var renderTarget = this.customRenderTargets[customIndex];
                     if (renderTarget._shouldRender()) {
@@ -1081,34 +1103,40 @@
                         renderTarget.render();
                     }
                 }
+                Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
+
                 this._renderId++;
             }
 
             if (this.customRenderTargets.length > 0) { // Restore back buffer
                 engine.restoreDefaultFramebuffer();
             }
-            this._renderTargetsDuration += new Date().getTime() - beforeRenderTargetDate;
+            this._renderTargetsDuration += Tools.Now - beforeRenderTargetDate;
 
             // Procedural textures
             if (this.proceduralTexturesEnabled) {
+                Tools.StartPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
                 for (var proceduralIndex = 0; proceduralIndex < this._proceduralTextures.length; proceduralIndex++) {
                     var proceduralTexture = this._proceduralTextures[proceduralIndex];
                     if (proceduralTexture._shouldRender()) {
                         proceduralTexture.render();
                     }
                 }
+                Tools.EndPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
             }
 
             // Clear
             this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe, true);
 
             // Shadows
-            for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
-                var light = this.lights[lightIndex];
-                var shadowGenerator = light.getShadowGenerator();
+            if (this.shadowsEnabled) {
+                for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
+                    var light = this.lights[lightIndex];
+                    var shadowGenerator = light.getShadowGenerator();
 
-                if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
-                    this._renderTargets.push(shadowGenerator.getShadowMap());
+                    if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
+                        this._renderTargets.push(shadowGenerator.getShadowMap());
+                    }
                 }
             }
 
@@ -1146,7 +1174,9 @@
 
             this._toBeDisposed.reset();
 
-            this._lastFrameDuration = new Date().getTime() - startDate;
+
+            Tools.EndPerformanceCounter("Scene rendering");
+            this._lastFrameDuration = Tools.Now - startDate;
         }
 
         public dispose(): void {

+ 567 - 53
babylon.2.0-alpha.debug.js

@@ -2556,7 +2556,7 @@ var BABYLON;
         };
 
         Tools._MeasureFps = function () {
-            previousFramesDuration.push((new Date).getTime());
+            previousFramesDuration.push(Tools.Now);
             var length = previousFramesDuration.length;
 
             if (length >= 2) {
@@ -2817,6 +2817,112 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+
+        Object.defineProperty(Tools, "PerformanceNoneLogLevel", {
+            get: function () {
+                return Tools._PerformanceNoneLogLevel;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Tools, "PerformanceUserMarkLogLevel", {
+            get: function () {
+                return Tools._PerformanceUserMarkLogLevel;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Tools, "PerformanceConsoleLogLevel", {
+            get: function () {
+                return Tools._PerformanceConsoleLogLevel;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Tools, "PerformanceLogLevel", {
+            set: function (level) {
+                if ((level & Tools.PerformanceUserMarkLogLevel) === Tools.PerformanceUserMarkLogLevel) {
+                    Tools.StartPerformanceCounter = Tools._StartUserMark;
+                    Tools.EndPerformanceCounter = Tools._EndUserMark;
+                    return;
+                }
+
+                if ((level & Tools.PerformanceConsoleLogLevel) === Tools.PerformanceConsoleLogLevel) {
+                    Tools.StartPerformanceCounter = Tools._StartPerformanceConsole;
+                    Tools.EndPerformanceCounter = Tools._EndPerformanceConsole;
+                    return;
+                }
+
+                Tools.StartPerformanceCounter = Tools._StartPerformanceCounterDisabled;
+                Tools.EndPerformanceCounter = Tools._EndPerformanceCounterDisabled;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Tools._StartPerformanceCounterDisabled = function (counterName, condition) {
+        };
+
+        Tools._EndPerformanceCounterDisabled = function (counterName, condition) {
+        };
+
+        Tools._StartUserMark = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition || !Tools._performance.mark) {
+                return;
+            }
+            Tools._performance.mark(counterName + "-Begin");
+        };
+
+        Tools._EndUserMark = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition || !Tools._performance.mark) {
+                return;
+            }
+            Tools._performance.mark(counterName + "-End");
+            Tools._performance.measure(counterName, counterName + "-Begin", counterName + "-End");
+        };
+
+        Tools._StartPerformanceConsole = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition) {
+                return;
+            }
+
+            Tools._StartUserMark(counterName, condition);
+
+            if (console.time) {
+                console.time(counterName);
+            }
+        };
+
+        Tools._EndPerformanceConsole = function (counterName, condition) {
+            if (typeof condition === "undefined") { condition = true; }
+            if (!condition) {
+                return;
+            }
+
+            Tools._EndUserMark(counterName, condition);
+
+            if (console.time) {
+                console.timeEnd(counterName);
+            }
+        };
+
+        Object.defineProperty(Tools, "Now", {
+            get: function () {
+                if (window.performance.now) {
+                    return window.performance.now();
+                }
+
+                return new Date().getTime();
+            },
+            enumerable: true,
+            configurable: true
+        });
         Tools.BaseUrl = "";
 
         Tools.GetExponantOfTwo = function (value, max) {
@@ -2842,6 +2948,15 @@ var BABYLON;
         Tools.Warn = Tools._WarnEnabled;
 
         Tools.Error = Tools._ErrorEnabled;
+
+        Tools._PerformanceNoneLogLevel = 0;
+        Tools._PerformanceUserMarkLogLevel = 1;
+        Tools._PerformanceConsoleLogLevel = 2;
+
+        Tools._performance = window.performance;
+
+        Tools.StartPerformanceCounter = Tools._StartPerformanceCounterDisabled;
+        Tools.EndPerformanceCounter = Tools._EndPerformanceCounterDisabled;
         return Tools;
     })();
     BABYLON.Tools = Tools;
@@ -4090,7 +4205,7 @@ var BABYLON;
                 else
                     callback(buffer);
             } else if (isDDS) {
-                var callback = function (data) {
+                callback = function (data) {
                     var info = BABYLON.Internals.DDSTools.GetDDSInfo(data);
 
                     var loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && !noMipmap && ((info.width >> (info.mipmapCount - 1)) == 1);
@@ -4996,6 +5111,10 @@ var BABYLON;
             return BoundingBox.IsInFrustum(this.vectorsWorld, frustumPlanes);
         };
 
+        BoundingBox.prototype.isCompletelyInFrustum = function (frustumPlanes) {
+            return BoundingBox.IsCompletelyInFrustum(this.vectorsWorld, frustumPlanes);
+        };
+
         BoundingBox.prototype.intersectsPoint = function (point) {
             var delta = BABYLON.Engine.Epsilon;
 
@@ -5048,6 +5167,17 @@ var BABYLON;
             return (num <= (sphereRadius * sphereRadius));
         };
 
+        BoundingBox.IsCompletelyInFrustum = function (boundingVectors, frustumPlanes) {
+            for (var p = 0; p < 6; p++) {
+                for (var i = 0; i < 8; i++) {
+                    if (frustumPlanes[p].dotCoordinate(boundingVectors[i]) < 0) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        };
+
         BoundingBox.IsInFrustum = function (boundingVectors, frustumPlanes) {
             for (var p = 0; p < 6; p++) {
                 var inCount = 8;
@@ -5115,6 +5245,10 @@ var BABYLON;
             return this.boundingBox.isInFrustum(frustumPlanes);
         };
 
+        BoundingInfo.prototype.isCompletelyInFrustum = function (frustumPlanes) {
+            return this.boundingBox.isCompletelyInFrustum(frustumPlanes);
+        };
+
         BoundingInfo.prototype._checkCollision = function (collider) {
             return collider._canDoCollision(this.boundingSphere.centerWorld, this.boundingSphere.radiusWorld, this.boundingBox.minimumWorld, this.boundingBox.maximumWorld);
         };
@@ -7667,6 +7801,7 @@ var BABYLON;
             this.fogStart = 0;
             this.fogEnd = 1000.0;
            
+            this.shadowsEnabled = true;
             this.lightsEnabled = true;
             this.lights = new Array();
            
@@ -7692,6 +7827,7 @@ var BABYLON;
            
             this.skeletons = new Array();
            
+            this.lensFlaresEnabled = true;
             this.lensFlareSystems = new Array();
            
             this.collisionsEnabled = true;
@@ -8082,11 +8218,11 @@ var BABYLON;
 
         Scene.prototype._animate = function () {
             if (!this._animationStartDate) {
-                this._animationStartDate = new Date().getTime();
+                this._animationStartDate = BABYLON.Tools.Now;
             }
 
            
-            var now = new Date().getTime();
+            var now = BABYLON.Tools.Now;
             var delay = now - this._animationStartDate;
 
             for (var index = 0; index < this._activeAnimatables.length; index++) {
@@ -8388,8 +8524,9 @@ var BABYLON;
             }
 
            
-            var beforeParticlesDate = new Date().getTime();
+            var beforeParticlesDate = BABYLON.Tools.Now;
             if (this.particlesEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Particles", this.particleSystems.length > 0);
                 for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
                     var particleSystem = this.particleSystems[particleIndex];
 
@@ -8402,8 +8539,9 @@ var BABYLON;
                         particleSystem.animate();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Particles", this.particleSystems.length > 0);
             }
-            this._particlesDuration += new Date().getTime() - beforeParticlesDate;
+            this._particlesDuration += BABYLON.Tools.Now - beforeParticlesDate;
         };
 
         Scene.prototype._activeMesh = function (mesh) {
@@ -8450,6 +8588,8 @@ var BABYLON;
             if (!this.activeCamera)
                 throw new Error("Active camera not set");
 
+            BABYLON.Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
+
            
             engine.setViewport(this.activeCamera.viewport);
 
@@ -8462,9 +8602,11 @@ var BABYLON;
             }
 
            
-            var beforeEvaluateActiveMeshesDate = new Date().getTime();
+            var beforeEvaluateActiveMeshesDate = BABYLON.Tools.Now;
+            BABYLON.Tools.StartPerformanceCounter("Active meshes evaluation");
             this._evaluateActiveMeshes();
-            this._evaluateActiveMeshesDuration += new Date().getTime() - beforeEvaluateActiveMeshesDate;
+            this._evaluateActiveMeshesDuration += BABYLON.Tools.Now - beforeEvaluateActiveMeshesDate;
+            BABYLON.Tools.EndPerformanceCounter("Active meshes evaluation");
 
             for (var skeletonIndex = 0; skeletonIndex < this._activeSkeletons.length; skeletonIndex++) {
                 var skeleton = this._activeSkeletons.data[skeletonIndex];
@@ -8473,8 +8615,9 @@ var BABYLON;
             }
 
            
-            var beforeRenderTargetDate = new Date().getTime();
+            var beforeRenderTargetDate = BABYLON.Tools.Now;
             if (this.renderTargetsEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
                 for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
                     var renderTarget = this._renderTargets.data[renderIndex];
                     if (renderTarget._shouldRender()) {
@@ -8482,18 +8625,19 @@ var BABYLON;
                         renderTarget.render();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0);
                 this._renderId++;
             }
 
             if (this._renderTargets.length > 0) {
                 engine.restoreDefaultFramebuffer();
             }
-            this._renderTargetsDuration += new Date().getTime() - beforeRenderTargetDate;
+            this._renderTargetsDuration += BABYLON.Tools.Now - beforeRenderTargetDate;
 
            
             this.postProcessManager._prepareFrame();
 
-            var beforeRenderDate = new Date().getTime();
+            var beforeRenderDate = BABYLON.Tools.Now;
 
            
             if (this.layers.length) {
@@ -8510,13 +8654,20 @@ var BABYLON;
             }
 
            
+            BABYLON.Tools.StartPerformanceCounter("Main render");
             this._renderingManager.render(null, null, true, true);
+            BABYLON.Tools.EndPerformanceCounter("Main render");
 
            
             this._boundingBoxRenderer.render();
 
-            for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
-                this.lensFlareSystems[lensFlareSystemIndex].render();
+           
+            if (this.lensFlaresEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
+                for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
+                    this.lensFlareSystems[lensFlareSystemIndex].render();
+                }
+                BABYLON.Tools.EndPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
             }
 
            
@@ -8531,7 +8682,7 @@ var BABYLON;
                 engine.setDepthBuffer(true);
             }
 
-            this._renderDuration += new Date().getTime() - beforeRenderDate;
+            this._renderDuration += BABYLON.Tools.Now - beforeRenderDate;
 
            
             this.postProcessManager._finalizeFrame(camera.isIntermediate);
@@ -8545,6 +8696,8 @@ var BABYLON;
             if (this.afterCameraRender) {
                 this.afterCameraRender(this.activeCamera);
             }
+
+            BABYLON.Tools.EndPerformanceCounter("Rendering camera " + this.activeCamera.name);
         };
 
         Scene.prototype._processSubCameras = function (camera) {
@@ -8595,7 +8748,7 @@ var BABYLON;
         };
 
         Scene.prototype.render = function () {
-            var startDate = new Date().getTime();
+            var startDate = BABYLON.Tools.Now;
             this._particlesDuration = 0;
             this._spritesDuration = 0;
             this._activeParticles = 0;
@@ -8605,6 +8758,8 @@ var BABYLON;
             this._activeVertices = 0;
             this._meshesForIntersections.reset();
 
+            BABYLON.Tools.StartPerformanceCounter("Scene rendering");
+
            
             if (this.actionManager) {
                 this.actionManager.processTrigger(BABYLON.ActionManager.OnEveryFrameTrigger, null);
@@ -8626,13 +8781,16 @@ var BABYLON;
 
            
             if (this._physicsEngine) {
+                BABYLON.Tools.StartPerformanceCounter("Physics");
                 this._physicsEngine._runOneStep(deltaTime / 1000.0);
+                BABYLON.Tools.EndPerformanceCounter("Physics");
             }
 
            
-            var beforeRenderTargetDate = new Date().getTime();
+            var beforeRenderTargetDate = BABYLON.Tools.Now;
             var engine = this.getEngine();
             if (this.renderTargetsEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
                 for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
                     var renderTarget = this.customRenderTargets[customIndex];
                     if (renderTarget._shouldRender()) {
@@ -8652,33 +8810,40 @@ var BABYLON;
                         renderTarget.render();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
+
                 this._renderId++;
             }
 
             if (this.customRenderTargets.length > 0) {
                 engine.restoreDefaultFramebuffer();
             }
-            this._renderTargetsDuration += new Date().getTime() - beforeRenderTargetDate;
+            this._renderTargetsDuration += BABYLON.Tools.Now - beforeRenderTargetDate;
 
            
             if (this.proceduralTexturesEnabled) {
+                BABYLON.Tools.StartPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
                 for (var proceduralIndex = 0; proceduralIndex < this._proceduralTextures.length; proceduralIndex++) {
                     var proceduralTexture = this._proceduralTextures[proceduralIndex];
                     if (proceduralTexture._shouldRender()) {
                         proceduralTexture.render();
                     }
                 }
+                BABYLON.Tools.EndPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
             }
 
            
             this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe, true);
 
-            for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
-                var light = this.lights[lightIndex];
-                var shadowGenerator = light.getShadowGenerator();
+           
+            if (this.shadowsEnabled) {
+                for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
+                    var light = this.lights[lightIndex];
+                    var shadowGenerator = light.getShadowGenerator();
 
-                if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
-                    this._renderTargets.push(shadowGenerator.getShadowMap());
+                    if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
+                        this._renderTargets.push(shadowGenerator.getShadowMap());
+                    }
                 }
             }
 
@@ -8715,7 +8880,8 @@ var BABYLON;
 
             this._toBeDisposed.reset();
 
-            this._lastFrameDuration = new Date().getTime() - startDate;
+            BABYLON.Tools.EndPerformanceCounter("Scene rendering");
+            this._lastFrameDuration = BABYLON.Tools.Now - startDate;
         };
 
         Scene.prototype.dispose = function () {
@@ -9699,6 +9865,20 @@ var BABYLON;
             return true;
         };
 
+        AbstractMesh.prototype.isCompletelyInFrustum = function (camera) {
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+
+            var transformMatrix = camera.getViewMatrix().multiply(camera.getProjectionMatrix());
+
+            if (!this._boundingInfo.isCompletelyInFrustum(BABYLON.Frustum.GetPlanes(transformMatrix))) {
+                return false;
+            }
+
+            return true;
+        };
+
         AbstractMesh.prototype.intersectsMesh = function (mesh, precise) {
             if (!this._boundingInfo || !mesh._boundingInfo) {
                 return false;
@@ -11551,6 +11731,29 @@ var BABYLON;
             return { width: this._texture._baseWidth, height: this._texture._baseHeight };
         };
 
+        BaseTexture.prototype.scale = function (ratio) {
+        };
+
+        Object.defineProperty(BaseTexture.prototype, "canRescale", {
+            get: function () {
+                return false;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        BaseTexture.prototype._removeFromCache = function (url, noMipmap) {
+            var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
+            for (var index = 0; index < texturesCache.length; index++) {
+                var texturesCacheEntry = texturesCache[index];
+
+                if (texturesCacheEntry.url === url && texturesCacheEntry.noMipmap === noMipmap) {
+                    texturesCache.splice(index, 1);
+                    return;
+                }
+            }
+        };
+
         BaseTexture.prototype._getFromCache = function (url, noMipmap) {
             var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
             for (var index = 0; index < texturesCache.length; index++) {
@@ -11729,7 +11932,7 @@ var BABYLON;
             }
 
            
-            var beforeParticlesDate = new Date().getTime();
+            var beforeParticlesDate = BABYLON.Tools.Now;
             for (var particleIndex = 0; particleIndex < this._scene._activeParticleSystems.length; particleIndex++) {
                 var particleSystem = this._scene._activeParticleSystems.data[particleIndex];
 
@@ -11743,7 +11946,7 @@ var BABYLON;
                     this._scene._activeParticles += particleSystem.render();
                 }
             }
-            this._scene._particlesDuration += new Date().getTime() - beforeParticlesDate;
+            this._scene._particlesDuration += BABYLON.Tools.Now - beforeParticlesDate;
         };
 
         RenderingManager.prototype._renderSprites = function (index) {
@@ -11752,7 +11955,7 @@ var BABYLON;
             }
 
            
-            var beforeSpritessDate = new Date().getTime();
+            var beforeSpritessDate = BABYLON.Tools.Now;
             for (var id = 0; id < this._scene.spriteManagers.length; id++) {
                 var spriteManager = this._scene.spriteManagers[id];
 
@@ -11761,7 +11964,7 @@ var BABYLON;
                     spriteManager.render();
                 }
             }
-            this._scene._spritesDuration += new Date().getTime() - beforeSpritessDate;
+            this._scene._spritesDuration += BABYLON.Tools.Now - beforeSpritessDate;
         };
 
         RenderingManager.prototype._clearDepthBuffer = function () {
@@ -12171,6 +12374,20 @@ var BABYLON;
             return this._size;
         };
 
+        Object.defineProperty(RenderTargetTexture.prototype, "canRescale", {
+            get: function () {
+                return true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        RenderTargetTexture.prototype.scale = function (ratio) {
+            var newSize = this._size * ratio;
+
+            this.resize(newSize, this._generateMipMaps);
+        };
+
         RenderTargetTexture.prototype.resize = function (size, generateMipMaps) {
             this.releaseInternalTexture();
             this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
@@ -12884,6 +13101,28 @@ var BABYLON;
             this._canvas.height = textureSize.height;
             this._context = this._canvas.getContext("2d");
         }
+        Object.defineProperty(DynamicTexture.prototype, "canRescale", {
+            get: function () {
+                return true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        DynamicTexture.prototype.scale = function (ratio) {
+            var textureSize = this.getSize();
+
+            textureSize.width *= ratio;
+            textureSize.height *= ratio;
+
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+
+            this.releaseInternalTexture();
+
+            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
+        };
+
         DynamicTexture.prototype.getContext = function () {
             return this._context;
         };
@@ -12974,7 +13213,7 @@ var BABYLON;
                 _this.video.appendChild(source);
             });
 
-            this._lastUpdate = new Date().getTime();
+            this._lastUpdate = BABYLON.Tools.Now;
         }
         VideoTexture.prototype.update = function () {
             if (this._autoLaunch) {
@@ -12982,7 +13221,7 @@ var BABYLON;
                 this.video.play();
             }
 
-            var now = new Date().getTime();
+            var now = BABYLON.Tools.Now;
 
             if (now - this._lastUpdate < 15) {
                 return false;
@@ -13550,6 +13789,7 @@ var BABYLON;
             this.emissiveColor = new BABYLON.Color3(0, 0, 0);
             this.useAlphaFromDiffuseTexture = false;
             this.useSpecularOverAlpha = true;
+            this.fogEnabled = true;
             this._cachedDefines = null;
             this._renderTargets = new BABYLON.SmartArray(16);
             this._worldViewProjectionMatrix = BABYLON.Matrix.Zero();
@@ -13688,7 +13928,7 @@ var BABYLON;
             }
 
            
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) {
+            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
                 defines.push("#define FOG");
                 fallbacks.addFallback(1, "FOG");
             }
@@ -13754,27 +13994,29 @@ var BABYLON;
                     }
 
                    
-                    var shadowGenerator = light.getShadowGenerator();
-                    if (mesh && mesh.receiveShadows && shadowGenerator) {
-                        defines.push("#define SHADOW" + lightIndex);
-                        fallbacks.addFallback(0, "SHADOW" + lightIndex);
-
-                        if (!shadowsActivated) {
-                            defines.push("#define SHADOWS");
-                            shadowsActivated = true;
-                        }
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh && mesh.receiveShadows && shadowGenerator) {
+                            defines.push("#define SHADOW" + lightIndex);
+                            fallbacks.addFallback(0, "SHADOW" + lightIndex);
+
+                            if (!shadowsActivated) {
+                                defines.push("#define SHADOWS");
+                                shadowsActivated = true;
+                            }
 
-                        if (shadowGenerator.useVarianceShadowMap) {
-                            defines.push("#define SHADOWVSM" + lightIndex);
-                            if (lightIndex > 0) {
-                                fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                            if (shadowGenerator.useVarianceShadowMap) {
+                                defines.push("#define SHADOWVSM" + lightIndex);
+                                if (lightIndex > 0) {
+                                    fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                                }
                             }
-                        }
 
-                        if (shadowGenerator.usePoissonSampling) {
-                            defines.push("#define SHADOWPCF" + lightIndex);
-                            if (lightIndex > 0) {
-                                fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                            if (shadowGenerator.usePoissonSampling) {
+                                defines.push("#define SHADOWPCF" + lightIndex);
+                                if (lightIndex > 0) {
+                                    fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                                }
                             }
                         }
                     }
@@ -14026,11 +14268,13 @@ var BABYLON;
                     this._effect.setColor3("vLightSpecular" + lightIndex, this._scaledSpecular);
 
                    
-                    var shadowGenerator = light.getShadowGenerator();
-                    if (mesh.receiveShadows && shadowGenerator) {
-                        this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
-                        this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
-                        this._effect.setFloat("darkness" + lightIndex, shadowGenerator.getDarkness());
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh.receiveShadows && shadowGenerator) {
+                            this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
+                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
+                            this._effect.setFloat("darkness" + lightIndex, shadowGenerator.getDarkness());
+                        }
                     }
 
                     lightIndex++;
@@ -26663,3 +26907,273 @@ var BABYLON;
     })(BABYLON.OculusCamera);
     BABYLON.WebVRCamera = WebVRCamera;
 })(BABYLON || (BABYLON = {}));
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+   
+    var SceneOptimization = (function () {
+        function SceneOptimization(priority) {
+            if (typeof priority === "undefined") { priority = 0; }
+            this.priority = priority;
+            this.apply = function (scene) {
+                return true;
+            };
+        }
+        return SceneOptimization;
+    })();
+    BABYLON.SceneOptimization = SceneOptimization;
+
+    var TextureSceneOptimization = (function (_super) {
+        __extends(TextureSceneOptimization, _super);
+        function TextureSceneOptimization(maximumSize, priority) {
+            if (typeof maximumSize === "undefined") { maximumSize = 1024; }
+            if (typeof priority === "undefined") { priority = 0; }
+            var _this = this;
+            _super.call(this, priority);
+            this.maximumSize = maximumSize;
+            this.priority = priority;
+            this.apply = function (scene) {
+                var allDone = true;
+                for (var index = 0; index < scene.textures.length; index++) {
+                    var texture = scene.textures[index];
+
+                    if (!texture.canRescale) {
+                        continue;
+                    }
+
+                    var currentSize = texture.getSize();
+                    var maxDimension = Math.max(currentSize.width, currentSize.height);
+
+                    if (maxDimension > _this.maximumSize) {
+                        texture.scale(0.5);
+                        allDone = false;
+                    }
+                }
+
+                return allDone;
+            };
+        }
+        return TextureSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.TextureSceneOptimization = TextureSceneOptimization;
+
+    var HardwareScalingSceneOptimization = (function (_super) {
+        __extends(HardwareScalingSceneOptimization, _super);
+        function HardwareScalingSceneOptimization(maximumScale, priority) {
+            if (typeof maximumScale === "undefined") { maximumScale = 2; }
+            if (typeof priority === "undefined") { priority = 0; }
+            var _this = this;
+            _super.call(this, priority);
+            this.maximumScale = maximumScale;
+            this.priority = priority;
+            this._currentScale = 1;
+            this.apply = function (scene) {
+                _this._currentScale++;
+
+                scene.getEngine().setHardwareScalingLevel(_this._currentScale);
+
+                return _this._currentScale >= _this.maximumScale;
+            };
+        }
+        return HardwareScalingSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.HardwareScalingSceneOptimization = HardwareScalingSceneOptimization;
+
+    var ShadowsSceneOptimization = (function (_super) {
+        __extends(ShadowsSceneOptimization, _super);
+        function ShadowsSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.shadowsEnabled = false;
+                return true;
+            };
+        }
+        return ShadowsSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.ShadowsSceneOptimization = ShadowsSceneOptimization;
+
+    var PostProcessesSceneOptimization = (function (_super) {
+        __extends(PostProcessesSceneOptimization, _super);
+        function PostProcessesSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.postProcessesEnabled = false;
+                return true;
+            };
+        }
+        return PostProcessesSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.PostProcessesSceneOptimization = PostProcessesSceneOptimization;
+
+    var LensFlaresSceneOptimization = (function (_super) {
+        __extends(LensFlaresSceneOptimization, _super);
+        function LensFlaresSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.lensFlaresEnabled = false;
+                return true;
+            };
+        }
+        return LensFlaresSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.LensFlaresSceneOptimization = LensFlaresSceneOptimization;
+
+    var ParticlesSceneOptimization = (function (_super) {
+        __extends(ParticlesSceneOptimization, _super);
+        function ParticlesSceneOptimization() {
+            _super.apply(this, arguments);
+            this.apply = function (scene) {
+                scene.particlesEnabled = false;
+                return true;
+            };
+        }
+        return ParticlesSceneOptimization;
+    })(SceneOptimization);
+    BABYLON.ParticlesSceneOptimization = ParticlesSceneOptimization;
+
+   
+    var SceneOptimizerOptions = (function () {
+        function SceneOptimizerOptions(targetFrameRate, trackerDuration) {
+            if (typeof targetFrameRate === "undefined") { targetFrameRate = 60; }
+            if (typeof trackerDuration === "undefined") { trackerDuration = 2000; }
+            this.targetFrameRate = targetFrameRate;
+            this.trackerDuration = trackerDuration;
+            this.optimizations = new Array();
+        }
+        SceneOptimizerOptions.LowDegradationAllowed = function (targetFrameRate) {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+           
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+           
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 1024));
+
+            return result;
+        };
+
+        SceneOptimizerOptions.ModerateDegradationAllowed = function (targetFrameRate) {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+           
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+           
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 512));
+
+           
+            priority++;
+            result.optimizations.push(new HardwareScalingSceneOptimization(priority, 2));
+
+            return result;
+        };
+
+        SceneOptimizerOptions.HighDegradationAllowed = function (targetFrameRate) {
+            var result = new SceneOptimizerOptions(targetFrameRate);
+
+            var priority = 0;
+            result.optimizations.push(new ShadowsSceneOptimization(priority));
+            result.optimizations.push(new LensFlaresSceneOptimization(priority));
+
+           
+            priority++;
+            result.optimizations.push(new PostProcessesSceneOptimization(priority));
+            result.optimizations.push(new ParticlesSceneOptimization(priority));
+
+           
+            priority++;
+            result.optimizations.push(new TextureSceneOptimization(priority, 256));
+
+           
+            priority++;
+            result.optimizations.push(new HardwareScalingSceneOptimization(priority, 4));
+
+            return result;
+        };
+        return SceneOptimizerOptions;
+    })();
+    BABYLON.SceneOptimizerOptions = SceneOptimizerOptions;
+
+   
+    var SceneOptimizer = (function () {
+        function SceneOptimizer() {
+        }
+        SceneOptimizer._CheckCurrentState = function (scene, options, currentPriorityLevel, onSuccess, onFailure) {
+           
+            if (BABYLON.Tools.GetFps() >= options.targetFrameRate) {
+                if (onSuccess) {
+                    onSuccess();
+                }
+
+                return;
+            }
+
+           
+            var allDone = true;
+            var noOptimizationApplied = true;
+            for (var index = 0; index < options.optimizations.length; index++) {
+                var optimization = options.optimizations[index];
+
+                if (optimization.priority === currentPriorityLevel) {
+                    noOptimizationApplied = false;
+                    allDone = allDone && optimization.apply(scene);
+                }
+            }
+
+           
+            if (noOptimizationApplied) {
+                if (onFailure) {
+                    onFailure();
+                }
+
+                return;
+            }
+
+           
+            if (allDone) {
+                currentPriorityLevel++;
+            }
+
+           
+            scene.executeWhenReady(function () {
+                setTimeout(function () {
+                    SceneOptimizer._CheckCurrentState(scene, options, currentPriorityLevel, onSuccess, onFailure);
+                }, options.trackerDuration);
+            });
+        };
+
+        SceneOptimizer.OptimizeAsync = function (scene, options, onSuccess, onFailure) {
+            if (!options) {
+                options = SceneOptimizerOptions.ModerateDegradationAllowed();
+            }
+
+           
+            scene.executeWhenReady(function () {
+                setTimeout(function () {
+                    SceneOptimizer._CheckCurrentState(scene, options, 0, onSuccess, onFailure);
+                }, options.trackerDuration);
+            });
+        };
+        return SceneOptimizer;
+    })();
+    BABYLON.SceneOptimizer = SceneOptimizer;
+})(BABYLON || (BABYLON = {}));

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 16 - 16
babylon.2.0-alpha.js


+ 78 - 2
babylon.2.0.d.ts

@@ -342,6 +342,7 @@ declare module BABYLON {
         public fogDensity: number;
         public fogStart: number;
         public fogEnd: number;
+        public shadowsEnabled: boolean;
         public lightsEnabled: boolean;
         public lights: Light[];
         public cameras: Camera[];
@@ -359,6 +360,7 @@ declare module BABYLON {
         public spriteManagers: SpriteManager[];
         public layers: Layer[];
         public skeletons: Skeleton[];
+        public lensFlaresEnabled: boolean;
         public lensFlareSystems: LensFlareSystem[];
         public collisionsEnabled: boolean;
         public gravity: Vector3;
@@ -1215,11 +1217,13 @@ declare module BABYLON {
         public getWorldMatrix(): Matrix;
         public _update(world: Matrix): void;
         public isInFrustum(frustumPlanes: Plane[]): boolean;
+        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
         public intersectsPoint(point: Vector3): boolean;
         public intersectsSphere(sphere: BoundingSphere): boolean;
         public intersectsMinMax(min: Vector3, max: Vector3): boolean;
         static Intersects(box0: BoundingBox, box1: BoundingBox): boolean;
         static IntersectsSphere(minPoint: Vector3, maxPoint: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean;
+        static IsCompletelyInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean;
         static IsInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean;
     }
 }
@@ -1232,6 +1236,7 @@ declare module BABYLON {
         constructor(minimum: Vector3, maximum: Vector3);
         public _update(world: Matrix): void;
         public isInFrustum(frustumPlanes: Plane[]): boolean;
+        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
         public _checkCollision(collider: Collider): boolean;
         public intersectsPoint(point: Vector3): boolean;
         public intersects(boundingInfo: BoundingInfo, precise: boolean): boolean;
@@ -1648,6 +1653,7 @@ declare module BABYLON {
         public emissiveColor: Color3;
         public useAlphaFromDiffuseTexture: boolean;
         public useSpecularOverAlpha: boolean;
+        public fogEnabled: boolean;
         public diffuseFresnelParameters: FresnelParameters;
         public opacityFresnelParameters: FresnelParameters;
         public reflectionFresnelParameters: FresnelParameters;
@@ -1707,6 +1713,9 @@ declare module BABYLON {
         public isReady(): boolean;
         public getSize(): ISize;
         public getBaseSize(): ISize;
+        public scale(ratio: number): void;
+        public canRescale : boolean;
+        public _removeFromCache(url: string, noMipmap: boolean): void;
         public _getFromCache(url: string, noMipmap: boolean): WebGLTexture;
         public delayLoad(): void;
         public releaseInternalTexture(): void;
@@ -1733,6 +1742,8 @@ declare module BABYLON {
         private _canvas;
         private _context;
         constructor(name: string, options: any, scene: Scene, generateMipMaps: boolean, samplingMode?: number);
+        public canRescale : boolean;
+        public scale(ratio: number): void;
         public getContext(): CanvasRenderingContext2D;
         public update(invertY?: boolean): void;
         public drawText(text: string, x: number, y: number, font: string, color: string, clearColor: string, invertY?: boolean): void;
@@ -1815,7 +1826,9 @@ declare module BABYLON {
         public refreshRate : number;
         public _shouldRender(): boolean;
         public getRenderSize(): number;
-        public resize(size: any, generateMipMaps: any): void;
+        public canRescale : boolean;
+        public scale(ratio: number): void;
+        public resize(size: any, generateMipMaps?: boolean): void;
         public render(useCameraPostProcess?: boolean): void;
         public clone(): RenderTargetTexture;
     }
@@ -1858,7 +1871,7 @@ declare module BABYLON {
         private _cachedVAng;
         private _cachedWAng;
         private _cachedCoordinatesMode;
-        private _samplingMode;
+        public _samplingMode: number;
         private _buffer;
         private _deleteBuffer;
         constructor(url: string, scene: Scene, noMipmap?: boolean, invertY?: boolean, samplingMode?: number, onLoad?: () => void, onError?: () => void, buffer?: any, deleteBuffer?: boolean);
@@ -2356,6 +2369,7 @@ declare module BABYLON {
         public locallyTranslate(vector3: Vector3): void;
         public lookAt(targetPoint: Vector3, yawCor: number, pitchCor: number, rollCor: number): void;
         public isInFrustum(frustumPlanes: Plane[]): boolean;
+        public isCompletelyInFrustum(camera?: Camera): boolean;
         public intersectsMesh(mesh: AbstractMesh, precise?: boolean): boolean;
         public intersectsPoint(point: Vector3): boolean;
         public setPhysicsState(impostor?: any, options?: PhysicsBodyCreationOptions): void;
@@ -3581,6 +3595,51 @@ interface Navigator {
     webkitGamepads(func?: any): any;
 }
 declare module BABYLON {
+    class SceneOptimization {
+        public priority: number;
+        public apply: (scene: Scene) => boolean;
+        constructor(priority?: number);
+    }
+    class TextureSceneOptimization extends SceneOptimization {
+        public maximumSize: number;
+        public priority: number;
+        constructor(maximumSize?: number, priority?: number);
+        public apply: (scene: Scene) => boolean;
+    }
+    class HardwareScalingSceneOptimization extends SceneOptimization {
+        public maximumScale: number;
+        public priority: number;
+        private _currentScale;
+        constructor(maximumScale?: number, priority?: number);
+        public apply: (scene: Scene) => boolean;
+    }
+    class ShadowsSceneOptimization extends SceneOptimization {
+        public apply: (scene: Scene) => boolean;
+    }
+    class PostProcessesSceneOptimization extends SceneOptimization {
+        public apply: (scene: Scene) => boolean;
+    }
+    class LensFlaresSceneOptimization extends SceneOptimization {
+        public apply: (scene: Scene) => boolean;
+    }
+    class ParticlesSceneOptimization extends SceneOptimization {
+        public apply: (scene: Scene) => boolean;
+    }
+    class SceneOptimizerOptions {
+        public targetFrameRate: number;
+        public trackerDuration: number;
+        public optimizations: SceneOptimization[];
+        constructor(targetFrameRate?: number, trackerDuration?: number);
+        static LowDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions;
+        static ModerateDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions;
+        static HighDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions;
+    }
+    class SceneOptimizer {
+        static _CheckCurrentState(scene: Scene, options: SceneOptimizerOptions, currentPriorityLevel: number, onSuccess?: () => void, onFailure?: () => void): void;
+        static OptimizeAsync(scene: Scene, options?: SceneOptimizerOptions, onSuccess?: () => void, onFailure?: () => void): void;
+    }
+}
+declare module BABYLON {
     class SceneSerializer {
         static Serialize(scene: Scene): any;
     }
@@ -3685,6 +3744,23 @@ declare module BABYLON {
         private static _ErrorDisabled(message);
         private static _ErrorEnabled(message);
         static LogLevels : number;
+        private static _PerformanceNoneLogLevel;
+        private static _PerformanceUserMarkLogLevel;
+        private static _PerformanceConsoleLogLevel;
+        private static _performance;
+        static PerformanceNoneLogLevel : number;
+        static PerformanceUserMarkLogLevel : number;
+        static PerformanceConsoleLogLevel : number;
+        static PerformanceLogLevel : number;
+        static _StartPerformanceCounterDisabled(counterName: string, condition?: boolean): void;
+        static _EndPerformanceCounterDisabled(counterName: string, condition?: boolean): void;
+        static _StartUserMark(counterName: string, condition?: boolean): void;
+        static _EndUserMark(counterName: string, condition?: boolean): void;
+        static _StartPerformanceConsole(counterName: string, condition?: boolean): void;
+        static _EndPerformanceConsole(counterName: string, condition?: boolean): void;
+        static StartPerformanceCounter: (counterName: string, condition?: boolean) => void;
+        static EndPerformanceCounter: (counterName: string, condition?: boolean) => void;
+        static Now : number;
     }
 }
 declare module BABYLON.Internals {