Browse Source

merge + material fixes

Simon Ferquel 10 years ago
parent
commit
5a74ef1e06
71 changed files with 7633 additions and 1582 deletions
  1. 2 1
      Babylon/Actions/babylon.actionManager.ts
  2. 63 6
      Babylon/Animations/babylon.animation.ts
  3. 270 0
      Babylon/Animations/babylon.easing.js
  4. 188 0
      Babylon/Animations/babylon.easing.ts
  5. 43 0
      Babylon/Audio/babylon.audioengine.js
  6. 46 0
      Babylon/Audio/babylon.audioengine.ts
  7. 216 0
      Babylon/Audio/babylon.sound.js
  8. 203 0
      Babylon/Audio/babylon.sound.ts
  9. 60 0
      Babylon/Audio/babylon.soundtrack.js
  10. 59 0
      Babylon/Audio/babylon.soundtrack.ts
  11. 49 0
      Babylon/Debug/babylon.debugLayer.d.ts
  12. 665 0
      Babylon/Debug/babylon.debugLayer.js
  13. 1 0
      Babylon/Debug/babylon.debugLayer.js.map
  14. 658 0
      Babylon/Debug/babylon.debugLayer.ts
  15. 3 2
      Babylon/Lights/Shadows/babylon.shadowGenerator.ts
  16. 8 0
      Babylon/Loading/Plugins/babylon.babylonFileLoader.ts
  17. 9 9
      Babylon/Loading/babylon.sceneLoader.ts
  18. 20 21
      Babylon/Materials/babylon.effect.ts
  19. 6 0
      Babylon/Materials/babylon.material.ts
  20. 82 53
      Babylon/Materials/babylon.shaderMaterial.ts
  21. 163 139
      Babylon/Materials/babylon.standardMaterial.ts
  22. 71 59
      Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.ts
  23. 48 10
      Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.ts
  24. 157 118
      Babylon/Materials/textures/Procedurals/babylon.standardProceduralTexture.ts
  25. 7 7
      Babylon/Materials/textures/babylon.baseTexture.ts
  26. 0 226
      Babylon/Materials/textures/babylon.proceduralTexture.js
  27. 1 1
      Babylon/Materials/textures/babylon.renderTargetTexture.ts
  28. 2 0
      Babylon/Materials/textures/babylon.texture.ts
  29. 58 0
      Babylon/Math/babylon.math.ts
  30. 13 2
      Babylon/Mesh/babylon.InstancedMesh.ts
  31. 51 7
      Babylon/Mesh/babylon.abstractMesh.ts
  32. 13 8
      Babylon/Mesh/babylon.geometry.ts
  33. 47 38
      Babylon/Mesh/babylon.mesh.ts
  34. 1 0
      Babylon/Mesh/babylon.subMesh.ts
  35. 2 2
      Babylon/Mesh/babylon.vertexBuffer.ts
  36. 30 29
      Babylon/Particles/babylon.particleSystem.ts
  37. 10 8
      Babylon/Rendering/babylon.boundingBoxRenderer.ts
  38. 5 6
      Babylon/Rendering/babylon.outlineRenderer.ts
  39. 12 7
      Babylon/Rendering/babylon.renderingGroup.ts
  40. 2 3
      Babylon/Rendering/babylon.renderingManager.ts
  41. 8 19
      Babylon/Shaders/brick.fragment.fx
  42. 2 2
      Babylon/Shaders/default.fragment.fx
  43. 7 6
      Babylon/Shaders/fire.fragment.fx
  44. 9 14
      Babylon/Shaders/grass.fragment.fx
  45. 11 28
      Babylon/Shaders/marble.fragment.fx
  46. 2 2
      Babylon/Shaders/outline.fragment.fx
  47. 3 8
      Babylon/Shaders/road.fragment.fx
  48. 0 3
      Babylon/Shaders/wood.fragment.fx
  49. 2 2
      Babylon/Sprites/babylon.spriteManager.ts
  50. 39 5
      Babylon/Tools/babylon.tools.ts
  51. 39 11
      Babylon/babylon.engine.ts
  52. 156 49
      Babylon/babylon.scene.ts
  53. 6 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs
  54. BIN
      Exporters/3ds Max/Max2Babylon-0.8.3.zip
  55. BIN
      Exporters/3ds Max/Max2Babylon-0.8.5.zip
  56. 9 1
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Animation.cs
  57. 19 15
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Camera.cs
  58. 76 63
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  59. 8 17
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs
  60. 23 10
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs
  61. 34 5
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs
  62. 3 0
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.cs
  63. 52 0
      Exporters/3ds Max/Max2Babylon/Tools/Tools.cs
  64. 21 1
      Exporters/3ds Max/Max2Babylon/Tools/WebServer.cs
  65. 18 64
      Exporters/Blender/io_export_babylon.py
  66. 1144 0
      References/waa.d.ts
  67. 4 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml
  68. 4 0
      Tools/Gulp/gulpfile.js
  69. 2251 446
      babylon.2.0-alpha.debug.js
  70. 19 17
      babylon.2.0-alpha.js
  71. 320 32
      babylon.2.0.d.ts

+ 2 - 1
Babylon/Actions/babylon.actionManager.ts

@@ -159,7 +159,8 @@
                 var action = this.actions[index];
 
                 if (action.trigger === trigger) {
-                    if (trigger == ActionManager.OnKeyUpTrigger || trigger == ActionManager.OnKeyDownTrigger) {
+                    if (trigger === ActionManager.OnKeyUpTrigger
+                        || trigger === ActionManager.OnKeyDownTrigger) {
                         var parameter = action.getTriggerParameter();
 
                         if (parameter) {

+ 63 - 6
Babylon/Animations/babylon.animation.ts

@@ -5,10 +5,47 @@
         private _highLimitsCache = {};
         private _stopped = false;
         public _target;
+        private _easingFunction: BABYLON.IEasingFunction;
 
         public targetPropertyPath: string[];
         public currentFrame: number;
 
+        public static CreateAndStartAnimation(name: string, mesh: BABYLON.AbstractMesh, tartgetProperty: string,
+            framePerSecond: number, totalFrame: number,
+            from: any, to: any, loopMode?: number) {
+
+            var dataType = undefined;
+
+            if (!isNaN(parseFloat(from)) && isFinite(from)) {
+                dataType = Animation.ANIMATIONTYPE_FLOAT;
+            } else if (from instanceof BABYLON.Quaternion) {
+                dataType = Animation.ANIMATIONTYPE_QUATERNION;
+            } else if (from instanceof BABYLON.Vector3) {
+                dataType = Animation.ANIMATIONTYPE_VECTOR3;
+            } else if (from instanceof BABYLON.Vector2) {
+                dataType = Animation.ANIMATIONTYPE_VECTOR2;
+            } else if (from instanceof BABYLON.Color3) {
+                dataType = Animation.ANIMATIONTYPE_COLOR3;
+            }
+
+            if (dataType == undefined) {
+                return;
+            }
+
+            var animation = new Animation(name, tartgetProperty, framePerSecond, dataType, loopMode);
+
+            var keys = [];
+            keys.push({ frame: 0, value: from });
+            keys.push({ frame: totalFrame, value: to });
+            animation.setKeys(keys);
+
+            mesh.animations.push(animation);
+
+            mesh.getScene().beginAnimation(mesh, 0, totalFrame, (animation.loopMode == 1));
+
+        }
+
+
         constructor(public name: string, public targetProperty: string, public framePerSecond: number, public dataType: number, public loopMode?: number) {
             this.targetPropertyPath = targetProperty.split(".");
             this.dataType = dataType;
@@ -24,6 +61,14 @@
             return this._keys;
         }
 
+        public getEasingFunction() {
+            return this._easingFunction;
+        }
+
+        public setEasingFunction(easingFunction: BABYLON.EasingFunction) {
+            this._easingFunction = easingFunction;
+        }
+
         public floatInterpolateFunction(startValue: number, endValue: number, gradient: number): number {
             return startValue + (endValue - startValue) * gradient;
         }
@@ -58,6 +103,7 @@
             this._highLimitsCache = {};
         }
 
+
         private _interpolate(currentFrame: number, repeatCount: number, loopMode: number, offsetValue?, highLimitValue?) {
             if (loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && repeatCount > 0) {
                 return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
@@ -66,11 +112,20 @@
             this.currentFrame = currentFrame;
 
             for (var key = 0; key < this._keys.length; key++) {
+                // for each frame, we need the key just before the frame superior
                 if (this._keys[key + 1].frame >= currentFrame) {
+
                     var startValue = this._keys[key].value;
                     var endValue = this._keys[key + 1].value;
+
+                    // gradient : percent of currentFrame between the frame inf and the frame sup
                     var gradient = (currentFrame - this._keys[key].frame) / (this._keys[key + 1].frame - this._keys[key].frame);
 
+                    // check for easingFunction and correction of gradient
+                    if (this._easingFunction != null) {
+                        gradient = this._easingFunction.ease(gradient);
+                    }
+
                     switch (this.dataType) {
                         // Float
                         case Animation.ANIMATIONTYPE_FLOAT:
@@ -140,20 +195,17 @@
             return this._keys[this._keys.length - 1].value;
         }
 
+
         public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number): boolean {
             if (!this.targetPropertyPath || this.targetPropertyPath.length < 1) {
                 this._stopped = true;
                 return false;
             }
-
             var returnValue = true;
+
             // Adding a start key at frame 0 if missing
             if (this._keys[0].frame != 0) {
-                var newKey = {
-                    frame: 0,
-                    value: this._keys[0].value
-                };
-
+                var newKey = { frame: 0, value: this._keys[0].value };
                 this._keys.splice(0, 0, newKey);
             }
 
@@ -168,6 +220,7 @@
             // Compute ratio
             var range = to - from;
             var offsetValue;
+            // ratio represents the frame delta between from and to
             var ratio = delay * (this.framePerSecond * speedRatio) / 1000.0;
 
             if (ratio > range && !loop) { // If we are out of range and not looping get back to caller
@@ -176,7 +229,9 @@
             } else {
                 // Get max value if required
                 var highLimitValue = 0;
+
                 if (this.loopMode != Animation.ANIMATIONLOOPMODE_CYCLE) {
+
                     var keyOffset = to.toString() + from.toString();
                     if (!this._offsetsCache[keyOffset]) {
                         var fromValue = this._interpolate(from, 0, Animation.ANIMATIONLOOPMODE_CYCLE);
@@ -264,6 +319,8 @@
             return returnValue;
         }
 
+
+
         // Statics
         private static _ANIMATIONTYPE_FLOAT = 0;
         private static _ANIMATIONTYPE_VECTOR3 = 1;

+ 270 - 0
Babylon/Animations/babylon.easing.js

@@ -0,0 +1,270 @@
+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 EasingFunction = (function () {
+        function EasingFunction() {
+            // Properties
+            this._easingMode = EasingFunction.EASINGMODE_EASEIN;
+        }
+        Object.defineProperty(EasingFunction, "EASINGMODE_EASEIN", {
+            get: function () {
+                return EasingFunction._EASINGMODE_EASEIN;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(EasingFunction, "EASINGMODE_EASEOUT", {
+            get: function () {
+                return EasingFunction._EASINGMODE_EASEOUT;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(EasingFunction, "EASINGMODE_EASEINOUT", {
+            get: function () {
+                return EasingFunction._EASINGMODE_EASEINOUT;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        EasingFunction.prototype.setEasingMode = function (easingMode) {
+            var n = Math.min(Math.max(easingMode, 0), 2);
+            this._easingMode = n;
+        };
+        EasingFunction.prototype.getEasingMode = function () {
+            return this._easingMode;
+        };
+
+        EasingFunction.prototype.easeInCore = function (gradient) {
+            throw new Error('You must implement this method');
+        };
+
+        EasingFunction.prototype.ease = function (gradient) {
+            switch (this._easingMode) {
+                case EasingFunction.EASINGMODE_EASEIN:
+                    return this.easeInCore(gradient);
+                case EasingFunction.EASINGMODE_EASEOUT:
+                    return (1 - this.easeInCore(1 - gradient));
+            }
+
+            if (gradient >= 0.5) {
+                return (((1 - this.easeInCore((1 - gradient) * 2)) * 0.5) + 0.5);
+            }
+
+            return (this.easeInCore(gradient * 2) * 0.5);
+        };
+        EasingFunction._EASINGMODE_EASEIN = 0;
+        EasingFunction._EASINGMODE_EASEOUT = 1;
+        EasingFunction._EASINGMODE_EASEINOUT = 2;
+        return EasingFunction;
+    })();
+    BABYLON.EasingFunction = EasingFunction;
+
+    var CircleEase = (function (_super) {
+        __extends(CircleEase, _super);
+        function CircleEase() {
+            _super.apply(this, arguments);
+        }
+        CircleEase.prototype.easeInCore = function (gradient) {
+            gradient = Math.max(0, Math.min(1, gradient));
+            return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
+        };
+        return CircleEase;
+    })(EasingFunction);
+    BABYLON.CircleEase = CircleEase;
+
+    var BackEase = (function (_super) {
+        __extends(BackEase, _super);
+        function BackEase(amplitude) {
+            if (typeof amplitude === "undefined") { amplitude = 1; }
+            _super.call(this);
+            this.amplitude = amplitude;
+        }
+        BackEase.prototype.easeInCore = function (gradient) {
+            var num = Math.max(0, this.amplitude);
+            return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
+        };
+        return BackEase;
+    })(EasingFunction);
+    BABYLON.BackEase = BackEase;
+
+    var BounceEase = (function (_super) {
+        __extends(BounceEase, _super);
+        function BounceEase(bounces, bounciness) {
+            if (typeof bounces === "undefined") { bounces = 3; }
+            if (typeof bounciness === "undefined") { bounciness = 2; }
+            _super.call(this);
+            this.bounces = bounces;
+            this.bounciness = bounciness;
+        }
+        BounceEase.prototype.easeInCore = function (gradient) {
+            var y = Math.max(0.0, this.bounces);
+            var bounciness = this.bounciness;
+            if (bounciness <= 1.0) {
+                bounciness = 1.001;
+            }
+            var num9 = Math.pow(bounciness, y);
+            var num5 = 1.0 - bounciness;
+            var num4 = ((1.0 - num9) / num5) + (num9 * 0.5);
+            var num15 = gradient * num4;
+            var num65 = Math.log((-num15 * (1.0 - bounciness)) + 1.0) / Math.log(bounciness);
+            var num3 = Math.floor(num65);
+            var num13 = num3 + 1.0;
+            var num8 = (1.0 - Math.pow(bounciness, num3)) / (num5 * num4);
+            var num12 = (1.0 - Math.pow(bounciness, num13)) / (num5 * num4);
+            var num7 = (num8 + num12) * 0.5;
+            var num6 = gradient - num7;
+            var num2 = num7 - num8;
+            return (((-Math.pow(1.0 / bounciness, y - num3) / (num2 * num2)) * (num6 - num2)) * (num6 + num2));
+        };
+        return BounceEase;
+    })(EasingFunction);
+    BABYLON.BounceEase = BounceEase;
+
+    var CubicEase = (function (_super) {
+        __extends(CubicEase, _super);
+        function CubicEase() {
+            _super.apply(this, arguments);
+        }
+        CubicEase.prototype.easeInCore = function (gradient) {
+            return (gradient * gradient * gradient);
+        };
+        return CubicEase;
+    })(EasingFunction);
+    BABYLON.CubicEase = CubicEase;
+
+    var ElasticEase = (function (_super) {
+        __extends(ElasticEase, _super);
+        function ElasticEase(oscillations, springiness) {
+            if (typeof oscillations === "undefined") { oscillations = 3; }
+            if (typeof springiness === "undefined") { springiness = 3; }
+            _super.call(this);
+            this.oscillations = oscillations;
+            this.springiness = springiness;
+        }
+        ElasticEase.prototype.easeInCore = function (gradient) {
+            var num2;
+            var num3 = Math.max(0.0, this.oscillations);
+            var num = Math.max(0.0, this.springiness);
+
+            if (num == 0) {
+                num2 = gradient;
+            } else {
+                num2 = (Math.exp(num * gradient) - 1.0) / (Math.exp(num) - 1.0);
+            }
+            return (num2 * Math.sin(((6.2831853071795862 * num3) + 1.5707963267948966) * gradient));
+        };
+        return ElasticEase;
+    })(EasingFunction);
+    BABYLON.ElasticEase = ElasticEase;
+
+    var ExponentialEase = (function (_super) {
+        __extends(ExponentialEase, _super);
+        function ExponentialEase(exponent) {
+            if (typeof exponent === "undefined") { exponent = 2; }
+            _super.call(this);
+            this.exponent = exponent;
+        }
+        ExponentialEase.prototype.easeInCore = function (gradient) {
+            if (this.exponent <= 0) {
+                return gradient;
+            }
+
+            return ((Math.exp(this.exponent * gradient) - 1.0) / (Math.exp(this.exponent) - 1.0));
+        };
+        return ExponentialEase;
+    })(EasingFunction);
+    BABYLON.ExponentialEase = ExponentialEase;
+
+    var PowerEase = (function (_super) {
+        __extends(PowerEase, _super);
+        function PowerEase(power) {
+            if (typeof power === "undefined") { power = 2; }
+            _super.call(this);
+            this.power = power;
+        }
+        PowerEase.prototype.easeInCore = function (gradient) {
+            var y = Math.max(0.0, this.power);
+            return Math.pow(gradient, y);
+        };
+        return PowerEase;
+    })(EasingFunction);
+    BABYLON.PowerEase = PowerEase;
+
+    var QuadraticEase = (function (_super) {
+        __extends(QuadraticEase, _super);
+        function QuadraticEase() {
+            _super.apply(this, arguments);
+        }
+        QuadraticEase.prototype.easeInCore = function (gradient) {
+            return (gradient * gradient);
+        };
+        return QuadraticEase;
+    })(EasingFunction);
+    BABYLON.QuadraticEase = QuadraticEase;
+
+    var QuarticEase = (function (_super) {
+        __extends(QuarticEase, _super);
+        function QuarticEase() {
+            _super.apply(this, arguments);
+        }
+        QuarticEase.prototype.easeInCore = function (gradient) {
+            return (gradient * gradient * gradient * gradient);
+        };
+        return QuarticEase;
+    })(EasingFunction);
+    BABYLON.QuarticEase = QuarticEase;
+
+    var QuinticEase = (function (_super) {
+        __extends(QuinticEase, _super);
+        function QuinticEase() {
+            _super.apply(this, arguments);
+        }
+        QuinticEase.prototype.easeInCore = function (gradient) {
+            return (gradient * gradient * gradient * gradient * gradient);
+        };
+        return QuinticEase;
+    })(EasingFunction);
+    BABYLON.QuinticEase = QuinticEase;
+
+    var SineEase = (function (_super) {
+        __extends(SineEase, _super);
+        function SineEase() {
+            _super.apply(this, arguments);
+        }
+        SineEase.prototype.easeInCore = function (gradient) {
+            return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
+        };
+        return SineEase;
+    })(EasingFunction);
+    BABYLON.SineEase = SineEase;
+
+    var BezierCurveEase = (function (_super) {
+        __extends(BezierCurveEase, _super);
+        function BezierCurveEase(x1, y1, x2, y2) {
+            if (typeof x1 === "undefined") { x1 = 0; }
+            if (typeof y1 === "undefined") { y1 = 0; }
+            if (typeof x2 === "undefined") { x2 = 1; }
+            if (typeof y2 === "undefined") { y2 = 1; }
+            _super.call(this);
+            this.x1 = x1;
+            this.y1 = y1;
+            this.x2 = x2;
+            this.y2 = y2;
+        }
+        BezierCurveEase.prototype.easeInCore = function (gradient) {
+            return BABYLON.BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
+        };
+        return BezierCurveEase;
+    })(EasingFunction);
+    BABYLON.BezierCurveEase = BezierCurveEase;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.easing.js.map

+ 188 - 0
Babylon/Animations/babylon.easing.ts

@@ -0,0 +1,188 @@
+module BABYLON {
+
+    export interface IEasingFunction {
+        ease(gradient: number): number;
+    }
+
+    export class EasingFunction implements IEasingFunction {
+        //Statics
+        private static _EASINGMODE_EASEIN = 0;
+        private static _EASINGMODE_EASEOUT = 1;
+        private static _EASINGMODE_EASEINOUT = 2;
+
+        public static get EASINGMODE_EASEIN(): number {
+            return EasingFunction._EASINGMODE_EASEIN;
+        }
+
+        public static get EASINGMODE_EASEOUT(): number {
+            return EasingFunction._EASINGMODE_EASEOUT;
+        }
+
+        public static get EASINGMODE_EASEINOUT(): number {
+            return EasingFunction._EASINGMODE_EASEINOUT;
+        }
+
+        // Properties
+        private _easingMode = EasingFunction.EASINGMODE_EASEIN;
+
+        public setEasingMode(easingMode: number) {
+            var n = Math.min(Math.max(easingMode, 0), 2);
+            this._easingMode = n;
+        }
+        public getEasingMode(): number {
+            return this._easingMode;
+        }
+
+        public easeInCore(gradient: number): number {
+            throw new Error('You must implement this method');
+        }
+
+        public ease(gradient: number): number {
+            switch (this._easingMode) {
+                case EasingFunction.EASINGMODE_EASEIN:
+                    return this.easeInCore(gradient);
+                case EasingFunction.EASINGMODE_EASEOUT:
+                    return (1 - this.easeInCore(1 - gradient));
+            }
+
+            if (gradient >= 0.5) {
+                return (((1 - this.easeInCore((1 - gradient) * 2)) * 0.5) + 0.5);
+            }
+
+            return (this.easeInCore(gradient * 2) * 0.5);
+        }
+
+    }
+
+    export class CircleEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            gradient = Math.max(0, Math.min(1, gradient));
+            return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
+        }
+    }
+
+    export class BackEase extends EasingFunction implements IEasingFunction {
+        constructor(public amplitude: number = 1) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var num = Math.max(0, this.amplitude);
+            return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
+        }
+    }
+
+    export class BounceEase extends EasingFunction implements IEasingFunction {
+        constructor(public bounces: number= 3, public bounciness: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var y = Math.max(0.0, this.bounces);
+            var bounciness = this.bounciness;
+            if (bounciness <= 1.0) {
+                bounciness = 1.001;
+            }
+            var num9 = Math.pow(bounciness, y);
+            var num5 = 1.0 - bounciness;
+            var num4 = ((1.0 - num9) / num5) + (num9 * 0.5);
+            var num15 = gradient * num4;
+            var num65 = Math.log((-num15 * (1.0 - bounciness)) + 1.0) / Math.log(bounciness);
+            var num3 = Math.floor(num65);
+            var num13 = num3 + 1.0;
+            var num8 = (1.0 - Math.pow(bounciness, num3)) / (num5 * num4);
+            var num12 = (1.0 - Math.pow(bounciness, num13)) / (num5 * num4);
+            var num7 = (num8 + num12) * 0.5;
+            var num6 = gradient - num7;
+            var num2 = num7 - num8;
+            return (((-Math.pow(1.0 / bounciness, y - num3) / (num2 * num2)) * (num6 - num2)) * (num6 + num2));
+        }
+    }
+
+    export class CubicEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient);
+        }
+    }
+
+    export class ElasticEase extends EasingFunction implements IEasingFunction {
+        constructor(public oscillations: number= 3, public springiness: number= 3) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var num2;
+            var num3 = Math.max(0.0, this.oscillations);
+            var num = Math.max(0.0, this.springiness);
+
+            if (num == 0) {
+                num2 = gradient;
+            }else {
+                num2 = (Math.exp(num * gradient) - 1.0) / (Math.exp(num) - 1.0);
+            }
+            return (num2 * Math.sin(((6.2831853071795862 * num3) + 1.5707963267948966) * gradient));
+        }
+    }
+
+    export class ExponentialEase  extends EasingFunction implements IEasingFunction {
+        constructor(public exponent: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            if (this.exponent <= 0) {
+                return gradient;
+            }
+
+            return ((Math.exp(this.exponent * gradient) - 1.0) / (Math.exp(this.exponent) - 1.0));
+        }
+    }
+
+    export class PowerEase  extends EasingFunction implements IEasingFunction {
+        constructor(public power: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var y = Math.max(0.0, this.power);
+            return Math.pow(gradient, y);
+        }
+    }
+
+    export class QuadraticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient);
+
+           
+
+        }
+    }
+
+    export class QuarticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient * gradient);
+        }
+    }
+
+    export class QuinticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient * gradient * gradient);
+        }
+    }
+
+    export class SineEase  extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
+        }
+    }
+
+    export class BezierCurveEase extends EasingFunction implements IEasingFunction {
+        constructor(public x1: number= 0, public y1: number= 0, public x2: number= 1, public y2: number= 1) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            return BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
+        }
+    }
+}

+ 43 - 0
Babylon/Audio/babylon.audioengine.js

@@ -0,0 +1,43 @@
+var BABYLON;
+(function (BABYLON) {
+    var AudioEngine = (function () {
+        function AudioEngine() {
+            this.audioContext = null;
+            this.canUseWebAudio = false;
+            try  {
+                if (typeof AudioContext !== 'undefined') {
+                    this.audioContext = new AudioContext();
+                    this.canUseWebAudio = true;
+                } else if (typeof webkitAudioContext !== 'undefined') {
+                    this.audioContext = new webkitAudioContext();
+                    this.canUseWebAudio = true;
+                }
+            } catch (e) {
+                this.canUseWebAudio = false;
+            }
+
+            // create a global volume gain node
+            if (this.canUseWebAudio) {
+                this.masterGain = this.audioContext.createGain();
+                this.masterGain.gain.value = 1;
+                this.masterGain.connect(this.audioContext.destination);
+            }
+        }
+        AudioEngine.prototype.getGlobalVolume = function () {
+            if (this.canUseWebAudio) {
+                return this.masterGain.gain.value;
+            } else {
+                return -1;
+            }
+        };
+
+        AudioEngine.prototype.setGlobalVolume = function (newVolume) {
+            if (this.canUseWebAudio) {
+                this.masterGain.gain.value = newVolume;
+            }
+        };
+        return AudioEngine;
+    })();
+    BABYLON.AudioEngine = AudioEngine;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.audioengine.js.map

+ 46 - 0
Babylon/Audio/babylon.audioengine.ts

@@ -0,0 +1,46 @@
+module BABYLON {
+    export class AudioEngine {
+        public audioContext: AudioContext = null;
+        public canUseWebAudio: boolean = false;
+        public masterGain: GainNode;
+
+        constructor() {
+             // creating the audio context 
+            try {
+                if (typeof AudioContext !== 'undefined') {
+                    this.audioContext = new AudioContext();
+                    this.canUseWebAudio = true;
+                } else if (typeof webkitAudioContext !== 'undefined') {
+                    this.audioContext = new webkitAudioContext();
+                    this.canUseWebAudio = true;
+                } 
+            } catch (e) {
+                this.canUseWebAudio = false;
+            }
+
+            // create a global volume gain node 
+            if (this.canUseWebAudio) {
+                this.masterGain = this.audioContext.createGain();
+                this.masterGain.gain.value = 1;
+                this.masterGain.connect(this.audioContext.destination);
+            }
+        }
+
+        public getGlobalVolume(): number {
+            if (this.canUseWebAudio) {
+                return this.masterGain.gain.value;
+            }
+            else {
+                return -1;
+            }
+        }
+
+        public setGlobalVolume(newVolume: number) {
+            if (this.canUseWebAudio) {
+                this.masterGain.gain.value = newVolume;
+            }
+        }
+    }
+}
+
+

+ 216 - 0
Babylon/Audio/babylon.sound.js

@@ -0,0 +1,216 @@
+var BABYLON;
+(function (BABYLON) {
+    var Sound = (function () {
+        /**
+        * Create a sound and attach it to a scene
+        * @param name Name of your sound
+        * @param url Url to the sound to load async
+        * @param readyToPlayCallback Provide a callback function if you'd like to load your code once the sound is ready to be played
+        * @param options Objects to provide with the current available options: autoplay, loop, distanceMax
+        */
+        function Sound(name, url, scene, readyToPlayCallback, options) {
+            var _this = this;
+            this.maxDistance = 20;
+            this.autoplay = false;
+            this.loop = false;
+            this.useBabylonJSAttenuation = true;
+            this._position = BABYLON.Vector3.Zero();
+            this._localDirection = new BABYLON.Vector3(1, 0, 0);
+            this._volume = 1;
+            this._isLoaded = false;
+            this._isReadyToPlay = false;
+            this._isPlaying = false;
+            this._isDirectional = false;
+            // Used if you'd like to create a directional sound.
+            // If not set, the sound will be omnidirectional
+            this._coneInnerAngle = null;
+            this._coneOuterAngle = null;
+            this._coneOuterGain = null;
+            this._name = name;
+            this._scene = scene;
+            this._audioEngine = this._scene.getEngine().getAudioEngine();
+            this._readyToPlayCallback = readyToPlayCallback;
+            if (options) {
+                if (options.maxDistance) {
+                    this.maxDistance = options.maxDistance;
+                }
+                if (options.autoplay) {
+                    this.autoplay = options.autoplay;
+                }
+                if (options.loop) {
+                    this.loop = options.loop;
+                }
+                if (options.volume) {
+                    this._volume = options.volume;
+                }
+                if (options.useBabylonJSAttenuation) {
+                    this.useBabylonJSAttenuation = options.useBabylonJSAttenuation;
+                }
+            }
+
+            if (this._audioEngine.canUseWebAudio) {
+                this._soundGain = this._audioEngine.audioContext.createGain();
+                this._soundGain.gain.value = this._volume;
+
+                //this._soundGain.connect(this._audioEngine.masterGain);
+                this._soundPanner = this._audioEngine.audioContext.createPanner();
+                this._soundPanner.connect(this._soundGain);
+                this._scene.mainSoundTrack.AddSound(this);
+                BABYLON.Tools.LoadFile(url, function (data) {
+                    _this._soundLoaded(data);
+                }, null, null, true);
+            }
+        }
+        Sound.prototype.connectToSoundTrackAudioNode = function (soundTrackAudioNode) {
+            if (this._audioEngine.canUseWebAudio) {
+                this._soundGain.disconnect();
+                this._soundGain.connect(soundTrackAudioNode);
+            }
+        };
+
+        /**
+        * Transform this sound into a directional source
+        * @param coneInnerAngle Size of the inner cone in degree
+        * @param coneOuterAngle Size of the outer cone in degree
+        * @param coneOuterGain Volume of the sound outside the outer cone (between 0.0 and 1.0)
+        */
+        Sound.prototype.setDirectionalCone = function (coneInnerAngle, coneOuterAngle, coneOuterGain) {
+            if (coneOuterAngle < coneInnerAngle) {
+                BABYLON.Tools.Error("setDirectionalCone(): outer angle of the cone must be superior or equal to the inner angle.");
+                return;
+            }
+            this._coneInnerAngle = coneInnerAngle;
+            this._coneOuterAngle = coneOuterAngle;
+            this._coneOuterGain = coneOuterGain;
+            this._isDirectional = true;
+
+            if (this._isPlaying && this.loop) {
+                this.stop();
+                this.play();
+            }
+        };
+
+        Sound.prototype.setPosition = function (newPosition) {
+            this._position = newPosition;
+
+            if (this._isPlaying) {
+                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+            }
+        };
+
+        Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
+            this._localDirection = newLocalDirection;
+
+            if (this._connectedMesh && this._isPlaying) {
+                this._updateDirection();
+            }
+        };
+
+        Sound.prototype._updateDirection = function () {
+            var mat = this._connectedMesh.getWorldMatrix();
+            var direction = BABYLON.Vector3.TransformNormal(this._localDirection, mat);
+            direction.normalize();
+            this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
+        };
+
+        Sound.prototype.updateDistanceFromListener = function () {
+            if (this._connectedMesh) {
+                var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
+
+                if (distance < 1)
+                    distance = 1;
+                if (this.useBabylonJSAttenuation) {
+                    if (distance < this.maxDistance) {
+                        this._soundGain.gain.value = this._volume / distance;
+                    } else {
+                        this._soundGain.gain.value = 0;
+                    }
+                }
+            }
+        };
+
+        /**
+        * Play the sound
+        * @param time (optional) Start the sound after X seconds. Start immediately (0) by default.
+        */
+        Sound.prototype.play = function (time) {
+            if (this._isReadyToPlay) {
+                try  {
+                    var startTime = time ? this._audioEngine.audioContext.currentTime + time : 0;
+                    this._soundSource = this._audioEngine.audioContext.createBufferSource();
+                    this._soundSource.buffer = this._audioBuffer;
+                    this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+                    if (this._isDirectional) {
+                        this._soundPanner.coneInnerAngle = this._coneInnerAngle;
+                        this._soundPanner.coneOuterAngle = this._coneOuterAngle;
+                        this._soundPanner.coneOuterGain = this._coneOuterGain;
+                        this._soundPanner.setOrientation(this._localDirection.x, this._localDirection.y, this._localDirection.z);
+                    }
+                    this._soundSource.connect(this._soundPanner);
+                    this._soundSource.loop = this.loop;
+                    this._soundSource.start(startTime);
+                    this._isPlaying = true;
+                } catch (ex) {
+                    BABYLON.Tools.Error("Error while trying to play audio: " + this._name + ", " + ex.message);
+                }
+            }
+        };
+
+        /**
+        * Stop the sound
+        * @param time (optional) Stop the sound after X seconds. Stop immediately (0) by default.
+        */
+        Sound.prototype.stop = function (time) {
+            var stopTime = time ? this._audioEngine.audioContext.currentTime + time : 0;
+            this._soundSource.stop(stopTime);
+            this._isPlaying = false;
+        };
+
+        Sound.prototype.pause = function () {
+            //this._soundSource.p
+        };
+
+        Sound.prototype.setVolume = function (newVolume) {
+            this._volume = newVolume;
+        };
+
+        Sound.prototype.getVolume = function () {
+            return this._volume;
+        };
+
+        Sound.prototype.attachToMesh = function (meshToConnectTo) {
+            var _this = this;
+            this._connectedMesh = meshToConnectTo;
+            meshToConnectTo.registerAfterWorldMatrixUpdate(function (connectedMesh) {
+                return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh);
+            });
+        };
+
+        Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (connectedMesh) {
+            this.setPosition(connectedMesh.position);
+            if (this._isDirectional && this._isPlaying) {
+                this._updateDirection();
+            }
+        };
+
+        Sound.prototype._soundLoaded = function (audioData) {
+            var _this = this;
+            this._isLoaded = true;
+            this._audioEngine.audioContext.decodeAudioData(audioData, function (buffer) {
+                _this._audioBuffer = buffer;
+                _this._isReadyToPlay = true;
+                if (_this.autoplay) {
+                    _this.play();
+                }
+                if (_this._readyToPlayCallback) {
+                    _this._readyToPlayCallback();
+                }
+            }, function (error) {
+                BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
+            });
+        };
+        return Sound;
+    })();
+    BABYLON.Sound = Sound;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.sound.js.map

+ 203 - 0
Babylon/Audio/babylon.sound.ts

@@ -0,0 +1,203 @@
+module BABYLON {
+    export class Sound {
+        public maxDistance: number = 20;
+        public autoplay: boolean = false;
+        public loop: boolean = false;
+        public useBabylonJSAttenuation: boolean = true;
+        public soundTrackId: number;
+        private _position: Vector3 = Vector3.Zero();
+        private _localDirection: Vector3 = new Vector3(1,0,0);
+        private _volume: number = 1;
+        private _isLoaded: boolean = false;
+        private _isReadyToPlay: boolean = false;
+        private _isPlaying: boolean = false;
+        private _isDirectional: boolean = false;
+        private _audioEngine: BABYLON.AudioEngine;
+        private _readyToPlayCallback;
+        private _audioBuffer;
+        private _soundSource: AudioBufferSourceNode;
+        private _soundPanner: PannerNode;
+        private _soundGain: GainNode;
+        // Used if you'd like to create a directional sound.
+        // If not set, the sound will be omnidirectional
+        private _coneInnerAngle: number = null;
+        private _coneOuterAngle: number = null;
+        private _coneOuterGain: number = null;
+        private _scene: BABYLON.Scene;
+        private _name: string;
+        private _connectedMesh: BABYLON.AbstractMesh;
+
+        /**
+        * Create a sound and attach it to a scene
+        * @param name Name of your sound 
+        * @param url Url to the sound to load async
+        * @param readyToPlayCallback Provide a callback function if you'd like to load your code once the sound is ready to be played
+        * @param options Objects to provide with the current available options: autoplay, loop, distanceMax
+        */
+        constructor(name: string, url: string, scene: BABYLON.Scene, readyToPlayCallback?: () => void, options?) {
+            this._name = name;
+            this._scene = scene;
+            this._audioEngine = this._scene.getEngine().getAudioEngine();
+            this._readyToPlayCallback = readyToPlayCallback;
+            if (options) {
+                if (options.maxDistance) { this.maxDistance = options.maxDistance; }
+                if (options.autoplay) { this.autoplay = options.autoplay; }
+                if (options.loop) { this.loop = options.loop; }
+                if (options.volume) { this._volume = options.volume; }
+                if (options.useBabylonJSAttenuation) { this.useBabylonJSAttenuation = options.useBabylonJSAttenuation; }
+            }
+
+            if (this._audioEngine.canUseWebAudio) {
+                this._soundGain = this._audioEngine.audioContext.createGain();
+                this._soundGain.gain.value = this._volume;
+                //this._soundGain.connect(this._audioEngine.masterGain);
+                this._soundPanner = this._audioEngine.audioContext.createPanner();
+                this._soundPanner.connect(this._soundGain);
+                this._scene.mainSoundTrack.AddSound(this);
+                BABYLON.Tools.LoadFile(url, (data) => { this._soundLoaded(data); }, null, null, true);
+            }
+        }
+
+        public connectToSoundTrackAudioNode(soundTrackAudioNode: AudioNode) {
+            if (this._audioEngine.canUseWebAudio) {
+                this._soundGain.disconnect();
+                this._soundGain.connect(soundTrackAudioNode);
+            }
+        }
+
+        /**
+        * Transform this sound into a directional source
+        * @param coneInnerAngle Size of the inner cone in degree
+        * @param coneOuterAngle Size of the outer cone in degree
+        * @param coneOuterGain Volume of the sound outside the outer cone (between 0.0 and 1.0)
+        */
+        public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number) {
+            if (coneOuterAngle < coneInnerAngle) {
+                BABYLON.Tools.Error("setDirectionalCone(): outer angle of the cone must be superior or equal to the inner angle.");
+                return;
+            }
+            this._coneInnerAngle = coneInnerAngle;
+            this._coneOuterAngle = coneOuterAngle;
+            this._coneOuterGain = coneOuterGain;
+            this._isDirectional = true;
+
+            if (this._isPlaying && this.loop) {
+                this.stop();
+                this.play();
+            }
+        }
+
+        public setPosition(newPosition: Vector3) {
+            this._position = newPosition;
+
+            if (this._isPlaying) {
+                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+            }
+        }
+
+        public setLocalDirectionToMesh(newLocalDirection: Vector3) {
+            this._localDirection = newLocalDirection;
+
+            if (this._connectedMesh && this._isPlaying) {
+                this._updateDirection();
+            }
+        }
+
+        private _updateDirection() {
+            var mat = this._connectedMesh.getWorldMatrix();
+            var direction = BABYLON.Vector3.TransformNormal(this._localDirection, mat);
+            direction.normalize();
+            this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
+        }
+
+        public updateDistanceFromListener() {
+            if (this._connectedMesh) {
+                var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
+
+                if (distance < 1) distance = 1;
+                if (this.useBabylonJSAttenuation) {
+                    if (distance < this.maxDistance) {
+                        this._soundGain.gain.value = this._volume / distance;
+                    }
+                    else {
+                        this._soundGain.gain.value = 0;
+                    }
+                }
+            }
+        }
+
+        /**
+        * Play the sound
+        * @param time (optional) Start the sound after X seconds. Start immediately (0) by default.
+        */
+        public play(time?: number) {
+            if (this._isReadyToPlay) {
+                try {
+                    var startTime = time ? this._audioEngine.audioContext.currentTime + time : 0;
+                    this._soundSource = this._audioEngine.audioContext.createBufferSource();
+                    this._soundSource.buffer = this._audioBuffer;
+                    this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+                    if (this._isDirectional) {
+                        this._soundPanner.coneInnerAngle = this._coneInnerAngle;
+                        this._soundPanner.coneOuterAngle = this._coneOuterAngle;
+                        this._soundPanner.coneOuterGain = this._coneOuterGain;
+                        this._soundPanner.setOrientation(this._localDirection.x, this._localDirection.y, this._localDirection.z);
+                    }
+                    this._soundSource.connect(this._soundPanner);
+                    this._soundSource.loop = this.loop;
+                    this._soundSource.start(startTime);
+                    this._isPlaying = true;
+                }
+                catch (ex) {
+                    BABYLON.Tools.Error("Error while trying to play audio: " + this._name + ", " + ex.message);
+                }
+            }
+        }
+
+        /**
+        * Stop the sound
+        * @param time (optional) Stop the sound after X seconds. Stop immediately (0) by default.
+        */
+        public stop(time?: number) {
+            var stopTime = time ? this._audioEngine.audioContext.currentTime + time : 0;
+            this._soundSource.stop(stopTime);
+            this._isPlaying = false;
+        }
+
+        public pause() {
+            //this._soundSource.p
+        }
+
+        public setVolume(newVolume: number) {
+            this._volume = newVolume;
+        }
+
+        public getVolume(): number {
+            return this._volume;
+        }
+
+        public attachToMesh(meshToConnectTo: BABYLON.AbstractMesh) {
+            this._connectedMesh = meshToConnectTo;
+            meshToConnectTo.registerAfterWorldMatrixUpdate((connectedMesh: BABYLON.AbstractMesh) => this._onRegisterAfterWorldMatrixUpdate(connectedMesh));
+        }
+
+        private _onRegisterAfterWorldMatrixUpdate(connectedMesh: BABYLON.AbstractMesh) {
+            this.setPosition(connectedMesh.position);
+            if (this._isDirectional && this._isPlaying) {
+                this._updateDirection();
+            }
+        }
+
+        private _soundLoaded(audioData: ArrayBuffer) {
+            this._isLoaded = true;
+            this._audioEngine.audioContext.decodeAudioData(audioData, (buffer) => {
+                this._audioBuffer = buffer;
+                this._isReadyToPlay = true;
+                if (this.autoplay) { this.play(); }
+                if (this._readyToPlayCallback) { this._readyToPlayCallback(); }
+            }, function (error) {
+                    BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
+                });
+        }
+    }
+}

+ 60 - 0
Babylon/Audio/babylon.soundtrack.js

@@ -0,0 +1,60 @@
+var BABYLON;
+(function (BABYLON) {
+    var SoundTrack = (function () {
+        function SoundTrack(scene, options) {
+            this.id = -1;
+            this._isMainTrack = false;
+            this._scene = scene;
+            this._audioEngine = scene.getEngine().getAudioEngine();
+            this.soundCollection = new Array();
+            if (this._audioEngine.canUseWebAudio) {
+                this._trackGain = this._audioEngine.audioContext.createGain();
+
+                //this._trackConvolver = this._audioEngine.audioContext.createConvolver();
+                //this._trackConvolver.connect(this._trackGain);
+                this._trackGain.connect(this._audioEngine.masterGain);
+
+                if (options) {
+                    if (options.volume) {
+                        this._trackGain.gain.value = options.volume;
+                    }
+                    if (options.mainTrack) {
+                        this._isMainTrack = options.mainTrack;
+                    }
+                }
+            }
+            if (!this._isMainTrack) {
+                this._scene.soundTracks.push(this);
+                this.id = this._scene.soundTracks.length - 1;
+            }
+        }
+        SoundTrack.prototype.AddSound = function (sound) {
+            sound.connectToSoundTrackAudioNode(this._trackGain);
+            if (sound.soundTrackId) {
+                if (sound.soundTrackId === -1) {
+                    this._scene.mainSoundTrack.RemoveSound(sound);
+                } else {
+                    this._scene.soundTracks[sound.soundTrackId].RemoveSound(sound);
+                }
+            }
+            this.soundCollection.push(sound);
+            sound.soundTrackId = this.id;
+        };
+
+        SoundTrack.prototype.RemoveSound = function (sound) {
+            var index = this.soundCollection.indexOf(sound);
+            if (index !== -1) {
+                this.soundCollection.splice(index, 1);
+            }
+        };
+
+        SoundTrack.prototype.setVolume = function (newVolume) {
+            if (this._audioEngine.canUseWebAudio) {
+                this._trackGain.gain.value = newVolume;
+            }
+        };
+        return SoundTrack;
+    })();
+    BABYLON.SoundTrack = SoundTrack;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.soundtrack.js.map

+ 59 - 0
Babylon/Audio/babylon.soundtrack.ts

@@ -0,0 +1,59 @@
+module BABYLON {
+    export class SoundTrack {
+        private _audioEngine: BABYLON.AudioEngine;
+        private _trackGain: GainNode;
+        private _trackConvolver: ConvolverNode;
+        private _scene: BABYLON.Scene;
+        public id: number = -1;
+        public soundCollection: Array<BABYLON.Sound>;
+        private _isMainTrack: boolean = false;
+
+        constructor(scene: BABYLON.Scene, options?: any) {
+            this._scene = scene;
+            this._audioEngine = scene.getEngine().getAudioEngine();
+            this.soundCollection = new Array();
+            if (this._audioEngine.canUseWebAudio) {
+                this._trackGain = this._audioEngine.audioContext.createGain();
+                //this._trackConvolver = this._audioEngine.audioContext.createConvolver();
+                //this._trackConvolver.connect(this._trackGain);
+                this._trackGain.connect(this._audioEngine.masterGain);
+
+                if (options) {
+                    if (options.volume) { this._trackGain.gain.value = options.volume; }
+                    if (options.mainTrack) { this._isMainTrack = options.mainTrack; }
+                }
+            }
+            if (!this._isMainTrack) {
+                this._scene.soundTracks.push(this);
+                this.id = this._scene.soundTracks.length - 1;
+            }
+        }
+
+        public AddSound(sound: BABYLON.Sound) {
+            sound.connectToSoundTrackAudioNode(this._trackGain);
+            if (sound.soundTrackId) {
+                if (sound.soundTrackId === -1) {
+                    this._scene.mainSoundTrack.RemoveSound(sound);
+                }
+                else {
+                    this._scene.soundTracks[sound.soundTrackId].RemoveSound(sound);
+                }
+            }
+            this.soundCollection.push(sound);
+            sound.soundTrackId = this.id;
+        }
+
+        public RemoveSound(sound: BABYLON.Sound) {
+            var index = this.soundCollection.indexOf(sound);
+            if (index !== -1) {
+                this.soundCollection.splice(index, 1);
+            }
+        }
+
+        public setVolume(newVolume: number) {
+            if (this._audioEngine.canUseWebAudio) {
+                this._trackGain.gain.value = newVolume;
+            }
+        }
+    }
+}

+ 49 - 0
Babylon/Debug/babylon.debugLayer.d.ts

@@ -0,0 +1,49 @@
+declare module BABYLON {
+    class DebugLayer {
+        private _scene;
+        private _enabled;
+        private _labelsEnabled;
+        private _displayStatistics;
+        private _displayTree;
+        private _displayLogs;
+        private _globalDiv;
+        private _statsDiv;
+        private _statsSubsetDiv;
+        private _optionsDiv;
+        private _optionsSubsetDiv;
+        private _logDiv;
+        private _logSubsetDiv;
+        private _treeDiv;
+        private _treeSubsetDiv;
+        private _drawingCanvas;
+        private _drawingContext;
+        private _syncPositions;
+        private _syncData;
+        private _onCanvasClick;
+        private _clickPosition;
+        private _ratio;
+        private _identityMatrix;
+        private _showUI;
+        private _needToRefreshMeshesTree;
+        public shouldDisplayLabel: (node: Node) => boolean;
+        public shouldDisplayAxis: (mesh: Mesh) => boolean;
+        public axisRatio: number;
+        constructor(scene: Scene);
+        private _refreshMeshesTreeContent();
+        private _renderSingleAxis(zero, unit, unitText, label, color);
+        private _renderAxis(projectedPosition, mesh, globalViewport);
+        private _renderLabel(text, projectedPosition, labelOffset, onClick, getFillStyle);
+        private _isClickInsideRect(x, y, width, height);
+        public isVisible(): boolean;
+        public hide(): void;
+        public show(showUI?: boolean): void;
+        private _clearLabels();
+        private _generateheader(root, text);
+        private _generateTexBox(root, title);
+        private _generateAdvancedCheckBox(root, leftTitle, rightTitle, initialState, task, tag?);
+        private _generateCheckBox(root, title, initialState, task, tag?);
+        private _generateRadio(root, title, name, initialState, task, tag?);
+        private _generateDOMelements();
+        private _displayStats();
+    }
+}

File diff suppressed because it is too large
+ 665 - 0
Babylon/Debug/babylon.debugLayer.js


File diff suppressed because it is too large
+ 1 - 0
Babylon/Debug/babylon.debugLayer.js.map


+ 658 - 0
Babylon/Debug/babylon.debugLayer.ts

@@ -0,0 +1,658 @@
+module BABYLON {
+    export class DebugLayer {
+        private _scene: Scene;
+        private _enabled: boolean = false;
+        private _labelsEnabled: boolean = false;
+        private _displayStatistics = true;
+        private _displayTree = false;
+        private _displayLogs = false;
+        private _globalDiv: HTMLDivElement;
+        private _statsDiv: HTMLDivElement;
+        private _statsSubsetDiv: HTMLDivElement;
+        private _optionsDiv: HTMLDivElement;
+        private _optionsSubsetDiv: HTMLDivElement;
+        private _logDiv: HTMLDivElement;
+        private _logSubsetDiv: HTMLDivElement;
+        private _treeDiv: HTMLDivElement;
+        private _treeSubsetDiv: HTMLDivElement;
+        private _drawingCanvas: HTMLCanvasElement;
+        private _drawingContext: CanvasRenderingContext2D;
+
+        private _syncPositions: () => void;
+        private _syncData: () => void;
+        private _onCanvasClick: (evt: MouseEvent) => void;
+
+        private _clickPosition: any;
+        private _ratio: number;
+
+        private _identityMatrix = Matrix.Identity();
+
+        private _showUI: boolean;
+        private _needToRefreshMeshesTree: boolean;
+
+        public shouldDisplayLabel: (node: Node) => boolean;
+        public shouldDisplayAxis: (mesh: Mesh) => boolean;
+
+        public axisRatio = 0.02;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+
+            this._syncPositions = (): void => {
+                var engine = this._scene.getEngine();
+                var canvasRect = engine.getRenderingCanvasClientRect();
+                
+                if (this._showUI) {
+                    this._statsDiv.style.left = (canvasRect.width - 310) + "px";
+                    this._statsDiv.style.top = (canvasRect.height - 370) + "px";
+                    this._statsDiv.style.width = "300px";
+                    this._statsDiv.style.height = "360px";
+                    this._statsSubsetDiv.style.maxHeight = (canvasRect.height - 60) + "px";
+
+                    this._optionsDiv.style.left = "0px";
+                    this._optionsDiv.style.top = "10px";
+                    this._optionsDiv.style.width = "200px";
+                    this._optionsDiv.style.height = "auto";
+                    this._optionsSubsetDiv.style.maxHeight = (canvasRect.height - 225) + "px";
+
+                    this._logDiv.style.left = "0px";
+                    this._logDiv.style.top = (canvasRect.height - 170) + "px";
+                    this._logDiv.style.width = "600px";
+                    this._logDiv.style.height = "160px";
+
+                    this._treeDiv.style.left = (canvasRect.width - 310) + "px";
+                    this._treeDiv.style.top = "10px";
+                    this._treeDiv.style.width = "300px";
+                    this._treeDiv.style.height = "auto";
+                    this._treeSubsetDiv.style.maxHeight = (canvasRect.height - 420) + "px";
+                }
+
+                this._globalDiv.style.left = canvasRect.left + "px";
+                this._globalDiv.style.top = canvasRect.top + "px";
+
+                this._drawingCanvas.style.left = "0px";
+                this._drawingCanvas.style.top = "0px";
+                this._drawingCanvas.style.width = engine.getRenderWidth() + "px";
+                this._drawingCanvas.style.height = engine.getRenderHeight() + "px";
+
+                var devicePixelRatio = window.devicePixelRatio || 1;
+                var context = <any>this._drawingContext;
+                var backingStoreRatio = context.webkitBackingStorePixelRatio ||
+                    context.mozBackingStorePixelRatio ||
+                    context.msBackingStorePixelRatio ||
+                    context.oBackingStorePixelRatio ||
+                    context.backingStorePixelRatio || 1;
+
+                this._ratio = devicePixelRatio / backingStoreRatio;
+
+                this._drawingCanvas.width = engine.getRenderWidth() * this._ratio;
+                this._drawingCanvas.height = engine.getRenderHeight() * this._ratio;
+            }
+
+            this._onCanvasClick = (evt: MouseEvent): void => {
+                this._clickPosition = {
+                    x: evt.clientX * this._ratio,
+                    y: evt.clientY * this._ratio
+                };
+            }
+
+            this._syncData = (): void => {
+                if (this._showUI) {
+                    if (this._displayStatistics) {
+                        this._displayStats();
+                        this._statsDiv.style.display = "";
+                    } else {
+                        this._statsDiv.style.display = "none";
+                    }
+
+                    if (this._displayLogs) {
+                        this._logDiv.style.display = "";
+                    } else {
+                        this._logDiv.style.display = "none";
+                    }
+
+                    if (this._displayTree) {
+                        this._treeDiv.style.display = "";
+
+                        if (this._needToRefreshMeshesTree) {
+                            this._needToRefreshMeshesTree = false;
+
+                            this._refreshMeshesTreeContent();
+                        }
+
+                    } else {
+                        this._treeDiv.style.display = "none";
+                    }
+                }
+
+                if (this._labelsEnabled || !this._showUI) {
+                    this._drawingContext.clearRect(0, 0, this._drawingCanvas.width, this._drawingCanvas.height);
+
+                    var engine = this._scene.getEngine();
+                    var viewport = this._scene.activeCamera.viewport;
+                    var globalViewport = viewport.toGlobal(engine);
+
+                    // Meshes
+                    var meshes = this._scene.getActiveMeshes();
+                    for (var index = 0; index < meshes.length; index++) {
+                        var mesh = meshes.data[index];
+
+                        var position = mesh.getBoundingInfo().boundingSphere.center;
+
+                        var projectedPosition = Vector3.Project(position, mesh.getWorldMatrix(), this._scene.getTransformMatrix(), globalViewport);
+
+                        if (mesh.renderOverlay || this.shouldDisplayAxis && this.shouldDisplayAxis(mesh)) {
+                            this._renderAxis(projectedPosition, mesh, globalViewport);
+                        }
+
+                        if (!this.shouldDisplayLabel || this.shouldDisplayLabel(mesh)) {
+                            this._renderLabel(mesh.name, projectedPosition, 12,
+                                () => { mesh.renderOverlay = !mesh.renderOverlay },
+                                () => { return mesh.renderOverlay ? 'red' : 'black'; });
+                        }
+                    }
+
+                    // Cameras
+                    var cameras = this._scene.cameras;
+                    for (index = 0; index < cameras.length; index++) {
+                        var camera = cameras[index];
+
+                        if (camera === this._scene.activeCamera) {
+                            continue;
+                        }
+
+                        projectedPosition = Vector3.Project(camera.position, this._identityMatrix, this._scene.getTransformMatrix(), globalViewport);
+
+                        if (!this.shouldDisplayLabel || this.shouldDisplayLabel(camera)) {
+                            this._renderLabel(camera.name, projectedPosition, 12,
+                                () => {
+                                    this._scene.activeCamera.detachControl(engine.getRenderingCanvas());
+                                    this._scene.activeCamera = camera;
+                                    this._scene.activeCamera.attachControl(engine.getRenderingCanvas());
+                                },
+                                () => { return "purple"; });
+                        }
+                    }
+
+                    // Lights
+                    var lights = this._scene.lights;
+                    for (index = 0; index < lights.length; index++) {
+                        var light = <any>lights[index];
+
+                        if (light.position) {
+
+                            projectedPosition = Vector3.Project(light.position, this._identityMatrix, this._scene.getTransformMatrix(), globalViewport);
+
+                            if (!this.shouldDisplayLabel || this.shouldDisplayLabel(light)) {
+                                this._renderLabel(light.name, projectedPosition, -20,
+                                () => {
+                                    light.setEnabled(!light.isEnabled());
+                                },
+                                () => { return light.isEnabled() ? "orange" : "gray"; });
+                            }
+
+                        }
+                    }
+                }
+
+                this._clickPosition = undefined;
+            }
+        }
+
+        private _refreshMeshesTreeContent(): void {
+            // Add meshes
+            var sortedArray = this._scene.meshes.slice(0, this._scene.meshes.length);
+
+            sortedArray.sort((a, b) => {
+                if (a.name === b.name) {
+                    return 0;
+                }
+
+                return (a.name > b.name) ? 1 : -1;
+            });
+
+            for (var index = 0; index < sortedArray.length; index++) {
+                var mesh = sortedArray[index];
+
+                if (!mesh.isEnabled()) {
+                    continue;
+                }
+
+                this._generateAdvancedCheckBox(this._treeSubsetDiv, mesh.name, mesh.getTotalVertices() + " verts", mesh.isVisible, (element, mesh) => {
+                    mesh.isVisible = element.checked;
+                }, mesh);
+            } 
+        }
+
+        private _renderSingleAxis(zero: Vector3, unit: Vector3, unitText: Vector3, label: string, color: string) {
+            this._drawingContext.beginPath();
+            this._drawingContext.moveTo(zero.x, zero.y);
+            this._drawingContext.lineTo(unit.x, unit.y);
+
+            this._drawingContext.strokeStyle = color;
+            this._drawingContext.lineWidth = 4;
+            this._drawingContext.stroke();
+
+            this._drawingContext.font = "normal 14px Segoe UI";
+            this._drawingContext.fillStyle = color;
+            this._drawingContext.fillText(label, unitText.x, unitText.y);
+        }
+
+        private _renderAxis(projectedPosition: Vector3, mesh: Mesh, globalViewport: Viewport) {
+            var position = mesh.getBoundingInfo().boundingSphere.center;
+            var worldMatrix = mesh.getWorldMatrix();
+
+            var unprojectedVector = Vector3.UnprojectFromTransform(projectedPosition.add(new Vector3(this._drawingCanvas.width * this.axisRatio, 0, 0)), globalViewport.width, globalViewport.height, worldMatrix, this._scene.getTransformMatrix());
+            var unit = (unprojectedVector.subtract(position)).length();
+
+            var xAxis = Vector3.Project(position.add(new Vector3(unit, 0, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
+            var xAxisText = Vector3.Project(position.add(new Vector3(unit * 1.5, 0, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
+
+            this._renderSingleAxis(projectedPosition, xAxis, xAxisText, "x", "#FF0000");
+
+            var yAxis = Vector3.Project(position.add(new Vector3(0, unit, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
+            var yAxisText = Vector3.Project(position.add(new Vector3(0, unit * 1.5, 0)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
+
+            this._renderSingleAxis(projectedPosition, yAxis, yAxisText, "y", "#00FF00");
+
+            var zAxis = Vector3.Project(position.add(new Vector3(0, 0, unit)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
+            var zAxisText = Vector3.Project(position.add(new Vector3(0, 0, unit * 1.5)), worldMatrix, this._scene.getTransformMatrix(), globalViewport);
+
+            this._renderSingleAxis(projectedPosition, zAxis, zAxisText, "z", "#0000FF");
+        }
+
+        private _renderLabel(text: string, projectedPosition: Vector3, labelOffset: number, onClick: () => void, getFillStyle: () => string): void {
+            if (projectedPosition.z > 0 && projectedPosition.z < 1.0) {
+                this._drawingContext.font = "normal 12px Segoe UI";
+                var textMetrics = this._drawingContext.measureText(text);
+                var centerX = projectedPosition.x - textMetrics.width / 2;
+                var centerY = projectedPosition.y;
+
+                if (this._isClickInsideRect(centerX - 5, centerY - labelOffset - 12, textMetrics.width + 10, 17)) {
+                    onClick();
+                }
+
+                this._drawingContext.beginPath();
+                this._drawingContext.rect(centerX - 5, centerY - labelOffset - 12, textMetrics.width + 10, 17);
+                this._drawingContext.fillStyle = getFillStyle();
+                this._drawingContext.globalAlpha = 0.5;
+                this._drawingContext.fill();
+                this._drawingContext.globalAlpha = 1.0;
+
+                this._drawingContext.strokeStyle = '#FFFFFF';
+                this._drawingContext.lineWidth = 1;
+                this._drawingContext.stroke();
+
+                this._drawingContext.fillStyle = "#FFFFFF";
+                this._drawingContext.fillText(text, centerX, centerY - labelOffset);
+
+                this._drawingContext.beginPath();
+                this._drawingContext.arc(projectedPosition.x, centerY, 5, 0, 2 * Math.PI, false);
+                this._drawingContext.fill();
+            }
+        }
+
+        private _isClickInsideRect(x: number, y: number, width: number, height: number): boolean {
+            if (!this._clickPosition) {
+                return false;
+            }
+
+            if (this._clickPosition.x < x || this._clickPosition.x > x + width) {
+                return false;
+            }
+
+            if (this._clickPosition.y < y || this._clickPosition.y > y + height) {
+                return false;
+            }
+
+            return true;
+        }
+
+        public isVisible(): boolean {
+            return this._enabled;
+        }
+
+        public hide() {
+            if (!this._enabled) {
+                return;
+            }
+
+            this._enabled = false;
+
+            var engine = this._scene.getEngine();
+
+            this._scene.unregisterAfterRender(this._syncData);
+            document.body.removeChild(this._globalDiv);
+
+            window.removeEventListener("resize", this._syncPositions);
+
+            this._scene.forceShowBoundingBoxes = false;
+            this._scene.forceWireframe = false;
+
+            StandardMaterial.DiffuseTextureEnabled = true;
+            StandardMaterial.AmbientTextureEnabled = true;
+            StandardMaterial.SpecularTextureEnabled = true;
+            StandardMaterial.EmissiveTextureEnabled = true;
+            StandardMaterial.BumpTextureEnabled = true;
+            StandardMaterial.OpacityTextureEnabled = true;
+            StandardMaterial.ReflectionTextureEnabled = true;
+
+            this._scene.shadowsEnabled = true;
+            this._scene.particlesEnabled = true;
+            this._scene.postProcessesEnabled = true;
+            this._scene.collisionsEnabled = true;
+            this._scene.lightsEnabled = true;
+            this._scene.texturesEnabled = true;
+            this._scene.lensFlaresEnabled = true;
+            this._scene.proceduralTexturesEnabled = true;
+            this._scene.renderTargetsEnabled = true;
+
+            engine.getRenderingCanvas().removeEventListener("click", this._onCanvasClick);
+        }
+
+        public show(showUI: boolean = true) {
+            if (this._enabled) {
+                return;
+            }
+
+            this._enabled = true;
+            this._showUI = showUI;
+
+            var engine = this._scene.getEngine();
+
+            this._scene.registerAfterRender(this._syncData);
+
+            this._globalDiv = document.createElement("div");
+
+            document.body.appendChild(this._globalDiv);
+
+            this._generateDOMelements();
+
+            window.addEventListener("resize", this._syncPositions);
+            engine.getRenderingCanvas().addEventListener("click", this._onCanvasClick);
+
+            this._syncPositions();
+        }
+
+        private _clearLabels(): void {
+            this._drawingContext.clearRect(0, 0, this._drawingCanvas.width, this._drawingCanvas.height);
+
+            for (var index = 0; index < this._scene.meshes.length; index++) {
+                var mesh = this._scene.meshes[index];
+                mesh.renderOverlay = false;
+            }
+        }
+
+        private _generateheader(root: HTMLDivElement, text: string): void {
+            var header = document.createElement("div");
+            header.innerHTML = text + "&nbsp;";
+
+            header.style.textAlign = "right";
+            header.style.width = "100%";
+            header.style.color = "white";
+            header.style.backgroundColor = "Black";
+            header.style.padding = "5px 5px 4px 0px";
+            header.style.marginLeft = "-5px";
+
+            root.appendChild(header);
+        }
+
+        private _generateTexBox(root: HTMLDivElement, title: string): void {
+            var label = document.createElement("label");
+            label.innerHTML = title;
+
+            root.appendChild(label);
+            root.appendChild(document.createElement("br"));
+        }
+
+        private _generateAdvancedCheckBox(root: HTMLDivElement, leftTitle: string, rightTitle: string, initialState: boolean, task: (element, tag) => void, tag: any = null): void {
+            var label = document.createElement("label");
+
+            var boundingBoxesCheckbox = document.createElement("input");
+            boundingBoxesCheckbox.type = "checkbox";
+            boundingBoxesCheckbox.checked = initialState;
+
+            boundingBoxesCheckbox.addEventListener("change", (evt: Event) => {
+                task(evt.target, tag);
+            });
+
+            label.appendChild(boundingBoxesCheckbox);
+            var container = document.createElement("span");
+            var leftPart = document.createElement("span");
+            var rightPart = document.createElement("span");
+
+            rightPart.style.cssFloat = "right";
+
+            leftPart.innerHTML = leftTitle;
+            rightPart.innerHTML = rightTitle;
+
+            container.appendChild(leftPart);
+            container.appendChild(rightPart);
+
+            label.appendChild(container);
+            root.appendChild(label);
+            root.appendChild(document.createElement("br"));
+        }
+
+        private _generateCheckBox(root: HTMLDivElement, title: string, initialState: boolean, task: (element, tag) => void, tag: any = null): void {
+            var label = document.createElement("label");
+
+            var boundingBoxesCheckbox = document.createElement("input");
+            boundingBoxesCheckbox.type = "checkbox";
+            boundingBoxesCheckbox.checked = initialState;
+
+            boundingBoxesCheckbox.addEventListener("change", (evt: Event) => {
+                task(evt.target, tag);
+            });
+
+            label.appendChild(boundingBoxesCheckbox);
+            label.appendChild(document.createTextNode(title));
+            root.appendChild(label);
+            root.appendChild(document.createElement("br"));
+        }
+
+        private _generateRadio(root: HTMLDivElement, title: string, name: string, initialState: boolean, task: (element, tag) => void, tag: any = null): void {
+            var label = document.createElement("label");
+
+            var boundingBoxesRadio = document.createElement("input");
+            boundingBoxesRadio.type = "radio";
+            boundingBoxesRadio.name = name;
+            boundingBoxesRadio.checked = initialState;
+
+            boundingBoxesRadio.addEventListener("change", (evt: Event) => {
+                task(evt.target, tag);
+            });
+
+            label.appendChild(boundingBoxesRadio);
+            label.appendChild(document.createTextNode(title));
+            root.appendChild(label);
+            root.appendChild(document.createElement("br"));
+        }
+
+        private _generateDOMelements(): void {
+            this._globalDiv.id = "DebugLayer";
+
+            // Drawing canvas
+            this._drawingCanvas = document.createElement("canvas");
+            this._drawingCanvas.id = "DebugLayerDrawingCanvas";
+            this._drawingCanvas.style.position = "absolute";
+            this._drawingCanvas.style.pointerEvents = "none";
+            this._drawingContext = this._drawingCanvas.getContext("2d");
+            this._globalDiv.appendChild(this._drawingCanvas);
+
+            if (this._showUI) {
+                var background = "rgba(128, 128, 128, 0.4)";
+                var border = "rgb(180, 180, 180) solid 1px";
+
+                // Stats
+                this._statsDiv = document.createElement("div");
+                this._statsDiv.id = "DebugLayerStats";
+                this._statsDiv.style.border = border;
+                this._statsDiv.style.position = "absolute";
+                this._statsDiv.style.background = background;
+                this._statsDiv.style.padding = "0px 0px 0px 5px";
+                this._statsDiv.style.pointerEvents = "none";
+                this._statsDiv.style.overflowY = "auto";
+                this._generateheader(this._statsDiv, "Statistics");
+                this._statsSubsetDiv = document.createElement("div");
+                this._statsSubsetDiv.style.paddingTop = "5px";
+                this._statsSubsetDiv.style.paddingBottom = "5px";
+                this._statsDiv.appendChild(this._statsSubsetDiv);
+
+                // Tree
+                this._treeDiv = document.createElement("div");
+                this._treeDiv.id = "DebugLayerTree";
+                this._treeDiv.style.border = border;
+                this._treeDiv.style.position = "absolute";
+                this._treeDiv.style.background = background;
+                this._treeDiv.style.padding = "0px 0px 0px 5px";
+                this._treeDiv.style.display = "none";
+                this._generateheader(this._treeDiv, "Meshes tree");
+                this._treeSubsetDiv = document.createElement("div");
+                this._treeSubsetDiv.style.paddingTop = "5px";
+                this._treeSubsetDiv.style.paddingRight = "5px";
+                this._treeSubsetDiv.style.overflowY = "auto";
+                this._treeSubsetDiv.style.maxHeight = "300px";
+                this._treeDiv.appendChild(this._treeSubsetDiv);
+                this._needToRefreshMeshesTree = true;
+
+                // Logs
+                this._logDiv = document.createElement("div");
+                this._logDiv.style.border = border;
+                this._logDiv.id = "DebugLayerLogs";
+                this._logDiv.style.position = "absolute";
+                this._logDiv.style.background = background;
+                this._logDiv.style.padding = "0px 0px 0px 5px";
+                this._logDiv.style.display = "none";
+                this._generateheader(this._logDiv, "Logs");
+                this._logSubsetDiv = document.createElement("div");
+                this._logSubsetDiv.style.height = "127px";
+                this._logSubsetDiv.style.paddingTop = "5px";
+                this._logSubsetDiv.style.overflowY = "auto";
+                this._logSubsetDiv.style.fontSize = "12px";
+                this._logSubsetDiv.style.fontFamily = "consolas";
+                this._logSubsetDiv.innerHTML = Tools.LogCache;
+                this._logDiv.appendChild(this._logSubsetDiv);
+                Tools.OnNewCacheEntry = (entry: string) => {
+                    this._logSubsetDiv.innerHTML = entry + this._logSubsetDiv.innerHTML;
+                }
+
+                // Options
+                this._optionsDiv = document.createElement("div");
+                this._optionsDiv.id = "DebugLayerOptions";
+                this._optionsDiv.style.border = border;
+                this._optionsDiv.style.position = "absolute";
+                this._optionsDiv.style.background = background;
+                this._optionsDiv.style.padding = "0px 0px 0px 5px";
+                this._optionsDiv.style.overflowY = "auto";
+                this._generateheader(this._optionsDiv, "Options");
+                this._optionsSubsetDiv = document.createElement("div");
+                this._optionsSubsetDiv.style.paddingTop = "5px";
+                this._optionsSubsetDiv.style.paddingBottom = "5px";
+                this._optionsSubsetDiv.style.overflowY = "auto";
+                this._optionsSubsetDiv.style.maxHeight = "200px";
+                this._optionsDiv.appendChild(this._optionsSubsetDiv);
+
+                this._generateTexBox(this._optionsSubsetDiv, "<b>General:</b>");
+                this._generateCheckBox(this._optionsSubsetDiv, "Statistics", this._displayStatistics, (element) => { this._displayStatistics = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Logs", this._displayLogs, (element) => { this._displayLogs = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Meshes tree", this._displayTree, (element) => {
+                    this._displayTree = element.checked;
+                    this._needToRefreshMeshesTree = true;
+                });
+                this._generateCheckBox(this._optionsSubsetDiv, "Bounding boxes", this._scene.forceShowBoundingBoxes, (element) => { this._scene.forceShowBoundingBoxes = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Clickable labels", this._labelsEnabled, (element) => {
+                    this._labelsEnabled = element.checked;
+                    if (!this._labelsEnabled) {
+                        this._clearLabels();
+                    }
+                });
+                this._generateCheckBox(this._optionsSubsetDiv, "Generate user marks", Tools.PerformanceLogLevel === Tools.PerformanceUserMarkLogLevel,
+                    (element) => {
+                        if (element.checked) {
+                            Tools.PerformanceLogLevel = Tools.PerformanceUserMarkLogLevel;
+                        } else {
+                            Tools.PerformanceLogLevel = Tools.PerformanceNoneLogLevel;
+                        }
+                    });
+                ;
+                this._optionsSubsetDiv.appendChild(document.createElement("br"));
+                this._generateTexBox(this._optionsSubsetDiv, "<b>Rendering mode:</b>");
+                this._generateRadio(this._optionsSubsetDiv, "Solid", "renderMode", !this._scene.forceWireframe && !this._scene.forcePointsCloud, (element) => {
+                    if (element.checked) {
+                        this._scene.forceWireframe = false;
+                        this._scene.forcePointsCloud = false;
+                    }
+                });
+                this._generateRadio(this._optionsSubsetDiv, "Wireframe", "renderMode", this._scene.forceWireframe, (element) => {
+                    if (element.checked) {
+                        this._scene.forceWireframe = true;
+                        this._scene.forcePointsCloud = false;
+                    }
+                });
+                this._generateRadio(this._optionsSubsetDiv, "Point", "renderMode", this._scene.forcePointsCloud, (element) => {
+                    if (element.checked) {
+                        this._scene.forceWireframe = false;
+                        this._scene.forcePointsCloud = true;
+                    }
+                });
+                this._optionsSubsetDiv.appendChild(document.createElement("br"));
+                this._generateTexBox(this._optionsSubsetDiv, "<b>Texture channels:</b>");
+                this._generateCheckBox(this._optionsSubsetDiv, "Diffuse", StandardMaterial.DiffuseTextureEnabled, (element) => { StandardMaterial.DiffuseTextureEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Ambient", StandardMaterial.AmbientTextureEnabled, (element) => { StandardMaterial.AmbientTextureEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Specular", StandardMaterial.SpecularTextureEnabled, (element) => { StandardMaterial.SpecularTextureEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Emissive", StandardMaterial.EmissiveTextureEnabled, (element) => { StandardMaterial.EmissiveTextureEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Bump", StandardMaterial.BumpTextureEnabled, (element) => { StandardMaterial.BumpTextureEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Opacity", StandardMaterial.OpacityTextureEnabled, (element) => { StandardMaterial.OpacityTextureEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Reflection", StandardMaterial.ReflectionTextureEnabled, (element) => { StandardMaterial.ReflectionTextureEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Fresnel", StandardMaterial.FresnelEnabled, (element) => { StandardMaterial.FresnelEnabled = element.checked });
+                this._optionsSubsetDiv.appendChild(document.createElement("br"));
+                this._generateTexBox(this._optionsSubsetDiv, "<b>Options:</b>");
+                this._generateCheckBox(this._optionsSubsetDiv, "Animations", this._scene.animationsEnabled, (element) => { this._scene.animationsEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Collisions", this._scene.collisionsEnabled, (element) => { this._scene.collisionsEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Fog", this._scene.fogEnabled, (element) => { this._scene.fogEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Lens flares", this._scene.lensFlaresEnabled, (element) => { this._scene.lensFlaresEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Lights", this._scene.lightsEnabled, (element) => { this._scene.lightsEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Particles", this._scene.particlesEnabled, (element) => { this._scene.particlesEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Post-processes", this._scene.postProcessesEnabled, (element) => { this._scene.postProcessesEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Procedural textures", this._scene.proceduralTexturesEnabled, (element) => { this._scene.proceduralTexturesEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Render targets", this._scene.renderTargetsEnabled, (element) => { this._scene.renderTargetsEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Shadows", this._scene.shadowsEnabled, (element) => { this._scene.shadowsEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Skeletons", this._scene.skeletonsEnabled, (element) => { this._scene.skeletonsEnabled = element.checked });
+                this._generateCheckBox(this._optionsSubsetDiv, "Textures", this._scene.texturesEnabled, (element) => { this._scene.texturesEnabled = element.checked });
+
+                // Global
+
+                this._globalDiv.style.position = "absolute";
+                this._globalDiv.appendChild(this._statsDiv);
+                this._globalDiv.appendChild(this._logDiv);
+                this._globalDiv.appendChild(this._optionsDiv);
+                this._globalDiv.appendChild(this._treeDiv);
+
+                this._globalDiv.style.fontFamily = "Segoe UI, Arial";
+                this._globalDiv.style.fontSize = "14px";
+                this._globalDiv.style.color = "white";
+            }
+        }
+
+        private _displayStats() {
+            var scene = this._scene;
+            var engine = scene.getEngine();
+
+            this._statsSubsetDiv.innerHTML = "Babylon.js v" + Engine.Version + " - <b>" + Tools.Format(Tools.GetFps(), 0) + " fps</b><br><br>"
+            + "Total meshes: " + scene.meshes.length + "<br>"
+            + "Total vertices: " + scene.getTotalVertices() + "<br>"
+            + "Active meshes: " + scene.getActiveMeshes().length + "<br>"
+            + "Active vertices: " + scene.getActiveVertices() + "<br>"
+            + "Active bones: " + scene.getActiveBones() + "<br>"
+            + "Active particles: " + scene.getActiveParticles() + "<br><br>"
+            + "Frame duration: " + Tools.Format(scene.getLastFrameDuration()) + " ms<br>"
+            + "<b>Draw calls: " + engine.drawCalls + "</b><br><br>"
+            + "<i>Evaluate Active Meshes duration:</i> " + Tools.Format(scene.getEvaluateActiveMeshesDuration()) + " ms<br>"
+            + "<i>Render Targets duration:</i> " + Tools.Format(scene.getRenderTargetsDuration()) + " ms<br>"
+            + "<i>Particles duration:</i> " + Tools.Format(scene.getParticlesDuration()) + " ms<br>"
+            + "<i>Sprites duration:</i> " + Tools.Format(scene.getSpritesDuration()) + " ms<br>"
+            + "<i>Render duration:</i> <b>" + Tools.Format(scene.getRenderDuration()) + " ms</b>";
+        }
+    }
+}

+ 3 - 2
Babylon/Lights/Shadows/babylon.shadowGenerator.ts

@@ -94,7 +94,7 @@
                     }
 
                     // Bones
-                    var useBones = mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
+                    var useBones = mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
 
                     if (useBones) {
                         this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
@@ -157,6 +157,7 @@
             var attribs = [BABYLON.VertexBuffer.PositionKind];
 
             var mesh = subMesh.getMesh();
+            var scene = mesh.getScene();
             var material = subMesh.getMaterial();
 
             // Alpha test
@@ -173,7 +174,7 @@
             }
 
             // Bones
-            if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            if (mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

+ 8 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -656,10 +656,18 @@
         mesh.showBoundingBox = parsedMesh.showBoundingBox;
         mesh.showSubMeshesBoundingBox = parsedMesh.showSubMeshesBoundingBox;
 
+        if (parsedMesh.applyFog !== undefined) {
+            mesh.applyFog = parsedMesh.applyFog;
+        }
+
         if (parsedMesh.pickable !== undefined) {
             mesh.isPickable = parsedMesh.pickable;
         }
 
+        if (parsedMesh.alphaIndex !== undefined) {
+            mesh.alphaIndex = parsedMesh.alphaIndex;
+        }
+
         mesh.receiveShadows = parsedMesh.receiveShadows;
 
         mesh.billboardMode = parsedMesh.billboardMode;

+ 9 - 9
Babylon/Loading/babylon.sceneLoader.ts

@@ -52,7 +52,7 @@
             SceneLoader._registeredPlugins.push(plugin);
         }
 
-        public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene) => void): void {
+        public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, e:any) => void): void {
             var manifestChecked = success => {
                 scene.database = database;
 
@@ -66,14 +66,14 @@
                     try {
                         if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
                             if (onerror) {
-                                onerror(scene);
+                                onerror(scene, 'unable to load the scene');
                             }
 
                             return;
                         }
                     } catch (e) {
                         if (onerror) {
-                            onerror(scene);
+                            onerror(scene, e);
                         }
 
                         return;
@@ -92,13 +92,13 @@
                     return;
                 }
 
-                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, data => {
+                Tools.LoadFile(rootUrl + sceneFilename, data => {
                     importMeshFromData(data);
                 }, progressCallBack, database);
             };
 
             // Checking if a manifest file has been set for this scene and if offline mode has been requested
-            var database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
+            var database = new Database(rootUrl + sceneFilename, manifestChecked);
         }
 
         /**
@@ -108,7 +108,7 @@
         * @param engine is the instance of BABYLON.Engine to use to create the scene
         */
         public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
-            SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onsuccess, progressCallBack, onerror);
+            SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onsuccess, progressCallBack, onerror);
         }
 
         /**
@@ -150,7 +150,7 @@
             };
 
             var manifestChecked = success => {
-                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
+                Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
             };
 
             if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
@@ -161,11 +161,11 @@
 
             if (rootUrl.indexOf("file:") === -1) {
                 // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
+                database = new Database(rootUrl + sceneFilename, manifestChecked);
             }
             // Loading file from disk via input file or drag'n'drop
             else {
-                BABYLON.Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack);
+                Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack);
             }
         }
     };

+ 20 - 21
Babylon/Materials/babylon.effect.ts

@@ -147,14 +147,14 @@
         public _loadVertexShader(vertex: any, callback: (data: any) => void): void {
             // DOM element ?
             if (vertex instanceof HTMLElement) {
-                var vertexCode = BABYLON.Tools.GetDOMTextContent(vertex);
+                var vertexCode = Tools.GetDOMTextContent(vertex);
                 callback(vertexCode);
                 return;
             }
 
             // Is in local store ?
-            if (BABYLON.Effect.ShadersStore[vertex + "VertexShader"]) {
-                callback(BABYLON.Effect.ShadersStore[vertex + "VertexShader"]);
+            if (Effect.ShadersStore[vertex + "VertexShader"]) {
+                callback(Effect.ShadersStore[vertex + "VertexShader"]);
                 return;
             }
 
@@ -163,29 +163,29 @@
             if (vertex[0] === ".") {
                 vertexShaderUrl = vertex;
             } else {
-                vertexShaderUrl = BABYLON.Engine.ShadersRepository + vertex;
+                vertexShaderUrl = Engine.ShadersRepository + vertex;
             }
 
             // Vertex shader
-            BABYLON.Tools.LoadFile(vertexShaderUrl + ".vertex.fx", callback);
+            Tools.LoadFile(vertexShaderUrl + ".vertex.fx", callback);
         }
 
         public _loadFragmentShader(fragment: any, callback: (data: any) => void): void {
             // DOM element ?
             if (fragment instanceof HTMLElement) {
-                var fragmentCode = BABYLON.Tools.GetDOMTextContent(fragment);
+                var fragmentCode = Tools.GetDOMTextContent(fragment);
                 callback(fragmentCode);
                 return;
             }
 
             // Is in local store ?
-            if (BABYLON.Effect.ShadersStore[fragment + "PixelShader"]) {
-                callback(BABYLON.Effect.ShadersStore[fragment + "PixelShader"]);
+            if (Effect.ShadersStore[fragment + "PixelShader"]) {
+                callback(Effect.ShadersStore[fragment + "PixelShader"]);
                 return;
             }
 
-            if (BABYLON.Effect.ShadersStore[fragment + "FragmentShader"]) {
-                callback(BABYLON.Effect.ShadersStore[fragment + "FragmentShader"]);
+            if (Effect.ShadersStore[fragment + "FragmentShader"]) {
+                callback(Effect.ShadersStore[fragment + "FragmentShader"]);
                 return;
             }
 
@@ -194,11 +194,11 @@
             if (fragment[0] === ".") {
                 fragmentShaderUrl = fragment;
             } else {
-                fragmentShaderUrl = BABYLON.Engine.ShadersRepository + fragment;
+                fragmentShaderUrl = Engine.ShadersRepository + fragment;
             }
 
             // Fragment shader
-            BABYLON.Tools.LoadFile(fragmentShaderUrl + ".fragment.fx", callback);
+            Tools.LoadFile(fragmentShaderUrl + ".fragment.fx", callback);
         }
 
         private _prepareEffect(vertexSourceCode: string, fragmentSourceCode: string, attributesNames: string[], defines: string, fallbacks?: EffectFallbacks): void {
@@ -218,7 +218,6 @@
                         index--;
                     }
                 }
-
                 engine.bindSamplers(this);
 
                 this._isReady = true;
@@ -239,7 +238,7 @@
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     defines = fallbacks.reduce(defines);
                     this._prepareEffect(vertexSourceCode, fragmentSourceCode, attributesNames, defines, fallbacks);
-                } else { // SOrry we did everything we can
+                } else { // Sorry we did everything we can
                     Tools.Error("Unable to compile effect: " + this.name);
                     Tools.Error("Defines: " + defines);
                     Tools.Error("Error: " + e.message);
@@ -352,7 +351,7 @@
         }
 
         public setVector2(uniformName: string, vector2: Vector2): Effect {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == vector2.x && this._valueCache[uniformName][1] == vector2.y)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === vector2.x && this._valueCache[uniformName][1] === vector2.y)
                 return this;
 
             this._cacheFloat2(uniformName, vector2.x, vector2.y);
@@ -362,7 +361,7 @@
         }
 
         public setFloat2(uniformName: string, x: number, y: number): Effect {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == x && this._valueCache[uniformName][1] == y)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === x && this._valueCache[uniformName][1] === y)
                 return this;
 
             this._cacheFloat2(uniformName, x, y);
@@ -372,7 +371,7 @@
         }
 
         public setVector3(uniformName: string, vector3: Vector3): Effect {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == vector3.x && this._valueCache[uniformName][1] == vector3.y && this._valueCache[uniformName][2] == vector3.z)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === vector3.x && this._valueCache[uniformName][1] === vector3.y && this._valueCache[uniformName][2] === vector3.z)
                 return this;
 
             this._cacheFloat3(uniformName, vector3.x, vector3.y, vector3.z);
@@ -383,7 +382,7 @@
         }
 
         public setFloat3(uniformName: string, x: number, y: number, z: number): Effect {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == x && this._valueCache[uniformName][1] == y && this._valueCache[uniformName][2] == z)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === x && this._valueCache[uniformName][1] === y && this._valueCache[uniformName][2] === z)
                 return this;
 
             this._cacheFloat3(uniformName, x, y, z);
@@ -393,7 +392,7 @@
         }
 
         public setFloat4(uniformName: string, x: number, y: number, z: number, w: number): Effect {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == x && this._valueCache[uniformName][1] == y && this._valueCache[uniformName][2] == z && this._valueCache[uniformName][3] == w)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === x && this._valueCache[uniformName][1] === y && this._valueCache[uniformName][2] === z && this._valueCache[uniformName][3] === w)
                 return this;
 
             this._cacheFloat4(uniformName, x, y, z, w);
@@ -403,7 +402,7 @@
         }
 
         public setColor3(uniformName: string, color3: Color3): Effect {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == color3.r && this._valueCache[uniformName][1] == color3.g && this._valueCache[uniformName][2] == color3.b)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === color3.r && this._valueCache[uniformName][1] === color3.g && this._valueCache[uniformName][2] === color3.b)
                 return this;
 
             this._cacheFloat3(uniformName, color3.r, color3.g, color3.b);
@@ -413,7 +412,7 @@
         }
 
         public setColor4(uniformName: string, color3: Color3, alpha: number): Effect {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == color3.r && this._valueCache[uniformName][1] == color3.g && this._valueCache[uniformName][2] == color3.b && this._valueCache[uniformName][3] == alpha)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === color3.r && this._valueCache[uniformName][1] === color3.g && this._valueCache[uniformName][2] === color3.b && this._valueCache[uniformName][3] === alpha)
                 return this;
 
             this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha);

+ 6 - 0
Babylon/Materials/babylon.material.ts

@@ -25,6 +25,7 @@
         public onCompiled: (effect: Effect) => void;
         public onError: (effect: Effect, errors: string) => void;
         public onDispose: () => void;
+        public onBind: (material: Material) => void;
         public getRenderTargetTextures: () => SmartArray<RenderTargetTexture>;
 
         public _effect: Effect;
@@ -103,6 +104,11 @@
         }
 
         public bind(world: Matrix, mesh: Mesh): void {
+            this._scene._cachedMaterial = this;
+
+            if (this.onBind) {
+                this.onBind(this);
+            }
         }
 
         public bindOnlyWorldMatrix(world: Matrix): void {

+ 82 - 53
Babylon/Materials/babylon.shaderMaterial.ts

@@ -11,6 +11,7 @@
         private _vectors3 = new Array<Vector3>();
         private _matrices = new Array<Matrix>();
         private _cachedWorldViewMatrix = new BABYLON.Matrix();
+        private _renderId: number;
 
         constructor(name: string, scene: Scene, shaderPath: any, options: any) {
             super(name, scene);
@@ -98,8 +99,16 @@
         }
 
         public isReady(): boolean {
-            var engine = this.getScene().getEngine();
+            var scene = this.getScene();
+            var engine = scene.getEngine();
 
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    return true;
+                }
+            }
+
+            var previousEffect = this._effect;
             this._effect = engine.createEffect(this._shaderPath,
                 this._options.attributes,
                 this._options.uniforms,
@@ -110,72 +119,92 @@
                 return false;
             }
 
+            if (previousEffect !== this._effect) {
+                scene.resetCachedMaterial();
+            }
+
+            this._renderId = scene.getRenderId();
+
             return true;
         }
 
-        public bind(world: Matrix): void {
-            // Std values
+        public bindOnlyWorldMatrix(world: Matrix): void {
+            var scene = this.getScene();
+
             if (this._options.uniforms.indexOf("world") !== -1) {
                 this._effect.setMatrix("world", world);
             }
 
-            if (this._options.uniforms.indexOf("view") !== -1) {
-                this._effect.setMatrix("view", this.getScene().getViewMatrix());
-            }
-
             if (this._options.uniforms.indexOf("worldView") !== -1) {
-                world.multiplyToRef(this.getScene().getViewMatrix(), this._cachedWorldViewMatrix);
+                world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
                 this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
             }
 
-            if (this._options.uniforms.indexOf("projection") !== -1) {
-                this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
-            }
-
             if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
-                this._effect.setMatrix("worldViewProjection", world.multiply(this.getScene().getTransformMatrix()));
-            }
-
-            // Texture
-            for (var name in this._textures) {
-                this._effect.setTexture(name, this._textures[name]);
-            }
-
-            // Float    
-            for (name in this._floats) {
-                this._effect.setFloat(name, this._floats[name]);
-            }
-
-            // Float s   
-            for (name in this._floatsArrays) {
-                this._effect.setArray(name, this._floatsArrays[name]);
-            }
-
-            // Color3        
-            for (name in this._colors3) {
-                this._effect.setColor3(name, this._colors3[name]);
-            }
-
-            // Color4      
-            for (name in this._colors4) {
-                var color = this._colors4[name];
-                this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
-            }
-
-            // Vector2        
-            for (name in this._vectors2) {
-                this._effect.setVector2(name, this._vectors2[name]);
-            }
-
-            // Vector3        
-            for (name in this._vectors3) {
-                this._effect.setVector3(name, this._vectors3[name]);
+                this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
             }
+        }
 
-            // Matrix      
-            for (name in this._matrices) {
-                this._effect.setMatrix(name, this._matrices[name]);
-            }
+        public bind(world: Matrix): void {
+            // Std values
+            this.bindOnlyWorldMatrix(world);
+
+            if (this.getScene().getCachedMaterial() !== this) {
+                if (this._options.uniforms.indexOf("view") !== -1) {
+                    this._effect.setMatrix("view", this.getScene().getViewMatrix());
+                }
+
+                if (this._options.uniforms.indexOf("projection") !== -1) {
+                    this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
+                }
+
+                if (this._options.uniforms.indexOf("viewProjection") !== -1) {
+                    this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
+                }
+
+                // Texture
+                for (var name in this._textures) {
+                    this._effect.setTexture(name, this._textures[name]);
+                }
+
+                // Float    
+                for (name in this._floats) {
+                    this._effect.setFloat(name, this._floats[name]);
+                }
+
+                // Float s   
+                for (name in this._floatsArrays) {
+                    this._effect.setArray(name, this._floatsArrays[name]);
+                }
+
+                // Color3        
+                for (name in this._colors3) {
+                    this._effect.setColor3(name, this._colors3[name]);
+                }
+
+                // Color4      
+                for (name in this._colors4) {
+                    var color = this._colors4[name];
+                    this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
+                }
+
+                // Vector2        
+                for (name in this._vectors2) {
+                    this._effect.setVector2(name, this._vectors2[name]);
+                }
+
+                // Vector3        
+                for (name in this._vectors3) {
+                    this._effect.setVector3(name, this._vectors3[name]);
+                }
+
+                // Matrix      
+                for (name in this._matrices) {
+                    this._effect.setMatrix(name, this._matrices[name]);
+                }
+            }
+
+            super.bind(world, null);
         }
 
         public dispose(forceDisposeEffect?: boolean): void {

+ 163 - 139
Babylon/Materials/babylon.standardMaterial.ts

@@ -18,11 +18,11 @@
         public specularTexture: BaseTexture;
         public bumpTexture: BaseTexture;
 
-        public ambientColor = new BABYLON.Color3(0, 0, 0);
-        public diffuseColor = new BABYLON.Color3(1, 1, 1);
-        public specularColor = new BABYLON.Color3(1, 1, 1);
+        public ambientColor = new Color3(0, 0, 0);
+        public diffuseColor = new Color3(1, 1, 1);
+        public specularColor = new Color3(1, 1, 1);
         public specularPower = 64;
-        public emissiveColor = new BABYLON.Color3(0, 0, 0);
+        public emissiveColor = new Color3(0, 0, 0);
         public useAlphaFromDiffuseTexture = false;
         public useSpecularOverAlpha = true;
 		public fogEnabled = true;
@@ -33,11 +33,11 @@
         public emissiveFresnelParameters: FresnelParameters;
 
         private _cachedDefines = null;
-        private _renderTargets = new BABYLON.SmartArray<RenderTargetTexture>(16);
-        private _worldViewProjectionMatrix = BABYLON.Matrix.Zero();
-        private _globalAmbientColor = new BABYLON.Color3(0, 0, 0);
-        private _scaledDiffuse = new BABYLON.Color3();
-        private _scaledSpecular = new BABYLON.Color3();
+        private _renderTargets = new SmartArray<RenderTargetTexture>(16);
+        private _worldViewProjectionMatrix = Matrix.Zero();
+        private _globalAmbientColor = new Color3(0, 0, 0);
+        private _scaledDiffuse = new Color3();
+        private _scaledSpecular = new Color3();
         private _renderId: number;
 
         constructor(name: string, scene: Scene) {
@@ -92,7 +92,7 @@
 
             // Textures
             if (scene.texturesEnabled) {
-                if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
                     if (!this.diffuseTexture.isReady()) {
                         return false;
                     } else {
@@ -100,7 +100,7 @@
                     }
                 }
 
-                if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
+                if (this.ambientTexture && StandardMaterial.AmbientTextureEnabled) {
                     if (!this.ambientTexture.isReady()) {
                         return false;
                     } else {
@@ -108,7 +108,7 @@
                     }
                 }
 
-                if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
+                if (this.opacityTexture && StandardMaterial.OpacityTextureEnabled) {
                     if (!this.opacityTexture.isReady()) {
                         return false;
                     } else {
@@ -120,7 +120,7 @@
                     }
                 }
 
-                if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
+                if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
                     if (!this.reflectionTexture.isReady()) {
                         return false;
                     } else {
@@ -129,7 +129,7 @@
                     }
                 }
 
-                if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
+                if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
                     if (!this.emissiveTexture.isReady()) {
                         return false;
                     } else {
@@ -137,7 +137,7 @@
                     }
                 }
 
-                if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
+                if (this.specularTexture && StandardMaterial.SpecularTextureEnabled) {
                     if (!this.specularTexture.isReady()) {
                         return false;
                     } else {
@@ -147,7 +147,7 @@
                 }
             }
 
-            if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && BABYLON.StandardMaterial.BumpTextureEnabled) {
+            if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && StandardMaterial.BumpTextureEnabled) {
                 if (!this.bumpTexture.isReady()) {
                     return false;
                 } else {
@@ -175,12 +175,12 @@
             }
 
             // Point size
-            if (this.pointsCloud) {
+            if (this.pointsCloud || scene.forcePointsCloud) {
                 defines.push("#define POINTSIZE");
             }
 
             // Fog
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
                 defines.push("#define FOG");
                 fallbacks.addFallback(1, "FOG");
             }
@@ -232,9 +232,9 @@
                     }
 
                     var type;
-                    if (light instanceof BABYLON.SpotLight) {
+                    if (light instanceof SpotLight) {
                         type = "#define SPOTLIGHT" + lightIndex;
-                    } else if (light instanceof BABYLON.HemisphericLight) {
+                    } else if (light instanceof HemisphericLight) {
                         type = "#define HEMILIGHT" + lightIndex;
                     } else {
                         type = "#define POINTDIRLIGHT" + lightIndex;
@@ -274,70 +274,72 @@
                     }
 
                     lightIndex++;
-                    if (lightIndex == maxSimultaneousLights)
+                    if (lightIndex === maxSimultaneousLights)
                         break;
                 }
             }
 
-            // Fresnel
-            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled ||
-                this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled ||
-                this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled ||
-                this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+            if (StandardMaterial.FresnelEnabled) {
+                // Fresnel
+                if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled ||
+                    this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled ||
+                    this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled ||
+                    this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
 
-                var fresnelRank = 1;
+                    var fresnelRank = 1;
 
-                if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
-                    defines.push("#define DIFFUSEFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "DIFFUSEFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                        defines.push("#define DIFFUSEFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "DIFFUSEFRESNEL");
+                        fresnelRank++;
+                    }
 
-                if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
-                    defines.push("#define OPACITYFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "OPACITYFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
+                        defines.push("#define OPACITYFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "OPACITYFRESNEL");
+                        fresnelRank++;
+                    }
 
-                if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
-                    defines.push("#define REFLECTIONFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "REFLECTIONFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                        defines.push("#define REFLECTIONFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "REFLECTIONFRESNEL");
+                        fresnelRank++;
+                    }
 
-                if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
-                    defines.push("#define EMISSIVEFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "EMISSIVEFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
+                        defines.push("#define EMISSIVEFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "EMISSIVEFRESNEL");
+                        fresnelRank++;
+                    }
 
-                defines.push("#define FRESNEL");
-                fallbacks.addFallback(fresnelRank - 1, "FRESNEL");
+                    defines.push("#define FRESNEL");
+                    fallbacks.addFallback(fresnelRank - 1, "FRESNEL");
+                }
             }
 
 
             // Attribs
-            var attribs = [BABYLON.VertexBuffer.PositionKind, BABYLON.VertexBuffer.NormalKind];
+            var attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
             if (mesh) {
-                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                    attribs.push(BABYLON.VertexBuffer.UVKind);
+                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                    attribs.push(VertexBuffer.UVKind);
                     defines.push("#define UV1");
                 }
-                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                    attribs.push(BABYLON.VertexBuffer.UV2Kind);
+                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                    attribs.push(VertexBuffer.UV2Kind);
                     defines.push("#define UV2");
                 }
-                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                    attribs.push(BABYLON.VertexBuffer.ColorKind);
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
+                    attribs.push(VertexBuffer.ColorKind);
                     defines.push("#define VERTEXCOLOR");
 
                     if (mesh.hasVertexAlpha) {
                         defines.push("#define VERTEXALPHA");
                     }
                 }
-                if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
-                    attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
-                    attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
+                if (mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind)) {
+                    attribs.push(VertexBuffer.MatricesIndicesKind);
+                    attribs.push(VertexBuffer.MatricesWeightsKind);
                     defines.push("#define BONES");
                     defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
                     defines.push("#define BONES4");
@@ -356,9 +358,11 @@
 
             // Get correct effect      
             var join = defines.join("\n");
-            if (this._cachedDefines != join) {
+            if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
 
+                scene.resetCachedMaterial();
+
                 // Legacy browser patch
                 var shaderName = "default";
                 if (!scene.getEngine().getCaps().standardDerivatives) {
@@ -412,92 +416,119 @@
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
             // Bones
-            if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            if (mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind)) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
 
-            // Fresnel
-            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
-                this._effect.setColor4("diffuseLeftColor", this.diffuseFresnelParameters.leftColor, this.diffuseFresnelParameters.power);
-                this._effect.setColor4("diffuseRightColor", this.diffuseFresnelParameters.rightColor, this.diffuseFresnelParameters.bias);
-            }
+            if (scene.getCachedMaterial() !== this) {
 
-            if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
-                this._effect.setColor4("opacityParts", new BABYLON.Color3(this.opacityFresnelParameters.leftColor.toLuminance(), this.opacityFresnelParameters.rightColor.toLuminance(), this.opacityFresnelParameters.bias), this.opacityFresnelParameters.power);
-            }
+                if (StandardMaterial.FresnelEnabled) {
+                    // Fresnel
+                    if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                        this._effect.setColor4("diffuseLeftColor", this.diffuseFresnelParameters.leftColor, this.diffuseFresnelParameters.power);
+                        this._effect.setColor4("diffuseRightColor", this.diffuseFresnelParameters.rightColor, this.diffuseFresnelParameters.bias);
+                    }
 
-            if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
-                this._effect.setColor4("reflectionLeftColor", this.reflectionFresnelParameters.leftColor, this.reflectionFresnelParameters.power);
-                this._effect.setColor4("reflectionRightColor", this.reflectionFresnelParameters.rightColor, this.reflectionFresnelParameters.bias);
-            }
+                    if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
+                        this._effect.setColor4("opacityParts", new Color3(this.opacityFresnelParameters.leftColor.toLuminance(), this.opacityFresnelParameters.rightColor.toLuminance(), this.opacityFresnelParameters.bias), this.opacityFresnelParameters.power);
+                    }
 
-            if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
-                this._effect.setColor4("emissiveLeftColor", this.emissiveFresnelParameters.leftColor, this.emissiveFresnelParameters.power);
-                this._effect.setColor4("emissiveRightColor", this.emissiveFresnelParameters.rightColor, this.emissiveFresnelParameters.bias);
-            }
+                    if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                        this._effect.setColor4("reflectionLeftColor", this.reflectionFresnelParameters.leftColor, this.reflectionFresnelParameters.power);
+                        this._effect.setColor4("reflectionRightColor", this.reflectionFresnelParameters.rightColor, this.reflectionFresnelParameters.bias);
+                    }
 
-            // Textures        
-            if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
-                this._effect.setTexture("diffuseSampler", this.diffuseTexture);
+                    if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
+                        this._effect.setColor4("emissiveLeftColor", this.emissiveFresnelParameters.leftColor, this.emissiveFresnelParameters.power);
+                        this._effect.setColor4("emissiveRightColor", this.emissiveFresnelParameters.rightColor, this.emissiveFresnelParameters.bias);
+                    }
+                }
 
-                this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
-                this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
-            }
+                // Textures        
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._effect.setTexture("diffuseSampler", this.diffuseTexture);
 
-            if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
-                this._effect.setTexture("ambientSampler", this.ambientTexture);
+                    this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
+                    this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
+                }
 
-                this._effect.setFloat2("vAmbientInfos", this.ambientTexture.coordinatesIndex, this.ambientTexture.level);
-                this._effect.setMatrix("ambientMatrix", this.ambientTexture.getTextureMatrix());
-            }
+                if (this.ambientTexture && StandardMaterial.AmbientTextureEnabled) {
+                    this._effect.setTexture("ambientSampler", this.ambientTexture);
 
-            if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
-                this._effect.setTexture("opacitySampler", this.opacityTexture);
+                    this._effect.setFloat2("vAmbientInfos", this.ambientTexture.coordinatesIndex, this.ambientTexture.level);
+                    this._effect.setMatrix("ambientMatrix", this.ambientTexture.getTextureMatrix());
+                }
 
-                this._effect.setFloat2("vOpacityInfos", this.opacityTexture.coordinatesIndex, this.opacityTexture.level);
-                this._effect.setMatrix("opacityMatrix", this.opacityTexture.getTextureMatrix());
-            }
+                if (this.opacityTexture && StandardMaterial.OpacityTextureEnabled) {
+                    this._effect.setTexture("opacitySampler", this.opacityTexture);
 
-            if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
-                if (this.reflectionTexture.isCube) {
-                    this._effect.setTexture("reflectionCubeSampler", this.reflectionTexture);
-                } else {
-                    this._effect.setTexture("reflection2DSampler", this.reflectionTexture);
+                    this._effect.setFloat2("vOpacityInfos", this.opacityTexture.coordinatesIndex, this.opacityTexture.level);
+                    this._effect.setMatrix("opacityMatrix", this.opacityTexture.getTextureMatrix());
                 }
 
-                this._effect.setMatrix("reflectionMatrix", this.reflectionTexture.getReflectionTextureMatrix());
-                this._effect.setFloat3("vReflectionInfos", this.reflectionTexture.coordinatesMode, this.reflectionTexture.level, this.reflectionTexture.isCube ? 1 : 0);
-            }
+                if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
+                    if (this.reflectionTexture.isCube) {
+                        this._effect.setTexture("reflectionCubeSampler", this.reflectionTexture);
+                    } else {
+                        this._effect.setTexture("reflection2DSampler", this.reflectionTexture);
+                    }
 
-            if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
-                this._effect.setTexture("emissiveSampler", this.emissiveTexture);
+                    this._effect.setMatrix("reflectionMatrix", this.reflectionTexture.getReflectionTextureMatrix());
+                    this._effect.setFloat3("vReflectionInfos", this.reflectionTexture.coordinatesMode, this.reflectionTexture.level, this.reflectionTexture.isCube ? 1 : 0);
+                }
 
-                this._effect.setFloat2("vEmissiveInfos", this.emissiveTexture.coordinatesIndex, this.emissiveTexture.level);
-                this._effect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
-            }
+                if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
+                    this._effect.setTexture("emissiveSampler", this.emissiveTexture);
 
-            if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
-                this._effect.setTexture("specularSampler", this.specularTexture);
+                    this._effect.setFloat2("vEmissiveInfos", this.emissiveTexture.coordinatesIndex, this.emissiveTexture.level);
+                    this._effect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
+                }
 
-                this._effect.setFloat2("vSpecularInfos", this.specularTexture.coordinatesIndex, this.specularTexture.level);
-                this._effect.setMatrix("specularMatrix", this.specularTexture.getTextureMatrix());
-            }
+                if (this.specularTexture && StandardMaterial.SpecularTextureEnabled) {
+                    this._effect.setTexture("specularSampler", this.specularTexture);
+
+                    this._effect.setFloat2("vSpecularInfos", this.specularTexture.coordinatesIndex, this.specularTexture.level);
+                    this._effect.setMatrix("specularMatrix", this.specularTexture.getTextureMatrix());
+                }
+
+                if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled) {
+                    this._effect.setTexture("bumpSampler", this.bumpTexture);
 
-            if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && BABYLON.StandardMaterial.BumpTextureEnabled) {
-                this._effect.setTexture("bumpSampler", this.bumpTexture);
+                    this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level);
+                    this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
+                }
 
-                this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
-                this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
+                // Clip plane
+                if (scene.clipPlane) {
+                    var clipPlane = scene.clipPlane;
+                    this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+                }
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._effect.setFloat("pointSize", this.pointSize);
+                }
+
+                // Colors
+                scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
+
+                // Scaling down color according to emissive
+                this._scaledSpecular.r = this.specularColor.r * Tools.Clamp(1.0 - this.emissiveColor.r);
+                this._scaledSpecular.g = this.specularColor.g * Tools.Clamp(1.0 - this.emissiveColor.g);
+                this._scaledSpecular.b = this.specularColor.b * Tools.Clamp(1.0 - this.emissiveColor.b);
+
+                this._effect.setVector3("vEyePosition", scene.activeCamera.position);
+                this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
+                this._effect.setColor4("vSpecularColor", this._scaledSpecular, this.specularPower);
+                this._effect.setColor3("vEmissiveColor", this.emissiveColor);
             }
 
-            // Colors
-            scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
+            // Scaling down color according to emissive
+            this._scaledDiffuse.r = this.diffuseColor.r * Tools.Clamp(1.0 - this.emissiveColor.r);
+            this._scaledDiffuse.g = this.diffuseColor.g * Tools.Clamp(1.0 - this.emissiveColor.g);
+            this._scaledDiffuse.b = this.diffuseColor.b * Tools.Clamp(1.0 - this.emissiveColor.b);
 
-            this._effect.setVector3("vEyePosition", scene.activeCamera.position);
-            this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
-            this._effect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
-            this._effect.setColor4("vSpecularColor", this.specularColor, this.specularPower);
-            this._effect.setColor3("vEmissiveColor", this.emissiveColor);
+            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
 
             if (scene.lightsEnabled) {
                 var lightIndex = 0;
@@ -512,16 +543,16 @@
                         continue;
                     }
 
-                    if (light instanceof BABYLON.PointLight) {
+                    if (light instanceof PointLight) {
                         // Point Light
                         light.transferToEffect(this._effect, "vLightData" + lightIndex);
-                    } else if (light instanceof BABYLON.DirectionalLight) {
+                    } else if (light instanceof DirectionalLight) {
                         // Directional Light
                         light.transferToEffect(this._effect, "vLightData" + lightIndex);
-                    } else if (light instanceof BABYLON.SpotLight) {
+                    } else if (light instanceof SpotLight) {
                         // Spot Light
                         light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightDirection" + lightIndex);
-                    } else if (light instanceof BABYLON.HemisphericLight) {
+                    } else if (light instanceof HemisphericLight) {
                         // Hemispheric Light
                         light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightGround" + lightIndex);
                     }
@@ -543,31 +574,23 @@
 
                     lightIndex++;
 
-                    if (lightIndex == maxSimultaneousLights)
+                    if (lightIndex === maxSimultaneousLights)
                         break;
                 }
             }
 
-            if (scene.clipPlane) {
-                var clipPlane = scene.clipPlane;
-                this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-            }
-
             // View
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE || this.reflectionTexture) {
+            if (scene.fogEnabled && mesh.applyFog &&scene.fogMode !== Scene.FOGMODE_NONE || this.reflectionTexture) {
                 this._effect.setMatrix("view", scene.getViewMatrix());
             }
 
             // Fog
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) {
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
                 this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
                 this._effect.setColor3("vFogColor", scene.fogColor);
             }
 
-            // Point size
-            if (this.pointsCloud) {
-                this._effect.setFloat("pointSize", this.pointSize);
-            }
+            super.bind(world, mesh);
         }
 
         public getAnimatables(): IAnimatable[] {
@@ -637,7 +660,7 @@
         }
 
         public clone(name: string): StandardMaterial {
-            var newStandardMaterial = new BABYLON.StandardMaterial(name, this.getScene());
+            var newStandardMaterial = new StandardMaterial(name, this.getScene());
 
             // Base material
             newStandardMaterial.checkReadyOnEveryCall = this.checkReadyOnEveryCall;
@@ -686,5 +709,6 @@
         public static EmissiveTextureEnabled = true;
         public static SpecularTextureEnabled = true;
         public static BumpTextureEnabled = true;
+        public static FresnelEnabled = true;
     }
 } 

+ 71 - 59
Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.ts

@@ -1,48 +1,47 @@
 module BABYLON {
     export class CustomProceduralTexture extends ProceduralTexture {
-
-        private _generateTime: boolean = true;
+        private _animate: boolean = true;
         private _time: number = 0;
-        private _shaderLoaded: boolean = false;
         private _config: any;
-        private _texturePath: string;
-
-        constructor(name: string, texturePath: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
-            super(name, size, "empty", scene, fallbackTexture, generateMipMaps);
+        private _texturePath: any;
 
+        constructor(name: string, texturePath: any, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
+            super(name, size, null, scene, fallbackTexture, generateMipMaps);
             this._texturePath = texturePath;
 
-            //readJson
+            //Try to load json
             this.loadJson(texturePath);
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-            this.refreshRate = 0;
-
+            this.refreshRate = 1;
         }
 
-        private loadJson(jsonUrl: string) {
+        private loadJson(jsonUrl: string): void {
+            var that = this;
 
             function noConfigFile() {
-                BABYLON.Tools.Log("No config file found in " + jsonUrl);
+                BABYLON.Tools.Log("No config file found in " + jsonUrl + " trying to use ShaderStore or DOM element");
+                try {
+                    that.setFragment(that._texturePath);
+                }
+                catch (ex) {
+                    BABYLON.Tools.Error("No json or ShaderStore or DOM element found for CustomProceduralTexture");
+                }
             }
 
-            var that = this;
             var configFileUrl = jsonUrl + "/config.json";
-
             var xhr: XMLHttpRequest = new XMLHttpRequest();
 
             xhr.open("GET", configFileUrl, true);
             xhr.addEventListener("load", () => {
                 if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
                     try {
-                        that._config = JSON.parse(xhr.response);
-                        that.updateShaderUniforms();
-                        that.setFragment(jsonUrl + "/custom");
-                        that._generateTime = that._config.generateTime;
-                        if (that._generateTime)
-                            this.refreshRate = 1;
-                        that._shaderLoaded = true;
-                        that.render();
+                        this._config = JSON.parse(xhr.response);
+
+                        this.updateShaderUniforms();
+                        this.updateTextures();
+                        this.setFragment(this._texturePath + "/custom");
+
+                        this._animate = this._config.animate;
+                        this.refreshRate = this._config.refreshrate;
                     }
                     catch (ex) {
                         noConfigFile();
@@ -61,18 +60,28 @@
                 xhr.send();
             }
             catch (ex) {
-                BABYLON.Tools.Error("Error on XHR send request.");
+                BABYLON.Tools.Error("CustomProceduralTexture: Error on XHR send request.");
             }
         }
 
-        public render(useCameraPostProcess?: boolean) {
+        public isReady(): boolean {
+            if (!super.isReady()) {
+                return false;
+            }
 
-            //if config and shader not loaded, do not render
-            if (!this._shaderLoaded)
-                return;
+            for (var name in this._textures) {
+                var texture = this._textures[name];
 
+                if (!texture.isReady()) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
 
-            if (this._generateTime) {
+        public render(useCameraPostProcess?: boolean): void {
+            if (this._animate) {
                 this._time += this.getScene().getAnimationRatio() * 0.03;
                 this.updateShaderUniforms();
             }
@@ -80,43 +89,46 @@
             super.render(useCameraPostProcess);
         }
 
-        public updateShaderUniforms() {
-
-            for (var i = 0; i < this._config.texture2Ds.length; i++) {
-                this.setTexture(this._config.texture2Ds[i].textureName, new BABYLON.Texture(this._texturePath + "/" + this._config.texture2Ds[i].textureRelativeUrl, this.getScene()));
+        public updateTextures(): void {
+            for (var i = 0; i < this._config.sampler2Ds.length; i++) {
+                this.setTexture(this._config.sampler2Ds[i].sample2Dname, new Texture(this._texturePath + "/" + this._config.sampler2Ds[i].textureRelativeUrl, this.getScene()));
             }
+        }
 
-            for (var j = 0; j < this._config.uniforms.length; j++) {
-                var uniform = this._config.uniforms[j];
-
-                switch (uniform.type) {
-                    case "float":
-                        this.setFloat(uniform.name, uniform.value);
-                        break;
-                    case "color3":
-                        this.setColor3(uniform.name, new BABYLON.Color3(uniform.r, uniform.g, uniform.b));
-                        break;
-                    case "color4":
-                        this.setColor4(uniform.name, new BABYLON.Color4(uniform.r, uniform.g, uniform.b, uniform.a));
-                        break;
-                    case "vector2":
-                        this.setVector2(uniform.name, new BABYLON.Vector2(uniform.x, uniform.y));
-                        break;
-                    case "vector3":
-                        this.setVector3(uniform.name, new BABYLON.Vector3(uniform.x, uniform.y, uniform.z));
-                        break;
+        public updateShaderUniforms(): void {
+            if (this._config) {
+                for (var j = 0; j < this._config.uniforms.length; j++) {
+                    var uniform = this._config.uniforms[j];
+
+                    switch (uniform.type) {
+                        case "float":
+                            this.setFloat(uniform.name, uniform.value);
+                            break;
+                        case "color3":
+                            this.setColor3(uniform.name, new Color3(uniform.r, uniform.g, uniform.b));
+                            break;
+                        case "color4":
+                            this.setColor4(uniform.name, new Color4(uniform.r, uniform.g, uniform.b, uniform.a));
+                            break;
+                        case "vector2":
+                            this.setVector2(uniform.name, new Vector2(uniform.x, uniform.y));
+                            break;
+                        case "vector3":
+                            this.setVector3(uniform.name, new Vector3(uniform.x, uniform.y, uniform.z));
+                            break;
+                    }
                 }
             }
-        }
 
-        public get generateTime(): boolean {
-            return this.generateTime;
+            this.setFloat("time", this._time);
         }
 
-        public set generateTime(value: boolean) {
-            this.generateTime = value;
-            this.updateShaderUniforms();
+        public get animate(): boolean {
+            return this._animate;
         }
 
+        public set animate(value: boolean) {
+            this._animate = value;
+        }
     }
 }

+ 48 - 10
Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.ts

@@ -17,7 +17,7 @@
         private _samplers = new Array<string>();
         private _fragment: any;
 
-        private _textures = new Array<Texture>();
+        public _textures = new Array<Texture>();
         private _floats = new Array<number>();
         private _floatsArrays = {};
         private _colors3 = new Array<Color3>();
@@ -28,7 +28,9 @@
 
         private _fallbackTexture: Texture;
 
-        constructor(name: string, size: any, fragment: any, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
+        private _fallbackTextureUsed = false;
+
+        constructor(name: string, size: any, fragment: any, scene: Scene, fallbackTexture?: Texture, generateMipMaps = true) {
             super(null, scene, !generateMipMaps);
 
             scene._proceduralTextures.push(this);
@@ -38,7 +40,7 @@
             this._size = size;
             this._generateMipMaps = generateMipMaps;
 
-            this._fragment = fragment;
+            this.setFragment(fragment);
 
             this._fallbackTexture = fallbackTexture;
 
@@ -66,19 +68,47 @@
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
         }
 
-      
+        public reset(): void {
+            if (this._effect === undefined) {
+                return;
+            }
+            var engine = this.getScene().getEngine();
+            engine._releaseEffect(this._effect);
+        }
+
+
         public isReady(): boolean {
             var engine = this.getScene().getEngine();
+            var shaders;
+
+            if (!this._fragment) {
+                return false;
+            }
+
+            if (this._fallbackTextureUsed) {
+                return true;
+            }
+
+            if (this._fragment.fragmentElement !== undefined) {
+                shaders = { vertex: "procedural", fragmentElement: this._fragment.fragmentElement };
+            }
+            else {
+                shaders = { vertex: "procedural", fragment: this._fragment };
+            }
 
-            this._effect = engine.createEffect({ vertex: "procedural", fragment: this._fragment },
+            this._effect = engine.createEffect(shaders,
                 ["position"],
                 this._uniforms,
                 this._samplers,
                 "", null, null, () => {
                     this.releaseInternalTexture();
 
-                    this._texture = this._fallbackTexture._texture;
-                    this._texture.references++;
+                    if (this._fallbackTexture) {
+                        this._texture = this._fallbackTexture._texture;
+                        this._texture.references++;
+                    }
+
+                    this._fallbackTextureUsed = true;
                 });
 
             return this._effect.isReady();
@@ -107,12 +137,16 @@
                 return false;
             }
 
+            if (this._fallbackTextureUsed) {
+                return false;
+            }
+
             if (this._currentRefreshId === -1) { // At least render once
                 this._currentRefreshId = 1;
                 return true;
             }
 
-            if (this.refreshRate == this._currentRefreshId) {
+            if (this.refreshRate === this._currentRefreshId) {
                 this._currentRefreshId = 1;
                 return true;
             }
@@ -126,6 +160,10 @@
         }
 
         public resize(size, generateMipMaps) {
+            if (this._fallbackTextureUsed) {
+                return;
+            }
+
             this.releaseInternalTexture();
             this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
         }
@@ -217,7 +255,7 @@
                 this._effect.setFloat(name, this._floats[name]);
             }
 
-            // Float s   
+            // Floats   
             for (name in this._floatsArrays) {
                 this._effect.setArray(name, this._floatsArrays[name]);
             }
@@ -260,7 +298,7 @@
 
         public clone(): ProceduralTexture {
             var textureSize = this.getSize();
-            var newTexture = new BABYLON.ProceduralTexture(this.name, textureSize.width, this._fragment, this.getScene(), this._fallbackTexture, this._generateMipMaps);
+            var newTexture = new ProceduralTexture(this.name, textureSize.width, this._fragment, this.getScene(), this._fallbackTexture, this._generateMipMaps);
 
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;

+ 157 - 118
Babylon/Materials/textures/Procedurals/babylon.standardProceduralTexture.ts

@@ -1,17 +1,12 @@
 module BABYLON {
     export class WoodProceduralTexture extends ProceduralTexture {
-
         private _ampScale: number = 100.0;
-        private _woodColor: BABYLON.Color3 = new BABYLON.Color3(0.32, 0.17, 0.09);
+        private _woodColor: Color3 = new Color3(0.32, 0.17, 0.09);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "wood", scene, fallbackTexture, generateMipMaps);
-
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
-
         }
 
         public updateShaderUniforms() {
@@ -28,114 +23,101 @@
             this.updateShaderUniforms();
         }
 
-
-        public get woodColor(): BABYLON.Color3 {
+        public get woodColor(): Color3 {
             return this._woodColor;
         }
 
-        public set woodColor(value: BABYLON.Color3) {
+        public set woodColor(value: Color3) {
             this._woodColor = value;
             this.updateShaderUniforms();
         }
-
     }
 
     export class FireProceduralTexture extends ProceduralTexture {
-
         private _time: number = 0.0;
-        private _speed: BABYLON.Vector2 = new BABYLON.Vector2(0.5, 0.3);
+        private _speed = new Vector2(0.5, 0.3);
         private _shift: number = 1.6;
-        private _alpha: number = 1.0;
         private _autoGenerateTime: boolean = true;
-
-        private _fireColors: number[][];
+        private _fireColors: Color3[];
+        private _alphaThreshold: number = 0.5;
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "fire", scene, fallbackTexture, generateMipMaps);
-
             this._fireColors = FireProceduralTexture.RedFireColors;
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 1;
-
         }
 
         public updateShaderUniforms() {
-
-            this.setFloat("iGlobalTime", this._time);
+            this.setFloat("time", this._time);
             this.setVector2("speed", this._speed);
             this.setFloat("shift", this._shift);
-            this.setFloat("alpha", this._alpha);
-
-            this.setColor3("c1", new BABYLON.Color3(this._fireColors[0][0], this._fireColors[0][1], this._fireColors[0][2]));
-            this.setColor3("c2", new BABYLON.Color3(this._fireColors[1][0], this._fireColors[1][1], this._fireColors[1][2]));
-            this.setColor3("c3", new BABYLON.Color3(this._fireColors[2][0], this._fireColors[2][1], this._fireColors[2][2]));
-            this.setColor3("c4", new BABYLON.Color3(this._fireColors[3][0], this._fireColors[3][1], this._fireColors[3][2]));
-            this.setColor3("c5", new BABYLON.Color3(this._fireColors[4][0], this._fireColors[4][1], this._fireColors[4][2]));
-            this.setColor3("c6", new BABYLON.Color3(this._fireColors[5][0], this._fireColors[5][1], this._fireColors[5][2]));
-
+            this.setColor3("c1", this._fireColors[0]);
+            this.setColor3("c2", this._fireColors[1]);
+            this.setColor3("c3", this._fireColors[2]);
+            this.setColor3("c4", this._fireColors[3]);
+            this.setColor3("c5", this._fireColors[4]);
+            this.setColor3("c6", this._fireColors[5]);
+            this.setFloat("alphaThreshold", this._alphaThreshold);
         }
 
         public render(useCameraPostProcess?: boolean) {
-
             if (this._autoGenerateTime) {
                 this._time += this.getScene().getAnimationRatio() * 0.03;
                 this.updateShaderUniforms();
             }
-
             super.render(useCameraPostProcess);
         }
 
-        public static get PurpleFireColors(): number[][] {
+        public static get PurpleFireColors(): Color3[] {
             return [
-                [0.5, 0.0, 1.0],
-                [0.9, 0.0, 1.0],
-                [0.2, 0.0, 1.0],
-                [1.0, 0.9, 1.0],
-                [0.1, 0.1, 1.0],
-                [0.9, 0.9, 1.0]
+                new Color3(0.5, 0.0, 1.0),
+                new Color3(0.9, 0.0, 1.0),
+                new Color3(0.2, 0.0, 1.0),
+                new Color3(1.0, 0.9, 1.0),
+                new Color3(0.1, 0.1, 1.0),
+                new Color3(0.9, 0.9, 1.0)
             ];
         }
 
-        public static get GreenFireColors(): number[][] {
+        public static get GreenFireColors(): Color3[] {
             return [
-                [0.5, 1.0, 0.0],
-                [0.5, 1.0, 0.0],
-                [0.3, 0.4, 0.0],
-                [0.5, 1.0, 0.0],
-                [0.2, 0.0, 0.0],
-                [0.5, 1.0, 0.0]
+                new Color3(0.5, 1.0, 0.0),
+                new Color3(0.5, 1.0, 0.0),
+                new Color3(0.3, 0.4, 0.0),
+                new Color3(0.5, 1.0, 0.0),
+                new Color3(0.2, 0.0, 0.0),
+                new Color3(0.5, 1.0, 0.0)
             ];
         }
 
-        public static get RedFireColors(): number[][] {
+        public static get RedFireColors(): Color3[] {
             return [
-                [0.5, 0.0, 0.1],
-                [0.9, 0.0, 0.0],
-                [0.2, 0.0, 0.0],
-                [1.0, 0.9, 0.0],
-                [0.1, 0.1, 0.1],
-                [0.9, 0.9, 0.9]
+                new Color3(0.5, 0.0, 0.1),
+                new Color3(0.9, 0.0, 0.0),
+                new Color3(0.2, 0.0, 0.0),
+                new Color3(1.0, 0.9, 0.0),
+                new Color3(0.1, 0.1, 0.1),
+                new Color3(0.9, 0.9, 0.9)
             ];
         }
 
-        public static get BlueFireColors(): number[][] {
+        public static get BlueFireColors(): Color3[] {
             return [
-                [0.1, 0.0, 0.5],
-                [0.0, 0.0, 0.5],
-                [0.1, 0.0, 0.2],
-                [0.0, 0.0, 1.0],
-                [0.1, 0.2, 0.3],
-                [0.0, 0.2, 0.9]
+                new Color3(0.1, 0.0, 0.5),
+                new Color3(0.0, 0.0, 0.5),
+                new Color3(0.1, 0.0, 0.2),
+                new Color3(0.0, 0.0, 1.0),
+                new Color3(0.1, 0.2, 0.3),
+                new Color3(0.0, 0.2, 0.9)
             ];
         }
 
-        public get fireColors(): number[][] {
+        public get fireColors(): Color3[] {
             return this._fireColors;
         }
 
-        public set fireColors(value: number[][]) {
+        public set fireColors(value: Color3[]) {
             this._fireColors = value;
             this.updateShaderUniforms();
         }
@@ -149,11 +131,11 @@
             this.updateShaderUniforms();
         }
 
-        public get speed(): BABYLON.Vector2 {
+        public get speed(): Vector2 {
             return this._speed;
         }
 
-        public set speed(value: BABYLON.Vector2) {
+        public set speed(value: Vector2) {
             this._speed = value;
             this.updateShaderUniforms();
         }
@@ -167,114 +149,138 @@
             this.updateShaderUniforms();
         }
 
-        public get alpha(): number {
-            return this._alpha;
+        public get alphaThreshold(): number {
+            return this._alphaThreshold;
         }
 
-        public set alpha(value: number) {
-            this._alpha = value;
+        public set alphaThreshold(value: number) {
+            this._alphaThreshold = value;
             this.updateShaderUniforms();
         }
-
     }
 
     export class CloudProceduralTexture extends ProceduralTexture {
-
-        private _skyColor: BABYLON.Color3 = new BABYLON.Color3(0.15, 0.68, 1.0);
-        private _cloudColor: BABYLON.Color3 = new BABYLON.Color3(1, 1, 1);
+        private _skyColor = new Color3(0.15, 0.68, 1.0);
+        private _cloudColor = new Color3(1, 1, 1);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "cloud", scene, fallbackTexture, generateMipMaps);
-
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
-            // https://www.shadertoy.com/view/XsjSRt
         }
 
         public updateShaderUniforms() {
-
             this.setColor3("skyColor", this._skyColor);
             this.setColor3("cloudColor", this._cloudColor);
         }
 
-        public get skyColor(): BABYLON.Color3 {
+        public get skyColor(): Color3 {
             return this._skyColor;
         }
 
-        public set skyColor(value: BABYLON.Color3) {
+        public set skyColor(value: Color3) {
             this._skyColor = value;
             this.updateShaderUniforms();
         }
 
-        public get cloudColor(): BABYLON.Color3 {
+        public get cloudColor(): Color3 {
             return this._cloudColor;
         }
 
-        public set cloudColor(value: BABYLON.Color3) {
+        public set cloudColor(value: Color3) {
             this._cloudColor = value;
             this.updateShaderUniforms();
         }
     }
 
     export class GrassProceduralTexture extends ProceduralTexture {
+        private _grassColors: Color3[];
+        private _herb1 = new Color3(0.29, 0.38, 0.02);
+        private _herb2 = new Color3(0.36, 0.49, 0.09);
+        private _herb3 = new Color3(0.51, 0.6, 0.28);
+        private _groundColor = new Color3(1, 1, 1);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "grass", scene, fallbackTexture, generateMipMaps);
 
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-            this.refreshRate = 0;
+            this._grassColors = [
+                new Color3(0.29, 0.38, 0.02),
+                new Color3(0.36, 0.49, 0.09),
+                new Color3(0.51, 0.6, 0.28)
+            ];
 
+            this.updateShaderUniforms();
+            this.refreshRate = 0;
         }
-    }
 
+        public updateShaderUniforms() {
+            this.setColor3("herb1Color", this._grassColors[0]);
+            this.setColor3("herb2Color", this._grassColors[1]);
+            this.setColor3("herb3Color", this._grassColors[2]);
+            this.setColor3("groundColor", this._groundColor);
+        }
 
-    export class RockProceduralTexture extends ProceduralTexture {
+        public get grassColors(): Color3[] {
+            return this._grassColors;
+        }
 
-        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
-            super(name, size, "rock", scene, fallbackTexture, generateMipMaps);
+        public set grassColors(value: Color3[]) {
+            this._grassColors = value;
+            this.updateShaderUniforms();
+        }
 
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-            this.refreshRate = 0;
+        public get groundColor(): Color3 {
+            return this._groundColor;
+        }
 
+        public set groundColor(value: Color3) {
+            this.groundColor = value;
+            this.updateShaderUniforms();
         }
     }
 
     export class RoadProceduralTexture extends ProceduralTexture {
+        private _roadColor = new Color3(0.53, 0.53, 0.53);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "road", scene, fallbackTexture, generateMipMaps);
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
+            this.updateShaderUniforms();
             this.refreshRate = 0;
+        }
 
+        public updateShaderUniforms() {
+            this.setColor3("roadColor", this._roadColor);
         }
-    }
 
+        public get roadColor(): Color3 {
+            return this._roadColor;
+        }
 
-    export class BrickProceduralTexture extends ProceduralTexture {
+        public set roadColor(value: Color3) {
+            this._roadColor = value;
+            this.updateShaderUniforms();
+        }
+    }
 
+    export class BrickProceduralTexture extends ProceduralTexture {
         private _numberOfBricksHeight: number = 15;
         private _numberOfBricksWidth: number = 5;
+        private _jointColor = new Color3(0.72, 0.72, 0.72);
+        private _brickColor = new Color3(0.77, 0.47, 0.40);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "brick", scene, fallbackTexture, generateMipMaps);
-
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
-
         }
 
         public updateShaderUniforms() {
-
             this.setFloat("numberOfBricksHeight", this._numberOfBricksHeight);
             this.setFloat("numberOfBricksWidth", this._numberOfBricksWidth);
+            this.setColor3("brickColor", this._brickColor);
+            this.setColor3("jointColor", this._jointColor);
         }
 
-
         public get numberOfBricksHeight(): number {
             return this._numberOfBricksHeight;
         }
@@ -292,48 +298,81 @@
             this._numberOfBricksHeight = value;
             this.updateShaderUniforms();
         }
-    }
 
+        public get jointColor(): Color3 {
+            return this._jointColor;
+        }
 
-    export class MarbleProceduralTexture extends ProceduralTexture {
+        public set jointColor(value: Color3) {
+            this._jointColor = value;
+            this.updateShaderUniforms();
+        }
+
+        public get brickColor(): Color3 {
+            return this._brickColor;
+        }
+
+        public set brickColor(value: Color3) {
+            this._brickColor = value;
+            this.updateShaderUniforms();
+        }
+    }
 
-        private _numberOfBricksHeight: number = 3;
-        private _numberOfBricksWidth: number = 3;
+    export class MarbleProceduralTexture extends ProceduralTexture {
+        private _numberOfTilesHeight: number = 3;
+        private _numberOfTilesWidth: number = 3;
+        private _amplitude: number = 9.0;
+        private _marbleColor = new Color3(0.77, 0.47, 0.40);
+        private _jointColor = new Color3(0.72, 0.72, 0.72);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "marble", scene, fallbackTexture, generateMipMaps);
-
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
-
         }
 
         public updateShaderUniforms() {
+            this.setFloat("numberOfTilesHeight", this._numberOfTilesHeight);
+            this.setFloat("numberOfTilesWidth", this._numberOfTilesWidth);
+            this.setFloat("amplitude", this._amplitude);
+            this.setColor3("marbleColor", this._marbleColor);
+            this.setColor3("jointColor", this._jointColor);
+        }
 
-            this.setFloat("numberOfBricksHeight", this._numberOfBricksHeight);
-            this.setFloat("numberOfBricksWidth", this._numberOfBricksWidth);
+        public get numberOfTilesHeight(): number {
+            return this._numberOfTilesHeight;
         }
 
-        public get numberOfBricksHeight(): number {
-            return this._numberOfBricksHeight;
+        public set numberOfTilesHeight(value: number) {
+            this._numberOfTilesHeight = value;
+            this.updateShaderUniforms();
         }
 
-        public set cloudColor(value: number) {
-            this._numberOfBricksHeight = value;
+        public get numberOfTilesWidth(): number {
+            return this._numberOfTilesWidth;
+        }
+
+        public set numberOfTilesWidth(value: number) {
+            this._numberOfTilesWidth = value;
             this.updateShaderUniforms();
         }
 
-        public get numberOfBricksWidth(): number {
-            return this._numberOfBricksWidth;
+        public get jointColor(): Color3 {
+            return this._jointColor;
         }
 
-        public set numberOfBricksWidth(value: number) {
-            this._numberOfBricksHeight = value;
+        public set jointColor(value: Color3) {
+            this._jointColor = value;
             this.updateShaderUniforms();
         }
 
-    }
+        public get marbleColor(): Color3 {
+            return this._marbleColor;
+        }
 
+        public set marbleColor(value: Color3) {
+            this._marbleColor = value;
+            this.updateShaderUniforms();
+        }
+    }
 }

+ 7 - 7
Babylon/Materials/textures/babylon.baseTexture.ts

@@ -1,18 +1,18 @@
 module BABYLON {
     export class BaseTexture {
         public name: string;
-        public delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
+        public delayLoadState = Engine.DELAYLOADSTATE_NONE;
         public hasAlpha = false;
         public getAlphaFromRGB = false;
         public level = 1;
-        public isCube = false
+        public isCube = false;
         public isRenderTarget = false;
         public animations = new Array<Animation>();
         public onDispose: () => void;
         public coordinatesIndex = 0;
-        public coordinatesMode = BABYLON.Texture.EXPLICIT_MODE;
-        public wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-        public wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+        public coordinatesMode = Texture.EXPLICIT_MODE;
+        public wrapU = Texture.WRAP_ADDRESSMODE;
+        public wrapV = Texture.WRAP_ADDRESSMODE;
         public anisotropicFilteringLevel = 4;
         public _cachedAnisotropicFilteringLevel: number;
 
@@ -41,7 +41,7 @@
         }
 
         public isReady(): boolean {
-            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
+            if (this.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) {
                 return true;
             }
 
@@ -119,7 +119,7 @@
             this._texture.references--;
 
             // Final reference ?
-            if (this._texture.references == 0) {
+            if (this._texture.references === 0) {
                 var index = texturesCache.indexOf(this._texture);
                 texturesCache.splice(index, 1);
 

+ 0 - 226
Babylon/Materials/textures/babylon.proceduralTexture.js

@@ -1,226 +0,0 @@
-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 ProceduralTexture = (function (_super) {
-        __extends(ProceduralTexture, _super);
-        function ProceduralTexture(name, size, fragment, scene, generateMipMaps) {
-            _super.call(this, null, scene, !generateMipMaps);
-            this._currentRefreshId = -1;
-            this._refreshRate = 1;
-            this._vertexDeclaration = [2];
-            this._vertexStrideSize = 2 * 4;
-            this._uniforms = new Array();
-            this._samplers = new Array();
-            this._textures = new Array();
-            this._floats = new Array();
-            this._floatsArrays = {};
-            this._colors3 = new Array();
-            this._colors4 = new Array();
-            this._vectors2 = new Array();
-            this._vectors3 = new Array();
-            this._matrices = new Array();
-
-            scene._proceduralTextures.push(this);
-
-            this.name = name;
-            this.isRenderTarget = true;
-            this._size = size;
-            this._generateMipMaps = generateMipMaps;
-
-            this._fragment = fragment;
-
-            this._texture = scene.getEngine().createRenderTargetTexture(size, generateMipMaps);
-
-            // VBO
-            var vertices = [];
-            vertices.push(1, 1);
-            vertices.push(-1, 1);
-            vertices.push(-1, -1);
-            vertices.push(1, -1);
-
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
-
-            // Indices
-            var indices = [];
-            indices.push(0);
-            indices.push(1);
-            indices.push(2);
-
-            indices.push(0);
-            indices.push(2);
-            indices.push(3);
-
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
-        }
-        ProceduralTexture.prototype.isReady = function () {
-            var engine = this.getScene().getEngine();
-
-            this._effect = engine.createEffect({ vertex: "procedural", fragment: this._fragment }, ["position"], this._uniforms, this._samplers, "");
-
-            return this._effect.isReady();
-        };
-
-        ProceduralTexture.prototype.resetRefreshCounter = function () {
-            this._currentRefreshId = -1;
-        };
-
-        Object.defineProperty(ProceduralTexture.prototype, "refreshRate", {
-            get: function () {
-                return this._refreshRate;
-            },
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-            set: function (value) {
-                this._refreshRate = value;
-                this.resetRefreshCounter();
-            },
-            enumerable: true,
-            configurable: true
-        });
-
-
-        ProceduralTexture.prototype._shouldRender = function () {
-            if (this._currentRefreshId === -1) {
-                this._currentRefreshId = 1;
-                return true;
-            }
-
-            if (this.refreshRate == this._currentRefreshId) {
-                this._currentRefreshId = 1;
-                return true;
-            }
-
-            this._currentRefreshId++;
-            return false;
-        };
-
-        ProceduralTexture.prototype.getRenderSize = function () {
-            return this._size;
-        };
-
-        ProceduralTexture.prototype.resize = function (size, generateMipMaps) {
-            this.releaseInternalTexture();
-            this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
-        };
-
-        ProceduralTexture.prototype._checkUniform = function (uniformName) {
-            if (this._uniforms.indexOf(uniformName) === -1) {
-                this._uniforms.push(uniformName);
-            }
-        };
-
-        ProceduralTexture.prototype.setTexture = function (name, texture) {
-            if (this._samplers.indexOf(name) === -1) {
-                this._samplers.push(name);
-            }
-            this._textures[name] = texture;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.setFloat = function (name, value) {
-            this._checkUniform(name);
-            this._floats[name] = value;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.setFloats = function (name, value) {
-            this._checkUniform(name);
-            this._floatsArrays[name] = value;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.setColor3 = function (name, value) {
-            this._checkUniform(name);
-            this._colors3[name] = value;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.setColor4 = function (name, value) {
-            this._checkUniform(name);
-            this._colors4[name] = value;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.setVector2 = function (name, value) {
-            this._checkUniform(name);
-            this._vectors2[name] = value;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.setVector3 = function (name, value) {
-            this._checkUniform(name);
-            this._vectors3[name] = value;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.setMatrix = function (name, value) {
-            this._checkUniform(name);
-            this._matrices[name] = value;
-
-            return this;
-        };
-
-        ProceduralTexture.prototype.render = function (useCameraPostProcess) {
-            if (!this.isReady() || !this._texture)
-                return;
-
-            var scene = this.getScene();
-            var engine = scene.getEngine();
-
-            engine.bindFramebuffer(this._texture);
-
-            // Clear
-            engine.clear(scene.clearColor, true, true);
-
-            // Render
-            engine.enableEffect(this._effect);
-            engine.setState(false);
-
-            // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
-
-            // Draw order
-            engine.draw(true, 0, 6);
-
-            // Unbind
-            engine.unBindFramebuffer(this._texture);
-        };
-
-        ProceduralTexture.prototype.clone = function () {
-            var textureSize = this.getSize();
-            var newTexture = new BABYLON.ProceduralTexture(this.name, textureSize.width, this._fragment, this.getScene(), this._generateMipMaps);
-
-            // Base texture
-            newTexture.hasAlpha = this.hasAlpha;
-            newTexture.level = this.level;
-
-            // RenderTarget Texture
-            newTexture.coordinatesMode = this.coordinatesMode;
-
-            return newTexture;
-        };
-
-        ProceduralTexture.prototype.dispose = function () {
-            var index = this.getScene()._proceduralTextures.indexOf(this);
-
-            if (index >= 0) {
-                this.getScene()._proceduralTextures.splice(index, 1);
-            }
-            _super.prototype.dispose.call(this);
-        };
-        return ProceduralTexture;
-    })(BABYLON.Texture);
-    BABYLON.ProceduralTexture = ProceduralTexture;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.proceduralTexture.js.map

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

@@ -130,7 +130,7 @@
 
                         for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
                             var subMesh = mesh.subMeshes[subIndex];
-                            scene._activeVertices += subMesh.verticesCount;
+                            scene._activeVertices += subMesh.indexCount;
                             this._renderingManager.dispatch(subMesh);
                         }
                     }

+ 2 - 0
Babylon/Materials/textures/babylon.texture.ts

@@ -167,6 +167,8 @@
                 this._projectionModeMatrix = BABYLON.Matrix.Zero();
             }
 
+            this._cachedCoordinatesMode = this.coordinatesMode;
+
             switch (this.coordinatesMode) {
                 case BABYLON.Texture.SPHERICAL_MODE:
                     BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);

+ 58 - 0
Babylon/Math/babylon.math.ts

@@ -403,6 +403,7 @@
             return new Vector2(x, y);
         }
 
+
         public static Dot(left: Vector2, right: Vector2): number {
             return left.x * right.x + left.y * right.y;
         }
@@ -444,6 +445,7 @@
 
             return (x * x) + (y * y);
         }
+
     }
 
     export class Vector3 {
@@ -823,6 +825,21 @@
             return Vector3.TransformCoordinates(vector, finalMatrix);
         }
 
+        public static UnprojectFromTransform(source: Vector3, viewportWidth: number, viewportHeight: number, world: Matrix, transform: Matrix): Vector3 {
+            var matrix = world.multiply(transform);
+            matrix.invert();
+            source.x = source.x / viewportWidth * 2 - 1;
+            source.y = -(source.y / viewportHeight * 2 - 1);
+            var vector = BABYLON.Vector3.TransformCoordinates(source, matrix);
+            var num = source.x * matrix.m[3] + source.y * matrix.m[7] + source.z * matrix.m[11] + matrix.m[15];
+
+            if (BABYLON.Tools.WithinEpsilon(num, 1.0)) {
+                vector = vector.scale(1.0 / num);
+            }
+
+            return vector;
+        }
+
         public static Unproject(source: Vector3, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Vector3 {
             var matrix = world.multiply(view).multiply(projection);
             matrix.invert();
@@ -2306,6 +2323,10 @@
                 var min = (minimum.x - this.origin.x) * inv;
                 var max = (maximum.x - this.origin.x) * inv;
 
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     var temp = min;
                     min = max;
@@ -2330,6 +2351,10 @@
                 min = (minimum.y - this.origin.y) * inv;
                 max = (maximum.y - this.origin.y) * inv;
 
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;
@@ -2354,6 +2379,10 @@
                 min = (minimum.z - this.origin.z) * inv;
                 max = (maximum.z - this.origin.z) * inv;
 
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;
@@ -2484,4 +2513,33 @@
         public static Y: Vector3 = new BABYLON.Vector3(0, 1, 0);
         public static Z: Vector3 = new BABYLON.Vector3(0, 0, 1);
     };
+
+    export class BezierCurve {
+
+        public static interpolate(t: number, x1: number, y1: number, x2: number, y2: number): number {
+
+            // Extract X (which is equal to time here)
+            var f0 = 1 - 3 * x2 + 3 * x1;
+            var f1 = 3 * x2 - 6 * x1;
+            var f2 = 3 * x1;
+
+            var refinedT = t;
+            for (var i = 0; i < 5; i++) {
+                var refinedT2 = refinedT * refinedT;
+                var refinedT3 = refinedT2 * refinedT;
+
+                var x = f0 * refinedT3 + f1 * refinedT2 + f2 * refinedT;
+                var slope = 1.0 / (3.0 * f0 * refinedT2 + 2.0 * f1 * refinedT + f2);
+                refinedT -= (x - t) * slope;
+                refinedT = Math.min(1, Math.max(0, refinedT));
+
+            }
+
+            // Resolve cubic bezier for the given x
+            return 3 * Math.pow(1 - refinedT, 2) * refinedT * y1 +
+                3 * (1 - refinedT) * Math.pow(refinedT, 2) * y2 +
+                Math.pow(refinedT, 3);
+
+        }
+    }
 }

+ 13 - 2
Babylon/Mesh/babylon.InstancedMesh.ts

@@ -1,6 +1,7 @@
 module BABYLON {
     export class InstancedMesh extends AbstractMesh {
         private _sourceMesh: Mesh;
+        private _currentLOD: Mesh;
 
         constructor(name: string, source: Mesh) {
             super(name, source.getScene());
@@ -78,11 +79,21 @@
         }
 
         public _preActivate(): void {
-            this.sourceMesh._preActivate();
+            if (this._currentLOD) {
+                this._currentLOD._preActivate();
+            }
         }
 
         public _activate(renderId: number): void {
-            this.sourceMesh._registerInstanceForRenderId(this, renderId);
+            if (this._currentLOD) {
+                this._currentLOD._registerInstanceForRenderId(this, renderId);
+            }
+        }
+
+        public getLOD(camera: Camera): AbstractMesh {
+            this._currentLOD = <Mesh>this.sourceMesh.getLOD(this.getScene().activeCamera, this.getBoundingInfo().boundingSphere);
+
+            return this._currentLOD
         }
 
         public _syncSubMeshes(): void {

+ 51 - 7
Babylon/Mesh/babylon.abstractMesh.ts

@@ -28,12 +28,13 @@
         }
 
         // Properties
-        public position = new BABYLON.Vector3(0, 0, 0);
-        public rotation = new BABYLON.Vector3(0, 0, 0);
+        public position = new Vector3(0, 0, 0);
+        public rotation = new Vector3(0, 0, 0);
         public rotationQuaternion: Quaternion;
-        public scaling = new BABYLON.Vector3(1, 1, 1);
-        public billboardMode = BABYLON.AbstractMesh.BILLBOARDMODE_NONE;
+        public scaling = new Vector3(1, 1, 1);
+        public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
         public visibility = 1.0;
+        public alphaIndex = Number.MAX_VALUE;
         public infiniteDistance = false;
         public isVisible = true;
         public isPickable = true;
@@ -50,7 +51,12 @@
         public renderOutline = false;
         public outlineColor = BABYLON.Color3.Red();
         public outlineWidth = 0.02;
+        public renderOverlay = false;
+        public overlayColor = BABYLON.Color3.Red();
+        public overlayAlpha = 0.5;
         public hasVertexAlpha = false;
+        public useVertexColors = true;
+        public applyFog = true;
 
         public useOctreeForRenderingSelection = true;
         public useOctreeForPicking = true;
@@ -87,6 +93,7 @@
         private _collisionsScalingMatrix = BABYLON.Matrix.Zero();
         public _positions: Vector3[];
         private _isDirty = false;
+        public _masterMesh: AbstractMesh;
 
         public _boundingInfo: BoundingInfo;
         private _pivotMatrix = BABYLON.Matrix.Identity();
@@ -97,6 +104,8 @@
         public _submeshesOctree: Octree<SubMesh>;
         public _intersectionsInProgress = new Array<AbstractMesh>();
 
+        private _onAfterWorldMatrixUpdate = new Array<(mesh: BABYLON.AbstractMesh) => void>();
+
         constructor(name: string, scene: Scene) {
             super(name, scene);
 
@@ -129,6 +138,10 @@
         }
 
         public getBoundingInfo(): BoundingInfo {
+            if (this._masterMesh) {
+                return this._masterMesh.getBoundingInfo();
+            }
+
             if (!this._boundingInfo) {
                 this._updateBoundingInfo();
             }
@@ -143,6 +156,10 @@
         }
 
         public getWorldMatrix(): Matrix {
+            if (this._masterMesh) {
+                return this._masterMesh.getWorldMatrix();
+            }
+
             if (this._currentRenderId !== this.getScene().getRenderId()) {
                 this.computeWorldMatrix();
             }
@@ -298,6 +315,10 @@
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
+            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+        }
+
+        public _updateSubMeshesBoundingInfo(matrix: Matrix): void {
             if (!this.subMeshes) {
                 return;
             }
@@ -305,7 +326,7 @@
             for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
                 var subMesh = this.subMeshes[subIndex];
 
-                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+                subMesh.updateBoundingInfo(matrix);
             }
         }
 
@@ -395,9 +416,30 @@
             // Absolute position
             this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
 
+            // Callbacks
+            for (var callbackIndex = 0; callbackIndex < this._onAfterWorldMatrixUpdate.length; callbackIndex++) {
+                this._onAfterWorldMatrixUpdate[callbackIndex](this);
+            }
+
             return this._worldMatrix;
         }
 
+        /**
+        * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
+        * @param func: callback function to add
+        */
+        public registerAfterWorldMatrixUpdate(func: (mesh: BABYLON.AbstractMesh) => void): void {
+            this._onAfterWorldMatrixUpdate.push(func);
+        }
+
+        public unregisterAfterWorldMatrixUpdate(func: (mesh: BABYLON.AbstractMesh) => void): void {
+            var index = this._onAfterWorldMatrixUpdate.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterWorldMatrixUpdate.splice(index, 1);
+            }
+        }
+
         public setPositionWithLocalVector(vector3: Vector3): void {
             this.computeWorldMatrix();
 
@@ -549,12 +591,12 @@
             return Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
         }
 
-        public getDistanceToCamera(camera?: Camera): Vector3 {
+        public getDistanceToCamera(camera?: Camera): number {
             if (!camera) {
                 camera = this.getScene().activeCamera;
             }
 
-            return this.absolutePosition.subtract(camera.position);
+            return this.absolutePosition.subtract(camera.position).length();
         }
 
         public applyImpulse(force: Vector3, contactPoint: Vector3): void {
@@ -818,6 +860,8 @@
                 }
             }
 
+            this._onAfterWorldMatrixUpdate = [];
+
             this._isDisposed = true;
 
             // Callback

+ 13 - 8
Babylon/Mesh/babylon.geometry.ts

@@ -83,14 +83,14 @@
             }
         }
 
-        public updateVerticesDataDirectly(kind: string, data: Float32Array): void {
+        public updateVerticesDataDirectly(kind: string, data: Float32Array, offset: number): void {
             var vertexBuffer = this.getVertexBuffer(kind);
 
             if (!vertexBuffer) {
                 return;
             }
 
-            vertexBuffer.updateDirectly(data);
+            vertexBuffer.updateDirectly(data, offset);
         }
 
         public updateVerticesData(kind: string, data: number[], updateExtends?: boolean): void {
@@ -102,14 +102,15 @@
 
             vertexBuffer.update(data);
 
-            if (kind === BABYLON.VertexBuffer.PositionKind) {
+            if (kind === VertexBuffer.PositionKind) {
 
                 var extend;
 
+                var stride = vertexBuffer.getStrideSize();
+                this._totalVertices = data.length / stride;
+
                 if (updateExtends) {
-                    var stride = vertexBuffer.getStrideSize();
-                    this._totalVertices = data.length / stride;
-                    extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
+                    extend = Tools.ExtractMinAndMax(data, 0, this._totalVertices);
                 }
 
                 var meshes = this._meshes;
@@ -119,7 +120,7 @@
                     var mesh = meshes[index];
                     mesh._resetPointsArrayCache();
                     if (updateExtends) {
-                        mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                        mesh._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
                     }
                 }
             }
@@ -180,7 +181,7 @@
             return result;
         }
 
-        public setIndices(indices: number[]): void {
+        public setIndices(indices: number[], totalVertices?: number): void {
             if (this._indexBuffer) {
                 this._engine._releaseBuffer(this._indexBuffer);
             }
@@ -190,6 +191,10 @@
                 this._indexBuffer = this._engine.createIndexBuffer(this._indices);
             }
 
+            if (totalVertices !== undefined) {
+                this._totalVertices = totalVertices;
+            }
+
             var meshes = this._meshes;
             var numOfMeshes = meshes.length;
 

+ 47 - 38
Babylon/Mesh/babylon.mesh.ts

@@ -27,13 +27,16 @@
         private _instancesBufferSize = 32 * 16 * 4; // let's start with a maximum of 32 instances
         public _shouldGenerateFlatShading: boolean;
         private _preActivateId: number;
-        private _attachedLODLevel: BABYLON.Internals.MeshLODLevel;
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
         }
 
         // Methods
+        public get hasLODLevels(): boolean {
+            return this._LODLevels.length > 0;
+        }
+
         private _sortLODLevels(): void {
             this._LODLevels.sort((a, b) => {
                 if (a.distance < b.distance) {
@@ -48,11 +51,16 @@
         }
 
         public addLODLevel(distance: number, mesh: Mesh): Mesh {
+            if (mesh && mesh._masterMesh) {
+                Tools.Warn("You cannot use a mesh as LOD level twice");
+                return this;
+            }
+
             var level = new BABYLON.Internals.MeshLODLevel(distance, mesh);
             this._LODLevels.push(level);
 
             if (mesh) {
-                mesh._attachedLODLevel = level;
+                mesh._masterMesh = this;
             }
 
             this._sortLODLevels();
@@ -61,37 +69,26 @@
         }
 
         public removeLODLevel(mesh: Mesh): Mesh {
-            if (mesh && !mesh._attachedLODLevel) {
-                return this;
-            }
-
-            var index;
-
-            if (mesh) {
-                index = this._LODLevels.indexOf(mesh._attachedLODLevel);
-                mesh._attachedLODLevel = null;
-
-                this._LODLevels.splice(index, 1);
 
-                this._sortLODLevels();
-            } else {
-                for (index = 0; index < this._LODLevels.length; index++) {
-                    if (this._LODLevels[index].mesh === null) {
-                        this._LODLevels.splice(index, 1);
-                        break;
+            for (var index = 0; index < this._LODLevels.length; index++) {
+                if (this._LODLevels[index].mesh === mesh) {
+                    this._LODLevels.splice(index, 1);
+                    if (mesh) {
+                        mesh._masterMesh = null;
                     }
                 }
             }
 
+            this._sortLODLevels();
             return this;
         }
 
-        public getLOD(camera: Camera): AbstractMesh {
+        public getLOD(camera: Camera, boundingSphere?: BoundingSphere): AbstractMesh {
             if (!this._LODLevels || this._LODLevels.length === 0) {
                 return this;
             }
 
-            var distanceToCamera = this.getBoundingInfo().boundingSphere.centerWorld.subtract(camera.position).length();
+            var distanceToCamera = (boundingSphere ? boundingSphere : this.getBoundingInfo().boundingSphere).centerWorld.subtract(camera.position).length();
 
             if (this._LODLevels[this._LODLevels.length - 1].distance > distanceToCamera) {
                 return this;
@@ -101,8 +98,10 @@
                 var level = this._LODLevels[index];
 
                 if (level.distance < distanceToCamera) {
+
                     if (level.mesh) {
-                        level.mesh._worldMatrix = this._worldMatrix;
+                        level.mesh._preActivate();
+                        level.mesh._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
                     }
                     return level.mesh;
                 }
@@ -174,7 +173,7 @@
         }
 
         public get isBlocked(): boolean {
-            return this._attachedLODLevel !== null && this._attachedLODLevel !== undefined;
+            return this._masterMesh !== null && this._masterMesh !== undefined;
         }
 
         public isReady(): boolean {
@@ -215,11 +214,11 @@
         }
 
         public refreshBoundingInfo(): void {
-            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            var data = this.getVerticesData(VertexBuffer.PositionKind);
 
             if (data) {
-                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices());
-                this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                var extend = Tools.ExtractMinAndMax(data, 0, this.getTotalVertices());
+                this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
             }
 
             if (this.subMeshes) {
@@ -238,7 +237,7 @@
             }
 
             this.releaseSubMeshes();
-            return new BABYLON.SubMesh(0, 0, totalVertices, 0, this.getTotalIndices(), this);
+            return new SubMesh(0, 0, totalVertices, 0, this.getTotalIndices(), this);
         }
 
         public subdivide(count: number): void {
@@ -304,16 +303,16 @@
             }
         }
 
-        public updateVerticesDataDirectly(kind: string, data: Float32Array, makeItUnique?: boolean): void {
+        public updateVerticesDataDirectly(kind: string, data: Float32Array, offset?: number, makeItUnique?: boolean): void {
             if (!this._geometry) {
                 return;
             }
             if (!makeItUnique) {
-                this._geometry.updateVerticesDataDirectly(kind, data);
+                this._geometry.updateVerticesDataDirectly(kind, data, offset);
             }
             else {
                 this.makeGeometryUnique();
-                this.updateVerticesDataDirectly(kind, data, false);
+                this.updateVerticesDataDirectly(kind, data, offset, false);
             }
         }
 
@@ -325,17 +324,17 @@
             geometry.applyToMesh(this);
         }
 
-        public setIndices(indices: number[]): void {
+        public setIndices(indices: number[], totalVertices?: number): void {
             if (!this._geometry) {
-                var vertexData = new BABYLON.VertexData();
+                var vertexData = new VertexData();
                 vertexData.indices = indices;
 
                 var scene = this.getScene();
 
-                new BABYLON.Geometry(BABYLON.Geometry.RandomId(), scene, vertexData, false, this);
+                new Geometry(Geometry.RandomId(), scene, vertexData, false, this);
             }
             else {
-                this._geometry.setIndices(indices);
+                this._geometry.setIndices(indices, totalVertices);
             }
         }
 
@@ -442,7 +441,8 @@
         }
 
         public _renderWithInstances(subMesh: SubMesh, fillMode: number, batch: _InstancesBatch, effect: Effect, engine: Engine): void {
-            var matricesCount = this.instances.length + 1;
+            var visibleInstances = batch.visibleInstances[subMesh._id];
+            var matricesCount = visibleInstances.length + 1;
             var bufferSize = matricesCount * 16 * 4;
 
             while (this._instancesBufferSize < bufferSize) {
@@ -468,7 +468,6 @@
                 instancesCount++;
             }
 
-            var visibleInstances = batch.visibleInstances[subMesh._id];
 
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
@@ -513,7 +512,7 @@
             }
 
             var engine = scene.getEngine();
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
 
             // Material
             var effectiveMaterial = subMesh.getMaterial();
@@ -527,16 +526,18 @@
             if (this.renderOutline) {
                 engine.setDepthWrite(false);
                 scene.getOutlineRenderer().render(subMesh, batch);
+                engine.setDepthWrite(savedDepthWrite);
             }
 
             effectiveMaterial._preBind();
             var effect = effectiveMaterial.getEffect();
 
             // Bind
-            var fillMode = engine.forceWireframe ? Material.WireFrameFillMode : effectiveMaterial.fillMode;
+            var fillMode = scene.forcePointsCloud ? Material.PointFillMode : (scene.forceWireframe ? Material.WireFrameFillMode : effectiveMaterial.fillMode);
             this._bind(subMesh, effect, fillMode);
 
             var world = this.getWorldMatrix();
+
             effectiveMaterial.bind(world, this);
 
             // Instances rendering
@@ -572,6 +573,14 @@
                 engine.setColorWrite(true);
             }
 
+            // Overlay
+            if (this.renderOverlay) {
+                var currentMode = engine.getAlphaMode();
+                engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                scene.getOutlineRenderer().render(subMesh, batch, true);
+                engine.setAlphaMode(currentMode);
+            }
+
             for (callbackIndex = 0; callbackIndex < this._onAfterRenderCallbacks.length; callbackIndex++) {
                 this._onAfterRenderCallbacks[callbackIndex]();
             }

+ 1 - 0
Babylon/Mesh/babylon.subMesh.ts

@@ -11,6 +11,7 @@
         public _lastColliderTransformMatrix: Matrix;
 
         public _renderId = 0;
+        public _alphaIndex: number;
         public _distanceToCamera: number;
         public _id: number;
 

+ 2 - 2
Babylon/Mesh/babylon.vertexBuffer.ts

@@ -100,13 +100,13 @@
             this.create(data);
         }
 
-        public updateDirectly(data: Float32Array): void {
+        public updateDirectly(data: Float32Array, offset: number): void {
             if (!this._buffer) {
                 return;
             }
 
             if (this._updatable) { // update buffer
-                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+                this._engine.updateDynamicVertexBuffer(this._buffer, data, offset);
                 this._data = null;
             }
         }

+ 30 - 29
Babylon/Particles/babylon.particleSystem.ts

@@ -1,6 +1,6 @@
 module BABYLON {
     var randomNumber = (min: number, max: number): number => {
-        if (min == max) {
+        if (min === max) {
             return (min);
         }
 
@@ -39,19 +39,19 @@
 
         public onDispose: () => void;
 
-        public blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;
+        public blendMode = ParticleSystem.BLENDMODE_ONEONE;
 
         public forceDepthWrite = false;
 
-        public gravity = BABYLON.Vector3.Zero();
-        public direction1 = new BABYLON.Vector3(0, 1.0, 0);
-        public direction2 = new BABYLON.Vector3(0, 1.0, 0);
-        public minEmitBox = new BABYLON.Vector3(-0.5, -0.5, -0.5);
-        public maxEmitBox = new BABYLON.Vector3(0.5, 0.5, 0.5);
-        public color1 = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);
-        public color2 = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);
-        public colorDead = new BABYLON.Color4(0, 0, 0, 1.0);
-        public textureMask = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);
+        public gravity = Vector3.Zero();
+        public direction1 = new Vector3(0, 1.0, 0);
+        public direction2 = new Vector3(0, 1.0, 0);
+        public minEmitBox = new Vector3(-0.5, -0.5, -0.5);
+        public maxEmitBox = new Vector3(0.5, 0.5, 0.5);
+        public color1 = new Color4(1.0, 1.0, 1.0, 1.0);
+        public color2 = new Color4(1.0, 1.0, 1.0, 1.0);
+        public colorDead = new Color4(0, 0, 0, 1.0);
+        public textureMask = new Color4(1.0, 1.0, 1.0, 1.0);
         public startDirectionFunction: (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3) => void;
         public startPositionFunction: (worldMatrix: Matrix, positionToUpdate: Vector3) => void;
 
@@ -70,10 +70,10 @@
         private _customEffect: Effect;
         private _cachedDefines: string;
 
-        private _scaledColorStep = new BABYLON.Color4(0, 0, 0, 0);
-        private _colorDiff = new BABYLON.Color4(0, 0, 0, 0);
-        private _scaledDirection = BABYLON.Vector3.Zero();
-        private _scaledGravity = BABYLON.Vector3.Zero();
+        private _scaledColorStep = new Color4(0, 0, 0, 0);
+        private _colorDiff = new Color4(0, 0, 0, 0);
+        private _scaledDirection = Vector3.Zero();
+        private _scaledGravity = Vector3.Zero();
         private _currentRenderId = -1;
 
         private _alive: boolean;
@@ -117,7 +117,7 @@
                 var randY = randomNumber(this.direction1.y, this.direction2.y);
                 var randZ = randomNumber(this.direction1.z, this.direction2.z);
 
-                BABYLON.Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+                Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
             }
 
             this.startPositionFunction = (worldMatrix: Matrix, positionToUpdate: Vector3): void => {
@@ -125,7 +125,7 @@
                 var randY = randomNumber(this.minEmitBox.y, this.maxEmitBox.y);
                 var randZ = randomNumber(this.minEmitBox.z, this.maxEmitBox.z);
 
-                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
+                Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
             }
         }
 
@@ -201,11 +201,11 @@
             if (this.emitter.position) {
                 worldMatrix = this.emitter.getWorldMatrix();
             } else {
-                worldMatrix = BABYLON.Matrix.Translation(this.emitter.x, this.emitter.y, this.emitter.z);
+                worldMatrix = Matrix.Translation(this.emitter.x, this.emitter.y, this.emitter.z);
             }
 
             for (index = 0; index < newParticles; index++) {
-                if (this.particles.length == this._capacity) {
+                if (this.particles.length === this._capacity) {
                     break;
                 }
 
@@ -213,7 +213,7 @@
                     particle = this._stockParticles.pop();
                     particle.age = 0;
                 } else {
-                    particle = new BABYLON.Particle();
+                    particle = new Particle();
                 }
                 this.particles.push(particle);
 
@@ -230,7 +230,7 @@
 
                 var step = randomNumber(0, 1.0);
 
-                BABYLON.Color4.LerpToRef(this.color1, this.color2, step, particle.color);
+                Color4.LerpToRef(this.color1, this.color2, step, particle.color);
 
                 this.colorDead.subtractToRef(particle.color, this._colorDiff);
                 this._colorDiff.scaleToRef(1.0 / particle.lifeTime, particle.colorStep);
@@ -250,7 +250,7 @@
 
             // Effect
             var join = defines.join("\n");
-            if (this._cachedDefines != join) {
+            if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
 
                 this._effect = this._scene.getEngine().createEffect(
@@ -347,6 +347,7 @@
 
             // Render
             engine.enableEffect(effect);
+            engine.setState(false);
 
             var viewMatrix = this._scene.getViewMatrix();
             effect.setTexture("diffuseSampler", this.particleTexture);
@@ -366,10 +367,10 @@
             engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
 
             // Draw order
-            if (this.blendMode === BABYLON.ParticleSystem.BLENDMODE_ONEONE) {
-                engine.setAlphaMode(BABYLON.Engine.ALPHA_ADD);
+            if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
+                engine.setAlphaMode(Engine.ALPHA_ADD);
             } else {
-                engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                engine.setAlphaMode(Engine.ALPHA_COMBINE);
             }
 
             if (this.forceDepthWrite) {
@@ -377,7 +378,7 @@
             }
 
             engine.draw(true, 0, this.particles.length * 6);
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+            engine.setAlphaMode(Engine.ALPHA_DISABLE);
 
             return this.particles.length;
         }
@@ -410,9 +411,9 @@
 
         // Clone
         public clone(name: string, newEmitter: any): ParticleSystem {
-            var result = new BABYLON.ParticleSystem(name, this._capacity, this._scene);
+            var result = new ParticleSystem(name, this._capacity, this._scene);
 
-            BABYLON.Tools.DeepCopy(this, result, ["particles"], ["_vertexDeclaration", "_vertexStrideSize"]);
+            Tools.DeepCopy(this, result, ["particles"], ["_vertexDeclaration", "_vertexStrideSize"]);
 
             if (newEmitter === undefined) {
                 newEmitter = this.emitter;
@@ -420,7 +421,7 @@
 
             result.emitter = newEmitter;
             if (this.particleTexture) {
-                result.particleTexture = new BABYLON.Texture(this.particleTexture.url, this._scene);
+                result.particleTexture = new Texture(this.particleTexture.url, this._scene);
             }
 
             result.start();

+ 10 - 8
Babylon/Rendering/babylon.boundingBoxRenderer.ts

@@ -1,9 +1,9 @@
 module BABYLON {
     export class BoundingBoxRenderer {
-        public frontColor = new BABYLON.Color3(1, 1, 1);
-        public backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
+        public frontColor = new Color3(1, 1, 1);
+        public backColor = new Color3(0.1, 0.1, 0.1);
         public showBackLines = true;
-        public renderList = new BABYLON.SmartArray<BoundingBox>(32);
+        public renderList = new SmartArray<BoundingBox>(32);
 
         private _scene: Scene;
         private _colorShader: ShaderMaterial;
@@ -21,8 +21,8 @@
 
 
             var engine = this._scene.getEngine();
-            var boxdata = BABYLON.VertexData.CreateBox(1.0);
-            this._vb = new BABYLON.VertexBuffer(engine, boxdata.positions, BABYLON.VertexBuffer.PositionKind, false);
+            var boxdata = VertexData.CreateBox(1.0);
+            this._vb = new VertexBuffer(engine, boxdata.positions, VertexBuffer.PositionKind, false);
             this._ib = engine.createIndexBuffer([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4]);
         }
 
@@ -31,7 +31,7 @@
         }
 
         public render(): void {
-            if (this.renderList.length == 0 || !this._colorShader.isReady()) {
+            if (this.renderList.length === 0 || !this._colorShader.isReady()) {
                 return;
             }
 
@@ -45,8 +45,8 @@
                 var diff = max.subtract(min);
                 var median = min.add(diff.scale(0.5));
 
-                var worldMatrix = BABYLON.Matrix.Scaling(diff.x, diff.y, diff.z)
-                    .multiply(BABYLON.Matrix.Translation(median.x, median.y, median.z))
+                var worldMatrix = Matrix.Scaling(diff.x, diff.y, diff.z)
+                    .multiply(Matrix.Translation(median.x, median.y, median.z))
                     .multiply(boundingBox.getWorldMatrix());
 
                 // VBOs
@@ -55,6 +55,7 @@
                 if (this.showBackLines) {
                     // Back
                     engine.setDepthFunctionToGreaterOrEqual();
+                    this._scene.resetCachedMaterial();
                     this._colorShader.setColor4("color", this.backColor.toColor4());
                     this._colorShader.bind(worldMatrix);
 
@@ -64,6 +65,7 @@
 
                 // Front
                 engine.setDepthFunctionToLess();
+                this._scene.resetCachedMaterial();
                 this._colorShader.setColor4("color", this.frontColor.toColor4());
                 this._colorShader.bind(worldMatrix);
 

+ 5 - 6
Babylon/Rendering/babylon.outlineRenderer.ts

@@ -8,11 +8,11 @@
             this._scene = scene;
         }
 
-        public render(subMesh: SubMesh, batch: _InstancesBatch) {
+        public render(subMesh: SubMesh, batch: _InstancesBatch, useOverlay: boolean = false) {
             var scene = this._scene;
             var engine = this._scene.getEngine();
 
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
 
             if (!this.isReady(subMesh, hardwareInstancedRendering)) {
                 return;
@@ -22,12 +22,12 @@
             var material = subMesh.getMaterial();
 
             engine.enableEffect(this._effect);
-            this._effect.setFloat("offset", mesh.outlineWidth);
-            this._effect.setColor3("color", mesh.outlineColor);
+            this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth);
+            this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : 1.0);
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
             // Bones
-            var useBones = mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
+            var useBones = mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
             if (useBones) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
@@ -41,7 +41,6 @@
                 this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
             }
 
-
             if (hardwareInstancedRendering) {
                 mesh._renderWithInstances(subMesh, Material.TriangleFillMode, batch, this._effect, engine);
             } else {

+ 12 - 7
Babylon/Rendering/babylon.renderingGroup.ts

@@ -11,7 +11,7 @@
         }
 
         public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents: () => void) => void,
-                      beforeTransparents): boolean {
+            beforeTransparents): boolean {
             if (customRenderFunction) {
                 customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes, beforeTransparents);
                 return true;
@@ -27,7 +27,6 @@
 
             for (subIndex = 0; subIndex < this._opaqueSubMeshes.length; subIndex++) {
                 submesh = this._opaqueSubMeshes.data[subIndex];
-                this._activeVertices += submesh.verticesCount;
 
                 submesh.render();
             }
@@ -36,7 +35,6 @@
             engine.setAlphaTesting(true);
             for (subIndex = 0; subIndex < this._alphaTestSubMeshes.length; subIndex++) {
                 submesh = this._alphaTestSubMeshes.data[subIndex];
-                this._activeVertices += submesh.verticesCount;
 
                 submesh.render();
             }
@@ -51,12 +49,22 @@
                 // Sorting
                 for (subIndex = 0; subIndex < this._transparentSubMeshes.length; subIndex++) {
                     submesh = this._transparentSubMeshes.data[subIndex];
+                    submesh._alphaIndex = submesh.getMesh().alphaIndex;
                     submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(this._scene.activeCamera.position).length();
                 }
 
                 var sortedArray = this._transparentSubMeshes.data.slice(0, this._transparentSubMeshes.length);
 
                 sortedArray.sort((a, b) => {
+                    // Alpha index first
+                    if (a._alphaIndex > b._alphaIndex) {
+                        return 1;
+                    }
+                    if (a._alphaIndex < b._alphaIndex) {
+                        return -1;
+                    }
+
+                    // Then distance to camera
                     if (a._distanceToCamera < b._distanceToCamera) {
                         return 1;
                     }
@@ -71,7 +79,6 @@
                 engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
                 for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
                     submesh = sortedArray[subIndex];
-                    this._activeVertices += submesh.verticesCount;
 
                     submesh.render();
                 }
@@ -92,9 +99,7 @@
             var mesh = subMesh.getMesh();
 
             if (material.needAlphaBlending() || mesh.visibility < 1.0 || mesh.hasVertexAlpha) { // Transparent
-                if (material.alpha > 0 || mesh.visibility < 1.0) {
-                    this._transparentSubMeshes.push(subMesh);
-                }
+                this._transparentSubMeshes.push(subMesh);
             } else if (material.needAlphaTesting()) { // Alpha test
                 this._alphaTestSubMeshes.push(subMesh);
             } else {

+ 2 - 3
Babylon/Rendering/babylon.renderingManager.ts

@@ -74,11 +74,10 @@
                         }
                     })) {
                         this._renderingGroups.splice(index, 1);
+                    } else if (renderSprites) {
+                        this._renderSprites(index);
                     }
-                } else if (renderSprites) {
-                    this._renderSprites(index);
                 }
-
                 if (renderParticles) {
                     this._renderParticles(index, activeMeshes);
                 }

+ 8 - 19
Babylon/Shaders/brick.fragment.fx

@@ -7,6 +7,8 @@ varying vec2 vUV;
 
 uniform float numberOfBricksHeight;
 uniform float numberOfBricksWidth;
+uniform vec3 brickColor;
+uniform vec3 jointColor;
 
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
@@ -34,20 +36,13 @@ float round(float number){
 
 void main(void)
 {
-	vec3 brick = vec3(0.77, 0.47, 0.40);
-	vec3 joint = vec3(0.72, 0.72, 0.72);
-
 	float brickW = 1.0 / numberOfBricksWidth;
 	float brickH = 1.0 / numberOfBricksHeight;
 	float jointWPercentage = 0.01;
 	float jointHPercentage = 0.05;
-
-	vec3 color = brick;
-
-
+	vec3 color = brickColor;
 	float yi = vUV.y / brickH;
 	float nyi = round(yi);
-
 	float xi = vUV.x / brickW;
 
 	if (mod(floor(yi), 2.0) == 0.0){
@@ -55,28 +50,22 @@ void main(void)
 	}
 
 	float nxi = round(xi);
-
 	vec2 brickvUV = vec2((xi - floor(xi)) / brickH, (yi - floor(yi)) /  brickW);
 
-
 	if (yi < nyi + jointHPercentage && yi > nyi - jointHPercentage){
-		color = mix(joint, vec3(0.37, 0.25, 0.25), (yi - nyi) / jointHPercentage + 0.2);
+		color = mix(jointColor, vec3(0.37, 0.25, 0.25), (yi - nyi) / jointHPercentage + 0.2);
 	}
 	else if (xi < nxi + jointWPercentage && xi > nxi - jointWPercentage){
-		color = mix(joint, vec3(0.44, 0.44, 0.44), (xi - nxi) / jointWPercentage + 0.2);
+		color = mix(jointColor, vec3(0.44, 0.44, 0.44), (xi - nxi) / jointWPercentage + 0.2);
 	}
 	else {
-		float momo = mod(floor(yi) + floor(xi), 3.0);
+		float brickColorSwitch = mod(floor(yi) + floor(xi), 3.0);
 
-		if (momo == 0.0)
+		if (brickColorSwitch == 0.0)
 			color = mix(color, vec3(0.33, 0.33, 0.33), 0.3);
-		else if (momo == 2.0)
+		else if (brickColorSwitch == 2.0)
 			color = mix(color, vec3(0.11, 0.11, 0.11), 0.3);
-
-
-		//color = mix(momo, vec3(0.53, 0.2, 0.0), fbm(brickvUV * 2.0));
 	}
 
-
 	gl_FragColor = vec4(color, 1.0);
 }

+ 2 - 2
Babylon/Shaders/default.fragment.fx

@@ -317,9 +317,9 @@ mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)
 
 vec3 perturbNormal(vec3 viewDir)
 {
-	vec3 map = texture2D(bumpSampler, vBumpUV).xyz * vBumpInfos.y;
+	vec3 map = texture2D(bumpSampler, vBumpUV).xyz;
 	map = map * 255. / 127. - 128. / 127.;
-	mat3 TBN = cotangent_frame(vNormalW, -viewDir, vBumpUV);
+	mat3 TBN = cotangent_frame(vNormalW * vBumpInfos.y, -viewDir, vBumpUV);
 	return normalize(TBN * map);
 }
 #endif

+ 7 - 6
Babylon/Shaders/fire.fragment.fx

@@ -2,7 +2,7 @@
 precision highp float;
 #endif
 
-uniform float iGlobalTime;
+uniform float time;
 uniform vec3 c1;
 uniform vec3 c2;
 uniform vec3 c3;
@@ -11,7 +11,7 @@ uniform vec3 c5;
 uniform vec3 c6;
 uniform vec2 speed;
 uniform float shift;
-uniform float alpha;
+uniform float alphaThreshold;
 
 varying vec2 vUV;
 
@@ -36,11 +36,12 @@ float fbm(vec2 n) {
 }
 
 void main() {
-
 	vec2 p = vUV * 8.0;
-	float q = fbm(p - iGlobalTime * 0.1);
-	vec2 r = vec2(fbm(p + q + iGlobalTime * speed.x - p.x - p.y), fbm(p + q - iGlobalTime * speed.y));
+	float q = fbm(p - time * 0.1);
+	vec2 r = vec2(fbm(p + q + time * speed.x - p.x - p.y), fbm(p + q - time * speed.y));
 	vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y);
-	gl_FragColor = vec4(c * cos(shift * vUV.y), alpha);
+	vec3 color = c * cos(shift * vUV.y);
+	float luminance = dot(color.rgb, vec3(0.3, 0.59, 0.11));
 
+	gl_FragColor = vec4(color, luminance * alphaThreshold + (1.0 - alphaThreshold));
 }

+ 9 - 14
Babylon/Shaders/grass.fragment.fx

@@ -5,6 +5,10 @@ precision highp float;
 varying vec2 vPosition;
 varying vec2 vUV;
 
+uniform vec3 herb1Color;
+uniform vec3 herb2Color;
+uniform vec3 herb3Color;
+uniform vec3 groundColor;
 
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
@@ -27,18 +31,9 @@ float fbm(vec2 n) {
 }
 
 void main(void) {
-
-	vec3 herb1 = vec3(0.29, 0.38, 0.02);
-	vec3 herb2 = vec3(0.36, 0.49, 0.09);
-	vec3 herb3 = vec3(0.51, 0.6, 0.28);
-	vec3 dirt = vec3(0.6, 0.46, 0.13);
-
-	vec3 ground = vec3(1,1,1);
-	
-	ground = mix(ground, herb1, rand(gl_FragCoord.xy * 4.0));
-	ground = mix(ground, herb2, rand(gl_FragCoord.xy * 8.0));
-	ground = mix(ground, herb3, rand(gl_FragCoord.xy));
-	ground = mix(ground, herb1, fbm(gl_FragCoord.xy * 16.0));
-
-	gl_FragColor = vec4(ground, 1.0);
+	vec3 color = mix(groundColor, herb1Color, rand(gl_FragCoord.xy * 4.0));
+	color = mix(color, herb2Color, rand(gl_FragCoord.xy * 8.0));
+	color = mix(color, herb3Color, rand(gl_FragCoord.xy));
+	color = mix(color, herb1Color, fbm(gl_FragCoord.xy * 16.0));
+	gl_FragColor = vec4(color, 1.0);
 }

+ 11 - 28
Babylon/Shaders/marble.fragment.fx

@@ -5,14 +5,15 @@ precision highp float;
 varying vec2 vPosition;
 varying vec2 vUV;
 
-
-uniform float numberOfBricksHeight;
-uniform float numberOfBricksWidth ;
+uniform float numberOfTilesHeight;
+uniform float numberOfTilesWidth;
+uniform float amplitude;
+uniform vec3 brickColor;
+uniform vec3 jointColor;
 
 const vec3 tileSize = vec3(1.1, 1.0, 1.1);
 const vec3 tilePct = vec3(0.98, 1.0, 0.98);
 
-
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
 }
@@ -39,7 +40,6 @@ float round(float number){
 	return sign(number)*floor(abs(number) + 0.5);
 }
 
-
 vec3 marble_color(float x)
 {
 	vec3 col;
@@ -51,23 +51,16 @@ vec3 marble_color(float x)
 	col.b *= 0.95;           
 	return col;
 }
+
 void main()
 {
-
-	vec3 brick = vec3(0.77, 0.47, 0.40);
-	vec3 joint = vec3(0.72, 0.72, 0.72);
-
-	float brickW = 1.0 / numberOfBricksWidth;
-	float brickH = 1.0 / numberOfBricksHeight;
+	float brickW = 1.0 / numberOfTilesWidth;
+	float brickH = 1.0 / numberOfTilesHeight;
 	float jointWPercentage = 0.01;
 	float jointHPercentage = 0.01;
-
-	vec3 color = brick;
-
-
+	vec3 color = brickColor;
 	float yi = vUV.y / brickH;
 	float nyi = round(yi);
-
 	float xi = vUV.x / brickW;
 
 	if (mod(floor(yi), 2.0) == 0.0){
@@ -75,30 +68,20 @@ void main()
 	}
 
 	float nxi = round(xi);
-
 	vec2 brickvUV = vec2((xi - floor(xi)) / brickH, (yi - floor(yi)) / brickW);
 
-
 	if (yi < nyi + jointHPercentage && yi > nyi - jointHPercentage){
-		color = mix(joint, vec3(0.37, 0.25, 0.25), (yi - nyi) / jointHPercentage + 0.2);
+		color = mix(jointColor, vec3(0.37, 0.25, 0.25), (yi - nyi) / jointHPercentage + 0.2);
 	}
 	else if (xi < nxi + jointWPercentage && xi > nxi - jointWPercentage){
-		color = mix(joint, vec3(0.44, 0.44, 0.44), (xi - nxi) / jointWPercentage + 0.2);
+		color = mix(jointColor, vec3(0.44, 0.44, 0.44), (xi - nxi) / jointWPercentage + 0.2);
 	}
 	else {
-
-		float amplitude = 9.0;
-
 		float t = 6.28 * brickvUV.x / (tileSize.x + noise(vec2(vUV)*6.0));
 		t += amplitude * turbulence(brickvUV.xy);
-
 		t = sin(t);
 		color = marble_color(t);
-
-
 	}
 
 	gl_FragColor = vec4(color, 0.0);
-
-	
 }

+ 2 - 2
Babylon/Shaders/outline.fragment.fx

@@ -1,6 +1,6 @@
 precision highp float;
 
-uniform vec3 color;
+uniform vec4 color;
 
 #ifdef ALPHATEST
 varying vec2 vUV;
@@ -13,5 +13,5 @@ void main(void) {
 		discard;
 #endif
 
-	gl_FragColor = vec4(color, 1.);
+	gl_FragColor = color;
 }

+ 3 - 8
Babylon/Shaders/road.fragment.fx

@@ -3,6 +3,7 @@ precision highp float;
 #endif
 
 varying vec2 vUV;                    
+uniform vec3 roadColor;
 
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
@@ -25,13 +26,7 @@ float fbm(vec2 n) {
 }
 
 void main(void) {
-
-
-	vec3 gray = vec3(0.53, 0.53, 0.53);
-
 	float ratioy = mod(gl_FragCoord.y * 100.0 , fbm(vUV * 2.0));
-		
-	gray = gray * ratioy;
-
-	gl_FragColor = vec4(gray, 1.0);
+	vec3 color = roadColor * ratioy;
+	gl_FragColor = vec4(color, 1.0);
 }

+ 0 - 3
Babylon/Shaders/wood.fragment.fx

@@ -8,7 +8,6 @@ varying vec2 vUV;
 uniform float ampScale;
 uniform vec3 woodColor;
 
-
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
 }
@@ -30,9 +29,7 @@ float fbm(vec2 n) {
 }
 
 void main(void) {
-
 	float ratioy = mod(vUV.x * ampScale, 2.0 + fbm(vUV * 0.8));
 	vec3 wood = woodColor * ratioy;
-
 	gl_FragColor = vec4(wood, 1.0);
 }

+ 2 - 2
Babylon/Sprites/babylon.spriteManager.ts

@@ -125,7 +125,7 @@
             // Render
             var effect = this._effectBase;
 
-            if (this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (this._scene.fogEnabled && this._scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
                 effect = this._effectFog;
             }
 
@@ -139,7 +139,7 @@
             effect.setFloat2("textureInfos", this.cellSize / baseSize.width, this.cellSize / baseSize.height);
 
             // Fog
-            if (this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (this._scene.fogEnabled && this._scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
                 effect.setFloat4("vFogInfos", this._scene.fogMode, this._scene.fogStart, this._scene.fogEnd, this._scene.fogDensity);
                 effect.setColor3("vFogColor", this._scene.fogColor);
             }

+ 39 - 5
Babylon/Tools/babylon.tools.ts

@@ -312,7 +312,14 @@
             }
         }
 
-        // Misc.        
+        // Misc.   
+        public static Clamp(value:number, min = 0, max = 1): number {
+            return Math.min(max, Math.max(min, value));
+        }     
+
+        public static Format(value: number, decimals: number = 2): string {
+            return value.toFixed(decimals);
+        }
 
         public static CheckExtends(v: Vector3, min: Vector3, max: Vector3): void {
             if (v.x < min.x)
@@ -612,6 +619,9 @@
         private static _MessageLogLevel = 1;
         private static _WarningLogLevel = 2;
         private static _ErrorLogLevel = 4;
+        private static _LogCache = "";
+
+        public static OnNewCacheEntry: (entry: string) => void;
 
         static get NoneLogLevel(): number {
             return Tools._NoneLogLevel;
@@ -633,11 +643,19 @@
             return Tools._MessageLogLevel | Tools._WarningLogLevel | Tools._ErrorLogLevel;
         }
 
+        private static _AddLogEntry(entry: string) {
+            Tools._LogCache = entry + Tools._LogCache;
+
+            if (Tools.OnNewCacheEntry) {
+                Tools.OnNewCacheEntry(entry);
+            }
+        }
+
         private static _FormatMessage(message: string): string {
             var padStr = i => (i < 10) ? "0" + i : "" + i;
 
             var date = new Date();
-            return "BJS - [" + padStr(date.getHours()) + ":" + padStr(date.getMinutes()) + ":" + padStr(date.getSeconds()) + "]: " + message;
+            return "[" + padStr(date.getHours()) + ":" + padStr(date.getMinutes()) + ":" + padStr(date.getSeconds()) + "]: " + message;
         }
 
         public static Log: (message: string) => void = Tools._LogEnabled;
@@ -646,7 +664,11 @@
             // nothing to do
         }
         private static _LogEnabled(message: string): void {
-            console.log(Tools._FormatMessage(message));
+            var formattedMessage = Tools._FormatMessage(message);
+            console.log("BJS - " + formattedMessage);
+
+            var entry = "<div style='color:white'>" + formattedMessage + "</div><br>";
+            Tools._AddLogEntry(entry);
         }
 
         public static Warn: (message: string) => void = Tools._WarnEnabled;
@@ -655,7 +677,11 @@
             // nothing to do
         }
         private static _WarnEnabled(message: string): void {
-            console.warn(Tools._FormatMessage(message));
+            var formattedMessage = Tools._FormatMessage(message);
+            console.warn("BJS - " + formattedMessage);
+
+            var entry = "<div style='color:orange'>" + formattedMessage + "</div><br>";
+            Tools._AddLogEntry(entry);
         }
 
         public static Error: (message: string) => void = Tools._ErrorEnabled;
@@ -664,7 +690,15 @@
             // nothing to do
         }
         private static _ErrorEnabled(message: string): void {
-            console.error(Tools._FormatMessage(message));
+            var formattedMessage = Tools._FormatMessage(message);
+            console.error("BJS - " + formattedMessage);
+
+            var entry = "<div style='color:red'>" + formattedMessage + "</div><br>";
+            Tools._AddLogEntry(entry);
+        }
+
+        public static get LogCache(): string {
+            return Tools._LogCache;
         }
 
         public static set LogLevels(level: number) {

+ 39 - 11
Babylon/babylon.engine.ts

@@ -12,7 +12,6 @@
         private _cull: boolean;
         private _cullFace: number;
 
-
         public get isDirty(): boolean {
             return this._isDepthFuncDirty || this._isDepthTestDirty || this._isDepthMaskDirty || this._isCullFaceDirty || this._isCullDirty;
         }
@@ -396,7 +395,6 @@
         // Public members
         public isFullscreen = false;
         public isPointerLock = false;
-        public forceWireframe = false;
         public cullBackFaces = true;
         public renderEvenInBackground = true;
         public scenes = new Array<Scene>();
@@ -406,6 +404,8 @@
         private _renderingCanvas: HTMLCanvasElement;
         private _windowIsBackground = false;
 
+        private _audioEngine: BABYLON.AudioEngine;
+
         private _onBlur: () => void;
         private _onFocus: () => void;
         private _onFullscreenChange: () => void;
@@ -424,9 +424,12 @@
         private _loadingTextDiv: HTMLDivElement;
         private _loadingDivBackgroundColor = "black";
 
+        private _drawCalls = 0;
+
         // States
         private _depthCullingState = new _DepthCullingState();
         private _alphaState = new _AlphaState();
+        private _alphaMode = Engine.ALPHA_DISABLE;
 
         // Cache
         private _loadedTexturesCache = new Array<WebGLTexture>();
@@ -547,6 +550,14 @@
             document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
+
+            this._audioEngine = new BABYLON.AudioEngine();
+
+            Tools.Log("Babylon.js engine (v" + Engine.Version + ") launched");
+        }
+
+        public getAudioEngine(): AudioEngine {
+            return this._audioEngine;
         }
 
         public getAspectRatio(camera: Camera): number {
@@ -595,7 +606,15 @@
             return this._caps;
         }
 
+        public get drawCalls(): number {
+            return this._drawCalls;
+        }
+
         // Methods
+        public resetDrawCalls(): void {
+            this._drawCalls = 0;
+        }
+
         public setDepthFunctionToGreater(): void {
             this._depthCullingState.depthFunc = this._gl.GREATER;
         }
@@ -739,7 +758,7 @@
         }
 
         public flushFramebuffer(): void {
-            this._gl.flush();
+         //   this._gl.flush();
         }
 
         public restoreDefaultFramebuffer(): void {
@@ -775,17 +794,18 @@
             return vbo;
         }
 
-        public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: any, length?: number): void {
+        public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: any, offset?: number): void {
             this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
-            //if (length && length != vertices.length) {
-            //    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices, 0, length));
-            //} else {
+
+            if (offset === undefined) {
+                offset = 0;
+            }
+
             if (vertices instanceof Float32Array) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, vertices);
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, vertices);
             } else {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, new Float32Array(vertices));
             }
-            //  }
 
             this._resetVertexBufferBinding();
         }
@@ -942,6 +962,8 @@
             }
 
             this._gl.drawElements(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, indexCount, indexFormat, indexStart * 2);
+
+            this._drawCalls++;
         }
 
         public drawPointClouds(verticesStart: number, verticesCount: number, instancesCount?: number): void {
@@ -954,6 +976,7 @@
             }
 
             this._gl.drawArrays(this._gl.POINTS, verticesStart, verticesCount);
+            this._drawCalls++;
         }
 
         // Shaders
@@ -1184,7 +1207,6 @@
         }
 
         public setAlphaMode(mode: number): void {
-
             switch (mode) {
                 case BABYLON.Engine.ALPHA_DISABLE:
                     this.setDepthWrite(true);
@@ -1201,6 +1223,12 @@
                     this._alphaState.alphaBlend = true;
                     break;
             }
+
+            this._alphaMode = mode;
+        }
+
+        public getAlphaMode(): number {
+            return this._alphaMode;
         }
 
         public setAlphaTesting(enable: boolean): void {

+ 156 - 49
Babylon/babylon.scene.ts

@@ -15,15 +15,18 @@
 
         // Members
         public autoClear = true;
-        public clearColor: any = new BABYLON.Color3(0.2, 0.2, 0.3);
-        public ambientColor = new BABYLON.Color3(0, 0, 0);
+        public clearColor: any = new Color3(0.2, 0.2, 0.3);
+        public ambientColor = new Color3(0, 0, 0);
         public beforeRender: () => void;
         public afterRender: () => void;
         public onDispose: () => void;
         public beforeCameraRender: (camera: Camera) => void;
         public afterCameraRender: (camera: Camera) => void;
         public forceWireframe = false;
+        public forcePointsCloud = false;
+        public forceShowBoundingBoxes = false;
         public clipPlane: Plane;
+        public animationsEnabled = true;
 
         // Pointers
         private _onPointerMove: (evt: PointerEvent) => void;
@@ -39,7 +42,8 @@
         private _onKeyUp: (evt: Event) => void;
 
         // Fog
-        public fogMode = BABYLON.Scene.FOGMODE_NONE;
+        public fogEnabled = true;
+        public fogMode = Scene.FOGMODE_NONE;
         public fogColor = new Color3(0.2, 0.2, 0.3);
         public fogDensity = 0.1;
         public fogStart = 0;
@@ -63,7 +67,7 @@
 
         public materials = new Array<Material>();
         public multiMaterials = new Array<MultiMaterial>();
-        public defaultMaterial = new BABYLON.StandardMaterial("default material", this);
+        public defaultMaterial = new StandardMaterial("default material", this);
 
         // Textures
         public texturesEnabled = true;
@@ -80,6 +84,7 @@
         public layers = new Array<Layer>();
 
         // Skeletons
+        public skeletonsEnabled = true;
         public skeletons = new Array<Skeleton>();
 
         // Lens flares
@@ -88,7 +93,7 @@
 
         // Collisions
         public collisionsEnabled = true;
-        public gravity = new BABYLON.Vector3(0, -9.0, 0);
+        public gravity = new Vector3(0, -9.0, 0);
 
         // Postprocesses
         public postProcessesEnabled = true;
@@ -117,6 +122,10 @@
         public proceduralTexturesEnabled = true;
         public _proceduralTextures = new Array<ProceduralTexture>();
 
+        // Sound Tracks
+        public mainSoundTrack: SoundTrack;
+        public soundTracks = new Array<SoundTrack>();
+
         // Private
         private _engine: Engine;
         private _totalVertices = 0;
@@ -130,6 +139,7 @@
         public _spritesDuration = 0;
         private _animationRatio = 0;
         private _animationStartDate: number;
+        public _cachedMaterial: Material;
 
         private _renderId = 0;
         private _executeWhenReadyTimeoutId = -1;
@@ -140,12 +150,14 @@
         private _pendingData = [];//ANY
 
         private _onBeforeRenderCallbacks = new Array<() => void>();
+        private _onAfterRenderCallbacks = new Array<() => void>();
 
         private _activeMeshes = new SmartArray<Mesh>(256);
         private _processedMaterials = new SmartArray<Material>(256);
         private _renderTargets = new SmartArray<RenderTargetTexture>(256);
         public _activeParticleSystems = new SmartArray<ParticleSystem>(256);
         private _activeSkeletons = new SmartArray<Skeleton>(32);
+        private _activeBones = 0;
 
         private _renderingManager: RenderingManager;
         private _physicsEngine: PhysicsEngine;
@@ -169,6 +181,8 @@
 
         private _pointerOverMesh: AbstractMesh;
 
+        private _debugLayer: DebugLayer;
+
         // Constructor
         constructor(engine: Engine) {
             this._engine = engine;
@@ -185,9 +199,16 @@
             this._outlineRenderer = new OutlineRenderer(this);
 
             this.attachControl();
+
+            this._debugLayer = new DebugLayer(this);
+            this.mainSoundTrack = new SoundTrack(this, { mainTrack: true });
         }
 
         // Properties 
+        public get debugLayer(): DebugLayer {
+            return this._debugLayer;
+        }
+
         public get meshUnderPointer(): AbstractMesh {
             return this._meshUnderPointer;
         }
@@ -200,6 +221,10 @@
             return this._pointerY;
         }
 
+        public getCachedMaterial(): Material {
+            return this._cachedMaterial;
+        }
+
         public getBoundingBoxRenderer(): BoundingBoxRenderer {
             return this._boundingBoxRenderer;
         }
@@ -224,6 +249,10 @@
             return this._activeParticles;
         }
 
+        public getActiveBones(): number {
+            return this._activeBones;
+        }
+
         // Stats
         public getLastFrameDuration(): number {
             return this._lastFrameDuration;
@@ -315,16 +344,16 @@
                     if (pickResult.pickedMesh.actionManager) {
                         switch (evt.button) {
                             case 0:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
+                                pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
                                 break;
                             case 1:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
+                                pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
                                 break;
                             case 2:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
+                                pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
                                 break;
                         }
-                        pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
+                        pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
                     }
                 }
 
@@ -335,13 +364,13 @@
 
             this._onKeyDown = (evt: Event) => {
                 if (this.actionManager) {
-                    this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
+                    this.actionManager.processTrigger(ActionManager.OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
                 }
             };
 
             this._onKeyUp = (evt: Event) => {
                 if (this.actionManager) {
-                    this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
+                    this.actionManager.processTrigger(ActionManager.OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
                 }
             };
 
@@ -372,7 +401,7 @@
             for (var index = 0; index < this._geometries.length; index++) {
                 var geometry = this._geometries[index];
 
-                if (geometry.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                if (geometry.delayLoadState === Engine.DELAYLOADSTATE_LOADING) {
                     return false;
                 }
             }
@@ -396,6 +425,10 @@
             return true;
         }
 
+        public resetCachedMaterial(): void {
+            this._cachedMaterial = null;
+        }
+
         public registerBeforeRender(func: () => void): void {
             this._onBeforeRenderCallbacks.push(func);
         }
@@ -408,6 +441,18 @@
             }
         }
 
+        public registerAfterRender(func: () => void): void {
+            this._onAfterRenderCallbacks.push(func);
+        }
+
+        public unregisterAfterRender(func: () => void): void {
+            var index = this._onAfterRenderCallbacks.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterRenderCallbacks.splice(index, 1);
+            }
+        }
+
         public _addPendingData(data): void {
             this._pendingData.push(data);
         }
@@ -485,7 +530,7 @@
                 speedRatio = 1.0;
             }
 
-            var animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations);
+            var animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations);
 
             return animatable;
         }
@@ -509,6 +554,10 @@
         }
 
         private _animate(): void {
+            if (!this.animationsEnabled) {
+                return;
+            }
+
             if (!this._animationStartDate) {
                 this._animationStartDate = Tools.Now;
             }
@@ -738,7 +787,7 @@
         }
 
         private _evaluateSubMesh(subMesh: SubMesh, mesh: AbstractMesh): void {
-            if (mesh.subMeshes.length == 1 || subMesh.isInFrustum(this._frustumPlanes)) {
+            if (mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
                 var material = subMesh.getMaterial();
 
                 if (mesh.showSubMeshesBoundingBox) {
@@ -756,7 +805,7 @@
                     }
 
                     // Dispatch
-                    this._activeVertices += subMesh.verticesCount;
+                    this._activeVertices += subMesh.indexCount;
                     this._renderingManager.dispatch(subMesh);
                 }
             }
@@ -771,9 +820,9 @@
             this._boundingBoxRenderer.reset();
 
             if (!this._frustumPlanes) {
-                this._frustumPlanes = BABYLON.Frustum.GetPlanes(this._transformMatrix);
+                this._frustumPlanes = Frustum.GetPlanes(this._transformMatrix);
             } else {
-                BABYLON.Frustum.GetPlanesToRef(this._transformMatrix, this._frustumPlanes);
+                Frustum.GetPlanesToRef(this._transformMatrix, this._frustumPlanes);
             }
 
             // Meshes
@@ -803,18 +852,26 @@
                 }
 
                 mesh.computeWorldMatrix();
-                mesh._preActivate();
 
                 // Intersections
                 if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([ActionManager.OnIntersectionEnterTrigger, ActionManager.OnIntersectionExitTrigger])) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 
-                if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
+                // Switch to current LOD
+                var meshLOD = mesh.getLOD(this.activeCamera);
+
+                if (!meshLOD) {
+                    continue;
+                }
+
+                mesh._preActivate();
+
+                if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && mesh.isInFrustum(this._frustumPlanes)) {
                     this._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
 
-                    this._activeMesh(mesh);
+                    this._activeMesh(meshLOD);
                 }
             }
 
@@ -840,35 +897,33 @@
         }
 
         private _activeMesh(mesh: AbstractMesh): void {
-            if (mesh.skeleton) {
+            if (mesh.skeleton && this.skeletonsEnabled) {
                 this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
             }
 
-            if (mesh.showBoundingBox) {
+            if (mesh.showBoundingBox || this.forceShowBoundingBoxes) {
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
             }            
 
-            var activeMesh = mesh.getLOD(this.activeCamera);
-
-            if (activeMesh && activeMesh.subMeshes) {
+            if (mesh && mesh.subMeshes) {
                 // Submeshes Octrees
                 var len: number;
                 var subMeshes: SubMesh[];
 
-                if (activeMesh._submeshesOctree && activeMesh.useOctreeForRenderingSelection) {
-                    var intersections = activeMesh._submeshesOctree.select(this._frustumPlanes);
+                if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
 
                     len = intersections.length;
                     subMeshes = intersections.data;
                 } else {
-                    subMeshes = activeMesh.subMeshes;
+                    subMeshes = mesh.subMeshes;
                     len = subMeshes.length;
                 }
 
                 for (var subIndex = 0; subIndex < len; subIndex++) {
                     var subMesh = subMeshes[subIndex];
 
-                    this._evaluateSubMesh(subMesh, activeMesh);
+                    this._evaluateSubMesh(subMesh, mesh);
                 }
             }
         }
@@ -910,6 +965,8 @@
                 var skeleton = this._activeSkeletons.data[skeletonIndex];
 
                 skeleton.prepare();
+
+                this._activeBones += skeleton.bones.length;
             }
 
             // Render targets
@@ -998,7 +1055,7 @@
         }
 
         private _processSubCameras(camera: Camera): void {
-            if (camera.subCameras.length == 0) {
+            if (camera.subCameras.length === 0) {
                 this._renderForCamera(camera);
                 return;
             }
@@ -1022,18 +1079,18 @@
                 for (var actionIndex = 0; actionIndex < sourceMesh.actionManager.actions.length; actionIndex++) {
                     var action = sourceMesh.actionManager.actions[actionIndex];
 
-                    if (action.trigger == ActionManager.OnIntersectionEnterTrigger || action.trigger == ActionManager.OnIntersectionExitTrigger) {
+                    if (action.trigger === ActionManager.OnIntersectionEnterTrigger || action.trigger === ActionManager.OnIntersectionExitTrigger) {
                         var otherMesh = action.getTriggerParameter();
 
                         var areIntersecting = otherMesh.intersectsMesh(sourceMesh, false);
                         var currentIntersectionInProgress = sourceMesh._intersectionsInProgress.indexOf(otherMesh);
 
-                        if (areIntersecting && currentIntersectionInProgress === -1 && action.trigger == ActionManager.OnIntersectionEnterTrigger) {
-                            sourceMesh.actionManager.processTrigger(ActionManager.OnIntersectionEnterTrigger, ActionEvent.CreateNew(sourceMesh));
+                        if (areIntersecting && currentIntersectionInProgress === -1 && action.trigger === ActionManager.OnIntersectionEnterTrigger) {
+                            action._executeCurrent(ActionEvent.CreateNew(sourceMesh));
                             sourceMesh._intersectionsInProgress.push(otherMesh);
 
-                        } else if (!areIntersecting && currentIntersectionInProgress > -1 && action.trigger == ActionManager.OnIntersectionExitTrigger) {
-                            sourceMesh.actionManager.processTrigger(ActionManager.OnIntersectionExitTrigger, ActionEvent.CreateNew(sourceMesh));
+                        } else if (!areIntersecting && currentIntersectionInProgress > -1 && action.trigger === ActionManager.OnIntersectionExitTrigger) {
+                            action._executeCurrent(ActionEvent.CreateNew(sourceMesh));
 
                             var indexOfOther = sourceMesh._intersectionsInProgress.indexOf(otherMesh);
 
@@ -1052,10 +1109,14 @@
             this._spritesDuration = 0;
             this._activeParticles = 0;
             this._renderDuration = 0;
+            this._renderTargetsDuration = 0;
             this._evaluateActiveMeshesDuration = 0;
             this._totalVertices = 0;
             this._activeVertices = 0;
+            this._activeBones = 0;
+            this.getEngine().resetDrawCalls();
             this._meshesForIntersections.reset();
+            this.resetCachedMaterial();
 
             Tools.StartPerformanceCounter("Scene rendering");
 
@@ -1074,7 +1135,7 @@
             }
 
             // Animations
-            var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(BABYLON.Tools.GetDeltaTime(), Scene.MaxDeltaTime));
+            var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(Tools.GetDeltaTime(), Scene.MaxDeltaTime));
             this._animationRatio = deltaTime * (60.0 / 1000.0);
             this._animate();
 
@@ -1132,7 +1193,7 @@
             }
 
             // Clear
-            this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe, true);
+            this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe || this.forcePointsCloud, true);
 
             // Shadows
             if (this.shadowsEnabled) {
@@ -1167,11 +1228,18 @@
             // Intersection checks
             this._checkIntersections();
 
+            // Update the audio listener attached to the camera
+            this._updateAudioParameters();
+
             // After render
             if (this.afterRender) {
                 this.afterRender();
             }
 
+            for (callbackIndex = 0; callbackIndex < this._onAfterRenderCallbacks.length; callbackIndex++) {
+                this._onAfterRenderCallbacks[callbackIndex]();
+            }
+
             // Cleaning
             for (var index = 0; index < this._toBeDisposed.length; index++) {
                 this._toBeDisposed.data[index].dispose();
@@ -1185,6 +1253,39 @@
             this._lastFrameDuration = Tools.Now - startDate;
         }
 
+        private _updateAudioParameters() {
+            var listeningCamera: Camera;
+            var audioEngine = this._engine.getAudioEngine();
+
+            if (this.activeCameras.length > 0) {
+                listeningCamera = this.activeCameras[0];
+            } else {
+                listeningCamera = this.activeCamera;
+            }
+
+            if (listeningCamera && audioEngine.canUseWebAudio) {
+                audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z);
+                var mat = Matrix.Invert(listeningCamera.getViewMatrix());
+                var cameraDirection = Vector3.TransformNormal(new Vector3(0, 0, -1), mat);
+                cameraDirection.normalize();
+                audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
+                for (var i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
+                    var sound = this.mainSoundTrack.soundCollection[i];
+                    if (sound.useBabylonJSAttenuation) {
+                        sound.updateDistanceFromListener();
+                    }
+                }
+                for (var i = 0; i < this.soundTracks.length; i++) {
+                    for (var j = 0; i < this.soundTracks[i].soundCollection.length; j++) {
+                        var sound = this.soundTracks[i].soundCollection[j];
+                        if (sound.useBabylonJSAttenuation) {
+                            sound.updateDistanceFromListener();
+                        }
+                    }
+                }
+            }
+        }
+
         public dispose(): void {
             this.beforeRender = null;
             this.afterRender = null;
@@ -1193,11 +1294,17 @@
 
             this._boundingBoxRenderer.dispose();
 
+            // Debug layer
+            this.debugLayer.hide();
+
             // Events
             if (this.onDispose) {
                 this.onDispose();
             }
 
+            this._onBeforeRenderCallbacks = [];
+            this._onAfterRenderCallbacks = [];
+
             this.detachControl();
 
             // Detach cameras
@@ -1279,7 +1386,7 @@
         }
 
         private _collideWithWorld(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3, excludedMesh: AbstractMesh = null): void {
-            var closeDistance = BABYLON.Engine.CollisionsEpsilon * 10.0;
+            var closeDistance = Engine.CollisionsEpsilon * 10.0;
 
             if (collider.retry >= maximumRetry) {
                 finalPosition.copyFrom(position);
@@ -1301,7 +1408,7 @@
                 return;
             }
 
-            if (velocity.x != 0 || velocity.y != 0 || velocity.z != 0) {
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
                 collider._getResponse(position, velocity);
             }
 
@@ -1317,11 +1424,11 @@
         // Octrees
         public createOrUpdateSelectionOctree(maxCapacity = 64, maxDepth = 2): Octree<AbstractMesh> {
             if (!this._selectionOctree) {
-                this._selectionOctree = new BABYLON.Octree<AbstractMesh>(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
+                this._selectionOctree = new Octree<AbstractMesh>(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
             }
 
-            var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-            var max = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+            var min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            var max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
             for (var index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
 
@@ -1356,7 +1463,7 @@
             // Moving coordinates to local viewport world
             x = x / this._engine.getHardwareScalingLevel() - viewport.x;
             y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
-            return BABYLON.Ray.CreateNew(x, y, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix());
+            return Ray.CreateNew(x, y, viewport.width, viewport.height, world ? world : Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix());
             //       return BABYLON.Ray.CreateNew(x / window.devicePixelRatio, y / window.devicePixelRatio, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix());
         }
 
@@ -1391,7 +1498,7 @@
                 }
             }
 
-            return pickingInfo || new BABYLON.PickingInfo();
+            return pickingInfo || new PickingInfo();
         }
 
         public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
@@ -1407,10 +1514,10 @@
         public pickWithRay(ray: Ray, predicate: (mesh: Mesh) => boolean, fastCheck?: boolean) {
             return this._internalPick(world => {
                 if (!this._pickWithRayInverseMatrix) {
-                    this._pickWithRayInverseMatrix = BABYLON.Matrix.Identity();
+                    this._pickWithRayInverseMatrix = Matrix.Identity();
                 }
                 world.invertToRef(this._pickWithRayInverseMatrix);
-                return BABYLON.Ray.Transform(ray, this._pickWithRayInverseMatrix);
+                return Ray.Transform(ray, this._pickWithRayInverseMatrix);
             }, predicate, fastCheck);
         }
 
@@ -1443,7 +1550,7 @@
                 return true;
             }
 
-            this._physicsEngine = new BABYLON.PhysicsEngine(plugin);
+            this._physicsEngine = new PhysicsEngine(plugin);
 
             if (!this._physicsEngine.isSupported()) {
                 this._physicsEngine = null;
@@ -1502,7 +1609,7 @@
         public deleteCompoundImpostor(compound: any): void {
             for (var index = 0; index < compound.parts.length; index++) {
                 var mesh = compound.parts[index].mesh;
-                mesh._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
+                mesh._physicImpostor = PhysicsEngine.NoImpostor;
                 this._physicsEngine._unregisterMesh(mesh);
             }
         }
@@ -1518,7 +1625,7 @@
 
             for (var i in list) {
                 var item = list[i];
-                if (BABYLON.Tags.MatchesQuery(item, tagsQuery)) {
+                if (Tags.MatchesQuery(item, tagsQuery)) {
                     listByTags.push(item);
                 }
             }

+ 6 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs

@@ -96,6 +96,12 @@ namespace BabylonExport.Entities
         [DataMember]
         public bool showSubMeshesBoundingBox { get; set; }
 
+        [DataMember]
+        public bool applyFog { get; set; }
+
+        [DataMember]
+        public int alphaIndex { get; set; }
+
         public BabylonMesh()
         {
             isEnabled = true;

BIN
Exporters/3ds Max/Max2Babylon-0.8.3.zip


BIN
Exporters/3ds Max/Max2Babylon-0.8.5.zip


+ 9 - 1
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Animation.cs

@@ -187,7 +187,7 @@ namespace Max2Babylon
 
         static void EliminateLinearAnimationKeys(List<BabylonAnimationKey> keys)
         {
-            for(int ixFirst = 0; ixFirst < keys.Count; ++ixFirst)
+            for(int ixFirst = keys.Count-3; ixFirst >=0; --ixFirst)
             {
                 while (keys.Count - ixFirst >= 3)
                 {
@@ -219,6 +219,14 @@ namespace Max2Babylon
             var middle = keys[ixFirst + 1];
             var last = keys[ixFirst + 2];
 
+            // first pass, frame equality
+            if(first.values.IsEqualTo(last.values) && first.values.IsEqualTo(middle.values))
+            {
+                keys.RemoveAt(ixFirst + 1);
+                return true;
+            }
+
+            // second pass : linear interpolation detection
             var computedMiddleValue = weightedLerp(first.frame, middle.frame, last.frame, first.values, last.values);
             if (computedMiddleValue.IsEqualTo(middle.values))
             {

+ 19 - 15
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Camera.cs

@@ -14,6 +14,7 @@ namespace Max2Babylon
                 return;
             }
             var gameCamera = cameraNode.IGameObject.AsGameCamera();
+            var maxCamera = gameCamera.MaxObject as ICameraObject;
             var initialized = gameCamera.InitializeData;
             var babylonCamera = new BabylonCamera();
 
@@ -25,15 +26,18 @@ namespace Max2Babylon
                 babylonCamera.parentId = cameraNode.NodeParent.MaxNode.GetGuid().ToString();
             }
 
-            float fov = 0;
-            gameCamera.CameraFOV.GetPropertyValue(ref fov, 0, false);
-            babylonCamera.fov = fov;
-            float minZ = 0;
-            gameCamera.CameraNearClip.GetPropertyValue(ref minZ, 0, false);
-            babylonCamera.minZ = minZ;
-            float maxZ = 0;
-            gameCamera.CameraFarClip.GetPropertyValue(ref maxZ, 0, false);
-            babylonCamera.maxZ = maxZ;
+            babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever));
+
+            if (maxCamera.ManualClip == 1)
+            {
+                babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever);
+                babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever);
+            }
+            else
+            {
+                 babylonCamera.minZ = 0.1f;
+                 babylonCamera.maxZ = 10000.0f;
+            }
 
             if (babylonCamera.minZ == 0.0f)
             {
@@ -55,14 +59,14 @@ namespace Max2Babylon
                 var position = wm.Translation;
                 babylonCamera.position = new float[] { position.X, position.Y, position.Z };
 
-                // Target
+            // Target
                 var target = gameCamera.CameraTarget;
-                if (target != null)
-                {
+            if (target != null)
+            {
                     babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString();
-                }
-                else
-                {
+            }
+            else
+            {
                     var dir = wm.GetRow(3);
                     babylonCamera.target = new float[] { position.X - dir.X, position.Y - dir.Y, position.Z - dir.Z };
                 }

+ 76 - 63
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

@@ -46,6 +46,8 @@ namespace Max2Babylon
             babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1;
             babylonMesh.showBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox");
             babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox");
+            babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1;
+            babylonMesh.alphaIndex = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_alphaindex", 1000);
 
             // Collisions
             babylonMesh.checkCollisions = meshNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions");
@@ -142,13 +144,13 @@ namespace Max2Babylon
                     IntPtr indexer = new IntPtr(i);
                     var channelNum = mappingChannels[indexer];
                     if (channelNum == 1)
-                    {
+                {
                         hasUV = true;
-                    }
+                }
                     else if (channelNum == 2)
-                    {
+                {
                         hasUV2 = true;
-                    }
+                }
                 }
                 var hasColor = unskinnedMesh.NumberOfColorVerts > 0;
                 var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0;
@@ -169,76 +171,43 @@ namespace Max2Babylon
                 var subMeshes = new List<BabylonSubMesh>();
                 var indexStart = 0;
 
-                List<Guid> orderedSubMeshes = new List<Guid>();
-                for (int i = 0; i < meshNode.NodeMaterial.SubMaterialCount; ++i)
+                
+                for (int i = 0; i < multiMatsCount; ++i)
                 {
-                    orderedSubMeshes.Add(meshNode.NodeMaterial.GetSubMaterial(i).MaxMaterial.GetGuid());
-                }
-
-                var materialIds = unskinnedMesh.ActiveMatIDs;
-                for (int i = 0; i < materialIds.Count; ++i)
-                {
-                    var materialIndexer = new IntPtr(i);
-                    int materialId = materialIds[materialIndexer];
-                    Marshal.FreeHGlobal(materialIndexer);
-                    var materialFaces = unskinnedMesh.GetFacesFromMatID(materialId);
-
+                    int materialId = meshNode.NodeMaterial.GetMaterialID(i);
+                    ITab<IFaceEx> materialFaces = null;
                     var indexCount = 0;
                     var minVertexIndex = int.MaxValue;
                     var maxVertexIndex = int.MinValue;
                     var subMesh = new BabylonSubMesh();
                     subMesh.indexStart = indexStart;
-                    subMesh.materialIndex = materialId;
+                    subMesh.materialIndex = i;
 
-
-
-                    for (int j = 0; j < materialFaces.Count; ++j)
+                    if (multiMatsCount == 1)
                     {
-                        var faceIndexer = new IntPtr(j);
-                        var face = materialFaces[faceIndexer];
-
-                        Marshal.FreeHGlobal(faceIndexer);
-                        var a = CreateGlobalVertex(unskinnedMesh, face, 0, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin);
-                        var b = CreateGlobalVertex(unskinnedMesh, face, 2, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin);
-                        var c = CreateGlobalVertex(unskinnedMesh, face, 1, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin);
-                        indices.Add(a);
-                        indices.Add(b);
-                        indices.Add(c);
-
-                        if (a < minVertexIndex)
+                        for(int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
                         {
-                            minVertexIndex = a;
+                            var face = unskinnedMesh.GetFace(j);
+                            ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face);
                         }
-
-                        if (b < minVertexIndex)
-                        {
-                            minVertexIndex = b;
-                        }
-
-                        if (c < minVertexIndex)
-                        {
-                            minVertexIndex = c;
-                        }
-
-                        if (a > maxVertexIndex)
+                    }
+                    else
+                    {
+                        materialFaces = unskinnedMesh.GetFacesFromMatID(materialId);
+                        for (int j = 0; j < materialFaces.Count; ++j)
                         {
-                            maxVertexIndex = a;
-                        }
+                            var faceIndexer = new IntPtr(j);
+                            var face = materialFaces[faceIndexer];
 
-                        if (b > maxVertexIndex)
-                        {
-                            maxVertexIndex = b;
+                            Marshal.FreeHGlobal(faceIndexer);
+                            ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face);
                         }
+                    }
+                    
 
-                        if (c > maxVertexIndex)
-                        {
-                            maxVertexIndex = c;
-                        }
 
 
-                        indexCount += 3;
-                        CheckCancelled();
-                    }
+                   
                     if (indexCount != 0)
                     {
 
@@ -358,7 +327,7 @@ namespace Max2Babylon
             // Animations
             var animations = new List<BabylonAnimation>();
             GenerateCoordinatesAnimations(meshNode, animations);
-
+            
 
             if (!ExportFloatController(meshNode.MaxNode.VisController, "visibility", animations))
             {
@@ -378,16 +347,60 @@ namespace Max2Babylon
             babylonScene.MeshesList.Add(babylonMesh);
         }
 
-        public static void GenerateCoordinatesAnimations(IIGameNode meshNode, List<BabylonAnimation> animations)
+        private void ExtractFace(IIGameSkin skin, IIGameMesh unskinnedMesh, List<GlobalVertex> vertices, List<int> indices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List<GlobalVertex>[] verticesAlreadyExported, ref int indexCount, ref int minVertexIndex, ref int maxVertexIndex, IFaceEx face)
         {
+            var a = CreateGlobalVertex(unskinnedMesh, face, 0, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin);
+            var b = CreateGlobalVertex(unskinnedMesh, face, 2, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin);
+            var c = CreateGlobalVertex(unskinnedMesh, face, 1, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin);
+            indices.Add(a);
+            indices.Add(b);
+            indices.Add(c);
+
+            if (a < minVertexIndex)
+            {
+                minVertexIndex = a;
+            }
+
+            if (b < minVertexIndex)
+            {
+                minVertexIndex = b;
+            }
+
+            if (c < minVertexIndex)
+            {
+                minVertexIndex = c;
+            }
+
+            if (a > maxVertexIndex)
+            {
+                maxVertexIndex = a;
+            }
+
+            if (b > maxVertexIndex)
+            {
+                maxVertexIndex = b;
+            }
+
+            if (c > maxVertexIndex)
+            {
+                maxVertexIndex = c;
+            }
+
+
+            indexCount += 3;
+            CheckCancelled();
+        }
+
+        public static void GenerateCoordinatesAnimations(IIGameNode meshNode, List<BabylonAnimation> animations)
+            {
             //if (!ExportVector3Controller(meshNode.TMController.PositionController, "position", animations))
             //{
-            ExportVector3Animation("position", animations, key =>
-            {
+                ExportVector3Animation("position", animations, key =>
+                {
                 var worldMatrix = meshNode.GetObjectTM(key);
                 var trans = worldMatrix.Translation;
                 return new float[] { trans.X, trans.Y, trans.Z };
-            });
+                });
             //}
 
 

+ 8 - 17
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs

@@ -190,7 +190,7 @@ namespace Max2Babylon
             {
                 babylonTexture.wrapV = 2;
             }
-
+            
             babylonTexture.name = Path.GetFileName(texture.MapName);
 
             // Animations
@@ -204,34 +204,25 @@ namespace Max2Babylon
             ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
 
             babylonTexture.animations = animations.ToArray();
-
+            var absolutePath = texture.Map.FullFilePath;
             // Copy texture to output
             try
             {
-                if (File.Exists(texture.MapName))
-                {
-                    babylonTexture.isCube = IsTextureCube(texture.MapName);
-                    if (CopyTexturesToOutput)
+               
+                   
+                    if (File.Exists(absolutePath))
                     {
-                        File.Copy(texture.MapName, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
-                    }
-                }
-                else
-                {
-                    var texturepath = Path.Combine(Path.GetDirectoryName(Loader.Core.CurFilePath), babylonTexture.name);
-                    if (File.Exists(texturepath))
-                    {
-                        babylonTexture.isCube = IsTextureCube(texturepath);
+                        babylonTexture.isCube = IsTextureCube(absolutePath);
                         if (CopyTexturesToOutput)
                         {
-                            File.Copy(texturepath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
+                            File.Copy(absolutePath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
                         }
                     }
                     else
                     {
                         RaiseWarning(string.Format("Texture {0} not found.", babylonTexture.name), 2);
                     }
-                }
+                
             }
             catch
             {

+ 23 - 10
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs

@@ -22,6 +22,8 @@ namespace Max2Babylon
         public event Action<string, Color, int, bool> OnMessage;
         public event Action<string, int> OnError;
 
+        string maxSceneFileName;
+
         readonly List<string> alreadyExportedTextures = new List<string>();
 
         public bool AutoSave3dsMaxFile { get; set; }
@@ -87,6 +89,8 @@ namespace Max2Babylon
             gameScene.InitialiseIGame(onlySelected);
             gameScene.SetStaticFrame(0);
 
+            maxSceneFileName = gameScene.SceneFileName;
+
             IsCancelled = false;
             RaiseMessage("Exportation started", Color.Blue);
             ReportProgressChanged(0);
@@ -127,6 +131,7 @@ namespace Max2Babylon
 
             // Cameras
             BabylonCamera mainCamera = null;
+            ICameraObject mainCameraNode = null;
 
             RaiseMessage("Exporting cameras");
             var camerasTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera);
@@ -139,6 +144,7 @@ namespace Max2Babylon
 
                 if (mainCamera == null && babylonScene.CamerasList.Count > 0)
                 {
+                    mainCameraNode = (cameraNode.MaxNode.ObjectRef as ICameraObject);
                     mainCamera = babylonScene.CamerasList[0];
                     babylonScene.activeCameraID = mainCamera.id;
                     RaiseMessage("Active camera set to " + mainCamera.name, Color.Green, 1, true);
@@ -164,19 +170,26 @@ namespace Max2Babylon
                 {
                     var fog = atmospheric as IStdFog;
 
-                    if (fog != null)
-                    {
                         RaiseMessage("Exporting fog");
 
+                    if (fog != null)
+                    {
                         babylonScene.fogColor = fog.GetColor(0).ToArray();
-                        babylonScene.fogDensity = fog.GetDensity(0);
-                        babylonScene.fogMode = fog.GetType_ == 0 ? 3 : 1;
+                        babylonScene.fogMode = 3;
+                    }
+#if !MAX2015
+                    else
+                    {
+                        var paramBlock = atmospheric.GetReference(0) as IIParamBlock;
 
+                        babylonScene.fogColor = Tools.GetParamBlockValueColor(paramBlock, "Fog Color");
+                        babylonScene.fogMode = 3;
+                    }
+#endif
                         if (mainCamera != null)
                         {
-                            babylonScene.fogStart = mainCamera.minZ * fog.GetNear(0);
-                            babylonScene.fogEnd = mainCamera.maxZ * fog.GetFar(0);
-                        }
+                        babylonScene.fogStart = mainCameraNode.GetEnvRange(0, 0, Tools.Forever);
+                        babylonScene.fogEnd = mainCameraNode.GetEnvRange(0, 1, Tools.Forever);
                     }
                 }
             }
@@ -188,7 +201,7 @@ namespace Max2Babylon
             var progressionStep = 80.0f / meshes.Count;
             var progression = 10.0f;
             for (int ix = 0; ix < meshes.Count; ++ix)
-            {
+                {
                 var indexer = new IntPtr(ix);
                 var meshNode = meshes[indexer];
                 Marshal.FreeHGlobal(indexer);
@@ -215,11 +228,11 @@ namespace Max2Babylon
             RaiseMessage("Exporting lights");
             var lightNodes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light);
             for(var i=0;i< lightNodes.Count; ++i)
-            {
+                {
                 ExportLight(lightNodes[new IntPtr(i)], babylonScene);
                 CheckCancelled();
             }
-          
+
 
             if (babylonScene.LightsList.Count == 0)
             {

+ 34 - 5
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs

@@ -46,12 +46,15 @@
             this.nupFrom = new System.Windows.Forms.NumericUpDown();
             this.label1 = new System.Windows.Forms.Label();
             this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
+            this.nupAlphaIndex = new System.Windows.Forms.NumericUpDown();
+            this.label3 = new System.Windows.Forms.Label();
             this.groupBox1.SuspendLayout();
             this.groupBox2.SuspendLayout();
             this.groupBox3.SuspendLayout();
             this.grpAutoAnimate.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupAlphaIndex)).BeginInit();
             this.SuspendLayout();
             // 
             // groupBox1
@@ -82,7 +85,7 @@
             this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
             this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
             this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butCancel.Location = new System.Drawing.Point(174, 419);
+            this.butCancel.Location = new System.Drawing.Point(174, 430);
             this.butCancel.Name = "butCancel";
             this.butCancel.Size = new System.Drawing.Size(75, 23);
             this.butCancel.TabIndex = 6;
@@ -94,7 +97,7 @@
             this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
             this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
             this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butOK.Location = new System.Drawing.Point(93, 419);
+            this.butOK.Location = new System.Drawing.Point(93, 430);
             this.butOK.Name = "butOK";
             this.butOK.Size = new System.Drawing.Size(75, 23);
             this.butOK.TabIndex = 5;
@@ -104,6 +107,8 @@
             // 
             // groupBox2
             // 
+            this.groupBox2.Controls.Add(this.nupAlphaIndex);
+            this.groupBox2.Controls.Add(this.label3);
             this.groupBox2.Controls.Add(this.chkNoExport);
             this.groupBox2.Controls.Add(this.chkShowSubMeshesBoundingBox);
             this.groupBox2.Controls.Add(this.chkShowBoundingBox);
@@ -112,7 +117,7 @@
             this.groupBox2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.groupBox2.Location = new System.Drawing.Point(12, 77);
             this.groupBox2.Name = "groupBox2";
-            this.groupBox2.Size = new System.Drawing.Size(319, 154);
+            this.groupBox2.Size = new System.Drawing.Size(319, 179);
             this.groupBox2.TabIndex = 2;
             this.groupBox2.TabStop = false;
             this.groupBox2.Text = "Misc.";
@@ -182,7 +187,7 @@
             this.groupBox3.Controls.Add(this.grpAutoAnimate);
             this.groupBox3.Controls.Add(this.chkAutoAnimate);
             this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox3.Location = new System.Drawing.Point(12, 237);
+            this.groupBox3.Location = new System.Drawing.Point(12, 262);
             this.groupBox3.Name = "groupBox3";
             this.groupBox3.Size = new System.Drawing.Size(319, 156);
             this.groupBox3.TabIndex = 4;
@@ -270,13 +275,34 @@
             this.chkAutoAnimate.UseVisualStyleBackColor = true;
             this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
             // 
+            // nupAlphaIndex
+            // 
+            this.nupAlphaIndex.Location = new System.Drawing.Point(89, 143);
+            this.nupAlphaIndex.Maximum = new decimal(new int[] {
+            1000,
+            0,
+            0,
+            0});
+            this.nupAlphaIndex.Name = "nupAlphaIndex";
+            this.nupAlphaIndex.Size = new System.Drawing.Size(120, 20);
+            this.nupAlphaIndex.TabIndex = 5;
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(18, 145);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(65, 13);
+            this.label3.TabIndex = 6;
+            this.label3.Text = "Alpha index:";
+            // 
             // ObjectPropertiesForm
             // 
             this.AcceptButton = this.butOK;
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.butCancel;
-            this.ClientSize = new System.Drawing.Size(343, 454);
+            this.ClientSize = new System.Drawing.Size(343, 465);
             this.Controls.Add(this.groupBox3);
             this.Controls.Add(this.groupBox2);
             this.Controls.Add(this.butCancel);
@@ -297,6 +323,7 @@
             this.grpAutoAnimate.PerformLayout();
             ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
             ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupAlphaIndex)).EndInit();
             this.ResumeLayout(false);
 
         }
@@ -321,5 +348,7 @@
         private System.Windows.Forms.Label label1;
         private System.Windows.Forms.CheckBox chkAutoAnimate;
         private System.Windows.Forms.CheckBox chkNoExport;
+        private System.Windows.Forms.NumericUpDown nupAlphaIndex;
+        private System.Windows.Forms.Label label3;
     }
 }

+ 3 - 0
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.cs

@@ -27,6 +27,8 @@ namespace Max2Babylon
             Tools.UpdateCheckBox(chkLoop, objects, "babylonjs_autoanimateloop");
             Tools.UpdateNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
             Tools.UpdateNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to");
+
+            Tools.UpdateNumericUpDown(nupAlphaIndex, objects, "babylonjs_alphaindex");
         }
 
         private void ObjectPropertiesForm_Load(object sender, EventArgs e)
@@ -52,6 +54,7 @@ namespace Max2Babylon
             Tools.PrepareCheckBox(chkLoop, objects, "babylonjs_autoanimateloop", 1);
             Tools.PrepareNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
             Tools.PrepareNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to", 100.0f);
+            Tools.PrepareNumericUpDown(nupAlphaIndex, objects, "babylonjs_alphaindex", 1000);
         }
 
         private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)

+ 52 - 0
Exporters/3ds Max/Max2Babylon/Tools/Tools.cs

@@ -76,8 +76,58 @@ namespace Max2Babylon
 
         public static IMatrix3 Identity { get { return Loader.Global.Matrix3.Create(XAxis, YAxis, ZAxis, Origin); } }
 
+#if !MAX2015
+        unsafe public static int GetParamBlockIndex(IIParamBlock paramBlock, string name)
+        {
+            for (short index = 0; index < paramBlock.NumParams; index++)
+            {
+                IGetParamName gpn = Loader.Global.GetParamName.Create("", index);
+
+                paramBlock.NotifyDependents(Tools.Forever, (UIntPtr)gpn.Handle.ToPointer(), RefMessage.GetParamName, (SClass_ID)0xfffffff0, false, null);
+
+                if (gpn.Name == name)
+                {
+                    return index;
+                }
+            }
 
+            return -1;
+        }
+
+
+        public static int GetParamBlockValueInt(IIParamBlock paramBlock, string name)
+        {
+            var index = Tools.GetParamBlockIndex(paramBlock, name);
+
+            if (index == -1)
+            {
+                return 0;
+            }
+            return paramBlock.GetInt(index, 0);
+        }
 
+        public static float GetParamBlockValueFloat(IIParamBlock paramBlock, string name)
+        {
+            var index = Tools.GetParamBlockIndex(paramBlock, name);
+
+            if (index == -1)
+            {
+                return 0;
+            }
+            return paramBlock.GetFloat(index, 0);
+        }
+
+        public static float[] GetParamBlockValueColor(IIParamBlock paramBlock, string name)
+        {
+            var index = Tools.GetParamBlockIndex(paramBlock, name);
+
+            if (index == -1)
+            {
+                return null;
+            }
+            return paramBlock.GetColor(index, 0).ToArray();
+        }
+#endif
         public static Vector3 ToEulerAngles(this IQuat q)
         {
             // Store the Euler angles in radians
@@ -507,6 +557,8 @@ namespace Max2Babylon
             return true;
         }
 
+     
+
         public static bool GetBoolProperty(this IINode node, string propertyName, int defaultState = 0)
         {
             int state = defaultState;

+ 21 - 1
Exporters/3ds Max/Max2Babylon/Tools/WebServer.cs

@@ -28,15 +28,27 @@ namespace Max2Babylon
             margin: 0;
             overflow: hidden;
         }
+
+        #debugLayerButton {
+            position: absolute;
+            border: white solid 1px;
+            background: rgba(128, 128, 128, 0.3);
+            color: white;
+            left: 50%;
+            width: 100px;
+            margin-left:-50px;
+            bottom: 10px;
+        }
     </style>
 </head>
 
 <body>
     <canvas id='canvas'></canvas>
+    <button id='debugLayerButton'>Debug layer</button>
     <script type='text/javascript'>
         var canvas = document.getElementById('canvas');
         var engine = new BABYLON.Engine(canvas, true);
-
+       
         BABYLON.SceneLoader.Load('', '###SCENE###', engine, function (newScene) {
             newScene.activeCamera.attachControl(canvas);
 
@@ -47,6 +59,14 @@ namespace Max2Babylon
             window.addEventListener('resize', function () {
                 engine.resize();
             });
+
+            document.getElementById('debugLayerButton').addEventListener('click', function () {
+                if (newScene.debugLayer.isVisible()) {
+                    newScene.debugLayer.hide();
+                } else {
+                    newScene.debugLayer.show();
+                }
+            });
         });
     </script>
 </body>

+ 18 - 64
Exporters/Blender/io_export_babylon.py

@@ -1,7 +1,7 @@
 bl_info = {
     'name': 'Babylon.js',
     'author': 'David Catuhe, Jeff Palmer',
-    'version': (1, 1, 0),
+    'version': (1, 3, 1),
     'blender': (2, 72, 0),
     "location": "File > Export > Babylon.js (.babylon)",
     "description": "Export Babylon.js scenes (.babylon)",
@@ -52,7 +52,6 @@ MAX_VERTEX_ELEMENTS = 65535
 VERTEX_OUTPUT_PER_LINE = 1000
 MAX_FLOAT_PRECISION = '%.4f'
 MAX_INFLUENCERS_PER_VERTEX = 4
-INTERNAL_NS_VAR = 'internal'
 MATERIALS_PATH_VAR = 'materialsRootDir'
 
 # used in World constructor, defined in BABYLON.Scene
@@ -129,7 +128,6 @@ class BabylonExporter(bpy.types.Operator, bpy_extras.io_utils.ExportHelper):
     filepath = bpy.props.StringProperty(subtype = 'FILE_PATH') # assigned once the file selector returns
     log_handler = None  # assigned in execute
     nameSpace   = None  # assigned in execute
-    versionCheckCode = 'if (typeof(BABYLON.Engine.Version) === "undefined" || Number(BABYLON.Engine.Version.substr(0, 4)) < 1.14) throw "Babylon version too old";\n'
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                
     export_onlyCurrentLayer = bpy.props.BoolProperty(
         name="Export only current layer",
@@ -392,14 +390,6 @@ class BabylonExporter(bpy.types.Operator, bpy_extras.io_utils.ExportHelper):
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                
     def isInSelectedLayer(self, obj, scene):
         return not self.export_onlyCurrentLayer or obj.layers[scene.active_layer]
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
-    # not relying on python parentObj.children, since would not account for forced parents (those meshes with > MAX_VERTEX_ELEMENTS)
-    def get_kids(self, prospectiveParent):
-        kids = []
-        for mesh in self.meshesAndNodes:
-            if hasattr(mesh, 'parentId') and mesh.parentId == prospectiveParent.name:
-                kids.append(mesh)
-        return kids
 #===============================================================================
 class World:
     def __init__(self, scene):
@@ -461,13 +451,13 @@ class FCurveAnimatable:
 
             if (hasattr(object.data, "autoAnimate") and object.data.autoAnimate):
                 self.autoAnimate = True
-                self.autoAnimateFrom = 0
-                self.autoAnimateTo =  bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1
-              #  for animation in self.animations:
-              #      if self.autoAnimateFrom > animation.get_first_frame():
-              #          self.autoAnimateFrom = animation.get_first_frame()
-              #      if self.autoAnimateTo < animation.get_last_frame():
-              #          self.autoAnimateTo = animation.get_last_frame()
+                self.autoAnimateFrom = bpy.context.scene.frame_end
+                self.autoAnimateTo =  0
+                for animation in self.animations:
+                    if self.autoAnimateFrom > animation.get_first_frame():
+                        self.autoAnimateFrom = animation.get_first_frame()
+                    if self.autoAnimateTo < animation.get_last_frame():
+                        self.autoAnimateTo = animation.get_last_frame()
                 self.autoAnimateLoop = True
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                
     def to_scene_file(self, file_handler):     
@@ -527,7 +517,7 @@ class Mesh(FCurveAnimatable):
             self.physicsFriction = object.rigid_body.friction
             self.physicsRestitution = object.rigid_body.restitution
         
-        # Geometry, awkward, maybe nuke hasSkeleton test; can there only be one?
+        # hasSkeleton detection & skeletonID determination
         hasSkeleton = True if object.parent and object.parent.type == 'ARMATURE' and len(object.vertex_groups) > 0 else False
         if hasSkeleton:
             # determine the skeleton ID by iterating thru objects counting armatures until parent is found
@@ -602,10 +592,9 @@ class Mesh(FCurveAnimatable):
 
         if hasSkeleton:
             self.skeletonWeights = []
-            self.skeletonIndices = []
             self.skeletonIndicesCompressed = []
     
-        # used tracking of vertices as they are recieved     
+        # used tracking of vertices as they are received     
         alreadySavedVertices = []
         vertices_UVs = []
         vertices_UV2s = []
@@ -656,11 +645,6 @@ class Mesh(FCurveAnimatable):
                         matricesWeights.append(0.0)
                         matricesWeights.append(0.0)
                         matricesWeights.append(0.0)
-                        matricesIndices = []
-                        matricesIndices.append(0.0)
-                        matricesIndices.append(0.0)
-                        matricesIndices.append(0.0)
-                        matricesIndices.append(0.0)
                         matricesIndicesCompressed = 0
 
                         # Getting influences
@@ -676,7 +660,6 @@ class Mesh(FCurveAnimatable):
                                         BabylonExporter.warn('WARNING: Maximum # of influencers exceeded for a vertex, extras ignored', 2)
                                         break
                                     matricesWeights[i] = weight
-                                    matricesIndices[i] = boneIndex
                                     matricesIndicesCompressed += boneIndex << offset
                                     offset = offset + 8
 
@@ -753,10 +736,6 @@ class Mesh(FCurveAnimatable):
                             self.skeletonWeights.append(matricesWeights[1])
                             self.skeletonWeights.append(matricesWeights[2])
                             self.skeletonWeights.append(matricesWeights[3])
-                            self.skeletonIndices.append(matricesIndices[0])
-                            self.skeletonIndices.append(matricesIndices[1])
-                            self.skeletonIndices.append(matricesIndices[2])
-                            self.skeletonIndices.append(matricesIndices[3])
                             self.skeletonIndicesCompressed.append(matricesIndicesCompressed)
 
                         vertices_indices[vertex_index].append(index)
@@ -778,7 +757,7 @@ class Mesh(FCurveAnimatable):
         BabylonExporter.log('num indices        :  ' + str(len(self.indices  )), 2)
         if hasattr(self, 'skeletonWeights'):
             BabylonExporter.log('num skeletonWeights:  ' + str(len(self.skeletonWeights)), 2)
-            BabylonExporter.log('num skeletonIndices:  ' + str(len(self.skeletonIndices)), 2)
+            BabylonExporter.log('num skeletonIndices:  ' + str(len(self.skeletonIndicesCompressed * 4)), 2)
             
         if uvRequired and len(self.uvs) == 0:
             BabylonExporter.warn('WARNING: textures being used, but no UV Map found', 2)
@@ -799,19 +778,6 @@ class Mesh(FCurveAnimatable):
             if same_vertex(p1, p2) or same_vertex(p1, p3) or same_vertex(p2, p3): nZeroAreaFaces += 1
            
         return nZeroAreaFaces       
-        
-    def get_key_order_map(self, basisKey):
-        basisData = basisKey.data
-        keySz =len(basisData)
-        
-        ret = []
-        positionsSz = len(self.positions)
-        for posIdx in range(0, positionsSz):
-            for keyIdx in range(0, keySz):
-                if same_vertex(basisData[keyIdx].co, self.positions[posIdx]): 
-                    ret.append(keyIdx)
-                    break
-        return ret
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -      
     @staticmethod
     def mesh_triangulate(mesh):
@@ -1058,8 +1024,9 @@ class Camera(FCurveAnimatable):
     def __init__(self, camera):         
         super().__init__(camera, True, True, False, math.pi / 2)
         
+        self.CameraType = camera.data.CameraType  
         self.name = camera.name        
-        BabylonExporter.log('processing begun of camera:  ' + self.name)
+        BabylonExporter.log('processing begun of camera (' + self.CameraType + '):  ' + self.name)
         self.position = camera.location
         self.rotation = mathutils.Vector((-camera.rotation_euler[0] + math.pi / 2, camera.rotation_euler[1], -camera.rotation_euler[2])) # extra parens needed
         self.fov = camera.data.angle
@@ -1075,9 +1042,7 @@ class Camera(FCurveAnimatable):
             if constraint.type == 'TRACK_TO':
                 self.lockedTargetId = constraint.target.name
                 break
-            
-        self.CameraType = camera.data.CameraType  
-                   
+                               
         if self.CameraType == ANAGLYPH_ARC_CAM or self.CameraType == ANAGLYPH_FREE_CAM:
             self.anaglyphEyeSpace = camera.data.anaglyphEyeSpace
         
@@ -1160,7 +1125,7 @@ class Light(FCurveAnimatable):
         super().__init__(light, False, True, False)
         
         self.name = light.name        
-        BabylonExporter.log('processing begun of light:  ' + self.name)
+        BabylonExporter.log('processing begun of light (' + light.data.type + '):  ' + self.name)
         light_type_items = {'POINT': POINT_LIGHT, 'SUN': DIRECTIONAL_LIGHT, 'SPOT': SPOT_LIGHT, 'HEMI': HEMI_LIGHT, 'AREA': 0}
         self.light_type = light_type_items[light.data.type]
         
@@ -1182,9 +1147,10 @@ class Light(FCurveAnimatable):
                 self.range = light.data.distance            
             
         else:
+            # Hemi & Area
             matrix_world = light.matrix_world.copy()
             matrix_world.translation = mathutils.Vector((0, 0, 0))
-            self.direction = -(mathutils.Vector((0, 0, -1)) * matrix_world)
+            self.direction = (mathutils.Vector((0, 0, -1)) * matrix_world)
             self.groundColor = mathutils.Color((0, 0, 0))
             
         self.intensity = light.data.energy        
@@ -1321,7 +1287,7 @@ class Texture:
                 self.wrapV = WRAP_ADDRESSMODE
         else:
             self.wrapU = CLAMP_ADDRESSMODE     
-            self.wrapU = CLAMP_ADDRESSMODE
+            self.wrapV = CLAMP_ADDRESSMODE
             
         self.coordinatesIndex = 0
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                
@@ -1466,22 +1432,10 @@ class VectorAnimation(Animation):
                     frames[frame] = 1
             
         #for each frame (next step ==> set for key frames)
-        i = 0
         for Frame in sorted(frames):
-            if i == 0 and Frame != 0.0:
-                self.frames.append(0)
-                bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
-                self.values.append(scale_vector(getattr(object, attrInBlender), mult, xOffset))                
-            
             self.frames.append(Frame)
             bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
             self.values.append(scale_vector(getattr(object, attrInBlender), mult, xOffset))
-
-            i = i + 1
-            if i == len(frames):
-                self.frames.append(bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1)
-                bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
-                self.values.append(scale_vector(getattr(object, attrInBlender), mult, xOffset))
 #===============================================================================
 #  module level formatting methods, called from multiple classes 
 #===============================================================================

File diff suppressed because it is too large
+ 1144 - 0
References/waa.d.ts


+ 4 - 0
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml

@@ -54,6 +54,7 @@
   <script src="Babylon/Culling/Octrees/babylon.octree.js"></script>
   <script src="Babylon/Animations/babylon.animatable.js"></script>
   <script src="Babylon/Animations/babylon.animation.js"></script>
+  <script src="Babylon/Animations/babylon.easing.js"></script>
   <script src="Babylon/Particles/babylon.particleSystem.js"></script>
   <script src="Babylon/Particles/babylon.particle.js"></script>
   <script src="Babylon/Layer/babylon.layer.js"></script>
@@ -73,6 +74,9 @@
   <script src="Babylon/Materials/textures/babylon.cubeTexture.js"></script>
   <script src="Babylon/Materials/textures/babylon.texture.js"></script>
   <script src="Babylon/Materials/textures/babylon.baseTexture.js"></script>
+  <script src="Babylon/Materials/textures/babylon.customProceduralTexture.js"></script>
+  <script src="Babylon/Materials/textures/babylon.proceduralTexture.js"></script>
+  <script src="Babylon/Materials/textures/babylon.standardProceduralTexture.js"></script>
   <script src="Babylon/Mesh/babylon.subMesh.js"></script>
   <script src="Babylon/Mesh/babylon.mesh.js"></script>
   <script src="Babylon/Mesh/babylon.InstancedMesh.js"></script>

+ 4 - 0
Tools/Gulp/gulpfile.js

@@ -90,6 +90,9 @@ gulp.task('scripts', ['shaders'] ,function() {
       '../../Babylon/Materials/textures/babylon.mirrorTexture.js',
       '../../Babylon/Materials/textures/babylon.dynamicTexture.js',
       '../../Babylon/Materials/textures/babylon.videoTexture.js',
+      '../../Babylon/Materials/textures/babylon.customProceduralTexture.js',
+      '../../Babylon/Materials/textures/babylon.proceduralTexture.js',
+      '../../Babylon/Materials/textures/babylon.standardProceduralTexture.js',
       '../../Babylon/Materials/babylon.effect.js',
       'build/shaders.js',
       '../../Babylon/Materials/babylon.material.js',
@@ -104,6 +107,7 @@ gulp.task('scripts', ['shaders'] ,function() {
       '../../Babylon/Particles/babylon.particleSystem.js',
       '../../Babylon/Animations/babylon.animation.js',
       '../../Babylon/Animations/babylon.animatable.js',
+      '../../Babylon/Animations/babylon.easing.js',
       '../../Babylon/Culling/Octrees/babylon.octree.js',
       '../../Babylon/Culling/Octrees/babylon.octreeBlock.js',
       '../../Babylon/Bones/babylon.bone.js',

File diff suppressed because it is too large
+ 2251 - 446
babylon.2.0-alpha.debug.js


File diff suppressed because it is too large
+ 19 - 17
babylon.2.0-alpha.js


+ 320 - 32
babylon.2.0.d.ts

@@ -64,13 +64,13 @@ declare module BABYLON {
         static ShadersRepository: string;
         public isFullscreen: boolean;
         public isPointerLock: boolean;
-        public forceWireframe: boolean;
         public cullBackFaces: boolean;
         public renderEvenInBackground: boolean;
         public scenes: Scene[];
         private _gl;
         private _renderingCanvas;
         private _windowIsBackground;
+        private _audioEngine;
         private _onBlur;
         private _onFocus;
         private _onFullscreenChange;
@@ -85,8 +85,10 @@ declare module BABYLON {
         private _loadingDiv;
         private _loadingTextDiv;
         private _loadingDivBackgroundColor;
+        private _drawCalls;
         private _depthCullingState;
         private _alphaState;
+        private _alphaMode;
         private _loadedTexturesCache;
         public _activeTexturesCache: BaseTexture[];
         private _currentEffect;
@@ -102,6 +104,7 @@ declare module BABYLON {
         private _workingCanvas;
         private _workingContext;
         constructor(canvas: HTMLCanvasElement, antialias?: boolean, options?: any);
+        public getAudioEngine(): AudioEngine;
         public getAspectRatio(camera: Camera): number;
         public getRenderWidth(): number;
         public getRenderHeight(): number;
@@ -111,6 +114,8 @@ declare module BABYLON {
         public getHardwareScalingLevel(): number;
         public getLoadedTexturesCache(): WebGLTexture[];
         public getCaps(): EngineCapabilities;
+        public drawCalls : number;
+        public resetDrawCalls(): void;
         public setDepthFunctionToGreater(): void;
         public setDepthFunctionToGreaterOrEqual(): void;
         public setDepthFunctionToLess(): void;
@@ -133,7 +138,7 @@ declare module BABYLON {
         private _resetVertexBufferBinding();
         public createVertexBuffer(vertices: number[]): WebGLBuffer;
         public createDynamicVertexBuffer(capacity: number): WebGLBuffer;
-        public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: any, length?: number): void;
+        public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: any, offset?: number): void;
         private _resetIndexBufferBinding();
         public createIndexBuffer(indices: number[]): WebGLBuffer;
         public bindBuffers(vertexBuffer: WebGLBuffer, indexBuffer: WebGLBuffer, vertexDeclaration: number[], vertexStrideSize: number, effect: Effect): void;
@@ -169,6 +174,7 @@ declare module BABYLON {
         public setDepthWrite(enable: boolean): void;
         public setColorWrite(enable: boolean): void;
         public setAlphaMode(mode: number): void;
+        public getAlphaMode(): number;
         public setAlphaTesting(enable: boolean): void;
         public getAlphaTesting(): boolean;
         public wipeCaches(): void;
@@ -333,7 +339,10 @@ declare module BABYLON {
         public beforeCameraRender: (camera: Camera) => void;
         public afterCameraRender: (camera: Camera) => void;
         public forceWireframe: boolean;
+        public forcePointsCloud: boolean;
+        public forceShowBoundingBoxes: boolean;
         public clipPlane: Plane;
+        public animationsEnabled: boolean;
         private _onPointerMove;
         private _onPointerDown;
         public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
@@ -343,6 +352,7 @@ declare module BABYLON {
         private _meshUnderPointer;
         private _onKeyDown;
         private _onKeyUp;
+        public fogEnabled: boolean;
         public fogMode: number;
         public fogColor: Color3;
         public fogDensity: number;
@@ -365,6 +375,7 @@ declare module BABYLON {
         public particleSystems: ParticleSystem[];
         public spriteManagers: SpriteManager[];
         public layers: Layer[];
+        public skeletonsEnabled: boolean;
         public skeletons: Skeleton[];
         public lensFlaresEnabled: boolean;
         public lensFlareSystems: LensFlareSystem[];
@@ -383,6 +394,8 @@ declare module BABYLON {
         private _meshesForIntersections;
         public proceduralTexturesEnabled: boolean;
         public _proceduralTextures: ProceduralTexture[];
+        public mainSoundTrack: SoundTrack;
+        public soundTracks: SoundTrack[];
         private _engine;
         private _totalVertices;
         public _activeVertices: number;
@@ -395,17 +408,20 @@ declare module BABYLON {
         public _spritesDuration: number;
         private _animationRatio;
         private _animationStartDate;
+        public _cachedMaterial: Material;
         private _renderId;
         private _executeWhenReadyTimeoutId;
         public _toBeDisposed: SmartArray<IDisposable>;
         private _onReadyCallbacks;
         private _pendingData;
         private _onBeforeRenderCallbacks;
+        private _onAfterRenderCallbacks;
         private _activeMeshes;
         private _processedMaterials;
         private _renderTargets;
         public _activeParticleSystems: SmartArray<ParticleSystem>;
         private _activeSkeletons;
+        private _activeBones;
         private _renderingManager;
         private _physicsEngine;
         public _activeAnimatables: Animatable[];
@@ -420,16 +436,20 @@ declare module BABYLON {
         private _frustumPlanes;
         private _selectionOctree;
         private _pointerOverMesh;
+        private _debugLayer;
         constructor(engine: Engine);
+        public debugLayer : DebugLayer;
         public meshUnderPointer : AbstractMesh;
         public pointerX : number;
         public pointerY : number;
+        public getCachedMaterial(): Material;
         public getBoundingBoxRenderer(): BoundingBoxRenderer;
         public getOutlineRenderer(): OutlineRenderer;
         public getEngine(): Engine;
         public getTotalVertices(): number;
         public getActiveVertices(): number;
         public getActiveParticles(): number;
+        public getActiveBones(): number;
         public getLastFrameDuration(): number;
         public getEvaluateActiveMeshesDuration(): number;
         public getActiveMeshes(): SmartArray<Mesh>;
@@ -443,8 +463,11 @@ declare module BABYLON {
         public attachControl(): void;
         public detachControl(): void;
         public isReady(): boolean;
+        public resetCachedMaterial(): void;
         public registerBeforeRender(func: () => void): void;
         public unregisterBeforeRender(func: () => void): void;
+        public registerAfterRender(func: () => void): void;
+        public unregisterAfterRender(func: () => void): void;
         public _addPendingData(data: any): void;
         public _removePendingData(data: any): void;
         public getWaitingItemsCount(): number;
@@ -486,6 +509,7 @@ declare module BABYLON {
         private _processSubCameras(camera);
         private _checkIntersections();
         public render(): void;
+        private _updateAudioParameters();
         public dispose(): void;
         public _getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3, excludedMesh?: AbstractMesh): void;
         private _collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh?);
@@ -740,11 +764,15 @@ declare module BABYLON {
         private _highLimitsCache;
         private _stopped;
         public _target: any;
+        private _easingFunction;
         public targetPropertyPath: string[];
         public currentFrame: number;
+        static CreateAndStartAnimation(name: string, mesh: AbstractMesh, tartgetProperty: string, framePerSecond: number, totalFrame: number, from: any, to: any, loopMode?: number): void;
         constructor(name: string, targetProperty: string, framePerSecond: number, dataType: number, loopMode?: number);
         public isStopped(): boolean;
         public getKeys(): any[];
+        public getEasingFunction(): IEasingFunction;
+        public setEasingFunction(easingFunction: EasingFunction): void;
         public floatInterpolateFunction(startValue: number, endValue: number, gradient: number): number;
         public quaternionInterpolateFunction(startValue: Quaternion, endValue: Quaternion, gradient: number): Quaternion;
         public vector3InterpolateFunction(startValue: Vector3, endValue: Vector3, gradient: number): Vector3;
@@ -775,6 +803,166 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    interface IEasingFunction {
+        ease(gradient: number): number;
+    }
+    class EasingFunction implements IEasingFunction {
+        private static _EASINGMODE_EASEIN;
+        private static _EASINGMODE_EASEOUT;
+        private static _EASINGMODE_EASEINOUT;
+        static EASINGMODE_EASEIN : number;
+        static EASINGMODE_EASEOUT : number;
+        static EASINGMODE_EASEINOUT : number;
+        private _easingMode;
+        public setEasingMode(easingMode: number): void;
+        public getEasingMode(): number;
+        public easeInCore(gradient: number): number;
+        public ease(gradient: number): number;
+    }
+    class CircleEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number;
+    }
+    class BackEase extends EasingFunction implements IEasingFunction {
+        public amplitude: number;
+        constructor(amplitude?: number);
+        public easeInCore(gradient: number): number;
+    }
+    class BounceEase extends EasingFunction implements IEasingFunction {
+        public bounces: number;
+        public bounciness: number;
+        constructor(bounces?: number, bounciness?: number);
+        public easeInCore(gradient: number): number;
+    }
+    class CubicEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number;
+    }
+    class ElasticEase extends EasingFunction implements IEasingFunction {
+        public oscillations: number;
+        public springiness: number;
+        constructor(oscillations?: number, springiness?: number);
+        public easeInCore(gradient: number): number;
+    }
+    class ExponentialEase extends EasingFunction implements IEasingFunction {
+        public exponent: number;
+        constructor(exponent?: number);
+        public easeInCore(gradient: number): number;
+    }
+    class PowerEase extends EasingFunction implements IEasingFunction {
+        public power: number;
+        constructor(power?: number);
+        public easeInCore(gradient: number): number;
+    }
+    class QuadraticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number;
+    }
+    class QuarticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number;
+    }
+    class QuinticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number;
+    }
+    class SineEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number;
+    }
+    class BezierCurveEase extends EasingFunction implements IEasingFunction {
+        public x1: number;
+        public y1: number;
+        public x2: number;
+        public y2: number;
+        constructor(x1?: number, y1?: number, x2?: number, y2?: number);
+        public easeInCore(gradient: number): number;
+    }
+}
+declare module BABYLON {
+    class AudioEngine {
+        public audioContext: AudioContext;
+        public canUseWebAudio: boolean;
+        public masterGain: GainNode;
+        constructor();
+        public getGlobalVolume(): number;
+        public setGlobalVolume(newVolume: number): void;
+    }
+}
+declare module BABYLON {
+    class Sound {
+        public maxDistance: number;
+        public autoplay: boolean;
+        public loop: boolean;
+        public useBabylonJSAttenuation: boolean;
+        public soundTrackId: number;
+        private _position;
+        private _localDirection;
+        private _volume;
+        private _isLoaded;
+        private _isReadyToPlay;
+        private _isPlaying;
+        private _isDirectional;
+        private _audioEngine;
+        private _readyToPlayCallback;
+        private _audioBuffer;
+        private _soundSource;
+        private _soundPanner;
+        private _soundGain;
+        private _coneInnerAngle;
+        private _coneOuterAngle;
+        private _coneOuterGain;
+        private _scene;
+        private _name;
+        private _connectedMesh;
+        /**
+        * Create a sound and attach it to a scene
+        * @param name Name of your sound
+        * @param url Url to the sound to load async
+        * @param readyToPlayCallback Provide a callback function if you'd like to load your code once the sound is ready to be played
+        * @param options Objects to provide with the current available options: autoplay, loop, distanceMax
+        */
+        constructor(name: string, url: string, scene: Scene, readyToPlayCallback?: () => void, options?: any);
+        public connectToSoundTrackAudioNode(soundTrackAudioNode: AudioNode): void;
+        /**
+        * Transform this sound into a directional source
+        * @param coneInnerAngle Size of the inner cone in degree
+        * @param coneOuterAngle Size of the outer cone in degree
+        * @param coneOuterGain Volume of the sound outside the outer cone (between 0.0 and 1.0)
+        */
+        public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number): void;
+        public setPosition(newPosition: Vector3): void;
+        public setLocalDirectionToMesh(newLocalDirection: Vector3): void;
+        private _updateDirection();
+        public updateDistanceFromListener(): void;
+        /**
+        * Play the sound
+        * @param time (optional) Start the sound after X seconds. Start immediately (0) by default.
+        */
+        public play(time?: number): void;
+        /**
+        * Stop the sound
+        * @param time (optional) Stop the sound after X seconds. Stop immediately (0) by default.
+        */
+        public stop(time?: number): void;
+        public pause(): void;
+        public setVolume(newVolume: number): void;
+        public getVolume(): number;
+        public attachToMesh(meshToConnectTo: AbstractMesh): void;
+        private _onRegisterAfterWorldMatrixUpdate(connectedMesh);
+        private _soundLoaded(audioData);
+    }
+}
+declare module BABYLON {
+    class SoundTrack {
+        private _audioEngine;
+        private _trackGain;
+        private _trackConvolver;
+        private _scene;
+        public id: number;
+        public soundCollection: Sound[];
+        private _isMainTrack;
+        constructor(scene: Scene, options?: any);
+        public AddSound(sound: Sound): void;
+        public RemoveSound(sound: Sound): void;
+        public setVolume(newVolume: number): void;
+    }
+}
+declare module BABYLON {
     class Bone {
         public name: string;
         public children: Bone[];
@@ -1311,6 +1499,55 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    class DebugLayer {
+        private _scene;
+        private _enabled;
+        private _labelsEnabled;
+        private _displayStatistics;
+        private _displayTree;
+        private _displayLogs;
+        private _globalDiv;
+        private _statsDiv;
+        private _statsSubsetDiv;
+        private _optionsDiv;
+        private _optionsSubsetDiv;
+        private _logDiv;
+        private _logSubsetDiv;
+        private _treeDiv;
+        private _treeSubsetDiv;
+        private _drawingCanvas;
+        private _drawingContext;
+        private _syncPositions;
+        private _syncData;
+        private _onCanvasClick;
+        private _clickPosition;
+        private _ratio;
+        private _identityMatrix;
+        private _showUI;
+        private _needToRefreshMeshesTree;
+        public shouldDisplayLabel: (node: Node) => boolean;
+        public shouldDisplayAxis: (mesh: Mesh) => boolean;
+        public axisRatio: number;
+        constructor(scene: Scene);
+        private _refreshMeshesTreeContent();
+        private _renderSingleAxis(zero, unit, unitText, label, color);
+        private _renderAxis(projectedPosition, mesh, globalViewport);
+        private _renderLabel(text, projectedPosition, labelOffset, onClick, getFillStyle);
+        private _isClickInsideRect(x, y, width, height);
+        public isVisible(): boolean;
+        public hide(): void;
+        public show(showUI?: boolean): void;
+        private _clearLabels();
+        private _generateheader(root, text);
+        private _generateTexBox(root, title);
+        private _generateAdvancedCheckBox(root, leftTitle, rightTitle, initialState, task, tag?);
+        private _generateCheckBox(root, title, initialState, task, tag?);
+        private _generateRadio(root, title, name, initialState, task, tag?);
+        private _generateDOMelements();
+        private _displayStats();
+    }
+}
+declare module BABYLON {
     class Layer {
         public name: string;
         public texture: Texture;
@@ -1488,7 +1725,7 @@ declare module BABYLON {
         private static _registeredPlugins;
         private static _getPluginForFilename(sceneFilename);
         static RegisterPlugin(plugin: ISceneLoaderPlugin): void;
-        static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene) => void): void;
+        static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, e: any) => void): void;
         /**
         * Load a scene
         * @param rootUrl a string that defines the root url for scene and resources
@@ -1586,6 +1823,7 @@ declare module BABYLON {
         public onCompiled: (effect: Effect) => void;
         public onError: (effect: Effect, errors: string) => void;
         public onDispose: () => void;
+        public onBind: (material: Material) => void;
         public getRenderTargetTextures: () => SmartArray<RenderTargetTexture>;
         public _effect: Effect;
         public _wasPreviouslyReady: boolean;
@@ -1631,6 +1869,7 @@ declare module BABYLON {
         private _vectors3;
         private _matrices;
         private _cachedWorldViewMatrix;
+        private _renderId;
         constructor(name: string, scene: Scene, shaderPath: any, options: any);
         public needAlphaBlending(): boolean;
         public needAlphaTesting(): boolean;
@@ -1644,6 +1883,7 @@ declare module BABYLON {
         public setVector3(name: string, value: Vector3): ShaderMaterial;
         public setMatrix(name: string, value: Matrix): ShaderMaterial;
         public isReady(): boolean;
+        public bindOnlyWorldMatrix(world: Matrix): void;
         public bind(world: Matrix): void;
         public dispose(forceDisposeEffect?: boolean): void;
     }
@@ -1702,6 +1942,7 @@ declare module BABYLON {
         static EmissiveTextureEnabled: boolean;
         static SpecularTextureEnabled: boolean;
         static BumpTextureEnabled: boolean;
+        static FresnelEnabled: boolean;
     }
 }
 declare module BABYLON {
@@ -1869,16 +2110,17 @@ declare module BABYLON {
 }
 declare module BABYLON {
     class CustomProceduralTexture extends ProceduralTexture {
-        private _generateTime;
+        private _animate;
         private _time;
-        private _shaderLoaded;
         private _config;
         private _texturePath;
-        constructor(name: string, texturePath: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        constructor(name: string, texturePath: any, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
         private loadJson(jsonUrl);
+        public isReady(): boolean;
         public render(useCameraPostProcess?: boolean): void;
+        public updateTextures(): void;
         public updateShaderUniforms(): void;
-        public generateTime : boolean;
+        public animate : boolean;
     }
 }
 declare module BABYLON {
@@ -1896,7 +2138,7 @@ declare module BABYLON {
         private _uniforms;
         private _samplers;
         private _fragment;
-        private _textures;
+        public _textures: Texture[];
         private _floats;
         private _floatsArrays;
         private _colors3;
@@ -1905,7 +2147,9 @@ declare module BABYLON {
         private _vectors3;
         private _matrices;
         private _fallbackTexture;
+        private _fallbackTextureUsed;
         constructor(name: string, size: any, fragment: any, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        public reset(): void;
         public isReady(): boolean;
         public resetRefreshCounter(): void;
         public setFragment(fragment: any): void;
@@ -1940,21 +2184,21 @@ declare module BABYLON {
         private _time;
         private _speed;
         private _shift;
-        private _alpha;
         private _autoGenerateTime;
         private _fireColors;
+        private _alphaThreshold;
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
         public updateShaderUniforms(): void;
         public render(useCameraPostProcess?: boolean): void;
-        static PurpleFireColors : number[][];
-        static GreenFireColors : number[][];
-        static RedFireColors : number[][];
-        static BlueFireColors : number[][];
-        public fireColors : number[][];
+        static PurpleFireColors : Color3[];
+        static GreenFireColors : Color3[];
+        static RedFireColors : Color3[];
+        static BlueFireColors : Color3[];
+        public fireColors : Color3[];
         public time : number;
         public speed : Vector2;
         public shift : number;
-        public alpha : number;
+        public alphaThreshold : number;
     }
     class CloudProceduralTexture extends ProceduralTexture {
         private _skyColor;
@@ -1965,31 +2209,47 @@ declare module BABYLON {
         public cloudColor : Color3;
     }
     class GrassProceduralTexture extends ProceduralTexture {
+        private _grassColors;
+        private _herb1;
+        private _herb2;
+        private _herb3;
+        private _groundColor;
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
-    }
-    class RockProceduralTexture extends ProceduralTexture {
-        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        public updateShaderUniforms(): void;
+        public grassColors : Color3[];
+        public groundColor : Color3;
     }
     class RoadProceduralTexture extends ProceduralTexture {
+        private _roadColor;
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        public updateShaderUniforms(): void;
+        public roadColor : Color3;
     }
     class BrickProceduralTexture extends ProceduralTexture {
         private _numberOfBricksHeight;
         private _numberOfBricksWidth;
+        private _jointColor;
+        private _brickColor;
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
         public updateShaderUniforms(): void;
         public numberOfBricksHeight : number;
         public cloudColor : number;
         public numberOfBricksWidth : number;
+        public jointColor : Color3;
+        public brickColor : Color3;
     }
     class MarbleProceduralTexture extends ProceduralTexture {
-        private _numberOfBricksHeight;
-        private _numberOfBricksWidth;
+        private _numberOfTilesHeight;
+        private _numberOfTilesWidth;
+        private _amplitude;
+        private _marbleColor;
+        private _jointColor;
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
         public updateShaderUniforms(): void;
-        public numberOfBricksHeight : number;
-        public cloudColor : number;
-        public numberOfBricksWidth : number;
+        public numberOfTilesHeight : number;
+        public numberOfTilesWidth : number;
+        public jointColor : Color3;
+        public marbleColor : Color3;
     }
 }
 declare module BABYLON {
@@ -2150,6 +2410,7 @@ declare module BABYLON {
         static Normalize(vector: Vector3): Vector3;
         static NormalizeToRef(vector: Vector3, result: Vector3): void;
         static Project(vector: Vector3, world: Matrix, transform: Matrix, viewport: Viewport): Vector3;
+        static UnprojectFromTransform(source: Vector3, viewportWidth: number, viewportHeight: number, world: Matrix, transform: Matrix): Vector3;
         static Unproject(source: Vector3, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Vector3;
         static Minimize(left: Vector3, right: Vector3): Vector3;
         static Maximize(left: Vector3, right: Vector3): Vector3;
@@ -2355,6 +2616,9 @@ declare module BABYLON {
         static Y: Vector3;
         static Z: Vector3;
     }
+    class BezierCurve {
+        static interpolate(t: number, x1: number, y1: number, x2: number, y2: number): number;
+    }
 }
 declare module BABYLON {
     class AbstractMesh extends Node implements IDisposable {
@@ -2374,6 +2638,7 @@ declare module BABYLON {
         public scaling: Vector3;
         public billboardMode: number;
         public visibility: number;
+        public alphaIndex: number;
         public infiniteDistance: boolean;
         public isVisible: boolean;
         public isPickable: boolean;
@@ -2390,7 +2655,12 @@ declare module BABYLON {
         public renderOutline: boolean;
         public outlineColor: Color3;
         public outlineWidth: number;
+        public renderOverlay: boolean;
+        public overlayColor: Color3;
+        public overlayAlpha: number;
         public hasVertexAlpha: boolean;
+        public useVertexColors: boolean;
+        public applyFog: boolean;
         public useOctreeForRenderingSelection: boolean;
         public useOctreeForPicking: boolean;
         public useOctreeForCollisions: boolean;
@@ -2419,6 +2689,7 @@ declare module BABYLON {
         private _collisionsScalingMatrix;
         public _positions: Vector3[];
         private _isDirty;
+        public _masterMesh: AbstractMesh;
         public _boundingInfo: BoundingInfo;
         private _pivotMatrix;
         public _isDisposed: boolean;
@@ -2426,6 +2697,7 @@ declare module BABYLON {
         public subMeshes: SubMesh[];
         public _submeshesOctree: Octree<SubMesh>;
         public _intersectionsInProgress: AbstractMesh[];
+        private _onAfterWorldMatrixUpdate;
         constructor(name: string, scene: Scene);
         public isBlocked : boolean;
         public getLOD(camera: Camera): AbstractMesh;
@@ -2449,7 +2721,14 @@ declare module BABYLON {
         public _initCache(): void;
         public markAsDirty(property: string): void;
         public _updateBoundingInfo(): void;
+        public _updateSubMeshesBoundingInfo(matrix: Matrix): void;
         public computeWorldMatrix(force?: boolean): Matrix;
+        /**
+        * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
+        * @param func: callback function to add
+        */
+        public registerAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void;
+        public unregisterAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void;
         public setPositionWithLocalVector(vector3: Vector3): void;
         public getPositionExpressedInLocalSpace(): Vector3;
         public locallyTranslate(vector3: Vector3): void;
@@ -2464,7 +2743,7 @@ declare module BABYLON {
         public getPhysicsFriction(): number;
         public getPhysicsRestitution(): number;
         public getPositionInCameraSpace(camera?: Camera): Vector3;
-        public getDistanceToCamera(camera?: Camera): Vector3;
+        public getDistanceToCamera(camera?: Camera): number;
         public applyImpulse(force: Vector3, contactPoint: Vector3): void;
         public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): void;
         public updatePhysicsBodyPosition(): void;
@@ -2529,7 +2808,7 @@ declare module BABYLON {
         public isReady(): boolean;
         public setAllVerticesData(vertexData: VertexData, updatable?: boolean): void;
         public setVerticesData(kind: string, data: number[], updatable?: boolean, stride?: number): void;
-        public updateVerticesDataDirectly(kind: string, data: Float32Array): void;
+        public updateVerticesDataDirectly(kind: string, data: Float32Array, offset: number): void;
         public updateVerticesData(kind: string, data: number[], updateExtends?: boolean): void;
         public getTotalVertices(): number;
         public getVerticesData(kind: string): number[];
@@ -2537,7 +2816,7 @@ declare module BABYLON {
         public getVertexBuffers(): VertexBuffer[];
         public isVerticesDataPresent(kind: string): boolean;
         public getVerticesDataKinds(): string[];
-        public setIndices(indices: number[]): void;
+        public setIndices(indices: number[], totalVertices?: number): void;
         public getTotalIndices(): number;
         public getIndices(): number[];
         public getIndexBuffer(): any;
@@ -2658,6 +2937,7 @@ declare module BABYLON {
 declare module BABYLON {
     class InstancedMesh extends AbstractMesh {
         private _sourceMesh;
+        private _currentLOD;
         constructor(name: string, source: Mesh);
         public receiveShadows : boolean;
         public material : Material;
@@ -2672,6 +2952,7 @@ declare module BABYLON {
         public refreshBoundingInfo(): void;
         public _preActivate(): void;
         public _activate(renderId: number): void;
+        public getLOD(camera: Camera): AbstractMesh;
         public _syncSubMeshes(): void;
         public _generatePointsArray(): boolean;
         public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): InstancedMesh;
@@ -2721,12 +3002,12 @@ declare module BABYLON {
         private _instancesBufferSize;
         public _shouldGenerateFlatShading: boolean;
         private _preActivateId;
-        private _attachedLODLevel;
         constructor(name: string, scene: Scene);
+        public hasLODLevels : boolean;
         private _sortLODLevels();
         public addLODLevel(distance: number, mesh: Mesh): Mesh;
         public removeLODLevel(mesh: Mesh): Mesh;
-        public getLOD(camera: Camera): AbstractMesh;
+        public getLOD(camera: Camera, boundingSphere?: BoundingSphere): AbstractMesh;
         public geometry : Geometry;
         public getTotalVertices(): number;
         public getVerticesData(kind: string): number[];
@@ -2745,9 +3026,9 @@ declare module BABYLON {
         public subdivide(count: number): void;
         public setVerticesData(kind: any, data: any, updatable?: boolean, stride?: number): void;
         public updateVerticesData(kind: string, data: number[], updateExtends?: boolean, makeItUnique?: boolean): void;
-        public updateVerticesDataDirectly(kind: string, data: Float32Array, makeItUnique?: boolean): void;
+        public updateVerticesDataDirectly(kind: string, data: Float32Array, offset?: number, makeItUnique?: boolean): void;
         public makeGeometryUnique(): void;
-        public setIndices(indices: number[]): void;
+        public setIndices(indices: number[], totalVertices?: number): void;
         public _bind(subMesh: SubMesh, effect: Effect, fillMode: number): void;
         public _draw(subMesh: SubMesh, fillMode: number, instancesCount?: number): void;
         public registerBeforeRender(func: () => void): void;
@@ -2869,6 +3150,7 @@ declare module BABYLON {
         public _trianglePlanes: Plane[];
         public _lastColliderTransformMatrix: Matrix;
         public _renderId: number;
+        public _alphaIndex: number;
         public _distanceToCamera: number;
         public _id: number;
         constructor(materialIndex: number, verticesStart: number, verticesCount: number, indexStart: any, indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh, createBoundingBox?: boolean);
@@ -2905,7 +3187,7 @@ declare module BABYLON {
         public getStrideSize(): number;
         public create(data?: number[]): void;
         public update(data: number[]): void;
-        public updateDirectly(data: Float32Array): void;
+        public updateDirectly(data: Float32Array, offset: number): void;
         public dispose(): void;
         private static _PositionKind;
         private static _NormalKind;
@@ -3341,7 +3623,7 @@ declare module BABYLON {
         private _effect;
         private _cachedDefines;
         constructor(scene: Scene);
-        public render(subMesh: SubMesh, batch: _InstancesBatch): void;
+        public render(subMesh: SubMesh, batch: _InstancesBatch, useOverlay?: boolean): void;
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean;
     }
 }
@@ -3813,6 +4095,8 @@ declare module BABYLON {
         static LoadFile(url: string, callback: (data: any) => void, progressCallBack?: () => void, database?: any, useArrayBuffer?: boolean, onError?: () => void): void;
         static ReadFileAsDataURL(fileToLoad: any, callback: any, progressCallback: any): void;
         static ReadFile(fileToLoad: any, callback: any, progressCallBack: any, useArrayBuffer?: boolean): void;
+        static Clamp(value: number, min?: number, max?: number): number;
+        static Format(value: number, decimals?: number): string;
         static CheckExtends(v: Vector3, min: Vector3, max: Vector3): void;
         static WithinEpsilon(a: number, b: number): boolean;
         static DeepCopy(source: any, destination: any, doNotCopyList?: string[], mustCopyList?: string[]): void;
@@ -3834,11 +4118,14 @@ declare module BABYLON {
         private static _MessageLogLevel;
         private static _WarningLogLevel;
         private static _ErrorLogLevel;
+        private static _LogCache;
+        static OnNewCacheEntry: (entry: string) => void;
         static NoneLogLevel : number;
         static MessageLogLevel : number;
         static WarningLogLevel : number;
         static ErrorLogLevel : number;
         static AllLogLevel : number;
+        private static _AddLogEntry(entry);
         private static _FormatMessage(message);
         static Log: (message: string) => void;
         private static _LogDisabled(message);
@@ -3849,6 +4136,7 @@ declare module BABYLON {
         static Error: (message: string) => void;
         private static _ErrorDisabled(message);
         private static _ErrorEnabled(message);
+        static LogCache : string;
         static LogLevels : number;
         private static _PerformanceNoneLogLevel;
         private static _PerformanceUserMarkLogLevel;