Parcourir la source

Merge remote-tracking branch 'upstream/master'

Raanan Weber il y a 10 ans
Parent
commit
352f3618a2
34 fichiers modifiés avec 1854 ajouts et 4002 suppressions
  1. 51 6
      Babylon/Animations/babylon.animation.js
  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. 92 0
      Babylon/Audio/babylon.sound.js
  8. 84 0
      Babylon/Audio/babylon.sound.ts
  9. 2 2
      Babylon/Loading/babylon.sceneLoader.js
  10. 3 3
      Babylon/Loading/babylon.sceneLoader.ts
  11. 25 16
      Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.js
  12. 26 22
      Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.ts
  13. 5 0
      Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.js
  14. 5 0
      Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.ts
  15. 27 0
      Babylon/Math/babylon.math.js
  16. 31 0
      Babylon/Math/babylon.math.ts
  17. 12 2
      Babylon/Mesh/babylon.InstancedMesh.js
  18. 13 2
      Babylon/Mesh/babylon.InstancedMesh.ts
  19. 36 1
      Babylon/Mesh/babylon.abstractMesh.js
  20. 39 1
      Babylon/Mesh/babylon.abstractMesh.ts
  21. 24 28
      Babylon/Mesh/babylon.mesh.js
  22. 20 26
      Babylon/Mesh/babylon.mesh.ts
  23. 2 0
      Babylon/Physics/Plugins/babylon.oimoJSPlugin.js
  24. 2 0
      Babylon/Physics/Plugins/babylon.oimoJSPlugin.ts
  25. 6 0
      Babylon/babylon.engine.js
  26. 8 1
      Babylon/babylon.engine.ts
  27. 39 9
      Babylon/babylon.scene.js
  28. 40 9
      Babylon/babylon.scene.ts
  29. 1 1
      Exporters/Blender/io_export_babylon.py
  30. 1 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml
  31. 1 0
      Tools/Gulp/gulpfile.js
  32. 631 64
      babylon.2.0-alpha.debug.js
  33. 15 15
      babylon.2.0-alpha.js
  34. 3 3788
      babylon.2.0.d.ts

+ 51 - 6
Babylon/Animations/babylon.animation.js

@@ -14,6 +14,37 @@
             this.dataType = dataType;
             this.loopMode = loopMode === undefined ? Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
         }
+        Animation.CreateAndStartAnimation = function (name, mesh, tartgetProperty, framePerSecond, totalFrame, from, to, loopMode) {
+            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));
+        };
+
         // Methods
         Animation.prototype.isStopped = function () {
             return this._stopped;
@@ -23,6 +54,14 @@
             return this._keys;
         };
 
+        Animation.prototype.getEasingFunction = function () {
+            return this._easingFunction;
+        };
+
+        Animation.prototype.setEasingFunction = function (easingFunction) {
+            this._easingFunction = easingFunction;
+        };
+
         Animation.prototype.floatInterpolateFunction = function (startValue, endValue, gradient) {
             return startValue + (endValue - startValue) * gradient;
         };
@@ -65,11 +104,19 @@
             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) {
                         case Animation.ANIMATIONTYPE_FLOAT:
                             switch (loopMode) {
@@ -143,16 +190,11 @@
                 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);
             }
 
@@ -167,6 +209,8 @@
             // 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) {
@@ -175,6 +219,7 @@
             } 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]) {

+ 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;
+            }
+        }
+    }
+}
+
+

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

@@ -0,0 +1,92 @@
+var BABYLON;
+(function (BABYLON) {
+    var Sound = (function () {
+        function Sound(url, engine, readyToPlayCallback, distanceMax, autoplay, loop) {
+            var _this = this;
+            this.distanceMax = 10;
+            this.autoplay = false;
+            this.loop = false;
+            this._position = BABYLON.Vector3.Zero();
+            this._orientation = BABYLON.Vector3.Zero();
+            this._isLoaded = false;
+            this._isReadyToPlay = false;
+            this._audioEngine = engine.getAudioEngine();
+            ;
+            this._readyToPlayCallback = readyToPlayCallback;
+            if (distanceMax)
+                this.distanceMax = distanceMax;
+            if (autoplay)
+                this.autoplay = autoplay;
+            if (loop)
+                this.loop = loop;
+            if (this._audioEngine.canUseWebAudio) {
+                BABYLON.Tools.LoadFile(url, function (data) {
+                    _this._soundLoaded(data);
+                }, null, null, true);
+            }
+        }
+        Sound.prototype.setPosition = function (newPosition) {
+            this._position = newPosition;
+
+            if (this._isReadyToPlay) {
+                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+            }
+        };
+
+        Sound.prototype.setOrientiation = function (newOrientation) {
+            this._orientation = newOrientation;
+
+            if (this._isReadyToPlay) {
+                this._soundPanner.setOrientation(this._orientation.x, this._orientation.y, this._orientation.z);
+            }
+        };
+
+        Sound.prototype.play = function () {
+            if (this._isReadyToPlay) {
+                this._soundSource = this._audioEngine.audioContext.createBufferSource();
+                this._soundSource.buffer = this._audioBuffer;
+                this._soundPanner = this._audioEngine.audioContext.createPanner();
+                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+                this._soundPanner.connect(this._audioEngine.masterGain);
+                this._soundSource.connect(this._soundPanner);
+                this._soundSource.loop = this.loop;
+                this._soundSource.start(0);
+            }
+        };
+
+        Sound.prototype.stop = function () {
+        };
+
+        Sound.prototype.pause = function () {
+        };
+
+        Sound.prototype.attachToMesh = function (meshToConnectTo) {
+            var _this = this;
+            meshToConnectTo.registerAfterWorldMatrixUpdate(function (connectedMesh) {
+                return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh);
+            });
+        };
+
+        Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (connectedMesh) {
+            this.setPosition(connectedMesh.position);
+        };
+
+        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

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

@@ -0,0 +1,84 @@
+module BABYLON {
+    export class Sound {
+        private _audioBuffer;
+        public distanceMax: number = 10;
+        public autoplay: boolean = false;
+        public loop: boolean = false;
+        private _position: Vector3 = Vector3.Zero();
+        private _orientation: Vector3 = Vector3.Zero();
+        private _volume: number;
+        private _currentVolume: number;
+        private _isLoaded: boolean = false;
+        private _isReadyToPlay: boolean = false;
+        private _audioEngine: BABYLON.AudioEngine;
+        private _readyToPlayCallback;
+        private _soundSource: AudioBufferSourceNode;
+        private _soundPanner: PannerNode;
+
+        constructor(url: string, engine: BABYLON.Engine, readyToPlayCallback, distanceMax?: number, autoplay?: boolean, loop?: boolean) {
+            this._audioEngine = engine.getAudioEngine();;
+            this._readyToPlayCallback = readyToPlayCallback;
+            if (distanceMax) this.distanceMax = distanceMax;
+            if (autoplay) this.autoplay = autoplay;
+            if (loop) this.loop = loop;
+            if (this._audioEngine.canUseWebAudio) {
+                BABYLON.Tools.LoadFile(url, (data) => { this._soundLoaded(data); }, null, null, true);
+            }
+        }
+
+        public setPosition(newPosition: Vector3) {
+            this._position = newPosition;
+
+            if (this._isReadyToPlay) {    
+                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+            }
+        }
+
+        public setOrientiation(newOrientation: Vector3) {
+            this._orientation = newOrientation;
+
+            if (this._isReadyToPlay) {
+                this._soundPanner.setOrientation(this._orientation.x, this._orientation.y, this._orientation.z);
+            }
+        }
+
+        public play() {
+            if (this._isReadyToPlay) {
+                this._soundSource = this._audioEngine.audioContext.createBufferSource();
+                this._soundSource.buffer = this._audioBuffer;
+                this._soundPanner = this._audioEngine.audioContext.createPanner();
+                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+                this._soundPanner.connect(this._audioEngine.masterGain);
+                this._soundSource.connect(this._soundPanner);
+                this._soundSource.loop = this.loop;
+                this._soundSource.start(0);
+            }
+        }
+        
+        public stop() {
+        }   
+
+        public pause() {
+        }
+
+        public attachToMesh(meshToConnectTo: BABYLON.AbstractMesh) {
+            meshToConnectTo.registerAfterWorldMatrixUpdate((connectedMesh: BABYLON.AbstractMesh) => this._onRegisterAfterWorldMatrixUpdate(connectedMesh));
+        }
+
+        private _onRegisterAfterWorldMatrixUpdate(connectedMesh: BABYLON.AbstractMesh) {
+            this.setPosition(connectedMesh.position);
+        }
+
+        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);
+            });
+        }
+    }
+}

+ 2 - 2
Babylon/Loading/babylon.sceneLoader.js

@@ -64,14 +64,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;

+ 3 - 3
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;

+ 25 - 16
Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.js

@@ -10,9 +10,10 @@ var BABYLON;
         __extends(CustomProceduralTexture, _super);
         function CustomProceduralTexture(name, texturePath, size, scene, fallbackTexture, generateMipMaps) {
             _super.call(this, name, size, "empty", scene, fallbackTexture, generateMipMaps);
-            this._generateTime = true;
+            this._animate = true;
             this._time = 0;
             this._shaderLoaded = false;
+            this._updateTexture = false;
 
             this._texturePath = texturePath;
 
@@ -20,17 +21,15 @@ var BABYLON;
             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;
         }
         CustomProceduralTexture.prototype.loadJson = function (jsonUrl) {
-            var _this = this;
             function noConfigFile() {
                 BABYLON.Tools.Log("No config file found in " + jsonUrl);
             }
 
             var that = this;
             var configFileUrl = jsonUrl + "/config.json";
-
             var xhr = new XMLHttpRequest();
 
             xhr.open("GET", configFileUrl, true);
@@ -38,13 +37,8 @@ var BABYLON;
                 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._updateTexture = true;
                         that._shaderLoaded = true;
-                        that.render();
                     } catch (ex) {
                         noConfigFile();
                     }
@@ -69,7 +63,20 @@ var BABYLON;
             if (!this._shaderLoaded)
                 return;
 
-            if (this._generateTime) {
+            if (this._updateTexture) {
+                this.reset();
+                this.setFragment(this._texturePath + "/custom");
+                this.updateTextures();
+                this.updateShaderUniforms();
+                this._shaderLoaded = true;
+                this._animate = this._config.animate;
+                this.refreshRate = this._config.refreshrate;
+                this.isReady();
+                this._updateTexture = false;
+                return;
+            }
+
+            if (this._animate) {
                 this._time += this.getScene().getAnimationRatio() * 0.03;
                 this.updateShaderUniforms();
             }
@@ -77,11 +84,13 @@ var BABYLON;
             _super.prototype.render.call(this, useCameraPostProcess);
         };
 
-        CustomProceduralTexture.prototype.updateShaderUniforms = function () {
+        CustomProceduralTexture.prototype.updateTextures = function () {
             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()));
+                this.setTexture(this._config.texture2Ds[i].textureName, new BABYLON.Texture(this._texturePath + "/" + this._config.texture2Ds[i].textureRelativeUrl, this.getScene(), false, false, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, null, null, null, true));
             }
+        };
 
+        CustomProceduralTexture.prototype.updateShaderUniforms = function () {
             for (var j = 0; j < this._config.uniforms.length; j++) {
                 var uniform = this._config.uniforms[j];
 
@@ -105,12 +114,12 @@ var BABYLON;
             }
         };
 
-        Object.defineProperty(CustomProceduralTexture.prototype, "generateTime", {
+        Object.defineProperty(CustomProceduralTexture.prototype, "animate", {
             get: function () {
-                return this.generateTime;
+                return this._animate;
             },
             set: function (value) {
-                this.generateTime = value;
+                this._animate = value;
                 this.updateShaderUniforms();
             },
             enumerable: true,

+ 26 - 22
Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.ts

@@ -1,11 +1,12 @@
 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;
+        private _updateTexture: boolean = false;
 
         constructor(name: string, texturePath: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "empty", scene, fallbackTexture, generateMipMaps);
@@ -16,33 +17,25 @@
             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) {
-
             function noConfigFile() {
                 BABYLON.Tools.Log("No config file found in " + jsonUrl);
             }
 
             var that = this;
             var configFileUrl = jsonUrl + "/config.json";
-
             var xhr: XMLHttpRequest = new XMLHttpRequest();
 
             xhr.open("GET", configFileUrl, true);
-            xhr.addEventListener("load", () => {
+            xhr.addEventListener("load", function () {
                 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._updateTexture = true;
                         that._shaderLoaded = true;
-                        that.render();
                     }
                     catch (ex) {
                         noConfigFile();
@@ -66,13 +59,24 @@
         }
 
         public render(useCameraPostProcess?: boolean) {
-
             //if config and shader not loaded, do not render
             if (!this._shaderLoaded)
                 return;
 
+            if (this._updateTexture) {
+                this.reset();
+                this.setFragment(this._texturePath + "/custom")
+                this.updateTextures();
+                this.updateShaderUniforms();
+                this._shaderLoaded = true;
+                this._animate = this._config.animate;
+                this.refreshRate = this._config.refreshrate;
+                this.isReady();
+                this._updateTexture = false;
+                return;
+            }
 
-            if (this._generateTime) {
+            if (this._animate) {
                 this._time += this.getScene().getAnimationRatio() * 0.03;
                 this.updateShaderUniforms();
             }
@@ -80,12 +84,13 @@
             super.render(useCameraPostProcess);
         }
 
-        public updateShaderUniforms() {
-
+        public updateTextures() {
             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()));
+                this.setTexture(this._config.texture2Ds[i].textureName, new BABYLON.Texture(this._texturePath + "/" + this._config.texture2Ds[i].textureRelativeUrl, this.getScene(), false, false, Texture.TRILINEAR_SAMPLINGMODE, null, null, null, true));
             }
+        }
 
+        public updateShaderUniforms() {
             for (var j = 0; j < this._config.uniforms.length; j++) {
                 var uniform = this._config.uniforms[j];
 
@@ -109,14 +114,13 @@
             }
         }
 
-        public get generateTime(): boolean {
-            return this.generateTime;
+        public get animate(): boolean {
+            return this._animate;
         }
 
-        public set generateTime(value: boolean) {
-            this.generateTime = value;
+        public set animate(value: boolean) {
+            this._animate = value;
             this.updateShaderUniforms();
         }
-
     }
 }

+ 5 - 0
Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.js

@@ -59,6 +59,11 @@ var BABYLON;
 
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
         }
+        ProceduralTexture.prototype.reset = function () {
+            var engine = this.getScene().getEngine();
+            engine._releaseEffect(this._effect);
+        };
+
         ProceduralTexture.prototype.isReady = function () {
             var _this = this;
             var engine = this.getScene().getEngine();

+ 5 - 0
Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.ts

@@ -66,6 +66,11 @@
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
         }
 
+        public reset(): void {
+            var engine = this.getScene().getEngine();
+            engine._releaseEffect(this._effect);
+        }
+
       
         public isReady(): boolean {
             var engine = this.getScene().getEngine();

+ 27 - 0
Babylon/Math/babylon.math.js

@@ -2494,5 +2494,32 @@
     })();
     BABYLON.Axis = Axis;
     ;
+
+    var BezierCurve = (function () {
+        function BezierCurve() {
+        }
+        BezierCurve.interpolate = function (t, x1, y1, x2, y2) {
+            // 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);
+        };
+        return BezierCurve;
+    })();
+    BABYLON.BezierCurve = BezierCurve;
 })(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.math.js.map

+ 31 - 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 {
@@ -2484,4 +2486,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);
+
+        }
+    }
 }

+ 12 - 2
Babylon/Mesh/babylon.InstancedMesh.js

@@ -107,11 +107,21 @@ var BABYLON;
         };
 
         InstancedMesh.prototype._preActivate = function () {
-            this.sourceMesh._preActivate();
+            if (this._currentLOD) {
+                this._currentLOD._preActivate();
+            }
         };
 
         InstancedMesh.prototype._activate = function (renderId) {
-            this.sourceMesh._registerInstanceForRenderId(this, renderId);
+            if (this._currentLOD) {
+                this._currentLOD._registerInstanceForRenderId(this, renderId);
+            }
+        };
+
+        InstancedMesh.prototype.getLOD = function (camera) {
+            this._currentLOD = this.sourceMesh.getLOD(this.getScene().activeCamera, this.getBoundingInfo().boundingSphere);
+
+            return this._currentLOD;
         };
 
         InstancedMesh.prototype._syncSubMeshes = function () {

+ 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 {

+ 36 - 1
Babylon/Mesh/babylon.abstractMesh.js

@@ -61,6 +61,7 @@ var BABYLON;
             this._isDisposed = false;
             this._renderId = 0;
             this._intersectionsInProgress = new Array();
+            this._onAfterWorldMatrixUpdate = new Array();
 
             scene.meshes.push(this);
         }
@@ -134,6 +135,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getBoundingInfo = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getBoundingInfo();
+            }
+
             if (!this._boundingInfo) {
                 this._updateBoundingInfo();
             }
@@ -148,6 +153,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getWorldMatrix = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getWorldMatrix();
+            }
+
             if (this._currentRenderId !== this.getScene().getRenderId()) {
                 this.computeWorldMatrix();
             }
@@ -308,6 +317,10 @@ var BABYLON;
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
+            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+        };
+
+        AbstractMesh.prototype._updateSubMeshesBoundingInfo = function (matrix) {
             if (!this.subMeshes) {
                 return;
             }
@@ -315,7 +328,7 @@ var BABYLON;
             for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
                 var subMesh = this.subMeshes[subIndex];
 
-                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+                subMesh.updateBoundingInfo(matrix);
             }
         };
 
@@ -404,9 +417,29 @@ var BABYLON;
             // Absolute position
             this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
 
+            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
+        */
+        AbstractMesh.prototype.registerAfterWorldMatrixUpdate = function (func) {
+            this._onAfterWorldMatrixUpdate.push(func);
+        };
+
+        AbstractMesh.prototype.unregisterAfterWorldMatrixUpdate = function (func) {
+            var index = this._onAfterWorldMatrixUpdate.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterWorldMatrixUpdate.splice(index, 1);
+            }
+        };
+
         AbstractMesh.prototype.setPositionWithLocalVector = function (vector3) {
             this.computeWorldMatrix();
 
@@ -825,6 +858,8 @@ var BABYLON;
                 }
             }
 
+            this._onAfterWorldMatrixUpdate = [];
+
             this._isDisposed = true;
 
             // Callback

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

@@ -87,6 +87,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 +98,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 +132,10 @@
         }
 
         public getBoundingInfo(): BoundingInfo {
+            if (this._masterMesh) {
+                return this._masterMesh.getBoundingInfo();
+            }
+
             if (!this._boundingInfo) {
                 this._updateBoundingInfo();
             }
@@ -143,6 +150,10 @@
         }
 
         public getWorldMatrix(): Matrix {
+            if (this._masterMesh) {
+                return this._masterMesh.getWorldMatrix();
+            }
+
             if (this._currentRenderId !== this.getScene().getRenderId()) {
                 this.computeWorldMatrix();
             }
@@ -298,6 +309,10 @@
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
+            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+        }
+
+        public _updateSubMeshesBoundingInfo(matrix: Matrix): void {
             if (!this.subMeshes) {
                 return;
             }
@@ -305,7 +320,7 @@
             for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
                 var subMesh = this.subMeshes[subIndex];
 
-                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+                subMesh.updateBoundingInfo(matrix);
             }
         }
 
@@ -395,9 +410,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();
 
@@ -818,6 +854,8 @@
                 }
             }
 
+            this._onAfterWorldMatrixUpdate = [];
+
             this._isDisposed = true;
 
             // Callback

+ 24 - 28
Babylon/Mesh/babylon.mesh.js

@@ -31,7 +31,15 @@ var BABYLON;
             this._batchCache = new _InstancesBatch();
             this._instancesBufferSize = 32 * 16 * 4;
         }
-        // Methods
+        Object.defineProperty(Mesh.prototype, "hasLODLevels", {
+            // Methods
+            get: function () {
+                return this._LODLevels.length > 0;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         Mesh.prototype._sortLODLevels = function () {
             this._LODLevels.sort(function (a, b) {
                 if (a.distance < b.distance) {
@@ -50,7 +58,7 @@ var BABYLON;
             this._LODLevels.push(level);
 
             if (mesh) {
-                mesh._attachedLODLevel = level;
+                mesh._masterMesh = this;
             }
 
             this._sortLODLevels();
@@ -59,37 +67,25 @@ var BABYLON;
         };
 
         Mesh.prototype.removeLODLevel = function (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;
         };
 
-        Mesh.prototype.getLOD = function (camera) {
+        Mesh.prototype.getLOD = function (camera, boundingSphere) {
             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;
@@ -100,7 +96,8 @@ var BABYLON;
 
                 if (level.distance < distanceToCamera) {
                     if (level.mesh) {
-                        level.mesh._worldMatrix = this._worldMatrix;
+                        level.mesh._preActivate();
+                        level.mesh._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
                     }
                     return level.mesh;
                 }
@@ -177,7 +174,7 @@ var BABYLON;
 
         Object.defineProperty(Mesh.prototype, "isBlocked", {
             get: function () {
-                return this._attachedLODLevel !== null && this._attachedLODLevel !== undefined;
+                return this._masterMesh !== null && this._masterMesh !== undefined;
             },
             enumerable: true,
             configurable: true
@@ -441,7 +438,8 @@ var BABYLON;
         };
 
         Mesh.prototype._renderWithInstances = function (subMesh, fillMode, batch, effect, engine) {
-            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) {
@@ -467,8 +465,6 @@ var BABYLON;
                 instancesCount++;
             }
 
-            var visibleInstances = batch.visibleInstances[subMesh._id];
-
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
                     var instance = visibleInstances[instanceIndex];
@@ -512,7 +508,7 @@ var BABYLON;
             }
 
             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();

+ 20 - 26
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) {
@@ -52,7 +55,7 @@
             this._LODLevels.push(level);
 
             if (mesh) {
-                mesh._attachedLODLevel = level;
+                mesh._masterMesh = this;
             }
 
             this._sortLODLevels();
@@ -61,37 +64,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 +93,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 +168,7 @@
         }
 
         public get isBlocked(): boolean {
-            return this._attachedLODLevel !== null && this._attachedLODLevel !== undefined;
+            return this._masterMesh !== null && this._masterMesh !== undefined;
         }
 
         public isReady(): boolean {
@@ -442,7 +436,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 +463,6 @@
                 instancesCount++;
             }
 
-            var visibleInstances = batch.visibleInstances[subMesh._id];
 
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
@@ -513,7 +507,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();

+ 2 - 0
Babylon/Physics/Plugins/babylon.oimoJSPlugin.js

@@ -304,6 +304,7 @@ var BABYLON;
                             mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
                         }
                         mesh.rotationQuaternion.fromRotationMatrix(mtx);
+                        mesh.computeWorldMatrix();
                     } else {
                         m = body.getMatrix();
                         mtx = BABYLON.Matrix.FromArray(m);
@@ -325,6 +326,7 @@ var BABYLON;
                             mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
                         }
                         mesh.rotationQuaternion.fromRotationMatrix(mtx);
+                        mesh.computeWorldMatrix();
                     }
                 }
             }

+ 2 - 0
Babylon/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -320,6 +320,7 @@ module BABYLON {
                             mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
                         }
                         mesh.rotationQuaternion.fromRotationMatrix(mtx);
+                        mesh.computeWorldMatrix();
 
                     } else {
                         m = body.getMatrix();
@@ -344,6 +345,7 @@ module BABYLON {
                             mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
                         }
                         mesh.rotationQuaternion.fromRotationMatrix(mtx);
+                        mesh.computeWorldMatrix();
                     }
                 }
             }

+ 6 - 0
Babylon/babylon.engine.js

@@ -471,6 +471,8 @@
             document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
+
+            this._audioEngine = new BABYLON.AudioEngine();
         }
         Object.defineProperty(Engine, "ALPHA_DISABLE", {
             get: function () {
@@ -536,6 +538,10 @@
             configurable: true
         });
 
+        Engine.prototype.getAudioEngine = function () {
+            return this._audioEngine;
+        };
+
         Engine.prototype.getAspectRatio = function (camera) {
             var viewport = camera.viewport;
             return (this.getRenderWidth() * viewport.width) / (this.getRenderHeight() * viewport.height);

+ 8 - 1
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;
         }
@@ -355,6 +354,8 @@
         private static _DELAYLOADSTATE_LOADING = 2;
         private static _DELAYLOADSTATE_NOTLOADED = 4;
 
+        private _audioEngine: BABYLON.AudioEngine;
+
         public static get ALPHA_DISABLE(): number {
             return Engine._ALPHA_DISABLE;
         }
@@ -547,6 +548,12 @@
             document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
+
+            this._audioEngine = new BABYLON.AudioEngine();
+        }
+
+        public getAudioEngine(): AudioEngine {
+            return this._audioEngine;
         }
 
         public getAspectRatio(camera: Camera): number {

+ 39 - 9
Babylon/babylon.scene.js

@@ -727,18 +727,26 @@
                 }
 
                 mesh.computeWorldMatrix();
-                mesh._preActivate();
 
                 // Intersections
                 if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([BABYLON.ActionManager.OnIntersectionEnterTrigger, BABYLON.ActionManager.OnIntersectionExitTrigger])) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 
+                // 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);
                 }
             }
 
@@ -772,27 +780,25 @@
                 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;
                 var subMeshes;
 
-                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);
                 }
             }
         };
@@ -1089,6 +1095,9 @@
             // Intersection checks
             this._checkIntersections();
 
+            // Update the audio listener attached to the camera
+            this._updateAudioParameters();
+
             // After render
             if (this.afterRender) {
                 this.afterRender();
@@ -1105,6 +1114,25 @@
             this._lastFrameDuration = BABYLON.Tools.Now - startDate;
         };
 
+        Scene.prototype._updateAudioParameters = function () {
+            var listeningCamera;
+            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 = BABYLON.Matrix.Invert(listeningCamera.getViewMatrix());
+                var cameraDirection = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(0, 0, -1), mat);
+                cameraDirection.normalize();
+                audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
+            }
+        };
+
         Scene.prototype.dispose = function () {
             this.beforeRender = null;
             this.afterRender = null;
@@ -1118,6 +1146,8 @@
                 this.onDispose();
             }
 
+            this._onBeforeRenderCallbacks = [];
+
             this.detachControl();
 
             // Detach cameras

+ 40 - 9
Babylon/babylon.scene.ts

@@ -803,18 +803,26 @@
                 }
 
                 mesh.computeWorldMatrix();
-                mesh._preActivate();
 
                 // Intersections
                 if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([ActionManager.OnIntersectionEnterTrigger, ActionManager.OnIntersectionExitTrigger])) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 
+                // 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);
                 }
             }
 
@@ -848,27 +856,25 @@
                 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);
                 }
             }
         }
@@ -1167,6 +1173,9 @@
             // Intersection checks
             this._checkIntersections();
 
+            // Update the audio listener attached to the camera
+            this._updateAudioParameters();
+
             // After render
             if (this.afterRender) {
                 this.afterRender();
@@ -1185,6 +1194,26 @@
             this._lastFrameDuration = Tools.Now - startDate;
         }
 
+        private _updateAudioParameters() {
+            var listeningCamera;
+            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 = BABYLON.Matrix.Invert(listeningCamera.getViewMatrix());
+                var cameraDirection = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(0, 0, -1), mat);
+                cameraDirection.normalize();
+                audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
+            }
+
+        }
+
         public dispose(): void {
             this.beforeRender = null;
             this.afterRender = null;
@@ -1198,6 +1227,8 @@
                 this.onDispose();
             }
 
+            this._onBeforeRenderCallbacks = [];
+
             this.detachControl();
 
             // Detach cameras

+ 1 - 1
Exporters/Blender/io_export_babylon.py

@@ -1184,7 +1184,7 @@ class Light(FCurveAnimatable):
         else:
             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        

+ 1 - 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>

+ 1 - 0
Tools/Gulp/gulpfile.js

@@ -104,6 +104,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',

Fichier diff supprimé car celui-ci est trop grand
+ 631 - 64
babylon.2.0-alpha.debug.js


Fichier diff supprimé car celui-ci est trop grand
+ 15 - 15
babylon.2.0-alpha.js


Fichier diff supprimé car celui-ci est trop grand
+ 3 - 3788
babylon.2.0.d.ts