Browse Source

Typescript port in progress

David Catuhe 11 years ago
parent
commit
0ba019b23f
54 changed files with 10132 additions and 4628 deletions
  1. 4 0
      Babylon/Animations/babylon.animation.ts
  2. 72 65
      Babylon/Cameras/babylon.anaglyphCamera.js
  3. 105 0
      Babylon/Cameras/babylon.anaglyphCamera.ts
  4. 324 339
      Babylon/Cameras/babylon.arcRotateCamera.js
  5. 410 0
      Babylon/Cameras/babylon.arcRotateCamera.ts
  6. 242 276
      Babylon/Cameras/babylon.camera.js
  7. 313 0
      Babylon/Cameras/babylon.camera.ts
  8. 322 338
      Babylon/Cameras/babylon.freeCamera.js
  9. 412 0
      Babylon/Cameras/babylon.freeCamera.ts
  10. 1 1
      Babylon/Cameras/babylon.oculusOrientedCamera.js
  11. 236 239
      Babylon/Collisions/babylon.collider.js
  12. 346 0
      Babylon/Collisions/babylon.collider.ts
  13. 35 36
      Babylon/Collisions/babylon.pickingInfo.js
  14. 31 0
      Babylon/Collisions/babylon.pickingInfo.ts
  15. 6 2
      Babylon/Culling/Octrees/babylon.octreeBlock.js
  16. 9 5
      Babylon/Culling/Octrees/babylon.octreeBlock.ts
  17. 1 0
      Babylon/Culling/babylon.boundingInfo.js
  18. 1 0
      Babylon/Culling/babylon.boundingInfo.ts
  19. 53 46
      Babylon/Lights/babylon.directionalLight.js
  20. 57 0
      Babylon/Lights/babylon.directionalLight.ts
  21. 39 33
      Babylon/Lights/babylon.hemisphericLight.js
  22. 34 0
      Babylon/Lights/babylon.hemisphericLight.ts
  23. 53 55
      Babylon/Lights/babylon.light.js
  24. 62 0
      Babylon/Lights/babylon.light.ts
  25. 44 37
      Babylon/Lights/babylon.pointLight.js
  26. 45 0
      Babylon/Lights/babylon.pointLight.ts
  27. 56 50
      Babylon/Lights/babylon.spotLight.js
  28. 52 0
      Babylon/Lights/babylon.spotLight.ts
  29. 374 477
      Babylon/Mesh/babylon.csg.js
  30. 534 0
      Babylon/Mesh/babylon.csg.ts
  31. 980 997
      Babylon/Mesh/babylon.mesh.js
  32. 1283 0
      Babylon/Mesh/babylon.mesh.ts
  33. 571 576
      Babylon/Mesh/babylon.mesh.vertexData.js
  34. 721 0
      Babylon/Mesh/babylon.mesh.vertexData.ts
  35. 107 106
      Babylon/Mesh/babylon.subMesh.js
  36. 142 0
      Babylon/Mesh/babylon.subMesh.ts
  37. 78 77
      Babylon/Mesh/babylon.vertexBuffer.js
  38. 91 0
      Babylon/Mesh/babylon.vertexBuffer.ts
  39. 222 225
      Babylon/Physics/babylon.physicsEngine.js
  40. 281 0
      Babylon/Physics/babylon.physicsEngine.ts
  41. 19 12
      Babylon/PostProcess/babylon.anaglyphPostProcess.js
  42. 8 0
      Babylon/PostProcess/babylon.anaglyphPostProcess.ts
  43. 19 12
      Babylon/PostProcess/babylon.passPostProcess.js
  44. 8 0
      Babylon/PostProcess/babylon.passPostProcess.ts
  45. 104 109
      Babylon/PostProcess/babylon.postProcess.js
  46. 132 0
      Babylon/PostProcess/babylon.postProcess.ts
  47. 110 139
      Babylon/Tools/babylon.tools.dds.js
  48. 141 0
      Babylon/Tools/babylon.tools.dds.ts
  49. 251 259
      Babylon/Tools/babylon.tools.js
  50. 329 0
      Babylon/Tools/babylon.tools.ts
  51. 2 2
      Babylon/babylon.engine.js
  52. 113 112
      Babylon/babylon.node.js
  53. 142 0
      Babylon/babylon.node.ts
  54. 5 3
      Babylon/babylon.scene.js

+ 4 - 0
Babylon/Animations/babylon.animation.ts

@@ -1,4 +1,8 @@
 module BABYLON {
+    export interface IAnimatable {
+         animations: Array<Animation>;
+    }
+
     export class Animation {
         private _keys: Array<any>;
         private _offsetsCache = {};

+ 72 - 65
Babylon/Cameras/babylon.anaglyphCamera.js

@@ -1,9 +1,11 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    // Common
+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 buildCamera = function (that, name) {
         that._leftCamera.isIntermediate = true;
 
@@ -13,89 +15,94 @@ var BABYLON = BABYLON || {};
         that._leftTexture = new BABYLON.PassPostProcess(name + "_leftTexture", 1.0, that._leftCamera);
         that._anaglyphPostProcess = new BABYLON.AnaglyphPostProcess(name + "_anaglyph", 1.0, that._rightCamera);
 
-        that._anaglyphPostProcess.onApply = function(effect) {
+        that._anaglyphPostProcess.onApply = function (effect) {
             effect.setTextureFromPostProcess("leftSampler", that._leftTexture);
         };
 
         that._update();
     };
 
-    // ArcRotate
-    BABYLON.AnaglyphArcRotateCamera = function (name, alpha, beta, radius, target, eyeSpace, scene) {
-        BABYLON.ArcRotateCamera.call(this, name, alpha, beta, radius, target, scene);
-
-        this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
+    var AnaglyphArcRotateCamera = (function (_super) {
+        __extends(AnaglyphArcRotateCamera, _super);
+        // ANY
+        function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, eyeSpace, scene) {
+            _super.call(this, name, alpha, beta, radius, target, scene);
 
-        this._leftCamera = new BABYLON.ArcRotateCamera(name + "_left", alpha - this._eyeSpace, beta, radius, target, scene);
-        this._rightCamera = new BABYLON.ArcRotateCamera(name + "_right", alpha + this._eyeSpace, beta, radius, target, scene);
-
-        buildCamera(this, name);
-    };
+            this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
 
-    BABYLON.AnaglyphArcRotateCamera.prototype = Object.create(BABYLON.ArcRotateCamera.prototype);
+            this._leftCamera = new BABYLON.ArcRotateCamera(name + "_left", alpha - this._eyeSpace, beta, radius, target, scene);
+            this._rightCamera = new BABYLON.ArcRotateCamera(name + "_right", alpha + this._eyeSpace, beta, radius, target, scene);
 
-    BABYLON.AnaglyphArcRotateCamera.prototype._update = function () {
-        this._updateCamera(this._leftCamera);
-        this._updateCamera(this._rightCamera);
+            buildCamera(this, name);
+        }
+        AnaglyphArcRotateCamera.prototype._update = function () {
+            this._updateCamera(this._leftCamera);
+            this._updateCamera(this._rightCamera);
 
-        this._leftCamera.alpha = this.alpha - this._eyeSpace;
-        this._rightCamera.alpha = this.alpha + this._eyeSpace;
+            this._leftCamera.alpha = this.alpha - this._eyeSpace;
+            this._rightCamera.alpha = this.alpha + this._eyeSpace;
 
-        BABYLON.ArcRotateCamera.prototype._update.call(this);
-    };
-
-    BABYLON.AnaglyphArcRotateCamera.prototype._updateCamera = function (camera) {
-        camera.beta = this.beta;
-        camera.radius = this.radius;
-
-        camera.minZ = this.minZ;
-        camera.maxZ = this.maxZ;
+            _super.prototype._update.call(this);
+        };
 
-        camera.fov = this.fov;
+        AnaglyphArcRotateCamera.prototype._updateCamera = function (camera) {
+            camera.beta = this.beta;
+            camera.radius = this.radius;
 
-        camera.target = this.target;
-    };
+            camera.minZ = this.minZ;
+            camera.maxZ = this.maxZ;
 
-    // FreeCamera
-    BABYLON.AnaglyphFreeCamera = function (name, position, eyeSpace, scene) {
-        BABYLON.FreeCamera.call(this, name, position, scene);
+            camera.fov = this.fov;
 
-        this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
-        this._transformMatrix = new BABYLON.Matrix();
+            camera.target = this.target;
+        };
+        return AnaglyphArcRotateCamera;
+    })(BABYLON.ArcRotateCamera);
+    BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
 
-        this._leftCamera = new BABYLON.FreeCamera(name + "_left", position, scene);
-        this._rightCamera = new BABYLON.FreeCamera(name + "_right", position, scene);
+    var AnaglyphFreeCamera = (function (_super) {
+        __extends(AnaglyphFreeCamera, _super);
+        //ANY
+        function AnaglyphFreeCamera(name, position, eyeSpace, scene) {
+            _super.call(this, name, position, scene);
 
-        buildCamera(this, name, eyeSpace);
-    };
+            this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
+            this._transformMatrix = new BABYLON.Matrix();
 
-    BABYLON.AnaglyphFreeCamera.prototype = Object.create(BABYLON.FreeCamera.prototype);
+            this._leftCamera = new BABYLON.FreeCamera(name + "_left", position.clone(), scene);
+            this._rightCamera = new BABYLON.FreeCamera(name + "_right", position.clone(), scene);
 
-    BABYLON.AnaglyphFreeCamera.prototype._getSubCameraPosition = function(eyeSpace, result) {
-        var target = this.getTarget();
-        BABYLON.Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(BABYLON.Matrix.RotationY(eyeSpace), this._transformMatrix);
+            buildCamera(this, name);
+        }
+        AnaglyphFreeCamera.prototype._getSubCameraPosition = function (eyeSpace, result) {
+            var target = this.getTarget();
+            BABYLON.Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(BABYLON.Matrix.RotationY(eyeSpace), this._transformMatrix);
 
-        this._transformMatrix = this._transformMatrix.multiply(BABYLON.Matrix.Translation(target.x, target.y, target.z));
+            this._transformMatrix = this._transformMatrix.multiply(BABYLON.Matrix.Translation(target.x, target.y, target.z));
 
-        BABYLON.Vector3.TransformCoordinatesToRef(this.position, this._transformMatrix, result);
-    };
+            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this._transformMatrix, result);
+        };
 
-    BABYLON.AnaglyphFreeCamera.prototype._update = function () {
-        this._getSubCameraPosition(-this._eyeSpace, this._leftCamera.position);
-        this._getSubCameraPosition(this._eyeSpace, this._rightCamera.position);
+        AnaglyphFreeCamera.prototype._update = function () {
+            this._getSubCameraPosition(-this._eyeSpace, this._leftCamera.position);
+            this._getSubCameraPosition(this._eyeSpace, this._rightCamera.position);
 
-        this._updateCamera(this._leftCamera);
-        this._updateCamera(this._rightCamera);
+            this._updateCamera(this._leftCamera);
+            this._updateCamera(this._rightCamera);
 
-        BABYLON.FreeCamera.prototype._update.call(this);
-    };
+            _super.prototype._update.call(this);
+        };
 
-    BABYLON.AnaglyphFreeCamera.prototype._updateCamera = function (camera) {
-        camera.minZ = this.minZ;
-        camera.maxZ = this.maxZ;
+        AnaglyphFreeCamera.prototype._updateCamera = function (camera) {
+            camera.minZ = this.minZ;
+            camera.maxZ = this.maxZ;
 
-        camera.fov = this.fov;
+            camera.fov = this.fov;
 
-        camera.setTarget(this.getTarget());
-    };
-})();
+            camera.setTarget(this.getTarget());
+        };
+        return AnaglyphFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.anaglyphCamera.js.map

+ 105 - 0
Babylon/Cameras/babylon.anaglyphCamera.ts

@@ -0,0 +1,105 @@
+module BABYLON {
+    var buildCamera = (that, name) => {
+        that._leftCamera.isIntermediate = true;
+
+        that.subCameras.push(that._leftCamera);
+        that.subCameras.push(that._rightCamera);
+
+        that._leftTexture = new BABYLON.PassPostProcess(name + "_leftTexture", 1.0, that._leftCamera);
+        that._anaglyphPostProcess = new BABYLON.AnaglyphPostProcess(name + "_anaglyph", 1.0, that._rightCamera);
+
+        that._anaglyphPostProcess.onApply = effect => {
+            effect.setTextureFromPostProcess("leftSampler", that._leftTexture);
+        };
+
+        that._update();
+    };
+
+    export class AnaglyphArcRotateCamera extends ArcRotateCamera {
+        private _eyeSpace: number;
+        private _leftCamera: ArcRotateCamera;
+        private _rightCamera: ArcRotateCamera;
+
+        // ANY
+        constructor(name: string, alpha: number, beta: number, radius: number, target, eyeSpace: number, scene) {
+            super(name, alpha, beta, radius, target, scene);
+
+            this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
+
+            this._leftCamera = new BABYLON.ArcRotateCamera(name + "_left", alpha - this._eyeSpace, beta, radius, target, scene);
+            this._rightCamera = new BABYLON.ArcRotateCamera(name + "_right", alpha + this._eyeSpace, beta, radius, target, scene);
+
+            buildCamera(this, name);
+        }
+
+        public _update(): void {
+            this._updateCamera(this._leftCamera);
+            this._updateCamera(this._rightCamera);
+
+            this._leftCamera.alpha = this.alpha - this._eyeSpace;
+            this._rightCamera.alpha = this.alpha + this._eyeSpace;
+
+            super._update();
+        }
+
+        public _updateCamera(camera: ArcRotateCamera) {
+            camera.beta = this.beta;
+            camera.radius = this.radius;
+
+            camera.minZ = this.minZ;
+            camera.maxZ = this.maxZ;
+
+            camera.fov = this.fov;
+
+            camera.target = this.target;
+        }
+    }
+
+    export class AnaglyphFreeCamera extends FreeCamera {
+        private _eyeSpace: number;
+        private _leftCamera: FreeCamera;
+        private _rightCamera: FreeCamera;
+        private _transformMatrix: Matrix;
+
+        //ANY
+        constructor(name: string, position: Vector3, eyeSpace: number, scene) {
+            super(name, position, scene);
+
+            this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
+            this._transformMatrix = new BABYLON.Matrix();
+
+            this._leftCamera = new BABYLON.FreeCamera(name + "_left", position.clone(), scene);
+            this._rightCamera = new BABYLON.FreeCamera(name + "_right", position.clone(), scene);
+
+            buildCamera(this, name);
+        }
+
+        public _getSubCameraPosition(eyeSpace, result) {
+            var target = this.getTarget();
+            BABYLON.Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(BABYLON.Matrix.RotationY(eyeSpace), this._transformMatrix);
+
+            this._transformMatrix = this._transformMatrix.multiply(BABYLON.Matrix.Translation(target.x, target.y, target.z));
+
+            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this._transformMatrix, result);
+        }
+
+        public _update(): void {
+            this._getSubCameraPosition(-this._eyeSpace, this._leftCamera.position);
+            this._getSubCameraPosition(this._eyeSpace, this._rightCamera.position);
+
+            this._updateCamera(this._leftCamera);
+            this._updateCamera(this._rightCamera);
+
+            super._update();
+        }
+
+        public _updateCamera(camera: FreeCamera): void {
+            camera.minZ = this.minZ;
+            camera.maxZ = this.maxZ;
+
+            camera.fov = this.fov;
+
+            camera.setTarget(this.getTarget());
+        }
+    }
+} 

+ 324 - 339
Babylon/Cameras/babylon.arcRotateCamera.js

@@ -1,407 +1,392 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
+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 eventPrefix = BABYLON.Tools.GetPointerPrefix();
 
-    BABYLON.ArcRotateCamera = function (name, alpha, beta, radius, target, scene) {
-        BABYLON.Camera.call(this, name, BABYLON.Vector3.Zero(), scene);
-
-        this.alpha = alpha;
-        this.beta = beta;
-        this.radius = radius;
-        this.target = target;
-
-        this._keys = [];
-        this.keysUp = [38];
-        this.keysDown = [40];
-        this.keysLeft = [37];
-        this.keysRight = [39];
-
-        this._viewMatrix = new BABYLON.Matrix();
-
-        BABYLON.ArcRotateCamera.prototype._initCache.call(this);
-
-        this.getViewMatrix();
-    };
-
-    BABYLON.ArcRotateCamera.prototype = Object.create(BABYLON.Camera.prototype);
-
-    // Members
-    BABYLON.ArcRotateCamera.prototype.inertialAlphaOffset = 0;
-    BABYLON.ArcRotateCamera.prototype.inertialBetaOffset = 0;
-    BABYLON.ArcRotateCamera.prototype.inertialRadiusOffset = 0;
-    BABYLON.ArcRotateCamera.prototype.lowerAlphaLimit = null;
-    BABYLON.ArcRotateCamera.prototype.upperAlphaLimit = null;
-    BABYLON.ArcRotateCamera.prototype.lowerBetaLimit = 0.01;
-    BABYLON.ArcRotateCamera.prototype.upperBetaLimit = Math.PI;
-    BABYLON.ArcRotateCamera.prototype.lowerRadiusLimit = null;
-    BABYLON.ArcRotateCamera.prototype.upperRadiusLimit = null;
-    BABYLON.ArcRotateCamera.prototype.angularSensibility = 1000.0;
-    BABYLON.ArcRotateCamera.prototype.wheelPrecision = 3.0;
-
-    BABYLON.ArcRotateCamera.prototype._getTargetPosition = function () {
-        return this.target.position || this.target;
-    };
-
-    // Cache
-    BABYLON.ArcRotateCamera.prototype._initCache = function () {
-        this._cache.target = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-        this._cache.alpha = undefined;
-        this._cache.beta = undefined;
-        this._cache.radius = undefined;
-    };
-
-    BABYLON.ArcRotateCamera.prototype._updateCache = function (ignoreParentClass) {
-        if (!ignoreParentClass)
-            BABYLON.Camera.prototype._updateCache.call(this);
-
-        this._cache.target.copyFrom(this._getTargetPosition());
-        this._cache.alpha = this.alpha;
-        this._cache.beta = this.beta;
-        this._cache.radius = this.radius;
-    };
-
-    // Synchronized
-    BABYLON.ArcRotateCamera.prototype._isSynchronizedViewMatrix = function () {
-        if (!BABYLON.Camera.prototype._isSynchronizedViewMatrix.call(this))
-            return false;
-
-        return this._cache.target.equals(this._getTargetPosition())
-            && this._cache.alpha === this.alpha
-            && this._cache.beta === this.beta
-            && this._cache.radius === this.radius;
-    };
-
-    // Methods
-    BABYLON.ArcRotateCamera.prototype.attachControl = function (canvas, noPreventDefault) {
-        var previousPosition;
-        var that = this;
-        var pointerId;
-
-        if (this._attachedCanvas) {
-            return;
+    var ArcRotateCamera = (function (_super) {
+        __extends(ArcRotateCamera, _super);
+        //ANY
+        function ArcRotateCamera(name, alpha, beta, radius, target, scene) {
+            _super.call(this, name, BABYLON.Vector3.Zero(), scene);
+            this.alpha = alpha;
+            this.beta = beta;
+            this.radius = radius;
+            this.target = target;
+            this.inertialAlphaOffset = 0;
+            this.inertialBetaOffset = 0;
+            this.inertialRadiusOffset = 0;
+            this.lowerAlphaLimit = null;
+            this.upperAlphaLimit = null;
+            this.lowerBetaLimit = 0.01;
+            this.upperBetaLimit = Math.PI;
+            this.lowerRadiusLimit = null;
+            this.upperRadiusLimit = null;
+            this.angularSensibility = 1000.0;
+            this.wheelPrecision = 3.0;
+            this.keysUp = [38];
+            this.keysDown = [40];
+            this.keysLeft = [37];
+            this.keysRight = [39];
+            this.zoomOnFactor = 1;
+            this._keys = [];
+            this._viewMatrix = new BABYLON.Matrix();
+
+            this.getViewMatrix();
         }
-        this._attachedCanvas = canvas;
+        ArcRotateCamera.prototype._getTargetPosition = function () {
+            return this.target.position || this.target;
+        };
+
+        // Cache
+        ArcRotateCamera.prototype._initCache = function () {
+            _super.prototype._initCache.call(this);
+            this._cache.target = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.alpha = undefined;
+            this._cache.beta = undefined;
+            this._cache.radius = undefined;
+        };
+
+        ArcRotateCamera.prototype._updateCache = function (ignoreParentClass) {
+            if (!ignoreParentClass) {
+                _super.prototype._updateCache.call(this);
+            }
 
-        var engine = this._scene.getEngine();
+            this._cache.target.copyFrom(this._getTargetPosition());
+            this._cache.alpha = this.alpha;
+            this._cache.beta = this.beta;
+            this._cache.radius = this.radius;
+        };
 
-        if (this._onPointerDown === undefined) {
-            this._onPointerDown = function (evt) {
+        // Synchronized
+        ArcRotateCamera.prototype._isSynchronizedViewMatrix = function () {
+            if (!_super.prototype._isSynchronizedViewMatrix.call(this))
+                return false;
 
-                if (pointerId) {
-                    return;
-                }
+            return this._cache.target.equals(this._getTargetPosition()) && this._cache.alpha === this.alpha && this._cache.beta === this.beta && this._cache.radius === this.radius;
+        };
 
-                pointerId = evt.pointerId;
+        // Methods
+        ArcRotateCamera.prototype.attachControl = function (element, noPreventDefault) {
+            var _this = this;
+            var previousPosition;
+            var pointerId;
 
-                previousPosition = {
-                    x: evt.clientX,
-                    y: evt.clientY
-                };
+            if (this._attachedElement) {
+                return;
+            }
+            this._attachedElement = element;
 
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
+            var engine = this.getEngine();
 
-            this._onPointerUp = function (evt) {
-                previousPosition = null;
-                pointerId = null;
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
+            if (this._onPointerDown === undefined) {
+                this._onPointerDown = function (evt) {
+                    if (pointerId) {
+                        return;
+                    }
 
+                    pointerId = evt.pointerId;
 
-            this._onPointerMove = function (evt) {
-                if (!previousPosition) {
-                    return;
-                }
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
 
-                if (pointerId !== evt.pointerId) {
-                    return;
-                }
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
 
-                var offsetX = evt.clientX - previousPosition.x;
-                var offsetY = evt.clientY - previousPosition.y;
+                this._onPointerUp = function (evt) {
+                    previousPosition = null;
+                    pointerId = null;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
 
-                that.inertialAlphaOffset -= offsetX / that.angularSensibility;
-                that.inertialBetaOffset -= offsetY / that.angularSensibility;
+                this._onPointerMove = function (evt) {
+                    if (!previousPosition) {
+                        return;
+                    }
 
-                previousPosition = {
-                    x: evt.clientX,
-                    y: evt.clientY
-                };
+                    if (pointerId !== evt.pointerId) {
+                        return;
+                    }
 
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
+                    var offsetX = evt.clientX - previousPosition.x;
+                    var offsetY = evt.clientY - previousPosition.y;
 
-            this._onMouseMove = function (evt) {
-                if (!engine.isPointerLock) {
-                    return;
-                }
+                    _this.inertialAlphaOffset -= offsetX / _this.angularSensibility;
+                    _this.inertialBetaOffset -= offsetY / _this.angularSensibility;
 
-                var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-                var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
 
-                that.inertialAlphaOffset -= offsetX / that.angularSensibility;
-                that.inertialBetaOffset -= offsetY / that.angularSensibility;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
 
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
-
-            this._wheel = function (event) {
-                var delta = 0;
-                if (event.wheelDelta) {
-                    delta = event.wheelDelta / (that.wheelPrecision * 40);
-                } else if (event.detail) {
-                    delta = -event.detail / that.wheelPrecision;
-                }
+                this._onMouseMove = function (evt) {
+                    if (!engine.isPointerLock) {
+                        return;
+                    }
+
+                    var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                    var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
 
-                if (delta)
-                    that.inertialRadiusOffset += delta;
+                    _this.inertialAlphaOffset -= offsetX / _this.angularSensibility;
+                    _this.inertialBetaOffset -= offsetY / _this.angularSensibility;
 
-                if (event.preventDefault) {
                     if (!noPreventDefault) {
-                        event.preventDefault();
+                        evt.preventDefault();
                     }
-                }
-            };
-
-            this._onKeyDown = function (evt) {
-                if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    that.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    that.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    that.keysRight.indexOf(evt.keyCode) !== -1) {
-                    var index = that._keys.indexOf(evt.keyCode);
+                };
 
-                    if (index === -1) {
-                        that._keys.push(evt.keyCode);
+                this._wheel = function (event) {
+                    var delta = 0;
+                    if (event.wheelDelta) {
+                        delta = event.wheelDelta / (_this.wheelPrecision * 40);
+                    } else if (event.detail) {
+                        delta = -event.detail / _this.wheelPrecision;
                     }
 
-                    if (evt.preventDefault) {
+                    if (delta)
+                        _this.inertialRadiusOffset += delta;
+
+                    if (event.preventDefault) {
                         if (!noPreventDefault) {
-                            evt.preventDefault();
+                            event.preventDefault();
                         }
                     }
-                }
-            };
+                };
 
-            this._onKeyUp = function (evt) {
-                if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    that.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    that.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    that.keysRight.indexOf(evt.keyCode) !== -1) {
-                    var index = that._keys.indexOf(evt.keyCode);
+                this._onKeyDown = function (evt) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
 
-                    if (index >= 0) {
-                        that._keys.splice(index, 1);
-                    }
+                        if (index === -1) {
+                            _this._keys.push(evt.keyCode);
+                        }
 
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                     }
-                }
-            };
+                };
 
-            this._onLostFocus = function () {
-                that._keys = [];
-                pointerId = null;
-            };
+                this._onKeyUp = function (evt) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
 
-            this._onGestureStart = function (e) {
-                if (window.MSGesture === undefined) {
-                    return;
-                }
+                        if (index >= 0) {
+                            _this._keys.splice(index, 1);
+                        }
 
-                if (!that._MSGestureHandler) {
-                    that._MSGestureHandler = new MSGesture();
-                    that._MSGestureHandler.target = canvas;
-                }
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
+                        }
+                    }
+                };
 
-                that._MSGestureHandler.addPointer(e.pointerId);
-            };
+                this._onLostFocus = function () {
+                    _this._keys = [];
+                    pointerId = null;
+                };
 
-            this._onGesture = function (e) {
-                that.radius *= e.scale;
+                this._onGestureStart = function (e) {
+                    if (window.MSGesture === undefined) {
+                        return;
+                    }
 
+                    if (!_this._MSGestureHandler) {
+                        _this._MSGestureHandler = new MSGesture();
+                        _this._MSGestureHandler.target = element;
+                    }
 
-                if (e.preventDefault) {
-                    if (!noPreventDefault) {
-                        e.stopPropagation();
-                        e.preventDefault();
+                    _this._MSGestureHandler.addPointer(e.pointerId);
+                };
+
+                this._onGesture = function (e) {
+                    _this.radius *= e.scale;
+
+                    if (e.preventDefault) {
+                        if (!noPreventDefault) {
+                            e.stopPropagation();
+                            e.preventDefault();
+                        }
                     }
-                }
-            };
-
-            this._reset = function () {
-                that._keys = [];
-                that.inertialAlphaOffset = 0;
-                that.inertialBetaOffset = 0;
-                previousPosition = null;
-                pointerId = null;
-            };
-        }
+                };
 
-        canvas.addEventListener(eventPrefix + "down", this._onPointerDown, false);
-        canvas.addEventListener(eventPrefix + "up", this._onPointerUp, false);
-        canvas.addEventListener(eventPrefix + "out", this._onPointerUp, false);
-        canvas.addEventListener(eventPrefix + "move", this._onPointerMove, false);
-        canvas.addEventListener("mousemove", this._onMouseMove, false);
-        canvas.addEventListener("MSPointerDown", this._onGestureStart, false);
-        canvas.addEventListener("MSGestureChange", this._onGesture, false);
-        window.addEventListener("keydown", this._onKeyDown, false);
-        window.addEventListener("keyup", this._onKeyUp, false);
-        window.addEventListener('mousewheel', this._wheel, false);
-        window.addEventListener('DOMMouseScroll', this._wheel, false);
-        window.addEventListener("blur", this._onLostFocus, false);
-    };
-
-    BABYLON.ArcRotateCamera.prototype.detachControl = function (canvas) {
-        if (this._attachedCanvas != canvas) {
-            return;
-        }
+                this._reset = function () {
+                    _this._keys = [];
+                    _this.inertialAlphaOffset = 0;
+                    _this.inertialBetaOffset = 0;
+                    previousPosition = null;
+                    pointerId = null;
+                };
+            }
 
-        canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
-        canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
-        canvas.removeEventListener(eventPrefix + "out", this._onPointerUp);
-        canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
-        canvas.removeEventListener("mousemove", this._onMouseMove);
-        canvas.removeEventListener("MSPointerDown", this._onGestureStart);
-        canvas.removeEventListener("MSGestureChange", this._onGesture);
-        window.removeEventListener("keydown", this._onKeyDown);
-        window.removeEventListener("keyup", this._onKeyUp);
-        window.removeEventListener('mousewheel', this._wheel);
-        window.removeEventListener('DOMMouseScroll', this._wheel);
-        window.removeEventListener("blur", this._onLostFocus);
-
-        this._MSGestureHandler = null;
-        this._attachedCanvas = null;
-
-        if (this._reset) {
-            this._reset();
-        }
-    };
-
-    BABYLON.ArcRotateCamera.prototype._update = function () {
-        // Keyboard
-        for (var index = 0; index < this._keys.length; index++) {
-            var keyCode = this._keys[index];
-
-            if (this.keysLeft.indexOf(keyCode) !== -1) {
-                this.inertialAlphaOffset -= 0.01;
-            } else if (this.keysUp.indexOf(keyCode) !== -1) {
-                this.inertialBetaOffset -= 0.01;
-            } else if (this.keysRight.indexOf(keyCode) !== -1) {
-                this.inertialAlphaOffset += 0.01;
-            } else if (this.keysDown.indexOf(keyCode) !== -1) {
-                this.inertialBetaOffset += 0.01;
+            element.addEventListener(eventPrefix + "down", this._onPointerDown, false);
+            element.addEventListener(eventPrefix + "up", this._onPointerUp, false);
+            element.addEventListener(eventPrefix + "out", this._onPointerUp, false);
+            element.addEventListener(eventPrefix + "move", this._onPointerMove, false);
+            element.addEventListener("mousemove", this._onMouseMove, false);
+            element.addEventListener("MSPointerDown", this._onGestureStart, false);
+            element.addEventListener("MSGestureChange", this._onGesture, false);
+            window.addEventListener("keydown", this._onKeyDown, false);
+            window.addEventListener("keyup", this._onKeyUp, false);
+            window.addEventListener('mousewheel', this._wheel, false);
+            window.addEventListener('DOMMouseScroll', this._wheel, false);
+            window.addEventListener("blur", this._onLostFocus, false);
+        };
+
+        ArcRotateCamera.prototype.detachControl = function (element) {
+            if (this._attachedElement != element) {
+                return;
             }
-        }
 
-        // Inertia
-        if (this.inertialAlphaOffset != 0 || this.inertialBetaOffset != 0 || this.inertialRadiusOffset != 0) {
+            element.removeEventListener(eventPrefix + "down", this._onPointerDown);
+            element.removeEventListener(eventPrefix + "up", this._onPointerUp);
+            element.removeEventListener(eventPrefix + "out", this._onPointerUp);
+            element.removeEventListener(eventPrefix + "move", this._onPointerMove);
+            element.removeEventListener("mousemove", this._onMouseMove);
+            element.removeEventListener("MSPointerDown", this._onGestureStart);
+            element.removeEventListener("MSGestureChange", this._onGesture);
+            window.removeEventListener("keydown", this._onKeyDown);
+            window.removeEventListener("keyup", this._onKeyUp);
+            window.removeEventListener('mousewheel', this._wheel);
+            window.removeEventListener('DOMMouseScroll', this._wheel);
+            window.removeEventListener("blur", this._onLostFocus);
+
+            this._MSGestureHandler = null;
+            this._attachedElement = null;
+
+            if (this._reset) {
+                this._reset();
+            }
+        };
+
+        ArcRotateCamera.prototype._update = function () {
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    this.inertialAlphaOffset -= 0.01;
+                } else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    this.inertialBetaOffset -= 0.01;
+                } else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    this.inertialAlphaOffset += 0.01;
+                } else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    this.inertialBetaOffset += 0.01;
+                }
+            }
 
-            this.alpha += this.inertialAlphaOffset;
-            this.beta += this.inertialBetaOffset;
-            this.radius -= this.inertialRadiusOffset;
+            // Inertia
+            if (this.inertialAlphaOffset != 0 || this.inertialBetaOffset != 0 || this.inertialRadiusOffset != 0) {
+                this.alpha += this.inertialAlphaOffset;
+                this.beta += this.inertialBetaOffset;
+                this.radius -= this.inertialRadiusOffset;
 
-            this.inertialAlphaOffset *= this.inertia;
-            this.inertialBetaOffset *= this.inertia;
-            this.inertialRadiusOffset *= this.inertia;
+                this.inertialAlphaOffset *= this.inertia;
+                this.inertialBetaOffset *= this.inertia;
+                this.inertialRadiusOffset *= this.inertia;
 
-            if (Math.abs(this.inertialAlphaOffset) < BABYLON.Engine.epsilon)
-                this.inertialAlphaOffset = 0;
+                if (Math.abs(this.inertialAlphaOffset) < 0.001)
+                    this.inertialAlphaOffset = 0;
 
-            if (Math.abs(this.inertialBetaOffset) < BABYLON.Engine.epsilon)
-                this.inertialBetaOffset = 0;
+                if (Math.abs(this.inertialBetaOffset) < 0.001)
+                    this.inertialBetaOffset = 0;
 
-            if (Math.abs(this.inertialRadiusOffset) < BABYLON.Engine.epsilon)
-                this.inertialRadiusOffset = 0;
-        }
+                if (Math.abs(this.inertialRadiusOffset) < 0.001)
+                    this.inertialRadiusOffset = 0;
+            }
 
-        // Limits
-        if (this.lowerAlphaLimit && this.alpha < this.lowerAlphaLimit) {
-            this.alpha = this.lowerAlphaLimit;
-        }
-        if (this.upperAlphaLimit && this.alpha > this.upperAlphaLimit) {
-            this.alpha = this.upperAlphaLimit;
-        }
-        if (this.lowerBetaLimit && this.beta < this.lowerBetaLimit) {
-            this.beta = this.lowerBetaLimit;
-        }
-        if (this.upperBetaLimit && this.beta > this.upperBetaLimit) {
-            this.beta = this.upperBetaLimit;
-        }
-        if (this.lowerRadiusLimit && this.radius < this.lowerRadiusLimit) {
-            this.radius = this.lowerRadiusLimit;
-        }
-        if (this.upperRadiusLimit && this.radius > this.upperRadiusLimit) {
-            this.radius = this.upperRadiusLimit;
-        }
-    };
+            // Limits
+            if (this.lowerAlphaLimit && this.alpha < this.lowerAlphaLimit) {
+                this.alpha = this.lowerAlphaLimit;
+            }
+            if (this.upperAlphaLimit && this.alpha > this.upperAlphaLimit) {
+                this.alpha = this.upperAlphaLimit;
+            }
+            if (this.lowerBetaLimit && this.beta < this.lowerBetaLimit) {
+                this.beta = this.lowerBetaLimit;
+            }
+            if (this.upperBetaLimit && this.beta > this.upperBetaLimit) {
+                this.beta = this.upperBetaLimit;
+            }
+            if (this.lowerRadiusLimit && this.radius < this.lowerRadiusLimit) {
+                this.radius = this.lowerRadiusLimit;
+            }
+            if (this.upperRadiusLimit && this.radius > this.upperRadiusLimit) {
+                this.radius = this.upperRadiusLimit;
+            }
+        };
 
-    BABYLON.ArcRotateCamera.prototype.setPosition = function (position) {
-        var radiusv3 = position.subtract(this._getTargetPosition());
-        this.radius = radiusv3.length();
+        ArcRotateCamera.prototype.setPosition = function (position) {
+            var radiusv3 = position.subtract(this._getTargetPosition());
+            this.radius = radiusv3.length();
 
-        this.alpha = Math.atan(radiusv3.z / radiusv3.x);
-        this.beta = Math.acos(radiusv3.y / this.radius);
-    };
+            this.alpha = Math.atan(radiusv3.z / radiusv3.x);
+            this.beta = Math.acos(radiusv3.y / this.radius);
+        };
 
-    BABYLON.ArcRotateCamera.prototype._getViewMatrix = function () {
-        // Compute
-        var cosa = Math.cos(this.alpha);
-        var sina = Math.sin(this.alpha);
-        var cosb = Math.cos(this.beta);
-        var sinb = Math.sin(this.beta);
+        ArcRotateCamera.prototype._getViewMatrix = function () {
+            // Compute
+            var cosa = Math.cos(this.alpha);
+            var sina = Math.sin(this.alpha);
+            var cosb = Math.cos(this.beta);
+            var sinb = Math.sin(this.beta);
 
-        var target = this._getTargetPosition();
+            var target = this._getTargetPosition();
 
-        target.addToRef(new BABYLON.Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this.position);
-        BABYLON.Matrix.LookAtLHToRef(this.position, target, this.upVector, this._viewMatrix);
+            target.addToRef(new BABYLON.Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this.position);
+            BABYLON.Matrix.LookAtLHToRef(this.position, target, this.upVector, this._viewMatrix);
 
-        return this._viewMatrix;
-    };
+            return this._viewMatrix;
+        };
 
-    BABYLON.ArcRotateCamera.ZOOM_ON_FACTOR = 1;
-    BABYLON.ArcRotateCamera.prototype.zoomOn = function (meshes) {
-        meshes = meshes || this._scene.meshes;
+        ArcRotateCamera.prototype.zoomOn = function (meshes) {
+            meshes = meshes || this.getScene().meshes;
 
-        var minMaxVector = BABYLON.Mesh.MinMax(meshes);
-        var distance = BABYLON.Vector3.Distance(minMaxVector.min, minMaxVector.max);
+            var minMaxVector = BABYLON.Mesh.MinMax(meshes);
+            var distance = BABYLON.Vector3.Distance(minMaxVector.min, minMaxVector.max);
 
-        this.radius = distance * BABYLON.ArcRotateCamera.ZOOM_ON_FACTOR;
+            this.radius = distance * this.zoomOnFactor;
 
-        this.focusOn({min: minMaxVector.min, max: minMaxVector.max, distance: distance});
-    };
+            this.focusOn({ min: minMaxVector.min, max: minMaxVector.max, distance: distance });
+        };
 
-    BABYLON.ArcRotateCamera.prototype.focusOn = function (meshesOrMinMaxVectorAndDistance) {
-        var meshesOrMinMaxVector;
-        var distance;
+        ArcRotateCamera.prototype.focusOn = function (meshesOrMinMaxVectorAndDistance) {
+            var meshesOrMinMaxVector;
+            var distance;
 
-        if (meshesOrMinMaxVectorAndDistance.min === undefined) { // meshes
-            meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance || this._scene.meshes;
-            meshesOrMinMaxVector = BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
-            distance = BABYLON.Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
-        }
-        else { //minMaxVector and distance
-            meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance;
-            distance = meshesOrMinMaxVectorAndDistance.distance;
-        }
-        
-        this.target = BABYLON.Mesh.Center(meshesOrMinMaxVector);
-        
-        this.maxZ = distance * 2;
-    };
+            if (meshesOrMinMaxVectorAndDistance.min === undefined) {
+                meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance || this.getScene().meshes;
+                meshesOrMinMaxVector = BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
+                distance = BABYLON.Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
+            } else {
+                meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance;
+                distance = meshesOrMinMaxVectorAndDistance.distance;
+            }
 
-})();
+            this.target = BABYLON.Mesh.Center(meshesOrMinMaxVector);
 
+            this.maxZ = distance * 2;
+        };
+        return ArcRotateCamera;
+    })(BABYLON.Camera);
+    BABYLON.ArcRotateCamera = ArcRotateCamera;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.arcRotateCamera.js.map

+ 410 - 0
Babylon/Cameras/babylon.arcRotateCamera.ts

@@ -0,0 +1,410 @@
+module BABYLON {
+    declare var window;
+
+    var eventPrefix = Tools.GetPointerPrefix();
+
+    export class ArcRotateCamera extends Camera {
+        public inertialAlphaOffset = 0;
+        public inertialBetaOffset = 0;
+        public inertialRadiusOffset = 0;
+        public lowerAlphaLimit = null;
+        public upperAlphaLimit = null;
+        public lowerBetaLimit = 0.01;
+        public upperBetaLimit = Math.PI;
+        public lowerRadiusLimit = null;
+        public upperRadiusLimit = null;
+        public angularSensibility = 1000.0;
+        public wheelPrecision = 3.0;
+        public keysUp = [38];
+        public keysDown = [40];
+        public keysLeft = [37];
+        public keysRight = [39];
+        public zoomOnFactor = 1;
+
+        private _keys = [];
+        private _viewMatrix = new BABYLON.Matrix();
+        private _attachedElement: HTMLElement;
+
+        private _onPointerDown; //ANY
+        private _onPointerUp; //ANY
+        private _onPointerMove; //ANY
+        private _wheel; //ANY
+        private _onMouseMove; //ANY
+        private _onKeyDown; //ANY
+        private _onKeyUp; //ANY
+        private _onLostFocus; //ANY
+        private _reset; //ANY
+        private _onGestureStart; //ANY
+        private _onGesture; //ANY
+        private _MSGestureHandler;
+
+        //ANY
+        constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: any, scene) {
+            super(name, BABYLON.Vector3.Zero(), scene);
+
+            this.getViewMatrix();
+        }
+
+        public _getTargetPosition(): Vector3 {
+            return this.target.position || this.target;
+        }
+
+        // Cache
+        public _initCache(): void {
+            super._initCache();
+            this._cache.target = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.alpha = undefined;
+            this._cache.beta = undefined;
+            this._cache.radius = undefined;
+        }
+
+        public _updateCache(ignoreParentClass?: boolean): void {
+            if (!ignoreParentClass) {
+                super._updateCache();
+            }
+
+            this._cache.target.copyFrom(this._getTargetPosition());
+            this._cache.alpha = this.alpha;
+            this._cache.beta = this.beta;
+            this._cache.radius = this.radius;
+        }
+
+        // Synchronized
+        public _isSynchronizedViewMatrix(): boolean {
+            if (!super._isSynchronizedViewMatrix())
+                return false;
+
+            return this._cache.target.equals(this._getTargetPosition())
+                && this._cache.alpha === this.alpha
+                && this._cache.beta === this.beta
+                && this._cache.radius === this.radius;
+        }
+
+        // Methods
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            var previousPosition;
+            var pointerId;
+
+            if (this._attachedElement) {
+                return;
+            }
+            this._attachedElement = element;
+
+            var engine = this.getEngine();
+
+            if (this._onPointerDown === undefined) {
+                this._onPointerDown = evt => {
+
+                    if (pointerId) {
+                        return;
+                    }
+
+                    pointerId = evt.pointerId;
+
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onPointerUp = evt => {
+                    previousPosition = null;
+                    pointerId = null;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+
+                this._onPointerMove = evt => {
+                    if (!previousPosition) {
+                        return;
+                    }
+
+                    if (pointerId !== evt.pointerId) {
+                        return;
+                    }
+
+                    var offsetX = evt.clientX - previousPosition.x;
+                    var offsetY = evt.clientY - previousPosition.y;
+
+                    this.inertialAlphaOffset -= offsetX / this.angularSensibility;
+                    this.inertialBetaOffset -= offsetY / this.angularSensibility;
+
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onMouseMove = evt => {
+                    if (!engine.isPointerLock) {
+                        return;
+                    }
+
+                    var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                    var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+
+                    this.inertialAlphaOffset -= offsetX / this.angularSensibility;
+                    this.inertialBetaOffset -= offsetY / this.angularSensibility;
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._wheel = event => {
+                    var delta = 0;
+                    if (event.wheelDelta) {
+                        delta = event.wheelDelta / (this.wheelPrecision * 40);
+                    } else if (event.detail) {
+                        delta = -event.detail / this.wheelPrecision;
+                    }
+
+                    if (delta)
+                        this.inertialRadiusOffset += delta;
+
+                    if (event.preventDefault) {
+                        if (!noPreventDefault) {
+                            event.preventDefault();
+                        }
+                    }
+                };
+
+                this._onKeyDown = evt => {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index === -1) {
+                            this._keys.push(evt.keyCode);
+                        }
+
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
+                        }
+                    }
+                };
+
+                this._onKeyUp = evt => {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index >= 0) {
+                            this._keys.splice(index, 1);
+                        }
+
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
+                        }
+                    }
+                };
+
+                this._onLostFocus = () => {
+                    this._keys = [];
+                    pointerId = null;
+                };
+
+                this._onGestureStart = e => {
+                    if (window.MSGesture === undefined) {
+                        return;
+                    }
+
+                    if (!this._MSGestureHandler) {
+                        this._MSGestureHandler = new MSGesture();
+                        this._MSGestureHandler.target = element;
+                    }
+
+                    this._MSGestureHandler.addPointer(e.pointerId);
+                };
+
+                this._onGesture = e => {
+                    this.radius *= e.scale;
+
+
+                    if (e.preventDefault) {
+                        if (!noPreventDefault) {
+                            e.stopPropagation();
+                            e.preventDefault();
+                        }
+                    }
+                };
+
+                this._reset = () => {
+                    this._keys = [];
+                    this.inertialAlphaOffset = 0;
+                    this.inertialBetaOffset = 0;
+                    previousPosition = null;
+                    pointerId = null;
+                };
+            }
+
+            element.addEventListener(eventPrefix + "down", this._onPointerDown, false);
+            element.addEventListener(eventPrefix + "up", this._onPointerUp, false);
+            element.addEventListener(eventPrefix + "out", this._onPointerUp, false);
+            element.addEventListener(eventPrefix + "move", this._onPointerMove, false);
+            element.addEventListener("mousemove", this._onMouseMove, false);
+            element.addEventListener("MSPointerDown", this._onGestureStart, false);
+            element.addEventListener("MSGestureChange", this._onGesture, false);
+            window.addEventListener("keydown", this._onKeyDown, false);
+            window.addEventListener("keyup", this._onKeyUp, false);
+            window.addEventListener('mousewheel', this._wheel, false);
+            window.addEventListener('DOMMouseScroll', this._wheel, false);
+            window.addEventListener("blur", this._onLostFocus, false);
+        }
+
+        public detachControl(element: HTMLElement): void {
+            if (this._attachedElement != element) {
+                return;
+            }
+
+            element.removeEventListener(eventPrefix + "down", this._onPointerDown);
+            element.removeEventListener(eventPrefix + "up", this._onPointerUp);
+            element.removeEventListener(eventPrefix + "out", this._onPointerUp);
+            element.removeEventListener(eventPrefix + "move", this._onPointerMove);
+            element.removeEventListener("mousemove", this._onMouseMove);
+            element.removeEventListener("MSPointerDown", this._onGestureStart);
+            element.removeEventListener("MSGestureChange", this._onGesture);
+            window.removeEventListener("keydown", this._onKeyDown);
+            window.removeEventListener("keyup", this._onKeyUp);
+            window.removeEventListener('mousewheel', this._wheel);
+            window.removeEventListener('DOMMouseScroll', this._wheel);
+            window.removeEventListener("blur", this._onLostFocus);
+
+            this._MSGestureHandler = null;
+            this._attachedElement = null;
+
+            if (this._reset) {
+                this._reset();
+            }
+        }
+
+        public _update(): void {
+            // Keyboard
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    this.inertialAlphaOffset -= 0.01;
+                } else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    this.inertialBetaOffset -= 0.01;
+                } else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    this.inertialAlphaOffset += 0.01;
+                } else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    this.inertialBetaOffset += 0.01;
+                }
+            }
+
+            // Inertia
+            if (this.inertialAlphaOffset != 0 || this.inertialBetaOffset != 0 || this.inertialRadiusOffset != 0) {
+
+                this.alpha += this.inertialAlphaOffset;
+                this.beta += this.inertialBetaOffset;
+                this.radius -= this.inertialRadiusOffset;
+
+                this.inertialAlphaOffset *= this.inertia;
+                this.inertialBetaOffset *= this.inertia;
+                this.inertialRadiusOffset *= this.inertia;
+
+                if (Math.abs(this.inertialAlphaOffset) < 0.001) //ANY BABYLON.Engine.epsilon
+                    this.inertialAlphaOffset = 0;
+
+                if (Math.abs(this.inertialBetaOffset) < 0.001) //ANY BABYLON.Engine.epsilon
+                    this.inertialBetaOffset = 0;
+
+                if (Math.abs(this.inertialRadiusOffset) < 0.001) //ANY BABYLON.Engine.epsilon
+                    this.inertialRadiusOffset = 0;
+            }
+
+            // Limits
+            if (this.lowerAlphaLimit && this.alpha < this.lowerAlphaLimit) {
+                this.alpha = this.lowerAlphaLimit;
+            }
+            if (this.upperAlphaLimit && this.alpha > this.upperAlphaLimit) {
+                this.alpha = this.upperAlphaLimit;
+            }
+            if (this.lowerBetaLimit && this.beta < this.lowerBetaLimit) {
+                this.beta = this.lowerBetaLimit;
+            }
+            if (this.upperBetaLimit && this.beta > this.upperBetaLimit) {
+                this.beta = this.upperBetaLimit;
+            }
+            if (this.lowerRadiusLimit && this.radius < this.lowerRadiusLimit) {
+                this.radius = this.lowerRadiusLimit;
+            }
+            if (this.upperRadiusLimit && this.radius > this.upperRadiusLimit) {
+                this.radius = this.upperRadiusLimit;
+            }
+        }
+
+        public setPosition(position: Vector3): void {
+            var radiusv3 = position.subtract(this._getTargetPosition());
+            this.radius = radiusv3.length();
+
+            this.alpha = Math.atan(radiusv3.z / radiusv3.x);
+            this.beta = Math.acos(radiusv3.y / this.radius);
+        }
+
+        public _getViewMatrix(): Matrix {
+            // Compute
+            var cosa = Math.cos(this.alpha);
+            var sina = Math.sin(this.alpha);
+            var cosb = Math.cos(this.beta);
+            var sinb = Math.sin(this.beta);
+
+            var target = this._getTargetPosition();
+
+            target.addToRef(new BABYLON.Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this.position);
+            Matrix.LookAtLHToRef(this.position, target, this.upVector, this._viewMatrix);
+
+            return this._viewMatrix;
+        }
+
+        public zoomOn(meshes?: Mesh[]): void {
+            meshes = meshes || this.getScene().meshes;
+
+            var minMaxVector = BABYLON.Mesh.MinMax(meshes);
+            var distance = BABYLON.Vector3.Distance(minMaxVector.min, minMaxVector.max);
+
+            this.radius = distance * this.zoomOnFactor;
+
+            this.focusOn({ min: minMaxVector.min, max: minMaxVector.max, distance: distance });
+        }
+
+        public focusOn(meshesOrMinMaxVectorAndDistance): void {
+            var meshesOrMinMaxVector;
+            var distance;
+
+            if (meshesOrMinMaxVectorAndDistance.min === undefined) { // meshes
+                meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance || this.getScene().meshes;
+                meshesOrMinMaxVector = BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
+                distance = BABYLON.Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
+            }
+            else { //minMaxVector and distance
+                meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance;
+                distance = meshesOrMinMaxVectorAndDistance.distance;
+            }
+
+            this.target = Mesh.Center(meshesOrMinMaxVector);
+
+            this.maxZ = distance * 2;
+        }
+    }
+} 

+ 242 - 276
Babylon/Cameras/babylon.camera.js

@@ -1,335 +1,301 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    var Camera = (function (_super) {
+        __extends(Camera, _super);
+        //ANY
+        function Camera(name, position, scene) {
+            _super.call(this, name, scene);
+            this.position = position;
+            // Members
+            this.upVector = BABYLON.Vector3.Up();
+            this.orthoLeft = null;
+            this.orthoRight = null;
+            this.orthoBottom = null;
+            this.orthoTop = null;
+            this.fov = 0.8;
+            this.minZ = 0.1;
+            this.maxZ = 1000.0;
+            this.inertia = 0.9;
+            this.mode = Camera.PERSPECTIVE_CAMERA;
+            this.isIntermediate = false;
+            this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
+            this._computedViewMatrix = BABYLON.Matrix.Identity();
+            this._projectionMatrix = new BABYLON.Matrix();
+            this.subCameras = [];
+            this._postProcesses = [];
+            this._postProcessesTakenIndices = [];
+
+            scene.cameras.push(this);
+
+            if (!scene.activeCamera) {
+                scene.activeCamera = this;
+            }
+        }
+        //Cache
+        Camera.prototype._initCache = function () {
+            _super.prototype._initCache.call(this);
+
+            this._cache.position = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.upVector = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+
+            this._cache.mode = undefined;
+            this._cache.minZ = undefined;
+            this._cache.maxZ = undefined;
+
+            this._cache.fov = undefined;
+            this._cache.aspectRatio = undefined;
+
+            this._cache.orthoLeft = undefined;
+            this._cache.orthoRight = undefined;
+            this._cache.orthoBottom = undefined;
+            this._cache.orthoTop = undefined;
+            this._cache.renderWidth = undefined;
+            this._cache.renderHeight = undefined;
+        };
+
+        Camera.prototype._updateCache = function (ignoreParentClass) {
+            if (!ignoreParentClass) {
+                _super.prototype._updateCache.call(this);
+            }
 
-(function () {
-    BABYLON.Camera = function (name, position, scene) {
-        BABYLON.Node.call(this, scene);
-        
-        this.name = name;
-        this.id = name;
-        this.position = position.clone();
-        this.upVector = BABYLON.Vector3.Up();
+            var engine = this.getEngine();
 
-        scene.cameras.push(this);
+            this._cache.position.copyFrom(this.position);
+            this._cache.upVector.copyFrom(this.upVector);
 
-        if (!scene.activeCamera) {
-            scene.activeCamera = this;
-        }
+            this._cache.mode = this.mode;
+            this._cache.minZ = this.minZ;
+            this._cache.maxZ = this.maxZ;
 
-        this._computedViewMatrix = BABYLON.Matrix.Identity();
-        this._projectionMatrix = new BABYLON.Matrix();
+            this._cache.fov = this.fov;
+            this._cache.aspectRatio = engine.getAspectRatio(this);
 
-        // Sub-cameras
-        this.subCameras = [];
+            this._cache.orthoLeft = this.orthoLeft;
+            this._cache.orthoRight = this.orthoRight;
+            this._cache.orthoBottom = this.orthoBottom;
+            this._cache.orthoTop = this.orthoTop;
+            this._cache.renderWidth = engine.getRenderWidth();
+            this._cache.renderHeight = engine.getRenderHeight();
+        };
 
-        // Animations
-        this.animations = [];
+        Camera.prototype._updateFromScene = function () {
+            this.updateCache();
+            this._update();
+        };
 
-        // Postprocesses
-        this._postProcesses = [];
-        this._postProcessesTakenIndices = [];
+        // Synchronized
+        Camera.prototype._isSynchronized = function () {
+            return this._isSynchronizedViewMatrix() && this._isSynchronizedProjectionMatrix();
+        };
 
-        // Viewport
-        this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
+        Camera.prototype._isSynchronizedViewMatrix = function () {
+            if (!_super.prototype._isSynchronized.call(this))
+                return false;
 
-        //Cache
-        BABYLON.Camera.prototype._initCache.call(this);
-    };
-
-    BABYLON.Camera.prototype = Object.create(BABYLON.Node.prototype);
-
-    // Statics
-    BABYLON.Camera.PERSPECTIVE_CAMERA = 0;
-    BABYLON.Camera.ORTHOGRAPHIC_CAMERA = 1;
-
-    // Members
-    BABYLON.Camera.prototype.orthoLeft = null;
-    BABYLON.Camera.prototype.orthoRight = null;
-    BABYLON.Camera.prototype.orthoBottom = null;
-    BABYLON.Camera.prototype.orthoTop = null;
-    BABYLON.Camera.prototype.fov = 0.8;
-    BABYLON.Camera.prototype.minZ = 0.1;
-    BABYLON.Camera.prototype.maxZ = 1000.0;
-    BABYLON.Camera.prototype.inertia = 0.9;
-    BABYLON.Camera.prototype.mode = BABYLON.Camera.PERSPECTIVE_CAMERA;
-    BABYLON.Camera.prototype.isIntermediate = false;
-
-    // Properties
-    BABYLON.Camera.prototype.getScene = function () {
-        return this._scene;
-    };
-
-    // Methods
-
-    //Cache
-    BABYLON.Camera.prototype._initCache = function () {
-        this._cache.position = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-        this._cache.upVector = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-
-        this._cache.mode = undefined;
-        this._cache.minZ = undefined;
-        this._cache.maxZ = undefined;
-
-        this._cache.fov = undefined;
-        this._cache.aspectRatio = undefined;
-
-        this._cache.orthoLeft = undefined;
-        this._cache.orthoRight = undefined;
-        this._cache.orthoBottom = undefined;
-        this._cache.orthoTop = undefined;
-        this._cache.renderWidth = undefined;
-        this._cache.renderHeight = undefined;
-    };
-
-    BABYLON.Camera.prototype._updateCache = function (ignoreParentClass) {
-        if (!ignoreParentClass) {
-            BABYLON.Node.prototype._updateCache.call(this);
-        }
+            return this._cache.position.equals(this.position) && this._cache.upVector.equals(this.upVector) && this.isSynchronizedWithParent();
+        };
 
-        var engine = this._scene.getEngine();
-
-        this._cache.position.copyFrom(this.position);
-        this._cache.upVector.copyFrom(this.upVector);
-
-        this._cache.mode = this.mode;
-        this._cache.minZ = this.minZ;
-        this._cache.maxZ = this.maxZ;
-
-        this._cache.fov = this.fov;
-        this._cache.aspectRatio = engine.getAspectRatio(this);
-
-        this._cache.orthoLeft = this.orthoLeft;
-        this._cache.orthoRight = this.orthoRight;
-        this._cache.orthoBottom = this.orthoBottom;
-        this._cache.orthoTop = this.orthoTop;
-        this._cache.renderWidth = engine.getRenderWidth();
-        this._cache.renderHeight = engine.getRenderHeight();
-    };
-
-    BABYLON.Camera.prototype._updateFromScene = function () {
-        this.updateCache();
-        this._update();
-    };
-
-    // Synchronized
-    BABYLON.Camera.prototype._isSynchronized = function () {
-        return this._isSynchronizedViewMatrix() && this._isSynchronizedProjectionMatrix();
-    };
-
-    BABYLON.Camera.prototype._isSynchronizedViewMatrix = function () {
-        if (!BABYLON.Node.prototype._isSynchronized.call(this))
-            return false;
-
-        return this._cache.position.equals(this.position)
-            && this._cache.upVector.equals(this.upVector)
-            && this.isSynchronizedWithParent();
-    };
-
-    BABYLON.Camera.prototype._isSynchronizedProjectionMatrix = function () {
-        var check = this._cache.mode === this.mode
-             && this._cache.minZ === this.minZ
-             && this._cache.maxZ === this.maxZ;
-             
-        if (!check) {
-            return false;
-        }
+        Camera.prototype._isSynchronizedProjectionMatrix = function () {
+            var check = this._cache.mode === this.mode && this._cache.minZ === this.minZ && this._cache.maxZ === this.maxZ;
 
-        var engine = this._scene.getEngine();
+            if (!check) {
+                return false;
+            }
 
-        if (this.mode === BABYLON.Camera.PERSPECTIVE_CAMERA) {
-            check = this._cache.fov === this.fov
-                 && this._cache.aspectRatio === engine.getAspectRatio(this);
-        }
-        else {
-            check = this._cache.orthoLeft === this.orthoLeft
-                 && this._cache.orthoRight === this.orthoRight
-                 && this._cache.orthoBottom === this.orthoBottom
-                 && this._cache.orthoTop === this.orthoTop
-                 && this._cache.renderWidth === engine.getRenderWidth()
-                 && this._cache.renderHeight === engine.getRenderHeight();
-        }
+            var engine = this.getEngine();
 
-        return check;
-    };
-
-    // Controls
-    BABYLON.Camera.prototype.attachControl = function (canvas) {
-    };
-    
-    BABYLON.Camera.prototype.detachControl = function (canvas) {
-    };
-
-    BABYLON.Camera.prototype._update = function () {
-    };
-    
-    BABYLON.Camera.prototype.attachPostProcess = function (postProcess, insertAt) {
-        if (!postProcess._reusable && this._postProcesses.indexOf(postProcess) > -1) {
-            console.error("You're trying to reuse a post process not defined as reusable.");
-            return;
-        }
+            if (this.mode === BABYLON.Camera.PERSPECTIVE_CAMERA) {
+                check = this._cache.fov === this.fov && this._cache.aspectRatio === engine.getAspectRatio(this);
+            } else {
+                check = this._cache.orthoLeft === this.orthoLeft && this._cache.orthoRight === this.orthoRight && this._cache.orthoBottom === this.orthoBottom && this._cache.orthoTop === this.orthoTop && this._cache.renderWidth === engine.getRenderWidth() && this._cache.renderHeight === engine.getRenderHeight();
+            }
 
-        if (insertAt == null || insertAt < 0) {
-            this._postProcesses.push(postProcess);
-            this._postProcessesTakenIndices.push(this._postProcesses.length - 1);
+            return check;
+        };
 
-            return this._postProcesses.length - 1;
-        }
+        // Controls
+        Camera.prototype.attachControl = function (element) {
+        };
 
-        var add = 0;
+        Camera.prototype.detachControl = function (element) {
+        };
 
-        if (this._postProcesses[insertAt]) {
+        Camera.prototype._update = function () {
+        };
 
-            var start = this._postProcesses.length - 1;
+        //ANY
+        Camera.prototype.attachPostProcess = function (postProcess, insertAt) {
+            if (typeof insertAt === "undefined") { insertAt = null; }
+            if (!postProcess._reusable && this._postProcesses.indexOf(postProcess) > -1) {
+                console.error("You're trying to reuse a post process not defined as reusable.");
+                return 0;
+            }
 
+            if (insertAt == null || insertAt < 0) {
+                this._postProcesses.push(postProcess);
+                this._postProcessesTakenIndices.push(this._postProcesses.length - 1);
 
-            for (var i = start; i >= insertAt + 1; --i) {
-                this._postProcesses[i + 1] = this._postProcesses[i];
+                return this._postProcesses.length - 1;
             }
 
-            add = 1;
-        }
+            var add = 0;
 
-        for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
-            if (this._postProcessesTakenIndices[i] < insertAt) {
-                continue;
-            }
+            if (this._postProcesses[insertAt]) {
+                var start = this._postProcesses.length - 1;
 
-            var start = this._postProcessesTakenIndices.length - 1;
-            for (var j = start; j >= i; --j) {
-                this._postProcessesTakenIndices[j + 1] = this._postProcessesTakenIndices[j] + add;
+                for (var i = start; i >= insertAt + 1; --i) {
+                    this._postProcesses[i + 1] = this._postProcesses[i];
+                }
+
+                add = 1;
             }
-            this._postProcessesTakenIndices[i] = insertAt;
-            break;
-        }
 
-        if (!add && this._postProcessesTakenIndices.indexOf(insertAt) == -1) {
-            this._postProcessesTakenIndices.push(insertAt);
-        }
+            for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
+                if (this._postProcessesTakenIndices[i] < insertAt) {
+                    continue;
+                }
 
-        var result = insertAt + add;
+                start = this._postProcessesTakenIndices.length - 1;
+                for (var j = start; j >= i; --j) {
+                    this._postProcessesTakenIndices[j + 1] = this._postProcessesTakenIndices[j] + add;
+                }
+                this._postProcessesTakenIndices[i] = insertAt;
+                break;
+            }
 
-        this._postProcesses[result] = postProcess;
+            if (!add && this._postProcessesTakenIndices.indexOf(insertAt) == -1) {
+                this._postProcessesTakenIndices.push(insertAt);
+            }
 
-        return result;
-    };
+            var result = insertAt + add;
 
-    BABYLON.Camera.prototype.detachPostProcess = function (postProcess, atIndices) {
-        var result = [];
+            this._postProcesses[result] = postProcess;
 
+            return result;
+        };
 
-        if (!atIndices) {
+        //ANY
+        Camera.prototype.detachPostProcess = function (postProcess, atIndices) {
+            if (typeof atIndices === "undefined") { atIndices = null; }
+            var result = [];
 
-            var length = this._postProcesses.length;
+            if (!atIndices) {
+                var length = this._postProcesses.length;
 
-            for (var i = 0; i < length; i++) {
+                for (var i = 0; i < length; i++) {
+                    if (this._postProcesses[i] !== postProcess) {
+                        continue;
+                    }
 
-                if (this._postProcesses[i] !== postProcess) {
-                    continue;
+                    delete this._postProcesses[i];
+
+                    var index = this._postProcessesTakenIndices.indexOf(i);
+                    this._postProcessesTakenIndices.splice(index, 1);
                 }
+            } else {
+                atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
+                for (i = 0; i < atIndices.length; i++) {
+                    var foundPostProcess = this._postProcesses[atIndices[i]];
+
+                    if (foundPostProcess !== postProcess) {
+                        result.push(i);
+                        continue;
+                    }
 
-                delete this._postProcesses[i];
+                    delete this._postProcesses[atIndices[i]];
 
-                var index = this._postProcessesTakenIndices.indexOf(i);
-                this._postProcessesTakenIndices.splice(index, 1);
+                    index = this._postProcessesTakenIndices.indexOf(atIndices[i]);
+                    this._postProcessesTakenIndices.splice(index, 1);
+                }
             }
+            return result;
+        };
 
-        }
-        else {
-            atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
-            for (var i = 0; i < atIndices.length; i++) {
-                var foundPostProcess = this._postProcesses[atIndices[i]];
+        Camera.prototype.getWorldMatrix = function () {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
 
-                if (foundPostProcess !== postProcess) {
-                    result.push(i);
-                    continue;
-                }
+            var viewMatrix = this.getViewMatrix();
 
-                delete this._postProcesses[atIndices[i]];
+            viewMatrix.invertToRef(this._worldMatrix);
 
-                var index = this._postProcessesTakenIndices.indexOf(atIndices[i]);
-                this._postProcessesTakenIndices.splice(index, 1);
-            }
-        }
-        return result;
-    };
+            return this._worldMatrix;
+        };
 
-    BABYLON.Camera.prototype.getWorldMatrix = function () {
-        if (!this._worldMatrix) {
-            this._worldMatrix = BABYLON.Matrix.Identity();
-        }
-        
-        var viewMatrix = this.getViewMatrix();
+        Camera.prototype._getViewMatrix = function () {
+            return BABYLON.Matrix.Identity();
+        };
 
-        viewMatrix.invertToRef(this._worldMatrix);
+        Camera.prototype.getViewMatrix = function () {
+            this._computedViewMatrix = this._computeViewMatrix();
 
-        return this._worldMatrix;
-    };
+            if (!this.parent || !this.parent.getWorldMatrix || this.isSynchronized()) {
+                return this._computedViewMatrix;
+            }
 
-    BABYLON.Camera.prototype._getViewMatrix = function () {
-        return BABYLON.Matrix.Identity();
-    };
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
 
-    BABYLON.Camera.prototype.getViewMatrix = function () {
-        this._computedViewMatrix = this._computeViewMatrix();
+            this._computedViewMatrix.invertToRef(this._worldMatrix);
 
-        if (!this.parent
-            || !this.parent.getWorldMatrix
-            || this.isSynchronized()) {
-            return this._computedViewMatrix;
-        }
+            this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
 
-        if (!this._worldMatrix) {
-            this._worldMatrix = BABYLON.Matrix.Identity();
-        }
-        
-        this._computedViewMatrix.invertToRef(this._worldMatrix);
+            this._computedViewMatrix.invert();
 
-        this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
+            this._currentRenderId = this.getScene().getRenderId();
+            return this._computedViewMatrix;
+        };
 
-        this._computedViewMatrix.invert();
+        Camera.prototype._computeViewMatrix = function (force) {
+            if (!force && this._isSynchronizedViewMatrix()) {
+                return this._computedViewMatrix;
+            }
 
-        this._currentRenderId = this._scene.getRenderId();
-        return this._computedViewMatrix;
-    };
-    
-    BABYLON.Camera.prototype._computeViewMatrix = function (force) {
-        if (!force && this._isSynchronizedViewMatrix()) {
+            this._computedViewMatrix = this._getViewMatrix();
+            if (!this.parent || !this.parent.getWorldMatrix) {
+                this._currentRenderId = this.getScene().getRenderId();
+            }
             return this._computedViewMatrix;
-        }
+        };
 
-        this._computedViewMatrix = this._getViewMatrix();
-        if (!this.parent || !this.parent.getWorldMatrix) {
-            this._currentRenderId = this._scene.getRenderId();
-        }
-        return this._computedViewMatrix;
-    };
+        Camera.prototype.getProjectionMatrix = function (force) {
+            if (!force && this._isSynchronizedProjectionMatrix()) {
+                return this._projectionMatrix;
+            }
 
-    BABYLON.Camera.prototype.getProjectionMatrix = function (force) {
-        if (!force && this._isSynchronizedProjectionMatrix()) {
-            return this._projectionMatrix;
-        }
+            var engine = this.getEngine();
+            if (this.mode === BABYLON.Camera.PERSPECTIVE_CAMERA) {
+                BABYLON.Matrix.PerspectiveFovLHToRef(this.fov, engine.getAspectRatio(this), this.minZ, this.maxZ, this._projectionMatrix);
+                return this._projectionMatrix;
+            }
 
-        var engine = this._scene.getEngine();
-        if (this.mode === BABYLON.Camera.PERSPECTIVE_CAMERA) {
-            BABYLON.Matrix.PerspectiveFovLHToRef(this.fov, engine.getAspectRatio(this), this.minZ, this.maxZ, this._projectionMatrix);
+            var halfWidth = engine.getRenderWidth() / 2.0;
+            var halfHeight = engine.getRenderHeight() / 2.0;
+            BABYLON.Matrix.OrthoOffCenterLHToRef(this.orthoLeft || -halfWidth, this.orthoRight || halfWidth, this.orthoBottom || -halfHeight, this.orthoTop || halfHeight, this.minZ, this.maxZ, this._projectionMatrix);
             return this._projectionMatrix;
-        }
+        };
 
-        var halfWidth = engine.getRenderWidth() / 2.0;
-        var halfHeight = engine.getRenderHeight() / 2.0;
-        BABYLON.Matrix.OrthoOffCenterLHToRef(this.orthoLeft || -halfWidth, this.orthoRight || halfWidth, this.orthoBottom || -halfHeight, this.orthoTop || halfHeight, this.minZ, this.maxZ, this._projectionMatrix);
-        return this._projectionMatrix;
-    };
-
-    BABYLON.Camera.prototype.dispose = function () {
-        // Remove from scene
-        var index = this._scene.cameras.indexOf(this);
-        this._scene.cameras.splice(index, 1);
-        
-        // Postprocesses
-        for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
-            this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
-        }
-    };
-})();
+        Camera.prototype.dispose = function () {
+            // Remove from scene
+            var index = this.getScene().cameras.indexOf(this);
+            this.getScene().cameras.splice(index, 1);
+
+            for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
+                this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
+            }
+        };
+        Camera.PERSPECTIVE_CAMERA = 0;
+        Camera.ORTHOGRAPHIC_CAMERA = 1;
+        return Camera;
+    })(BABYLON.Node);
+    BABYLON.Camera = Camera;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.camera.js.map

+ 313 - 0
Babylon/Cameras/babylon.camera.ts

@@ -0,0 +1,313 @@
+module BABYLON {
+    export class Camera extends Node {
+        // Statics
+        public static PERSPECTIVE_CAMERA = 0;
+        public static ORTHOGRAPHIC_CAMERA = 1;
+
+        // Members
+        public upVector = Vector3.Up();
+        public orthoLeft = null;
+        public orthoRight = null;
+        public orthoBottom = null;
+        public orthoTop = null;
+        public fov = 0.8;
+        public minZ = 0.1;
+        public maxZ = 1000.0;
+        public inertia = 0.9;
+        public mode = Camera.PERSPECTIVE_CAMERA;
+        public isIntermediate = false;
+        public viewport = new Viewport(0, 0, 1.0, 1.0);
+
+        private _computedViewMatrix = BABYLON.Matrix.Identity();
+        private _projectionMatrix = new BABYLON.Matrix();
+        private _worldMatrix: Matrix;
+        private subCameras = [];
+        public _postProcesses = [];
+        public _postProcessesTakenIndices = [];
+
+        //ANY
+        constructor(name: string, public position: Vector3, scene) {
+            super(name, scene);
+
+            scene.cameras.push(this);
+
+            if (!scene.activeCamera) {
+                scene.activeCamera = this;
+            }
+        }
+
+        //Cache
+        public _initCache() {
+            super._initCache();
+
+            this._cache.position = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.upVector = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+
+            this._cache.mode = undefined;
+            this._cache.minZ = undefined;
+            this._cache.maxZ = undefined;
+
+            this._cache.fov = undefined;
+            this._cache.aspectRatio = undefined;
+
+            this._cache.orthoLeft = undefined;
+            this._cache.orthoRight = undefined;
+            this._cache.orthoBottom = undefined;
+            this._cache.orthoTop = undefined;
+            this._cache.renderWidth = undefined;
+            this._cache.renderHeight = undefined;
+        }
+
+        public _updateCache(ignoreParentClass?: boolean): void {
+            if (!ignoreParentClass) {
+                super._updateCache();
+            }
+
+            var engine = this.getEngine();
+
+            this._cache.position.copyFrom(this.position);
+            this._cache.upVector.copyFrom(this.upVector);
+
+            this._cache.mode = this.mode;
+            this._cache.minZ = this.minZ;
+            this._cache.maxZ = this.maxZ;
+
+            this._cache.fov = this.fov;
+            this._cache.aspectRatio = engine.getAspectRatio(this);
+
+            this._cache.orthoLeft = this.orthoLeft;
+            this._cache.orthoRight = this.orthoRight;
+            this._cache.orthoBottom = this.orthoBottom;
+            this._cache.orthoTop = this.orthoTop;
+            this._cache.renderWidth = engine.getRenderWidth();
+            this._cache.renderHeight = engine.getRenderHeight();
+        }
+
+        public _updateFromScene(): void {
+            this.updateCache();
+            this._update();
+        }
+
+        // Synchronized
+        public _isSynchronized(): boolean {
+            return this._isSynchronizedViewMatrix() && this._isSynchronizedProjectionMatrix();
+        }
+
+        public _isSynchronizedViewMatrix(): boolean {
+            if (!super._isSynchronized())
+                return false;
+
+            return this._cache.position.equals(this.position)
+                && this._cache.upVector.equals(this.upVector)
+                && this.isSynchronizedWithParent();
+        }
+
+        public _isSynchronizedProjectionMatrix(): boolean {
+            var check = this._cache.mode === this.mode
+                && this._cache.minZ === this.minZ
+                && this._cache.maxZ === this.maxZ;
+
+            if (!check) {
+                return false;
+            }
+
+            var engine = this.getEngine();
+
+            if (this.mode === BABYLON.Camera.PERSPECTIVE_CAMERA) {
+                check = this._cache.fov === this.fov
+                && this._cache.aspectRatio === engine.getAspectRatio(this);
+            }
+            else {
+                check = this._cache.orthoLeft === this.orthoLeft
+                && this._cache.orthoRight === this.orthoRight
+                && this._cache.orthoBottom === this.orthoBottom
+                && this._cache.orthoTop === this.orthoTop
+                && this._cache.renderWidth === engine.getRenderWidth()
+                && this._cache.renderHeight === engine.getRenderHeight();
+            }
+
+            return check;
+        }
+
+        // Controls
+        public attachControl(element: HTMLElement): void {
+        }
+
+        public detachControl(element: HTMLElement): void {
+        }
+
+        public _update(): void {
+        }
+
+        //ANY
+        public attachPostProcess(postProcess, insertAt: number = null): number {
+            if (!postProcess._reusable && this._postProcesses.indexOf(postProcess) > -1) {
+                console.error("You're trying to reuse a post process not defined as reusable.");
+                return 0;
+            }
+
+            if (insertAt == null || insertAt < 0) {
+                this._postProcesses.push(postProcess);
+                this._postProcessesTakenIndices.push(this._postProcesses.length - 1);
+
+                return this._postProcesses.length - 1;
+            }
+
+            var add = 0;
+
+            if (this._postProcesses[insertAt]) {
+
+                var start = this._postProcesses.length - 1;
+
+
+                for (var i = start; i >= insertAt + 1; --i) {
+                    this._postProcesses[i + 1] = this._postProcesses[i];
+                }
+
+                add = 1;
+            }
+
+            for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
+                if (this._postProcessesTakenIndices[i] < insertAt) {
+                    continue;
+                }
+
+                start = this._postProcessesTakenIndices.length - 1;
+                for (var j = start; j >= i; --j) {
+                    this._postProcessesTakenIndices[j + 1] = this._postProcessesTakenIndices[j] + add;
+                }
+                this._postProcessesTakenIndices[i] = insertAt;
+                break;
+            }
+
+            if (!add && this._postProcessesTakenIndices.indexOf(insertAt) == -1) {
+                this._postProcessesTakenIndices.push(insertAt);
+            }
+
+            var result = insertAt + add;
+
+            this._postProcesses[result] = postProcess;
+
+            return result;
+        }
+
+        //ANY
+        public detachPostProcess(postProcess, atIndices: any = null): number[] {
+            var result = [];
+
+            if (!atIndices) {
+
+                var length = this._postProcesses.length;
+
+                for (var i = 0; i < length; i++) {
+
+                    if (this._postProcesses[i] !== postProcess) {
+                        continue;
+                    }
+
+                    delete this._postProcesses[i];
+
+                    var index = this._postProcessesTakenIndices.indexOf(i);
+                    this._postProcessesTakenIndices.splice(index, 1);
+                }
+
+            }
+            else {
+                atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
+                for (i = 0; i < atIndices.length; i++) {
+                    var foundPostProcess = this._postProcesses[atIndices[i]];
+
+                    if (foundPostProcess !== postProcess) {
+                        result.push(i);
+                        continue;
+                    }
+
+                    delete this._postProcesses[atIndices[i]];
+
+                    index = this._postProcessesTakenIndices.indexOf(atIndices[i]);
+                    this._postProcessesTakenIndices.splice(index, 1);
+                }
+            }
+            return result;
+        }
+
+        public getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
+
+            var viewMatrix = this.getViewMatrix();
+
+            viewMatrix.invertToRef(this._worldMatrix);
+
+            return this._worldMatrix;
+        }
+
+        public _getViewMatrix(): Matrix {
+            return BABYLON.Matrix.Identity();
+        }
+
+        public getViewMatrix(): Matrix {
+            this._computedViewMatrix = this._computeViewMatrix();
+
+            if (!this.parent
+                || !this.parent.getWorldMatrix
+                || this.isSynchronized()) {
+                return this._computedViewMatrix;
+            }
+
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
+
+            this._computedViewMatrix.invertToRef(this._worldMatrix);
+
+            this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
+
+            this._computedViewMatrix.invert();
+
+            this._currentRenderId = this.getScene().getRenderId();
+            return this._computedViewMatrix;
+        }
+
+        public _computeViewMatrix(force?: boolean): Matrix {
+            if (!force && this._isSynchronizedViewMatrix()) {
+                return this._computedViewMatrix;
+            }
+
+            this._computedViewMatrix = this._getViewMatrix();
+            if (!this.parent || !this.parent.getWorldMatrix) {
+                this._currentRenderId = this.getScene().getRenderId();
+            }
+            return this._computedViewMatrix;
+        }
+
+        public getProjectionMatrix(force?: boolean): Matrix {
+            if (!force && this._isSynchronizedProjectionMatrix()) {
+                return this._projectionMatrix;
+            }
+
+            var engine = this.getEngine();
+            if (this.mode === BABYLON.Camera.PERSPECTIVE_CAMERA) {
+                BABYLON.Matrix.PerspectiveFovLHToRef(this.fov, engine.getAspectRatio(this), this.minZ, this.maxZ, this._projectionMatrix);
+                return this._projectionMatrix;
+            }
+
+            var halfWidth = engine.getRenderWidth() / 2.0;
+            var halfHeight = engine.getRenderHeight() / 2.0;
+            BABYLON.Matrix.OrthoOffCenterLHToRef(this.orthoLeft || -halfWidth, this.orthoRight || halfWidth, this.orthoBottom || -halfHeight, this.orthoTop || halfHeight, this.minZ, this.maxZ, this._projectionMatrix);
+            return this._projectionMatrix;
+        }
+
+        public dispose(): void {
+            // Remove from scene
+            var index = this.getScene().cameras.indexOf(this);
+            this.getScene().cameras.splice(index, 1);
+
+            // Postprocesses
+            for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
+                this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
+            }
+        }
+    }
+}

+ 322 - 338
Babylon/Cameras/babylon.freeCamera.js

@@ -1,411 +1,395 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.FreeCamera = function (name, position, scene) {
-        BABYLON.Camera.call(this, name, position, scene);
-
-        this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
-        this.cameraRotation = new BABYLON.Vector2(0, 0);
-        this.rotation = new BABYLON.Vector3(0, 0, 0);
-        this.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
-
-        this._keys = [];
-        this.keysUp = [38];
-        this.keysDown = [40];
-        this.keysLeft = [37];
-        this.keysRight = [39];
-
-        // Collisions
-        this._collider = new BABYLON.Collider();
-        this._needMoveForGravity = true;
-
-        // Internals
-        this._currentTarget = BABYLON.Vector3.Zero();
-        this._viewMatrix = BABYLON.Matrix.Zero();
-        this._camMatrix = BABYLON.Matrix.Zero();
-        this._cameraTransformMatrix = BABYLON.Matrix.Zero();
-        this._cameraRotationMatrix = BABYLON.Matrix.Zero();
-        this._referencePoint = BABYLON.Vector3.Zero();
-        this._transformedReferencePoint = BABYLON.Vector3.Zero();
-        this._oldPosition = BABYLON.Vector3.Zero();
-        this._diffPosition = BABYLON.Vector3.Zero();
-        this._newPosition = BABYLON.Vector3.Zero();
-        this._lookAtTemp = BABYLON.Matrix.Zero();
-        this._tempMatrix = BABYLON.Matrix.Zero();
-
-        BABYLON.FreeCamera.prototype._initCache.call(this);
-    };
-
-    BABYLON.FreeCamera.prototype = Object.create(BABYLON.Camera.prototype);
-
-    // Members
-    BABYLON.FreeCamera.prototype.speed = 2.0;
-    BABYLON.FreeCamera.prototype.checkCollisions = false;
-    BABYLON.FreeCamera.prototype.applyGravity = false;
-    BABYLON.FreeCamera.prototype.noRotationConstraint = false;
-    BABYLON.FreeCamera.prototype.angularSensibility = 2000.0;
-    BABYLON.FreeCamera.prototype.lockedTarget = null;
-    BABYLON.FreeCamera.prototype.onCollide = null;
-
-    BABYLON.FreeCamera.prototype._getLockedTargetPosition = function () {
-        if (!this.lockedTarget) {
-            return null;
+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 FreeCamera = (function (_super) {
+        __extends(FreeCamera, _super);
+        //ANY
+        function FreeCamera(name, position, scene) {
+            _super.call(this, name, position, scene);
+            this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
+            this.cameraRotation = new BABYLON.Vector2(0, 0);
+            this.rotation = new BABYLON.Vector3(0, 0, 0);
+            this.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
+            this.keysUp = [38];
+            this.keysDown = [40];
+            this.keysLeft = [37];
+            this.keysRight = [39];
+            this.speed = 2.0;
+            this.checkCollisions = false;
+            this.applyGravity = false;
+            this.noRotationConstraint = false;
+            this.angularSensibility = 2000.0;
+            this.lockedTarget = null;
+            this.onCollide = null;
+            this._keys = [];
+            this._collider = new BABYLON.Collider();
+            this._needMoveForGravity = true;
+            this._currentTarget = BABYLON.Vector3.Zero();
+            this._viewMatrix = BABYLON.Matrix.Zero();
+            this._camMatrix = BABYLON.Matrix.Zero();
+            this._cameraTransformMatrix = BABYLON.Matrix.Zero();
+            this._cameraRotationMatrix = BABYLON.Matrix.Zero();
+            this._referencePoint = BABYLON.Vector3.Zero();
+            this._transformedReferencePoint = BABYLON.Vector3.Zero();
+            this._oldPosition = BABYLON.Vector3.Zero();
+            this._diffPosition = BABYLON.Vector3.Zero();
+            this._newPosition = BABYLON.Vector3.Zero();
+            this._lookAtTemp = BABYLON.Matrix.Zero();
+            this._tempMatrix = BABYLON.Matrix.Zero();
         }
+        FreeCamera.prototype._getLockedTargetPosition = function () {
+            if (!this.lockedTarget) {
+                return null;
+            }
 
-        return this.lockedTarget.position || this.lockedTarget;
-    };
+            return this.lockedTarget.position || this.lockedTarget;
+        };
 
-    // Cache
-    BABYLON.FreeCamera.prototype._initCache = function () {
-        this._cache.lockedTarget = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-        this._cache.rotation = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-    };
+        // Cache
+        FreeCamera.prototype._initCache = function () {
+            _super.prototype._initCache.call(this);
+            this._cache.lockedTarget = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.rotation = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+        };
 
-    BABYLON.FreeCamera.prototype._updateCache = function (ignoreParentClass) {
-        if (!ignoreParentClass)
-            BABYLON.Camera.prototype._updateCache.call(this);
+        FreeCamera.prototype._updateCache = function (ignoreParentClass) {
+            if (!ignoreParentClass) {
+                _super.prototype._updateCache.call(this);
+            }
 
-        var lockedTargetPosition = this._getLockedTargetPosition();
-        if (!lockedTargetPosition) {
-            this._cache.lockedTarget = null;
-        }
-        else {
-            if (!this._cache.lockedTarget) {
-                this._cache.lockedTarget = lockedTargetPosition.clone();
+            var lockedTargetPosition = this._getLockedTargetPosition();
+            if (!lockedTargetPosition) {
+                this._cache.lockedTarget = null;
+            } else {
+                if (!this._cache.lockedTarget) {
+                    this._cache.lockedTarget = lockedTargetPosition.clone();
+                } else {
+                    this._cache.lockedTarget.copyFrom(lockedTargetPosition);
+                }
             }
-            else {
-                this._cache.lockedTarget.copyFrom(lockedTargetPosition);
+
+            this._cache.rotation.copyFrom(this.rotation);
+        };
+
+        // Synchronized
+        FreeCamera.prototype._isSynchronizedViewMatrix = function () {
+            if (!_super.prototype._isSynchronizedViewMatrix.call(this)) {
+                return false;
             }
-        }
 
-        this._cache.rotation.copyFrom(this.rotation);
-    };
+            var lockedTargetPosition = this._getLockedTargetPosition();
 
-    // Synchronized
-    BABYLON.FreeCamera.prototype._isSynchronizedViewMatrix = function () {
-        if (!BABYLON.Camera.prototype._isSynchronizedViewMatrix.call(this)) {
-            return false;
-        }
+            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition) && this._cache.rotation.equals(this.rotation);
+        };
 
-        var lockedTargetPosition = this._getLockedTargetPosition();
+        // Methods
+        FreeCamera.prototype._computeLocalCameraSpeed = function () {
+            return this.speed * ((BABYLON.Tools.GetDeltaTime() / (BABYLON.Tools.GetFps() * 10.0)));
+        };
 
-        return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition)
-            && this._cache.rotation.equals(this.rotation);
-    };
+        // Target
+        FreeCamera.prototype.setTarget = function (target) {
+            this.upVector.normalize();
 
-    // Methods
-    BABYLON.FreeCamera.prototype._computeLocalCameraSpeed = function () {
-        return this.speed * ((BABYLON.Tools.GetDeltaTime() / (BABYLON.Tools.GetFps() * 10.0)));
-    };
+            BABYLON.Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
+            this._camMatrix.invert();
 
-    // Target
-    BABYLON.FreeCamera.prototype.setTarget = function (target) {
-        this.upVector.normalize();
+            this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
 
-        BABYLON.Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
-        this._camMatrix.invert();
+            var vDir = target.subtract(this.position);
 
-        this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
+            if (vDir.x >= 0.0) {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
+            } else {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
+            }
 
-        var vDir = target.subtract(this.position);
+            this.rotation.z = -Math.acos(BABYLON.Vector3.Dot(new BABYLON.Vector3(0, 1.0, 0), this.upVector));
 
-        if (vDir.x >= 0.0) {
-            this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
-        } else {
-            this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
-        }
+            if (isNaN(this.rotation.x)) {
+                this.rotation.x = 0;
+            }
 
-        this.rotation.z = -Math.acos(BABYLON.Vector3.Dot(new BABYLON.Vector3(0, 1.0, 0), this.upVector));
+            if (isNaN(this.rotation.y)) {
+                this.rotation.y = 0;
+            }
 
-        if (isNaN(this.rotation.x)) {
-            this.rotation.x = 0;
-        }
+            if (isNaN(this.rotation.z)) {
+                this.rotation.z = 0;
+            }
+        };
 
-        if (isNaN(this.rotation.y)) {
-            this.rotation.y = 0;
-        }
+        FreeCamera.prototype.getTarget = function () {
+            return this._currentTarget;
+        };
 
-        if (isNaN(this.rotation.z)) {
-            this.rotation.z = 0;
-        }
-    };
+        // Controls
+        FreeCamera.prototype.attachControl = function (element, noPreventDefault) {
+            var _this = this;
+            var previousPosition;
+            var engine = this.getEngine();
 
-    BABYLON.FreeCamera.prototype.getTarget = function () {
-        return this._currentTarget;
-    };
+            if (this._attachedElement) {
+                return;
+            }
+            this._attachedElement = element;
 
-    // Controls
-    BABYLON.FreeCamera.prototype.attachControl = function (canvas, noPreventDefault) {
-        var previousPosition;
-        var that = this;
-        var engine = this._scene.getEngine();
+            if (this._onMouseDown === undefined) {
+                this._onMouseDown = function (evt) {
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
 
-        if (this._attachedCanvas) {
-            return;
-        }
-        this._attachedCanvas = canvas;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
 
-        if (this._onMouseDown === undefined) {
-            this._onMouseDown = function (evt) {
-                previousPosition = {
-                    x: evt.clientX,
-                    y: evt.clientY
+                this._onMouseUp = function (evt) {
+                    previousPosition = null;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
                 };
 
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
+                this._onMouseOut = function (evt) {
+                    previousPosition = null;
+                    _this._keys = [];
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
 
-            this._onMouseUp = function (evt) {
-                previousPosition = null;
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
+                this._onMouseMove = function (evt) {
+                    if (!previousPosition && !engine.isPointerLock) {
+                        return;
+                    }
 
-            this._onMouseOut = function (evt) {
-                previousPosition = null;
-                that._keys = [];
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
+                    var offsetX;
+                    var offsetY;
 
-            this._onMouseMove = function (evt) {
-                if (!previousPosition && !engine.isPointerLock) {
-                    return;
-                }
+                    if (!engine.isPointerLock) {
+                        offsetX = evt.clientX - previousPosition.x;
+                        offsetY = evt.clientY - previousPosition.y;
+                    } else {
+                        offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                        offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+                    }
 
-                var offsetX;
-                var offsetY;
+                    _this.cameraRotation.y += offsetX / _this.angularSensibility;
+                    _this.cameraRotation.x += offsetY / _this.angularSensibility;
 
-                if (!engine.isPointerLock) {
-                    offsetX = evt.clientX - previousPosition.x;
-                    offsetY = evt.clientY - previousPosition.y;
-                } else {
-                    offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-                    offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
-                }
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
 
-                that.cameraRotation.y += offsetX / that.angularSensibility;
-                that.cameraRotation.x += offsetY / that.angularSensibility;
+                this._onKeyDown = function (evt) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
 
-                previousPosition = {
-                    x: evt.clientX,
-                    y: evt.clientY
+                        if (index === -1) {
+                            _this._keys.push(evt.keyCode);
+                        }
+                        if (!noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
                 };
-                if (!noPreventDefault) {
-                    evt.preventDefault();
-                }
-            };
 
-            this._onKeyDown = function (evt) {
-                if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    that.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    that.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    that.keysRight.indexOf(evt.keyCode) !== -1) {
-                    var index = that._keys.indexOf(evt.keyCode);
+                this._onKeyUp = function (evt) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
 
-                    if (index === -1) {
-                        that._keys.push(evt.keyCode);
-                    }
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
+                        if (index >= 0) {
+                            _this._keys.splice(index, 1);
+                        }
+                        if (!noPreventDefault) {
+                            evt.preventDefault();
+                        }
                     }
-                }
-            };
+                };
 
-            this._onKeyUp = function (evt) {
-                if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    that.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    that.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    that.keysRight.indexOf(evt.keyCode) !== -1) {
-                    var index = that._keys.indexOf(evt.keyCode);
+                this._onLostFocus = function () {
+                    _this._keys = [];
+                };
 
-                    if (index >= 0) {
-                        that._keys.splice(index, 1);
-                    }
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                }
-            };
-
-            this._onLostFocus = function () {
-                that._keys = [];
-            };
-
-            this._reset = function () {
-                that._keys = [];
-                previousPosition = null;
-                that.cameraDirection = new BABYLON.Vector3(0, 0, 0);
-                that.cameraRotation = new BABYLON.Vector2(0, 0);
-            };
-        }
+                this._reset = function () {
+                    _this._keys = [];
+                    previousPosition = null;
+                    _this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
+                    _this.cameraRotation = new BABYLON.Vector2(0, 0);
+                };
+            }
 
-        canvas.addEventListener("mousedown", this._onMouseDown, false);
-        canvas.addEventListener("mouseup", this._onMouseUp, false);
-        canvas.addEventListener("mouseout", this._onMouseOut, false);
-        canvas.addEventListener("mousemove", this._onMouseMove, false);
-        window.addEventListener("keydown", this._onKeyDown, false);
-        window.addEventListener("keyup", this._onKeyUp, false);
-        window.addEventListener("blur", this._onLostFocus, false);
-    };
-
-    BABYLON.FreeCamera.prototype.detachControl = function (canvas) {
-        if (this._attachedCanvas != canvas) {
-            return;
-        }
+            element.addEventListener("mousedown", this._onMouseDown, false);
+            element.addEventListener("mouseup", this._onMouseUp, false);
+            element.addEventListener("mouseout", this._onMouseOut, false);
+            element.addEventListener("mousemove", this._onMouseMove, false);
+            window.addEventListener("keydown", this._onKeyDown, false);
+            window.addEventListener("keyup", this._onKeyUp, false);
+            window.addEventListener("blur", this._onLostFocus, false);
+        };
+
+        FreeCamera.prototype.detachControl = function (element) {
+            if (this._attachedElement != element) {
+                return;
+            }
 
-        canvas.removeEventListener("mousedown", this._onMouseDown);
-        canvas.removeEventListener("mouseup", this._onMouseUp);
-        canvas.removeEventListener("mouseout", this._onMouseOut);
-        canvas.removeEventListener("mousemove", this._onMouseMove);
-        window.removeEventListener("keydown", this._onKeyDown);
-        window.removeEventListener("keyup", this._onKeyUp);
-        window.removeEventListener("blur", this._onLostFocus);
-
-        this._attachedCanvas = null;
-        if (this._reset) {
-            this._reset();
-        }
-    };
+            element.removeEventListener("mousedown", this._onMouseDown);
+            element.removeEventListener("mouseup", this._onMouseUp);
+            element.removeEventListener("mouseout", this._onMouseOut);
+            element.removeEventListener("mousemove", this._onMouseMove);
+            window.removeEventListener("keydown", this._onKeyDown);
+            window.removeEventListener("keyup", this._onKeyUp);
+            window.removeEventListener("blur", this._onLostFocus);
+
+            this._attachedElement = null;
+            if (this._reset) {
+                this._reset();
+            }
+        };
 
-    BABYLON.FreeCamera.prototype._collideWithWorld = function (velocity) {
-        this.position.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
-        this._collider.radius = this.ellipsoid;
+        FreeCamera.prototype._collideWithWorld = function (velocity) {
+            this.position.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
+            this._collider.radius = this.ellipsoid;
 
-        this._scene._getNewPosition(this._oldPosition, velocity, this._collider, 3, this._newPosition);
-        this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
+            this.getScene()._getNewPosition(this._oldPosition, velocity, this._collider, 3, this._newPosition);
+            this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
 
-        if (this._diffPosition.length() > BABYLON.Engine.collisionsEpsilon) {
-            this.position.addInPlace(this._diffPosition);
-            if (this.onCollide) {
-                this.onCollide(this._collider.collidedMesh);
+            if (this._diffPosition.length() > 0.001) {
+                this.position.addInPlace(this._diffPosition);
+                if (this.onCollide) {
+                    this.onCollide(this._collider.collidedMesh);
+                }
             }
-        }
-    };
-
-    BABYLON.FreeCamera.prototype._checkInputs = function () {
-        if (!this._localDirection) {
-            this._localDirection = BABYLON.Vector3.Zero();
-            this._transformedDirection = BABYLON.Vector3.Zero();
-        }
+        };
 
-        // Keyboard
-        for (var index = 0; index < this._keys.length; index++) {
-            var keyCode = this._keys[index];
-            var speed = this._computeLocalCameraSpeed();
-
-            if (this.keysLeft.indexOf(keyCode) !== -1) {
-                this._localDirection.copyFromFloats(-speed, 0, 0);
-            } else if (this.keysUp.indexOf(keyCode) !== -1) {
-                this._localDirection.copyFromFloats(0, 0, speed);
-            } else if (this.keysRight.indexOf(keyCode) !== -1) {
-                this._localDirection.copyFromFloats(speed, 0, 0);
-            } else if (this.keysDown.indexOf(keyCode) !== -1) {
-                this._localDirection.copyFromFloats(0, 0, -speed);
+        FreeCamera.prototype._checkInputs = function () {
+            if (!this._localDirection) {
+                this._localDirection = BABYLON.Vector3.Zero();
+                this._transformedDirection = BABYLON.Vector3.Zero();
             }
 
-            this.getViewMatrix().invertToRef(this._cameraTransformMatrix);
-            BABYLON.Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
-            this.cameraDirection.addInPlace(this._transformedDirection);
-        }
-    };
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+                var speed = this._computeLocalCameraSpeed();
+
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(-speed, 0, 0);
+                } else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(0, 0, speed);
+                } else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(speed, 0, 0);
+                } else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(0, 0, -speed);
+                }
 
-    BABYLON.FreeCamera.prototype._update = function () {
-        this._checkInputs();
+                this.getViewMatrix().invertToRef(this._cameraTransformMatrix);
+                BABYLON.Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
+                this.cameraDirection.addInPlace(this._transformedDirection);
+            }
+        };
 
-        var needToMove = this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
-        var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
+        FreeCamera.prototype._update = function () {
+            this._checkInputs();
 
-        // Move
-        if (needToMove) {
-            if (this.checkCollisions && this._scene.collisionsEnabled) {
-                this._collideWithWorld(this.cameraDirection);
+            var needToMove = this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
+            var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
 
+            // Move
+            if (needToMove) {
+                if (this.checkCollisions && this.getScene().collisionsEnabled) {
+                    this._collideWithWorld(this.cameraDirection);
 
-                if (this.applyGravity) {
-                    var oldPosition = this.position;
-                    this._collideWithWorld(this._scene.gravity);
-                    this._needMoveForGravity = (BABYLON.Vector3.DistanceSquared(oldPosition, this.position) != 0);
+                    if (this.applyGravity) {
+                        var oldPosition = this.position;
+                        this._collideWithWorld(this.getScene().gravity);
+                        this._needMoveForGravity = (BABYLON.Vector3.DistanceSquared(oldPosition, this.position) != 0);
+                    }
+                } else {
+                    this.position.addInPlace(this.cameraDirection);
                 }
-            } else {
-                this.position.addInPlace(this.cameraDirection);
             }
-        }
-
-        // Rotate
-        if (needToRotate) {
-            this.rotation.x += this.cameraRotation.x;
-            this.rotation.y += this.cameraRotation.y;
-
 
-            if (!this.noRotationConstraint) {
-                var limit = (Math.PI / 2) * 0.95;
+            // Rotate
+            if (needToRotate) {
+                this.rotation.x += this.cameraRotation.x;
+                this.rotation.y += this.cameraRotation.y;
 
+                if (!this.noRotationConstraint) {
+                    var limit = (Math.PI / 2) * 0.95;
 
-                if (this.rotation.x > limit)
-                    this.rotation.x = limit;
-                if (this.rotation.x < -limit)
-                    this.rotation.x = -limit;
+                    if (this.rotation.x > limit)
+                        this.rotation.x = limit;
+                    if (this.rotation.x < -limit)
+                        this.rotation.x = -limit;
+                }
             }
-        }
 
-        // Inertia
-        if (needToMove) {
-            if (Math.abs(this.cameraDirection.x) < BABYLON.Engine.epsilon)
-                this.cameraDirection.x = 0;
+            // Inertia
+            if (needToMove) {
+                if (Math.abs(this.cameraDirection.x) < 0.001)
+                    this.cameraDirection.x = 0;
 
-            if (Math.abs(this.cameraDirection.y) < BABYLON.Engine.epsilon)
-                this.cameraDirection.y = 0;
+                if (Math.abs(this.cameraDirection.y) < 0.001)
+                    this.cameraDirection.y = 0;
 
-            if (Math.abs(this.cameraDirection.z) < BABYLON.Engine.epsilon)
-                this.cameraDirection.z = 0;
+                if (Math.abs(this.cameraDirection.z) < 0.001)
+                    this.cameraDirection.z = 0;
 
-            this.cameraDirection.scaleInPlace(this.inertia);
-        }
-        if (needToRotate) {
-            if (Math.abs(this.cameraRotation.x) < BABYLON.Engine.epsilon)
-                this.cameraRotation.x = 0;
+                this.cameraDirection.scaleInPlace(this.inertia);
+            }
+            if (needToRotate) {
+                if (Math.abs(this.cameraRotation.x) < 0.001)
+                    this.cameraRotation.x = 0;
 
-            if (Math.abs(this.cameraRotation.y) < BABYLON.Engine.epsilon)
-                this.cameraRotation.y = 0;
+                if (Math.abs(this.cameraRotation.y) < 0.001)
+                    this.cameraRotation.y = 0;
 
-            this.cameraRotation.scaleInPlace(this.inertia);
-        }
-    };
+                this.cameraRotation.scaleInPlace(this.inertia);
+            }
+        };
 
-    BABYLON.FreeCamera.prototype._getViewMatrix = function () {
-        BABYLON.Vector3.FromFloatsToRef(0, 0, 1, this._referencePoint);
+        FreeCamera.prototype._getViewMatrix = function () {
+            BABYLON.Vector3.FromFloatsToRef(0, 0, 1, this._referencePoint);
 
-        if (!this.lockedTarget) {
-            // Compute
-            if (this.upVector.x != 0 || this.upVector.y != 1.0 || this.upVector.z != 0) {
-                BABYLON.Matrix.LookAtLHToRef(BABYLON.Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
-                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+            if (!this.lockedTarget) {
+                // Compute
+                if (this.upVector.x != 0 || this.upVector.y != 1.0 || this.upVector.z != 0) {
+                    BABYLON.Matrix.LookAtLHToRef(BABYLON.Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
+                    BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
 
+                    this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);
+                    this._lookAtTemp.invert();
+                    this._tempMatrix.multiplyToRef(this._lookAtTemp, this._cameraRotationMatrix);
+                } else {
+                    BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+                }
 
-                this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);
-                this._lookAtTemp.invert();
-                this._tempMatrix.multiplyToRef(this._lookAtTemp, this._cameraRotationMatrix);
+                BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+
+                // Computing target and final matrix
+                this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
             } else {
-                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+                this._currentTarget.copyFrom(this._getLockedTargetPosition());
             }
 
-            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-        } else {
-            this._currentTarget.copyFrom(this._getLockedTargetPosition());
-        }
-
-        BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
-        return this._viewMatrix;
-    };
-})();
-
+            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
+            return this._viewMatrix;
+        };
+        return FreeCamera;
+    })(BABYLON.Camera);
+    BABYLON.FreeCamera = FreeCamera;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.freeCamera.js.map

+ 412 - 0
Babylon/Cameras/babylon.freeCamera.ts

@@ -0,0 +1,412 @@
+module BABYLON {
+    export class FreeCamera extends Camera {
+        public cameraDirection = new BABYLON.Vector3(0, 0, 0);
+        public cameraRotation = new BABYLON.Vector2(0, 0);
+        public rotation = new BABYLON.Vector3(0, 0, 0);
+        public ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
+        public keysUp = [38];
+        public keysDown = [40];
+        public keysLeft = [37];
+        public keysRight = [39];
+        public speed = 2.0;
+        public checkCollisions = false;
+        public applyGravity = false;
+        public noRotationConstraint = false;
+        public angularSensibility = 2000.0;
+        public lockedTarget = null;
+        public onCollide = null;
+
+        private _keys = [];
+        private _collider = new Collider();
+        private _needMoveForGravity = true;
+        private _currentTarget = BABYLON.Vector3.Zero();
+        private _viewMatrix = BABYLON.Matrix.Zero();
+        private _camMatrix = BABYLON.Matrix.Zero();
+        private _cameraTransformMatrix = BABYLON.Matrix.Zero();
+        private _cameraRotationMatrix = BABYLON.Matrix.Zero();
+        private _referencePoint = BABYLON.Vector3.Zero();
+        private _transformedReferencePoint = BABYLON.Vector3.Zero();
+        private _oldPosition = BABYLON.Vector3.Zero();
+        private _diffPosition = BABYLON.Vector3.Zero();
+        private _newPosition = BABYLON.Vector3.Zero();
+        private _lookAtTemp = BABYLON.Matrix.Zero();
+        private _tempMatrix = BABYLON.Matrix.Zero();
+        private _attachedElement: HTMLElement;
+        private _localDirection: Vector3;
+        private _transformedDirection: Vector3;
+
+        private _onMouseDown; //ANY
+        private _onMouseUp; //ANY
+        private _onMouseOut; //ANY
+        private _onMouseMove; //ANY
+        private _onKeyDown; //ANY
+        private _onKeyUp; //ANY
+        private _onLostFocus; //ANY
+        private _reset; //ANY
+
+        //ANY
+        constructor(name: string, position: Vector3, scene) {
+            super(name, position, scene);
+        }
+
+        public _getLockedTargetPosition(): Vector3 {
+            if (!this.lockedTarget) {
+                return null;
+            }
+
+            return this.lockedTarget.position || this.lockedTarget;
+        }
+
+        // Cache
+        public _initCache() {
+            super._initCache();
+            this._cache.lockedTarget = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.rotation = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+        }
+
+        public _updateCache(ignoreParentClass?: boolean): void {
+            if (!ignoreParentClass) {
+                super._updateCache();
+            }
+
+            var lockedTargetPosition = this._getLockedTargetPosition();
+            if (!lockedTargetPosition) {
+                this._cache.lockedTarget = null;
+            }
+            else {
+                if (!this._cache.lockedTarget) {
+                    this._cache.lockedTarget = lockedTargetPosition.clone();
+                }
+                else {
+                    this._cache.lockedTarget.copyFrom(lockedTargetPosition);
+                }
+            }
+
+            this._cache.rotation.copyFrom(this.rotation);
+        }
+
+        // Synchronized
+        public _isSynchronizedViewMatrix(): boolean {
+            if (!super._isSynchronizedViewMatrix()) {
+                return false;
+            }
+
+            var lockedTargetPosition = this._getLockedTargetPosition();
+
+            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition)
+                && this._cache.rotation.equals(this.rotation);
+        }
+
+        // Methods
+        private _computeLocalCameraSpeed(): number {
+            return this.speed * ((BABYLON.Tools.GetDeltaTime() / (BABYLON.Tools.GetFps() * 10.0)));
+        }
+
+        // Target
+        public setTarget(target: Vector3): void {
+            this.upVector.normalize();
+
+            BABYLON.Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
+            this._camMatrix.invert();
+
+            this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
+
+            var vDir = target.subtract(this.position);
+
+            if (vDir.x >= 0.0) {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
+            } else {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
+            }
+
+            this.rotation.z = -Math.acos(BABYLON.Vector3.Dot(new BABYLON.Vector3(0, 1.0, 0), this.upVector));
+
+            if (isNaN(this.rotation.x)) {
+                this.rotation.x = 0;
+            }
+
+            if (isNaN(this.rotation.y)) {
+                this.rotation.y = 0;
+            }
+
+            if (isNaN(this.rotation.z)) {
+                this.rotation.z = 0;
+            }
+        }
+
+        public getTarget(): Vector3 {
+            return this._currentTarget;
+        }
+
+        // Controls
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            var previousPosition;
+            var engine = this.getEngine();
+
+            if (this._attachedElement) {
+                return;
+            }
+            this._attachedElement = element;
+
+            if (this._onMouseDown === undefined) {
+                this._onMouseDown = evt => {
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onMouseUp = evt => {
+                    previousPosition = null;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onMouseOut = evt => {
+                    previousPosition = null;
+                    this._keys = [];
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onMouseMove = evt => {
+                    if (!previousPosition && !engine.isPointerLock) {
+                        return;
+                    }
+
+                    var offsetX;
+                    var offsetY;
+
+                    if (!engine.isPointerLock) {
+                        offsetX = evt.clientX - previousPosition.x;
+                        offsetY = evt.clientY - previousPosition.y;
+                    } else {
+                        offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                        offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+                    }
+
+                    this.cameraRotation.y += offsetX / this.angularSensibility;
+                    this.cameraRotation.x += offsetY / this.angularSensibility;
+
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onKeyDown = evt => {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index === -1) {
+                            this._keys.push(evt.keyCode);
+                        }
+                        if (!noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                };
+
+                this._onKeyUp = evt => {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index >= 0) {
+                            this._keys.splice(index, 1);
+                        }
+                        if (!noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                };
+
+                this._onLostFocus = () => {
+                    this._keys = [];
+                };
+
+                this._reset = () => {
+                    this._keys = [];
+                    previousPosition = null;
+                    this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
+                    this.cameraRotation = new BABYLON.Vector2(0, 0);
+                };
+            }
+
+            element.addEventListener("mousedown", this._onMouseDown, false);
+            element.addEventListener("mouseup", this._onMouseUp, false);
+            element.addEventListener("mouseout", this._onMouseOut, false);
+            element.addEventListener("mousemove", this._onMouseMove, false);
+            window.addEventListener("keydown", this._onKeyDown, false);
+            window.addEventListener("keyup", this._onKeyUp, false);
+            window.addEventListener("blur", this._onLostFocus, false);
+        }
+
+        public detachControl(element: HTMLElement): void {
+            if (this._attachedElement != element) {
+                return;
+            }
+
+            element.removeEventListener("mousedown", this._onMouseDown);
+            element.removeEventListener("mouseup", this._onMouseUp);
+            element.removeEventListener("mouseout", this._onMouseOut);
+            element.removeEventListener("mousemove", this._onMouseMove);
+            window.removeEventListener("keydown", this._onKeyDown);
+            window.removeEventListener("keyup", this._onKeyUp);
+            window.removeEventListener("blur", this._onLostFocus);
+
+            this._attachedElement = null;
+            if (this._reset) {
+                this._reset();
+            }
+        }
+
+        public _collideWithWorld(velocity: Vector3): void {
+            this.position.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
+            this._collider.radius = this.ellipsoid;
+
+            this.getScene()._getNewPosition(this._oldPosition, velocity, this._collider, 3, this._newPosition);
+            this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
+
+            if (this._diffPosition.length() > 0.001) {//ANY Engine.collisionEpsilon
+                this.position.addInPlace(this._diffPosition);
+                if (this.onCollide) {
+                    this.onCollide(this._collider.collidedMesh);
+                }
+            }
+        }
+
+        public _checkInputs(): void {
+            if (!this._localDirection) {
+                this._localDirection = BABYLON.Vector3.Zero();
+                this._transformedDirection = BABYLON.Vector3.Zero();
+            }
+
+            // Keyboard
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+                var speed = this._computeLocalCameraSpeed();
+
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(-speed, 0, 0);
+                } else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(0, 0, speed);
+                } else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(speed, 0, 0);
+                } else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    this._localDirection.copyFromFloats(0, 0, -speed);
+                }
+
+                this.getViewMatrix().invertToRef(this._cameraTransformMatrix);
+                BABYLON.Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
+                this.cameraDirection.addInPlace(this._transformedDirection);
+            }
+        }
+
+        public _update(): void {
+            this._checkInputs();
+
+            var needToMove = this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
+            var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
+
+            // Move
+            if (needToMove) {
+                if (this.checkCollisions && this.getScene().collisionsEnabled) {
+                    this._collideWithWorld(this.cameraDirection);
+
+
+                    if (this.applyGravity) {
+                        var oldPosition = this.position;
+                        this._collideWithWorld(this.getScene().gravity);
+                        this._needMoveForGravity = (BABYLON.Vector3.DistanceSquared(oldPosition, this.position) != 0);
+                    }
+                } else {
+                    this.position.addInPlace(this.cameraDirection);
+                }
+            }
+
+            // Rotate
+            if (needToRotate) {
+                this.rotation.x += this.cameraRotation.x;
+                this.rotation.y += this.cameraRotation.y;
+
+
+                if (!this.noRotationConstraint) {
+                    var limit = (Math.PI / 2) * 0.95;
+
+
+                    if (this.rotation.x > limit)
+                        this.rotation.x = limit;
+                    if (this.rotation.x < -limit)
+                        this.rotation.x = -limit;
+                }
+            }
+
+            // Inertia
+            if (needToMove) {
+                if (Math.abs(this.cameraDirection.x) < 0.001) //ANY: BABYLON.Engine.epsilon
+                    this.cameraDirection.x = 0;
+
+                if (Math.abs(this.cameraDirection.y) < 0.001)
+                    this.cameraDirection.y = 0;
+
+                if (Math.abs(this.cameraDirection.z) < 0.001)
+                    this.cameraDirection.z = 0;
+
+                this.cameraDirection.scaleInPlace(this.inertia);
+            }
+            if (needToRotate) {
+                if (Math.abs(this.cameraRotation.x) < 0.001)
+                    this.cameraRotation.x = 0;
+
+                if (Math.abs(this.cameraRotation.y) < 0.001)
+                    this.cameraRotation.y = 0;
+
+                this.cameraRotation.scaleInPlace(this.inertia);
+            }
+        }
+
+        public _getViewMatrix(): Matrix {
+            BABYLON.Vector3.FromFloatsToRef(0, 0, 1, this._referencePoint);
+
+            if (!this.lockedTarget) {
+                // Compute
+                if (this.upVector.x != 0 || this.upVector.y != 1.0 || this.upVector.z != 0) {
+                    BABYLON.Matrix.LookAtLHToRef(BABYLON.Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
+                    BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+
+
+                    this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);
+                    this._lookAtTemp.invert();
+                    this._tempMatrix.multiplyToRef(this._lookAtTemp, this._cameraRotationMatrix);
+                } else {
+                    BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+                }
+
+                BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+
+                // Computing target and final matrix
+                this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
+            } else {
+                this._currentTarget.copyFrom(this._getLockedTargetPosition());
+            }
+
+            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
+            return this._viewMatrix;
+        }
+    }
+} 

+ 1 - 1
Babylon/Cameras/babylon.oculusOrientedCamera.js

@@ -52,7 +52,7 @@ var BABYLON = BABYLON || {};
             new BABYLON.FxaaPostProcess("fxaa_left", 1.0, leftCamera);
         }
 
-        var rightCamera = new BABYLON.OculusOrientedCamera(name + "_right", position, scene, false, ovrSettings, neutralOrientation);
+        var rightCamera = new BABYLON.OculusOrientedCamera(name + "_right", position.clone(), scene, false, ovrSettings, neutralOrientation);
         rightCamera.minZ = minZ;
         rightCamera.maxZ = maxZ;
         if (useFXAA) {

+ 236 - 239
Babylon/Collisions/babylon.collider.js

@@ -1,65 +1,5 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.Collider = function () {
-        this.radius = new BABYLON.Vector3(1, 1, 1);
-        this.retry = 0;
-
-        this.basePointWorld = BABYLON.Vector3.Zero();
-        this.velocityWorld = BABYLON.Vector3.Zero();
-        this.normalizedVelocity = BABYLON.Vector3.Zero();
-        
-        // Internals
-        this._collisionPoint = BABYLON.Vector3.Zero();
-        this._planeIntersectionPoint = BABYLON.Vector3.Zero();
-        this._tempVector = BABYLON.Vector3.Zero();
-        this._tempVector2 = BABYLON.Vector3.Zero();
-        this._tempVector3 = BABYLON.Vector3.Zero();
-        this._tempVector4 = BABYLON.Vector3.Zero();
-        this._edge = BABYLON.Vector3.Zero();
-        this._baseToVertex = BABYLON.Vector3.Zero();
-        this._destinationPoint = BABYLON.Vector3.Zero();
-        this._slidePlaneNormal = BABYLON.Vector3.Zero();
-        this._displacementVector = BABYLON.Vector3.Zero();
-    };
-
-    // Methods
-    BABYLON.Collider.prototype._initialize = function (source, dir, e) {
-        this.velocity = dir;
-        BABYLON.Vector3.NormalizeToRef(dir, this.normalizedVelocity);
-        this.basePoint = source;
-
-        source.multiplyToRef(this.radius, this.basePointWorld);
-        dir.multiplyToRef(this.radius, this.velocityWorld);
-
-        this.velocityWorldLength = this.velocityWorld.length();
-
-        this.epsilon = e;
-        this.collisionFound = false;
-    };
-
-    BABYLON.Collider.prototype._checkPointInTriangle = function (point, pa, pb, pc, n) {
-        pa.subtractToRef(point, this._tempVector);
-        pb.subtractToRef(point, this._tempVector2);
-
-        BABYLON.Vector3.CrossToRef(this._tempVector, this._tempVector2, this._tempVector4);
-        var d = BABYLON.Vector3.Dot(this._tempVector4, n);
-        if (d < 0)
-            return false;
-
-        pc.subtractToRef(point, this._tempVector3);
-        BABYLON.Vector3.CrossToRef(this._tempVector2, this._tempVector3, this._tempVector4);
-        d = BABYLON.Vector3.Dot(this._tempVector4, n);
-        if (d < 0)
-            return false;
-
-        BABYLON.Vector3.CrossToRef(this._tempVector3, this._tempVector, this._tempVector4);
-        d = BABYLON.Vector3.Dot(this._tempVector4, n);
-        return d >= 0;
-    };
-
+var BABYLON;
+(function (BABYLON) {
     var intersectBoxAASphere = function (boxMin, boxMax, sphereCenter, sphereRadius) {
         if (boxMin.x > sphereCenter.x + sphereRadius)
             return false;
@@ -114,231 +54,288 @@ var BABYLON = BABYLON || {};
         return result;
     };
 
-    BABYLON.Collider.prototype._canDoCollision = function (sphereCenter, sphereRadius, vecMin, vecMax) {
-        var distance = BABYLON.Vector3.Distance(this.basePointWorld, sphereCenter);
-
-        var max = Math.max(this.radius.x, this.radius.y);
-        max = Math.max(max, this.radius.z);
-
-        if (distance > this.velocityWorldLength + max + sphereRadius) {
-            return false;
+    var Collider = (function () {
+        function Collider() {
+            this.radius = new BABYLON.Vector3(1, 1, 1);
+            this.retry = 0;
+            this.basePointWorld = BABYLON.Vector3.Zero();
+            this.velocityWorld = BABYLON.Vector3.Zero();
+            this.normalizedVelocity = BABYLON.Vector3.Zero();
+            this._collisionPoint = BABYLON.Vector3.Zero();
+            this._planeIntersectionPoint = BABYLON.Vector3.Zero();
+            this._tempVector = BABYLON.Vector3.Zero();
+            this._tempVector2 = BABYLON.Vector3.Zero();
+            this._tempVector3 = BABYLON.Vector3.Zero();
+            this._tempVector4 = BABYLON.Vector3.Zero();
+            this._edge = BABYLON.Vector3.Zero();
+            this._baseToVertex = BABYLON.Vector3.Zero();
+            this._destinationPoint = BABYLON.Vector3.Zero();
+            this._slidePlaneNormal = BABYLON.Vector3.Zero();
+            this._displacementVector = BABYLON.Vector3.Zero();
         }
+        // Methods
+        Collider.prototype._initialize = function (source, dir, e) {
+            this.velocity = dir;
+            BABYLON.Vector3.NormalizeToRef(dir, this.normalizedVelocity);
+            this.basePoint = source;
 
-        if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
-            return false;
+            source.multiplyToRef(this.radius, this.basePointWorld);
+            dir.multiplyToRef(this.radius, this.velocityWorld);
 
-        return true;
-    };
+            this.velocityWorldLength = this.velocityWorld.length();
 
-    BABYLON.Collider.prototype._testTriangle = function (faceIndex, subMesh, p1, p2, p3) {
-        var t0;
-        var embeddedInPlane = false;
+            this.epsilon = e;
+            this.collisionFound = false;
+        };
 
-        if (!subMesh._trianglePlanes) {
-            subMesh._trianglePlanes = [];
-        }
-        
-        if (!subMesh._trianglePlanes[faceIndex]) {
-            subMesh._trianglePlanes[faceIndex] = new BABYLON.Plane(0, 0, 0, 0);
-            subMesh._trianglePlanes[faceIndex].copyFromPoints(p1, p2, p3);
-        }
+        Collider.prototype._checkPointInTriangle = function (point, pa, pb, pc, n) {
+            pa.subtractToRef(point, this._tempVector);
+            pb.subtractToRef(point, this._tempVector2);
 
-        var trianglePlane = subMesh._trianglePlanes[faceIndex];
+            BABYLON.Vector3.CrossToRef(this._tempVector, this._tempVector2, this._tempVector4);
+            var d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            if (d < 0)
+                return false;
 
-        if ((!subMesh.getMaterial()) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
-            return;
+            pc.subtractToRef(point, this._tempVector3);
+            BABYLON.Vector3.CrossToRef(this._tempVector2, this._tempVector3, this._tempVector4);
+            d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            if (d < 0)
+                return false;
 
-        var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
-        var normalDotVelocity = BABYLON.Vector3.Dot(trianglePlane.normal, this.velocity);
+            BABYLON.Vector3.CrossToRef(this._tempVector3, this._tempVector, this._tempVector4);
+            d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            return d >= 0;
+        };
 
-        if (normalDotVelocity == 0) {
-            if (Math.abs(signedDistToTrianglePlane) >= 1.0)
-                return;
-            embeddedInPlane = true;
-            t0 = 0;
-        }
-        else {
-            t0 = (-1.0 - signedDistToTrianglePlane) / normalDotVelocity;
-            var t1 = (1.0 - signedDistToTrianglePlane) / normalDotVelocity;
-
-            if (t0 > t1) {
-                var temp = t1;
-                t1 = t0;
-                t0 = temp;
-            }
+        Collider.prototype._canDoCollision = function (sphereCenter, sphereRadius, vecMin, vecMax) {
+            var distance = BABYLON.Vector3.Distance(this.basePointWorld, sphereCenter);
 
-            if (t0 > 1.0 || t1 < 0.0)
-                return;
+            var max = Math.max(this.radius.x, this.radius.y);
+            max = Math.max(max, this.radius.z);
 
-            if (t0 < 0)
-                t0 = 0;
-            if (t0 > 1.0)
-                t0 = 1.0;
-        }
+            if (distance > this.velocityWorldLength + max + sphereRadius) {
+                return false;
+            }
 
-        this._collisionPoint.copyFromFloats(0, 0, 0);
+            if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
+                return false;
 
-        var found = false;
-        var t = 1.0;
+            return true;
+        };
 
-        if (!embeddedInPlane) {
-            this.basePoint.subtractToRef(trianglePlane.normal, this._planeIntersectionPoint);
-            this.velocity.scaleToRef(t0, this._tempVector);
-            this._planeIntersectionPoint.addInPlace(this._tempVector);
+        //ANY
+        Collider.prototype._testTriangle = function (faceIndex, subMesh, p1, p2, p3) {
+            var t0;
+            var embeddedInPlane = false;
 
-            if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
-                found = true;
-                t = t0;
-                this._collisionPoint.copyFrom(this._planeIntersectionPoint);
+            if (!subMesh._trianglePlanes) {
+                subMesh._trianglePlanes = [];
             }
-        }
 
-        if (!found) {
-            var velocitySquaredLength = this.velocity.lengthSquared();
-
-            var a = velocitySquaredLength;
+            if (!subMesh._trianglePlanes[faceIndex]) {
+                subMesh._trianglePlanes[faceIndex] = new BABYLON.Plane(0, 0, 0, 0);
+                subMesh._trianglePlanes[faceIndex].copyFromPoints(p1, p2, p3);
+            }
 
-            this.basePoint.subtractToRef(p1, this._tempVector);
-            var b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
-            var c = this._tempVector.lengthSquared - 1.0;
+            var trianglePlane = subMesh._trianglePlanes[faceIndex];
 
-            var lowestRoot = getLowestRoot(a, b, c, t);
-            if (lowestRoot.found) {
-                t = lowestRoot.root;
-                found = true;
-                this._collisionPoint.copyFrom(p1);
-            }
+            if ((!subMesh.getMaterial()) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
+                return;
 
-            this.basePoint.subtractToRef(p2, this._tempVector);
-            b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
-            c = this._tempVector.lengthSquared - 1.0;
+            var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
+            var normalDotVelocity = BABYLON.Vector3.Dot(trianglePlane.normal, this.velocity);
 
-            lowestRoot = getLowestRoot(a, b, c, t);
-            if (lowestRoot.found) {
-                t = lowestRoot.root;
-                found = true;
-                this._collisionPoint.copyFrom(p2);
-            }
+            if (normalDotVelocity == 0) {
+                if (Math.abs(signedDistToTrianglePlane) >= 1.0)
+                    return;
+                embeddedInPlane = true;
+                t0 = 0;
+            } else {
+                t0 = (-1.0 - signedDistToTrianglePlane) / normalDotVelocity;
+                var t1 = (1.0 - signedDistToTrianglePlane) / normalDotVelocity;
+
+                if (t0 > t1) {
+                    var temp = t1;
+                    t1 = t0;
+                    t0 = temp;
+                }
 
-            this.basePoint.subtractToRef(p3, this._tempVector);
-            b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
-            c = this._tempVector.lengthSquared - 1.0;
+                if (t0 > 1.0 || t1 < 0.0)
+                    return;
 
-            lowestRoot = getLowestRoot(a, b, c, t);
-            if (lowestRoot.found) {
-                t = lowestRoot.root;
-                found = true;
-                this._collisionPoint.copyFrom(p3);
+                if (t0 < 0)
+                    t0 = 0;
+                if (t0 > 1.0)
+                    t0 = 1.0;
             }
 
-            p2.subtractToRef(p1, this._edge);
-            p1.subtractToRef(this.basePoint, this._baseToVertex);
-            var edgeSquaredLength = this._edge.lengthSquared();
-            var edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
-            var edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+            this._collisionPoint.copyFromFloats(0, 0, 0);
 
-            a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-            b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
-            c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+            var found = false;
+            var t = 1.0;
 
-            lowestRoot = getLowestRoot(a, b, c, t);
-            if (lowestRoot.found) {
-                var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+            if (!embeddedInPlane) {
+                this.basePoint.subtractToRef(trianglePlane.normal, this._planeIntersectionPoint);
+                this.velocity.scaleToRef(t0, this._tempVector);
+                this._planeIntersectionPoint.addInPlace(this._tempVector);
 
-                if (f >= 0.0 && f <= 1.0) {
-                    t = lowestRoot.root;
+                if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
                     found = true;
-                    this._edge.scaleInPlace(f);
-                    p1.addToRef(this._edge, this._collisionPoint);
+                    t = t0;
+                    this._collisionPoint.copyFrom(this._planeIntersectionPoint);
                 }
             }
 
-            p3.subtractToRef(p2, this._edge);
-            p2.subtractToRef(this.basePoint, this._baseToVertex);
-            edgeSquaredLength = this._edge.lengthSquared();
-            edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
-            edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+            if (!found) {
+                var velocitySquaredLength = this.velocity.lengthSquared();
 
-            a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-            b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
-            c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
-            lowestRoot = getLowestRoot(a, b, c, t);
-            if (lowestRoot.found) {
-                var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+                var a = velocitySquaredLength;
 
-                if (f >= 0.0 && f <= 1.0) {
+                this.basePoint.subtractToRef(p1, this._tempVector);
+                var b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                var c = this._tempVector.lengthSquared() - 1.0;
+
+                var lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
                     t = lowestRoot.root;
                     found = true;
-                    this._edge.scaleInPlace(f);
-                    p2.addToRef(this._edge, this._collisionPoint);
+                    this._collisionPoint.copyFrom(p1);
                 }
-            }
-
-            p1.subtractToRef(p3, this._edge);
-            p3.subtractToRef(this.basePoint, this._baseToVertex);
-            edgeSquaredLength = this._edge.lengthSquared();
-            edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
-            edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
-
-            a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-            b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
-            c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
 
-            lowestRoot = getLowestRoot(a, b, c, t);
-            if (lowestRoot.found) {
-                var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+                this.basePoint.subtractToRef(p2, this._tempVector);
+                b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                c = this._tempVector.lengthSquared() - 1.0;
 
-                if (f >= 0.0 && f <= 1.0) {
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
                     t = lowestRoot.root;
                     found = true;
-                    this._edge.scaleInPlace(f);
-                    p3.addToRef(this._edge, this._collisionPoint);
+                    this._collisionPoint.copyFrom(p2);
                 }
-            }
-        }
 
-        if (found) {
-            var distToCollision = t * this.velocity.length();
+                this.basePoint.subtractToRef(p3, this._tempVector);
+                b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                c = this._tempVector.lengthSquared() - 1.0;
 
-            if (!this.collisionFound || distToCollision < this.nearestDistance) {
-                if (!this.intersectionPoint) {
-                    this.intersectionPoint = this._collisionPoint.clone();
-                } else {
-                    this.intersectionPoint.copyFrom(this._collisionPoint);
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    t = lowestRoot.root;
+                    found = true;
+                    this._collisionPoint.copyFrom(p3);
                 }
-                this.nearestDistance = distToCollision;                
-                this.collisionFound = true;
-                this.collidedMesh = subMesh.getMesh();
-            }
-        }
-    };
 
-    BABYLON.Collider.prototype._collide = function (subMesh, pts, indices, indexStart, indexEnd, decal) {
-        for (var i = indexStart; i < indexEnd; i += 3) {
-            var p1 = pts[indices[i] - decal];
-            var p2 = pts[indices[i + 1] - decal];
-            var p3 = pts[indices[i + 2] - decal];
-
-            this._testTriangle(i, subMesh, p3, p2, p1);
-        }
-    };
-    
-    BABYLON.Collider.prototype._getResponse = function(pos, vel) {
-        pos.addToRef(vel, this._destinationPoint);
-        vel.scaleInPlace((this.nearestDistance / vel.length()));
+                p2.subtractToRef(p1, this._edge);
+                p1.subtractToRef(this.basePoint, this._baseToVertex);
+                var edgeSquaredLength = this._edge.lengthSquared();
+                var edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
+                var edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p1.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
 
-        this.basePoint.addToRef(vel, pos);
-        pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
-        this._slidePlaneNormal.normalize();
-        this._slidePlaneNormal.scaleToRef(this.epsilon, this._displacementVector);
+                p3.subtractToRef(p2, this._edge);
+                p2.subtractToRef(this.basePoint, this._baseToVertex);
+                edgeSquaredLength = this._edge.lengthSquared();
+                edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p2.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
 
-        pos.addInPlace(this._displacementVector);
-        this.intersectionPoint.addInPlace(this._displacementVector);
+                p1.subtractToRef(p3, this._edge);
+                p3.subtractToRef(this.basePoint, this._baseToVertex);
+                edgeSquaredLength = this._edge.lengthSquared();
+                edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p3.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
+            }
 
-        this._slidePlaneNormal.scaleInPlace(BABYLON.Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
-        this._destinationPoint.subtractInPlace(this._slidePlaneNormal);
+            if (found) {
+                var distToCollision = t * this.velocity.length();
+
+                if (!this.collisionFound || distToCollision < this.nearestDistance) {
+                    if (!this.intersectionPoint) {
+                        this.intersectionPoint = this._collisionPoint.clone();
+                    } else {
+                        this.intersectionPoint.copyFrom(this._collisionPoint);
+                    }
+                    this.nearestDistance = distToCollision;
+                    this.collisionFound = true;
+                    this.collidedMesh = subMesh.getMesh();
+                }
+            }
+        };
 
-        this._destinationPoint.subtractToRef(this.intersectionPoint, vel);
-    };
+        Collider.prototype._collide = function (subMesh, pts, indices, indexStart, indexEnd, decal) {
+            for (var i = indexStart; i < indexEnd; i += 3) {
+                var p1 = pts[indices[i] - decal];
+                var p2 = pts[indices[i + 1] - decal];
+                var p3 = pts[indices[i + 2] - decal];
 
-})();
+                this._testTriangle(i, subMesh, p3, p2, p1);
+            }
+        };
+
+        Collider.prototype._getResponse = function (pos, vel) {
+            pos.addToRef(vel, this._destinationPoint);
+            vel.scaleInPlace((this.nearestDistance / vel.length()));
+
+            this.basePoint.addToRef(vel, pos);
+            pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
+            this._slidePlaneNormal.normalize();
+            this._slidePlaneNormal.scaleToRef(this.epsilon, this._displacementVector);
+
+            pos.addInPlace(this._displacementVector);
+            this.intersectionPoint.addInPlace(this._displacementVector);
+
+            this._slidePlaneNormal.scaleInPlace(BABYLON.Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
+            this._destinationPoint.subtractInPlace(this._slidePlaneNormal);
+
+            this._destinationPoint.subtractToRef(this.intersectionPoint, vel);
+        };
+        return Collider;
+    })();
+    BABYLON.Collider = Collider;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.collider.js.map

+ 346 - 0
Babylon/Collisions/babylon.collider.ts

@@ -0,0 +1,346 @@
+module BABYLON {
+    var intersectBoxAASphere = (boxMin: Vector3, boxMax: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean => {
+        if (boxMin.x > sphereCenter.x + sphereRadius)
+            return false;
+
+        if (sphereCenter.x - sphereRadius > boxMax.x)
+            return false;
+
+        if (boxMin.y > sphereCenter.y + sphereRadius)
+            return false;
+
+        if (sphereCenter.y - sphereRadius > boxMax.y)
+            return false;
+
+        if (boxMin.z > sphereCenter.z + sphereRadius)
+            return false;
+
+        if (sphereCenter.z - sphereRadius > boxMax.z)
+            return false;
+
+        return true;
+    };
+
+    var getLowestRoot = (a: number, b: number, c: number, maxR: number) => {
+        var determinant = b * b - 4.0 * a * c;
+        var result = { root: 0, found: false };
+
+        if (determinant < 0)
+            return result;
+
+        var sqrtD = Math.sqrt(determinant);
+        var r1 = (-b - sqrtD) / (2.0 * a);
+        var r2 = (-b + sqrtD) / (2.0 * a);
+
+        if (r1 > r2) {
+            var temp = r2;
+            r2 = r1;
+            r1 = temp;
+        }
+
+        if (r1 > 0 && r1 < maxR) {
+            result.root = r1;
+            result.found = true;
+            return result;
+        }
+
+        if (r2 > 0 && r2 < maxR) {
+            result.root = r2;
+            result.found = true;
+            return result;
+        }
+
+        return result;
+    };
+
+    export class Collider {
+        public radius = new BABYLON.Vector3(1, 1, 1);
+        public retry = 0;
+        public velocity: Vector3;
+        public basePoint: Vector3;
+        public epsilon: number;
+        public collisionFound: boolean;
+        public velocityWorldLength: number;
+        public basePointWorld = BABYLON.Vector3.Zero();
+        public velocityWorld = BABYLON.Vector3.Zero();
+        public normalizedVelocity = BABYLON.Vector3.Zero();
+        public nearestDistance: number;
+        public intersectionPoint: Vector3;
+        public collidedMesh; //ANY
+
+        private _collisionPoint = BABYLON.Vector3.Zero();
+        private _planeIntersectionPoint = BABYLON.Vector3.Zero();
+        private _tempVector = BABYLON.Vector3.Zero();
+        private _tempVector2 = BABYLON.Vector3.Zero();
+        private _tempVector3 = BABYLON.Vector3.Zero();
+        private _tempVector4 = BABYLON.Vector3.Zero();
+        private _edge = BABYLON.Vector3.Zero();
+        private _baseToVertex = BABYLON.Vector3.Zero();
+        private _destinationPoint = BABYLON.Vector3.Zero();
+        private _slidePlaneNormal = BABYLON.Vector3.Zero();
+        private _displacementVector = BABYLON.Vector3.Zero();
+
+        // Methods
+        public _initialize(source: Vector3, dir: Vector3, e: number): void {
+            this.velocity = dir;
+            BABYLON.Vector3.NormalizeToRef(dir, this.normalizedVelocity);
+            this.basePoint = source;
+
+            source.multiplyToRef(this.radius, this.basePointWorld);
+            dir.multiplyToRef(this.radius, this.velocityWorld);
+
+            this.velocityWorldLength = this.velocityWorld.length();
+
+            this.epsilon = e;
+            this.collisionFound = false;
+        }
+
+        public _checkPointInTriangle(point: Vector3, pa: Vector3, pb: Vector3, pc: Vector3, n: Vector3): boolean {
+            pa.subtractToRef(point, this._tempVector);
+            pb.subtractToRef(point, this._tempVector2);
+
+            BABYLON.Vector3.CrossToRef(this._tempVector, this._tempVector2, this._tempVector4);
+            var d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            if (d < 0)
+                return false;
+
+            pc.subtractToRef(point, this._tempVector3);
+            BABYLON.Vector3.CrossToRef(this._tempVector2, this._tempVector3, this._tempVector4);
+            d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            if (d < 0)
+                return false;
+
+            BABYLON.Vector3.CrossToRef(this._tempVector3, this._tempVector, this._tempVector4);
+            d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            return d >= 0;
+        }
+
+        public _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean {
+            var distance = BABYLON.Vector3.Distance(this.basePointWorld, sphereCenter);
+
+            var max = Math.max(this.radius.x, this.radius.y);
+            max = Math.max(max, this.radius.z);
+
+            if (distance > this.velocityWorldLength + max + sphereRadius) {
+                return false;
+            }
+
+            if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
+                return false;
+
+            return true;
+        }
+
+        //ANY
+        public _testTriangle(faceIndex: number, subMesh, p1: Vector3, p2: Vector3, p3: Vector3): void {
+            var t0;
+            var embeddedInPlane = false;
+
+            if (!subMesh._trianglePlanes) {
+                subMesh._trianglePlanes = [];
+            }
+
+            if (!subMesh._trianglePlanes[faceIndex]) {
+                subMesh._trianglePlanes[faceIndex] = new BABYLON.Plane(0, 0, 0, 0);
+                subMesh._trianglePlanes[faceIndex].copyFromPoints(p1, p2, p3);
+            }
+
+            var trianglePlane = subMesh._trianglePlanes[faceIndex];
+
+            if ((!subMesh.getMaterial()) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
+                return;
+
+            var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
+            var normalDotVelocity = BABYLON.Vector3.Dot(trianglePlane.normal, this.velocity);
+
+            if (normalDotVelocity == 0) {
+                if (Math.abs(signedDistToTrianglePlane) >= 1.0)
+                    return;
+                embeddedInPlane = true;
+                t0 = 0;
+            }
+            else {
+                t0 = (-1.0 - signedDistToTrianglePlane) / normalDotVelocity;
+                var t1 = (1.0 - signedDistToTrianglePlane) / normalDotVelocity;
+
+                if (t0 > t1) {
+                    var temp = t1;
+                    t1 = t0;
+                    t0 = temp;
+                }
+
+                if (t0 > 1.0 || t1 < 0.0)
+                    return;
+
+                if (t0 < 0)
+                    t0 = 0;
+                if (t0 > 1.0)
+                    t0 = 1.0;
+            }
+
+            this._collisionPoint.copyFromFloats(0, 0, 0);
+
+            var found = false;
+            var t = 1.0;
+
+            if (!embeddedInPlane) {
+                this.basePoint.subtractToRef(trianglePlane.normal, this._planeIntersectionPoint);
+                this.velocity.scaleToRef(t0, this._tempVector);
+                this._planeIntersectionPoint.addInPlace(this._tempVector);
+
+                if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
+                    found = true;
+                    t = t0;
+                    this._collisionPoint.copyFrom(this._planeIntersectionPoint);
+                }
+            }
+
+            if (!found) {
+                var velocitySquaredLength = this.velocity.lengthSquared();
+
+                var a = velocitySquaredLength;
+
+                this.basePoint.subtractToRef(p1, this._tempVector);
+                var b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                var c = this._tempVector.lengthSquared() - 1.0;
+
+                var lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    t = lowestRoot.root;
+                    found = true;
+                    this._collisionPoint.copyFrom(p1);
+                }
+
+                this.basePoint.subtractToRef(p2, this._tempVector);
+                b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                c = this._tempVector.lengthSquared() - 1.0;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    t = lowestRoot.root;
+                    found = true;
+                    this._collisionPoint.copyFrom(p2);
+                }
+
+                this.basePoint.subtractToRef(p3, this._tempVector);
+                b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                c = this._tempVector.lengthSquared() - 1.0;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    t = lowestRoot.root;
+                    found = true;
+                    this._collisionPoint.copyFrom(p3);
+                }
+
+                p2.subtractToRef(p1, this._edge);
+                p1.subtractToRef(this.basePoint, this._baseToVertex);
+                var edgeSquaredLength = this._edge.lengthSquared();
+                var edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
+                var edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p1.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
+
+                p3.subtractToRef(p2, this._edge);
+                p2.subtractToRef(this.basePoint, this._baseToVertex);
+                edgeSquaredLength = this._edge.lengthSquared();
+                edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p2.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
+
+                p1.subtractToRef(p3, this._edge);
+                p3.subtractToRef(this.basePoint, this._baseToVertex);
+                edgeSquaredLength = this._edge.lengthSquared();
+                edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p3.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
+            }
+
+            if (found) {
+                var distToCollision = t * this.velocity.length();
+
+                if (!this.collisionFound || distToCollision < this.nearestDistance) {
+                    if (!this.intersectionPoint) {
+                        this.intersectionPoint = this._collisionPoint.clone();
+                    } else {
+                        this.intersectionPoint.copyFrom(this._collisionPoint);
+                    }
+                    this.nearestDistance = distToCollision;
+                    this.collisionFound = true;
+                    this.collidedMesh = subMesh.getMesh();
+                }
+            }
+        }
+
+        public _collide(subMesh, pts: Vector3[], indices: number[], indexStart: number, indexEnd: number, decal: number): void {
+            for (var i = indexStart; i < indexEnd; i += 3) {
+                var p1 = pts[indices[i] - decal];
+                var p2 = pts[indices[i + 1] - decal];
+                var p3 = pts[indices[i + 2] - decal];
+
+                this._testTriangle(i, subMesh, p3, p2, p1);
+            }
+        }
+
+        public _getResponse(pos: Vector3, vel: Vector3): void {
+            pos.addToRef(vel, this._destinationPoint);
+            vel.scaleInPlace((this.nearestDistance / vel.length()));
+
+            this.basePoint.addToRef(vel, pos);
+            pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
+            this._slidePlaneNormal.normalize();
+            this._slidePlaneNormal.scaleToRef(this.epsilon, this._displacementVector);
+
+            pos.addInPlace(this._displacementVector);
+            this.intersectionPoint.addInPlace(this._displacementVector);
+
+            this._slidePlaneNormal.scaleInPlace(BABYLON.Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
+            this._destinationPoint.subtractInPlace(this._slidePlaneNormal);
+
+            this._destinationPoint.subtractToRef(this.intersectionPoint, vel);
+        }
+    }
+} 

+ 35 - 36
Babylon/Collisions/babylon.pickingInfo.js

@@ -1,37 +1,36 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.PickingInfo = function () {
-    };
-
-    // Properties
-    BABYLON.PickingInfo.prototype.hit = false;
-    BABYLON.PickingInfo.prototype.distance = 0;
-    BABYLON.PickingInfo.prototype.pickedPoint = null;
-    BABYLON.PickingInfo.prototype.pickedMesh = null;
-    BABYLON.PickingInfo.prototype.bu = 0;
-    BABYLON.PickingInfo.prototype.bv = 0;
-    BABYLON.PickingInfo.prototype.faceId = -1;
-
-    // Methods
-    BABYLON.PickingInfo.prototype.getNormal = function() {
-        if (!this.pickedMesh) {
-            return null;
+var BABYLON;
+(function (BABYLON) {
+    var PickingInfo = (function () {
+        function PickingInfo() {
+            this.hit = false;
+            this.distance = 0;
+            this.pickedPoint = null;
+            this.pickedMesh = null;
+            this.bu = 0;
+            this.bv = 0;
+            this.faceId = -1;
         }
-
-        var indices = this.pickedMesh.getIndices();
-        var normals = this.pickedMesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
-
-        var normal0 = BABYLON.Vector3.FromArray(normals , indices[this.faceId * 3] * 3);
-        var normal1 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3 + 1] * 3);
-        var normal2 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3 + 2] * 3);
-
-        normal0 = normal0.scale(this.bu);
-        normal1 = normal1.scale(this.bv);
-        normal2 = normal2.scale(1.0 - this.bu - this.bv);
-
-        return new BABYLON.Vector3(normal0.x + normal1.x + normal2.x, normal0.y + normal1.y + normal2.y, normal0.z + normal1.z + normal2.z);
-    };
-})();
+        // Methods
+        PickingInfo.prototype.getNormal = function () {
+            if (!this.pickedMesh) {
+                return null;
+            }
+
+            var indices = this.pickedMesh.getIndices();
+            var normals = this.pickedMesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+
+            var normal0 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3] * 3);
+            var normal1 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3 + 1] * 3);
+            var normal2 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3 + 2] * 3);
+
+            normal0 = normal0.scale(this.bu);
+            normal1 = normal1.scale(this.bv);
+            normal2 = normal2.scale(1.0 - this.bu - this.bv);
+
+            return new BABYLON.Vector3(normal0.x + normal1.x + normal2.x, normal0.y + normal1.y + normal2.y, normal0.z + normal1.z + normal2.z);
+        };
+        return PickingInfo;
+    })();
+    BABYLON.PickingInfo = PickingInfo;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.pickingInfo.js.map

+ 31 - 0
Babylon/Collisions/babylon.pickingInfo.ts

@@ -0,0 +1,31 @@
+module BABYLON {
+    export class PickingInfo {
+        public hit = false;
+        public distance = 0;
+        public pickedPoint = null;
+        public pickedMesh = null;
+        public bu = 0;
+        public bv = 0;
+        public faceId = -1;
+
+        // Methods
+        public getNormal(): Vector3 {
+            if (!this.pickedMesh) {
+                return null;
+            }
+
+            var indices = this.pickedMesh.getIndices();
+            var normals = this.pickedMesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+
+            var normal0 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3] * 3);
+            var normal1 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3 + 1] * 3);
+            var normal2 = BABYLON.Vector3.FromArray(normals, indices[this.faceId * 3 + 2] * 3);
+
+            normal0 = normal0.scale(this.bu);
+            normal1 = normal1.scale(this.bv);
+            normal2 = normal2.scale(1.0 - this.bu - this.bv);
+
+            return new BABYLON.Vector3(normal0.x + normal1.x + normal2.x, normal0.y + normal1.y + normal2.y, normal0.z + normal1.z + normal2.z);
+        }
+    }
+} 

+ 6 - 2
Babylon/Culling/Octrees/babylon.octreeBlock.js

@@ -2,8 +2,8 @@
 (function (BABYLON) {
     var OctreeBlock = (function () {
         function OctreeBlock(minPoint, maxPoint, capacity) {
-            this.meshes = [];
-            this.subMeshes = [];
+            this.meshes = new Array();
+            this.subMeshes = new Array();
             this._boundingVectors = new Array();
             this._capacity = capacity;
 
@@ -33,6 +33,10 @@
         }
         // Methods
         OctreeBlock.prototype.addMesh = function (mesh) {
+            if (!mesh.subMeshes) {
+                return;
+            }
+
             if (this.blocks) {
                 for (var index = 0; index < this.blocks.length; index++) {
                     var block = this.blocks[index];

+ 9 - 5
Babylon/Culling/Octrees/babylon.octreeBlock.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     export class OctreeBlock {
-        public meshes = [];
-        public subMeshes = [];
+        public meshes = new Array<Mesh>();
+        public subMeshes = new Array <Array<SubMesh>>();
         public blocks: Array<OctreeBlock>;
 
         private _capacity: number;
@@ -38,7 +38,11 @@
         }
 
         // Methods
-        public addMesh(mesh): void {
+        public addMesh(mesh: Mesh): void {
+            if (!mesh.subMeshes) {
+                return;
+            }
+
             if (this.blocks) {
                 for (var index = 0; index < this.blocks.length; index++) {
                     var block = this.blocks[index];
@@ -65,14 +69,14 @@
             }
         }
 
-        public addEntries(meshes): void {
+        public addEntries(meshes: Mesh[]): void {
             for (var index = 0; index < meshes.length; index++) {
                 var mesh = meshes[index];
                 this.addMesh(mesh);
             }
         }
 
-        public select(frustumPlanes: Plane[], selection): void {
+        public select(frustumPlanes: Plane[], selection: OctreeBlock[]): void {
             if (this.blocks) {
                 for (var index = 0; index < this.blocks.length; index++) {
                     var block = this.blocks[index];

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

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

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

@@ -44,6 +44,7 @@
             return this.boundingBox.isInFrustum(frustumPlanes);
         }
 
+        //ANY
         public _checkCollision(collider): boolean {
             return collider._canDoCollision(this.boundingSphere.centerWorld, this.boundingSphere.radiusWorld, this.boundingBox.minimumWorld, this.boundingBox.maximumWorld);
         }

+ 53 - 46
Babylon/Lights/babylon.directionalLight.js

@@ -1,55 +1,62 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.DirectionalLight = function (name, direction, scene) {
-        BABYLON.Light.call(this, name, scene);
-
-        this.position = direction.scale(-1);
-        this.direction = direction;
-        this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
-        this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
-    };
-    
-    BABYLON.DirectionalLight.prototype = Object.create(BABYLON.Light.prototype);
-    
-    // Methods
-    BABYLON.DirectionalLight.prototype._computeTransformedPosition = function () {
-        if (this.parent && this.parent.getWorldMatrix) {
-            if (!this._transformedPosition) {
-                this._transformedPosition = BABYLON.Vector3.Zero();
+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 DirectionalLight = (function (_super) {
+        __extends(DirectionalLight, _super);
+        //ANY
+        function DirectionalLight(name, direction, scene) {
+            _super.call(this, name, scene);
+            this.direction = direction;
+            this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
+            this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
+
+            this.position = direction.scale(-1);
+        }
+        DirectionalLight.prototype._computeTransformedPosition = function () {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedPosition) {
+                    this._transformedPosition = BABYLON.Vector3.Zero();
+                }
+
+                BABYLON.Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this._transformedPosition);
+                return true;
             }
 
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this._transformedPosition);
-            return true;
-        }
+            return false;
+        };
 
-        return false;
-    };
+        //ANY
+        DirectionalLight.prototype.transferToEffect = function (effect, directionUniformName) {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedDirection) {
+                    this._transformedDirection = BABYLON.Vector3.Zero();
+                }
 
-    BABYLON.DirectionalLight.prototype.transferToEffect = function (effect, directionUniformName) {
-        if (this.parent && this.parent.getWorldMatrix) {
-            if (!this._transformedDirection) {
-                this._transformedDirection = BABYLON.Vector3.Zero();
+                BABYLON.Vector3.TransformNormalToRef(this.direction, this.parent.getWorldMatrix(), this._transformedDirection);
+                effect.setFloat4(directionUniformName, this._transformedDirection.x, this._transformedDirection.y, this._transformedDirection.z, 1);
+
+                return;
             }
 
-            BABYLON.Vector3.TransformNormalToRef(this.direction, this.parent.getWorldMatrix(), this._transformedDirection);
-            effect.setFloat4(directionUniformName, this._transformedDirection.x, this._transformedDirection.y, this._transformedDirection.z, 1);
+            effect.setFloat4(directionUniformName, this.direction.x, this.direction.y, this.direction.z, 1);
+        };
 
-            return;
-        }
-
-        effect.setFloat4(directionUniformName, this.direction.x, this.direction.y, this.direction.z, 1);
-    };
-    
-    BABYLON.DirectionalLight.prototype._getWorldMatrix = function () {
-        if (!this._worldMatrix) {
-            this._worldMatrix = BABYLON.Matrix.Identity();
-        }
+        DirectionalLight.prototype._getWorldMatrix = function () {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
 
-        BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+            BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
 
-        return this._worldMatrix;
-    };
-})();
+            return this._worldMatrix;
+        };
+        return DirectionalLight;
+    })(BABYLON.Light);
+    BABYLON.DirectionalLight = DirectionalLight;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.directionalLight.js.map

+ 57 - 0
Babylon/Lights/babylon.directionalLight.ts

@@ -0,0 +1,57 @@
+module BABYLON {
+    export class DirectionalLight extends Light {
+        public position: Vector3;
+        public diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
+        public specular = new BABYLON.Color3(1.0, 1.0, 1.0);
+
+        private _transformedDirection: Vector3;
+        private _transformedPosition: Vector3;
+        private _worldMatrix: Matrix;
+
+        //ANY
+        constructor(name: string, public direction: Vector3, scene) {
+            super(name, scene);
+
+            this.position = direction.scale(-1);
+        }
+
+        public _computeTransformedPosition(): boolean {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedPosition) {
+                    this._transformedPosition = BABYLON.Vector3.Zero();
+                }
+
+                BABYLON.Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this._transformedPosition);
+                return true;
+            }
+
+            return false;
+        }
+
+        //ANY
+        public transferToEffect(effect, directionUniformName: string): void {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedDirection) {
+                    this._transformedDirection = BABYLON.Vector3.Zero();
+                }
+
+                BABYLON.Vector3.TransformNormalToRef(this.direction, this.parent.getWorldMatrix(), this._transformedDirection);
+                effect.setFloat4(directionUniformName, this._transformedDirection.x, this._transformedDirection.y, this._transformedDirection.z, 1);
+
+                return;
+            }
+
+            effect.setFloat4(directionUniformName, this.direction.x, this.direction.y, this.direction.z, 1);
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
+
+            BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+
+            return this._worldMatrix;
+        }
+    }
+}  

+ 39 - 33
Babylon/Lights/babylon.hemisphericLight.js

@@ -1,36 +1,42 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.HemisphericLight = function (name, direction, scene) {
-        BABYLON.Light.call(this, name, scene);
-        
-        this.direction = direction;
-        this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
-        this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
-        this.groundColor = new BABYLON.Color3(0.0, 0.0, 0.0);
-    };
-    
-    BABYLON.HemisphericLight.prototype = Object.create(BABYLON.Light.prototype);
-    
-    // Properties
-    BABYLON.HemisphericLight.prototype.getShadowGenerator = function () {
-        return null;
-    };
-    
-    // Methods
-    BABYLON.HemisphericLight.prototype._getWorldMatrix = function () {
-        if (!this._worldMatrix) {
-            this._worldMatrix = BABYLON.Matrix.Identity();
+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 HemisphericLight = (function (_super) {
+        __extends(HemisphericLight, _super);
+        //ANY
+        function HemisphericLight(name, direction, scene) {
+            _super.call(this, name, scene);
+            this.direction = direction;
+            this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
+            this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
+            this.groundColor = new BABYLON.Color3(0.0, 0.0, 0.0);
         }
+        //ANY
+        HemisphericLight.prototype.getShadowGenerator = function () {
+            return null;
+        };
+
+        //ANY
+        HemisphericLight.prototype.transferToEffect = function (effect, directionUniformName, groundColorUniformName) {
+            var normalizeDirection = BABYLON.Vector3.Normalize(this.direction);
+            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, 0);
+            effect.setColor3(groundColorUniformName, this.groundColor.scale(this.intensity));
+        };
 
-        return this._worldMatrix;
-    };
+        HemisphericLight.prototype._getWorldMatrix = function () {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
 
-    BABYLON.HemisphericLight.prototype.transferToEffect = function (effect, directionUniformName, groundColorUniformName) {
-        var normalizeDirection = BABYLON.Vector3.Normalize(this.direction);
-        effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, 0);
-        effect.setColor3(groundColorUniformName, this.groundColor.scale(this.intensity));
-    };
-})();
+            return this._worldMatrix;
+        };
+        return HemisphericLight;
+    })(BABYLON.Light);
+    BABYLON.HemisphericLight = HemisphericLight;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.hemisphericLight.js.map

+ 34 - 0
Babylon/Lights/babylon.hemisphericLight.ts

@@ -0,0 +1,34 @@
+module BABYLON {
+    export class HemisphericLight extends Light {
+        public diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
+        public specular = new BABYLON.Color3(1.0, 1.0, 1.0);
+        public groundColor = new BABYLON.Color3(0.0, 0.0, 0.0);
+
+        private _worldMatrix: Matrix;
+
+        //ANY
+        constructor(name: string, public direction: Vector3, scene) {
+            super(name, scene);
+        }
+
+        //ANY
+        public getShadowGenerator() {
+            return null;
+        }
+
+        //ANY
+        public transferToEffect(effect, directionUniformName: string, groundColorUniformName: string): void {
+            var normalizeDirection = BABYLON.Vector3.Normalize(this.direction);
+            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, 0);
+            effect.setColor3(groundColorUniformName, this.groundColor.scale(this.intensity));
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
+
+            return this._worldMatrix;
+        }
+    }
+} 

+ 53 - 55
Babylon/Lights/babylon.light.js

@@ -1,68 +1,66 @@
-"use strict";
+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 Light = (function (_super) {
+        __extends(Light, _super);
+        //ANY
+        function Light(name, scene) {
+            _super.call(this, name, scene);
+            this.intensity = 1.0;
 
-var BABYLON = BABYLON || {};
+            scene.lights.push(this);
 
-(function () {
-    BABYLON.Light = function (name, scene) {
-        BABYLON.Node.call(this, scene);
+            // Exclusions
+            this.excludedMeshes = [];
+        }
+        //ANY
+        Light.prototype.getShadowGenerator = function () {
+            return this._shadowGenerator;
+        };
 
-        this.name = name;
-        this.id = name;
+        // ANY
+        Light.prototype.transferToEffect = function (effect, uniformName0, uniformName1) {
+        };
 
-        scene.lights.push(this);
-        
-        // Animations
-        this.animations = [];
-        
-        // Exclusions
-        this.excludedMeshes = [];
-    };
-    
-    BABYLON.Light.prototype = Object.create(BABYLON.Node.prototype);
-    
-    // Members
-    BABYLON.Light.prototype.intensity = 1.0;
-    
-    // Properties
-    BABYLON.Light.prototype.getScene = function () {
-        return this._scene;
-    };
+        Light.prototype._getWorldMatrix = function () {
+            return BABYLON.Matrix.Identity();
+        };
 
-    BABYLON.Light.prototype.getShadowGenerator = function() {
-        return this._shadowGenerator;
-    };
+        Light.prototype.getWorldMatrix = function () {
+            this._currentRenderId = this.getScene().getRenderId();
 
-    // Methods
-    BABYLON.Light.prototype.transferToEffect = function() {
-    };
+            var worldMatrix = this._getWorldMatrix();
 
-    BABYLON.Light.prototype.getWorldMatrix = function () {
-        this._currentRenderId = this._scene.getRenderId();
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._parentedWorldMatrix) {
+                    this._parentedWorldMatrix = BABYLON.Matrix.Identity();
+                }
 
-        var worldMatrix = this._getWorldMatrix();
+                worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._parentedWorldMatrix);
 
-        if (this.parent && this.parent.getWorldMatrix) {
-            if (!this._parentedWorldMatrix) {
-                this._parentedWorldMatrix = BABYLON.Matrix.Identity();
+                return this._parentedWorldMatrix;
             }
 
-            worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._parentedWorldMatrix);
-
-            return this._parentedWorldMatrix;
-        }
-
-        return worldMatrix;
-    };
+            return worldMatrix;
+        };
 
-    BABYLON.Light.prototype.dispose = function () {
-        if (this._shadowGenerator) {
-            this._shadowGenerator.dispose();
-            this._shadowGenerator = null;
-        }
-        
-        // Remove from scene
-        var index = this._scene.lights.indexOf(this);
-        this._scene.lights.splice(index, 1);
-    };
+        Light.prototype.dispose = function () {
+            if (this._shadowGenerator) {
+                this._shadowGenerator.dispose();
+                this._shadowGenerator = null;
+            }
 
-})();
+            // Remove from scene
+            var index = this.getScene().lights.indexOf(this);
+            this.getScene().lights.splice(index, 1);
+        };
+        return Light;
+    })(BABYLON.Node);
+    BABYLON.Light = Light;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.light.js.map

+ 62 - 0
Babylon/Lights/babylon.light.ts

@@ -0,0 +1,62 @@
+module BABYLON {
+    export class Light extends Node {
+        public intensity = 1.0;
+        public animations; //ANY
+        public excludedMeshes; //ANY
+
+        private _shadowGenerator; //ANY
+        private _parentedWorldMatrix: Matrix;
+
+        //ANY
+        constructor(name: string, scene) {
+            super(name, scene);
+
+            scene.lights.push(this);
+
+            // Exclusions
+            this.excludedMeshes = [];
+        }
+
+        //ANY
+        public getShadowGenerator() {
+            return this._shadowGenerator;
+        }
+
+        // ANY
+        public transferToEffect(effect, uniformName0?: string, uniformName1?: string): void {
+        }
+
+        public _getWorldMatrix(): Matrix {
+            return Matrix.Identity();
+        }
+
+        public getWorldMatrix(): Matrix {
+            this._currentRenderId = this.getScene().getRenderId();
+
+            var worldMatrix = this._getWorldMatrix();
+
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._parentedWorldMatrix) {
+                    this._parentedWorldMatrix = BABYLON.Matrix.Identity();
+                }
+
+                worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._parentedWorldMatrix);
+
+                return this._parentedWorldMatrix;
+            }
+
+            return worldMatrix;
+        }
+
+        public dispose(): void {
+            if (this._shadowGenerator) {
+                this._shadowGenerator.dispose();
+                this._shadowGenerator = null;
+            }
+
+            // Remove from scene
+            var index = this.getScene().lights.indexOf(this);
+            this.getScene().lights.splice(index, 1);
+        }
+    }
+} 

+ 44 - 37
Babylon/Lights/babylon.pointLight.js

@@ -1,45 +1,52 @@
-"use strict";
+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 PointLight = (function (_super) {
+        __extends(PointLight, _super);
+        //ANY
+        function PointLight(name, position, scene) {
+            _super.call(this, name, scene);
+            this.position = position;
+            this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
+            this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
+        }
+        //ANY
+        PointLight.prototype.transferToEffect = function (effect, positionUniformName) {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedPosition) {
+                    this._transformedPosition = BABYLON.Vector3.Zero();
+                }
 
-var BABYLON = BABYLON || {};
+                BABYLON.Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this._transformedPosition);
+                effect.setFloat4(positionUniformName, this._transformedPosition.x, this._transformedPosition.y, this._transformedPosition.z, 0);
 
-(function () {
-    BABYLON.PointLight = function (name, position, scene) {
-        BABYLON.Light.call(this, name, scene);
-        
-        this.position = position;
-        this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
-        this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
-    };
-    
-    BABYLON.PointLight.prototype = Object.create(BABYLON.Light.prototype);
-    
-    // Methods
-    BABYLON.PointLight.prototype.transferToEffect = function (effect, positionUniformName) {
-        if (this.parent && this.parent.getWorldMatrix) {
-            if (!this._transformedPosition) {
-                this._transformedPosition = BABYLON.Vector3.Zero();
+                return;
             }
 
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this._transformedPosition);
-            effect.setFloat4(positionUniformName, this._transformedPosition.x, this._transformedPosition.y, this._transformedPosition.z, 0);
-
-            return;
-        }
+            effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, 0);
+        };
 
-        effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, 0);
-    };
+        //ANY
+        PointLight.prototype.getShadowGenerator = function () {
+            return null;
+        };
 
-    BABYLON.PointLight.prototype.getShadowGenerator = function () {
-        return null;
-    };
-    
-    BABYLON.PointLight.prototype._getWorldMatrix = function () {
-        if (!this._worldMatrix) {
-            this._worldMatrix = BABYLON.Matrix.Identity();
-        }
+        PointLight.prototype._getWorldMatrix = function () {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
 
-        BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+            BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
 
-        return this._worldMatrix;
-    };
-})();
+            return this._worldMatrix;
+        };
+        return PointLight;
+    })(BABYLON.Light);
+    BABYLON.PointLight = PointLight;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.pointLight.js.map

+ 45 - 0
Babylon/Lights/babylon.pointLight.ts

@@ -0,0 +1,45 @@
+module BABYLON {
+    export class PointLight extends Light {
+        public diffuse = new Color3(1.0, 1.0, 1.0);
+        public specular = new Color3(1.0, 1.0, 1.0);
+
+        private _worldMatrix: Matrix;
+        private _transformedPosition: Vector3;
+
+        //ANY
+        constructor(name: string, public position: Vector3, scene) {
+            super(name, scene);
+        }
+
+        //ANY
+        public transferToEffect(effect, positionUniformName: string): void {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedPosition) {
+                    this._transformedPosition = BABYLON.Vector3.Zero();
+                }
+
+                BABYLON.Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this._transformedPosition);
+                effect.setFloat4(positionUniformName, this._transformedPosition.x, this._transformedPosition.y, this._transformedPosition.z, 0);
+
+                return;
+            }
+
+            effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, 0);
+        }
+
+        //ANY
+        public getShadowGenerator() {
+            return null;
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
+
+            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+
+            return this._worldMatrix;
+        }
+    }
+} 

+ 56 - 50
Babylon/Lights/babylon.spotLight.js

@@ -1,55 +1,61 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.SpotLight = function (name, position, direction, angle, exponent, scene) {
-        BABYLON.Light.call(this, name, scene);
-        
-        this.position = position;
-        this.direction = direction;
-        this.angle = angle;
-        this.exponent = exponent;
-        this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
-        this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
-    };
-    
-    BABYLON.SpotLight.prototype = Object.create(BABYLON.Light.prototype);
-    
-    // Methods
-    BABYLON.SpotLight.prototype.transferToEffect = function (effect, positionUniformName, directionUniformName) {
-        var normalizeDirection;
-        
-        if (this.parent && this.parent.getWorldMatrix) {
-            if (!this._transformedDirection) {
-                this._transformedDirection = BABYLON.Vector3.Zero();
-            }
-            if (!this._transformedPosition) {
-                this._transformedPosition = BABYLON.Vector3.Zero();
-            }
-            
-            var parentWorldMatrix = this.parent.getWorldMatrix();
-
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, parentWorldMatrix, this._transformedPosition);
-            BABYLON.Vector3.TransformNormalToRef(this.direction, parentWorldMatrix, this._transformedDirection);
-
-            effect.setFloat4(positionUniformName, this._transformedPosition.x, this._transformedPosition.y, this._transformedPosition.z, this.exponent);
-            normalizeDirection = BABYLON.Vector3.Normalize(this._transformedDirection);
-        } else {
-            effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, this.exponent);
-            normalizeDirection = BABYLON.Vector3.Normalize(this.direction);
+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 SpotLight = (function (_super) {
+        __extends(SpotLight, _super);
+        //ANY
+        function SpotLight(name, position, direction, angle, exponent, scene) {
+            _super.call(this, name, scene);
+            this.position = position;
+            this.direction = direction;
+            this.angle = angle;
+            this.exponent = exponent;
+            this.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0);
+            this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
         }
+        //ANY
+        SpotLight.prototype.transferToEffect = function (effect, positionUniformName, directionUniformName) {
+            var normalizeDirection;
+
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedDirection) {
+                    this._transformedDirection = BABYLON.Vector3.Zero();
+                }
+                if (!this._transformedPosition) {
+                    this._transformedPosition = BABYLON.Vector3.Zero();
+                }
+
+                var parentWorldMatrix = this.parent.getWorldMatrix();
+
+                BABYLON.Vector3.TransformCoordinatesToRef(this.position, parentWorldMatrix, this._transformedPosition);
+                BABYLON.Vector3.TransformNormalToRef(this.direction, parentWorldMatrix, this._transformedDirection);
+
+                effect.setFloat4(positionUniformName, this._transformedPosition.x, this._transformedPosition.y, this._transformedPosition.z, this.exponent);
+                normalizeDirection = BABYLON.Vector3.Normalize(this._transformedDirection);
+            } else {
+                effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, this.exponent);
+                normalizeDirection = BABYLON.Vector3.Normalize(this.direction);
+            }
 
-        effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, Math.cos(this.angle * 0.5));
-    };
+            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, Math.cos(this.angle * 0.5));
+        };
 
-    BABYLON.SpotLight.prototype._getWorldMatrix = function () {
-        if (!this._worldMatrix) {
-            this._worldMatrix = BABYLON.Matrix.Identity();
-        }
+        SpotLight.prototype._getWorldMatrix = function () {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
 
-        BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+            BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
 
-        return this._worldMatrix;
-    };
-})();
+            return this._worldMatrix;
+        };
+        return SpotLight;
+    })(BABYLON.Light);
+    BABYLON.SpotLight = SpotLight;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.spotLight.js.map

+ 52 - 0
Babylon/Lights/babylon.spotLight.ts

@@ -0,0 +1,52 @@
+module BABYLON {
+    export class SpotLight extends Light {
+        public diffuse = new Color3(1.0, 1.0, 1.0);
+        public specular = new Color3(1.0, 1.0, 1.0);
+
+        private _transformedDirection: Vector3;
+        private _transformedPosition: Vector3;
+        private _worldMatrix: Matrix;
+
+        //ANY
+        constructor(name: string, public position: Vector3, public direction: Vector3, public angle: number, public exponent: number, scene) {
+            super(name, scene);
+        }
+
+        //ANY
+        public transferToEffect(effect, positionUniformName: string, directionUniformName: string): void {
+            var normalizeDirection;
+
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedDirection) {
+                    this._transformedDirection = BABYLON.Vector3.Zero();
+                }
+                if (!this._transformedPosition) {
+                    this._transformedPosition = BABYLON.Vector3.Zero();
+                }
+
+                var parentWorldMatrix = this.parent.getWorldMatrix();
+
+                BABYLON.Vector3.TransformCoordinatesToRef(this.position, parentWorldMatrix, this._transformedPosition);
+                BABYLON.Vector3.TransformNormalToRef(this.direction, parentWorldMatrix, this._transformedDirection);
+
+                effect.setFloat4(positionUniformName, this._transformedPosition.x, this._transformedPosition.y, this._transformedPosition.z, this.exponent);
+                normalizeDirection = BABYLON.Vector3.Normalize(this._transformedDirection);
+            } else {
+                effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, this.exponent);
+                normalizeDirection = BABYLON.Vector3.Normalize(this.direction);
+            }
+
+            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, Math.cos(this.angle * 0.5));
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = BABYLON.Matrix.Identity();
+            }
+
+            BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+
+            return this._worldMatrix;
+        }
+    }
+}

+ 374 - 477
Babylon/Mesh/babylon.csg.js

@@ -1,443 +1,76 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-// Constructive Solid Geometry for BABYLON
-// Based on https://github.com/evanw/csg.js/
-(function () {
-
+var BABYLON;
+(function (BABYLON) {
     // Unique ID when we import meshes from Babylon to CSG
     var currentCSGMeshId = 0;
 
-    BABYLON.CSG = function () {
-        this.polygons = [];
-    };
-
-    // Convert BABYLON.Mesh to BABYLON.CSG
-    BABYLON.CSG.FromMesh = function (mesh) {
-        var vertex, normal, uv, position,
-            polygon,
-            polygons = [],
-            vertices;
-
-        if (mesh instanceof BABYLON.Mesh) {
-            mesh.computeWorldMatrix(true);
-            this.matrix = mesh.getWorldMatrix();
-            this.position = mesh.position.clone();
-            this.rotation = mesh.rotation.clone();
-            this.scaling = mesh.scaling.clone();
-        } else {
-            throw 'BABYLON.CSG: Wrong Mesh type, must be BABYLON.Mesh';
-        }
-
-        var indices = mesh.getIndices(),
-            positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind),
-            normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind),
-            uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
-
-        var subMeshes = mesh.subMeshes;
-
-        for (var sm = 0, sml = subMeshes.length; sm < sml; sm++) {
-            for (var i = subMeshes[sm].indexStart, il = subMeshes[sm].indexCount + subMeshes[sm].indexStart; i < il; i += 3) {
-                vertices = [];
-                for (var j = 0; j < 3; j++) {
-                    normal = new BABYLON.Vector3(normals[indices[i + j] * 3], normals[indices[i + j] * 3 + 1], normals[indices[i + j] * 3 + 2]);
-                    uv = new BABYLON.Vector2(uvs[indices[i + j] * 2], uvs[indices[i + j] * 2 + 1]);
-                    position = new BABYLON.Vector3(positions[indices[i + j] * 3], positions[indices[i + j] * 3 + 1], positions[indices[i + j] * 3 + 2]);
-                    position = BABYLON.Vector3.TransformCoordinates(position, this.matrix);
-                    normal = BABYLON.Vector3.TransformNormal(normal, this.matrix);
-
-                    vertex = new BABYLON.CSG.Vertex(position, normal, uv);
-                    vertices.push(vertex);
-                }
-
-                polygon = new BABYLON.CSG.Polygon(vertices, { subMeshId: sm, meshId: currentCSGMeshId, materialIndex: subMeshes[sm].materialIndex });
-
-                // To handle the case of degenerated triangle
-                // polygon.plane == null <=> the polygon does not represent 1 single plane <=> the triangle is degenerated
-                if (polygon.plane)
-                    polygons.push(polygon);
-            }
-        }
-
-        var csg = BABYLON.CSG.fromPolygons(polygons);
-        csg.copyTransformAttributes(this);
-        currentCSGMeshId++;
-
-        return csg;
-    };
-
-
-    // Construct a BABYLON.CSG solid from a list of `BABYLON.CSG.Polygon` instances.
-    BABYLON.CSG.fromPolygons = function (polygons) {
-        var csg = new BABYLON.CSG();
-        csg.polygons = polygons;
-        return csg;
-    };
-
-    BABYLON.CSG.prototype = {
-        clone: function () {
-            var csg = new BABYLON.CSG();
-            csg.polygons = this.polygons.map(function (p) { return p.clone(); });
-            csg.copyTransformAttributes(this);
-            return csg;
-        },
-
-        toPolygons: function () {
-            return this.polygons;
-        },
-
-        union: function (csg) {
-            var a = new BABYLON.CSG.Node(this.clone().polygons);
-            var b = new BABYLON.CSG.Node(csg.clone().polygons);
-            a.clipTo(b);
-            b.clipTo(a);
-            b.invert();
-            b.clipTo(a);
-            b.invert();
-            a.build(b.allPolygons());
-            return BABYLON.CSG.fromPolygons(a.allPolygons()).copyTransformAttributes(this);
-        },
-
-        subtract: function (csg) {
-            var a = new BABYLON.CSG.Node(this.clone().polygons);
-            var b = new BABYLON.CSG.Node(csg.clone().polygons);
-            a.invert();
-            a.clipTo(b);
-            b.clipTo(a);
-            b.invert();
-            b.clipTo(a);
-            b.invert();
-            a.build(b.allPolygons());
-            a.invert();
-            return BABYLON.CSG.fromPolygons(a.allPolygons()).copyTransformAttributes(this);
-        },
-
-        intersect: function (csg) {
-            var a = new BABYLON.CSG.Node(this.clone().polygons);
-            var b = new BABYLON.CSG.Node(csg.clone().polygons);
-            a.invert();
-            b.clipTo(a);
-            b.invert();
-            a.clipTo(b);
-            b.clipTo(a);
-            a.build(b.allPolygons());
-            a.invert();
-            return BABYLON.CSG.fromPolygons(a.allPolygons()).copyTransformAttributes(this);
-        },
-
-        // Return a new BABYLON.CSG solid with solid and empty space switched. This solid is
-        // not modified.
-        inverse: function () {
-            var csg = this.clone();
-            csg.polygons.map(function (p) { p.flip(); });
-            return csg;
-        }
-    };
-
-    // This is used to keep meshes transformations so they can be restored
-    // when we build back a Babylon Mesh
-    // NB : All CSG operations are performed in world coordinates
-    BABYLON.CSG.prototype.copyTransformAttributes = function(object) {
-        this.matrix = object.matrix;
-        this.position = object.position;
-        this.rotation = object.rotation;
-        this.scaling = object.scaling;
-
-        return this;
-    };
-
-    // Build Raw mesh from CSG
-    // Coordinates here are in world space
-    BABYLON.CSG.prototype.buildMeshGeometry = function (name, scene, keepSubMeshes) {
-        var matrix = this.matrix.clone();
-        matrix.invert();
-
-        var mesh = new BABYLON.Mesh(name, scene),
-            vertices = [],
-            indices = [],
-            normals = [],
-            uvs = [],
-            vertex, normal, uv,
-            polygons = this.polygons,
-            polygonIndices = [0, 0, 0],
-            polygon,
-            vertice_dict = {},
-            vertex_idx,
-            currentIndex = 0,
-            subMesh_dict = {},
-            subMesh_obj;
-
-        if (keepSubMeshes) {
-            // Sort Polygons, since subMeshes are indices range
-            polygons.sort(function (a, b) {
-                if (a.shared.meshId === b.shared.meshId) {
-                    return a.shared.subMeshId - b.shared.subMeshId;
-                } else {
-                    return a.shared.meshId - b.shared.meshId;
-                }
-            });
-        }
-
-        for (var i = 0, il = polygons.length; i < il; i++) {
-            polygon = polygons[i];
-
-            // Building SubMeshes
-            if (!subMesh_dict[polygon.shared.meshId]) {
-                subMesh_dict[polygon.shared.meshId] = {};
-            }
-            if (!subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId]) {
-                subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId] = {
-                    indexStart: +Infinity,
-                    indexEnd: -Infinity,
-                    materialIndex: polygon.shared.materialIndex
-                };
-            }
-            subMesh_obj = subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId];
-
-
-            for (var j = 2, jl = polygon.vertices.length; j < jl; j++) {
-
-                polygonIndices[0] = 0;
-                polygonIndices[1] = j - 1;
-                polygonIndices[2] = j;
-
-                for (var k = 0; k < 3; k++) {
-                    vertex = polygon.vertices[polygonIndices[k]].pos;
-                    normal = polygon.vertices[polygonIndices[k]].normal;
-                    uv = polygon.vertices[polygonIndices[k]].uv;
-                    vertex = new BABYLON.Vector3(vertex.x, vertex.y, vertex.z);
-                    normal = new BABYLON.Vector3(normal.x, normal.y, normal.z);
-                    vertex = BABYLON.Vector3.TransformCoordinates(vertex, matrix);
-                    normal = BABYLON.Vector3.TransformNormal(normal, matrix);
-
-                    vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
-
-                    // Check if 2 points can be merged
-                    if (!(typeof vertex_idx !== 'undefined' &&
-                         normals[vertex_idx * 3] === normal.x &&
-                         normals[vertex_idx * 3 + 1] === normal.y &&
-                         normals[vertex_idx * 3 + 2] === normal.z &&
-                         uvs[vertex_idx * 2] === uv.x &&
-                         uvs[vertex_idx * 2 + 1] === uv.y)) {
-                        vertices.push(vertex.x, vertex.y, vertex.z);
-                        uvs.push(uv.x, uv.y);
-                        normals.push(normal.x, normal.y, normal.z);
-                        vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = (vertices.length / 3) - 1;
-                    }
-
-                    indices.push(vertex_idx);
-
-                    subMesh_obj.indexStart = Math.min(currentIndex, subMesh_obj.indexStart);
-                    subMesh_obj.indexEnd = Math.max(currentIndex, subMesh_obj.indexEnd);
-                    currentIndex++;
-                }
-
-            }
-
-        }
-
-        mesh.setVerticesData(vertices, BABYLON.VertexBuffer.PositionKind);
-        mesh.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
-        mesh.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
-        mesh.setIndices(indices);
-
-        if (keepSubMeshes) {
-            // We offset the materialIndex by the previous number of materials in the CSG mixed meshes
-            var materialIndexOffset = 0,
-                materialMaxIndex;
-
-            mesh.subMeshes.length = 0;
-
-            for (var m in subMesh_dict) {
-                materialMaxIndex = -1;
-                for (var sm in subMesh_dict[m]) {
-                    subMesh_obj = subMesh_dict[m][sm];
-                    BABYLON.SubMesh.CreateFromIndices(subMesh_obj.materialIndex + materialIndexOffset, subMesh_obj.indexStart, subMesh_obj.indexEnd - subMesh_obj.indexStart + 1, mesh);
-                    materialMaxIndex = Math.max(subMesh_obj.materialIndex, materialMaxIndex);
-                }
-                materialIndexOffset += ++materialMaxIndex;
-            }
-        }
-
-        return mesh;
-    };
-
-    // Build Mesh from CSG taking material and transforms into account
-    BABYLON.CSG.prototype.toMesh = function (name, material, scene, keepSubMeshes) {
-        var mesh = this.buildMeshGeometry(name, scene, keepSubMeshes);
-
-        mesh.material = material;
-
-        mesh.position.copyFrom(this.position);
-        mesh.rotation.copyFrom(this.rotation);
-        mesh.scaling.copyFrom(this.scaling);
-        mesh.computeWorldMatrix(true);
-
-        return mesh;
-    };
-
-    // # class Vector
-
-    // Represents a 3D vector.
-    // 
-    // Example usage:
-    // 
-    //         new BABYLON.CSG.Vector(1, 2, 3);
-    //         new BABYLON.CSG.Vector([1, 2, 3]);
-    //         new BABYLON.CSG.Vector({ x: 1, y: 2, z: 3 });
-
-    BABYLON.CSG.Vector = function (x, y, z) {
-        if (arguments.length == 3) {
-            this.x = x;
-            this.y = y;
-            this.z = z;
-        } else if ('x' in x) {
-            this.x = x.x;
-            this.y = x.y;
-            this.z = x.z;
-        } else {
-            this.x = x[0];
-            this.y = x[1];
-            this.z = x[2];
-        }
-    };
-
-    BABYLON.CSG.Vector.prototype = {
-        clone: function () {
-            return new BABYLON.CSG.Vector(this.x, this.y, this.z);
-        },
-
-        negated: function () {
-            return new BABYLON.CSG.Vector(-this.x, -this.y, -this.z);
-        },
-
-        plus: function (a) {
-            return new BABYLON.CSG.Vector(this.x + a.x, this.y + a.y, this.z + a.z);
-        },
-
-        minus: function (a) {
-            return new BABYLON.CSG.Vector(this.x - a.x, this.y - a.y, this.z - a.z);
-        },
-
-        times: function (a) {
-            return new BABYLON.CSG.Vector(this.x * a, this.y * a, this.z * a);
-        },
-
-        dividedBy: function (a) {
-            return new BABYLON.CSG.Vector(this.x / a, this.y / a, this.z / a);
-        },
-
-        dot: function (a) {
-            return this.x * a.x + this.y * a.y + this.z * a.z;
-        },
-
-        lerp: function (a, t) {
-            return this.plus(a.minus(this).times(t));
-        },
-
-        length: function () {
-            return Math.sqrt(this.dot(this));
-        },
-
-        lengthSq: function () {
-            return this.dot(this);
-        },
-
-        unit: function () {
-            return this.dividedBy(this.length());
-        },
-
-        cross: function (a) {
-            return new BABYLON.CSG.Vector(
-                this.y * a.z - this.z * a.y,
-                this.z * a.x - this.x * a.z,
-                this.x * a.y - this.y * a.x
-            );
-        }
-    };
-
     // # class Vertex
-
     // Represents a vertex of a polygon. Use your own vertex class instead of this
     // one to provide additional features like texture coordinates and vertex
     // colors. Custom vertex classes need to provide a `pos` property and `clone()`,
     // `flip()`, and `interpolate()` methods that behave analogous to the ones
     // defined by `BABYLON.CSG.Vertex`. This class provides `normal` so convenience
     // functions like `BABYLON.CSG.sphere()` can return a smooth vertex normal, but `normal`
-    // is not used anywhere else. 
+    // is not used anywhere else.
     // Same goes for uv, it allows to keep the original vertex uv coordinates of the 2 meshes
-
-    BABYLON.CSG.Vertex = function (pos, normal, uv) {
-        this.pos = new BABYLON.CSG.Vector(pos);
-        this.normal = new BABYLON.CSG.Vector(normal);
-        this.uv = new BABYLON.CSG.Vector(uv.x, uv.y, 0);
-    };
-
-    BABYLON.CSG.Vertex.prototype = {
-        clone: function () {
-            return new BABYLON.CSG.Vertex(this.pos.clone(), this.normal.clone(), this.uv.clone());
-        },
+    var Vertex = (function () {
+        function Vertex(pos, normal, uv) {
+            this.pos = pos;
+            this.normal = normal;
+            this.uv = uv;
+        }
+        Vertex.prototype.clone = function () {
+            return new Vertex(this.pos.clone(), this.normal.clone(), this.uv.clone());
+        };
 
         // Invert all orientation-specific data (e.g. vertex normal). Called when the
         // orientation of a polygon is flipped.
-        flip: function () {
-            this.normal = this.normal.negated();
-        },
+        Vertex.prototype.flip = function () {
+            this.normal = this.normal.scale(-1);
+        };
 
         // Create a new vertex between this vertex and `other` by linearly
         // interpolating all properties using a parameter of `t`. Subclasses should
         // override this to interpolate additional properties.
-        interpolate: function (other, t) {
-            return new BABYLON.CSG.Vertex(
-                this.pos.lerp(other.pos, t),
-                this.normal.lerp(other.normal, t),
-                this.uv.lerp(other.uv, t)
-            );
-        }
-    };
+        Vertex.prototype.interpolate = function (other, t) {
+            return new Vertex(BABYLON.Vector3.Lerp(this.pos, other.pos, t), BABYLON.Vector3.Lerp(this.normal, other.normal, t), BABYLON.Vector2.Lerp(this.uv, other.uv, t));
+        };
+        return Vertex;
+    })();
 
     // # class Plane
-
     // Represents a plane in 3D space.
-
-    BABYLON.CSG.Plane = function (normal, w) {
-        this.normal = normal;
-        this.w = w;
-    };
-
-    // `BABYLON.CSG.Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a
-    // point is on the plane.
-    BABYLON.CSG.Plane.EPSILON = 1e-5;
-
-    BABYLON.CSG.Plane.fromPoints = function (a, b, c) {
-        var v0 = c.minus(a);
-        var v1 = b.minus(a);
-
-        if (v0.lengthSq() === 0 || v1.lengthSq() === 0) {
-            return null;
+    var Plane = (function () {
+        function Plane(normal, w) {
+            this.normal = normal;
+            this.w = w;
         }
+        Plane.FromPoints = function (a, b, c) {
+            var v0 = c.subtract(a);
+            var v1 = b.subtract(a);
+
+            if (v0.lengthSquared() === 0 || v1.lengthSquared() === 0) {
+                return null;
+            }
 
-        var n = c.minus(a).cross(b.minus(a)).unit();
-        return new BABYLON.CSG.Plane(n, n.dot(a));
-    };
+            var n = BABYLON.Vector3.Normalize(BABYLON.Vector3.Cross(c.subtract(a), b.subtract(a)));
+            return new Plane(n, BABYLON.Vector3.Dot(n, a));
+        };
 
-    BABYLON.CSG.Plane.prototype = {
-        clone: function () {
-            return new BABYLON.CSG.Plane(this.normal.clone(), this.w);
-        },
+        Plane.prototype.clone = function () {
+            return new Plane(this.normal.clone(), this.w);
+        };
 
-        flip: function () {
-            this.normal = this.normal.negated();
+        Plane.prototype.flip = function () {
+            this.normal = this.normal.scale(-1);
             this.w = -this.w;
-        },
+        };
 
         // Split `polygon` by this plane if needed, then put the polygon or polygon
         // fragments in the appropriate lists. Coplanar polygons go into either
         // `coplanarFront` or `coplanarBack` depending on their orientation with
         // respect to this plane. Polygons in front or in back of this plane go into
         // either `front` or `back`.
-        splitPolygon: function (polygon, coplanarFront, coplanarBack, front, back) {
+        Plane.prototype.splitPolygon = function (polygon, coplanarFront, coplanarBack, front, back) {
             var COPLANAR = 0;
             var FRONT = 1;
             var BACK = 2;
@@ -448,16 +81,15 @@ var BABYLON = BABYLON || {};
             var polygonType = 0;
             var types = [];
             for (var i = 0; i < polygon.vertices.length; i++) {
-                var t = this.normal.dot(polygon.vertices[i].pos) - this.w;
-                var type = (t < -BABYLON.CSG.Plane.EPSILON) ? BACK : (t > BABYLON.CSG.Plane.EPSILON) ? FRONT : COPLANAR;
+                var t = BABYLON.Vector3.Dot(this.normal, polygon.vertices[i].pos) - this.w;
+                var type = (t < -Plane.EPSILON) ? BACK : (t > Plane.EPSILON) ? FRONT : COPLANAR;
                 polygonType |= type;
                 types.push(type);
             }
 
-            // Put the polygon in the correct list, splitting it when necessary.
             switch (polygonType) {
                 case COPLANAR:
-                    (this.normal.dot(polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon);
+                    (BABYLON.Vector3.Dot(this.normal, polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon);
                     break;
                 case FRONT:
                     front.push(polygon);
@@ -467,84 +99,90 @@ var BABYLON = BABYLON || {};
                     break;
                 case SPANNING:
                     var f = [], b = [];
-                    for (var i = 0; i < polygon.vertices.length; i++) {
+                    for (i = 0; i < polygon.vertices.length; i++) {
                         var j = (i + 1) % polygon.vertices.length;
                         var ti = types[i], tj = types[j];
                         var vi = polygon.vertices[i], vj = polygon.vertices[j];
-                        if (ti != BACK) f.push(vi);
-                        if (ti != FRONT) b.push(ti != BACK ? vi.clone() : vi);
+                        if (ti != BACK)
+                            f.push(vi);
+                        if (ti != FRONT)
+                            b.push(ti != BACK ? vi.clone() : vi);
                         if ((ti | tj) == SPANNING) {
-                            var t = (this.w - this.normal.dot(vi.pos)) / this.normal.dot(vj.pos.minus(vi.pos));
+                            t = (this.w - BABYLON.Vector3.Dot(this.normal, vi.pos)) / BABYLON.Vector3.Dot(this.normal, vj.pos.subtract(vi.pos));
                             var v = vi.interpolate(vj, t);
                             f.push(v);
                             b.push(v.clone());
                         }
                     }
-                    if (f.length >= 3) front.push(new BABYLON.CSG.Polygon(f, polygon.shared));
-                    if (b.length >= 3) back.push(new BABYLON.CSG.Polygon(b, polygon.shared));
+                    if (f.length >= 3)
+                        front.push(new Polygon(f, polygon.shared));
+                    if (b.length >= 3)
+                        back.push(new Polygon(b, polygon.shared));
                     break;
             }
-        }
-    };
+        };
+        Plane.EPSILON = 1e-5;
+        return Plane;
+    })();
 
     // # class Polygon
-
     // Represents a convex polygon. The vertices used to initialize a polygon must
-    // be coplanar and form a convex loop. They do not have to be `BABYLON.CSG.Vertex`
-    // instances but they must behave similarly (duck typing can be used for
-    // customization).
-    // 
+    // be coplanar and form a convex loop.
+    //
     // Each convex polygon has a `shared` property, which is shared between all
     // polygons that are clones of each other or were split from the same polygon.
     // This can be used to define per-polygon properties (such as surface color).
+    var Polygon = (function () {
+        function Polygon(vertices, shared) {
+            this.vertices = vertices;
+            this.shared = shared;
+            this.plane = Plane.FromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
+        }
+        Polygon.prototype.clone = function () {
+            var vertices = this.vertices.map(function (v) {
+                return v.clone();
+            });
+            return new Polygon(vertices, this.shared);
+        };
 
-    BABYLON.CSG.Polygon = function (vertices, shared) {
-        this.vertices = vertices;
-        this.shared = shared;
-        this.plane = BABYLON.CSG.Plane.fromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
-
-    };
-
-    BABYLON.CSG.Polygon.prototype = {
-        clone: function () {
-            var vertices = this.vertices.map(function (v) { return v.clone(); });
-            return new BABYLON.CSG.Polygon(vertices, this.shared);
-        },
-
-        flip: function () {
-            this.vertices.reverse().map(function (v) { v.flip(); });
+        Polygon.prototype.flip = function () {
+            this.vertices.reverse().map(function (v) {
+                v.flip();
+            });
             this.plane.flip();
-        }
-    };
+        };
+        return Polygon;
+    })();
 
     // # class Node
-
     // Holds a node in a BSP tree. A BSP tree is built from a collection of polygons
     // by picking a polygon to split along. That polygon (and all other coplanar
     // polygons) are added directly to that node and the other polygons are added to
     // the front and/or back subtrees. This is not a leafy BSP tree since there is
     // no distinction between internal and leaf nodes.
-
-    BABYLON.CSG.Node = function (polygons) {
-        this.plane = null;
-        this.front = null;
-        this.back = null;
-        this.polygons = [];
-        if (polygons) this.build(polygons);
-    };
-
-    BABYLON.CSG.Node.prototype = {
-        clone: function () {
-            var node = new BABYLON.CSG.Node();
+    var Node = (function () {
+        function Node(polygons) {
+            this.plane = null;
+            this.front = null;
+            this.back = null;
+            this.polygons = [];
+            if (polygons) {
+                this.build(polygons);
+            }
+        }
+        Node.prototype.clone = function () {
+            var node = new Node();
             node.plane = this.plane && this.plane.clone();
             node.front = this.front && this.front.clone();
             node.back = this.back && this.back.clone();
-            node.polygons = this.polygons.map(function (p) { return p.clone(); });
+            node.polygons = this.polygons.map(function (p) {
+                return p.clone();
+            });
             return node;
-        },
+        };
 
         // Convert solid space to empty space and empty space to solid space.
-        invert: function () {
+        Node.prototype.invert = function () {
             for (var i = 0; i < this.polygons.length; i++) {
                 this.polygons[i].flip();
             }
@@ -558,12 +196,13 @@ var BABYLON = BABYLON || {};
             var temp = this.front;
             this.front = this.back;
             this.back = temp;
-        },
+        };
 
         // Recursively remove all polygons in `polygons` that are inside this BSP
         // tree.
-        clipPolygons: function (polygons) {
-            if (!this.plane) return polygons.slice();
+        Node.prototype.clipPolygons = function (polygons) {
+            if (!this.plane)
+                return polygons.slice();
             var front = [], back = [];
             for (var i = 0; i < polygons.length; i++) {
                 this.plane.splitPolygon(polygons[i], front, back, front, back);
@@ -577,43 +216,301 @@ var BABYLON = BABYLON || {};
                 back = [];
             }
             return front.concat(back);
-        },
+        };
 
         // Remove all polygons in this BSP tree that are inside the other BSP tree
         // `bsp`.
-        clipTo: function (bsp) {
+        Node.prototype.clipTo = function (bsp) {
             this.polygons = bsp.clipPolygons(this.polygons);
-            if (this.front) this.front.clipTo(bsp);
-            if (this.back) this.back.clipTo(bsp);
-        },
+            if (this.front)
+                this.front.clipTo(bsp);
+            if (this.back)
+                this.back.clipTo(bsp);
+        };
 
         // Return a list of all polygons in this BSP tree.
-        allPolygons: function () {
+        Node.prototype.allPolygons = function () {
             var polygons = this.polygons.slice();
-            if (this.front) polygons = polygons.concat(this.front.allPolygons());
-            if (this.back) polygons = polygons.concat(this.back.allPolygons());
+            if (this.front)
+                polygons = polygons.concat(this.front.allPolygons());
+            if (this.back)
+                polygons = polygons.concat(this.back.allPolygons());
             return polygons;
-        },
+        };
 
         // Build a BSP tree out of `polygons`. When called on an existing tree, the
         // new polygons are filtered down to the bottom of the tree and become new
         // nodes there. Each set of polygons is partitioned using the first polygon
         // (no heuristic is used to pick a good split).
-        build: function (polygons) {
-            if (!polygons.length) return;
-            if (!this.plane) this.plane = polygons[0].plane.clone();
+        Node.prototype.build = function (polygons) {
+            if (!polygons.length)
+                return;
+            if (!this.plane)
+                this.plane = polygons[0].plane.clone();
             var front = [], back = [];
             for (var i = 0; i < polygons.length; i++) {
                 this.plane.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);
             }
             if (front.length) {
-                if (!this.front) this.front = new BABYLON.CSG.Node();
+                if (!this.front)
+                    this.front = new Node();
                 this.front.build(front);
             }
             if (back.length) {
-                if (!this.back) this.back = new BABYLON.CSG.Node();
+                if (!this.back)
+                    this.back = new Node();
                 this.back.build(back);
             }
+        };
+        return Node;
+    })();
+
+    var CSG = (function () {
+        function CSG() {
+            this.polygons = new Array();
         }
-    };
-})();
+        // Convert BABYLON.Mesh to BABYLON.CSG
+        CSG.FromMesh = function (mesh) {
+            var vertex, normal, uv, position, polygon, polygons = [], vertices;
+
+            if (mesh instanceof BABYLON.Mesh) {
+                mesh.computeWorldMatrix(true);
+                var matrix = mesh.getWorldMatrix();
+                var meshPosition = mesh.position.clone();
+                var meshRotation = mesh.rotation.clone();
+                var meshScaling = mesh.scaling.clone();
+            } else {
+                throw 'BABYLON.CSG: Wrong Mesh type, must be BABYLON.Mesh';
+            }
+
+            var indices = mesh.getIndices(), positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind), normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind), uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+
+            var subMeshes = mesh.subMeshes;
+
+            for (var sm = 0, sml = subMeshes.length; sm < sml; sm++) {
+                for (var i = subMeshes[sm].indexStart, il = subMeshes[sm].indexCount + subMeshes[sm].indexStart; i < il; i += 3) {
+                    vertices = [];
+                    for (var j = 0; j < 3; j++) {
+                        normal = new BABYLON.Vector3(normals[indices[i + j] * 3], normals[indices[i + j] * 3 + 1], normals[indices[i + j] * 3 + 2]);
+                        uv = new BABYLON.Vector2(uvs[indices[i + j] * 2], uvs[indices[i + j] * 2 + 1]);
+                        position = new BABYLON.Vector3(positions[indices[i + j] * 3], positions[indices[i + j] * 3 + 1], positions[indices[i + j] * 3 + 2]);
+                        position = BABYLON.Vector3.TransformCoordinates(position, matrix);
+                        normal = BABYLON.Vector3.TransformNormal(normal, matrix);
+
+                        vertex = new Vertex(position, normal, uv);
+                        vertices.push(vertex);
+                    }
+
+                    polygon = new Polygon(vertices, { subMeshId: sm, meshId: currentCSGMeshId, materialIndex: subMeshes[sm].materialIndex });
+
+                    // To handle the case of degenerated triangle
+                    // polygon.plane == null <=> the polygon does not represent 1 single plane <=> the triangle is degenerated
+                    if (polygon.plane)
+                        polygons.push(polygon);
+                }
+            }
+
+            var csg = CSG.FromPolygons(polygons);
+            csg.matrix = matrix;
+            csg.position = meshPosition;
+            csg.rotation = meshRotation;
+            csg.scaling = meshScaling;
+            currentCSGMeshId++;
+
+            return csg;
+        };
+
+        // Construct a BABYLON.CSG solid from a list of `BABYLON.CSG.Polygon` instances.
+        CSG.FromPolygons = function (polygons) {
+            var csg = new BABYLON.CSG();
+            csg.polygons = polygons;
+            return csg;
+        };
+
+        CSG.prototype.clone = function () {
+            var csg = new BABYLON.CSG();
+            csg.polygons = this.polygons.map(function (p) {
+                return p.clone();
+            });
+            csg.copyTransformAttributes(this);
+            return csg;
+        };
+
+        CSG.prototype.toPolygons = function () {
+            return this.polygons;
+        };
+
+        CSG.prototype.union = function (csg) {
+            var a = new Node(this.clone().polygons);
+            var b = new Node(csg.clone().polygons);
+            a.clipTo(b);
+            b.clipTo(a);
+            b.invert();
+            b.clipTo(a);
+            b.invert();
+            a.build(b.allPolygons());
+            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
+        };
+
+        CSG.prototype.subtract = function (csg) {
+            var a = new Node(this.clone().polygons);
+            var b = new Node(csg.clone().polygons);
+            a.invert();
+            a.clipTo(b);
+            b.clipTo(a);
+            b.invert();
+            b.clipTo(a);
+            b.invert();
+            a.build(b.allPolygons());
+            a.invert();
+            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
+        };
+
+        CSG.prototype.intersect = function (csg) {
+            var a = new Node(this.clone().polygons);
+            var b = new Node(csg.clone().polygons);
+            a.invert();
+            b.clipTo(a);
+            b.invert();
+            a.clipTo(b);
+            b.clipTo(a);
+            a.build(b.allPolygons());
+            a.invert();
+            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
+        };
+
+        // Return a new BABYLON.CSG solid with solid and empty space switched. This solid is
+        // not modified.
+        CSG.prototype.inverse = function () {
+            var csg = this.clone();
+            csg.polygons.map(function (p) {
+                p.flip();
+            });
+            return csg;
+        };
+
+        // This is used to keep meshes transformations so they can be restored
+        // when we build back a Babylon Mesh
+        // NB : All CSG operations are performed in world coordinates
+        CSG.prototype.copyTransformAttributes = function (csg) {
+            this.matrix = csg.matrix;
+            this.position = csg.position;
+            this.rotation = csg.rotation;
+            this.scaling = csg.scaling;
+
+            return this;
+        };
+
+        // Build Raw mesh from CSG
+        // Coordinates here are in world space
+        //ANY
+        CSG.prototype.buildMeshGeometry = function (name, scene, keepSubMeshes) {
+            var matrix = this.matrix.clone();
+            matrix.invert();
+
+            var mesh = new BABYLON.Mesh(name, scene), vertices = [], indices = [], normals = [], uvs = [], vertex, normal, uv, polygons = this.polygons, polygonIndices = [0, 0, 0], polygon, vertice_dict = {}, vertex_idx, currentIndex = 0, subMesh_dict = {}, subMesh_obj;
+
+            if (keepSubMeshes) {
+                // Sort Polygons, since subMeshes are indices range
+                polygons.sort(function (a, b) {
+                    if (a.shared.meshId === b.shared.meshId) {
+                        return a.shared.subMeshId - b.shared.subMeshId;
+                    } else {
+                        return a.shared.meshId - b.shared.meshId;
+                    }
+                });
+            }
+
+            for (var i = 0, il = polygons.length; i < il; i++) {
+                polygon = polygons[i];
+
+                // Building SubMeshes
+                if (!subMesh_dict[polygon.shared.meshId]) {
+                    subMesh_dict[polygon.shared.meshId] = {};
+                }
+                if (!subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId]) {
+                    subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId] = {
+                        indexStart: +Infinity,
+                        indexEnd: -Infinity,
+                        materialIndex: polygon.shared.materialIndex
+                    };
+                }
+                subMesh_obj = subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId];
+
+                for (var j = 2, jl = polygon.vertices.length; j < jl; j++) {
+                    polygonIndices[0] = 0;
+                    polygonIndices[1] = j - 1;
+                    polygonIndices[2] = j;
+
+                    for (var k = 0; k < 3; k++) {
+                        vertex = polygon.vertices[polygonIndices[k]].pos;
+                        normal = polygon.vertices[polygonIndices[k]].normal;
+                        uv = polygon.vertices[polygonIndices[k]].uv;
+                        vertex = new BABYLON.Vector3(vertex.x, vertex.y, vertex.z);
+                        normal = new BABYLON.Vector3(normal.x, normal.y, normal.z);
+                        vertex = BABYLON.Vector3.TransformCoordinates(vertex, matrix);
+                        normal = BABYLON.Vector3.TransformNormal(normal, matrix);
+
+                        vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
+
+                        // Check if 2 points can be merged
+                        if (!(typeof vertex_idx !== 'undefined' && normals[vertex_idx * 3] === normal.x && normals[vertex_idx * 3 + 1] === normal.y && normals[vertex_idx * 3 + 2] === normal.z && uvs[vertex_idx * 2] === uv.x && uvs[vertex_idx * 2 + 1] === uv.y)) {
+                            vertices.push(vertex.x, vertex.y, vertex.z);
+                            uvs.push(uv.x, uv.y);
+                            normals.push(normal.x, normal.y, normal.z);
+                            vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = (vertices.length / 3) - 1;
+                        }
+
+                        indices.push(vertex_idx);
+
+                        subMesh_obj.indexStart = Math.min(currentIndex, subMesh_obj.indexStart);
+                        subMesh_obj.indexEnd = Math.max(currentIndex, subMesh_obj.indexEnd);
+                        currentIndex++;
+                    }
+                }
+            }
+
+            mesh.setVerticesData(vertices, BABYLON.VertexBuffer.PositionKind);
+            mesh.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
+            mesh.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
+            mesh.setIndices(indices);
+
+            if (keepSubMeshes) {
+                // We offset the materialIndex by the previous number of materials in the CSG mixed meshes
+                var materialIndexOffset = 0, materialMaxIndex;
+
+                mesh.subMeshes.length = 0;
+
+                for (var m in subMesh_dict) {
+                    materialMaxIndex = -1;
+                    for (var sm in subMesh_dict[m]) {
+                        subMesh_obj = subMesh_dict[m][sm];
+                        BABYLON.SubMesh.CreateFromIndices(subMesh_obj.materialIndex + materialIndexOffset, subMesh_obj.indexStart, subMesh_obj.indexEnd - subMesh_obj.indexStart + 1, mesh);
+                        materialMaxIndex = Math.max(subMesh_obj.materialIndex, materialMaxIndex);
+                    }
+                    materialIndexOffset += ++materialMaxIndex;
+                }
+            }
+
+            return mesh;
+        };
+
+        // Build Mesh from CSG taking material and transforms into account
+        //ANY
+        CSG.prototype.toMesh = function (name, material, scene, keepSubMeshes) {
+            var mesh = this.buildMeshGeometry(name, scene, keepSubMeshes);
+
+            mesh.material = material;
+
+            mesh.position.copyFrom(this.position);
+            mesh.rotation.copyFrom(this.rotation);
+            mesh.scaling.copyFrom(this.scaling);
+            mesh.computeWorldMatrix(true);
+
+            return mesh;
+        };
+        return CSG;
+    })();
+    BABYLON.CSG = CSG;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.csg.js.map

+ 534 - 0
Babylon/Mesh/babylon.csg.ts

@@ -0,0 +1,534 @@
+module BABYLON {
+    // Unique ID when we import meshes from Babylon to CSG
+    var currentCSGMeshId = 0;
+
+    // # class Vertex
+
+    // Represents a vertex of a polygon. Use your own vertex class instead of this
+    // one to provide additional features like texture coordinates and vertex
+    // colors. Custom vertex classes need to provide a `pos` property and `clone()`,
+    // `flip()`, and `interpolate()` methods that behave analogous to the ones
+    // defined by `BABYLON.CSG.Vertex`. This class provides `normal` so convenience
+    // functions like `BABYLON.CSG.sphere()` can return a smooth vertex normal, but `normal`
+    // is not used anywhere else. 
+    // Same goes for uv, it allows to keep the original vertex uv coordinates of the 2 meshes
+    class Vertex {
+        constructor(public pos: Vector3, public normal: Vector3, public uv: Vector2) {
+        }
+
+        public clone(): Vertex {
+            return new Vertex(this.pos.clone(), this.normal.clone(), this.uv.clone());
+        }
+
+        // Invert all orientation-specific data (e.g. vertex normal). Called when the
+        // orientation of a polygon is flipped.
+        public flip(): void {
+            this.normal = this.normal.scale(-1);
+        }
+
+        // Create a new vertex between this vertex and `other` by linearly
+        // interpolating all properties using a parameter of `t`. Subclasses should
+        // override this to interpolate additional properties.
+        public interpolate(other, t): Vertex {
+            return new Vertex(Vector3.Lerp(this.pos, other.pos, t),
+                Vector3.Lerp(this.normal, other.normal, t),
+                Vector2.Lerp(this.uv, other.uv, t)
+                );
+        }
+    }
+
+    // # class Plane
+
+    // Represents a plane in 3D space.
+    class Plane {
+        constructor(public normal: Vector3, public w: number) {
+        }
+
+        // `BABYLON.CSG.Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a
+        // point is on the plane.
+        static EPSILON = 1e-5;
+
+        public static FromPoints(a: Vector3, b: Vector3, c: Vector3): Plane {
+            var v0 = c.subtract(a);
+            var v1 = b.subtract(a);
+
+            if (v0.lengthSquared() === 0 || v1.lengthSquared() === 0) {
+                return null;
+            }
+
+            var n = Vector3.Normalize(Vector3.Cross(c.subtract(a), b.subtract(a)));
+            return new Plane(n, Vector3.Dot(n, a));
+        }
+
+        public clone(): Plane {
+            return new Plane(this.normal.clone(), this.w);
+        }
+
+        public flip() {
+            this.normal = this.normal.scale(-1);
+            this.w = -this.w;
+        }
+
+        // Split `polygon` by this plane if needed, then put the polygon or polygon
+        // fragments in the appropriate lists. Coplanar polygons go into either
+        // `coplanarFront` or `coplanarBack` depending on their orientation with
+        // respect to this plane. Polygons in front or in back of this plane go into
+        // either `front` or `back`.
+        public splitPolygon(polygon: Polygon, coplanarFront: Polygon[], coplanarBack: Polygon[], front: Polygon[], back: Polygon[]): void {
+            var COPLANAR = 0;
+            var FRONT = 1;
+            var BACK = 2;
+            var SPANNING = 3;
+
+            // Classify each point as well as the entire polygon into one of the above
+            // four classes.
+            var polygonType = 0;
+            var types = [];
+            for (var i = 0; i < polygon.vertices.length; i++) {
+                var t = Vector3.Dot(this.normal, polygon.vertices[i].pos) - this.w;
+                var type = (t < -Plane.EPSILON) ? BACK : (t > Plane.EPSILON) ? FRONT : COPLANAR;
+                polygonType |= type;
+                types.push(type);
+            }
+
+            // Put the polygon in the correct list, splitting it when necessary.
+            switch (polygonType) {
+                case COPLANAR:
+                    (Vector3.Dot(this.normal, polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon);
+                    break;
+                case FRONT:
+                    front.push(polygon);
+                    break;
+                case BACK:
+                    back.push(polygon);
+                    break;
+                case SPANNING:
+                    var f = [], b = [];
+                    for (i = 0; i < polygon.vertices.length; i++) {
+                        var j = (i + 1) % polygon.vertices.length;
+                        var ti = types[i], tj = types[j];
+                        var vi = polygon.vertices[i], vj = polygon.vertices[j];
+                        if (ti != BACK) f.push(vi);
+                        if (ti != FRONT) b.push(ti != BACK ? vi.clone() : vi);
+                        if ((ti | tj) == SPANNING) {
+                            t = (this.w - Vector3.Dot(this.normal, vi.pos)) / Vector3.Dot(this.normal, vj.pos.subtract(vi.pos));
+                            var v = vi.interpolate(vj, t);
+                            f.push(v);
+                            b.push(v.clone());
+                        }
+                    }
+                    if (f.length >= 3) front.push(new Polygon(f, polygon.shared));
+                    if (b.length >= 3) back.push(new Polygon(b, polygon.shared));
+                    break;
+            }
+        }
+    }
+
+    // # class Polygon
+
+    // Represents a convex polygon. The vertices used to initialize a polygon must
+    // be coplanar and form a convex loop.
+    // 
+    // Each convex polygon has a `shared` property, which is shared between all
+    // polygons that are clones of each other or were split from the same polygon.
+    // This can be used to define per-polygon properties (such as surface color).
+    class Polygon {
+        public vertices: Vertex[];
+        public shared;
+        public plane: Plane;
+
+        constructor(vertices: Vertex[], shared) {
+            this.vertices = vertices;
+            this.shared = shared;
+            this.plane = Plane.FromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
+
+        }
+
+        public clone(): Polygon {
+            var vertices = this.vertices.map(v => v.clone());
+            return new Polygon(vertices, this.shared);
+        }
+
+        public flip() {
+            this.vertices.reverse().map(v => { v.flip(); });
+            this.plane.flip();
+        }
+    }
+
+    // # class Node
+
+    // Holds a node in a BSP tree. A BSP tree is built from a collection of polygons
+    // by picking a polygon to split along. That polygon (and all other coplanar
+    // polygons) are added directly to that node and the other polygons are added to
+    // the front and/or back subtrees. This is not a leafy BSP tree since there is
+    // no distinction between internal and leaf nodes.
+    class Node {
+        private plane = null;
+        private front = null;
+        private back = null;
+        private polygons = [];
+
+        constructor(polygons?) {
+            if (polygons) {
+                this.build(polygons);
+            }
+        }
+
+        public clone(): Node {
+            var node = new Node();
+            node.plane = this.plane && this.plane.clone();
+            node.front = this.front && this.front.clone();
+            node.back = this.back && this.back.clone();
+            node.polygons = this.polygons.map(p => p.clone());
+            return node;
+        }
+
+        // Convert solid space to empty space and empty space to solid space.
+        public invert(): void {
+            for (var i = 0; i < this.polygons.length; i++) {
+                this.polygons[i].flip();
+            }
+            this.plane.flip();
+            if (this.front) {
+                this.front.invert();
+            }
+            if (this.back) {
+                this.back.invert();
+            }
+            var temp = this.front;
+            this.front = this.back;
+            this.back = temp;
+        }
+
+        // Recursively remove all polygons in `polygons` that are inside this BSP
+        // tree.
+        clipPolygons(polygons: Polygon[]) {
+            if (!this.plane) return polygons.slice();
+            var front = [], back = [];
+            for (var i = 0; i < polygons.length; i++) {
+                this.plane.splitPolygon(polygons[i], front, back, front, back);
+            }
+            if (this.front) {
+                front = this.front.clipPolygons(front);
+            }
+            if (this.back) {
+                back = this.back.clipPolygons(back);
+            } else {
+                back = [];
+            }
+            return front.concat(back);
+        }
+
+        // Remove all polygons in this BSP tree that are inside the other BSP tree
+        // `bsp`.
+        clipTo(bsp: Node): void {
+            this.polygons = bsp.clipPolygons(this.polygons);
+            if (this.front) this.front.clipTo(bsp);
+            if (this.back) this.back.clipTo(bsp);
+        }
+
+        // Return a list of all polygons in this BSP tree.
+        allPolygons(): Polygon[] {
+            var polygons = this.polygons.slice();
+            if (this.front) polygons = polygons.concat(this.front.allPolygons());
+            if (this.back) polygons = polygons.concat(this.back.allPolygons());
+            return polygons;
+        }
+
+        // Build a BSP tree out of `polygons`. When called on an existing tree, the
+        // new polygons are filtered down to the bottom of the tree and become new
+        // nodes there. Each set of polygons is partitioned using the first polygon
+        // (no heuristic is used to pick a good split).
+        build(polygons: Polygon[]) {
+            if (!polygons.length) return;
+            if (!this.plane) this.plane = polygons[0].plane.clone();
+            var front = [], back = [];
+            for (var i = 0; i < polygons.length; i++) {
+                this.plane.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);
+            }
+            if (front.length) {
+                if (!this.front) this.front = new Node();
+                this.front.build(front);
+            }
+            if (back.length) {
+                if (!this.back) this.back = new Node();
+                this.back.build(back);
+            }
+        }
+    }
+
+    export class CSG {
+        private polygons = new Array<Polygon>();
+        public matrix: Matrix;
+        public position: Vector3;
+        public rotation: Vector3;
+        public scaling: Vector3;
+
+        // Convert BABYLON.Mesh to BABYLON.CSG
+        public static FromMesh(mesh: Mesh) {
+            var vertex, normal, uv, position,
+                polygon,
+                polygons = [],
+                vertices;
+
+            if (mesh instanceof BABYLON.Mesh) {
+                mesh.computeWorldMatrix(true);
+                var matrix = mesh.getWorldMatrix();
+                var meshPosition = mesh.position.clone();
+                var meshRotation = mesh.rotation.clone();
+                var meshScaling = mesh.scaling.clone();
+            } else {
+                throw 'BABYLON.CSG: Wrong Mesh type, must be BABYLON.Mesh';
+            }
+
+            var indices = mesh.getIndices(),
+                positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind),
+                normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind),
+                uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+
+            var subMeshes = mesh.subMeshes;
+
+            for (var sm = 0, sml = subMeshes.length; sm < sml; sm++) {
+                for (var i = subMeshes[sm].indexStart, il = subMeshes[sm].indexCount + subMeshes[sm].indexStart; i < il; i += 3) {
+                    vertices = [];
+                    for (var j = 0; j < 3; j++) {
+                        normal = new BABYLON.Vector3(normals[indices[i + j] * 3], normals[indices[i + j] * 3 + 1], normals[indices[i + j] * 3 + 2]);
+                        uv = new BABYLON.Vector2(uvs[indices[i + j] * 2], uvs[indices[i + j] * 2 + 1]);
+                        position = new BABYLON.Vector3(positions[indices[i + j] * 3], positions[indices[i + j] * 3 + 1], positions[indices[i + j] * 3 + 2]);
+                        position = BABYLON.Vector3.TransformCoordinates(position, matrix);
+                        normal = BABYLON.Vector3.TransformNormal(normal, matrix);
+
+                        vertex = new Vertex(position, normal, uv);
+                        vertices.push(vertex);
+                    }
+
+                    polygon = new Polygon(vertices, { subMeshId: sm, meshId: currentCSGMeshId, materialIndex: subMeshes[sm].materialIndex });
+
+                    // To handle the case of degenerated triangle
+                    // polygon.plane == null <=> the polygon does not represent 1 single plane <=> the triangle is degenerated
+                    if (polygon.plane)
+                        polygons.push(polygon);
+                }
+            }
+
+            var csg = CSG.FromPolygons(polygons);
+            csg.matrix = matrix;
+            csg.position = meshPosition;
+            csg.rotation = meshRotation;
+            csg.scaling = meshScaling;
+            currentCSGMeshId++;
+
+            return csg;
+        }
+
+
+        // Construct a BABYLON.CSG solid from a list of `BABYLON.CSG.Polygon` instances.
+        private static FromPolygons(polygons: Polygon[]): CSG {
+            var csg = new BABYLON.CSG();
+            csg.polygons = polygons;
+            return csg;
+        }
+
+        public clone(): CSG {
+            var csg = new BABYLON.CSG();
+            csg.polygons = this.polygons.map(p => p.clone());
+            csg.copyTransformAttributes(this);
+            return csg;
+        }
+
+        private toPolygons(): Polygon[] {
+            return this.polygons;
+        }
+
+        public union(csg: CSG): CSG {
+            var a = new Node(this.clone().polygons);
+            var b = new Node(csg.clone().polygons);
+            a.clipTo(b);
+            b.clipTo(a);
+            b.invert();
+            b.clipTo(a);
+            b.invert();
+            a.build(b.allPolygons());
+            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
+        }
+
+        public subtract(csg: CSG): CSG {
+            var a = new Node(this.clone().polygons);
+            var b = new Node(csg.clone().polygons);
+            a.invert();
+            a.clipTo(b);
+            b.clipTo(a);
+            b.invert();
+            b.clipTo(a);
+            b.invert();
+            a.build(b.allPolygons());
+            a.invert();
+            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
+        }
+
+        public intersect(csg: CSG): CSG {
+            var a = new Node(this.clone().polygons);
+            var b = new Node(csg.clone().polygons);
+            a.invert();
+            b.clipTo(a);
+            b.invert();
+            a.clipTo(b);
+            b.clipTo(a);
+            a.build(b.allPolygons());
+            a.invert();
+            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
+        }
+
+        // Return a new BABYLON.CSG solid with solid and empty space switched. This solid is
+        // not modified.
+        public inverse(): CSG {
+            var csg = this.clone();
+            csg.polygons.map(p => { p.flip(); });
+            return csg;
+        }
+
+        // This is used to keep meshes transformations so they can be restored
+        // when we build back a Babylon Mesh
+        // NB : All CSG operations are performed in world coordinates
+        public copyTransformAttributes(csg: CSG): CSG {
+            this.matrix = csg.matrix;
+            this.position = csg.position;
+            this.rotation = csg.rotation;
+            this.scaling = csg.scaling;
+
+            return this;
+        }
+
+        // Build Raw mesh from CSG
+        // Coordinates here are in world space
+        //ANY
+        public buildMeshGeometry(name: string, scene, keepSubMeshes: boolean): Mesh {
+            var matrix = this.matrix.clone();
+            matrix.invert();
+
+            var mesh = new BABYLON.Mesh(name, scene),
+                vertices = [],
+                indices = [],
+                normals = [],
+                uvs = [],
+                vertex, normal, uv,
+                polygons = this.polygons,
+                polygonIndices = [0, 0, 0],
+                polygon,
+                vertice_dict = {},
+                vertex_idx,
+                currentIndex = 0,
+                subMesh_dict = {},
+                subMesh_obj;
+
+            if (keepSubMeshes) {
+                // Sort Polygons, since subMeshes are indices range
+                polygons.sort((a, b) => {
+                    if (a.shared.meshId === b.shared.meshId) {
+                        return a.shared.subMeshId - b.shared.subMeshId;
+                    } else {
+                        return a.shared.meshId - b.shared.meshId;
+                    }
+                });
+            }
+
+            for (var i = 0, il = polygons.length; i < il; i++) {
+                polygon = polygons[i];
+
+                // Building SubMeshes
+                if (!subMesh_dict[polygon.shared.meshId]) {
+                    subMesh_dict[polygon.shared.meshId] = {};
+                }
+                if (!subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId]) {
+                    subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId] = {
+                        indexStart: +Infinity,
+                        indexEnd: -Infinity,
+                        materialIndex: polygon.shared.materialIndex
+                    };
+                }
+                subMesh_obj = subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId];
+
+
+                for (var j = 2, jl = polygon.vertices.length; j < jl; j++) {
+
+                    polygonIndices[0] = 0;
+                    polygonIndices[1] = j - 1;
+                    polygonIndices[2] = j;
+
+                    for (var k = 0; k < 3; k++) {
+                        vertex = polygon.vertices[polygonIndices[k]].pos;
+                        normal = polygon.vertices[polygonIndices[k]].normal;
+                        uv = polygon.vertices[polygonIndices[k]].uv;
+                        vertex = new BABYLON.Vector3(vertex.x, vertex.y, vertex.z);
+                        normal = new BABYLON.Vector3(normal.x, normal.y, normal.z);
+                        vertex = BABYLON.Vector3.TransformCoordinates(vertex, matrix);
+                        normal = BABYLON.Vector3.TransformNormal(normal, matrix);
+
+                        vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
+
+                        // Check if 2 points can be merged
+                        if (!(typeof vertex_idx !== 'undefined' &&
+                            normals[vertex_idx * 3] === normal.x &&
+                            normals[vertex_idx * 3 + 1] === normal.y &&
+                            normals[vertex_idx * 3 + 2] === normal.z &&
+                            uvs[vertex_idx * 2] === uv.x &&
+                            uvs[vertex_idx * 2 + 1] === uv.y)) {
+                            vertices.push(vertex.x, vertex.y, vertex.z);
+                            uvs.push(uv.x, uv.y);
+                            normals.push(normal.x, normal.y, normal.z);
+                            vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = (vertices.length / 3) - 1;
+                        }
+
+                        indices.push(vertex_idx);
+
+                        subMesh_obj.indexStart = Math.min(currentIndex, subMesh_obj.indexStart);
+                        subMesh_obj.indexEnd = Math.max(currentIndex, subMesh_obj.indexEnd);
+                        currentIndex++;
+                    }
+
+                }
+
+            }
+
+            mesh.setVerticesData(vertices, BABYLON.VertexBuffer.PositionKind);
+            mesh.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
+            mesh.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
+            mesh.setIndices(indices);
+
+            if (keepSubMeshes) {
+                // We offset the materialIndex by the previous number of materials in the CSG mixed meshes
+                var materialIndexOffset = 0,
+                    materialMaxIndex;
+
+                mesh.subMeshes.length = 0;
+
+                for (var m in subMesh_dict) {
+                    materialMaxIndex = -1;
+                    for (var sm in subMesh_dict[m]) {
+                        subMesh_obj = subMesh_dict[m][sm];
+                        BABYLON.SubMesh.CreateFromIndices(subMesh_obj.materialIndex + materialIndexOffset, subMesh_obj.indexStart, subMesh_obj.indexEnd - subMesh_obj.indexStart + 1, mesh);
+                        materialMaxIndex = Math.max(subMesh_obj.materialIndex, materialMaxIndex);
+                    }
+                    materialIndexOffset += ++materialMaxIndex;
+                }
+            }
+
+            return mesh;
+        }
+
+        // Build Mesh from CSG taking material and transforms into account
+        //ANY
+        public toMesh(name: string, material, scene, keepSubMeshes: boolean): Mesh {
+            var mesh = this.buildMeshGeometry(name, scene, keepSubMeshes);
+
+            mesh.material = material;
+
+            mesh.position.copyFrom(this.position);
+            mesh.rotation.copyFrom(this.rotation);
+            mesh.scaling.copyFrom(this.scaling);
+            mesh.computeWorldMatrix(true);
+
+            return mesh;
+        }
+    }
+} 

File diff suppressed because it is too large
+ 980 - 997
Babylon/Mesh/babylon.mesh.js


File diff suppressed because it is too large
+ 1283 - 0
Babylon/Mesh/babylon.mesh.ts


File diff suppressed because it is too large
+ 571 - 576
Babylon/Mesh/babylon.mesh.vertexData.js


+ 721 - 0
Babylon/Mesh/babylon.mesh.vertexData.ts

@@ -0,0 +1,721 @@
+module BABYLON {
+    export class VertexData {
+        public positions: number[];
+        public normals: number[];
+        public uvs: number[];
+        public uv2s: number[];
+        public colors: number[];
+        public matricesIndices: number[];
+        public matricesWeights: number[];
+        public indices: number[];
+
+        public applyToMesh(mesh: Mesh, updatable?: boolean): void {
+            if (this.positions) {
+                mesh.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
+            }
+
+            if (this.normals) {
+                mesh.setVerticesData(this.normals, BABYLON.VertexBuffer.NormalKind, updatable);
+            }
+
+            if (this.uvs) {
+                mesh.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
+            }
+
+            if (this.uv2s) {
+                mesh.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
+            }
+
+            if (this.colors) {
+                mesh.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
+            }
+
+            if (this.matricesIndices) {
+                mesh.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
+            }
+
+            if (this.matricesWeights) {
+                mesh.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
+            }
+
+            if (this.indices) {
+                mesh.setIndices(this.indices);
+            }
+        }
+
+        public transform(matrix: Matrix): void {
+            var transformed = BABYLON.Vector3.Zero();
+
+            if (this.positions) {
+                var position = BABYLON.Vector3.Zero();
+
+                for (var index = 0; index < this.positions.length; index += 3) {
+                    BABYLON.Vector3.FromArrayToRef(this.positions, index, position);
+
+                    BABYLON.Vector3.TransformCoordinatesToRef(position, matrix, transformed);
+                    this.positions[index] = transformed.x;
+                    this.positions[index + 1] = transformed.y;
+                    this.positions[index + 2] = transformed.z;
+                }
+            }
+
+            if (this.normals) {
+                var normal = BABYLON.Vector3.Zero();
+
+                for (index = 0; index < this.normals.length; index += 3) {
+                    BABYLON.Vector3.FromArrayToRef(this.normals, index, normal);
+
+                    BABYLON.Vector3.TransformNormalToRef(normal, matrix, transformed);
+                    this.normals[index] = transformed.x;
+                    this.normals[index + 1] = transformed.y;
+                    this.normals[index + 2] = transformed.z;
+                }
+            }
+        }
+
+        public merge(other: VertexData): void {
+            if (other.indices) {
+                if (!this.indices) {
+                    this.indices = [];
+                }
+
+                var offset = this.positions ? this.positions.length / 3 : 0;
+                for (var index = 0; index < other.indices.length; index++) {
+                    this.indices.push(other.indices[index] + offset);
+                }
+            }
+
+            if (other.positions) {
+                if (!this.positions) {
+                    this.positions = [];
+                }
+
+                for (index = 0; index < other.positions.length; index++) {
+                    this.positions.push(other.positions[index]);
+                }
+            }
+
+            if (other.normals) {
+                if (!this.normals) {
+                    this.normals = [];
+                }
+                for (index = 0; index < other.normals.length; index++) {
+                    this.normals.push(other.normals[index]);
+                }
+            }
+
+            if (other.uvs) {
+                if (!this.uvs) {
+                    this.uvs = [];
+                }
+                for (index = 0; index < other.uvs.length; index++) {
+                    this.uvs.push(other.uvs[index]);
+                }
+            }
+
+            if (other.uv2s) {
+                if (!this.uv2s) {
+                    this.uv2s = [];
+                }
+                for (index = 0; index < other.uv2s.length; index++) {
+                    this.uv2s.push(other.uv2s[index]);
+                }
+            }
+
+            if (other.matricesIndices) {
+                if (!this.matricesIndices) {
+                    this.matricesIndices = [];
+                }
+                for (index = 0; index < other.matricesIndices.length; index++) {
+                    this.matricesIndices.push(other.matricesIndices[index]);
+                }
+            }
+
+            if (other.matricesWeights) {
+                if (!this.matricesWeights) {
+                    this.matricesWeights = [];
+                }
+                for (index = 0; index < other.matricesWeights.length; index++) {
+                    this.matricesWeights.push(other.matricesWeights[index]);
+                }
+            }
+
+            if (other.colors) {
+                if (!this.colors) {
+                    this.colors = [];
+                }
+                for (index = 0; index < other.colors.length; index++) {
+                    this.colors.push(other.colors[index]);
+                }
+            }
+        }
+
+        // Statics
+        public static ExtractFromMesh(mesh: Mesh): VertexData {
+            var result = new BABYLON.VertexData();
+
+            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                result.positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            }
+
+            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                result.normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+            }
+
+            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                result.uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+            }
+
+            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                result.uv2s = mesh.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
+            }
+
+            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                result.colors = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+            }
+
+            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
+                result.matricesIndices = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+            }
+
+            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+                result.matricesWeights = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+            }
+
+            result.indices = mesh.getIndices();
+
+            return result;
+        }
+
+        public static CreateBox(size: number): VertexData {
+            var normalsSource = [
+                new BABYLON.Vector3(0, 0, 1),
+                new BABYLON.Vector3(0, 0, -1),
+                new BABYLON.Vector3(1, 0, 0),
+                new BABYLON.Vector3(-1, 0, 0),
+                new BABYLON.Vector3(0, 1, 0),
+                new BABYLON.Vector3(0, -1, 0)
+            ];
+
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
+
+            size = size || 1;
+
+            // Create each face in turn.
+            for (var index = 0; index < normalsSource.length; index++) {
+                var normal = normalsSource[index];
+
+                // Get two vectors perpendicular to the face normal and to each other.
+                var side1 = new BABYLON.Vector3(normal.y, normal.z, normal.x);
+                var side2 = BABYLON.Vector3.Cross(normal, side1);
+
+                // Six indices (two triangles) per face.
+                var verticesLength = positions.length / 3;
+                indices.push(verticesLength);
+                indices.push(verticesLength + 1);
+                indices.push(verticesLength + 2);
+
+                indices.push(verticesLength);
+                indices.push(verticesLength + 2);
+                indices.push(verticesLength + 3);
+
+                // Four vertices per face.
+                var vertex = normal.subtract(side1).subtract(side2).scale(size / 2);
+                positions.push(vertex.x, vertex.y, vertex.z);
+                normals.push(normal.x, normal.y, normal.z);
+                uvs.push(1.0, 1.0);
+
+                vertex = normal.subtract(side1).add(side2).scale(size / 2);
+                positions.push(vertex.x, vertex.y, vertex.z);
+                normals.push(normal.x, normal.y, normal.z);
+                uvs.push(0.0, 1.0);
+
+                vertex = normal.add(side1).add(side2).scale(size / 2);
+                positions.push(vertex.x, vertex.y, vertex.z);
+                normals.push(normal.x, normal.y, normal.z);
+                uvs.push(0.0, 0.0);
+
+                vertex = normal.add(side1).subtract(side2).scale(size / 2);
+                positions.push(vertex.x, vertex.y, vertex.z);
+                normals.push(normal.x, normal.y, normal.z);
+                uvs.push(1.0, 0.0);
+            }
+
+            // Result
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
+        }
+
+        public static CreateSphere(segments: number, diameter: number): VertexData {
+
+            segments = segments || 32;
+            diameter = diameter || 1;
+
+            var radius = diameter / 2;
+
+            var totalZRotationSteps = 2 + segments;
+            var totalYRotationSteps = 2 * totalZRotationSteps;
+
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
+
+            for (var zRotationStep = 0; zRotationStep <= totalZRotationSteps; zRotationStep++) {
+                var normalizedZ = zRotationStep / totalZRotationSteps;
+                var angleZ = (normalizedZ * Math.PI);
+
+                for (var yRotationStep = 0; yRotationStep <= totalYRotationSteps; yRotationStep++) {
+                    var normalizedY = yRotationStep / totalYRotationSteps;
+
+                    var angleY = normalizedY * Math.PI * 2;
+
+                    var rotationZ = BABYLON.Matrix.RotationZ(-angleZ);
+                    var rotationY = BABYLON.Matrix.RotationY(angleY);
+                    var afterRotZ = BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.Up(), rotationZ);
+                    var complete = BABYLON.Vector3.TransformCoordinates(afterRotZ, rotationY);
+
+                    var vertex = complete.scale(radius);
+                    var normal = BABYLON.Vector3.Normalize(vertex);
+
+                    positions.push(vertex.x, vertex.y, vertex.z);
+                    normals.push(normal.x, normal.y, normal.z);
+                    uvs.push(normalizedZ, normalizedY);
+                }
+
+                if (zRotationStep > 0) {
+                    var verticesCount = positions.length / 3;
+                    for (var firstIndex = verticesCount - 2 * (totalYRotationSteps + 1); (firstIndex + totalYRotationSteps + 2) < verticesCount; firstIndex++) {
+                        indices.push((firstIndex));
+                        indices.push((firstIndex + 1));
+                        indices.push(firstIndex + totalYRotationSteps + 1);
+
+                        indices.push((firstIndex + totalYRotationSteps + 1));
+                        indices.push((firstIndex + 1));
+                        indices.push((firstIndex + totalYRotationSteps + 2));
+                    }
+                }
+            }
+
+            // Result
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
+        }
+
+        public static CreateCylinder(height: number, diameterTop: number, diameterBottom: number, tessellation: number): VertexData {
+            var radiusTop = diameterTop / 2;
+            var radiusBottom = diameterBottom / 2;
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
+
+            height = height || 1;
+            diameterTop = diameterTop || 0.5;
+            diameterBottom = diameterBottom || 1;
+            tessellation = tessellation || 16;
+
+            var getCircleVector = i => {
+                var angle = (i * 2.0 * Math.PI / tessellation);
+                var dx = Math.sin(angle);
+                var dz = Math.cos(angle);
+
+                return new BABYLON.Vector3(dx, 0, dz);
+            };
+
+            var createCylinderCap = isTop => {
+                var radius = isTop ? radiusTop : radiusBottom;
+
+                if (radius == 0) {
+                    return;
+                }
+
+                // Create cap indices.
+                for (var i = 0; i < tessellation - 2; i++) {
+                    var i1 = (i + 1) % tessellation;
+                    var i2 = (i + 2) % tessellation;
+
+                    if (!isTop) {
+                        var tmp = i1;
+                        i1 = i2;
+                        i2 = tmp;
+                    }
+
+                    var vbase = positions.length / 3;
+                    indices.push(vbase);
+                    indices.push(vbase + i1);
+                    indices.push(vbase + i2);
+                }
+
+                // Which end of the cylinder is this?
+                var normal = new BABYLON.Vector3(0, -1, 0);
+                var textureScale = new BABYLON.Vector2(-0.5, -0.5);
+
+                if (!isTop) {
+                    normal = normal.scale(-1);
+                    textureScale.x = -textureScale.x;
+                }
+
+                // Create cap vertices.
+                for (i = 0; i < tessellation; i++) {
+                    var circleVector = getCircleVector(i);
+                    var position = circleVector.scale(radius).add(normal.scale(height));
+                    var textureCoordinate = new BABYLON.Vector2(circleVector.x * textureScale.x + 0.5, circleVector.z * textureScale.y + 0.5);
+
+                    positions.push(position.x, position.y, position.z);
+                    normals.push(normal.x, normal.y, normal.z);
+                    uvs.push(textureCoordinate.x, textureCoordinate.y);
+                }
+            };
+
+            height /= 2;
+
+            var topOffset = new BABYLON.Vector3(0, 1, 0).scale(height);
+
+            var stride = tessellation + 1;
+
+            // Create a ring of triangles around the outside of the cylinder.
+            for (var i = 0; i <= tessellation; i++) {
+                var normal = getCircleVector(i);
+                var sideOffsetBottom = normal.scale(radiusBottom);
+                var sideOffsetTop = normal.scale(radiusTop);
+                var textureCoordinate = new BABYLON.Vector2(i / tessellation, 0);
+
+                var position = sideOffsetBottom.add(topOffset);
+                positions.push(position.x, position.y, position.z);
+                normals.push(normal.x, normal.y, normal.z);
+                uvs.push(textureCoordinate.x, textureCoordinate.y);
+
+                position = sideOffsetTop.subtract(topOffset);
+                textureCoordinate.y += 1;
+                positions.push(position.x, position.y, position.z);
+                normals.push(normal.x, normal.y, normal.z);
+                uvs.push(textureCoordinate.x, textureCoordinate.y);
+
+                indices.push(i * 2);
+                indices.push((i * 2 + 2) % (stride * 2));
+                indices.push(i * 2 + 1);
+
+                indices.push(i * 2 + 1);
+                indices.push((i * 2 + 2) % (stride * 2));
+                indices.push((i * 2 + 3) % (stride * 2));
+            }
+
+            // Create flat triangle fan caps to seal the top and bottom.
+            createCylinderCap(true);
+            createCylinderCap(false);
+
+            // Result
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
+        }
+
+        public static CreateTorus(diameter, thickness, tessellation) {
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
+
+            diameter = diameter || 1;
+            thickness = thickness || 0.5;
+            tessellation = tessellation || 16;
+
+            var stride = tessellation + 1;
+
+            for (var i = 0; i <= tessellation; i++) {
+                var u = i / tessellation;
+
+                var outerAngle = i * Math.PI * 2.0 / tessellation - Math.PI / 2.0;
+
+                var transform = BABYLON.Matrix.Translation(diameter / 2.0, 0, 0).multiply(BABYLON.Matrix.RotationY(outerAngle));
+
+                for (var j = 0; j <= tessellation; j++) {
+                    var v = 1 - j / tessellation;
+
+                    var innerAngle = j * Math.PI * 2.0 / tessellation + Math.PI;
+                    var dx = Math.cos(innerAngle);
+                    var dy = Math.sin(innerAngle);
+
+                    // Create a vertex.
+                    var normal = new BABYLON.Vector3(dx, dy, 0);
+                    var position = normal.scale(thickness / 2);
+                    var textureCoordinate = new BABYLON.Vector2(u, v);
+
+                    position = BABYLON.Vector3.TransformCoordinates(position, transform);
+                    normal = BABYLON.Vector3.TransformNormal(normal, transform);
+
+                    positions.push(position.x, position.y, position.z);
+                    normals.push(normal.x, normal.y, normal.z);
+                    uvs.push(textureCoordinate.x, textureCoordinate.y);
+
+                    // And create indices for two triangles.
+                    var nextI = (i + 1) % stride;
+                    var nextJ = (j + 1) % stride;
+
+                    indices.push(i * stride + j);
+                    indices.push(i * stride + nextJ);
+                    indices.push(nextI * stride + j);
+
+                    indices.push(i * stride + nextJ);
+                    indices.push(nextI * stride + nextJ);
+                    indices.push(nextI * stride + j);
+                }
+            }
+
+            // Result
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
+        }
+
+        public static CreateGround(width: number, height: number, subdivisions: number): VertexData {
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
+            var row, col;
+
+            width = width || 1;
+            height = height || 1;
+            subdivisions = subdivisions || 1;
+
+            for (row = 0; row <= subdivisions; row++) {
+                for (col = 0; col <= subdivisions; col++) {
+                    var position = new BABYLON.Vector3((col * width) / subdivisions - (width / 2.0), 0, ((subdivisions - row) * height) / subdivisions - (height / 2.0));
+                    var normal = new BABYLON.Vector3(0, 1.0, 0);
+
+                    positions.push(position.x, position.y, position.z);
+                    normals.push(normal.x, normal.y, normal.z);
+                    uvs.push(col / subdivisions, 1.0 - row / subdivisions);
+                }
+            }
+
+            for (row = 0; row < subdivisions; row++) {
+                for (col = 0; col < subdivisions; col++) {
+                    indices.push(col + 1 + (row + 1) * (subdivisions + 1));
+                    indices.push(col + 1 + row * (subdivisions + 1));
+                    indices.push(col + row * (subdivisions + 1));
+
+                    indices.push(col + (row + 1) * (subdivisions + 1));
+                    indices.push(col + 1 + (row + 1) * (subdivisions + 1));
+                    indices.push(col + row * (subdivisions + 1));
+                }
+            }
+
+            // Result
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
+        }
+
+        public static CreatePlane(size: number): VertexData {
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
+
+            size = size || 1;
+
+            // Vertices
+            var halfSize = size / 2.0;
+            positions.push(-halfSize, -halfSize, 0);
+            normals.push(0, 0, -1.0);
+            uvs.push(0.0, 0.0);
+
+            positions.push(halfSize, -halfSize, 0);
+            normals.push(0, 0, -1.0);
+            uvs.push(1.0, 0.0);
+
+            positions.push(halfSize, halfSize, 0);
+            normals.push(0, 0, -1.0);
+            uvs.push(1.0, 1.0);
+
+            positions.push(-halfSize, halfSize, 0);
+            normals.push(0, 0, -1.0);
+            uvs.push(0.0, 1.0);
+
+            // Indices
+            indices.push(0);
+            indices.push(1);
+            indices.push(2);
+
+            indices.push(0);
+            indices.push(2);
+            indices.push(3);
+
+            // Result
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
+        }
+
+        // based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
+        public static CreateTorusKnot(radius: number, tube: number, radialSegments: number, tubularSegments: number, p: number, q: number): VertexData {
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
+
+            radius = radius || 2;
+            tube = tube || 0.5;
+            radialSegments = radialSegments || 32;
+            tubularSegments = tubularSegments || 32;
+            p = p || 2;
+            q = q || 3;
+
+            // Helper
+            var getPos = (angle) => {
+
+                var cu = Math.cos(angle);
+                var su = Math.sin(angle);
+                var quOverP = q / p * angle;
+                var cs = Math.cos(quOverP);
+
+                var tx = radius * (2 + cs) * 0.5 * cu;
+                var ty = radius * (2 + cs) * su * 0.5;
+                var tz = radius * Math.sin(quOverP) * 0.5;
+
+                return new BABYLON.Vector3(tx, ty, tz);
+            };
+
+            // Vertices
+            for (var i = 0; i <= radialSegments; i++) {
+                var modI = i % radialSegments;
+                var u = modI / radialSegments * 2 * p * Math.PI;
+                var p1 = getPos(u);
+                var p2 = getPos(u + 0.01);
+                var tang = p2.subtract(p1);
+                var n = p2.add(p1);
+
+                var bitan = BABYLON.Vector3.Cross(tang, n);
+                n = BABYLON.Vector3.Cross(bitan, tang);
+
+                bitan.normalize();
+                n.normalize();
+
+                for (var j = 0; j < tubularSegments; j++) {
+                    var modJ = j % tubularSegments;
+                    var v = modJ / tubularSegments * 2 * Math.PI;
+                    var cx = -tube * Math.cos(v);
+                    var cy = tube * Math.sin(v);
+
+                    positions.push(p1.x + cx * n.x + cy * bitan.x);
+                    positions.push(p1.y + cx * n.y + cy * bitan.y);
+                    positions.push(p1.z + cx * n.z + cy * bitan.z);
+
+                    uvs.push(i / radialSegments);
+                    uvs.push(j / tubularSegments);
+                }
+            }
+
+            for (i = 0; i < radialSegments; i++) {
+                for (j = 0; j < tubularSegments; j++) {
+                    var jNext = (j + 1) % tubularSegments;
+                    var a = i * tubularSegments + j;
+                    var b = (i + 1) * tubularSegments + j;
+                    var c = (i + 1) * tubularSegments + jNext;
+                    var d = i * tubularSegments + jNext;
+
+                    indices.push(d); indices.push(b); indices.push(a);
+                    indices.push(d); indices.push(c); indices.push(b);
+                }
+            }
+
+            // Normals
+            BABYLON.VertexData.ComputeNormals(positions, indices, normals);
+
+            // Result
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
+        }
+
+        // Tools
+        public static ComputeNormals(positions: number[], indices: number[], normals: number[]) {
+            var positionVectors = [];
+            var facesOfVertices = [];
+            var index;
+
+            for (index = 0; index < positions.length; index += 3) {
+                var vector3 = new BABYLON.Vector3(positions[index], positions[index + 1], positions[index + 2]);
+                positionVectors.push(vector3);
+                facesOfVertices.push([]);
+            }
+            // Compute normals
+            var facesNormals = [];
+            for (index = 0; index < indices.length / 3; index++) {
+                var i1 = indices[index * 3];
+                var i2 = indices[index * 3 + 1];
+                var i3 = indices[index * 3 + 2];
+
+                var p1 = positionVectors[i1];
+                var p2 = positionVectors[i2];
+                var p3 = positionVectors[i3];
+
+                var p1p2 = p1.subtract(p2);
+                var p3p2 = p3.subtract(p2);
+
+                facesNormals[index] = BABYLON.Vector3.Normalize(BABYLON.Vector3.Cross(p1p2, p3p2));
+                facesOfVertices[i1].push(index);
+                facesOfVertices[i2].push(index);
+                facesOfVertices[i3].push(index);
+            }
+
+            for (index = 0; index < positionVectors.length; index++) {
+                var faces = facesOfVertices[index];
+
+                var normal = BABYLON.Vector3.Zero();
+                for (var faceIndex = 0; faceIndex < faces.length; faceIndex++) {
+                    normal.addInPlace(facesNormals[faces[faceIndex]]);
+                }
+
+                normal = BABYLON.Vector3.Normalize(normal.scale(1.0 / faces.length));
+
+                normals[index * 3] = normal.x;
+                normals[index * 3 + 1] = normal.y;
+                normals[index * 3 + 2] = normal.z;
+            }
+        }
+    }
+} 

+ 107 - 106
Babylon/Mesh/babylon.subMesh.js

@@ -1,138 +1,139 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.SubMesh = function (materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh) {
-        this._mesh = mesh;
-        mesh.subMeshes.push(this);
-        this.materialIndex = materialIndex;
-        this.verticesStart = verticesStart;
-        this.verticesCount = verticesCount;
-        this.indexStart = indexStart;
-        this.indexCount = indexCount;
-
-        this.refreshBoundingInfo();
-    };
+var BABYLON;
+(function (BABYLON) {
+    var SubMesh = (function () {
+        function SubMesh(materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh) {
+            this.materialIndex = materialIndex;
+            this.verticesStart = verticesStart;
+            this.verticesCount = verticesCount;
+            this.indexStart = indexStart;
+            this.indexCount = indexCount;
+            this._mesh = mesh;
+            mesh.subMeshes.push(this);
+
+            this.refreshBoundingInfo();
+        }
+        SubMesh.prototype.getBoundingInfo = function () {
+            return this._boundingInfo;
+        };
 
-    //Properties
-    BABYLON.SubMesh.prototype.getBoundingInfo = function () {
-        return this._boundingInfo;
-    };
+        SubMesh.prototype.getMesh = function () {
+            return this._mesh;
+        };
 
-    BABYLON.SubMesh.prototype.getMesh = function () {
-        return this._mesh;
-    };
+        //ANY
+        SubMesh.prototype.getMaterial = function () {
+            var rootMaterial = this._mesh.material;
 
-    BABYLON.SubMesh.prototype.getMaterial = function () {
-        var rootMaterial = this._mesh.material;
+            if (rootMaterial && rootMaterial.getSubMaterial) {
+                return rootMaterial.getSubMaterial(this.materialIndex);
+            }
 
-        if (rootMaterial && rootMaterial.getSubMaterial) {
-            return rootMaterial.getSubMaterial(this.materialIndex);
-        }
+            if (!rootMaterial) {
+                return this._mesh.getScene().defaultMaterial;
+            }
 
-        if (!rootMaterial) {
-            return this._mesh._scene.defaultMaterial;
-        }
+            return rootMaterial;
+        };
 
-        return rootMaterial;
-    };
+        // Methods
+        SubMesh.prototype.refreshBoundingInfo = function () {
+            var data = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
 
-    // Methods
-    BABYLON.SubMesh.prototype.refreshBoundingInfo = function () {
-        var data = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            if (!data) {
+                return;
+            }
 
-        if (!data) {
-            return;
-        }
+            var extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
+            this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+        };
 
-        var extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
-        this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-    };
+        SubMesh.prototype._checkCollision = function (collider) {
+            return this._boundingInfo._checkCollision(collider);
+        };
 
-    BABYLON.SubMesh.prototype._checkCollision = function (collider) {
-        return this._boundingInfo._checkCollision(collider);
-    };
+        SubMesh.prototype.updateBoundingInfo = function (world, scale) {
+            if (typeof scale === "undefined") { scale = 1.0; }
+            this._boundingInfo._update(world, scale);
+        };
 
-    BABYLON.SubMesh.prototype.updateBoundingInfo = function (world, scale) {
-        this._boundingInfo._update(world, scale);
-    };
+        SubMesh.prototype.isInFrustum = function (frustumPlanes) {
+            return this._boundingInfo.isInFrustum(frustumPlanes);
+        };
 
-    BABYLON.SubMesh.prototype.isInFrustum = function (frustumPlanes) {
-        return this._boundingInfo.isInFrustum(frustumPlanes);
-    };
+        SubMesh.prototype.render = function () {
+            this._mesh.render(this);
+        };
 
-    BABYLON.SubMesh.prototype.render = function () {
-        this._mesh.render(this);
-    };
+        //ANY
+        SubMesh.prototype.getLinesIndexBuffer = function (indices, engine) {
+            if (!this._linesIndexBuffer) {
+                var linesIndices = [];
 
-    BABYLON.SubMesh.prototype.getLinesIndexBuffer = function (indices, engine) {
-        if (!this._linesIndexBuffer) {
-            var linesIndices = [];
+                for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
+                    linesIndices.push(indices[index], indices[index + 1], indices[index + 1], indices[index + 2], indices[index + 2], indices[index]);
+                }
 
-            for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
-                linesIndices.push(indices[index], indices[index + 1],
-                                    indices[index + 1], indices[index + 2],
-                                    indices[index + 2], indices[index]);
+                this._linesIndexBuffer = engine.createIndexBuffer(linesIndices);
+                this.linesIndexCount = linesIndices.length;
             }
+            return this._linesIndexBuffer;
+        };
 
-            this._linesIndexBuffer = engine.createIndexBuffer(linesIndices);
-            this.linesIndexCount = linesIndices.length;
-        }
-        return this._linesIndexBuffer;
-    };
-
-    BABYLON.SubMesh.prototype.canIntersects = function (ray) {
-        return ray.intersectsBox(this._boundingInfo.boundingBox);
-    };
+        SubMesh.prototype.canIntersects = function (ray) {
+            return ray.intersectsBox(this._boundingInfo.boundingBox);
+        };
 
-    BABYLON.SubMesh.prototype.intersects = function (ray, positions, indices, fastCheck) {
-        var intersectInfo = null;
+        //ANY create intersectinfo class
+        SubMesh.prototype.intersects = function (ray, positions, indices, fastCheck) {
+            var intersectInfo = null;
 
-        // Triangles test
-        for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
-            var p0 = positions[indices[index]];
-            var p1 = positions[indices[index + 1]];
-            var p2 = positions[indices[index + 2]];
+            for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
+                var p0 = positions[indices[index]];
+                var p1 = positions[indices[index + 1]];
+                var p2 = positions[indices[index + 2]];
 
-            var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
+                var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
 
-            if (currentIntersectInfo) {
-                if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
-                    intersectInfo = currentIntersectInfo;
-                    intersectInfo.faceId = index / 3;
+                if (currentIntersectInfo) {
+                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
+                        intersectInfo = currentIntersectInfo;
+                        intersectInfo.faceId = index / 3;
 
-                    if (fastCheck) {
-                        break;
+                        if (fastCheck) {
+                            break;
+                        }
                     }
                 }
             }
-        }
 
-        return intersectInfo;
-    };
+            return intersectInfo;
+        };
 
-    // Clone    
-    BABYLON.SubMesh.prototype.clone = function (newMesh) {
-        return new BABYLON.SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh);
-    };
+        // Clone
+        SubMesh.prototype.clone = function (newMesh) {
+            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh);
+        };
 
-    // Statics
-    BABYLON.SubMesh.CreateFromIndices = function (materialIndex, startIndex, indexCount, mesh) {
-        var minVertexIndex = Number.MAX_VALUE;
-        var maxVertexIndex = -Number.MAX_VALUE;
+        // Statics
+        SubMesh.CreateFromIndices = function (materialIndex, startIndex, indexCount, mesh) {
+            var minVertexIndex = Number.MAX_VALUE;
+            var maxVertexIndex = -Number.MAX_VALUE;
 
-        var indices = mesh.getIndices();
+            var indices = mesh.getIndices();
 
-        for (var index = startIndex; index < startIndex + indexCount; index++) {
-            var vertexIndex = indices[index];
+            for (var index = startIndex; index < startIndex + indexCount; index++) {
+                var vertexIndex = indices[index];
 
-            if (vertexIndex < minVertexIndex)
-                minVertexIndex = vertexIndex;
-            else if (vertexIndex > maxVertexIndex)
-                maxVertexIndex = vertexIndex;
-        }
+                if (vertexIndex < minVertexIndex)
+                    minVertexIndex = vertexIndex;
+                else if (vertexIndex > maxVertexIndex)
+                    maxVertexIndex = vertexIndex;
+            }
 
-        return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh);
-    };
-})();
+            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh);
+        };
+        return SubMesh;
+    })();
+    BABYLON.SubMesh = SubMesh;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.subMesh.js.map

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

@@ -0,0 +1,142 @@
+module BABYLON {
+    export class SubMesh {
+        public linesIndexCount: number;
+
+        private _mesh: Mesh;
+        private _boundingInfo: BoundingInfo;
+        private _linesIndexBuffer; //ANY
+        public _lastColliderWorldVertices: Vector3[];
+        public _trianglePlanes: Plane[];
+        public _lastColliderTransformMatrix: Matrix;
+
+        constructor(public materialIndex: number, public verticesStart: number, public verticesCount: number, public indexStart, public indexCount: number, mesh: Mesh) {
+            this._mesh = mesh;
+            mesh.subMeshes.push(this);
+
+            this.refreshBoundingInfo();
+        }
+
+        public getBoundingInfo(): BoundingInfo {
+            return this._boundingInfo;
+        }
+
+        public getMesh(): Mesh {
+            return this._mesh;
+        }
+
+        //ANY
+        public getMaterial() {
+            var rootMaterial = this._mesh.material;
+
+            if (rootMaterial && rootMaterial.getSubMaterial) {
+                return rootMaterial.getSubMaterial(this.materialIndex);
+            }
+
+            if (!rootMaterial) {
+                return this._mesh.getScene().defaultMaterial;
+            }
+
+            return rootMaterial;
+        }
+
+        // Methods
+        public refreshBoundingInfo(): void {
+            var data = this._mesh.getVerticesData(VertexBuffer.PositionKind);
+
+            if (!data) {
+                return;
+            }
+
+            var extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
+            this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
+        }
+
+        public _checkCollision(collider: Collider): boolean {
+            return this._boundingInfo._checkCollision(collider);
+        }
+
+        public updateBoundingInfo(world: Matrix, scale: number = 1.0): void {
+            this._boundingInfo._update(world, scale);
+        }
+
+        public isInFrustum(frustumPlanes: Plane[]): boolean {
+            return this._boundingInfo.isInFrustum(frustumPlanes);
+        }
+
+        public render(): void {
+            this._mesh.render(this);
+        }
+
+        //ANY
+        public getLinesIndexBuffer(indices: number[], engine) {
+            if (!this._linesIndexBuffer) {
+                var linesIndices = [];
+
+                for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
+                    linesIndices.push(indices[index], indices[index + 1],
+                        indices[index + 1], indices[index + 2],
+                        indices[index + 2], indices[index]);
+                }
+
+                this._linesIndexBuffer = engine.createIndexBuffer(linesIndices);
+                this.linesIndexCount = linesIndices.length;
+            }
+            return this._linesIndexBuffer;
+        }
+
+        public canIntersects(ray: Ray): boolean {
+            return ray.intersectsBox(this._boundingInfo.boundingBox);
+        }
+
+        //ANY create intersectinfo class
+        public intersects(ray: Ray, positions: Vector3[], indices: number[], fastCheck?: boolean) {
+            var intersectInfo = null;
+
+            // Triangles test
+            for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
+                var p0 = positions[indices[index]];
+                var p1 = positions[indices[index + 1]];
+                var p2 = positions[indices[index + 2]];
+
+                var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
+
+                if (currentIntersectInfo) {
+                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
+                        intersectInfo = currentIntersectInfo;
+                        intersectInfo.faceId = index / 3;
+
+                        if (fastCheck) {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return intersectInfo;
+        }
+
+        // Clone    
+        public clone(newMesh: Mesh): SubMesh {
+            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh);
+        }
+
+        // Statics
+        public static CreateFromIndices(materialIndex: number, startIndex: number, indexCount: number, mesh: Mesh): SubMesh {
+            var minVertexIndex = Number.MAX_VALUE;
+            var maxVertexIndex = -Number.MAX_VALUE;
+
+            var indices = mesh.getIndices();
+
+            for (var index = startIndex; index < startIndex + indexCount; index++) {
+                var vertexIndex = indices[index];
+
+                if (vertexIndex < minVertexIndex)
+                    minVertexIndex = vertexIndex;
+                else if (vertexIndex > maxVertexIndex)
+                    maxVertexIndex = vertexIndex;
+            }
+
+            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh);
+        }
+    }
+}

+ 78 - 77
Babylon/Mesh/babylon.vertexBuffer.js

@@ -1,84 +1,85 @@
-"use strict";
+var BABYLON;
+(function (BABYLON) {
+    var VertexBuffer = (function () {
+        //ANY
+        function VertexBuffer(mesh, data, kind, updatable, engine) {
+            this._mesh = mesh;
+            this._engine = engine || mesh.getScene().getEngine();
+            this._updatable = updatable;
 
-var BABYLON = BABYLON || {};
+            if (updatable) {
+                this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
+                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+            } else {
+                this._buffer = this._engine.createVertexBuffer(data);
+            }
 
-(function () {
-    BABYLON.VertexBuffer = function (mesh, data, kind, updatable, engine) {
-        this._mesh = mesh;
-        this._engine = engine || mesh.getScene().getEngine();
-        this._updatable = updatable;
-        
-        if (updatable) {
-            this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
-            this._engine.updateDynamicVertexBuffer(this._buffer, data);
-        } else {
-            this._buffer = this._engine.createVertexBuffer(data);
+            this._data = data;
+            this._kind = kind;
+
+            switch (kind) {
+                case VertexBuffer.PositionKind:
+                    this._strideSize = 3;
+                    if (this._mesh) {
+                        this._mesh._resetPointsArrayCache();
+                    }
+                    break;
+                case VertexBuffer.NormalKind:
+                    this._strideSize = 3;
+                    break;
+                case VertexBuffer.UVKind:
+                    this._strideSize = 2;
+                    break;
+                case VertexBuffer.UV2Kind:
+                    this._strideSize = 2;
+                    break;
+                case VertexBuffer.ColorKind:
+                    this._strideSize = 3;
+                    break;
+                case VertexBuffer.MatricesIndicesKind:
+                    this._strideSize = 4;
+                    break;
+                case VertexBuffer.MatricesWeightsKind:
+                    this._strideSize = 4;
+                    break;
+            }
         }
+        // Properties
+        VertexBuffer.prototype.isUpdatable = function () {
+            return this._updatable;
+        };
 
-        this._data = data;
-        this._kind = kind;
+        VertexBuffer.prototype.getData = function () {
+            return this._data;
+        };
 
-        switch (kind) {
-            case BABYLON.VertexBuffer.PositionKind:
-                this._strideSize = 3;
-                if (this._mesh) {
-                    this._mesh._resetPointsArrayCache();
-                }
-                break;
-            case BABYLON.VertexBuffer.NormalKind:
-                this._strideSize = 3;
-                break;
-            case BABYLON.VertexBuffer.UVKind:
-                this._strideSize = 2;
-                break;
-            case BABYLON.VertexBuffer.UV2Kind:
-                this._strideSize = 2;
-                break;
-            case BABYLON.VertexBuffer.ColorKind:
-                this._strideSize = 3;
-                break;
-            case BABYLON.VertexBuffer.MatricesIndicesKind:
-                this._strideSize = 4;
-                break;
-            case BABYLON.VertexBuffer.MatricesWeightsKind:
-                this._strideSize = 4;
-                break;
-        }
-    };
-    
-    // Properties
-    BABYLON.VertexBuffer.prototype.isUpdatable = function () {
-        return this._updatable;
-    };
+        VertexBuffer.prototype.getStrideSize = function () {
+            return this._strideSize;
+        };
 
-    BABYLON.VertexBuffer.prototype.getData = function() {
-        return this._data;
-    };
-    
-    BABYLON.VertexBuffer.prototype.getStrideSize = function () {
-        return this._strideSize;
-    };
-    
-    // Methods
-    BABYLON.VertexBuffer.prototype.update = function (data) {
-        this._engine.updateDynamicVertexBuffer(this._buffer, data);
-        this._data = data;
-        
-        if (this._kind === BABYLON.VertexBuffer.PositionKind && this._mesh) {
-            this._mesh._resetPointsArrayCache();
-        }
-    };
+        // Methods
+        VertexBuffer.prototype.update = function (data) {
+            this._engine.updateDynamicVertexBuffer(this._buffer, data);
+            this._data = data;
+
+            if (this._kind === BABYLON.VertexBuffer.PositionKind && this._mesh) {
+                this._mesh._resetPointsArrayCache();
+            }
+        };
+
+        VertexBuffer.prototype.dispose = function () {
+            this._engine._releaseBuffer(this._buffer);
+        };
 
-    BABYLON.VertexBuffer.prototype.dispose = function() {
-        this._engine._releaseBuffer(this._buffer);
-    }; 
-        
-    // Enums
-    BABYLON.VertexBuffer.PositionKind           = "position";
-    BABYLON.VertexBuffer.NormalKind             = "normal";
-    BABYLON.VertexBuffer.UVKind                 = "uv";
-    BABYLON.VertexBuffer.UV2Kind                = "uv2";
-    BABYLON.VertexBuffer.ColorKind              = "color";
-    BABYLON.VertexBuffer.MatricesIndicesKind    = "matricesIndices";
-    BABYLON.VertexBuffer.MatricesWeightsKind    = "matricesWeights";
-})();
+        VertexBuffer.PositionKind = "position";
+        VertexBuffer.NormalKind = "normal";
+        VertexBuffer.UVKind = "uv";
+        VertexBuffer.UV2Kind = "uv2";
+        VertexBuffer.ColorKind = "color";
+        VertexBuffer.MatricesIndicesKind = "matricesIndices";
+        VertexBuffer.MatricesWeightsKind = "matricesWeights";
+        return VertexBuffer;
+    })();
+    BABYLON.VertexBuffer = VertexBuffer;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.vertexBuffer.js.map

+ 91 - 0
Babylon/Mesh/babylon.vertexBuffer.ts

@@ -0,0 +1,91 @@
+module BABYLON {
+    export class VertexBuffer {
+        private _mesh; //ANY
+        private _engine; //ANY
+        private _buffer;
+        private _data: number[];
+        private _updatable: boolean;
+        private _kind: string;
+        private _strideSize: number;
+
+        //ANY
+        constructor(mesh, data: number[], kind: string, updatable: boolean, engine?) {
+            this._mesh = mesh;
+            this._engine = engine || mesh.getScene().getEngine();
+            this._updatable = updatable;
+
+            if (updatable) {
+                this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
+                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+            } else {
+                this._buffer = this._engine.createVertexBuffer(data);
+            }
+
+            this._data = data;
+            this._kind = kind;
+
+            switch (kind) {
+                case VertexBuffer.PositionKind:
+                    this._strideSize = 3;
+                    if (this._mesh) {
+                        this._mesh._resetPointsArrayCache();
+                    }
+                    break;
+                case VertexBuffer.NormalKind:
+                    this._strideSize = 3;
+                    break;
+                case VertexBuffer.UVKind:
+                    this._strideSize = 2;
+                    break;
+                case VertexBuffer.UV2Kind:
+                    this._strideSize = 2;
+                    break;
+                case VertexBuffer.ColorKind:
+                    this._strideSize = 3;
+                    break;
+                case VertexBuffer.MatricesIndicesKind:
+                    this._strideSize = 4;
+                    break;
+                case VertexBuffer.MatricesWeightsKind:
+                    this._strideSize = 4;
+                    break;
+            }
+        }
+
+        // Properties
+        public isUpdatable(): boolean {
+            return this._updatable;
+        }
+
+        public getData(): number[] {
+            return this._data;
+        }
+
+        public getStrideSize(): number {
+            return this._strideSize;
+        }
+
+        // Methods
+        public update(data: number[]): void {
+            this._engine.updateDynamicVertexBuffer(this._buffer, data);
+            this._data = data;
+
+            if (this._kind === BABYLON.VertexBuffer.PositionKind && this._mesh) {
+                this._mesh._resetPointsArrayCache();
+            }
+        }
+
+        public dispose(): void {
+            this._engine._releaseBuffer(this._buffer);
+        }
+
+        // Enums
+        public static PositionKind = "position";
+        public static NormalKind = "normal";
+        public static UVKind = "uv";
+        public static UV2Kind = "uv2";
+        public static ColorKind = "color";
+        public static MatricesIndicesKind = "matricesIndices";
+        public static MatricesWeightsKind = "matricesWeights";
+    }
+} 

+ 222 - 225
Babylon/Physics/babylon.physicsEngine.js

@@ -1,281 +1,278 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.PhysicsEngine = function (gravity, iterations) {
-        this._world = new CANNON.World();
-        this._world.broadphase = new CANNON.NaiveBroadphase();
-        this._world.solver.iterations = iterations;
+var BABYLON;
+(function (BABYLON) {
+    var PhysicsEngine = (function () {
+        function PhysicsEngine(gravity, iterations) {
+            this.gravity = gravity;
+            this._world = new CANNON.World();
+            this._registeredMeshes = [];
+            this._physicsMaterials = [];
+            this._world.broadphase = new CANNON.NaiveBroadphase();
+            this._world.solver.iterations = iterations;
+            this._setGravity(gravity);
+        }
+        PhysicsEngine.prototype._runOneStep = function (delta) {
+            if (delta > 0.1) {
+                delta = 0.1;
+            } else if (delta <= 0) {
+                delta = 1.0 / 60.0;
+            }
 
-        this._registeredMeshes = [];
-        this._physicsMaterials = [];
+            this._world.step(delta);
 
-        this._setGravity(gravity);
-    };
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
 
-    BABYLON.PhysicsEngine.prototype._runOneStep = function (delta) {
-        if (delta > 0.1) {
-            delta = 0.1;
-        } else if (delta <= 0) {
-            delta = 1.0 / 60.0;
-        }
+                if (registeredMesh.isChild) {
+                    continue;
+                }
 
-        this._world.step(delta);
+                registeredMesh.mesh.position.x = registeredMesh.body.position.x;
+                registeredMesh.mesh.position.y = registeredMesh.body.position.z;
+                registeredMesh.mesh.position.z = registeredMesh.body.position.y;
 
-        for (var index = 0; index < this._registeredMeshes.length; index++) {
-            var registeredMesh = this._registeredMeshes[index];
+                if (!registeredMesh.mesh.rotationQuaternion) {
+                    registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+                }
 
-            if (registeredMesh.isChild) {
-                continue;
+                registeredMesh.mesh.rotationQuaternion.x = registeredMesh.body.quaternion.x;
+                registeredMesh.mesh.rotationQuaternion.y = registeredMesh.body.quaternion.z;
+                registeredMesh.mesh.rotationQuaternion.z = registeredMesh.body.quaternion.y;
+                registeredMesh.mesh.rotationQuaternion.w = -registeredMesh.body.quaternion.w;
             }
+        };
+
+        PhysicsEngine.prototype._addMaterial = function (friction, restitution) {
+            var index;
+            var mat;
 
-            registeredMesh.mesh.position.x = registeredMesh.body.position.x;
-            registeredMesh.mesh.position.y = registeredMesh.body.position.z;
-            registeredMesh.mesh.position.z = registeredMesh.body.position.y;
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
 
-            if (!registeredMesh.mesh.rotationQuaternion) {
-                registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+                if (mat.friction === friction && mat.restitution === restitution) {
+                    return mat;
+                }
             }
 
-            registeredMesh.mesh.rotationQuaternion.x = registeredMesh.body.quaternion.x;
-            registeredMesh.mesh.rotationQuaternion.y = registeredMesh.body.quaternion.z;
-            registeredMesh.mesh.rotationQuaternion.z = registeredMesh.body.quaternion.y;
-            registeredMesh.mesh.rotationQuaternion.w = -registeredMesh.body.quaternion.w;
-        }
-    };
+            var currentMat = new CANNON.Material();
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
+            this._physicsMaterials.push(currentMat);
 
-    BABYLON.PhysicsEngine.prototype._addMaterial = function (friction, restitution) {
-        var index;
-        var mat;
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
 
-        for (index = 0; index < this._physicsMaterials.length; index++) {
-            mat = this._physicsMaterials[index];
+                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, mat.friction * currentMat.friction, mat.restitution * currentMat.restitution);
+                contactMaterial.contactEquationStiffness = 1e10;
+                contactMaterial.contactEquationRegularizationTime = 10;
 
-            if (mat.friction === friction && mat.restitution === restitution) {
-                return mat;
+                this._world.addContactMaterial(contactMaterial);
             }
-        }
 
-        var currentMat = new CANNON.Material();
-        currentMat.friction = friction;
-        currentMat.restitution = restitution;
-        this._physicsMaterials.push(currentMat);
+            return currentMat;
+        };
 
-        for (index = 0; index < this._physicsMaterials.length; index++) {
-            mat = this._physicsMaterials[index];
+        PhysicsEngine.prototype._setGravity = function (gravity) {
+            this.gravity = gravity || new BABYLON.Vector3(0, -9.82, 0);
+            this._world.gravity.set(this.gravity.x, this.gravity.z, this.gravity.y);
+        };
 
-            var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, mat.friction * currentMat.friction, mat.restitution * currentMat.restitution);
-            contactMaterial.contactEquationStiffness = 1e10;
-            contactMaterial.contactEquationRegularizationTime = 10;
+        PhysicsEngine.prototype._checkWithEpsilon = function (value) {
+            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        };
 
-            this._world.addContactMaterial(contactMaterial);
-        }
+        PhysicsEngine.prototype._registerMesh = function (mesh, options, onlyShape) {
+            var shape = null;
+            var initialRotation;
 
-        return currentMat;
-    };
-
-    BABYLON.PhysicsEngine.prototype._setGravity = function (gravity) {
-        this.gravity = gravity || new BABYLON.Vector3(0, -9.82, 0);
-        this._world.gravity.set(this.gravity.x, this.gravity.z, this.gravity.y);
-    };
-
-    BABYLON.PhysicsEngine.prototype._checkWithEpsilon = function (value) {
-        return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
-    };
-
-    BABYLON.PhysicsEngine.prototype._registerMesh = function (mesh, options, onlyShape) {
-        var shape = null;
-        var initialRotation;
+            if (mesh.rotationQuaternion) {
+                initialRotation = mesh.rotationQuaternion.clone();
+                mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+            }
 
-        if (mesh.rotationQuaternion) {
-            initialRotation = mesh.rotationQuaternion.clone();
-            mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
-        }
+            this._unregisterMesh(mesh);
+
+            mesh.computeWorldMatrix(true);
+
+            switch (options.impostor) {
+                case BABYLON.PhysicsEngine.SphereImpostor:
+                    var bbox = mesh.getBoundingInfo().boundingBox;
+                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
+                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
+                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
+
+                    shape = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
+                    break;
+                case BABYLON.PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min).scale(0.5);
+                    shape = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.z), this._checkWithEpsilon(box.y)));
+                    break;
+                case BABYLON.PhysicsEngine.PlaneImpostor:
+                    shape = new CANNON.Plane();
+                    break;
+                case BABYLON.PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                    var rawFaces = mesh.getIndices();
+
+                    var verts = [], faces = [];
+
+                    mesh.computeWorldMatrix(true);
+
+                    for (var i = 0; i < rawVerts.length; i += 3) {
+                        var transformed = BABYLON.Vector3.Zero();
+
+                        BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
+                        verts.push(new CANNON.Vec3(transformed.x, transformed.z, transformed.y));
+                    }
+
+                    for (var j = 0; j < rawFaces.length; j += 3) {
+                        faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
+                    }
+
+                    // Construct polyhedron
+                    shape = new CANNON.ConvexPolyhedron(verts, faces);
+                    break;
+            }
 
-        this._unregisterMesh(mesh);
-
-        mesh.computeWorldMatrix(true);
-
-        switch (options.impostor) {
-            case BABYLON.PhysicsEngine.SphereImpostor:
-                var bbox = mesh.getBoundingInfo().boundingBox;
-                var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                shape = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
-                break;
-            case BABYLON.PhysicsEngine.BoxImpostor:
-                var bbox = mesh.getBoundingInfo().boundingBox;
-                var min = bbox.minimumWorld;
-                var max = bbox.maximumWorld;
-                var box = max.subtract(min).scale(0.5);
-                shape = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.z), this._checkWithEpsilon(box.y)));
-                break;
-            case BABYLON.PhysicsEngine.PlaneImpostor:
-                shape = new CANNON.Plane();
-                break;
-            case BABYLON.PhysicsEngine.MeshImpostor:
-                var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-                var rawFaces = mesh.getIndices();
-
-                var verts = [], faces = [];
-
-                mesh.computeWorldMatrix(true);
-
-                // Get vertices
-                for (var i = 0; i < rawVerts.length; i += 3) {
-                    var transformed = BABYLON.Vector3.Zero();
-
-                    BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
-                    verts.push(new CANNON.Vec3(transformed.x, transformed.z, transformed.y));
-                }
+            if (onlyShape) {
+                return shape;
+            }
 
-                // Get faces
-                for (var j = 0; j < rawFaces.length; j += 3) {
-                    faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
-                }
+            var material = this._addMaterial(options.friction, options.restitution);
+            var body = new CANNON.RigidBody(options.mass, shape, material);
 
-                // Construct polyhedron
-                shape = new CANNON.ConvexPolyhedron(verts, faces);
-                break;
-        }
+            if (initialRotation) {
+                body.quaternion.x = initialRotation.x;
+                body.quaternion.z = initialRotation.y;
+                body.quaternion.y = initialRotation.z;
+                body.quaternion.w = -initialRotation.w;
+            }
 
-        if (onlyShape) {
-            return shape;
-        }
+            body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
+            this._world.add(body);
 
-        var material = this._addMaterial(options.friction, options.restitution);
-        var body = new CANNON.RigidBody(options.mass, shape, material);
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
 
-        if (initialRotation) {
-            body.quaternion.x = initialRotation.x;
-            body.quaternion.z = initialRotation.y;
-            body.quaternion.y = initialRotation.z;
-            body.quaternion.w = -initialRotation.w;
-        }
+            return body;
+        };
 
-        body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
-        this._world.add(body);
+        PhysicsEngine.prototype._registerCompound = function (options) {
+            var compoundShape = new CANNON.Compound();
+            var initialMesh = options.parts[0].mesh;
+            var initialPosition = initialMesh.position;
 
-        this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
+            for (var index = 0; index < options.parts.length; index++) {
+                var mesh = options.parts[index].mesh;
 
-        return body;
-    };
+                var shape = this._registerMesh(mesh, options.parts[index], true);
 
-    BABYLON.PhysicsEngine.prototype._registerCompound = function (options) {
-        var compoundShape = new CANNON.Compound();
-        var initialMesh = options.parts[0].mesh;
-        var initialPosition = initialMesh.position;
+                if (index == 0) {
+                    compoundShape.addChild(shape, new CANNON.Vec3(0, 0, 0));
+                } else {
+                    compoundShape.addChild(shape, new CANNON.Vec3(mesh.position.x, mesh.position.z, mesh.position.y));
+                }
+            }
 
-        for (var index = 0; index < options.parts.length; index++) {
-            var mesh = options.parts[index].mesh;
+            var material = this._addMaterial(options.friction, options.restitution);
+            var body = new CANNON.RigidBody(options.mass, compoundShape, material);
 
-            var shape = this._registerMesh(mesh, options.parts[index], true);
+            body.position.set(initialPosition.x, initialPosition.z, initialPosition.y);
+            this._world.add(body);
 
-            if (index == 0) { // Parent
-                compoundShape.addChild(shape, new CANNON.Vec3(0, 0, 0));
-            } else {
-                compoundShape.addChild(shape, new CANNON.Vec3(mesh.position.x, mesh.position.z, mesh.position.y));
+            for (index = 0; index < options.parts.length; index++) {
+                mesh = options.parts[index].mesh;
+                this._registeredMeshes.push({ mesh: mesh, body: body, material: material, isChild: index != 0 });
             }
-        }
 
-        var material = this._addMaterial(options.friction, options.restitution);
-        var body = new CANNON.RigidBody(options.mass, compoundShape, material);
+            body.parts = options.parts;
 
-        body.position.set(initialPosition.x, initialPosition.z, initialPosition.y);
-        this._world.add(body);
+            return body;
+        };
 
-        for (var index = 0; index < options.parts.length; index++) {
-            var mesh = options.parts[index].mesh;
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, isChild: index != 0 });
-        }
+        PhysicsEngine.prototype._unbindBody = function (body) {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
 
-        body.parts = options.parts;
+                if (registeredMesh.body === body) {
+                    registeredMesh.body = null;
+                }
+            }
+        };
+
+        PhysicsEngine.prototype._unregisterMesh = function (mesh) {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
 
-        return body;
-    };
+                if (registeredMesh.mesh === mesh) {
+                    // Remove body
+                    if (registeredMesh.body) {
+                        this._world.remove(registeredMesh.body);
 
-    BABYLON.PhysicsEngine.prototype._unbindBody = function (body) {
-        for (var index = 0; index < this._registeredMeshes.length; index++) {
-            var registeredMesh = this._registeredMeshes[index];
+                        this._unbindBody(registeredMesh.body);
+                    }
 
-            if (registeredMesh.body === body) {
-                registeredMesh.body = null;
+                    this._registeredMeshes.splice(index, 1);
+                    return;
+                }
             }
-        }
-    };
+        };
 
-    BABYLON.PhysicsEngine.prototype._unregisterMesh = function (mesh) {
-        for (var index = 0; index < this._registeredMeshes.length; index++) {
-            var registeredMesh = this._registeredMeshes[index];
+        PhysicsEngine.prototype._applyImpulse = function (mesh, force, contactPoint) {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
+            var impulse = new CANNON.Vec3(force.x, force.z, force.y);
 
-            if (registeredMesh.mesh === mesh) {
-                // Remove body
-                if (registeredMesh.body) {
-                    this._world.remove(registeredMesh.body);
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
 
-                    this._unbindBody(registeredMesh.body);
+                if (registeredMesh.mesh === mesh) {
+                    registeredMesh.body.applyImpulse(impulse, worldPoint);
+                    return;
                 }
-
-                this._registeredMeshes.splice(index, 1);
-                return;
             }
-        }
-    };
+        };
 
-    BABYLON.PhysicsEngine.prototype._applyImpulse = function (mesh, force, contactPoint) {
-        var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
-        var impulse = new CANNON.Vec3(force.x, force.z, force.y);
+        PhysicsEngine.prototype._createLink = function (mesh1, mesh2, pivot1, pivot2) {
+            var body1, body2;
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
 
-        for (var index = 0; index < this._registeredMeshes.length; index++) {
-            var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh1) {
+                    body1 = registeredMesh.body;
+                } else if (registeredMesh.mesh === mesh2) {
+                    body2 = registeredMesh.body;
+                }
+            }
 
-            if (registeredMesh.mesh === mesh) {
-                registeredMesh.body.applyImpulse(impulse, worldPoint);
+            if (!body1 || !body2) {
                 return;
             }
-        }
-    };
 
-    BABYLON.PhysicsEngine.prototype._createLink = function (mesh1, mesh2, pivot1, pivot2) {
-        var body1, body2;
-        for (var index = 0; index < this._registeredMeshes.length; index++) {
-            var registeredMesh = this._registeredMeshes[index];
+            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.z, pivot1.y), body2, new CANNON.Vec3(pivot2.x, pivot2.z, pivot2.y));
+            this._world.addConstraint(constraint);
+        };
 
-            if (registeredMesh.mesh === mesh1) {
-                body1 = registeredMesh.body;
-            } else if (registeredMesh.mesh === mesh2) {
-                body2 = registeredMesh.body;
+        PhysicsEngine.prototype.dispose = function () {
+            while (this._registeredMeshes.length) {
+                this._unregisterMesh(this._registeredMeshes[0].mesh);
             }
-        }
-
-        if (!body1 || !body2) {
-            return;
-        }
-
-        var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.z, pivot1.y), body2, new CANNON.Vec3(pivot2.x, pivot2.z, pivot2.y));
-        this._world.addConstraint(constraint);
-    };
-
-    BABYLON.PhysicsEngine.prototype.dispose = function () {
-        while (this._registeredMeshes.length) {
-            this._unregisterMesh(this._registeredMeshes[0].mesh);
-        }
-    };
-
-    // Statics
-    BABYLON.PhysicsEngine.IsSupported = function () {
-        return window.CANNON !== undefined;
-    };
-
-    BABYLON.PhysicsEngine.NoImpostor = 0;
-    BABYLON.PhysicsEngine.SphereImpostor = 1;
-    BABYLON.PhysicsEngine.BoxImpostor = 2;
-    BABYLON.PhysicsEngine.PlaneImpostor = 3;
-    BABYLON.PhysicsEngine.CompoundImpostor = 4;
-    BABYLON.PhysicsEngine.MeshImpostor = 4;
-
-    BABYLON.PhysicsEngine.Epsilon = 0.001;
-})();
+        };
+
+        // Statics
+        PhysicsEngine.IsSupported = function () {
+            return window.CANNON !== undefined;
+        };
+
+        PhysicsEngine.NoImpostor = 0;
+        PhysicsEngine.SphereImpostor = 1;
+        PhysicsEngine.BoxImpostor = 2;
+        PhysicsEngine.PlaneImpostor = 3;
+        PhysicsEngine.CompoundImpostor = 4;
+        PhysicsEngine.MeshImpostor = 4;
+        PhysicsEngine.Epsilon = 0.001;
+        return PhysicsEngine;
+    })();
+    BABYLON.PhysicsEngine = PhysicsEngine;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.physicsEngine.js.map

+ 281 - 0
Babylon/Physics/babylon.physicsEngine.ts

@@ -0,0 +1,281 @@
+module BABYLON {
+    declare var CANNON;
+    declare var window;
+
+    export class PhysicsEngine {
+        private _world = new CANNON.World();
+
+        private _registeredMeshes = [];
+        private _physicsMaterials = [];
+
+        constructor(public gravity: Vector3, iterations: number) {
+            this._world.broadphase = new CANNON.NaiveBroadphase();
+            this._world.solver.iterations = iterations;
+            this._setGravity(gravity);
+        }
+
+        public _runOneStep(delta: number): void {
+            if (delta > 0.1) {
+                delta = 0.1;
+            } else if (delta <= 0) {
+                delta = 1.0 / 60.0;
+            }
+
+            this._world.step(delta);
+
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.isChild) {
+                    continue;
+                }
+
+                registeredMesh.mesh.position.x = registeredMesh.body.position.x;
+                registeredMesh.mesh.position.y = registeredMesh.body.position.z;
+                registeredMesh.mesh.position.z = registeredMesh.body.position.y;
+
+                if (!registeredMesh.mesh.rotationQuaternion) {
+                    registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+                }
+
+                registeredMesh.mesh.rotationQuaternion.x = registeredMesh.body.quaternion.x;
+                registeredMesh.mesh.rotationQuaternion.y = registeredMesh.body.quaternion.z;
+                registeredMesh.mesh.rotationQuaternion.z = registeredMesh.body.quaternion.y;
+                registeredMesh.mesh.rotationQuaternion.w = -registeredMesh.body.quaternion.w;
+            }
+        }
+
+        public _addMaterial(friction: number, restitution: number) {
+            var index;
+            var mat;
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+
+                if (mat.friction === friction && mat.restitution === restitution) {
+                    return mat;
+                }
+            }
+
+            var currentMat = new CANNON.Material();
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
+            this._physicsMaterials.push(currentMat);
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+
+                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, mat.friction * currentMat.friction, mat.restitution * currentMat.restitution);
+                contactMaterial.contactEquationStiffness = 1e10;
+                contactMaterial.contactEquationRegularizationTime = 10;
+
+                this._world.addContactMaterial(contactMaterial);
+            }
+
+            return currentMat;
+        }
+
+        public _setGravity(gravity: Vector3): void {
+            this.gravity = gravity || new BABYLON.Vector3(0, -9.82, 0);
+            this._world.gravity.set(this.gravity.x, this.gravity.z, this.gravity.y);
+        }
+
+        public _checkWithEpsilon(value: number): number {
+            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        }
+
+        public _registerMesh(mesh: Mesh, options, onlyShape?: boolean): void {
+            var shape = null;
+            var initialRotation;
+
+            if (mesh.rotationQuaternion) {
+                initialRotation = mesh.rotationQuaternion.clone();
+                mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+            }
+
+            this._unregisterMesh(mesh);
+
+            mesh.computeWorldMatrix(true);
+
+            switch (options.impostor) {
+                case BABYLON.PhysicsEngine.SphereImpostor:
+                    var bbox = mesh.getBoundingInfo().boundingBox;
+                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
+                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
+                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
+
+                    shape = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
+                    break;
+                case BABYLON.PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min).scale(0.5);
+                    shape = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.z), this._checkWithEpsilon(box.y)));
+                    break;
+                case BABYLON.PhysicsEngine.PlaneImpostor:
+                    shape = new CANNON.Plane();
+                    break;
+                case BABYLON.PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                    var rawFaces = mesh.getIndices();
+
+                    var verts = [], faces = [];
+
+                    mesh.computeWorldMatrix(true);
+
+                    // Get vertices
+                    for (var i = 0; i < rawVerts.length; i += 3) {
+                        var transformed = BABYLON.Vector3.Zero();
+
+                        BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
+                        verts.push(new CANNON.Vec3(transformed.x, transformed.z, transformed.y));
+                    }
+
+                    // Get faces
+                    for (var j = 0; j < rawFaces.length; j += 3) {
+                        faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
+                    }
+
+                    // Construct polyhedron
+                    shape = new CANNON.ConvexPolyhedron(verts, faces);
+                    break;
+            }
+
+            if (onlyShape) {
+                return shape;
+            }
+
+            var material = this._addMaterial(options.friction, options.restitution);
+            var body = new CANNON.RigidBody(options.mass, shape, material);
+
+            if (initialRotation) {
+                body.quaternion.x = initialRotation.x;
+                body.quaternion.z = initialRotation.y;
+                body.quaternion.y = initialRotation.z;
+                body.quaternion.w = -initialRotation.w;
+            }
+
+            body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
+            this._world.add(body);
+
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
+
+            return body;
+        }
+
+        public _registerCompound(options): void {
+            var compoundShape = new CANNON.Compound();
+            var initialMesh = options.parts[0].mesh;
+            var initialPosition = initialMesh.position;
+
+            for (var index = 0; index < options.parts.length; index++) {
+                var mesh = options.parts[index].mesh;
+
+                var shape = this._registerMesh(mesh, options.parts[index], true);
+
+                if (index == 0) { // Parent
+                    compoundShape.addChild(shape, new CANNON.Vec3(0, 0, 0));
+                } else {
+                    compoundShape.addChild(shape, new CANNON.Vec3(mesh.position.x, mesh.position.z, mesh.position.y));
+                }
+            }
+
+            var material = this._addMaterial(options.friction, options.restitution);
+            var body = new CANNON.RigidBody(options.mass, compoundShape, material);
+
+            body.position.set(initialPosition.x, initialPosition.z, initialPosition.y);
+            this._world.add(body);
+
+            for (index = 0; index < options.parts.length; index++) {
+                mesh = options.parts[index].mesh;
+                this._registeredMeshes.push({ mesh: mesh, body: body, material: material, isChild: index != 0 });
+            }
+
+            body.parts = options.parts;
+
+            return body;
+        }
+
+        public _unbindBody(body): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.body === body) {
+                    registeredMesh.body = null;
+                }
+            }
+        }
+
+        public _unregisterMesh(mesh: Mesh): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh) {
+                    // Remove body
+                    if (registeredMesh.body) {
+                        this._world.remove(registeredMesh.body);
+
+                        this._unbindBody(registeredMesh.body);
+                    }
+
+                    this._registeredMeshes.splice(index, 1);
+                    return;
+                }
+            }
+        }
+
+        public _applyImpulse(mesh: Mesh, force: Vector3, contactPoint: Vector3): void {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
+            var impulse = new CANNON.Vec3(force.x, force.z, force.y);
+
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh) {
+                    registeredMesh.body.applyImpulse(impulse, worldPoint);
+                    return;
+                }
+            }
+        }
+
+        public _createLink(mesh1: Mesh, mesh2: Mesh, pivot1: Vector3, pivot2: Vector3): void {
+            var body1, body2;
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh1) {
+                    body1 = registeredMesh.body;
+                } else if (registeredMesh.mesh === mesh2) {
+                    body2 = registeredMesh.body;
+                }
+            }
+
+            if (!body1 || !body2) {
+                return;
+            }
+
+            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.z, pivot1.y), body2, new CANNON.Vec3(pivot2.x, pivot2.z, pivot2.y));
+            this._world.addConstraint(constraint);
+        }
+
+        public dispose(): void {
+            while (this._registeredMeshes.length) {
+                this._unregisterMesh(this._registeredMeshes[0].mesh);
+            }
+        }
+
+        // Statics
+        public static IsSupported(): boolean {
+            return window.CANNON !== undefined;
+        }
+
+        public static NoImpostor = 0;
+        public static SphereImpostor = 1;
+        public static BoxImpostor = 2;
+        public static PlaneImpostor = 3;
+        public static CompoundImpostor = 4;
+        public static MeshImpostor = 4;
+        public static Epsilon = 0.001;
+    }
+}

+ 19 - 12
Babylon/PostProcess/babylon.anaglyphPostProcess.js

@@ -1,12 +1,19 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.AnaglyphPostProcess = function (name, ratio, camera, samplingMode, engine, reusable) {
-        BABYLON.PostProcess.call(this, name, "anaglyph", null, ["leftSampler"], ratio, camera, samplingMode, engine, reusable);
-    };
-
-    BABYLON.AnaglyphPostProcess.prototype = Object.create(BABYLON.PostProcess.prototype);
-
-})();
+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 AnaglyphPostProcess = (function (_super) {
+        __extends(AnaglyphPostProcess, _super);
+        //ANY
+        function AnaglyphPostProcess(name, ratio, camera, samplingMode, engine, reusable) {
+            _super.call(this, name, "anaglyph", null, ["leftSampler"], ratio, camera, samplingMode, engine, reusable);
+        }
+        return AnaglyphPostProcess;
+    })(BABYLON.PostProcess);
+    BABYLON.AnaglyphPostProcess = AnaglyphPostProcess;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.anaglyphPostProcess.js.map

+ 8 - 0
Babylon/PostProcess/babylon.anaglyphPostProcess.ts

@@ -0,0 +1,8 @@
+module BABYLON {
+    export class AnaglyphPostProcess extends PostProcess {
+        //ANY
+        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?, reusable?: boolean) {
+            super(name, "anaglyph", null, ["leftSampler"], ratio, camera, samplingMode, engine, reusable);
+        }
+    }
+} 

+ 19 - 12
Babylon/PostProcess/babylon.passPostProcess.js

@@ -1,12 +1,19 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.PassPostProcess = function (name, ratio, camera, samplingMode, engine, reusable) {
-        BABYLON.PostProcess.call(this, name, "pass", null, null, ratio, camera, samplingMode, engine, reusable);
-    };
-    
-    BABYLON.PassPostProcess.prototype = Object.create(BABYLON.PostProcess.prototype);
-
-})();
+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 PassPostProcess = (function (_super) {
+        __extends(PassPostProcess, _super);
+        //ANY
+        function PassPostProcess(name, ratio, camera, samplingMode, engine, reusable) {
+            _super.call(this, name, "pass", null, null, ratio, camera, samplingMode, engine, reusable);
+        }
+        return PassPostProcess;
+    })(BABYLON.PostProcess);
+    BABYLON.PassPostProcess = PassPostProcess;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.passPostProcess.js.map

+ 8 - 0
Babylon/PostProcess/babylon.passPostProcess.ts

@@ -0,0 +1,8 @@
+module BABYLON {
+    export class PassPostProcess extends PostProcess {
+        //ANY
+        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?, reusable?: boolean) {
+            super(name, "pass", null, null, ratio, camera, samplingMode, engine, reusable);
+        }
+    }
+} 

+ 104 - 109
Babylon/PostProcess/babylon.postProcess.js

@@ -1,127 +1,122 @@
-"use strict";
+var BABYLON;
+(function (BABYLON) {
+    var PostProcess = (function () {
+        //ANY
+        function PostProcess(name, fragmentUrl, parameters, samplers, ratio, camera, samplingMode, engine, reusable) {
+            this.name = name;
+            this.onApply = null;
+            this.onSizeChanged = null;
+            this.onActivate = null;
+            this.width = -1;
+            this.height = -1;
+            this._onDispose = null;
+            this._reusable = false;
+            this._textures = new BABYLON.SmartArray(2);
+            this._currentRenderTextureInd = 0;
+            if (camera != null) {
+                this._camera = camera;
+                this._scene = camera.getScene();
+                camera.attachPostProcess(this);
+                this._engine = this._scene.getEngine();
+            } else {
+                this._engine = engine;
+            }
 
-var BABYLON = BABYLON || {};
+            this._renderRatio = ratio;
+            this.renderTargetSamplingMode = samplingMode ? samplingMode : 1; //ANY BABYLON.Texture.NEAREST_SAMPLINGMODE;
+            this._reusable = reusable || false;
 
-(function () {
-    BABYLON.PostProcess = function (name, fragmentUrl, parameters, samplers, ratio, camera, samplingMode, engine, reusable) {
-        this.name = name;
+            samplers = samplers || [];
+            samplers.push("textureSampler");
 
-        if (camera != null) {
-            this._camera = camera;
-            this._scene = camera.getScene();
-            camera.attachPostProcess(this);
-            this._engine = this._scene.getEngine();
-        }
-        else {
-            this._engine = engine;
+            this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: fragmentUrl }, ["position"], parameters || [], samplers, "");
         }
-
-        this._renderRatio = ratio;
-        this.width = -1;
-        this.height = -1;
-        this.renderTargetSamplingMode = samplingMode ? samplingMode : BABYLON.Texture.NEAREST_SAMPLINGMODE;
-        this._reusable = reusable || false;
-
-        this._textures = new BABYLON.SmartArray(2);
-        this._currentRenderTextureInd = 0;
-
-        samplers = samplers || [];
-        samplers.push("textureSampler");
-
-        this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: fragmentUrl },
-            ["position"],
-            parameters || [],
-            samplers, "");
-    };
-    
-    // Methods
-    BABYLON.PostProcess.prototype.onApply = null;
-    BABYLON.PostProcess.prototype._onDispose = null;
-    BABYLON.PostProcess.prototype.onSizeChanged = null;
-    BABYLON.PostProcess.prototype.onActivate = null;
-    BABYLON.PostProcess.prototype.activate = function (camera) {
-        camera = camera || this._camera;
-
-        var scene = camera.getScene();
-        var desiredWidth = this._engine._renderingCanvas.width * this._renderRatio;
-        var desiredHeight = this._engine._renderingCanvas.height * this._renderRatio;
-        if (this.width !== desiredWidth || this.height !== desiredHeight) {
-            if (this._textures.length > 0) {
-                for (var i = 0; i < this._textures.length; i++) {
-                    this._engine._releaseTexture(this._textures.data[i]);
+        // Methods
+        PostProcess.prototype.activate = function (camera) {
+            camera = camera || this._camera;
+
+            var scene = camera.getScene();
+            var desiredWidth = this._engine._renderingCanvas.width * this._renderRatio;
+            var desiredHeight = this._engine._renderingCanvas.height * this._renderRatio;
+            if (this.width !== desiredWidth || this.height !== desiredHeight) {
+                if (this._textures.length > 0) {
+                    for (var i = 0; i < this._textures.length; i++) {
+                        this._engine._releaseTexture(this._textures.data[i]);
+                    }
+                    this._textures.reset();
                 }
-                this._textures.reset();
-            }
-            this.width = desiredWidth;
-            this.height = desiredHeight;
-            this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode }));
-
-            if (this._reusable) {
+                this.width = desiredWidth;
+                this.height = desiredHeight;
                 this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode }));
-            }
 
-            if (this.onSizeChanged) {
-                this.onSizeChanged();
+                if (this._reusable) {
+                    this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode }));
+                }
+
+                if (this.onSizeChanged) {
+                    this.onSizeChanged();
+                }
             }
 
-        }
+            this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
 
-        this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
-        
-        if (this.onActivate) {
-            this.onActivate(camera);
-        }
+            if (this.onActivate) {
+                this.onActivate(camera);
+            }
 
-        // Clear
-        this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
+            // Clear
+            this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
 
-        if (this._reusable) {
-            this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;
-        }
-    };
-
-    BABYLON.PostProcess.prototype.apply = function () {
-        // Check
-        if (!this._effect.isReady())
-            return null;
-
-        // States
-        this._engine.enableEffect(this._effect);
-        this._engine.setState(false);
-        this._engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
-        this._engine.setDepthBuffer(false);
-        this._engine.setDepthWrite(false);
-
-        // Texture
-        this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
-        
-        // Parameters
-        if (this.onApply) {
-            this.onApply(this._effect);
-        }
+            if (this._reusable) {
+                this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;
+            }
+        };
+
+        PostProcess.prototype.apply = function () {
+            // Check
+            if (!this._effect.isReady())
+                return null;
+
+            // States
+            this._engine.enableEffect(this._effect);
+            this._engine.setState(false);
+            this._engine.setAlphaMode(0); //ANY BABYLON.Engine.ALPHA_DISABLE);
+            this._engine.setDepthBuffer(false);
+            this._engine.setDepthWrite(false);
+
+            // Texture
+            this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
+
+            // Parameters
+            if (this.onApply) {
+                this.onApply(this._effect);
+            }
 
-        return this._effect;
-    };
+            return this._effect;
+        };
 
-    BABYLON.PostProcess.prototype.dispose = function (camera) {
-        camera = camera || this._camera;
+        PostProcess.prototype.dispose = function (camera) {
+            camera = camera || this._camera;
 
-        if (this._onDispose) {
-            this._onDispose();
-        }
-        if (this._textures.length > 0) {
-            for (var i = 0; i < this._textures.length; i++) {
-                this._engine._releaseTexture(this._textures.data[i]);
+            if (this._onDispose) {
+                this._onDispose();
+            }
+            if (this._textures.length > 0) {
+                for (var i = 0; i < this._textures.length; i++) {
+                    this._engine._releaseTexture(this._textures.data[i]);
+                }
+                this._textures.reset();
             }
-            this._textures.reset();
-        }
-        
-        camera.detachPostProcess(this);
 
-        var index = camera._postProcesses.indexOf(this);
-        if (index === camera._postProcessesTakenIndices[0] && camera._postProcessesTakenIndices.length > 0) {
-            this._camera._postProcesses[camera._postProcessesTakenIndices[0]].width = -1; // invalidate frameBuffer to hint the postprocess to create a depth buffer
-        }
-    };
+            camera.detachPostProcess(this);
 
-})();
+            var index = camera._postProcesses.indexOf(this);
+            if (index === camera._postProcessesTakenIndices[0] && camera._postProcessesTakenIndices.length > 0) {
+                this._camera._postProcesses[camera._postProcessesTakenIndices[0]].width = -1; // invalidate frameBuffer to hint the postprocess to create a depth buffer
+            }
+        };
+        return PostProcess;
+    })();
+    BABYLON.PostProcess = PostProcess;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.postProcess.js.map

+ 132 - 0
Babylon/PostProcess/babylon.postProcess.ts

@@ -0,0 +1,132 @@
+module BABYLON {
+    export class PostProcess {
+        public onApply = null;
+        public onSizeChanged = null;
+        public onActivate = null;
+        public width = -1;
+        public height = -1;
+        public renderTargetSamplingMode: number;
+
+        private _onDispose = null;
+        private _camera: Camera;
+        private _scene; //ANY
+        private _engine; //ANY
+        private _renderRatio: number;
+        private _reusable = false;
+        private _textures = new BABYLON.SmartArray(2);
+        private _currentRenderTextureInd = 0;
+        private _effect; //ANY
+
+        //ANY
+        constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], ratio: number, camera: Camera, samplingMode: number, engine, reusable?: boolean) {
+            if (camera != null) {
+                this._camera = camera;
+                this._scene = camera.getScene();
+                camera.attachPostProcess(this);
+                this._engine = this._scene.getEngine();
+            }
+            else {
+                this._engine = engine;
+            }
+
+            this._renderRatio = ratio;
+            this.renderTargetSamplingMode = samplingMode ? samplingMode : 1; //ANY BABYLON.Texture.NEAREST_SAMPLINGMODE;
+            this._reusable = reusable || false;
+
+            samplers = samplers || [];
+            samplers.push("textureSampler");
+
+            this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: fragmentUrl },
+                ["position"],
+                parameters || [],
+                samplers, "");
+        }
+
+        // Methods
+
+        public activate(camera: Camera): void {
+            camera = camera || this._camera;
+
+            var scene = camera.getScene();
+            var desiredWidth = this._engine._renderingCanvas.width * this._renderRatio;
+            var desiredHeight = this._engine._renderingCanvas.height * this._renderRatio;
+            if (this.width !== desiredWidth || this.height !== desiredHeight) {
+                if (this._textures.length > 0) {
+                    for (var i = 0; i < this._textures.length; i++) {
+                        this._engine._releaseTexture(this._textures.data[i]);
+                    }
+                    this._textures.reset();
+                }
+                this.width = desiredWidth;
+                this.height = desiredHeight;
+                this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode }));
+
+                if (this._reusable) {
+                    this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode }));
+                }
+
+                if (this.onSizeChanged) {
+                    this.onSizeChanged();
+                }
+
+            }
+
+            this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
+
+            if (this.onActivate) {
+                this.onActivate(camera);
+            }
+
+            // Clear
+            this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
+
+            if (this._reusable) {
+                this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;
+            }
+        }
+
+        public apply(): void {
+            // Check
+            if (!this._effect.isReady())
+                return null;
+
+            // States
+            this._engine.enableEffect(this._effect);
+            this._engine.setState(false);
+            this._engine.setAlphaMode(0); //ANY BABYLON.Engine.ALPHA_DISABLE);
+            this._engine.setDepthBuffer(false);
+            this._engine.setDepthWrite(false);
+
+            // Texture
+            this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
+
+            // Parameters
+            if (this.onApply) {
+                this.onApply(this._effect);
+            }
+
+            return this._effect;
+        }
+
+        public dispose(camera: Camera): void {
+            camera = camera || this._camera;
+
+            if (this._onDispose) {
+                this._onDispose();
+            }
+            if (this._textures.length > 0) {
+                for (var i = 0; i < this._textures.length; i++) {
+                    this._engine._releaseTexture(this._textures.data[i]);
+                }
+                this._textures.reset();
+            }
+
+            camera.detachPostProcess(this);
+
+            var index = camera._postProcesses.indexOf(this);
+            if (index === camera._postProcessesTakenIndices[0] && camera._postProcessesTakenIndices.length > 0) {
+                this._camera._postProcesses[camera._postProcessesTakenIndices[0]].width = -1; // invalidate frameBuffer to hint the postprocess to create a depth buffer
+            }
+        }
+    }
+} 

+ 110 - 139
Babylon/Tools/babylon.tools.dds.js

@@ -1,147 +1,118 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.Tools = BABYLON.Tools|| {};
-
-    // Based on demo done by Brandon Jones - http://media.tojicode.com/webgl-samples/dds.html
-    // All values and structures referenced from:
-    // http://msdn.microsoft.com/en-us/library/bb943991.aspx/
-    var DDS_MAGIC = 0x20534444;
-
-    var DDSD_CAPS = 0x1,
-        DDSD_HEIGHT = 0x2,
-        DDSD_WIDTH = 0x4,
-        DDSD_PITCH = 0x8,
-        DDSD_PIXELFORMAT = 0x1000,
-        DDSD_MIPMAPCOUNT = 0x20000,
-        DDSD_LINEARSIZE = 0x80000,
-        DDSD_DEPTH = 0x800000;
-
-    var DDSCAPS_COMPLEX = 0x8,
-        DDSCAPS_MIPMAP = 0x400000,
-        DDSCAPS_TEXTURE = 0x1000;
-
-    var DDSCAPS2_CUBEMAP = 0x200,
-        DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
-        DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
-        DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
-        DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
-        DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
-        DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
-        DDSCAPS2_VOLUME = 0x200000;
-
-    var DDPF_ALPHAPIXELS = 0x1,
-        DDPF_ALPHA = 0x2,
-        DDPF_FOURCC = 0x4,
-        DDPF_RGB = 0x40,
-        DDPF_YUV = 0x200,
-        DDPF_LUMINANCE = 0x20000;
-
-    function FourCCToInt32(value) {
-        return value.charCodeAt(0) +
-            (value.charCodeAt(1) << 8) +
-            (value.charCodeAt(2) << 16) +
-            (value.charCodeAt(3) << 24);
-    }
-
-    function Int32ToFourCC(value) {
-        return String.fromCharCode(
-            value & 0xff,
-            (value >> 8) & 0xff,
-            (value >> 16) & 0xff,
-            (value >> 24) & 0xff
-        );
-    }
-
-    var FOURCC_DXT1 = FourCCToInt32("DXT1");
-    var FOURCC_DXT3 = FourCCToInt32("DXT3");
-    var FOURCC_DXT5 = FourCCToInt32("DXT5");
-
-    var headerLengthInt = 31; // The header length in 32 bit ints
-
-    // Offsets into the header array
-    var off_magic = 0;
-
-    var off_size = 1;
-    var off_flags = 2;
-    var off_height = 3;
-    var off_width = 4;
-
-    var off_mipmapCount = 7;
-
-    var off_pfFlags = 20;
-    var off_pfFourCC = 21;
-
-
-    BABYLON.Tools.GetDDSInfo = function (arrayBuffer) {
-        var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
-
-        var mipmapCount = 1;
-        if (header[off_flags] & DDSD_MIPMAPCOUNT) {
-            mipmapCount = Math.max(1, header[off_mipmapCount]);
-        }
+var BABYLON;
+(function (BABYLON) {
+    (function (Internals) {
+        // Based on demo done by Brandon Jones - http://media.tojicode.com/webgl-samples/dds.html
+        // All values and structures referenced from:
+        // http://msdn.microsoft.com/en-us/library/bb943991.aspx/
+        var DDS_MAGIC = 0x20534444;
 
-        return {
-            width: header[off_width],
-            height: header[off_height],
-            mipmapCount: mipmapCount
-        };
-    };
-
-    BABYLON.Tools.UploadDDSLevels = function (gl, ext, arrayBuffer, loadMipmaps) {
-        var header = new Int32Array(arrayBuffer, 0, headerLengthInt),
-            fourCC, blockBytes, internalFormat,
-            width, height, dataLength, dataOffset,
-            byteArray, mipmapCount, i;
-
-        if (header[off_magic] != DDS_MAGIC) {
-            console.error("Invalid magic number in DDS header");
-            return;
-        }
+        var DDSD_CAPS = 0x1, DDSD_HEIGHT = 0x2, DDSD_WIDTH = 0x4, DDSD_PITCH = 0x8, DDSD_PIXELFORMAT = 0x1000, DDSD_MIPMAPCOUNT = 0x20000, DDSD_LINEARSIZE = 0x80000, DDSD_DEPTH = 0x800000;
 
-        if (!header[off_pfFlags] & DDPF_FOURCC) {
-            console.error("Unsupported format, must contain a FourCC code");
-            return;
-        }
+        var DDSCAPS_COMPLEX = 0x8, DDSCAPS_MIPMAP = 0x400000, DDSCAPS_TEXTURE = 0x1000;
 
-        fourCC = header[off_pfFourCC];
-        switch (fourCC) {
-            case FOURCC_DXT1:
-                blockBytes = 8;
-                internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
-                break;
-            case FOURCC_DXT3:
-                blockBytes = 16;
-                internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;
-                break;
-            case FOURCC_DXT5:
-                blockBytes = 16;
-                internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
-                break;
-            default:
-                console.error("Unsupported FourCC code:", Int32ToFourCC(fourCC));
-                return;
-        }
+        var DDSCAPS2_CUBEMAP = 0x200, DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, DDSCAPS2_VOLUME = 0x200000;
+
+        var DDPF_ALPHAPIXELS = 0x1, DDPF_ALPHA = 0x2, DDPF_FOURCC = 0x4, DDPF_RGB = 0x40, DDPF_YUV = 0x200, DDPF_LUMINANCE = 0x20000;
 
-        mipmapCount = 1;
-        if (header[off_flags] & DDSD_MIPMAPCOUNT && loadMipmaps !== false) {
-            mipmapCount = Math.max(1, header[off_mipmapCount]);
+        function FourCCToInt32(value) {
+            return value.charCodeAt(0) + (value.charCodeAt(1) << 8) + (value.charCodeAt(2) << 16) + (value.charCodeAt(3) << 24);
         }
 
-        width = header[off_width];
-        height = header[off_height];
-        dataOffset = header[off_size] + 4;
-
-        for (i = 0; i < mipmapCount; ++i) {
-            dataLength = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes;
-            byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength);
-            gl.compressedTexImage2D(gl.TEXTURE_2D, i, internalFormat, width, height, 0, byteArray);
-            dataOffset += dataLength;
-            width *= 0.5;
-            height *= 0.5;
+        function Int32ToFourCC(value) {
+            return String.fromCharCode(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, (value >> 24) & 0xff);
         }
-    };
 
-})();
+        var FOURCC_DXT1 = FourCCToInt32("DXT1");
+        var FOURCC_DXT3 = FourCCToInt32("DXT3");
+        var FOURCC_DXT5 = FourCCToInt32("DXT5");
+
+        var headerLengthInt = 31;
+
+        // Offsets into the header array
+        var off_magic = 0;
+
+        var off_size = 1;
+        var off_flags = 2;
+        var off_height = 3;
+        var off_width = 4;
+
+        var off_mipmapCount = 7;
+
+        var off_pfFlags = 20;
+        var off_pfFourCC = 21;
+
+        var DDSTools = (function () {
+            function DDSTools() {
+            }
+            DDSTools.GetDDSInfo = function (arrayBuffer) {
+                var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
+
+                var mipmapCount = 1;
+                if (header[off_flags] & DDSD_MIPMAPCOUNT) {
+                    mipmapCount = Math.max(1, header[off_mipmapCount]);
+                }
+
+                return {
+                    width: header[off_width],
+                    height: header[off_height],
+                    mipmapCount: mipmapCount
+                };
+            };
+
+            DDSTools.UploadDDSLevels = function (gl, ext, arrayBuffer, loadMipmaps) {
+                var header = new Int32Array(arrayBuffer, 0, headerLengthInt), fourCC, blockBytes, internalFormat, width, height, dataLength, dataOffset, byteArray, mipmapCount, i;
+
+                if (header[off_magic] != DDS_MAGIC) {
+                    console.error("Invalid magic number in DDS header");
+                    return;
+                }
+
+                if ((header[off_pfFlags] & DDPF_FOURCC) !== DDPF_FOURCC) {
+                    console.error("Unsupported format, must contain a FourCC code");
+                    return;
+                }
+
+                fourCC = header[off_pfFourCC];
+                switch (fourCC) {
+                    case FOURCC_DXT1:
+                        blockBytes = 8;
+                        internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+                        break;
+                    case FOURCC_DXT3:
+                        blockBytes = 16;
+                        internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;
+                        break;
+                    case FOURCC_DXT5:
+                        blockBytes = 16;
+                        internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+                        break;
+                    default:
+                        console.error("Unsupported FourCC code:", Int32ToFourCC(fourCC));
+                        return;
+                }
+
+                mipmapCount = 1;
+                if (header[off_flags] & DDSD_MIPMAPCOUNT && loadMipmaps !== false) {
+                    mipmapCount = Math.max(1, header[off_mipmapCount]);
+                }
+
+                width = header[off_width];
+                height = header[off_height];
+                dataOffset = header[off_size] + 4;
+
+                for (i = 0; i < mipmapCount; ++i) {
+                    dataLength = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes;
+                    byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength);
+                    gl.compressedTexImage2D(gl.TEXTURE_2D, i, internalFormat, width, height, 0, byteArray);
+                    dataOffset += dataLength;
+                    width *= 0.5;
+                    height *= 0.5;
+                }
+            };
+            return DDSTools;
+        })();
+        Internals.DDSTools = DDSTools;
+    })(BABYLON.Internals || (BABYLON.Internals = {}));
+    var Internals = BABYLON.Internals;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.tools.dds.js.map

+ 141 - 0
Babylon/Tools/babylon.tools.dds.ts

@@ -0,0 +1,141 @@
+module BABYLON.Internals {
+    // Based on demo done by Brandon Jones - http://media.tojicode.com/webgl-samples/dds.html
+    // All values and structures referenced from:
+    // http://msdn.microsoft.com/en-us/library/bb943991.aspx/
+    var DDS_MAGIC = 0x20534444;
+
+    var DDSD_CAPS = 0x1,
+        DDSD_HEIGHT = 0x2,
+        DDSD_WIDTH = 0x4,
+        DDSD_PITCH = 0x8,
+        DDSD_PIXELFORMAT = 0x1000,
+        DDSD_MIPMAPCOUNT = 0x20000,
+        DDSD_LINEARSIZE = 0x80000,
+        DDSD_DEPTH = 0x800000;
+
+    var DDSCAPS_COMPLEX = 0x8,
+        DDSCAPS_MIPMAP = 0x400000,
+        DDSCAPS_TEXTURE = 0x1000;
+
+    var DDSCAPS2_CUBEMAP = 0x200,
+        DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
+        DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
+        DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
+        DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
+        DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
+        DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
+        DDSCAPS2_VOLUME = 0x200000;
+
+    var DDPF_ALPHAPIXELS = 0x1,
+        DDPF_ALPHA = 0x2,
+        DDPF_FOURCC = 0x4,
+        DDPF_RGB = 0x40,
+        DDPF_YUV = 0x200,
+        DDPF_LUMINANCE = 0x20000;
+
+    function FourCCToInt32(value) {
+        return value.charCodeAt(0) +
+            (value.charCodeAt(1) << 8) +
+            (value.charCodeAt(2) << 16) +
+            (value.charCodeAt(3) << 24);
+    }
+
+    function Int32ToFourCC(value) {
+        return String.fromCharCode(
+            value & 0xff,
+            (value >> 8) & 0xff,
+            (value >> 16) & 0xff,
+            (value >> 24) & 0xff
+            );
+    }
+
+    var FOURCC_DXT1 = FourCCToInt32("DXT1");
+    var FOURCC_DXT3 = FourCCToInt32("DXT3");
+    var FOURCC_DXT5 = FourCCToInt32("DXT5");
+
+    var headerLengthInt = 31; // The header length in 32 bit ints
+
+    // Offsets into the header array
+    var off_magic = 0;
+
+    var off_size = 1;
+    var off_flags = 2;
+    var off_height = 3;
+    var off_width = 4;
+
+    var off_mipmapCount = 7;
+
+    var off_pfFlags = 20;
+    var off_pfFourCC = 21;
+
+    export class DDSTools {
+        public static GetDDSInfo(arrayBuffer): { width: number; height: number; mipmapCount: number } {
+            var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
+
+            var mipmapCount = 1;
+            if (header[off_flags] & DDSD_MIPMAPCOUNT) {
+                mipmapCount = Math.max(1, header[off_mipmapCount]);
+            }
+
+            return {
+                width: header[off_width],
+                height: header[off_height],
+                mipmapCount: mipmapCount
+            };
+        }
+
+        public static UploadDDSLevels(gl, ext, arrayBuffer, loadMipmaps?: boolean): void {
+            var header = new Int32Array(arrayBuffer, 0, headerLengthInt),
+                fourCC, blockBytes, internalFormat,
+                width, height, dataLength, dataOffset,
+                byteArray, mipmapCount, i;
+
+            if (header[off_magic] != DDS_MAGIC) {
+                console.error("Invalid magic number in DDS header");
+                return;
+            }
+
+            if ((header[off_pfFlags] & DDPF_FOURCC) !== DDPF_FOURCC) {
+                console.error("Unsupported format, must contain a FourCC code");
+                return;
+            }
+
+            fourCC = header[off_pfFourCC];
+            switch (fourCC) {
+                case FOURCC_DXT1:
+                    blockBytes = 8;
+                    internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+                    break;
+                case FOURCC_DXT3:
+                    blockBytes = 16;
+                    internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;
+                    break;
+                case FOURCC_DXT5:
+                    blockBytes = 16;
+                    internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+                    break;
+                default:
+                    console.error("Unsupported FourCC code:", Int32ToFourCC(fourCC));
+                    return;
+            }
+
+            mipmapCount = 1;
+            if (header[off_flags] & DDSD_MIPMAPCOUNT && loadMipmaps !== false) {
+                mipmapCount = Math.max(1, header[off_mipmapCount]);
+            }
+
+            width = header[off_width];
+            height = header[off_height];
+            dataOffset = header[off_size] + 4;
+
+            for (i = 0; i < mipmapCount; ++i) {
+                dataLength = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes;
+                byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength);
+                gl.compressedTexImage2D(gl.TEXTURE_2D, i, internalFormat, width, height, 0, byteArray);
+                dataOffset += dataLength;
+                width *= 0.5;
+                height *= 0.5;
+            }
+        }
+    }
+} 

+ 251 - 259
Babylon/Tools/babylon.tools.js

@@ -1,327 +1,319 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.Tools = BABYLON.Tools || {};
-
-    BABYLON.Tools.GetFilename = function (path) {
-        var index = path.lastIndexOf("/");
-        if (index < 0)
-            return path;
-
-        return path.substring(index + 1);
-    };
+var BABYLON;
+(function (BABYLON) {
+    // FPS
+    var fpsRange = 60;
+    var previousFramesDuration = [];
+    var fps = 60;
+    var deltaTime = 0;
 
-    BABYLON.Tools.GetDOMTextContent = function(element) {
-        var result = "";
-        var child = element.firstChild;
+    var cloneValue = function (source, destinationObject) {
+        if (!source)
+            return null;
 
-        while (child) {
-            if (child.nodeType == 3) {
-                result += child.textContent;
-            }
-            child = child.nextSibling;
+        if (source instanceof BABYLON.Mesh) {
+            return null;
         }
 
-        return result;
+        if (source instanceof BABYLON.SubMesh) {
+            return source.clone(destinationObject);
+        } else if (source.clone) {
+            return source.clone();
+        }
+        return null;
     };
 
-    BABYLON.Tools.ToDegrees = function(angle) {
-        return angle * 180 / Math.PI;
-    };
+    var Tools = (function () {
+        function Tools() {
+        }
+        Tools.GetFilename = function (path) {
+            var index = path.lastIndexOf("/");
+            if (index < 0)
+                return path;
 
-    BABYLON.Tools.ToRadians = function(angle) {
-         return angle * Math.PI / 180;
-    };
+            return path.substring(index + 1);
+        };
 
-    BABYLON.Tools.ExtractMinAndMax = function (positions, start, count) {
-        var minimum = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-        var maximum = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+        Tools.GetDOMTextContent = function (element) {
+            var result = "";
+            var child = element.firstChild;
 
-        for (var index = start; index < start + count; index++) {
-            var current = new BABYLON.Vector3(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]);
+            while (child) {
+                if (child.nodeType == 3) {
+                    result += child.textContent;
+                }
+                child = child.nextSibling;
+            }
 
-            minimum = BABYLON.Vector3.Minimize(current, minimum);
-            maximum = BABYLON.Vector3.Maximize(current, maximum);
-        }
+            return result;
+        };
 
-        return {
-            minimum: minimum,
-            maximum: maximum
+        Tools.ToDegrees = function (angle) {
+            return angle * 180 / Math.PI;
         };
-    };
-	
-	BABYLON.Tools.MakeArray = function (obj, allowsNullUndefined) {
-		if (allowsNullUndefined !== true && (obj === undefined || obj == null))
-			return undefined;
 
-		return Array.isArray(obj) ? obj : [obj];
-    };
+        Tools.ToRadians = function (angle) {
+            return angle * Math.PI / 180;
+        };
 
-    // Misc.
-    BABYLON.Tools.GetPointerPrefix = function() {
-        var eventPrefix = "pointer";
+        Tools.ExtractMinAndMax = function (positions, start, count) {
+            var minimum = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            var maximum = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
 
-        // Check if hand.js is referenced or if the browser natively supports pointer events
-        if (!navigator.pointerEnabled) {
-            eventPrefix = "mouse";
-        }
+            for (var index = start; index < start + count; index++) {
+                var current = new BABYLON.Vector3(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]);
 
-        return eventPrefix;
-    };
+                minimum = BABYLON.Vector3.Minimize(current, minimum);
+                maximum = BABYLON.Vector3.Maximize(current, maximum);
+            }
 
-    BABYLON.Tools.QueueNewFrame = function (func) {
-        if (window.requestAnimationFrame)
-            window.requestAnimationFrame(func);
-        else if (window.msRequestAnimationFrame)
-            window.msRequestAnimationFrame(func);
-        else if (window.webkitRequestAnimationFrame)
-            window.webkitRequestAnimationFrame(func);
-        else if (window.mozRequestAnimationFrame)
-            window.mozRequestAnimationFrame(func);
-        else if (window.oRequestAnimationFrame)
-            window.oRequestAnimationFrame(func);
-        else {
-            window.setTimeout(func, 16);
-        }
-    };
+            return {
+                minimum: minimum,
+                maximum: maximum
+            };
+        };
 
-    BABYLON.Tools.RequestFullscreen = function (element) {
-        if (element.requestFullscreen)
-            element.requestFullscreen();
-        else if (element.msRequestFullscreen)
-            element.msRequestFullscreen();
-        else if (element.webkitRequestFullscreen)
-            element.webkitRequestFullscreen();
-        else if (element.mozRequestFullScreen)
-            element.mozRequestFullScreen();        
-    };
+        Tools.MakeArray = function (obj, allowsNullUndefined) {
+            if (allowsNullUndefined !== true && (obj === undefined || obj == null))
+                return undefined;
 
-    BABYLON.Tools.ExitFullscreen = function () {
-        if (document.exitFullscreen) {
-            document.exitFullscreen();
-        }
-        else if (document.mozCancelFullScreen) {
-            document.mozCancelFullScreen();
-        }
-        else if (document.webkitCancelFullScreen) {
-            document.webkitCancelFullScreen();
-        }
-        else if (document.msCancelFullScreen) {
-            document.msCancelFullScreen();
-        }
-    };
+            return Array.isArray(obj) ? obj : [obj];
+        };
 
-    // External files
-    BABYLON.Tools.BaseUrl = "";
+        // Misc.
+        Tools.GetPointerPrefix = function () {
+            var eventPrefix = "pointer";
 
-    BABYLON.Tools.LoadImage = function (url, onload, onerror, database) {  
-        var img = new Image();
-        img.crossOrigin = 'anonymous';
+            // Check if hand.js is referenced or if the browser natively supports pointer events
+            if (!navigator.pointerEnabled) {
+                eventPrefix = "mouse";
+            }
 
-        img.onload = function () {
-            onload(img);
+            return eventPrefix;
         };
 
-        img.onerror = function (err) {
-            onerror(img, err);
+        Tools.QueueNewFrame = function (func) {
+            if (window.requestAnimationFrame)
+                window.requestAnimationFrame(func);
+            else if (window.msRequestAnimationFrame)
+                window.msRequestAnimationFrame(func);
+            else if (window.webkitRequestAnimationFrame)
+                window.webkitRequestAnimationFrame(func);
+            else if (window.mozRequestAnimationFrame)
+                window.mozRequestAnimationFrame(func);
+            else if (window.oRequestAnimationFrame)
+                window.oRequestAnimationFrame(func);
+            else {
+                window.setTimeout(func, 16);
+            }
         };
 
-        var noIndexedDB = function () {
-            img.src = url;
+        Tools.RequestFullscreen = function (element) {
+            if (element.requestFullscreen)
+                element.requestFullscreen();
+            else if (element.msRequestFullscreen)
+                element.msRequestFullscreen();
+            else if (element.webkitRequestFullscreen)
+                element.webkitRequestFullscreen();
+            else if (element.mozRequestFullScreen)
+                element.mozRequestFullScreen();
         };
 
-        var loadFromIndexedDB = function () {
-            database.loadImageFromDB(url, img);
+        Tools.ExitFullscreen = function () {
+            if (document.exitFullscreen) {
+                document.exitFullscreen();
+            } else if (document.mozCancelFullScreen) {
+                document.mozCancelFullScreen();
+            } else if (document.webkitCancelFullScreen) {
+                document.webkitCancelFullScreen();
+            } else if (document.msCancelFullScreen) {
+                document.msCancelFullScreen();
+            }
         };
 
-        if (database && database.enableTexturesOffline && BABYLON.Database.isUASupportingBlobStorage) {
-            database.openAsync(loadFromIndexedDB, noIndexedDB);
-        }
-        else {
-            if (url.indexOf("file:") === -1) {
-                noIndexedDB();
-            }
-            else {
-                try {
-                    var textureName = url.substring(5);
-                    var blobURL;
-                    try {
-                        blobURL = URL.createObjectURL(BABYLON.FilesTextures[textureName], { oneTimeOnly: true });
-                    }
-                    catch (ex) {
-                        // Chrome doesn't support oneTimeOnly parameter
-                        blobURL = URL.createObjectURL(BABYLON.FilesTextures[textureName]);
-                    }
-                    img.src = blobURL;
-                }
-                catch (e) {
-                    console.log("Error while trying to load texture: " + textureName);
-                    img.src = null;
-                }
-            }
-        }
+        // External files
+        Tools.LoadImage = function (url, onload, onerror, database) {
+            var img = new Image();
+            img.crossOrigin = 'anonymous';
 
-        return img;
-    };
+            img.onload = function () {
+                onload(img);
+            };
 
-    BABYLON.Tools.LoadFile = function (url, callback, progressCallBack, database, useArrayBuffer) {
-        var noIndexedDB = function () {
-            var request = new XMLHttpRequest();
-            var loadUrl = BABYLON.Tools.BaseUrl + url;
-            request.open('GET', loadUrl, true);
-            
-            if (useArrayBuffer) {
-                request.responseType = "arraybuffer";
-            }
+            img.onerror = function (err) {
+                onerror(img, err);
+            };
 
-            request.onprogress = progressCallBack;
+            var noIndexedDB = function () {
+                img.src = url;
+            };
+
+            var loadFromIndexedDB = function () {
+                database.loadImageFromDB(url, img);
+            };
 
-            request.onreadystatechange = function () {
-                if (request.readyState == 4) {
-                    if (request.status == 200) {
-                        callback(!useArrayBuffer ? request.responseText : request.response);
-                    } else { // Failed
-                        throw new Error(request.status, "Unable to load " + loadUrl);
+            //ANY database to do!
+            if (database && database.enableTexturesOffline) {
+                database.openAsync(loadFromIndexedDB, noIndexedDB);
+            } else {
+                if (url.indexOf("file:") === -1) {
+                    noIndexedDB();
+                } else {
+                    try  {
+                        var textureName = url.substring(5);
+                        var blobURL;
+                        try  {
+                            blobURL = URL.createObjectURL(FilesTextures[textureName], { oneTimeOnly: true });
+                        } catch (ex) {
+                            // Chrome doesn't support oneTimeOnly parameter
+                            blobURL = URL.createObjectURL(FilesTextures[textureName]);
+                        }
+                        img.src = blobURL;
+                    } catch (e) {
+                        console.log("Error while trying to load texture: " + textureName);
+                        img.src = null;
                     }
                 }
-            };
+            }
 
-            request.send(null);
+            return img;
         };
 
-        var loadFromIndexedDB = function () {
-            database.loadSceneFromDB(url, callback, progressCallBack, noIndexedDB);
-        };
+        Tools.LoadFile = function (url, callback, progressCallBack, database, useArrayBuffer) {
+            var noIndexedDB = function () {
+                var request = new XMLHttpRequest();
+                var loadUrl = Tools.BaseUrl + url;
+                request.open('GET', loadUrl, true);
 
-        // Caching only scenes files
-        if (database && url.indexOf(".babylon") !== -1 && (database.enableSceneOffline)) {
-            database.openAsync(loadFromIndexedDB, noIndexedDB);
-        }
-        else {
-            noIndexedDB();
-        }
-    };
+                if (useArrayBuffer) {
+                    request.responseType = "arraybuffer";
+                }
 
-    BABYLON.Tools.ReadFile = function (fileToLoad, callback, progressCallBack) {
-        var reader = new FileReader();
-        reader.onload = function (e) {
-            callback(e.target.result);
-        };
-        reader.onprogress = progressCallBack;
-        // Asynchronous read
-        reader.readAsText(fileToLoad);
-    };
+                request.onprogress = progressCallBack;
 
-    // Misc.        
-    BABYLON.Tools.WithinEpsilon = function (a, b) {
-        var num = a - b;
-        return -1.401298E-45 <= num && num <= 1.401298E-45;
-    };
+                request.onreadystatechange = function () {
+                    if (request.readyState == 4) {
+                        if (request.status == 200) {
+                            callback(!useArrayBuffer ? request.responseText : request.response);
+                        } else {
+                            throw new Error("Error status: " + request.status + " - Unable to load " + loadUrl);
+                        }
+                    }
+                };
 
-    var cloneValue = function (source, destinationObject) {
-        if (!source)
-            return null;
+                request.send(null);
+            };
 
-        if (source instanceof BABYLON.Mesh) {
-            return null;
-        }
+            var loadFromIndexedDB = function () {
+                database.loadSceneFromDB(url, callback, progressCallBack, noIndexedDB);
+            };
 
-        if (source instanceof BABYLON.SubMesh) {
-            return source.clone(destinationObject);
-        } else if (source.clone) {
-            return source.clone();
-        }
-        return null;
-    };
+            // Caching only scenes files
+            if (database && url.indexOf(".babylon") !== -1 && (database.enableSceneOffline)) {
+                database.openAsync(loadFromIndexedDB, noIndexedDB);
+            } else {
+                noIndexedDB();
+            }
+        };
 
-    BABYLON.Tools.DeepCopy = function (source, destination, doNotCopyList, mustCopyList) {
-        for (var prop in source) {
+        Tools.ReadFile = function (fileToLoad, callback, progressCallBack) {
+            var reader = new FileReader();
+            reader.onload = function (e) {
+                callback(e.target.result);
+            };
+            reader.onprogress = progressCallBack;
 
-            if (prop[0] === "_" && (!mustCopyList || mustCopyList.indexOf(prop) === -1)) {
-                continue;
-            }
+            // Asynchronous read
+            reader.readAsText(fileToLoad);
+        };
 
-            if (doNotCopyList && doNotCopyList.indexOf(prop) !== -1) {
-                continue;
-            }
-            var sourceValue = source[prop];
-            var typeOfSourceValue = typeof sourceValue;
+        // Misc.
+        Tools.WithinEpsilon = function (a, b) {
+            var num = a - b;
+            return -1.401298E-45 <= num && num <= 1.401298E-45;
+        };
 
-            if (typeOfSourceValue == "function") {
-                continue;
-            }
+        Tools.DeepCopy = function (source, destination, doNotCopyList, mustCopyList) {
+            for (var prop in source) {
+                if (prop[0] === "_" && (!mustCopyList || mustCopyList.indexOf(prop) === -1)) {
+                    continue;
+                }
 
-            if (typeOfSourceValue == "object") {
-                if (sourceValue instanceof Array) {
-                    destination[prop] = [];
+                if (doNotCopyList && doNotCopyList.indexOf(prop) !== -1) {
+                    continue;
+                }
+                var sourceValue = source[prop];
+                var typeOfSourceValue = typeof sourceValue;
+
+                if (typeOfSourceValue == "function") {
+                    continue;
+                }
 
-                    if (sourceValue.length > 0) {
-                        if (typeof sourceValue[0] == "object") {
-                            for (var index = 0; index < sourceValue.length; index++) {
-                                var clonedValue = cloneValue(sourceValue[index], destination);
+                if (typeOfSourceValue == "object") {
+                    if (sourceValue instanceof Array) {
+                        destination[prop] = [];
 
-                                if (destination[prop].indexOf(clonedValue) === -1) { // Test if auto inject was not done
-                                    destination[prop].push(clonedValue);
+                        if (sourceValue.length > 0) {
+                            if (typeof sourceValue[0] == "object") {
+                                for (var index = 0; index < sourceValue.length; index++) {
+                                    var clonedValue = cloneValue(sourceValue[index], destination);
+
+                                    if (destination[prop].indexOf(clonedValue) === -1) {
+                                        destination[prop].push(clonedValue);
+                                    }
                                 }
+                            } else {
+                                destination[prop] = sourceValue.slice(0);
                             }
-                        } else {
-                            destination[prop] = sourceValue.slice(0);
                         }
+                    } else {
+                        destination[prop] = cloneValue(sourceValue, destination);
                     }
                 } else {
-                    destination[prop] = cloneValue(sourceValue, destination);
+                    destination[prop] = sourceValue;
                 }
-            } else {
-                destination[prop] = sourceValue;
             }
-        }
-    };
-
-    BABYLON.Tools.IsEmpty = function (obj) {
-        for (var i in obj) {
-            return false;
-        }
-        return true;
-    };
-
-    // FPS
-    var fpsRange = 60;
-    var previousFramesDuration = [];
-    var fps = 60;
-    var deltaTime = 0;
-
-    BABYLON.Tools.GetFps = function () {
-        return fps;
-    };
+        };
 
-    BABYLON.Tools.GetDeltaTime = function () {
-        return deltaTime;
-    };
+        Tools.IsEmpty = function (obj) {
+            for (var i in obj) {
+                return false;
+            }
+            return true;
+        };
 
-    BABYLON.Tools._MeasureFps = function () {
-        previousFramesDuration.push((new Date).getTime());
-        var length = previousFramesDuration.length;
+        Tools.GetFps = function () {
+            return fps;
+        };
 
-        if (length >= 2) {
-            deltaTime = previousFramesDuration[length - 1] - previousFramesDuration[length - 2];
-        }
+        Tools.GetDeltaTime = function () {
+            return deltaTime;
+        };
 
-        if (length >= fpsRange) {
+        Tools._MeasureFps = function () {
+            previousFramesDuration.push((new Date).getTime());
+            var length = previousFramesDuration.length;
 
-            if (length > fpsRange) {
-                previousFramesDuration.splice(0, 1);
-                length = previousFramesDuration.length;
+            if (length >= 2) {
+                deltaTime = previousFramesDuration[length - 1] - previousFramesDuration[length - 2];
             }
 
-            var sum = 0;
-            for (var id = 0; id < length - 1; id++) {
-                sum += previousFramesDuration[id + 1] - previousFramesDuration[id];
-            }
+            if (length >= fpsRange) {
+                if (length > fpsRange) {
+                    previousFramesDuration.splice(0, 1);
+                    length = previousFramesDuration.length;
+                }
 
-            fps = 1000.0 / (sum / (length - 1));
-        }
-    };
+                var sum = 0;
+                for (var id = 0; id < length - 1; id++) {
+                    sum += previousFramesDuration[id + 1] - previousFramesDuration[id];
+                }
 
-})();
+                fps = 1000.0 / (sum / (length - 1));
+            }
+        };
+        Tools.BaseUrl = "";
+        return Tools;
+    })();
+    BABYLON.Tools = Tools;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.tools.js.map

+ 329 - 0
Babylon/Tools/babylon.tools.ts

@@ -0,0 +1,329 @@
+module BABYLON {
+    declare var window;
+    declare var document;
+
+    declare var FilesTextures; //ANY
+
+    // FPS
+    var fpsRange = 60;
+    var previousFramesDuration = [];
+    var fps = 60;
+    var deltaTime = 0;
+
+    var cloneValue = (source, destinationObject) => {
+        if (!source)
+            return null;
+
+        if (source instanceof Mesh) {
+            return null;
+        }
+
+        if (source instanceof SubMesh) {
+            return source.clone(destinationObject);
+        } else if (source.clone) {
+            return source.clone();
+        }
+        return null;
+    };
+
+    export class Tools {
+        public static BaseUrl = "";
+
+        public static GetFilename(path: string): string {
+            var index = path.lastIndexOf("/");
+            if (index < 0)
+                return path;
+
+            return path.substring(index + 1);
+        }
+
+        public static GetDOMTextContent(element: HTMLElement): string {
+            var result = "";
+            var child = element.firstChild;
+
+            while (child) {
+                if (child.nodeType == 3) {
+                    result += child.textContent;
+                }
+                child = child.nextSibling;
+            }
+
+            return result;
+        }
+
+        public static ToDegrees(angle: number): number {
+            return angle * 180 / Math.PI;
+        }
+
+        public static ToRadians(angle: number): number {
+            return angle * Math.PI / 180;
+        }
+
+        public static ExtractMinAndMax(positions: number[], start: number, count: number): { minimum: Vector3; maximum: Vector3 } {
+            var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+
+            for (var index = start; index < start + count; index++) {
+                var current = new Vector3(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]);
+
+                minimum = BABYLON.Vector3.Minimize(current, minimum);
+                maximum = BABYLON.Vector3.Maximize(current, maximum);
+            }
+
+            return {
+                minimum: minimum,
+                maximum: maximum
+            };
+        }
+
+        public static MakeArray(obj, allowsNullUndefined: boolean): Array<any> {
+            if (allowsNullUndefined !== true && (obj === undefined || obj == null))
+                return undefined;
+
+            return Array.isArray(obj) ? obj : [obj];
+        }
+
+        // Misc.
+        public static GetPointerPrefix(): string {
+            var eventPrefix = "pointer";
+
+            // Check if hand.js is referenced or if the browser natively supports pointer events
+            if (!navigator.pointerEnabled) {
+                eventPrefix = "mouse";
+            }
+
+            return eventPrefix;
+        }
+
+        public static QueueNewFrame(func): void {
+            if (window.requestAnimationFrame)
+                window.requestAnimationFrame(func);
+            else if (window.msRequestAnimationFrame)
+                window.msRequestAnimationFrame(func);
+            else if (window.webkitRequestAnimationFrame)
+                window.webkitRequestAnimationFrame(func);
+            else if (window.mozRequestAnimationFrame)
+                window.mozRequestAnimationFrame(func);
+            else if (window.oRequestAnimationFrame)
+                window.oRequestAnimationFrame(func);
+            else {
+                window.setTimeout(func, 16);
+            }
+        }
+
+        public static RequestFullscreen(element): void {
+            if (element.requestFullscreen)
+                element.requestFullscreen();
+            else if (element.msRequestFullscreen)
+                element.msRequestFullscreen();
+            else if (element.webkitRequestFullscreen)
+                element.webkitRequestFullscreen();
+            else if (element.mozRequestFullScreen)
+                element.mozRequestFullScreen();
+        }
+
+        public static ExitFullscreen(): void {
+            if (document.exitFullscreen) {
+                document.exitFullscreen();
+            }
+            else if (document.mozCancelFullScreen) {
+                document.mozCancelFullScreen();
+            }
+            else if (document.webkitCancelFullScreen) {
+                document.webkitCancelFullScreen();
+            }
+            else if (document.msCancelFullScreen) {
+                document.msCancelFullScreen();
+            }
+        }
+
+        // External files
+        public static LoadImage(url: string, onload, onerror, database): HTMLImageElement {
+            var img = new Image();
+            img.crossOrigin = 'anonymous';
+
+            img.onload = () => {
+                onload(img);
+            };
+
+            img.onerror = err => {
+                onerror(img, err);
+            };
+
+            var noIndexedDB = () => {
+                img.src = url;
+            };
+
+            var loadFromIndexedDB = () => {
+                database.loadImageFromDB(url, img);
+            };
+
+
+            //ANY database to do!
+            if (database && database.enableTexturesOffline) { //} && BABYLON.Database.isUASupportingBlobStorage) {
+                database.openAsync(loadFromIndexedDB, noIndexedDB);
+            }
+            else {
+                if (url.indexOf("file:") === -1) {
+                    noIndexedDB();
+                }
+                else {
+                    try {
+                        var textureName = url.substring(5);
+                        var blobURL;
+                        try {
+                            blobURL = URL.createObjectURL(FilesTextures[textureName], { oneTimeOnly: true });
+                        }
+                        catch (ex) {
+                            // Chrome doesn't support oneTimeOnly parameter
+                            blobURL = URL.createObjectURL(FilesTextures[textureName]);
+                        }
+                        img.src = blobURL;
+                    }
+                    catch (e) {
+                        console.log("Error while trying to load texture: " + textureName);
+                        img.src = null;
+                    }
+                }
+            }
+
+            return img;
+        }
+
+        public static LoadFile(url: string, callback: (string) => void, progressCallBack: () => void, database, useArrayBuffer?: boolean): void {
+            var noIndexedDB = () => {
+                var request = new XMLHttpRequest();
+                var loadUrl = Tools.BaseUrl + url;
+                request.open('GET', loadUrl, true);
+
+                if (useArrayBuffer) {
+                    request.responseType = "arraybuffer";
+                }
+
+                request.onprogress = progressCallBack;
+
+                request.onreadystatechange = () => {
+                    if (request.readyState == 4) {
+                        if (request.status == 200) {
+                            callback(!useArrayBuffer ? request.responseText : request.response);
+                        } else { // Failed
+                            throw new Error("Error status: " + request.status + " - Unable to load " + loadUrl);
+                        }
+                    }
+                };
+
+                request.send(null);
+            };
+
+            var loadFromIndexedDB = () => {
+                database.loadSceneFromDB(url, callback, progressCallBack, noIndexedDB);
+            };
+
+            // Caching only scenes files
+            if (database && url.indexOf(".babylon") !== -1 && (database.enableSceneOffline)) {
+                database.openAsync(loadFromIndexedDB, noIndexedDB);
+            }
+            else {
+                noIndexedDB();
+            }
+        }
+
+        public static ReadFile(fileToLoad, callback, progressCallBack): void {
+            var reader = new FileReader();
+            reader.onload = e => {
+                callback(e.target.result);
+            };
+            reader.onprogress = progressCallBack;
+            // Asynchronous read
+            reader.readAsText(fileToLoad);
+        }
+
+        // Misc.        
+        public static WithinEpsilon(a: number, b: number): boolean {
+            var num = a - b;
+            return -1.401298E-45 <= num && num <= 1.401298E-45;
+        }
+
+        public static DeepCopy(source, destination, doNotCopyList: string[], mustCopyList: string[]): void {
+            for (var prop in source) {
+
+                if (prop[0] === "_" && (!mustCopyList || mustCopyList.indexOf(prop) === -1)) {
+                    continue;
+                }
+
+                if (doNotCopyList && doNotCopyList.indexOf(prop) !== -1) {
+                    continue;
+                }
+                var sourceValue = source[prop];
+                var typeOfSourceValue = typeof sourceValue;
+
+                if (typeOfSourceValue == "function") {
+                    continue;
+                }
+
+                if (typeOfSourceValue == "object") {
+                    if (sourceValue instanceof Array) {
+                        destination[prop] = [];
+
+                        if (sourceValue.length > 0) {
+                            if (typeof sourceValue[0] == "object") {
+                                for (var index = 0; index < sourceValue.length; index++) {
+                                    var clonedValue = cloneValue(sourceValue[index], destination);
+
+                                    if (destination[prop].indexOf(clonedValue) === -1) { // Test if auto inject was not done
+                                        destination[prop].push(clonedValue);
+                                    }
+                                }
+                            } else {
+                                destination[prop] = sourceValue.slice(0);
+                            }
+                        }
+                    } else {
+                        destination[prop] = cloneValue(sourceValue, destination);
+                    }
+                } else {
+                    destination[prop] = sourceValue;
+                }
+            }
+        }
+
+        public static IsEmpty(obj): boolean {
+            for (var i in obj) {
+                return false;
+            }
+            return true;
+        }
+
+        public static GetFps(): number {
+            return fps;
+        }
+
+        public static GetDeltaTime(): number {
+            return deltaTime;
+        }
+
+        public static _MeasureFps(): void {
+            previousFramesDuration.push((new Date).getTime());
+            var length = previousFramesDuration.length;
+
+            if (length >= 2) {
+                deltaTime = previousFramesDuration[length - 1] - previousFramesDuration[length - 2];
+            }
+
+            if (length >= fpsRange) {
+
+                if (length > fpsRange) {
+                    previousFramesDuration.splice(0, 1);
+                    length = previousFramesDuration.length;
+                }
+
+                var sum = 0;
+                for (var id = 0; id < length - 1; id++) {
+                    sum += previousFramesDuration[id + 1] - previousFramesDuration[id];
+                }
+
+                fps = 1000.0 / (sum / (length - 1));
+            }
+        }
+    }
+} 

+ 2 - 2
Babylon/babylon.engine.js

@@ -708,12 +708,12 @@ var BABYLON = BABYLON || {};
 
         if (isDDS) {
             BABYLON.Tools.LoadFile(url, function (data) {
-                var info = BABYLON.Tools.GetDDSInfo(data);
+                var info = BABYLON.Internals.DDSTools.GetDDSInfo(data);
 
                 var loadMipmap = info.mipmapCount > 1 && !noMipmap;
 
                 prepareWebGLTexture(texture, scene, info.width, info.height, invertY, !loadMipmap, function (potWidth, potHeight) {
-                    BABYLON.Tools.UploadDDSLevels(that._gl, that.getCaps().s3tc, data, loadMipmap);
+                    BABYLON.Internals.DDSTools.UploadDDSLevels(that._gl, that.getCaps().s3tc, data, loadMipmap);
                 });
             }, null, scene.database, true);
         } else {

+ 113 - 112
Babylon/babylon.node.js

@@ -1,134 +1,135 @@
-"use strict";
-
-
-var BABYLON = BABYLON || {};
-
-
-(function () {
-    BABYLON.Node = function (scene) {
-        this._scene = scene;
-        BABYLON.Node.prototype._initCache.call(this);
-    };
-
-    // Properties
-    BABYLON.Node.prototype.parent = null;
-    BABYLON.Node.prototype._childrenFlag = -1;
-    BABYLON.Node.prototype._isReady = true;
-    BABYLON.Node.prototype._isEnabled = true;
-    BABYLON.Node.prototype._currentRenderId = -1;
-
-    // Cache
-    BABYLON.Node.prototype._cache = null;
-
-    // override it in derived class if you add new variables to the cache
-    // and call it in the constructor of your class like this
-    // BABYLON.YourClass.prototype._initCache.call(this)
-    // DO NOT call parent class method
-    BABYLON.Node.prototype._initCache = function () {
-        this._cache = {};
-        this._cache.parent = undefined;
-    };
-
-    BABYLON.Node.prototype.updateCache = function (force) {
-        if (!force && this.isSynchronized())
-            return;
-
-        this._cache.parent = this.parent;
-
-        this._updateCache();
-    };
-
-    // override it in derived class if you add new variables to the cache
-    // and call the parent class method if !ignoreParentClass
-    // BABYLON.ParentClass.prototype._updateCache.call(this, ignoreParentClass)
-    BABYLON.Node.prototype._updateCache = function (ignoreParentClass) {
-    };
-
-    // override it in derived class if you add new variables to the cache
-    // and call the parent class method
-    // BABYLON.ParentClass.prototype._isSynchronized.call(this)
-    BABYLON.Node.prototype._isSynchronized = function () {
-        return true;
-    };
-
-    BABYLON.Node.prototype.isSynchronizedWithParent = function() {
-        return this.parent ? this.parent._currentRenderId <= this._currentRenderId : true;
-    };
-
-    BABYLON.Node.prototype.isSynchronized = function (updateCache) {
-        var check = this.hasNewParent();
+var BABYLON;
+(function (BABYLON) {
+    var Node = (function () {
+        function Node(name, scene) {
+            this.animations = new Array();
+            this._childrenFlag = -1;
+            this._isEnabled = true;
+            this._isReady = true;
+            this._currentRenderId = -1;
+            this.name = name;
+            this.id = name;
+            this._scene = scene;
+            this._initCache();
+        }
+        //ANY
+        Node.prototype.getScene = function () {
+            return this._scene;
+        };
+
+        //ANY
+        Node.prototype.getEngine = function () {
+            return this._scene.getEngine();
+        };
+
+        // override it in derived class
+        Node.prototype.getWorldMatrix = function () {
+            return BABYLON.Matrix.Identity();
+        };
+
+        // override it in derived class if you add new variables to the cache
+        // and call the parent class method
+        Node.prototype._initCache = function () {
+            this._cache = {};
+            this._cache.parent = undefined;
+        };
+
+        Node.prototype.updateCache = function (force) {
+            if (!force && this.isSynchronized())
+                return;
 
-        check = check || !this.isSynchronizedWithParent();
+            this._cache.parent = this.parent;
 
-        check = check || !this._isSynchronized();
+            this._updateCache();
+        };
 
-        if (updateCache)
-            this.updateCache(true);
+        // override it in derived class if you add new variables to the cache
+        // and call the parent class method if !ignoreParentClass
+        Node.prototype._updateCache = function (ignoreParentClass) {
+        };
 
-        return !check;
-    };
+        // override it in derived class if you add new variables to the cache
+        Node.prototype._isSynchronized = function () {
+            return true;
+        };
 
-    BABYLON.Node.prototype.hasNewParent = function (update) {
-        if (this._cache.parent === this.parent)
-            return false;
+        Node.prototype.isSynchronizedWithParent = function () {
+            return this.parent ? this.parent._currentRenderId <= this._currentRenderId : true;
+        };
 
-        if (update)
-            this._cache.parent = this.parent;
+        Node.prototype.isSynchronized = function (updateCache) {
+            var check = this.hasNewParent();
 
-        return true;
-    };
+            check = check || !this.isSynchronizedWithParent();
 
-    BABYLON.Node.prototype.isReady = function () {
-        return this._isReady;
-    };
+            check = check || !this._isSynchronized();
 
-    BABYLON.Node.prototype.isEnabled = function () {
-        if (!this.isReady() || !this._isEnabled) {
-            return false;
-        }
+            if (updateCache)
+                this.updateCache(true);
 
+            return !check;
+        };
 
-        if (this.parent) {
-            return this.parent.isEnabled();
-        }
+        Node.prototype.hasNewParent = function (update) {
+            if (this._cache.parent === this.parent)
+                return false;
 
+            if (update)
+                this._cache.parent = this.parent;
 
-        return true;
-    };
+            return true;
+        };
 
-    BABYLON.Node.prototype.setEnabled = function (value) {
-        this._isEnabled = value;
-    };
+        Node.prototype.isReady = function () {
+            return this._isReady;
+        };
 
-    BABYLON.Node.prototype.isDescendantOf = function (ancestor) {
-        if (this.parent) {
-            if (this.parent === ancestor) {
-                return true;
+        Node.prototype.isEnabled = function () {
+            if (!this.isReady() || !this._isEnabled) {
+                return false;
             }
 
-
-            return this.parent.isDescendantOf(ancestor);
-        }
-        return false;
-    };
-
-    BABYLON.Node.prototype._getDescendants = function (list, results) {
-        for (var index = 0; index < list.length; index++) {
-            var item = list[index];
-            if (item.isDescendantOf(this)) {
-                results.push(item);
+            if (this.parent) {
+                return this.parent.isEnabled();
             }
-        }
-    };
 
-    BABYLON.Node.prototype.getDescendants = function () {
-        var results = [];
-        this._getDescendants(this._scene.meshes, results);
-        this._getDescendants(this._scene.lights, results);
-        this._getDescendants(this._scene.cameras, results);
+            return true;
+        };
 
-        return results;
-    };
+        Node.prototype.setEnabled = function (value) {
+            this._isEnabled = value;
+        };
 
-})();
+        Node.prototype.isDescendantOf = function (ancestor) {
+            if (this.parent) {
+                if (this.parent === ancestor) {
+                    return true;
+                }
 
+                return this.parent.isDescendantOf(ancestor);
+            }
+            return false;
+        };
+
+        Node.prototype._getDescendants = function (list, results) {
+            for (var index = 0; index < list.length; index++) {
+                var item = list[index];
+                if (item.isDescendantOf(this)) {
+                    results.push(item);
+                }
+            }
+        };
+
+        Node.prototype.getDescendants = function () {
+            var results = [];
+            this._getDescendants(this._scene.meshes, results);
+            this._getDescendants(this._scene.lights, results);
+            this._getDescendants(this._scene.cameras, results);
+
+            return results;
+        };
+        return Node;
+    })();
+    BABYLON.Node = Node;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.node.js.map

+ 142 - 0
Babylon/babylon.node.ts

@@ -0,0 +1,142 @@
+module BABYLON {
+    export class Node {
+        public parent: Node;
+        public name: string;
+        public id: string;
+
+        public animations = new Array<Animation>();
+
+        private _childrenFlag = -1;
+        private _isEnabled = true;
+        public _isReady = true;
+        public _currentRenderId = -1;
+
+        private _scene;
+        public _cache;
+
+        constructor(name: string, scene) {
+            this.name = name;
+            this.id = name;
+            this._scene = scene;
+            this._initCache();
+        }
+
+        //ANY
+        public getScene() {
+            return this._scene;
+        }
+
+        //ANY
+        public getEngine() {
+            return this._scene.getEngine();
+        }
+
+        // override it in derived class
+        public getWorldMatrix(): Matrix {
+            return Matrix.Identity();
+        }
+
+        // override it in derived class if you add new variables to the cache
+        // and call the parent class method
+        public _initCache() {
+            this._cache = {};
+            this._cache.parent = undefined;
+        }
+
+        public updateCache(force?: boolean): void {
+            if (!force && this.isSynchronized())
+                return;
+
+            this._cache.parent = this.parent;
+
+            this._updateCache();
+        }
+
+        // override it in derived class if you add new variables to the cache
+        // and call the parent class method if !ignoreParentClass
+        public _updateCache(ignoreParentClass?: boolean): void {
+        }
+
+        // override it in derived class if you add new variables to the cache
+        public _isSynchronized(): boolean {
+            return true;
+        }
+
+        public isSynchronizedWithParent(): boolean {
+            return this.parent ? this.parent._currentRenderId <= this._currentRenderId : true;
+        }
+
+        public isSynchronized(updateCache?: boolean): boolean {
+            var check = this.hasNewParent();
+
+            check = check || !this.isSynchronizedWithParent();
+
+            check = check || !this._isSynchronized();
+
+            if (updateCache)
+                this.updateCache(true);
+
+            return !check;
+        }
+
+        public hasNewParent(update?: boolean): boolean {
+            if (this._cache.parent === this.parent)
+                return false;
+
+            if (update)
+                this._cache.parent = this.parent;
+
+            return true;
+        }
+
+        public isReady(): boolean {
+            return this._isReady;
+        }
+
+        public isEnabled(): boolean {
+            if (!this.isReady() || !this._isEnabled) {
+                return false;
+            }
+
+            if (this.parent) {
+                return this.parent.isEnabled();
+            }
+
+            return true;
+        }
+
+        public setEnabled(value: boolean): void {
+            this._isEnabled = value;
+        }
+
+        public isDescendantOf(ancestor: Node): boolean {
+            if (this.parent) {
+                if (this.parent === ancestor) {
+                    return true;
+                }
+
+
+                return this.parent.isDescendantOf(ancestor);
+            }
+            return false;
+        }
+
+        public _getDescendants(list: Node[], results: Node[]): void {
+            for (var index = 0; index < list.length; index++) {
+                var item = list[index];
+                if (item.isDescendantOf(this)) {
+                    results.push(item);
+                }
+            }
+        }
+
+        public getDescendants(): Node[] {
+            var results = [];
+            this._getDescendants(this._scene.meshes, results);
+            this._getDescendants(this._scene.lights, results);
+            this._getDescendants(this._scene.cameras, results);
+
+            return results;
+        }
+    }
+} 

+ 5 - 3
Babylon/babylon.scene.js

@@ -600,10 +600,12 @@ var BABYLON = BABYLON || {};
                         this._boundingBoxRenderer.renderList.push(mesh);
                     }
 
-                    for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                        var subMesh = mesh.subMeshes[subIndex];
+                    if (mesh.subMeshes) {
+                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
+                            var subMesh = mesh.subMeshes[subIndex];
 
-                        this._evaluateSubMesh(subMesh, mesh);
+                            this._evaluateSubMesh(subMesh, mesh);
+                        }
                     }
                 }
             }