Forráskód Böngészése

Physics Engine v2

A new physics engine.
For now CannonJS Plugin is implemented.
Raanan Weber 9 éve
szülő
commit
b7b3ff5c5c

+ 2 - 0
Tools/Gulp/config.json

@@ -81,6 +81,8 @@
       "../../src/PostProcess/babylon.postProcess.js",
       "../../src/PostProcess/babylon.postProcessManager.js",
       "../../src/PostProcess/babylon.passPostProcess.js",
+      "../../src/Physics/babylon.physicsJoint.js",
+      "../../src/Physics/babylon.physicsImpostor.js",
       "../../src/Physics/babylon.physicsEngine.js",
       "../../src/Mesh/babylon.mesh.vertexData.js",
       "../../src/Tools/babylon.tags.js",

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 25 - 19
dist/preview release/babylon.core.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2040 - 1921
dist/preview release/babylon.d.ts


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 36 - 28
dist/preview release/babylon.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 9282 - 8499
dist/preview release/babylon.max.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 37 - 29
dist/preview release/babylon.noworker.js


+ 119 - 60
src/Mesh/babylon.abstractMesh.js

@@ -13,9 +13,9 @@ var BABYLON;
             _super.call(this, name, scene);
             // Properties
             this.definedFacingForward = true; // orientation for POV movement & rotation
-            this.position = new BABYLON.Vector3(0, 0, 0);
-            this.rotation = new BABYLON.Vector3(0, 0, 0);
-            this.scaling = new BABYLON.Vector3(1, 1, 1);
+            this._position = new BABYLON.Vector3(0, 0, 0);
+            this._rotation = new BABYLON.Vector3(0, 0, 0);
+            this._scaling = new BABYLON.Vector3(1, 1, 1);
             this.billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
             this.visibility = 1.0;
             this.alphaIndex = Number.MAX_VALUE;
@@ -45,8 +45,6 @@ var BABYLON;
             this.useOctreeForCollisions = true;
             this.layerMask = 0x0FFFFFFF;
             this.alwaysSelectAsActiveMesh = false;
-            // Physics
-            this._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
             // Collisions
             this._checkCollisions = false;
             this.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
@@ -145,6 +143,60 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(AbstractMesh.prototype, "position", {
+            get: function () {
+                return this._position;
+            },
+            set: function (newPosition) {
+                this._position = newPosition;
+                if (this.physicImpostor) {
+                    this.physicImpostor.setTransformationUpdated(true);
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(AbstractMesh.prototype, "rotation", {
+            get: function () {
+                if (this.rotationQuaternion) {
+                    BABYLON.Tools.Warn("Quaternion rotation is used, the rotation value is probably wrong");
+                }
+                return this._rotation;
+            },
+            set: function (newRotation) {
+                this._rotation = newRotation;
+                //check if rotationQuaternion exists, and if it does - update it!
+                if (this._rotationQuaternion) {
+                    var len = this._rotation.length();
+                    if (len) {
+                        this._rotationQuaternion.multiplyInPlace(BABYLON.Quaternion.RotationYawPitchRoll(this._rotation.y, this._rotation.x, this._rotation.z));
+                        this._rotation.copyFromFloats(0, 0, 0);
+                    }
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(AbstractMesh.prototype, "scaling", {
+            get: function () {
+                return this._scaling;
+            },
+            set: function (newScaling) {
+                this._scaling = newScaling;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(AbstractMesh.prototype, "rotationQuaternion", {
+            get: function () {
+                return this._rotationQuaternion;
+            },
+            set: function (quaternion) {
+                this._rotationQuaternion = quaternion;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         AbstractMesh.prototype.updatePoseMatrix = function (matrix) {
             this._poseMatrix.copyFrom(matrix);
@@ -602,62 +654,61 @@ var BABYLON;
             }
             return this._boundingInfo.intersectsPoint(point);
         };
-        // Physics
-        AbstractMesh.prototype.setPhysicsState = function (impostor, options) {
-            var physicsEngine = this.getScene().getPhysicsEngine();
-            if (!physicsEngine) {
-                return null;
-            }
-            impostor = impostor || BABYLON.PhysicsEngine.NoImpostor;
-            if (impostor.impostor) {
-                // Old API
-                options = impostor;
-                impostor = impostor.impostor;
+        AbstractMesh.prototype.getChildMeshes = function () {
+            var _this = this;
+            return this.getScene().meshes.filter(function (m) {
+                return m.parent === _this;
+            });
+        };
+        AbstractMesh.prototype.getChildren = function () {
+            var results = [];
+            for (var index = 0; index < this.getScene().meshes.length; index++) {
+                var mesh = this.getScene().meshes[index];
+                if (mesh.parent === this) {
+                    results.push(mesh);
+                }
             }
-            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
-                physicsEngine._unregisterMesh(this);
-                return null;
+            for (var index = 0; index < this.getScene().lights.length; index++) {
+                var light = this.getScene().lights[index];
+                if (light.parent === this) {
+                    results.push(mesh);
+                }
             }
-            if (!options) {
-                options = { mass: 0, friction: 0.2, restitution: 0.2 };
+            for (var index = 0; index < this.getScene().cameras.length; index++) {
+                var camera = this.getScene().cameras[index];
+                if (camera.parent === this) {
+                    results.push(mesh);
+                }
             }
-            else {
-                if (!options.mass && options.mass !== 0)
-                    options.mass = 0;
-                if (!options.friction && options.friction !== 0)
-                    options.friction = 0.2;
-                if (!options.restitution && options.restitution !== 0)
-                    options.restitution = 0.2;
-            }
-            this._physicImpostor = impostor;
-            this._physicsMass = options.mass;
-            this._physicsFriction = options.friction;
-            this._physicRestitution = options.restitution;
-            return physicsEngine._registerMesh(this, impostor, options);
+            return results;
+        };
+        // Physics
+        /**
+         *  @Deprecated. Use new PhysicsImpostor instead.
+         * */
+        AbstractMesh.prototype.setPhysicsState = function (impostor, options) {
+            this.physicImpostor = new BABYLON.PhysicsImpostor(this, impostor, options);
         };
         AbstractMesh.prototype.getPhysicsImpostor = function () {
-            if (!this._physicImpostor) {
-                return BABYLON.PhysicsEngine.NoImpostor;
-            }
-            return this._physicImpostor;
+            return this.physicImpostor;
         };
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("mass");
+         */
         AbstractMesh.prototype.getPhysicsMass = function () {
-            if (!this._physicsMass) {
-                return 0;
-            }
-            return this._physicsMass;
+            return this.physicImpostor.getParam("mass");
         };
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("friction");
+         */
         AbstractMesh.prototype.getPhysicsFriction = function () {
-            if (!this._physicsFriction) {
-                return 0;
-            }
-            return this._physicsFriction;
+            return this.physicImpostor.getParam("friction");
         };
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("restitution");
+         */
         AbstractMesh.prototype.getPhysicsRestitution = function () {
-            if (!this._physicRestitution) {
-                return 0;
-            }
-            return this._physicRestitution;
+            return this.physicImpostor.getParam("resitution");
         };
         AbstractMesh.prototype.getPositionInCameraSpace = function (camera) {
             if (!camera) {
@@ -672,26 +723,34 @@ var BABYLON;
             return this.absolutePosition.subtract(camera.position).length();
         };
         AbstractMesh.prototype.applyImpulse = function (force, contactPoint) {
-            if (!this._physicImpostor) {
+            if (!this.physicImpostor) {
                 return;
             }
-            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
+            this.physicImpostor.applyImpulse(force, contactPoint);
         };
         AbstractMesh.prototype.setPhysicsLinkWith = function (otherMesh, pivot1, pivot2, options) {
-            if (!this._physicImpostor) {
+            if (!this.physicImpostor || !otherMesh.physicImpostor) {
                 return;
             }
-            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2, options);
+            this.physicImpostor.createJoint(otherMesh.physicImpostor, BABYLON.PhysicsJoint.HingeJoint, {
+                mainPivot: pivot1,
+                connectedPivot: pivot2
+            });
         };
+        /**
+         * @Deprecated
+         */
         AbstractMesh.prototype.updatePhysicsBodyPosition = function () {
             BABYLON.Tools.Warn("updatePhysicsBodyPosition() is deprecated, please use updatePhysicsBody()");
             this.updatePhysicsBody();
         };
+        /**
+         * @Deprecated
+         * Calling this function is not needed anymore.
+         * The physics engine takes care of transofmration automatically.
+         */
         AbstractMesh.prototype.updatePhysicsBody = function () {
-            if (!this._physicImpostor) {
-                return;
-            }
-            this.getScene().getPhysicsEngine()._updateBodyPosition(this);
+            //Unneeded
         };
         Object.defineProperty(AbstractMesh.prototype, "checkCollisions", {
             // Collisions
@@ -865,8 +924,8 @@ var BABYLON;
             // Animations
             this.getScene().stopAnimation(this);
             // Physics
-            if (this.getPhysicsImpostor() !== BABYLON.PhysicsEngine.NoImpostor) {
-                this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
+            if (this.physicImpostor) {
+                this.physicImpostor.dispose(!doNotRecurse);
             }
             // Intersections in progress
             for (index = 0; index < this._intersectionsInProgress.length; index++) {

+ 114 - 67
src/Mesh/babylon.abstractMesh.ts

@@ -29,10 +29,10 @@
 
         // Properties
         public definedFacingForward = true; // orientation for POV movement & rotation
-        public position = new Vector3(0, 0, 0);
-        public rotation = new Vector3(0, 0, 0);
-        public rotationQuaternion: Quaternion;
-        public scaling = new Vector3(1, 1, 1);
+        private _position = new Vector3(0, 0, 0);
+        private _rotation = new Vector3(0, 0, 0);
+        private _rotationQuaternion: Quaternion;
+        private _scaling = new Vector3(1, 1, 1);
         public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
         public visibility = 1.0;
         public alphaIndex = Number.MAX_VALUE;
@@ -69,10 +69,8 @@
         public alwaysSelectAsActiveMesh = false;
 
         // Physics
-        public _physicImpostor = PhysicsEngine.NoImpostor;
-        public _physicsMass: number;
-        public _physicsFriction: number;
-        public _physicRestitution: number;
+        public physicImpostor: BABYLON.PhysicsImpostor;
+        //Deprecated, Legacy support
         public onPhysicsCollide: (collidedMesh: AbstractMesh, contact: any) => void; 
 
         // Collisions
@@ -158,6 +156,52 @@
             scene.addMesh(this);
         }
 
+        public get position(): Vector3 {
+            return this._position;
+        }
+
+        public set position(newPosition: Vector3) {
+            this._position = newPosition;
+            if (this.physicImpostor) {
+                this.physicImpostor.setTransformationUpdated(true);
+            }
+        }
+
+        public get rotation(): Vector3 {
+            if (this.rotationQuaternion) {
+                Tools.Warn("Quaternion rotation is used, the rotation value is probably wrong");
+            }
+            return this._rotation;
+        }
+
+        public set rotation(newRotation: Vector3) {
+            this._rotation = newRotation;
+            //check if rotationQuaternion exists, and if it does - update it!
+            if (this._rotationQuaternion) {
+                var len = this._rotation.length();
+                if (len) {
+                    this._rotationQuaternion.multiplyInPlace(BABYLON.Quaternion.RotationYawPitchRoll(this._rotation.y, this._rotation.x, this._rotation.z))
+                    this._rotation.copyFromFloats(0, 0, 0);
+                }
+            }
+        }
+
+        public get scaling(): Vector3 {
+            return this._scaling;
+        }
+
+        public set scaling(newScaling: Vector3) {
+            this._scaling = newScaling;
+        }
+
+        public get rotationQuaternion(): Quaternion {
+            return this._rotationQuaternion;
+        }
+
+        public set rotationQuaternion(quaternion: Quaternion) {
+            this._rotationQuaternion = quaternion;
+        }
+
         // Methods
         public updatePoseMatrix(matrix: Matrix) {
             this._poseMatrix.copyFrom(matrix);
@@ -692,74 +736,69 @@
             return this._boundingInfo.intersectsPoint(point);
         }
 
-        // Physics
-        public setPhysicsState(impostor?: any, options?: PhysicsBodyCreationOptions): any {
-            var physicsEngine = this.getScene().getPhysicsEngine();
-
-            if (!physicsEngine) {
-                return null;
-            }
-
-            impostor = impostor || PhysicsEngine.NoImpostor;
+        public getChildMeshes(): AbstractMesh[] {
+            return this.getScene().meshes.filter((m) => {
+                return m.parent === this;
+            });
+        }
 
-            if (impostor.impostor) {
-                // Old API
-                options = impostor;
-                impostor = impostor.impostor;
+        public getChildren(): Node[] {
+            var results = [];
+            for (var index = 0; index < this.getScene().meshes.length; index++) {
+                var mesh = this.getScene().meshes[index];
+                if (mesh.parent === this) {
+                    results.push(mesh);
+                }
             }
 
-            if (impostor === PhysicsEngine.NoImpostor) {
-                physicsEngine._unregisterMesh(this);
-                return null;
+            for (var index = 0; index < this.getScene().lights.length; index++) {
+                var light = this.getScene().lights[index];
+                if (light.parent === this) {
+                    results.push(mesh);
+                }
             }
 
-            if (!options) {
-                options = { mass: 0, friction: 0.2, restitution: 0.2 };
-            } else {
-                if (!options.mass && options.mass !== 0) options.mass = 0;
-                if (!options.friction && options.friction !== 0) options.friction = 0.2;
-                if (!options.restitution && options.restitution !== 0) options.restitution = 0.2;
+            for (var index = 0; index < this.getScene().cameras.length; index++) {
+                var camera = this.getScene().cameras[index];
+                if (camera.parent === this) {
+                    results.push(mesh);
+                }
             }
 
-            this._physicImpostor = impostor;
-            this._physicsMass = options.mass;
-            this._physicsFriction = options.friction;
-            this._physicRestitution = options.restitution;
-
-
-            return physicsEngine._registerMesh(this, impostor, options);
+            return results;
         }
 
-        public getPhysicsImpostor(): number {
-            if (!this._physicImpostor) {
-                return PhysicsEngine.NoImpostor;
-            }
+        // Physics
+        /**
+         *  @Deprecated. Use new PhysicsImpostor instead.
+         * */
+        public setPhysicsState(impostor?: any, options?: PhysicsImpostorParameters): any {
+            this.physicImpostor = new PhysicsImpostor(this, impostor, options);
+        }
 
-            return this._physicImpostor;
+        public getPhysicsImpostor(): PhysicsImpostor {
+            return this.physicImpostor;
         }
 
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("mass");
+         */
         public getPhysicsMass(): number {
-            if (!this._physicsMass) {
-                return 0;
-            }
-
-            return this._physicsMass;
+            return this.physicImpostor.getParam("mass")
         }
 
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("friction");
+         */
         public getPhysicsFriction(): number {
-            if (!this._physicsFriction) {
-                return 0;
-            }
-
-            return this._physicsFriction;
+            return this.physicImpostor.getParam("friction")
         }
 
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("restitution");
+         */
         public getPhysicsRestitution(): number {
-            if (!this._physicRestitution) {
-                return 0;
-            }
-
-            return this._physicRestitution;
+            return this.physicImpostor.getParam("resitution")
         }
 
         public getPositionInCameraSpace(camera?: Camera): Vector3 {
@@ -779,31 +818,39 @@
         }
 
         public applyImpulse(force: Vector3, contactPoint: Vector3): void {
-            if (!this._physicImpostor) {
+            if (!this.physicImpostor) {
                 return;
             }
 
-            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
+            this.physicImpostor.applyImpulse(force, contactPoint);
         }
 
         public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): void {
-            if (!this._physicImpostor) {
+            if (!this.physicImpostor || !otherMesh.physicImpostor) {
                 return;
             }
 
-            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2, options);
+            this.physicImpostor.createJoint(otherMesh.physicImpostor, PhysicsJoint.HingeJoint, {
+                mainPivot: pivot1,
+                connectedPivot: pivot2
+            })
         }
 
+        /**
+         * @Deprecated
+         */
         public updatePhysicsBodyPosition(): void {
             Tools.Warn("updatePhysicsBodyPosition() is deprecated, please use updatePhysicsBody()")
             this.updatePhysicsBody();
         }
 
+        /**
+         * @Deprecated
+         * Calling this function is not needed anymore. 
+         * The physics engine takes care of transofmration automatically.
+         */
         public updatePhysicsBody(): void {
-            if (!this._physicImpostor) {
-                return;
-            }
-            this.getScene().getPhysicsEngine()._updateBodyPosition(this);
+            //Unneeded
         }
 
 
@@ -1033,8 +1080,8 @@
             this.getScene().stopAnimation(this);
 
             // Physics
-            if (this.getPhysicsImpostor() !== PhysicsEngine.NoImpostor) {
-                this.setPhysicsState(PhysicsEngine.NoImpostor);
+            if (this.physicImpostor) {
+                this.physicImpostor.dispose(!doNotRecurse);
             }
 
             // Intersections in progress

+ 0 - 10
src/Mesh/babylon.mesh.js

@@ -713,16 +713,6 @@ var BABYLON;
             }
             return results;
         };
-        Mesh.prototype.getChildren = function () {
-            var results = [];
-            for (var index = 0; index < this.getScene().meshes.length; index++) {
-                var mesh = this.getScene().meshes[index];
-                if (mesh.parent === this) {
-                    results.push(mesh);
-                }
-            }
-            return results;
-        };
         Mesh.prototype._checkDelayState = function () {
             var _this = this;
             var that = this;

+ 0 - 12
src/Mesh/babylon.mesh.ts

@@ -819,18 +819,6 @@
             return results;
         }
 
-        public getChildren(): Node[] {
-            var results = [];
-            for (var index = 0; index < this.getScene().meshes.length; index++) {
-                var mesh = this.getScene().meshes[index];
-                if (mesh.parent === this) {
-                    results.push(mesh);
-                }
-            }
-
-            return results;
-        }
-
         public _checkDelayState(): void {
             var that = this;
             var scene = this.getScene();

+ 567 - 132
src/Physics/Plugins/babylon.cannonJSPlugin.js

@@ -1,184 +1,192 @@
 var BABYLON;
 (function (BABYLON) {
-    var CannonJSPlugin = (function () {
-        function CannonJSPlugin(_useDeltaForWorldStep) {
-            if (_useDeltaForWorldStep === void 0) { _useDeltaForWorldStep = true; }
-            this._useDeltaForWorldStep = _useDeltaForWorldStep;
-            this._registeredMeshes = [];
-            this._physicsMaterials = [];
-            this._fixedTimeStep = 1 / 60;
-            //private _maxSubSteps : number = 15;
-            this.name = "CannonJS";
-            this.updateBodyPosition = function (mesh) {
-                for (var index = 0; index < this._registeredMeshes.length; index++) {
-                    var registeredMesh = this._registeredMeshes[index];
-                    if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                        var body = registeredMesh.body;
-                        var center = mesh.getBoundingInfo().boundingBox.center.clone();
-                        body.quaternion.copy(mesh.rotationQuaternion);
-                        if (registeredMesh.deltaRotation) {
-                            var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                            body.quaternion = body.quaternion.mult(tmpQ);
-                        }
-                        if (registeredMesh.type === CANNON.Shape.types.HEIGHTFIELD) {
-                            //calculate the correct body position:
-                            var rotationQuaternion = mesh.rotationQuaternion;
-                            mesh.rotationQuaternion = new BABYLON.Quaternion();
-                            mesh.computeWorldMatrix(true);
-                            //get original center with no rotation
-                            var center = mesh.getBoundingInfo().boundingBox.center.clone();
-                            var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
-                            //rotation is back
-                            mesh.rotationQuaternion = rotationQuaternion;
-                            //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                            var p = BABYLON.Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
-                            mesh.setPivotMatrix(p);
-                            mesh.computeWorldMatrix(true);
-                            //calculate the translation
-                            var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-                            center.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                            //add it inverted to the delta 
-                            registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
-                            registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
-                            mesh.setPivotMatrix(oldPivot);
-                            mesh.computeWorldMatrix(true);
-                        }
-                        else if (registeredMesh.type === CANNON.Shape.types.TRIMESH) {
-                            center.copyFromFloats(mesh.position.x, mesh.position.y, mesh.position.z);
-                        }
-                        body.position.set(center.x, center.y, center.z);
-                        return;
-                    }
-                }
-            };
+    /*interface IRegisteredMesh {
+        mesh: AbstractMesh;
+        body: any; //Cannon body
+        material: any;
+        delta: Vector3;
+        deltaRotation: Quaternion;
+        type: any;
+        collisionFunction?: (event: any) => void;
+
+    }*/
+    /*export class OldCannonJSPlugin {
+
+        private _world: any;
+        private _registeredMeshes: Array<IRegisteredMesh> = [];
+        private _physicsMaterials = [];
+        private _gravity: Vector3;
+        private _fixedTimeStep: number = 1 / 60;
+        //private _maxSubSteps : number = 15;
+
+        public name = "CannonJS";
+
+        public constructor(private _useDeltaForWorldStep: boolean = true) {
+
         }
-        CannonJSPlugin.prototype.initialize = function (iterations) {
-            if (iterations === void 0) { iterations = 10; }
+
+        public initialize(iterations: number = 10): void {
             this._world = new CANNON.World();
             this._world.broadphase = new CANNON.NaiveBroadphase();
             this._world.solver.iterations = iterations;
-        };
-        CannonJSPlugin.prototype._checkWithEpsilon = function (value) {
-            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
-        };
-        CannonJSPlugin.prototype.runOneStep = function (delta) {
-            var _this = this;
+        }
+
+        private _checkWithEpsilon(value: number): number {
+            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
+        }
+
+        public runOneStep(delta: number): void {
+
             this._world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
-            this._registeredMeshes.forEach(function (registeredMesh) {
+
+            this._registeredMeshes.forEach((registeredMesh) => {
+
                 // Body position
-                var bodyX = registeredMesh.body.position.x, bodyY = registeredMesh.body.position.y, bodyZ = registeredMesh.body.position.z;
+                var bodyX = registeredMesh.body.position.x,
+                    bodyY = registeredMesh.body.position.y,
+                    bodyZ = registeredMesh.body.position.z;
+
                 registeredMesh.mesh.position.x = bodyX + registeredMesh.delta.x;
                 registeredMesh.mesh.position.y = bodyY + registeredMesh.delta.y;
                 registeredMesh.mesh.position.z = bodyZ + registeredMesh.delta.z;
+
                 registeredMesh.mesh.rotationQuaternion.copyFrom(registeredMesh.body.quaternion);
                 if (registeredMesh.deltaRotation) {
                     registeredMesh.mesh.rotationQuaternion.multiplyInPlace(registeredMesh.deltaRotation);
                 }
+
                 //is the physics collision callback is set?
                 if (registeredMesh.mesh.onPhysicsCollide) {
                     if (!registeredMesh.collisionFunction) {
-                        registeredMesh.collisionFunction = function (e) {
+                        registeredMesh.collisionFunction = (e) => {
                             //find the mesh that collided with the registered mesh
-                            for (var idx = 0; idx < _this._registeredMeshes.length; idx++) {
-                                if (_this._registeredMeshes[idx].body == e.body) {
-                                    registeredMesh.mesh.onPhysicsCollide(_this._registeredMeshes[idx].mesh, e.contact);
+                            for (var idx = 0; idx < this._registeredMeshes.length; idx++) {
+                                if (this._registeredMeshes[idx].body == e.body) {
+                                    registeredMesh.mesh.onPhysicsCollide(this._registeredMeshes[idx].mesh, e.contact);
                                 }
                             }
-                        };
+                        }
                         registeredMesh.body.addEventListener("collide", registeredMesh.collisionFunction);
                     }
-                }
-                else {
+                } else {
                     //unregister, in case the function was removed for some reason
                     if (registeredMesh.collisionFunction) {
                         registeredMesh.body.removeEventListener("collide", registeredMesh.collisionFunction);
                     }
                 }
             });
-        };
-        CannonJSPlugin.prototype.setGravity = function (gravity) {
+        }
+
+        public setGravity(gravity: Vector3): void {
             this._gravity = gravity;
             this._world.gravity.set(gravity.x, gravity.y, gravity.z);
-        };
-        CannonJSPlugin.prototype.getGravity = function () {
+        }
+
+        public getGravity(): Vector3 {
             return this._gravity;
-        };
-        CannonJSPlugin.prototype.registerMesh = function (mesh, impostor, options) {
+        }
+
+        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsImpostorParameters): any {
             this.unregisterMesh(mesh);
+
             if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
             }
+
             mesh.computeWorldMatrix(true);
+
             var shape = this._createShape(mesh, impostor);
+
             return this._createRigidBodyFromShape(shape, mesh, options);
-        };
-        CannonJSPlugin.prototype._createShape = function (mesh, impostor) {
+        }
+
+        private _createShape(mesh: AbstractMesh, impostor: number) {
+        
             //get the correct bounding box
             var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
             mesh.computeWorldMatrix(true);
+
             var returnValue;
+
             switch (impostor) {
-                case BABYLON.PhysicsEngine.SphereImpostor:
+                case 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;
+
                     returnValue = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
+
                     break;
                 //TMP also for cylinder - TODO Cannon supports cylinder natively.
-                case BABYLON.PhysicsEngine.CylinderImpostor:
-                    BABYLON.Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
-                case BABYLON.PhysicsEngine.BoxImpostor:
+                case PhysicsEngine.CylinderImpostor:
+                    Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
+                case PhysicsEngine.BoxImpostor:
                     bbox = mesh.getBoundingInfo().boundingBox;
                     var min = bbox.minimumWorld;
                     var max = bbox.maximumWorld;
                     var box = max.subtract(min).scale(0.5);
                     returnValue = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
                     break;
-                case BABYLON.PhysicsEngine.PlaneImpostor:
-                    BABYLON.Tools.Warn("Attention, Cannon.js PlaneImposter might not behave as you wish. Consider using BoxImposter instead");
+                case PhysicsEngine.PlaneImpostor:
+                    Tools.Warn("Attention, Cannon.js PlaneImposter might not behave as you wish. Consider using BoxImposter instead");
                     returnValue = new CANNON.Plane();
                     break;
-                case BABYLON.PhysicsEngine.MeshImpostor:
-                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                case PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(VertexBuffer.PositionKind);
                     var rawFaces = mesh.getIndices();
-                    BABYLON.Tools.Warn("MeshImpostor only collides against spheres.");
+                    Tools.Warn("MeshImpostor only collides against spheres.");
                     returnValue = new CANNON.Trimesh(rawVerts, rawFaces); //this._createConvexPolyhedron(rawVerts, rawFaces, mesh);
                     break;
-                case BABYLON.PhysicsEngine.HeightmapImpostor:
+                case PhysicsEngine.HeightmapImpostor:
                     returnValue = this._createHeightmap(mesh);
                     break;
+
             }
+
             mesh.rotationQuaternion = oldQuaternion;
+
             return returnValue;
-        };
-        CannonJSPlugin.prototype._createConvexPolyhedron = function (rawVerts, rawFaces, mesh) {
+        }
+
+        private _createConvexPolyhedron(rawVerts: number[] | Float32Array, rawFaces: number[] | Int32Array, mesh: AbstractMesh): any {
             var verts = [], faces = [];
+
             mesh.computeWorldMatrix(true);
+
             //reuse this variable
-            var transformed = BABYLON.Vector3.Zero();
+            var transformed = Vector3.Zero();
             // Get vertices
             for (var i = 0; i < rawVerts.length; i += 3) {
-                BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
+                Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
                 verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
             }
+
             // Get faces
             for (var j = 0; j < rawFaces.length; j += 3) {
                 faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
             }
+
             var shape = new CANNON.ConvexPolyhedron(verts, faces);
+
             return shape;
-        };
-        CannonJSPlugin.prototype._createHeightmap = function (mesh, pointDepth) {
-            var pos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+        }
+
+        private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
+            var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
             var matrix = [];
+    
             //For now pointDepth will not be used and will be automatically calculated.
             //Future reference - try and find the best place to add a reference to the pointDepth variable.
             var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
+
             var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
+
             var elementSize = dim * 2 / arraySize;
+
             var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
+
             for (var i = 0; i < pos.length; i = i + 3) {
                 var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
                 var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
@@ -191,6 +199,8 @@ var BABYLON;
                 }
                 matrix[x][z] = Math.max(y, matrix[x][z]);
             }
+
+
             for (var x = 0; x <= arraySize; ++x) {
                 if (!matrix[x]) {
                     var loc = 1;
@@ -198,6 +208,7 @@ var BABYLON;
                         loc++;
                     }
                     matrix[x] = matrix[(x + loc) % arraySize].slice();
+                    //console.log("missing x", x);
                 }
                 for (var z = 0; z <= arraySize; ++z) {
                     if (!matrix[x][z]) {
@@ -207,48 +218,64 @@ var BABYLON;
                             newValue = matrix[x][(z + loc++) % arraySize];
                         }
                         matrix[x][z] = newValue;
+
                     }
                 }
             }
+
             var shape = new CANNON.Heightfield(matrix, {
                 elementSize: elementSize
             });
+            
             //For future reference, needed for body transformation
             shape.minY = minY;
+
             return shape;
-        };
-        CannonJSPlugin.prototype._addMaterial = function (friction, restitution) {
+        }
+
+        private _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("mat");
             this._physicsMaterials.push(currentMat);
+
             for (index = 0; index < this._physicsMaterials.length; index++) {
                 mat = this._physicsMaterials[index];
+
                 var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
+
                 this._world.addContactMaterial(contactMaterial);
             }
+
             return currentMat;
-        };
-        CannonJSPlugin.prototype._createRigidBodyFromShape = function (shape, mesh, options) {
+        }
+
+        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsImpostorParameters): any {
             if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
             }
+            
             // The delta between the mesh position and the mesh bounding box center
             var bbox = mesh.getBoundingInfo().boundingBox;
             var deltaPosition = mesh.position.subtract(bbox.center);
             var deltaRotation;
+
             var material = this._addMaterial(options.friction, options.restitution);
             var body = new CANNON.Body({
                 mass: options.mass,
                 material: material,
                 position: new CANNON.Vec3(bbox.center.x, bbox.center.y, bbox.center.z)
             });
+
             body.quaternion = new CANNON.Quaternion(mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z, mesh.rotationQuaternion.w);
             //is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
             if (shape.type === CANNON.Shape.types.PLANE || shape.type === CANNON.Shape.types.HEIGHTFIELD) {
@@ -256,59 +283,81 @@ var BABYLON;
                 var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                 body.quaternion = body.quaternion.mult(tmpQ);
                 //Invert! (Precalculated, 90 deg in X)
-                deltaRotation = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+                deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
             }
+            
             //If it is a heightfield, if should be centered.
             if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
+                
                 //calculate the correct body position:
                 var rotationQuaternion = mesh.rotationQuaternion;
-                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.rotationQuaternion = new Quaternion();
                 mesh.computeWorldMatrix(true);
+                
                 //get original center with no rotation
                 var center = mesh.getBoundingInfo().boundingBox.center.clone();
-                var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
+
+                var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
+                
                 //rotation is back
                 mesh.rotationQuaternion = rotationQuaternion;
+        
                 //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                var p = BABYLON.Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
                 mesh.setPivotMatrix(p);
                 mesh.computeWorldMatrix(true);
+        
                 //calculate the translation
                 var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+
                 body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                //add it inverted to the delta 
+                //add it inverted to the delta
                 deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
                 deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+
                 mesh.setPivotMatrix(oldPivot);
                 mesh.computeWorldMatrix(true);
+            } else if (shape.type === CANNON.Shape.types.TRIMESH) {
+                deltaPosition = Vector3.Zero();
             }
-            else if (shape.type === CANNON.Shape.types.TRIMESH) {
-                deltaPosition = BABYLON.Vector3.Zero();
-            }
+            
             //add the shape
             body.addShape(shape);
+
             this._world.add(body);
+
             this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation, type: shape.type });
+
             return body;
-        };
-        CannonJSPlugin.prototype.registerMeshesAsCompound = function (parts, options) {
+        }
+
+        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
+
             var initialMesh = parts[0].mesh;
+
             this.unregisterMesh(initialMesh);
+
             initialMesh.computeWorldMatrix(true);
+
             var initialShape = this._createShape(initialMesh, parts[0].impostor);
             var body = this._createRigidBodyFromShape(initialShape, initialMesh, options);
+
             for (var index = 1; index < parts.length; index++) {
                 var mesh = parts[index].mesh;
                 mesh.computeWorldMatrix(true);
                 var shape = this._createShape(mesh, parts[index].impostor);
                 var localPosition = mesh.position;
+
                 body.addShape(shape, new CANNON.Vec3(localPosition.x, localPosition.y, localPosition.z));
             }
+
             return body;
-        };
-        CannonJSPlugin.prototype._unbindBody = function (body) {
+        }
+
+        private _unbindBody(body): void {
             for (var index = 0; index < this._registeredMeshes.length; index++) {
                 var registeredMesh = this._registeredMeshes[index];
+
                 if (registeredMesh.body === body) {
                     this._world.remove(registeredMesh.body);
                     registeredMesh.body = null;
@@ -316,65 +365,132 @@ var BABYLON;
                     registeredMesh.deltaRotation = null;
                 }
             }
-        };
-        CannonJSPlugin.prototype.unregisterMesh = function (mesh) {
+        }
+
+        public unregisterMesh(mesh: AbstractMesh): 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._unbindBody(registeredMesh.body);
                     }
+
                     this._registeredMeshes.splice(index, 1);
                     return;
                 }
             }
-        };
-        CannonJSPlugin.prototype.applyImpulse = function (mesh, force, contactPoint) {
+        }
+
+        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
             var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
             var impulse = new CANNON.Vec3(force.x, force.y, force.z);
+
             for (var index = 0; index < this._registeredMeshes.length; index++) {
                 var registeredMesh = this._registeredMeshes[index];
+
                 if (registeredMesh.mesh === mesh) {
                     registeredMesh.body.applyImpulse(impulse, worldPoint);
                     return;
                 }
             }
-        };
-        CannonJSPlugin.prototype.createLink = function (mesh1, mesh2, pivot1, pivot2) {
+        }
+
+        public updateBodyPosition = function(mesh: AbstractMesh): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
+                    var body = registeredMesh.body;
+
+                    var center = mesh.getBoundingInfo().boundingBox.center.clone();
+
+                    body.quaternion.copy(mesh.rotationQuaternion);
+
+                    if (registeredMesh.deltaRotation) {
+                        var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
+                        body.quaternion = body.quaternion.mult(tmpQ);
+                    }
+
+                    if (registeredMesh.type === CANNON.Shape.types.HEIGHTFIELD) {
+                        //calculate the correct body position:
+                        var rotationQuaternion = mesh.rotationQuaternion;
+                        mesh.rotationQuaternion = new Quaternion();
+                        mesh.computeWorldMatrix(true);
+                        
+                        //get original center with no rotation
+                        var center = mesh.getBoundingInfo().boundingBox.center.clone();
+
+                        var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
+                        
+                        //rotation is back
+                        mesh.rotationQuaternion = rotationQuaternion;
+                
+                        //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                        var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                        mesh.setPivotMatrix(p);
+                        mesh.computeWorldMatrix(true);
+                
+                        //calculate the translation
+                        var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+
+                        center.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                        //add it inverted to the delta
+                        registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                        registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+                        mesh.setPivotMatrix(oldPivot);
+                        mesh.computeWorldMatrix(true);
+                    } else if (registeredMesh.type === CANNON.Shape.types.TRIMESH) {
+                        center.copyFromFloats(mesh.position.x, mesh.position.y, mesh.position.z);
+                    }
+
+                    body.position.set(center.x, center.y, center.z);
+
+                    return;
+                }
+            }
+        }
+
+        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean {
             var body1 = null, body2 = null;
             for (var index = 0; index < this._registeredMeshes.length; index++) {
                 var registeredMesh = this._registeredMeshes[index];
+
                 if (registeredMesh.mesh === mesh1) {
                     body1 = registeredMesh.body;
-                    if (body2)
-                        break;
-                }
-                else if (registeredMesh.mesh === mesh2) {
+                    if (body2) break;
+                } else if (registeredMesh.mesh === mesh2) {
                     body2 = registeredMesh.body;
-                    if (body1)
-                        break;
+                    if (body1) break;
                 }
             }
+
             if (!body1 || !body2) {
                 return false;
             }
+
             var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.y, pivot1.z), body2, new CANNON.Vec3(pivot2.x, pivot2.y, pivot2.z));
             this._world.addConstraint(constraint);
+
             return true;
-        };
-        CannonJSPlugin.prototype.dispose = function () {
+        }
+
+        public dispose(): void {
             while (this._registeredMeshes.length) {
                 this.unregisterMesh(this._registeredMeshes[0].mesh);
             }
-        };
-        CannonJSPlugin.prototype.isSupported = function () {
+        }
+
+        public isSupported(): boolean {
             return window.CANNON !== undefined;
-        };
-        CannonJSPlugin.prototype.getWorldObject = function () {
+        }
+
+        public getWorldObject(): any {
             return this._world;
-        };
-        CannonJSPlugin.prototype.getPhysicsBodyOfMesh = function (mesh) {
+        }
+
+        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
             for (var index = 0; index < this._registeredMeshes.length; index++) {
                 var registeredMesh = this._registeredMeshes[index];
                 if (registeredMesh.mesh === mesh) {
@@ -382,6 +498,325 @@ var BABYLON;
                 }
             }
             return null;
+        }
+    }*/
+    var CannonJSPlugin = (function () {
+        function CannonJSPlugin(_useDeltaForWorldStep, iterations) {
+            if (_useDeltaForWorldStep === void 0) { _useDeltaForWorldStep = true; }
+            if (iterations === void 0) { iterations = 10; }
+            this._useDeltaForWorldStep = _useDeltaForWorldStep;
+            this.name = "CannonJSPlugin";
+            this._physicsMaterials = [];
+            this._fixedTimeStep = 1 / 60;
+            if (!this.isSupported()) {
+                BABYLON.Tools.Error("CannonJS is not available. Please make sure you included the js file.");
+                return;
+            }
+            this.world = new CANNON.World();
+            this.world.broadphase = new CANNON.NaiveBroadphase();
+            this.world.solver.iterations = iterations;
+        }
+        CannonJSPlugin.prototype.setGravity = function (gravity) {
+            this.world.gravity.copy(gravity);
+        };
+        CannonJSPlugin.prototype.executeStep = function (delta, impostors) {
+            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
+        };
+        CannonJSPlugin.prototype.applyImpulse = function (impostor, force, contactPoint) {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
+            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
+            impostor.physicsBody.applyImpulse(impulse, worldPoint);
+        };
+        CannonJSPlugin.prototype.applyForce = function (impostor, force, contactPoint) {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
+            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
+            impostor.physicsBody.applyImpulse(impulse, worldPoint);
+        };
+        CannonJSPlugin.prototype.generatePhysicsBody = function (impostor) {
+            //parent-child relationship. Does this impostor has a parent impostor?
+            if (impostor.parent) {
+                if (impostor.physicsBody) {
+                    this.removePhysicsBody(impostor);
+                    //TODO is that needed?
+                    impostor.forceUpdate();
+                }
+                return;
+            }
+            //should a new body be created for this impostor?
+            if (impostor.isBodyInitRequired()) {
+                if (!impostor.mesh.rotationQuaternion) {
+                    impostor.mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(impostor.mesh.rotation.y, impostor.mesh.rotation.x, impostor.mesh.rotation.z);
+                }
+                var shape = this._createShape(impostor);
+                //unregister events, if body is being changed
+                var oldBody = impostor.physicsBody;
+                if (oldBody) {
+                    this.removePhysicsBody(oldBody);
+                }
+                //create the body and material
+                var material = this._addMaterial(impostor.getOptions().friction, impostor.getOptions().restitution);
+                var bodyCreationObject = {
+                    mass: impostor.getOptions().mass,
+                    material: material
+                };
+                // A simple extend, in case native options were used.
+                var nativeOptions = impostor.getOptions().nativeOptions;
+                for (var key in nativeOptions) {
+                    if (nativeOptions.hasOwnProperty(key)) {
+                        bodyCreationObject[key] = nativeOptions[key];
+                    }
+                }
+                impostor.physicsBody = new CANNON.Body(bodyCreationObject);
+                impostor.physicsBody.addEventListener("collide", impostor.onCollide);
+                this.world.addEventListener("preStep", impostor.beforeStep);
+                this.world.addEventListener("postStep", impostor.afterStep);
+                impostor.physicsBody.addShape(shape);
+                //try to keep the body moving in the right direction by taking old properties.
+                //Should be tested!
+                if (oldBody) {
+                    ['force', 'torque', 'velocity', 'angularVelocity'].forEach(function (param) {
+                        impostor.physicsBody[param].copy(oldBody[param]);
+                    });
+                }
+                this._processChildMeshes(impostor);
+            }
+            //now update the body's transformation
+            this._updatePhysicsBodyTransformation(impostor);
+        };
+        CannonJSPlugin.prototype._processChildMeshes = function (mainImpostor) {
+            var _this = this;
+            var meshChildren = mainImpostor.mesh.getChildMeshes();
+            if (meshChildren.length) {
+                var processMesh = function (localPosition, mesh) {
+                    var childImpostor = mesh.getPhysicsImpostor();
+                    if (childImpostor) {
+                        var parent = childImpostor.parent;
+                        if (parent !== mainImpostor) {
+                            var localPosition = mesh.position;
+                            if (childImpostor.physicsBody) {
+                                _this.removePhysicsBody(childImpostor);
+                                childImpostor.physicsBody = null;
+                            }
+                            childImpostor.parent = mainImpostor;
+                            childImpostor.resetUpdateFlags();
+                            mainImpostor.physicsBody.addShape(_this._createShape(childImpostor), new CANNON.Vec3(localPosition.x, localPosition.y, localPosition.z));
+                            //Add the mass of the children.
+                            mainImpostor.physicsBody.mass += childImpostor.getParam("mass");
+                        }
+                    }
+                    mesh.getChildMeshes().forEach(processMesh.bind(_this, mesh.position));
+                };
+                meshChildren.forEach(processMesh.bind(this, BABYLON.Vector3.Zero()));
+            }
+        };
+        CannonJSPlugin.prototype.removePhysicsBody = function (impostor) {
+            impostor.physicsBody.removeEventListener("collide", impostor.onCollide);
+            this.world.removeEventListener("preStep", impostor.beforeStep);
+            this.world.removeEventListener("postStep", impostor.afterStep);
+            this.world.remove(impostor.physicsBody);
+        };
+        CannonJSPlugin.prototype.generateJoint = function (impostorJoint) {
+            var mainBody = impostorJoint.mainImpostor.physicsBody;
+            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
+            var constraint;
+            var jointData = impostorJoint.joint.jointData;
+            var constraintData = {
+                pivotA: jointData.mainPivot ? new CANNON.Vec3().copy(jointData.mainPivot) : null,
+                pivotB: jointData.connectedPivot ? new CANNON.Vec3().copy(jointData.connectedPivot) : null,
+                axisA: jointData.mainAxis ? new CANNON.Vec3().copy(jointData.mainAxis) : null,
+                axisB: jointData.connectedAxis ? new CANNON.Vec3().copy(jointData.connectedAxis) : null,
+                maxForce: jointData.nativeParams.maxForce
+            };
+            switch (impostorJoint.joint.type) {
+                case BABYLON.PhysicsJoint.HingeJoint:
+                    constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
+                    break;
+                default:
+                    constraint = new CANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
+                    break;
+            }
+            this.world.addConstraint(constraint);
+            return true;
+        };
+        CannonJSPlugin.prototype.removeJoint = function (joint) {
+            //TODO
+        };
+        CannonJSPlugin.prototype._addMaterial = function (friction, restitution) {
+            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("mat");
+            this._physicsMaterials.push(currentMat);
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
+                this.world.addContactMaterial(contactMaterial);
+            }
+            return currentMat;
+        };
+        CannonJSPlugin.prototype._checkWithEpsilon = function (value) {
+            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        };
+        CannonJSPlugin.prototype._createShape = function (impostor) {
+            var mesh = impostor.mesh;
+            //get the correct bounding box
+            var oldQuaternion = mesh.rotationQuaternion;
+            mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+            mesh.computeWorldMatrix(true);
+            var returnValue;
+            switch (impostor.type) {
+                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;
+                    returnValue = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
+                    break;
+                //TMP also for cylinder - TODO Cannon supports cylinder natively.
+                case BABYLON.PhysicsEngine.CylinderImpostor:
+                    BABYLON.Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
+                case BABYLON.PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min).scale(0.5);
+                    returnValue = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
+                    break;
+                case BABYLON.PhysicsEngine.PlaneImpostor:
+                    BABYLON.Tools.Warn("Attention, PlaneImposter might not behave as you expect. Consider using BoxImposter instead");
+                    returnValue = new CANNON.Plane();
+                    break;
+                case BABYLON.PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                    var rawFaces = mesh.getIndices();
+                    BABYLON.Tools.Warn("MeshImpostor only collides against spheres.");
+                    returnValue = new CANNON.Trimesh(rawVerts, rawFaces);
+                    break;
+                case BABYLON.PhysicsEngine.HeightmapImpostor:
+                    returnValue = this._createHeightmap(mesh);
+                    break;
+            }
+            mesh.rotationQuaternion = oldQuaternion;
+            return returnValue;
+        };
+        CannonJSPlugin.prototype._createHeightmap = function (mesh, pointDepth) {
+            var pos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            var matrix = [];
+            //For now pointDepth will not be used and will be automatically calculated.
+            //Future reference - try and find the best place to add a reference to the pointDepth variable.
+            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
+            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
+            var elementSize = dim * 2 / arraySize;
+            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
+            for (var i = 0; i < pos.length; i = i + 3) {
+                var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
+                var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
+                var y = pos[i + 1] + minY;
+                if (!matrix[x]) {
+                    matrix[x] = [];
+                }
+                if (!matrix[x][z]) {
+                    matrix[x][z] = y;
+                }
+                matrix[x][z] = Math.max(y, matrix[x][z]);
+            }
+            for (var x = 0; x <= arraySize; ++x) {
+                if (!matrix[x]) {
+                    var loc = 1;
+                    while (!matrix[(x + loc) % arraySize]) {
+                        loc++;
+                    }
+                    matrix[x] = matrix[(x + loc) % arraySize].slice();
+                }
+                for (var z = 0; z <= arraySize; ++z) {
+                    if (!matrix[x][z]) {
+                        var loc = 1;
+                        var newValue;
+                        while (newValue === undefined) {
+                            newValue = matrix[x][(z + loc++) % arraySize];
+                        }
+                        matrix[x][z] = newValue;
+                    }
+                }
+            }
+            var shape = new CANNON.Heightfield(matrix, {
+                elementSize: elementSize
+            });
+            //For future reference, needed for body transformation
+            shape.minY = minY;
+            return shape;
+        };
+        CannonJSPlugin.prototype._updatePhysicsBodyTransformation = function (impostor) {
+            var mesh = impostor.mesh;
+            //make sure it is updated...
+            impostor.mesh.computeWorldMatrix(true);
+            // The delta between the mesh position and the mesh bounding box center
+            var bbox = mesh.getBoundingInfo().boundingBox;
+            var deltaPosition = mesh.position.subtract(bbox.center);
+            var deltaRotation;
+            var quaternion = mesh.rotationQuaternion;
+            var position = mesh.getBoundingInfo().boundingBox.center.clone();
+            //is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
+            if (impostor.type === BABYLON.PhysicsEngine.PlaneImpostor || impostor.type === BABYLON.PhysicsEngine.HeightmapImpostor) {
+                //-90 DEG in X, precalculated
+                var tmpQ = new BABYLON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
+                quaternion = quaternion.multiply(tmpQ);
+                //Invert! (Precalculated, 90 deg in X)
+                deltaRotation = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+            }
+            //If it is a heightfield, if should be centered.
+            if (impostor.type === BABYLON.PhysicsEngine.HeightmapImpostor) {
+                //calculate the correct body position:
+                var rotationQuaternion = mesh.rotationQuaternion;
+                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.computeWorldMatrix(true);
+                //get original center with no rotation
+                var center = mesh.getBoundingInfo().boundingBox.center.clone();
+                var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
+                //rotation is back
+                mesh.rotationQuaternion = rotationQuaternion;
+                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                var p = BABYLON.Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                mesh.setPivotMatrix(p);
+                mesh.computeWorldMatrix(true);
+                //calculate the translation
+                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+                position.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                //add it inverted to the delta 
+                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+                mesh.setPivotMatrix(oldPivot);
+                mesh.computeWorldMatrix(true);
+            }
+            else if (impostor.type === BABYLON.PhysicsEngine.MeshImpostor) {
+                deltaPosition = BABYLON.Vector3.Zero();
+                position.copyFrom(mesh.position);
+            }
+            impostor.setDeltaPosition(deltaPosition);
+            impostor.setDeltaRotation(deltaRotation);
+            //Now update the impostor object
+            impostor.physicsBody.position.copy(position);
+            impostor.physicsBody.quaternion.copy(quaternion);
+        };
+        CannonJSPlugin.prototype.isSupported = function () {
+            return window.CANNON !== undefined;
+        };
+        //TODO 
+        CannonJSPlugin.prototype.supports = function (feature) {
+            switch (feature) {
+                case BABYLON.PhysicsFeature.PIVOT_IN_JOINT:
+                    return false;
+                case BABYLON.PhysicsFeature.TRIMESH:
+                    return true;
+            }
+        };
+        CannonJSPlugin.prototype.dispose = function () {
+            //nothing to do, actually.
         };
         return CannonJSPlugin;
     })();

+ 394 - 8
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     declare var CANNON;
 
-    interface IRegisteredMesh {
+    /*interface IRegisteredMesh {
         mesh: AbstractMesh;
         body: any; //Cannon body
         material: any;
@@ -10,9 +10,9 @@
         type: any;
         collisionFunction?: (event: any) => void;
 
-    }
+    }*/
 
-    export class CannonJSPlugin implements IPhysicsEnginePlugin {
+    /*export class OldCannonJSPlugin {
 
         private _world: any;
         private _registeredMeshes: Array<IRegisteredMesh> = [];
@@ -88,7 +88,7 @@
             return this._gravity;
         }
 
-        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsBodyCreationOptions): any {
+        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsImpostorParameters): any {
             this.unregisterMesh(mesh);
 
             if (!mesh.rotationQuaternion) {
@@ -261,7 +261,7 @@
             return currentMat;
         }
 
-        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsBodyCreationOptions): any {
+        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsImpostorParameters): any {
             if (!mesh.rotationQuaternion) {
                 mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
             }
@@ -293,7 +293,7 @@
                 
                 //calculate the correct body position:
                 var rotationQuaternion = mesh.rotationQuaternion;
-                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.rotationQuaternion = new Quaternion();
                 mesh.computeWorldMatrix(true);
                 
                 //get original center with no rotation
@@ -399,7 +399,7 @@
             }
         }
 
-        public updateBodyPosition = function (mesh: AbstractMesh): void {
+        public updateBodyPosition = function(mesh: AbstractMesh): void {
             for (var index = 0; index < this._registeredMeshes.length; index++) {
                 var registeredMesh = this._registeredMeshes[index];
                 if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
@@ -417,7 +417,7 @@
                     if (registeredMesh.type === CANNON.Shape.types.HEIGHTFIELD) {
                         //calculate the correct body position:
                         var rotationQuaternion = mesh.rotationQuaternion;
-                        mesh.rotationQuaternion = new BABYLON.Quaternion();
+                        mesh.rotationQuaternion = new Quaternion();
                         mesh.computeWorldMatrix(true);
                         
                         //get original center with no rotation
@@ -501,6 +501,392 @@
             }
             return null;
         }
+    }*/
+
+    export class CannonJSPlugin implements IPhysicsEnginePlugin {
+
+        public world: any; //CANNON.World
+        public name: string = "CannonJSPlugin";
+        private _physicsMaterials = [];
+        private _fixedTimeStep: number = 1 / 60;
+
+        public constructor(private _useDeltaForWorldStep: boolean = true, iterations: number = 10) {
+            if (!this.isSupported()) {
+                Tools.Error("CannonJS is not available. Please make sure you included the js file.");
+                return;
+            }
+            this.world = new CANNON.World();
+            this.world.broadphase = new CANNON.NaiveBroadphase();
+            this.world.solver.iterations = iterations;
+        }
+
+        public setGravity(gravity: Vector3): void {
+            this.world.gravity.copy(gravity);
+        }
+
+        public executeStep(delta: number, impostors: Array<PhysicsImpostor>): void {
+            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
+        }
+
+        public applyImpulse(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3) {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
+            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
+
+            impostor.physicsBody.applyImpulse(impulse, worldPoint);
+        }
+
+        public applyForce(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3) {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
+            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
+
+            impostor.physicsBody.applyImpulse(impulse, worldPoint);
+        }
+
+        public generatePhysicsBody(impostor: PhysicsImpostor) {
+            //parent-child relationship. Does this impostor has a parent impostor?
+            if (impostor.parent) {
+                if (impostor.physicsBody) {
+                    this.removePhysicsBody(impostor);
+                    //TODO is that needed?
+                    impostor.forceUpdate();
+                }
+                return;
+            }
+
+            //should a new body be created for this impostor?
+            if (impostor.isBodyInitRequired()) {
+                if (!impostor.mesh.rotationQuaternion) {
+                    impostor.mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(impostor.mesh.rotation.y, impostor.mesh.rotation.x, impostor.mesh.rotation.z);
+                }
+
+                var shape = this._createShape(impostor);
+                
+                //unregister events, if body is being changed
+                var oldBody = impostor.physicsBody;
+                if (oldBody) {
+                    this.removePhysicsBody(oldBody);
+                }
+                
+                //create the body and material
+                var material = this._addMaterial(impostor.getOptions().friction, impostor.getOptions().restitution);
+
+                var bodyCreationObject = {
+                    mass: impostor.getOptions().mass,
+                    material: material
+                };
+                // A simple extend, in case native options were used.
+                var nativeOptions = impostor.getOptions().nativeOptions;
+                for (var key in nativeOptions) {
+                    if (nativeOptions.hasOwnProperty(key)) {
+                        bodyCreationObject[key] = nativeOptions[key];
+                    }
+                }
+                impostor.physicsBody = new CANNON.Body(bodyCreationObject);
+                impostor.physicsBody.addEventListener("collide", impostor.onCollide);
+                this.world.addEventListener("preStep", impostor.beforeStep);
+                this.world.addEventListener("postStep", impostor.afterStep);
+                impostor.physicsBody.addShape(shape);
+                this.world.add(impostor.physicsBody);
+                
+                //try to keep the body moving in the right direction by taking old properties.
+                //Should be tested!
+                if (oldBody) {
+                    ['force', 'torque', 'velocity', 'angularVelocity'].forEach(function(param) {
+                        impostor.physicsBody[param].copy(oldBody[param]);
+                    });
+                }
+                this._processChildMeshes(impostor);
+            }
+
+            //now update the body's transformation
+            this._updatePhysicsBodyTransformation(impostor);
+        }
+
+        private _processChildMeshes(mainImpostor: PhysicsImpostor) {
+            var meshChildren = mainImpostor.mesh.getChildMeshes();
+            if (meshChildren.length) {
+                var processMesh = (localPosition: Vector3, mesh: AbstractMesh) => {
+                    var childImpostor = mesh.getPhysicsImpostor();
+                    if (childImpostor) {
+                        var parent = childImpostor.parent;
+                        if (parent !== mainImpostor) {
+                            var localPosition = mesh.position;
+                            if (childImpostor.physicsBody) {
+                                this.removePhysicsBody(childImpostor);
+                                childImpostor.physicsBody = null;
+                            }
+                            childImpostor.parent = mainImpostor;
+                            childImpostor.resetUpdateFlags();
+                            mainImpostor.physicsBody.addShape(this._createShape(childImpostor), new CANNON.Vec3(localPosition.x, localPosition.y, localPosition.z));
+                            //Add the mass of the children.
+                            mainImpostor.physicsBody.mass += childImpostor.getParam("mass");
+                        }
+                    }
+                    mesh.getChildMeshes().forEach(processMesh.bind(this, mesh.position));
+                }
+                meshChildren.forEach(processMesh.bind(this, Vector3.Zero()));
+            }
+        }
+
+        public removePhysicsBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.removeEventListener("collide", impostor.onCollide);
+            this.world.removeEventListener("preStep", impostor.beforeStep);
+            this.world.removeEventListener("postStep", impostor.afterStep);
+            this.world.remove(impostor.physicsBody);
+        }
+
+        public generateJoint(impostorJoint: PhysicsImpostorJoint) {
+            var mainBody = impostorJoint.mainImpostor.physicsBody;
+            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
+
+            var constraint;
+            var jointData = impostorJoint.joint.jointData;
+            var constraintData = {
+                pivotA: jointData.mainPivot ? new CANNON.Vec3().copy(jointData.mainPivot) : null,
+                pivotB: jointData.connectedPivot ? new CANNON.Vec3().copy(jointData.connectedPivot) : null,
+                axisA: jointData.mainAxis ? new CANNON.Vec3().copy(jointData.mainAxis) : null,
+                axisB: jointData.connectedAxis ? new CANNON.Vec3().copy(jointData.connectedAxis) : null,
+                maxForce: jointData.nativeParams.maxForce
+            };
+            switch (impostorJoint.joint.type) {
+                case PhysicsJoint.HingeJoint:
+                    constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
+                    break;
+                default:
+                    constraint = new CANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
+                    break;
+            }
+            this.world.addConstraint(constraint);
+
+            return true;
+        }
+
+        public removeJoint(joint: PhysicsImpostorJoint) {
+            //TODO
+        }
+
+        private _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("mat");
+            this._physicsMaterials.push(currentMat);
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+
+                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
+
+                this.world.addContactMaterial(contactMaterial);
+            }
+
+            return currentMat;
+        }
+
+        private _checkWithEpsilon(value: number): number {
+            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
+        }
+
+        private _createShape(impostor: PhysicsImpostor) {
+            var mesh = impostor.mesh;
+        
+            //get the correct bounding box
+            var oldQuaternion = mesh.rotationQuaternion;
+            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
+            mesh.computeWorldMatrix(true);
+
+            var returnValue;
+
+            switch (impostor.type) {
+                case 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;
+
+                    returnValue = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
+
+                    break;
+                //TMP also for cylinder - TODO Cannon supports cylinder natively.
+                case PhysicsEngine.CylinderImpostor:
+                    Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
+                case PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min).scale(0.5);
+                    returnValue = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
+                    break;
+                case PhysicsEngine.PlaneImpostor:
+                    Tools.Warn("Attention, PlaneImposter might not behave as you expect. Consider using BoxImposter instead");
+                    returnValue = new CANNON.Plane();
+                    break;
+                case PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(VertexBuffer.PositionKind);
+                    var rawFaces = mesh.getIndices();
+                    Tools.Warn("MeshImpostor only collides against spheres.");
+                    returnValue = new CANNON.Trimesh(rawVerts, rawFaces);
+                    break;
+                case PhysicsEngine.HeightmapImpostor:
+                    returnValue = this._createHeightmap(mesh);
+                    break;
+
+            }
+
+            mesh.rotationQuaternion = oldQuaternion;
+
+            return returnValue;
+        }
+
+        private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
+            var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
+            var matrix = [];
+    
+            //For now pointDepth will not be used and will be automatically calculated.
+            //Future reference - try and find the best place to add a reference to the pointDepth variable.
+            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
+
+            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
+
+            var elementSize = dim * 2 / arraySize;
+
+            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+            for (var i = 0; i < pos.length; i = i + 3) {
+                var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
+                var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
+                var y = pos[i + 1] + minY;
+                if (!matrix[x]) {
+                    matrix[x] = [];
+                }
+                if (!matrix[x][z]) {
+                    matrix[x][z] = y;
+                }
+                matrix[x][z] = Math.max(y, matrix[x][z]);
+            }
+
+
+            for (var x = 0; x <= arraySize; ++x) {
+                if (!matrix[x]) {
+                    var loc = 1;
+                    while (!matrix[(x + loc) % arraySize]) {
+                        loc++;
+                    }
+                    matrix[x] = matrix[(x + loc) % arraySize].slice();
+                    //console.log("missing x", x);
+                }
+                for (var z = 0; z <= arraySize; ++z) {
+                    if (!matrix[x][z]) {
+                        var loc = 1;
+                        var newValue;
+                        while (newValue === undefined) {
+                            newValue = matrix[x][(z + loc++) % arraySize];
+                        }
+                        matrix[x][z] = newValue;
+
+                    }
+                }
+            }
+
+            var shape = new CANNON.Heightfield(matrix, {
+                elementSize: elementSize
+            });
+            
+            //For future reference, needed for body transformation
+            shape.minY = minY;
+
+            return shape;
+        }
+
+        private _updatePhysicsBodyTransformation(impostor: PhysicsImpostor) {
+            var mesh = impostor.mesh;
+            //make sure it is updated...
+            impostor.mesh.computeWorldMatrix(true);
+            // The delta between the mesh position and the mesh bounding box center
+            var bbox = mesh.getBoundingInfo().boundingBox;
+            var deltaPosition = mesh.position.subtract(bbox.center);
+            var deltaRotation;
+
+            var quaternion = mesh.rotationQuaternion;
+            var position = mesh.getBoundingInfo().boundingBox.center.clone();
+            //is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
+            if (impostor.type === PhysicsEngine.PlaneImpostor || impostor.type === PhysicsEngine.HeightmapImpostor) {
+                //-90 DEG in X, precalculated
+                var tmpQ = new Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
+                quaternion = quaternion.multiply(tmpQ);
+                //Invert! (Precalculated, 90 deg in X)
+                deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+            }
+            
+            //If it is a heightfield, if should be centered.
+            if (impostor.type === PhysicsEngine.HeightmapImpostor) {
+                
+                //calculate the correct body position:
+                var rotationQuaternion = mesh.rotationQuaternion;
+                mesh.rotationQuaternion = new Quaternion();
+                mesh.computeWorldMatrix(true);
+                
+                //get original center with no rotation
+                var center = mesh.getBoundingInfo().boundingBox.center.clone();
+
+                var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
+                
+                //rotation is back
+                mesh.rotationQuaternion = rotationQuaternion;
+        
+                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                mesh.setPivotMatrix(p);
+                mesh.computeWorldMatrix(true);
+        
+                //calculate the translation
+                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+
+                position.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                //add it inverted to the delta 
+                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+                mesh.setPivotMatrix(oldPivot);
+                mesh.computeWorldMatrix(true);
+            } else if (impostor.type === PhysicsEngine.MeshImpostor) {
+                deltaPosition = Vector3.Zero();
+                position.copyFrom(mesh.position);
+            }
+            
+            
+            impostor.setDeltaPosition(deltaPosition);
+            impostor.setDeltaRotation(deltaRotation);
+            //Now update the impostor object
+            impostor.physicsBody.position.copy(position);
+            impostor.physicsBody.quaternion.copy(quaternion);
+        }
+
+        public isSupported(): boolean {
+            return window.CANNON !== undefined;
+        }
+
+        //TODO 
+        public supports(feature: PhysicsFeature) {
+            switch (feature) {
+                case PhysicsFeature.PIVOT_IN_JOINT:
+                    return false;
+                case PhysicsFeature.TRIMESH:
+                    return true;
+            }
+        }
+
+        public dispose() {
+            //nothing to do, actually.
+        }
     }
 }
 

+ 4 - 4
src/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     declare var OIMO;
 
-    export class OimoJSPlugin implements IPhysicsEnginePlugin {
+    export class OimoJSPlugin {
         private _world;
         private _registeredMeshes = [];
 
@@ -26,7 +26,7 @@ module BABYLON {
             return this._gravity;
         }
 
-        public registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
+        public registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsImpostorParameters): any {
             this.unregisterMesh(mesh);
 
             if (!mesh.rotationQuaternion) {
@@ -112,7 +112,7 @@ module BABYLON {
             return body;
         }
 
-        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
+        public registerMeshesAsCompound(parts: any[], options: PhysicsImpostorParameters): any {
             var types = [],
                 sizes = [],
                 positions = [],
@@ -153,7 +153,7 @@ module BABYLON {
             return body;
         }
 
-        private _createBodyAsCompound(part: PhysicsCompoundBodyPart, options: PhysicsBodyCreationOptions, initialMesh: AbstractMesh): any {
+        private _createBodyAsCompound(part: any, options: PhysicsImpostorParameters, initialMesh: AbstractMesh): any {
             var mesh = part.mesh;
 
             if (!mesh.rotationQuaternion) {

+ 91 - 56
src/Physics/babylon.physicsEngine.js

@@ -1,75 +1,110 @@
 var BABYLON;
 (function (BABYLON) {
     var PhysicsEngine = (function () {
-        function PhysicsEngine(plugin) {
-            this._currentPlugin = plugin || new BABYLON.OimoJSPlugin();
-        }
-        PhysicsEngine.prototype._initialize = function (gravity) {
-            this._currentPlugin.initialize();
-            this._setGravity(gravity);
-        };
-        PhysicsEngine.prototype._runOneStep = function (delta) {
-            if (delta > 0.1) {
-                delta = 0.1;
-            }
-            else if (delta <= 0) {
-                delta = 1.0 / 60.0;
+        function PhysicsEngine(gravity, _physicsPlugin) {
+            if (gravity === void 0) { gravity = new BABYLON.Vector3(0, -9.807, 0); }
+            if (_physicsPlugin === void 0) { _physicsPlugin = new BABYLON.CannonJSPlugin(); }
+            this._physicsPlugin = _physicsPlugin;
+            //new methods and parameters
+            this._impostors = [];
+            this._joints = [];
+            if (!this._physicsPlugin.isSupported()) {
+                throw new Error("Physics Engine " + this._physicsPlugin.name + " cannot be found. "
+                    + "Please make sure it is included.");
             }
-            this._currentPlugin.runOneStep(delta);
-        };
-        PhysicsEngine.prototype._setGravity = function (gravity) {
-            this.gravity = gravity || new BABYLON.Vector3(0, -9.807, 0);
-            this._currentPlugin.setGravity(this.gravity);
-        };
-        PhysicsEngine.prototype._getGravity = function () {
-            return this._currentPlugin.getGravity();
-        };
-        PhysicsEngine.prototype._registerMesh = function (mesh, impostor, options) {
-            return this._currentPlugin.registerMesh(mesh, impostor, options);
-        };
-        PhysicsEngine.prototype._registerMeshesAsCompound = function (parts, options) {
-            return this._currentPlugin.registerMeshesAsCompound(parts, options);
+            this.setGravity(gravity);
+        }
+        PhysicsEngine.prototype.setGravity = function (gravity) {
+            this.gravity = gravity;
+            this._physicsPlugin.setGravity(this.gravity);
         };
-        PhysicsEngine.prototype._unregisterMesh = function (mesh) {
-            this._currentPlugin.unregisterMesh(mesh);
+        PhysicsEngine.prototype.dispose = function () {
+            this._impostors.forEach(function (impostor) {
+                impostor.dispose();
+            });
+            this._physicsPlugin.dispose();
         };
-        PhysicsEngine.prototype._applyImpulse = function (mesh, force, contactPoint) {
-            this._currentPlugin.applyImpulse(mesh, force, contactPoint);
+        PhysicsEngine.prototype.getPhysicsPluginName = function () {
+            return this._physicsPlugin.name;
         };
-        PhysicsEngine.prototype._createLink = function (mesh1, mesh2, pivot1, pivot2, options) {
-            return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2, options);
+        PhysicsEngine.prototype.addImpostor = function (impostor) {
+            this._impostors.push(impostor);
         };
-        PhysicsEngine.prototype._updateBodyPosition = function (mesh) {
-            this._currentPlugin.updateBodyPosition(mesh);
+        PhysicsEngine.prototype.removeImpostor = function (impostor) {
+            var index = this._impostors.indexOf(impostor);
+            if (index > -1) {
+                var removed = this._impostors.splice(index, 1);
+                //Is it needed?
+                if (removed.length) {
+                    this._physicsPlugin.removePhysicsBody(removed[0]);
+                }
+            }
         };
-        PhysicsEngine.prototype.dispose = function () {
-            this._currentPlugin.dispose();
+        PhysicsEngine.prototype.addJoint = function (mainImpostor, connectedImpostor, joint) {
+            this._joints.push({
+                mainImpostor: mainImpostor,
+                connectedImpostor: connectedImpostor,
+                joint: joint
+            });
         };
-        PhysicsEngine.prototype.isSupported = function () {
-            return this._currentPlugin.isSupported();
+        PhysicsEngine.prototype.removeJoint = function (mainImpostor, connectedImpostor, joint) {
+            var matchingJoints = this._joints.filter(function (impostorJoint) {
+                return (impostorJoint.connectedImpostor === connectedImpostor
+                    && impostorJoint.joint === joint
+                    && impostorJoint.mainImpostor === mainImpostor);
+            });
+            if (matchingJoints.length) {
+                this._physicsPlugin.removeJoint(matchingJoints[0]);
+            }
         };
-        PhysicsEngine.prototype.getPhysicsBodyOfMesh = function (mesh) {
-            return this._currentPlugin.getPhysicsBodyOfMesh(mesh);
+        PhysicsEngine.prototype._step = function (delta) {
+            var _this = this;
+            //check if any mesh has no body / requires an update
+            this._impostors.forEach(function (impostor) {
+                if (impostor.isUpdateRequired()) {
+                    _this._physicsPlugin.generatePhysicsBody(impostor);
+                }
+            });
+            if (delta > 0.1) {
+                delta = 0.1;
+            }
+            else if (delta <= 0) {
+                delta = 1.0 / 60.0;
+            }
+            this._physicsPlugin.executeStep(delta, this._impostors);
         };
-        PhysicsEngine.prototype.getPhysicsPluginName = function () {
-            return this._currentPlugin.name;
+        PhysicsEngine.prototype.getPhysicsPlugin = function () {
+            return this._physicsPlugin;
         };
-        PhysicsEngine.prototype.getWorldObject = function () {
-            return this._currentPlugin.getWorldObject();
+        PhysicsEngine.prototype.getImpostorWithPhysicsBody = function (body) {
+            for (var i = 0; i < this._impostors.length; ++i) {
+                if (this._impostors[i].physicsBody === body) {
+                    return this._impostors[i];
+                }
+            }
         };
-        // Statics
-        PhysicsEngine.NoImpostor = 0;
-        PhysicsEngine.SphereImpostor = 1;
-        PhysicsEngine.BoxImpostor = 2;
-        PhysicsEngine.PlaneImpostor = 3;
-        PhysicsEngine.MeshImpostor = 4;
-        PhysicsEngine.CapsuleImpostor = 5;
-        PhysicsEngine.ConeImpostor = 6;
-        PhysicsEngine.CylinderImpostor = 7;
-        PhysicsEngine.ConvexHullImpostor = 8;
-        PhysicsEngine.HeightmapImpostor = 9;
+        // Statics, Legacy support.
+        /**
+         * @Deprecated
+         *
+         */
+        PhysicsEngine.NoImpostor = BABYLON.PhysicsImpostor.NoImpostor;
+        PhysicsEngine.SphereImpostor = BABYLON.PhysicsImpostor.SphereImpostor;
+        PhysicsEngine.BoxImpostor = BABYLON.PhysicsImpostor.BoxImpostor;
+        PhysicsEngine.PlaneImpostor = BABYLON.PhysicsImpostor.PlaneImpostor;
+        PhysicsEngine.MeshImpostor = BABYLON.PhysicsImpostor.MeshImpostor;
+        PhysicsEngine.CapsuleImpostor = BABYLON.PhysicsImpostor.CapsuleImpostor;
+        PhysicsEngine.ConeImpostor = BABYLON.PhysicsImpostor.ConeImpostor;
+        PhysicsEngine.CylinderImpostor = BABYLON.PhysicsImpostor.CylinderImpostor;
+        PhysicsEngine.ConvexHullImpostor = BABYLON.PhysicsImpostor.ConvexHullImpostor;
+        PhysicsEngine.HeightmapImpostor = BABYLON.PhysicsImpostor.HeightmapImpostor;
         PhysicsEngine.Epsilon = 0.001;
         return PhysicsEngine;
     })();
     BABYLON.PhysicsEngine = PhysicsEngine;
+    (function (PhysicsFeature) {
+        PhysicsFeature[PhysicsFeature["PIVOT_IN_JOINT"] = 0] = "PIVOT_IN_JOINT";
+        PhysicsFeature[PhysicsFeature["TRIMESH"] = 1] = "TRIMESH";
+    })(BABYLON.PhysicsFeature || (BABYLON.PhysicsFeature = {}));
+    var PhysicsFeature = BABYLON.PhysicsFeature;
 })(BABYLON || (BABYLON = {}));

+ 120 - 88
src/Physics/babylon.physicsEngine.ts

@@ -1,121 +1,153 @@
 module BABYLON {
-    export interface IPhysicsEnginePlugin {
-        name: string;
-        initialize(iterations?: number);
-        setGravity(gravity: Vector3): void;
-        getGravity(): Vector3;
-        runOneStep(delta: number): void;
-        registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any;
-        registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any;
-        unregisterMesh(mesh: AbstractMesh);
-        applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void;
-        createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean;
-        dispose(): void;
-        isSupported(): boolean;
-        updateBodyPosition(mesh: AbstractMesh): void;
-        getWorldObject(): any; //Will return the physics world object of the engine used.
-        getPhysicsBodyOfMesh(mesh: AbstractMesh): any;
-    }
-
-    export interface PhysicsBodyCreationOptions {
-        mass: number;
-        friction: number;
-        restitution: number;
-    }
 
-    export interface PhysicsCompoundBodyPart {
-        mesh: Mesh;
-        impostor: number;
+    export interface PhysicsImpostorJoint {
+        mainImpostor: PhysicsImpostor;
+        connectedImpostor: PhysicsImpostor;
+        joint: PhysicsJoint;
     }
 
     export class PhysicsEngine {
-        public gravity: Vector3;
 
-        private _currentPlugin: IPhysicsEnginePlugin;
+        public gravity: Vector3;
 
-        constructor(plugin?: IPhysicsEnginePlugin) {
-            this._currentPlugin = plugin || new OimoJSPlugin();
+        constructor(gravity?: Vector3, private _physicsPlugin: IPhysicsEnginePlugin = new CannonJSPlugin()) {
+            if (!this._physicsPlugin.isSupported()) {
+                throw new Error("Physics Engine " + this._physicsPlugin.name + " cannot be found. "
+                    + "Please make sure it is included.")
+            }
+            gravity = gravity || new Vector3(0, -9.807, 0)
+            this.setGravity(gravity);
         }
 
-        public _initialize(gravity?: Vector3) {
-            this._currentPlugin.initialize();
-            this._setGravity(gravity);
+        public setGravity(gravity: Vector3): void {
+            this.gravity = gravity;
+            this._physicsPlugin.setGravity(this.gravity);
         }
 
-        public _runOneStep(delta: number): void {
-            if (delta > 0.1) {
-                delta = 0.1;
-            } else if (delta <= 0) {
-                delta = 1.0 / 60.0;
-            }
-
-            this._currentPlugin.runOneStep(delta);
+        public dispose(): void {
+            this._impostors.forEach(function(impostor) {
+                impostor.dispose();
+            })
+            this._physicsPlugin.dispose();
         }
 
-        public _setGravity(gravity: Vector3): void {
-            this.gravity = gravity || new Vector3(0, -9.807, 0);
-            this._currentPlugin.setGravity(this.gravity);
-        }
+        public getPhysicsPluginName(): string {
+            return this._physicsPlugin.name;
+        }
+
+        // Statics, Legacy support.
+        /**
+         * @Deprecated
+         *  
+         */
+        public static NoImpostor = PhysicsImpostor.NoImpostor;
+        public static SphereImpostor = PhysicsImpostor.SphereImpostor;
+        public static BoxImpostor = PhysicsImpostor.BoxImpostor;
+        public static PlaneImpostor = PhysicsImpostor.PlaneImpostor;
+        public static MeshImpostor = PhysicsImpostor.MeshImpostor;
+        public static CapsuleImpostor = PhysicsImpostor.CapsuleImpostor;
+        public static ConeImpostor = PhysicsImpostor.ConeImpostor;
+        public static CylinderImpostor = PhysicsImpostor.CylinderImpostor;
+        public static ConvexHullImpostor = PhysicsImpostor.ConvexHullImpostor;
+        public static HeightmapImpostor = PhysicsImpostor.HeightmapImpostor;
 
-        public _getGravity(): Vector3 {
-            return this._currentPlugin.getGravity();
+        public static Epsilon = 0.001;
+        
+        //new methods and parameters
+        
+        private _impostors: Array<PhysicsImpostor> = [];
+        private _joints: Array<PhysicsImpostorJoint> = [];
+
+        public addImpostor(impostor: PhysicsImpostor) {
+            this._impostors.push(impostor);
+        }
+
+        public removeImpostor(impostor: PhysicsImpostor) {
+            var index = this._impostors.indexOf(impostor);
+            if (index > -1) {
+                var removed = this._impostors.splice(index, 1);
+                //Is it needed?
+                if(removed.length) {
+                    this._physicsPlugin.removePhysicsBody(removed[0]);
+                }
+            }
         }
 
-        public _registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
-            return this._currentPlugin.registerMesh(mesh, impostor, options);
+        public addJoint(mainImpostor: PhysicsImpostor, connectedImpostor: PhysicsImpostor, joint: PhysicsJoint) {
+            this._joints.push({
+                mainImpostor: mainImpostor,
+                connectedImpostor: connectedImpostor,
+                joint: joint
+            });
+        }
+
+        public removeJoint(mainImpostor: PhysicsImpostor, connectedImpostor: PhysicsImpostor, joint: PhysicsJoint) {
+            var matchingJoints = this._joints.filter(function(impostorJoint) {
+                return (impostorJoint.connectedImpostor === connectedImpostor
+                    && impostorJoint.joint === joint
+                    && impostorJoint.mainImpostor === mainImpostor)
+            });
+            if(matchingJoints.length) {
+                this._physicsPlugin.removeJoint(matchingJoints[0]);
+                //TODO remove it from the list as well
+                
+            }
         }
 
-        public _registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-            return this._currentPlugin.registerMeshesAsCompound(parts, options);
-        }
+        public _step(delta: number) {
+            //check if any mesh has no body / requires an update
+            this._impostors.forEach((impostor) => {
 
-        public _unregisterMesh(mesh: AbstractMesh): void {
-            this._currentPlugin.unregisterMesh(mesh);
-        }
+                if (impostor.isUpdateRequired()) {
+                    this._physicsPlugin.generatePhysicsBody(impostor);
+                }
+            });
 
-        public _applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            this._currentPlugin.applyImpulse(mesh, force, contactPoint);
-        }
+            if (delta > 0.1) {
+                delta = 0.1;
+            } else if (delta <= 0) {
+                delta = 1.0 / 60.0;
+            }
 
-        public _createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean {
-            return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2, options);
+            this._physicsPlugin.executeStep(delta, this._impostors);
         }
 
-        public _updateBodyPosition(mesh: AbstractMesh): void {
-            this._currentPlugin.updateBodyPosition(mesh);
+        public getPhysicsPlugin(): IPhysicsEnginePlugin {
+            return this._physicsPlugin;
         }
 
-        public dispose(): void {
-            this._currentPlugin.dispose();
+        public getImpostorWithPhysicsBody(body: any): PhysicsImpostor {
+            for (var i = 0; i < this._impostors.length; ++i) {
+                if (this._impostors[i].physicsBody === body) {
+                    return this._impostors[i];
+                }
+            }
         }
+    }
 
-        public isSupported(): boolean {
-            return this._currentPlugin.isSupported();
-        }
+    export enum PhysicsFeature {
+        PIVOT_IN_JOINT,
+        TRIMESH,
 
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            return this._currentPlugin.getPhysicsBodyOfMesh(mesh);
-        }
+    }
 
-        public getPhysicsPluginName(): string {
-            return this._currentPlugin.name;
-        }
+    export interface PhysicsFeatures {
 
-        public getWorldObject(): any {
-            return this._currentPlugin.getWorldObject();
-        }
+    }
 
-        // Statics
-        public static NoImpostor = 0;
-        public static SphereImpostor = 1;
-        public static BoxImpostor = 2;
-        public static PlaneImpostor = 3;
-        public static MeshImpostor = 4;
-        public static CapsuleImpostor = 5;
-        public static ConeImpostor = 6;
-        public static CylinderImpostor = 7;
-        public static ConvexHullImpostor = 8;
-        public static HeightmapImpostor = 9;
-        public static Epsilon = 0.001;
+    export interface IPhysicsEnginePlugin {
+        world: any;
+        name: string;
+        setGravity(gravity: Vector3);
+        executeStep(delta: number, impostors: Array<PhysicsImpostor>): void; //not forgetting pre and post events
+        applyImpulse(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3);
+        applyForce(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3);
+        generatePhysicsBody(impostor: PhysicsImpostor);
+        removePhysicsBody(impostor: PhysicsImpostor);
+        generateJoint(joint: PhysicsImpostorJoint);
+        removeJoint(joint: PhysicsImpostorJoint)
+        isSupported(): boolean;
+        supports(feature: PhysicsFeature): boolean;
+        dispose();
     }
 }

+ 219 - 0
src/Physics/babylon.physicsImpostor.js

@@ -0,0 +1,219 @@
+var BABYLON;
+(function (BABYLON) {
+    var PhysicsImpostor = (function () {
+        function PhysicsImpostor(_mesh, type, _options) {
+            var _this = this;
+            this._mesh = _mesh;
+            this.type = type;
+            this._options = _options;
+            this._transformationUpdated = false;
+            this._bodyUpdateRequired = false;
+            this._onBeforePhysicsStepCallbacks = new Array();
+            this._onAfterPhysicsStepCallbacks = new Array();
+            this._onPhysicsCollideCallbacks = new Array();
+            this.beforeStep = function () {
+                _this._onBeforePhysicsStepCallbacks.forEach(function (func) {
+                    func(_this);
+                });
+            };
+            this.afterStep = function () {
+                _this._onAfterPhysicsStepCallbacks.forEach(function (func) {
+                    func(_this);
+                });
+                //update the mesh's position and rotation
+                var bodyX = _this.physicsBody.position.x, bodyY = _this.physicsBody.position.y, bodyZ = _this.physicsBody.position.z;
+                _this._mesh.position.x = bodyX + _this._deltaPosition.x;
+                _this._mesh.position.y = bodyY + _this._deltaPosition.y;
+                _this._mesh.position.z = bodyZ + _this._deltaPosition.z;
+                _this._mesh.rotationQuaternion.copyFrom(_this.physicsBody.quaternion);
+                if (_this._deltaRotation) {
+                    _this._mesh.rotationQuaternion.multiplyInPlace(_this._deltaRotation);
+                }
+            };
+            //event object due to cannon's architecture.
+            this.onCollide = function (e) {
+                var otherImpostor = _this._physicsEngine.getImpostorWithPhysicsBody(e.body);
+                if (otherImpostor) {
+                    _this._onPhysicsCollideCallbacks.forEach(function (func) {
+                        func(_this, otherImpostor);
+                    });
+                }
+            };
+            //default options params
+            _options.mass = (_options.mass === void 0) ? 0 : _options.mass;
+            _options.friction = (_options.friction === void 0) ? 0.2 : _options.friction;
+            _options.restitution = (_options.restitution === void 0) ? 0.2 : _options.restitution;
+            this._physicsEngine = this._mesh.getScene().getPhysicsEngine();
+            this._joints = [];
+            this._init();
+        }
+        PhysicsImpostor.prototype._init = function () {
+            this._physicsEngine.removeImpostor(this);
+            this._parent = this._parent || this._getPhysicsParent();
+            if (!this.parent) {
+                this._physicsEngine.addImpostor(this);
+                this._bodyUpdateRequired = true;
+            }
+        };
+        PhysicsImpostor.prototype._getPhysicsParent = function () {
+            if (this.mesh.parent instanceof BABYLON.AbstractMesh) {
+                var parentMesh = this.mesh.parent;
+                return parentMesh.getPhysicsImpostor();
+            }
+            return;
+        };
+        PhysicsImpostor.prototype.isBodyInitRequired = function () {
+            return this._bodyUpdateRequired || (!this._physicsBody && !this._parent);
+        };
+        PhysicsImpostor.prototype.isUpdateRequired = function () {
+            return this._transformationUpdated || this.isBodyInitRequired();
+        };
+        PhysicsImpostor.prototype.setTransformationUpdated = function (updated) {
+            this._transformationUpdated = updated;
+            if (this._parent) {
+                this._parent.setTransformationUpdated(updated);
+            }
+        };
+        PhysicsImpostor.prototype.setScalingUpdated = function (updated) {
+            this.forceUpdate();
+        };
+        PhysicsImpostor.prototype.forceUpdate = function () {
+            this._init();
+            if (this.parent) {
+                this.parent.forceUpdate();
+            }
+        };
+        Object.defineProperty(PhysicsImpostor.prototype, "mesh", {
+            get: function () {
+                return this._mesh;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PhysicsImpostor.prototype, "physicsBody", {
+            get: function () {
+                return this._physicsBody;
+            },
+            set: function (physicsBody) {
+                if (this._physicsBody) {
+                    this._physicsEngine.getPhysicsPlugin().removePhysicsBody(this._physicsBody);
+                }
+                this._physicsBody = physicsBody;
+                this.resetUpdateFlags();
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PhysicsImpostor.prototype, "parent", {
+            get: function () {
+                return this._parent;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        PhysicsImpostor.prototype.resetUpdateFlags = function () {
+            this._transformationUpdated = false;
+            this._bodyUpdateRequired = false;
+        };
+        PhysicsImpostor.prototype.getOptions = function () {
+            return this._options;
+        };
+        PhysicsImpostor.prototype.getParam = function (paramName) {
+            return this._options[paramName];
+        };
+        PhysicsImpostor.prototype.setParam = function (paramName, value) {
+            this._options[paramName] = value;
+            this._bodyUpdateRequired = true;
+        };
+        PhysicsImpostor.prototype.registerBeforePhysicsStep = function (func) {
+            this._onBeforePhysicsStepCallbacks.push(func);
+        };
+        PhysicsImpostor.prototype.unregisterBeforePhysicsStep = function (func) {
+            var index = this._onBeforePhysicsStepCallbacks.indexOf(func);
+            if (index > -1) {
+                this._onBeforePhysicsStepCallbacks.splice(index, 1);
+            }
+            else {
+                BABYLON.Tools.Warn("Function to remove was not found");
+            }
+        };
+        PhysicsImpostor.prototype.registerAfterPhysicsStep = function (func) {
+            this._onAfterPhysicsStepCallbacks.push(func);
+        };
+        PhysicsImpostor.prototype.unregisterAfterPhysicsStep = function (func) {
+            var index = this._onAfterPhysicsStepCallbacks.indexOf(func);
+            if (index > -1) {
+                this._onAfterPhysicsStepCallbacks.splice(index, 1);
+            }
+            else {
+                BABYLON.Tools.Warn("Function to remove was not found");
+            }
+        };
+        PhysicsImpostor.prototype.registerOnPhysicsCollide = function (func) {
+            this._onPhysicsCollideCallbacks.push(func);
+        };
+        PhysicsImpostor.prototype.unregisterOnPhysicsCollide = function (func) {
+            var index = this._onPhysicsCollideCallbacks.indexOf(func);
+            if (index > -1) {
+                this._onPhysicsCollideCallbacks.splice(index, 1);
+            }
+            else {
+                BABYLON.Tools.Warn("Function to remove was not found");
+            }
+        };
+        PhysicsImpostor.prototype.applyForce = function (force, contactPoint) {
+            this._physicsEngine.getPhysicsPlugin().applyForce(this, force, contactPoint);
+        };
+        PhysicsImpostor.prototype.applyImpulse = function (force, contactPoint) {
+            this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
+        };
+        PhysicsImpostor.prototype.createJoint = function (otherImpostor, jointType, jointData) {
+            var joint = new BABYLON.PhysicsJoint(jointType, jointData);
+            this.addJoint(otherImpostor, joint);
+        };
+        PhysicsImpostor.prototype.addJoint = function (otherImpostor, joint) {
+            this._joints.push({
+                otherImpostor: otherImpostor,
+                joint: joint
+            });
+            this._physicsEngine.addJoint(this, otherImpostor, joint);
+        };
+        //TODO
+        PhysicsImpostor.prototype.dispose = function (disposeChildren) {
+            if (disposeChildren === void 0) { disposeChildren = true; }
+            this.physicsBody = null;
+            if (this.parent) {
+                this.parent.forceUpdate();
+            }
+            else {
+                this.mesh.getChildMeshes().forEach(function (mesh) {
+                    if (mesh.physicImpostor) {
+                        if (disposeChildren) {
+                            mesh.physicImpostor.dispose();
+                            mesh.physicImpostor = null;
+                        }
+                    }
+                });
+            }
+        };
+        PhysicsImpostor.prototype.setDeltaPosition = function (position) {
+            this._deltaPosition = position;
+        };
+        PhysicsImpostor.prototype.setDeltaRotation = function (rotation) {
+            this._deltaRotation = rotation;
+        };
+        //Impostor types
+        PhysicsImpostor.NoImpostor = 0;
+        PhysicsImpostor.SphereImpostor = 1;
+        PhysicsImpostor.BoxImpostor = 2;
+        PhysicsImpostor.PlaneImpostor = 3;
+        PhysicsImpostor.MeshImpostor = 4;
+        PhysicsImpostor.CapsuleImpostor = 5;
+        PhysicsImpostor.ConeImpostor = 6;
+        PhysicsImpostor.CylinderImpostor = 7;
+        PhysicsImpostor.ConvexHullImpostor = 8;
+        PhysicsImpostor.HeightmapImpostor = 9;
+        return PhysicsImpostor;
+    })();
+    BABYLON.PhysicsImpostor = PhysicsImpostor;
+})(BABYLON || (BABYLON = {}));

+ 260 - 0
src/Physics/babylon.physicsImpostor.ts

@@ -0,0 +1,260 @@
+module BABYLON {
+
+    export interface PhysicsImpostorParameters {
+        mass: number;
+        friction?: number;
+        restitution?: number;
+        nativeOptions?: any;
+    }
+
+    export class PhysicsImpostor {
+
+        private _physicsEngine: PhysicsEngine;
+        //The native cannon/oimo/energy physics body object.
+        private _physicsBody: any;
+        private _transformationUpdated: boolean = false;
+        private _bodyUpdateRequired: boolean = false;
+
+        private _onBeforePhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
+        private _onAfterPhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
+        private _onPhysicsCollideCallbacks = new Array<(collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor) => void>();
+
+        private _deltaPosition: Vector3;
+        private _deltaRotation: Quaternion;
+        
+        //If set, this is this impostor's parent
+        private _parent: PhysicsImpostor;
+
+        private _joints: Array<{
+            joint: PhysicsJoint,
+            otherImpostor: PhysicsImpostor
+        }>;
+
+        constructor(private _mesh: AbstractMesh, public type: number, private _options: PhysicsImpostorParameters) {
+            //default options params
+            _options.mass = (_options.mass === void 0) ? 0 : _options.mass
+            _options.friction = (_options.friction === void 0) ? 0.2 : _options.friction
+            _options.restitution = (_options.restitution === void 0) ? 0.2 : _options.restitution
+            this._physicsEngine = this._mesh.getScene().getPhysicsEngine();
+            this._joints = [];
+            this._init();
+        }
+
+        private _init() {
+            this._physicsEngine.removeImpostor(this);
+            this._parent = this._parent || this._getPhysicsParent();
+            if (!this.parent) {
+                this._physicsEngine.addImpostor(this);
+                this._bodyUpdateRequired = true;
+            }
+        }
+
+        private _getPhysicsParent(): PhysicsImpostor {
+            if (this.mesh.parent instanceof AbstractMesh) {
+                var parentMesh: AbstractMesh = <AbstractMesh>this.mesh.parent;
+                return parentMesh.getPhysicsImpostor();
+            }
+            return;
+        }
+
+        public isBodyInitRequired(): boolean {
+            return this._bodyUpdateRequired || (!this._physicsBody && !this._parent);
+        }
+
+        public isUpdateRequired(): boolean {
+            return this._transformationUpdated || this.isBodyInitRequired();
+        }
+
+        public setTransformationUpdated(updated: boolean) {
+            this._transformationUpdated = updated;
+            if (this._parent) {
+                this._parent.setTransformationUpdated(updated);
+            }
+        }
+
+        public setScalingUpdated(updated: boolean) {
+            this.forceUpdate();
+        }
+
+        public forceUpdate() {
+            this._init();
+            if (this.parent) {
+                this.parent.forceUpdate();
+            }
+        }
+
+        public get mesh(): AbstractMesh {
+            return this._mesh;
+        }
+
+        public get physicsBody(): any {
+            return this._physicsBody;
+        }
+
+        public get parent() {
+            return this._parent;
+        }
+
+        public set physicsBody(physicsBody: any) {
+            if (this._physicsBody) {
+                this._physicsEngine.getPhysicsPlugin().removePhysicsBody(this._physicsBody);
+            }
+            this._physicsBody = physicsBody;
+            this.resetUpdateFlags();
+        }
+
+        public resetUpdateFlags() {
+            this._transformationUpdated = false;
+            this._bodyUpdateRequired = false;
+        }
+
+        public getOptions() {
+            return this._options;
+        }
+
+        public getParam(paramName: string) {
+            return this._options[paramName];
+        }
+        public setParam(paramName: string, value: number) {
+            this._options[paramName] = value;
+            this._bodyUpdateRequired = true;
+        }
+
+        public registerBeforePhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
+            this._onBeforePhysicsStepCallbacks.push(func);
+        }
+
+        public unregisterBeforePhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
+            var index = this._onBeforePhysicsStepCallbacks.indexOf(func);
+
+            if (index > -1) {
+                this._onBeforePhysicsStepCallbacks.splice(index, 1);
+            } else {
+                Tools.Warn("Function to remove was not found");
+            }
+        }
+
+        public registerAfterPhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
+            this._onAfterPhysicsStepCallbacks.push(func);
+        }
+
+        public unregisterAfterPhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
+            var index = this._onAfterPhysicsStepCallbacks.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterPhysicsStepCallbacks.splice(index, 1);
+            } else {
+                Tools.Warn("Function to remove was not found");
+            }
+        }
+
+        public registerOnPhysicsCollide(func: (impostor: PhysicsImpostor) => void): void {
+            this._onPhysicsCollideCallbacks.push(func);
+        }
+
+        public unregisterOnPhysicsCollide(func: (impostor: PhysicsImpostor) => void): void {
+            var index = this._onPhysicsCollideCallbacks.indexOf(func);
+
+            if (index > -1) {
+                this._onPhysicsCollideCallbacks.splice(index, 1);
+            } else {
+                Tools.Warn("Function to remove was not found");
+            }
+        }
+
+        public beforeStep = () => {
+            this._onBeforePhysicsStepCallbacks.forEach((func) => {
+                func(this);
+            });
+        }
+
+        public afterStep = () => {
+            this._onAfterPhysicsStepCallbacks.forEach((func) => {
+                func(this);
+            });
+            
+            //update the mesh's position and rotation
+            var bodyX = this.physicsBody.position.x,
+                bodyY = this.physicsBody.position.y,
+                bodyZ = this.physicsBody.position.z;
+
+            this._mesh.position.x = bodyX + this._deltaPosition.x;
+            this._mesh.position.y = bodyY + this._deltaPosition.y;
+            this._mesh.position.z = bodyZ + this._deltaPosition.z;
+
+            this._mesh.rotationQuaternion.copyFrom(this.physicsBody.quaternion);
+            if (this._deltaRotation) {
+                this._mesh.rotationQuaternion.multiplyInPlace(this._deltaRotation);
+            }
+        }
+        
+        //event object due to cannon's architecture.
+        public onCollide = (e: { body: any }) => {
+            var otherImpostor = this._physicsEngine.getImpostorWithPhysicsBody(e.body);
+            if (otherImpostor) {
+                this._onPhysicsCollideCallbacks.forEach((func) => {
+                    func(this, otherImpostor);
+                })
+            }
+        }
+
+        public applyForce(force: Vector3, contactPoint: Vector3) {
+            this._physicsEngine.getPhysicsPlugin().applyForce(this, force, contactPoint);
+        }
+
+        public applyImpulse(force: Vector3, contactPoint: Vector3) {
+            this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
+        }
+
+        public createJoint(otherImpostor: PhysicsImpostor, jointType:number,  jointData: PhysicsJointData) {
+            var joint = new PhysicsJoint(jointType, jointData);
+            this.addJoint(otherImpostor, joint);
+        }
+
+        public addJoint(otherImpostor: PhysicsImpostor, joint: PhysicsJoint) {
+            this._joints.push({
+                otherImpostor: otherImpostor,
+                joint: joint
+            })
+            this._physicsEngine.addJoint(this, otherImpostor, joint);
+        }
+
+        //TODO
+        public dispose(disposeChildren: boolean = true) {
+            this.physicsBody = null;
+            if (this.parent) {
+                this.parent.forceUpdate();
+            } else {
+                this.mesh.getChildMeshes().forEach(function(mesh) {
+                    if (mesh.physicImpostor) {
+                        if (disposeChildren) {
+                            mesh.physicImpostor.dispose();
+                            mesh.physicImpostor = null;
+                        }
+                    }
+                })
+            }
+        }
+        
+        public setDeltaPosition(position: Vector3) {
+            this._deltaPosition = position;
+        }
+        
+        public setDeltaRotation(rotation: Quaternion) {
+            this._deltaRotation = rotation;
+        }
+        
+        //Impostor types
+        public static NoImpostor = 0;
+        public static SphereImpostor = 1;
+        public static BoxImpostor = 2;
+        public static PlaneImpostor = 3;
+        public static MeshImpostor = 4;
+        public static CapsuleImpostor = 5;
+        public static ConeImpostor = 6;
+        public static CylinderImpostor = 7;
+        public static ConvexHullImpostor = 8;
+        public static HeightmapImpostor = 9;
+    }
+
+}

+ 40 - 0
src/Physics/babylon.physicsJoint.js

@@ -0,0 +1,40 @@
+var BABYLON;
+(function (BABYLON) {
+    var PhysicsJoint = (function () {
+        function PhysicsJoint(type, jointData) {
+            this.type = type;
+            this.jointData = jointData;
+            jointData.nativeParams = jointData.nativeParams || {};
+        }
+        Object.defineProperty(PhysicsJoint.prototype, "physicsJoint", {
+            get: function () {
+                return this._physicsJoint;
+            },
+            set: function (newJoint) {
+                if (this._physicsJoint) {
+                }
+                this._physicsJoint = newJoint;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        //TODO check if the native joints are the same
+        //Joint Types
+        PhysicsJoint.DistanceJoint = 0;
+        PhysicsJoint.HingeJoint = 1;
+        PhysicsJoint.BallAndSocketJoint = 2;
+        PhysicsJoint.WheelJoint = 3;
+        PhysicsJoint.SliderJoint = 4;
+        //OIMO
+        PhysicsJoint.PrismaticJoint = 5;
+        //ENERGY FTW! (compare with this - http://ode-wiki.org/wiki/index.php?title=Manual:_Joint_Types_and_Functions)
+        PhysicsJoint.UniversalJoint = 6;
+        PhysicsJoint.Hinge2Joint = 7;
+        //Cannon
+        //Similar to a Ball-Joint. Different in params
+        //TODO check!!
+        PhysicsJoint.PointToPointJoint = 8;
+        return PhysicsJoint;
+    })();
+    BABYLON.PhysicsJoint = PhysicsJoint;
+})(BABYLON || (BABYLON = {}));

+ 60 - 0
src/Physics/babylon.physicsJoint.ts

@@ -0,0 +1,60 @@
+module BABYLON {
+
+    export interface PhysicsJointData {
+        //Important for some engines, optional!
+        mainPivot?: Vector3;
+        connectedPivot?: Vector3;
+        mainAxis?: Vector3,
+        connectedAxis?: Vector3,
+        //Native Oimo/Cannon/Energy data
+        nativeParams?: any;
+    }
+
+    export class PhysicsJoint {
+        
+        private _physicsJoint;
+        
+        constructor(public type: number, public jointData: PhysicsJointData) {
+            jointData.nativeParams = jointData.nativeParams || {};
+        }
+        
+        public get physicsJoint() {
+            return this._physicsJoint;
+        }
+        
+        public set physicsJoint(newJoint: any) {
+            
+            if(this._physicsJoint) {
+                //remove from the wolrd
+            }
+            
+            this._physicsJoint = newJoint;
+        }
+        
+        
+        //TODO check if the native joints are the same
+        
+        //Joint Types
+        public static DistanceJoint = 0;
+        public static HingeJoint = 1;
+        public static BallAndSocketJoint = 2;
+        public static WheelJoint = 3;
+        public static SliderJoint = 4;
+        //OIMO
+        public static PrismaticJoint = 5;
+        //ENERGY FTW! (compare with this - http://ode-wiki.org/wiki/index.php?title=Manual:_Joint_Types_and_Functions)
+        public static UniversalJoint = 6;
+        public static Hinge2Joint = 7;
+        //Cannon
+        //Similar to a Ball-Joint. Different in params
+        //TODO check!!
+        public static PointToPointJoint = 8;
+
+    }
+    
+    export interface DistanceJointData extends PhysicsJointData {
+        maxDistance: number;
+        //Oimo - minDistance
+        //Cannon - maxForce
+    }
+}

+ 3 - 3
src/Tools/babylon.sceneSerializer.js

@@ -96,11 +96,11 @@ var BABYLON;
             serializationObject.skeletonId = mesh.skeleton.id;
         }
         // Physics
-        if (mesh.getPhysicsImpostor() !== BABYLON.PhysicsEngine.NoImpostor) {
+        if (mesh.getPhysicsImpostor().type !== BABYLON.PhysicsEngine.NoImpostor) {
             serializationObject.physicsMass = mesh.getPhysicsMass();
             serializationObject.physicsFriction = mesh.getPhysicsFriction();
             serializationObject.physicsRestitution = mesh.getPhysicsRestitution();
-            switch (mesh.getPhysicsImpostor()) {
+            switch (mesh.getPhysicsImpostor().type) {
                 case BABYLON.PhysicsEngine.BoxImpostor:
                     serializationObject.physicsImpostor = 1;
                     break;
@@ -207,7 +207,7 @@ var BABYLON;
             //Physics
             if (scene.isPhysicsEnabled()) {
                 serializationObject.physicsEnabled = true;
-                serializationObject.physicsGravity = scene.getPhysicsEngine()._getGravity().asArray();
+                serializationObject.physicsGravity = scene.getPhysicsEngine().gravity.asArray();
                 serializationObject.physicsEngine = scene.getPhysicsEngine().getPhysicsPluginName();
             }
             // Lights

+ 3 - 3
src/Tools/babylon.sceneSerializer.ts

@@ -112,12 +112,12 @@
         }
 
         // Physics
-        if (mesh.getPhysicsImpostor() !== PhysicsEngine.NoImpostor) {
+        if (mesh.getPhysicsImpostor().type !== PhysicsEngine.NoImpostor) {
             serializationObject.physicsMass = mesh.getPhysicsMass();
             serializationObject.physicsFriction = mesh.getPhysicsFriction();
             serializationObject.physicsRestitution = mesh.getPhysicsRestitution();
 
-            switch (mesh.getPhysicsImpostor()) {
+            switch (mesh.getPhysicsImpostor().type) {
                 case PhysicsEngine.BoxImpostor:
                     serializationObject.physicsImpostor = 1;
                     break;
@@ -235,7 +235,7 @@
             //Physics
             if (scene.isPhysicsEnabled()) {
                 serializationObject.physicsEnabled = true;
-                serializationObject.physicsGravity = scene.getPhysicsEngine()._getGravity().asArray();
+                serializationObject.physicsGravity = scene.getPhysicsEngine().gravity.asArray();
                 serializationObject.physicsEngine = scene.getPhysicsEngine().getPhysicsPluginName();
             }
 

+ 24 - 21
src/babylon.scene.js

@@ -1486,7 +1486,7 @@ var BABYLON;
             // Physics
             if (this._physicsEngine) {
                 BABYLON.Tools.StartPerformanceCounter("Physics");
-                this._physicsEngine._runOneStep(deltaTime / 1000.0);
+                this._physicsEngine._step(deltaTime / 1000.0);
                 BABYLON.Tools.EndPerformanceCounter("Physics");
             }
             // Before render
@@ -1990,13 +1990,14 @@ var BABYLON;
             if (this._physicsEngine) {
                 return true;
             }
-            this._physicsEngine = new BABYLON.PhysicsEngine(plugin);
-            if (!this._physicsEngine.isSupported()) {
-                this._physicsEngine = null;
+            try {
+                this._physicsEngine = new BABYLON.PhysicsEngine(gravity, plugin);
+                return true;
+            }
+            catch (e) {
+                BABYLON.Tools.Error(e.message);
                 return false;
             }
-            this._physicsEngine._initialize(gravity);
-            return true;
         };
         Scene.prototype.disablePhysicsEngine = function () {
             if (!this._physicsEngine) {
@@ -2009,38 +2010,40 @@ var BABYLON;
             return this._physicsEngine !== undefined;
         };
         /**
+         *
          * Sets the gravity of the physics engine (and NOT of the scene)
          * @param {BABYLON.Vector3} [gravity] - the new gravity to be used
          */
         Scene.prototype.setGravity = function (gravity) {
+            BABYLON.Tools.Warn("Deprecated, please use 'scene.getPhysicsEngine().setGravity()'");
             if (!this._physicsEngine) {
                 return;
             }
-            this._physicsEngine._setGravity(gravity);
+            this._physicsEngine.setGravity(gravity);
         };
+        /**
+         * Legacy support, using the new API
+         * @Deprecated
+         */
         Scene.prototype.createCompoundImpostor = function (parts, options) {
+            BABYLON.Tools.Warn("This function is deprecated. Please use PhysicsImpostor parent/child");
             if (parts.parts) {
                 options = parts;
                 parts = parts.parts;
             }
-            if (!this._physicsEngine) {
-                return null;
-            }
-            for (var index = 0; index < parts.length; index++) {
+            var mainMesh = parts[0].mesh;
+            mainMesh.physicImpostor = new BABYLON.PhysicsImpostor(mainMesh, parts[0].impostor, options);
+            for (var index = 1; index < parts.length; index++) {
                 var mesh = parts[index].mesh;
-                mesh._physicImpostor = parts[index].impostor;
-                mesh._physicsMass = options.mass / parts.length;
-                mesh._physicsFriction = options.friction;
-                mesh._physicRestitution = options.restitution;
+                mesh.position = mesh.position.subtract(mainMesh.position);
+                mesh.parent = mainMesh;
+                mesh.physicImpostor = new BABYLON.PhysicsImpostor(mesh, parts[index].impostor, options);
             }
-            return this._physicsEngine._registerMeshesAsCompound(parts, options);
         };
         Scene.prototype.deleteCompoundImpostor = function (compound) {
-            for (var index = 0; index < compound.parts.length; index++) {
-                var mesh = compound.parts[index].mesh;
-                mesh._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
-                this._physicsEngine._unregisterMesh(mesh);
-            }
+            var mesh = compound.parts[0].mesh;
+            mesh.physicImpostor.dispose(true);
+            mesh.physicImpostor = null;
         };
         // Misc.
         Scene.prototype.createDefaultCameraOrLight = function () {

+ 28 - 30
src/babylon.scene.ts

@@ -1875,7 +1875,7 @@
             // Physics
             if (this._physicsEngine) {
                 Tools.StartPerformanceCounter("Physics");
-                this._physicsEngine._runOneStep(deltaTime / 1000.0);
+                this._physicsEngine._step(deltaTime / 1000.0);
                 Tools.EndPerformanceCounter("Physics");
             }
 
@@ -2486,16 +2486,14 @@
                 return true;
             }
 
-            this._physicsEngine = new PhysicsEngine(plugin);
-
-            if (!this._physicsEngine.isSupported()) {
-                this._physicsEngine = null;
+            try {
+                this._physicsEngine = new PhysicsEngine(gravity, plugin);
+                return true;
+            } catch(e) {
+                Tools.Error(e.message);
                 return false;
             }
-
-            this._physicsEngine._initialize(gravity);
-
-            return true;
+            
         }
 
         public disablePhysicsEngine(): void {
@@ -2512,45 +2510,45 @@
         }
 
         /**
+         * 
          * Sets the gravity of the physics engine (and NOT of the scene)
          * @param {BABYLON.Vector3} [gravity] - the new gravity to be used
          */
         public setGravity(gravity: Vector3): void {
+            Tools.Warn("Deprecated, please use 'scene.getPhysicsEngine().setGravity()'")
             if (!this._physicsEngine) {
                 return;
             }
 
-            this._physicsEngine._setGravity(gravity);
+            this._physicsEngine.setGravity(gravity);
         }
 
-        public createCompoundImpostor(parts: any, options: PhysicsBodyCreationOptions): any {
+        /**
+         * Legacy support, using the new API
+         * @Deprecated
+         */
+        public createCompoundImpostor(parts: any, options: PhysicsImpostorParameters): any {
+            Tools.Warn("This function is deprecated. Please use PhysicsImpostor parent/child")
+            
             if (parts.parts) { // Old API
                 options = parts;
                 parts = parts.parts;
             }
-
-            if (!this._physicsEngine) {
-                return null;
+            
+            var mainMesh : AbstractMesh = parts[0].mesh;
+            mainMesh.physicImpostor = new PhysicsImpostor(mainMesh, parts[0].impostor, options)
+            for (var index = 1; index < parts.length; index++) {
+                var mesh : AbstractMesh = parts[index].mesh;
+                mesh.position = mesh.position.subtract(mainMesh.position);
+                mesh.parent = mainMesh;
+                mesh.physicImpostor = new PhysicsImpostor(mesh, parts[index].impostor, options)
             }
-
-            for (var index = 0; index < parts.length; index++) {
-                var mesh = parts[index].mesh;
-
-                mesh._physicImpostor = parts[index].impostor;
-                mesh._physicsMass = options.mass / parts.length;
-                mesh._physicsFriction = options.friction;
-                mesh._physicRestitution = options.restitution;
-            }
-
-            return this._physicsEngine._registerMeshesAsCompound(parts, options);
         }
 
         public deleteCompoundImpostor(compound: any): void {
-            for (var index = 0; index < compound.parts.length; index++) {
-                var mesh = compound.parts[index].mesh;
-                mesh._physicImpostor = PhysicsEngine.NoImpostor;
-                this._physicsEngine._unregisterMesh(mesh);
-            }
+            var mesh : AbstractMesh = compound.parts[0].mesh;
+            mesh.physicImpostor.dispose(true);
+            mesh.physicImpostor = null;
         }
 
         // Misc.