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

Merge remote-tracking branch 'upstream/master' into PMREMGenerator

Sebastien Vandenberghe 9 éve
szülő
commit
e309bd02f3
86 módosított fájl, 7459 hozzáadás és 5600 törlés
  1. BIN
      Exporters/3ds Max/Max2Babylon-0.4.2.zip
  2. 2 2
      Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs
  3. 14 14
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs
  4. 2 2
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs
  5. 64 59
      Exporters/FBX/BabylonFbxNative/BabylonMesh.cpp
  6. 2 0
      Exporters/FBX/readme.md
  7. 2 0
      Tools/Gulp/config.json
  8. 81 0
      Tools/Gulp/gulp-removeShaderComments.js
  9. 27 10
      Tools/Gulp/gulpfile.js
  10. 22 22
      dist/preview release/babylon.core.js
  11. 1993 1793
      dist/preview release/babylon.d.ts
  12. 29 29
      dist/preview release/babylon.js
  13. 1114 738
      dist/preview release/babylon.max.js
  14. 29 29
      dist/preview release/babylon.noworker.js
  15. 2 0
      dist/preview release/what's new.md
  16. 2 2
      materialsLibrary/dist/babylon.fireMaterial.js
  17. 1 1
      materialsLibrary/dist/babylon.fireMaterial.min.js
  18. 2 2
      materialsLibrary/dist/babylon.furMaterial.js
  19. 1 1
      materialsLibrary/dist/babylon.furMaterial.min.js
  20. 2 2
      materialsLibrary/dist/babylon.gradientMaterial.js
  21. 1 1
      materialsLibrary/dist/babylon.gradientMaterial.min.js
  22. 2 2
      materialsLibrary/dist/babylon.lavaMaterial.js
  23. 1 1
      materialsLibrary/dist/babylon.lavaMaterial.min.js
  24. 2 2
      materialsLibrary/dist/babylon.normalMaterial.js
  25. 1 1
      materialsLibrary/dist/babylon.normalMaterial.min.js
  26. 4 4
      materialsLibrary/dist/babylon.pbrMaterial.js
  27. 3 3
      materialsLibrary/dist/babylon.pbrMaterial.min.js
  28. 2 2
      materialsLibrary/dist/babylon.simpleMaterial.js
  29. 1 1
      materialsLibrary/dist/babylon.simpleMaterial.min.js
  30. 2 2
      materialsLibrary/dist/babylon.skyMaterial.js
  31. 1 1
      materialsLibrary/dist/babylon.skyMaterial.min.js
  32. 2 2
      materialsLibrary/dist/babylon.terrainMaterial.js
  33. 1 1
      materialsLibrary/dist/babylon.terrainMaterial.min.js
  34. 2 2
      materialsLibrary/dist/babylon.triPlanarMaterial.js
  35. 1 1
      materialsLibrary/dist/babylon.triPlanarMaterial.min.js
  36. 2 2
      materialsLibrary/dist/babylon.waterMaterial.js
  37. 1 1
      materialsLibrary/dist/babylon.waterMaterial.min.js
  38. 81 0
      materialsLibrary/gulp-removeShaderComments.js
  39. 4 1
      materialsLibrary/gulpfile.js
  40. 2 1
      materialsLibrary/materials/pbr/pbr.fragment.fx
  41. 1394 1026
      materialsLibrary/test/refs/babylon.max.js
  42. 1 1
      readme.md
  43. 37 5
      src/Animations/babylon.animation.js
  44. 38 5
      src/Animations/babylon.animation.ts
  45. 12 6
      src/Cameras/babylon.arcRotateCamera.js
  46. 14 6
      src/Cameras/babylon.arcRotateCamera.ts
  47. 2 1
      src/Loading/babylon.sceneLoader.js
  48. 4 3
      src/Loading/babylon.sceneLoader.ts
  49. 27 1
      src/Materials/babylon.standardMaterial.js
  50. 29 3
      src/Materials/babylon.standardMaterial.ts
  51. 1 1
      src/Math/babylon.math.ts
  52. 89 56
      src/Mesh/babylon.abstractMesh.js
  53. 91 75
      src/Mesh/babylon.abstractMesh.ts
  54. 17 13
      src/Mesh/babylon.geometry.js
  55. 26 126
      src/Mesh/babylon.geometry.ts
  56. 0 17
      src/Mesh/babylon.mesh.js
  57. 1 21
      src/Mesh/babylon.mesh.ts
  58. 211 248
      src/Physics/Plugins/babylon.cannonJSPlugin.js
  59. 229 311
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  60. 219 289
      src/Physics/Plugins/babylon.oimoJSPlugin.js
  61. 252 340
      src/Physics/Plugins/babylon.oimoJSPlugin.ts
  62. 96 56
      src/Physics/babylon.physicsEngine.js
  63. 125 89
      src/Physics/babylon.physicsEngine.ts
  64. 278 0
      src/Physics/babylon.physicsImpostor.js
  65. 333 0
      src/Physics/babylon.physicsImpostor.ts
  66. 40 0
      src/Physics/babylon.physicsJoint.js
  67. 61 0
      src/Physics/babylon.physicsJoint.ts
  68. 9 8
      src/PostProcess/babylon.tonemapPostProcess.js
  69. 14 21
      src/PostProcess/babylon.tonemapPostProcess.ts
  70. 31 0
      src/Shaders/ShadersInclude/bumpFragment.fx
  71. 64 5
      src/Shaders/ShadersInclude/bumpFragmentFunctions.fx
  72. 13 0
      src/Shaders/ShadersInclude/helperFunctions.fx
  73. 23 19
      src/Shaders/default.fragment.fx
  74. 1 1
      src/Shaders/default.vertex.fx
  75. 16 5
      src/Tools/babylon.decorators.js
  76. 20 9
      src/Tools/babylon.decorators.ts
  77. 1 1
      src/Tools/babylon.gamepads.js
  78. 5 16
      src/Tools/babylon.gamepads.ts
  79. 3 3
      src/Tools/babylon.sceneSerializer.js
  80. 3 3
      src/Tools/babylon.sceneSerializer.ts
  81. 9 5
      src/babylon.engine.js
  82. 10 5
      src/babylon.engine.ts
  83. 22 6
      src/babylon.node.js
  84. 24 8
      src/babylon.node.ts
  85. 27 21
      src/babylon.scene.js
  86. 30 28
      src/babylon.scene.ts

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


+ 2 - 2
Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs

@@ -244,7 +244,7 @@
             // 
             this.nupTo.Location = new System.Drawing.Point(47, 40);
             this.nupTo.Maximum = new decimal(new int[] {
-            1000,
+            100000,
             0,
             0,
             0});
@@ -265,7 +265,7 @@
             // 
             this.nupFrom.Location = new System.Drawing.Point(47, 14);
             this.nupFrom.Maximum = new decimal(new int[] {
-            1000,
+            100000,
             0,
             0,
             0});

+ 14 - 14
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs

@@ -41,6 +41,7 @@
             this.groupBox4 = new System.Windows.Forms.GroupBox();
             this.chkNoExport = new System.Windows.Forms.CheckBox();
             this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.ckForceBackFaces = new System.Windows.Forms.CheckBox();
             this.grpBlurInfo = new System.Windows.Forms.GroupBox();
             this.nupBlurBoxOffset = new System.Windows.Forms.NumericUpDown();
             this.label3 = new System.Windows.Forms.Label();
@@ -50,7 +51,6 @@
             this.label6 = new System.Windows.Forms.Label();
             this.label1 = new System.Windows.Forms.Label();
             this.cbCameraType = new System.Windows.Forms.ComboBox();
-            this.ckForceBackFaces = new System.Windows.Forms.CheckBox();
             this.groupBox3.SuspendLayout();
             this.grpAutoAnimate.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
@@ -131,7 +131,7 @@
             // 
             this.nupTo.Location = new System.Drawing.Point(47, 40);
             this.nupTo.Maximum = new decimal(new int[] {
-            1000,
+            100000,
             0,
             0,
             0});
@@ -152,7 +152,7 @@
             // 
             this.nupFrom.Location = new System.Drawing.Point(47, 14);
             this.nupFrom.Maximum = new decimal(new int[] {
-            1000,
+            100000,
             0,
             0,
             0});
@@ -220,6 +220,17 @@
             this.groupBox1.TabStop = false;
             this.groupBox1.Text = "Shadows";
             // 
+            // ckForceBackFaces
+            // 
+            this.ckForceBackFaces.AutoSize = true;
+            this.ckForceBackFaces.Location = new System.Drawing.Point(24, 61);
+            this.ckForceBackFaces.Name = "ckForceBackFaces";
+            this.ckForceBackFaces.Size = new System.Drawing.Size(135, 17);
+            this.ckForceBackFaces.TabIndex = 14;
+            this.ckForceBackFaces.Text = "Force Back Faces only";
+            this.ckForceBackFaces.ThreeState = true;
+            this.ckForceBackFaces.UseVisualStyleBackColor = true;
+            // 
             // grpBlurInfo
             // 
             this.grpBlurInfo.Controls.Add(this.nupBlurBoxOffset);
@@ -344,17 +355,6 @@
             this.cbCameraType.TabIndex = 7;
             this.cbCameraType.SelectedIndexChanged += new System.EventHandler(this.cbCameraType_SelectedIndexChanged);
             // 
-            // ckForceBackFaces
-            // 
-            this.ckForceBackFaces.AutoSize = true;
-            this.ckForceBackFaces.Location = new System.Drawing.Point(24, 61);
-            this.ckForceBackFaces.Name = "ckForceBackFaces";
-            this.ckForceBackFaces.Size = new System.Drawing.Size(135, 17);
-            this.ckForceBackFaces.TabIndex = 14;
-            this.ckForceBackFaces.Text = "Force Back Faces only";
-            this.ckForceBackFaces.ThreeState = true;
-            this.ckForceBackFaces.UseVisualStyleBackColor = true;
-            // 
             // LightPropertiesForm
             // 
             this.AcceptButton = this.butOK;

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

@@ -297,7 +297,7 @@
             // 
             this.nupTo.Location = new System.Drawing.Point(47, 40);
             this.nupTo.Maximum = new decimal(new int[] {
-            1000,
+            100000,
             0,
             0,
             0});
@@ -318,7 +318,7 @@
             // 
             this.nupFrom.Location = new System.Drawing.Point(47, 14);
             this.nupFrom.Maximum = new decimal(new int[] {
-            1000,
+            100000,
             0,
             0,
             0});

+ 64 - 59
Exporters/FBX/BabylonFbxNative/BabylonMesh.cpp

@@ -440,77 +440,82 @@ BabylonMesh::BabylonMesh(BabylonNode* node) :
 	}
 	pivotMatrix = ConvertToBabylonCoordinateSystem( GetGeometryTransformation(fbxNode));
 
-	auto animStack = fbxNode->GetScene()->GetCurrentAnimationStack();
-	FbxString animStackName = animStack->GetName();
-	//FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName);
-	auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode;
-	auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate();
-	auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode);
-	auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode);
-	auto animLengthInFrame = endFrame - startFrame + 1;
-	_visibility = static_cast<float>(node->fbxNode()->Visibility.Get());
-	auto posAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"position", L"position", true, 0, static_cast<int>(animLengthInFrame), true);
-	auto rotAnim = std::make_shared<BabylonAnimation<babylon_vector4>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"rotationQuaternion", L"rotationQuaternion", true, 0, static_cast<int>(animLengthInFrame), true);
-	auto scaleAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"scaling", L"scaling", true, 0, static_cast<int>(animLengthInFrame), true);
-	auto visibilityAnim = std::make_shared<BabylonAnimation<float>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"visibility", L"visibility", true, 0, static_cast<int>(animLengthInFrame), true);
 	auto mesh = fbxNode->GetMesh();
-	_isVisible = fbxNode->Show.Get();
-	
-	auto rotCurveNode = fbxNode->LclRotation.GetCurveNode();
-	auto translateCurveNode = fbxNode->LclTranslation.GetCurveNode();
-	auto scalingCurveNode = fbxNode->LclScaling.GetCurveNode();
-	auto visibilityCurveNode = fbxNode->Visibility.GetCurveNode();
-	if (rotCurveNode || translateCurveNode || scalingCurveNode) {
-		for (auto ix = 0; ix < animLengthInFrame; ix++) {
-			FbxTime currTime;
-			currTime.SetFrame(startFrame + ix, animTimeMode);
-
-			babylon_animation_key<babylon_vector3> poskey;
-			babylon_animation_key<babylon_vector4> rotkey;
-			babylon_animation_key<babylon_vector3> scalekey;
-			poskey.frame = ix;
-			rotkey.frame = ix;
-			scalekey.frame = ix;
-			auto currTransform = node->GetLocal(currTime);
-			poskey.values = currTransform.translation();
-			rotkey.values = currTransform.rotationQuaternion();
-			scalekey.values = currTransform.scaling();
-			posAnim->appendKey(poskey);
-			rotAnim->appendKey(rotkey);
-			scaleAnim->appendKey(scalekey);
+	auto animStack = fbxNode->GetScene()->GetCurrentAnimationStack();
 
+	if (animStack) {
+		FbxString animStackName = animStack->GetName();
+		//FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName);
+		auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode;
+		auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate();
+		auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode);
+		auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode);
+		auto animLengthInFrame = endFrame - startFrame + 1;
+		_visibility = static_cast<float>(node->fbxNode()->Visibility.Get());
+		auto posAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"position", L"position", true, 0, static_cast<int>(animLengthInFrame), true);
+		auto rotAnim = std::make_shared<BabylonAnimation<babylon_vector4>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"rotationQuaternion", L"rotationQuaternion", true, 0, static_cast<int>(animLengthInFrame), true);
+		auto scaleAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"scaling", L"scaling", true, 0, static_cast<int>(animLengthInFrame), true);
+		auto visibilityAnim = std::make_shared<BabylonAnimation<float>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"visibility", L"visibility", true, 0, static_cast<int>(animLengthInFrame), true);
+
+		_isVisible = fbxNode->Show.Get();
+
+		auto rotCurveNode = fbxNode->LclRotation.GetCurveNode();
+		auto translateCurveNode = fbxNode->LclTranslation.GetCurveNode();
+		auto scalingCurveNode = fbxNode->LclScaling.GetCurveNode();
+		auto visibilityCurveNode = fbxNode->Visibility.GetCurveNode();
+		if (rotCurveNode || translateCurveNode || scalingCurveNode) {
+			for (auto ix = 0; ix < animLengthInFrame; ix++) {
+				FbxTime currTime;
+				currTime.SetFrame(startFrame + ix, animTimeMode);
+
+				babylon_animation_key<babylon_vector3> poskey;
+				babylon_animation_key<babylon_vector4> rotkey;
+				babylon_animation_key<babylon_vector3> scalekey;
+				poskey.frame = ix;
+				rotkey.frame = ix;
+				scalekey.frame = ix;
+				auto currTransform = node->GetLocal(currTime);
+				poskey.values = currTransform.translation();
+				rotkey.values = currTransform.rotationQuaternion();
+				scalekey.values = currTransform.scaling();
+				posAnim->appendKey(poskey);
+				rotAnim->appendKey(rotkey);
+				scaleAnim->appendKey(scalekey);
 
+
+			}
 		}
-	}
-	if (visibilityCurveNode) {
-		for (auto ix = 0; ix < animLengthInFrame; ix++) {
-			FbxTime currTime;
-			currTime.SetFrame(startFrame + ix, animTimeMode);
+		if (visibilityCurveNode) {
+			for (auto ix = 0; ix < animLengthInFrame; ix++) {
+				FbxTime currTime;
+				currTime.SetFrame(startFrame + ix, animTimeMode);
 
-			babylon_animation_key<float> visibilityKey;
+				babylon_animation_key<float> visibilityKey;
 
-			visibilityKey.frame = ix;
+				visibilityKey.frame = ix;
 
-			visibilityKey.values = static_cast<float>(node->fbxNode()->Visibility.EvaluateValue(currTime));
+				visibilityKey.values = static_cast<float>(node->fbxNode()->Visibility.EvaluateValue(currTime));
 
-			visibilityAnim->appendKey(visibilityKey);
+				visibilityAnim->appendKey(visibilityKey);
 
 
+			}
+		}
+
+		if (!posAnim->isConstant()){
+			animations.push_back(posAnim);
+		}
+		if (!rotAnim->isConstant()){
+			animations.push_back(rotAnim);
+		}
+		if (!scaleAnim->isConstant()){
+			animations.push_back(scaleAnim);
+		}
+		if (!visibilityAnim->isConstant()) {
+			animations.push_back(visibilityAnim);
 		}
 	}
-	
-	if (!posAnim->isConstant()){
-		animations.push_back(posAnim);
-	}
-	if (!rotAnim->isConstant()){
-		animations.push_back(rotAnim);
-	}
-	if (!scaleAnim->isConstant()){
-		animations.push_back(scaleAnim);
-	}
-	if (!visibilityAnim->isConstant()) {
-		animations.push_back(visibilityAnim);
-	}
+
 	if (!mesh) {
 		return;
 	}

+ 2 - 0
Exporters/FBX/readme.md

@@ -11,6 +11,8 @@ FBX Exporter produces a babylon scene file from an FBX asset
 
 ##Prerequisites
 To use this tool, you need to download the Visual C++ 2015 redistribuable package : http://www.microsoft.com/en-us/download/details.aspx?id=48145
+
+To build from source you need to install the Autodesk FBX SDK 2016.1 and copy the lib folder from the SDK install location to 3rdParty\Fbx2016.1\
 ##Usage
 FbxExporter.exe "fbx file" "outdir" [/fps:60|30|24] [/skipemptynodes]
 - fbx file : path to the source FBX asset

+ 2 - 0
Tools/Gulp/config.json

@@ -85,6 +85,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",

+ 81 - 0
Tools/Gulp/gulp-removeShaderComments.js

@@ -0,0 +1,81 @@
+'use strict';
+
+var through = require('through2');
+var PluginError = require('gulp-util').PluginError;
+var singleComment = 1;
+var multiComment = 2;
+
+function uncomment(str, opts) {
+    opts = opts || {};
+
+	var currentChar;
+	var nextChar;
+	var insideString = false;
+	var insideComment = 0;
+	var offset = 0;
+	var ret = '';
+
+    str = str.replace(/\r\n/g, '\n');
+    str = str.replace(/[ \f\t\v]+/g, ' ');
+    str = str.replace(/^\s*\n/gm, '');
+    
+	for (var i = 0; i < str.length; i++) {
+		currentChar = str[i];
+		nextChar = str[i + 1];
+
+		if (!insideComment && currentChar === '"') {
+			var escaped = str[i - 1] === '\\' && str[i - 2] !== '\\';
+			if (!escaped) {
+				insideString = !insideString;
+			}
+		}
+
+		if (insideString) {
+			continue;
+		}
+
+		if (!insideComment && currentChar + nextChar === '//') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = singleComment;
+			i++;
+		} else if (insideComment === singleComment && currentChar === '\n') {
+			insideComment = 0;
+			offset = i;
+		} else if (!insideComment && currentChar + nextChar === '/*') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = multiComment;
+			i++;
+			continue;
+		} else if (insideComment === multiComment && currentChar + nextChar === '*/') {
+			i++;
+			insideComment = 0;
+			offset = i + 1;
+			continue;
+		}
+	}
+
+	return ret + (insideComment ? '' : str.substr(offset));
+}
+
+function gulpUncomment(options) {
+    return main(options, uncomment);
+}
+
+function main(options, func) {
+    return through.obj(function (file, enc, cb) {
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+        if (file.isStream()) {
+            cb(new PluginError("Remove Shader Comments", "Streaming not supported."));
+        }
+        file.contents = new Buffer(func(file.contents.toString(), options));
+        this.push(file);
+        return cb();
+    });
+}
+
+module.exports = gulpUncomment;

+ 27 - 10
Tools/Gulp/gulpfile.js

@@ -11,6 +11,7 @@ var cleants = require('gulp-clean-ts-extends');
 var changed = require('gulp-changed');
 var runSequence = require('run-sequence');
 var replace = require("gulp-replace");
+var uncommentShader = require("./gulp-removeShaderComments");
 
 var config = require("./config.json");
 
@@ -33,7 +34,9 @@ function includeShadersName(filename) {
 
 gulp.task("includeShaders", function (cb) {
     includeShadersStream = config.includeShadersDirectories.map(function (shadersDef) {
-        return gulp.src(shadersDef.files).pipe(srcToVariable({
+        return gulp.src(shadersDef.files).
+            pipe(uncommentShader()).
+            pipe(srcToVariable({
             variableName: shadersDef.variable, asMap: true, namingCallback: includeShadersName
         }));
     });
@@ -42,7 +45,9 @@ gulp.task("includeShaders", function (cb) {
 
 gulp.task("shaders", ["includeShaders"], function (cb) {
     shadersStream = config.shadersDirectories.map(function (shadersDef) {
-        return gulp.src(shadersDef.files).pipe(srcToVariable({
+        return gulp.src(shadersDef.files).
+            pipe(uncommentShader()).
+            pipe(srcToVariable({
             variableName: shadersDef.variable, asMap: true, namingCallback: shadersName
         }));
     });
@@ -70,13 +75,25 @@ gulp.task('typescript-compile', function () {
             typescript: require('typescript'),
             experimentalDecorators: true
         }));
+    //If this gulp task is running on travis, file the build!
+    if (process.env.TRAVIS) {
+        var error = false;
+        tsResult.on('error', function () {
+            error = true;
+        }).on('end', function () {
+            if (error) {
+                console.log('Typescript compile failed');
+                process.exit(1);
+            }
+        });
+    }
     return merge2([
         tsResult.dts
             .pipe(concat(config.build.declarationFilename))
             .pipe(gulp.dest(config.build.outputDirectory)),
         tsResult.js
             .pipe(gulp.dest(config.build.srcOutputDirectory))
-    ]);
+    ])
 });
 
 gulp.task('typescript-sourcemaps', function () {
@@ -97,7 +114,7 @@ gulp.task('typescript-sourcemaps', function () {
 gulp.task("buildCore", ["shaders"], function () {
     return merge2(
         gulp.src(config.core.files),
-        shadersStream, 
+        shadersStream,
         includeShadersStream
         )
         .pipe(concat(config.build.minCoreFilename))
@@ -112,7 +129,7 @@ gulp.task("buildNoWorker", ["shaders"], function () {
     return merge2(
         gulp.src(config.core.files),
         gulp.src(config.extras.files),
-        shadersStream, 
+        shadersStream,
         includeShadersStream
         )
         .pipe(concat(config.build.minNoWorkerFilename))
@@ -128,8 +145,8 @@ gulp.task("build", ["workers", "shaders"], function () {
         gulp.src(config.core.files),
         gulp.src(config.extras.files),
         shadersStream,
-        workersStream, 
-        includeShadersStream
+        includeShadersStream,
+        workersStream
         )
         .pipe(concat(config.build.filename))
         .pipe(cleants())
@@ -142,14 +159,14 @@ gulp.task("build", ["workers", "shaders"], function () {
 });
 
 gulp.task("typescript", function (cb) {
-    runSequence("typescript-compile", "default");
+    runSequence("typescript-compile", "default", cb);
 });
 
 /**
  * The default task, call the tasks: build
  */
-gulp.task('default', function () {
-    return runSequence("buildNoWorker", "build", "buildCore");
+gulp.task('default', function (cb) {
+    runSequence("buildNoWorker", "build", "buildCore", cb);
 });
 
 /**

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


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


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


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


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


+ 2 - 0
dist/preview release/what's new.md

@@ -5,6 +5,8 @@
     - Support for shaders includes ([deltakosh](https://github.com/deltakosh))
     - new mesh type : `LineSystem` ([jerome](https://github.com/jbousquie))
     - SerializationHelper for complex classes using TypeScript decorators  ([deltakosh](https://github.com/deltakosh))
+    - StandardMaterial now supports Parallax and Parallax Occlusion Mapping ([nockawa](https://github.com/nockawa))
+    - Animations blending. See [demo here](http://www.babylonjs-playground.com/#2BLI9T#2). More [info here](NEED DOC!) ([deltakosh](https://github.com/deltakosh))
   - **Updates**
     - New OnPickTrigger support for spritesManager ([deltakosh](https://github.com/deltakosh))
     - New SPS method `digest()` ([jerome](https://github.com/jbousquie))    

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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.fireMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.furMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.gradientMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.lavaMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.normalMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3 - 3
materialsLibrary/dist/babylon.pbrMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.simpleMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.skyMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.terrainMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.triPlanarMaterial.min.js


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
materialsLibrary/dist/babylon.waterMaterial.min.js


+ 81 - 0
materialsLibrary/gulp-removeShaderComments.js

@@ -0,0 +1,81 @@
+'use strict';
+
+var through = require('through2');
+var PluginError = require('gulp-util').PluginError;
+var singleComment = 1;
+var multiComment = 2;
+
+function uncomment(str, opts) {
+    opts = opts || {};
+
+	var currentChar;
+	var nextChar;
+	var insideString = false;
+	var insideComment = 0;
+	var offset = 0;
+	var ret = '';
+
+    str = str.replace(/\r\n/g, '\n');
+    str = str.replace(/[ \f\t\v]+/g, ' ');
+    str = str.replace(/^\s*\n/gm, '');
+    
+	for (var i = 0; i < str.length; i++) {
+		currentChar = str[i];
+		nextChar = str[i + 1];
+
+		if (!insideComment && currentChar === '"') {
+			var escaped = str[i - 1] === '\\' && str[i - 2] !== '\\';
+			if (!escaped) {
+				insideString = !insideString;
+			}
+		}
+
+		if (insideString) {
+			continue;
+		}
+
+		if (!insideComment && currentChar + nextChar === '//') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = singleComment;
+			i++;
+		} else if (insideComment === singleComment && currentChar === '\n') {
+			insideComment = 0;
+			offset = i;
+		} else if (!insideComment && currentChar + nextChar === '/*') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = multiComment;
+			i++;
+			continue;
+		} else if (insideComment === multiComment && currentChar + nextChar === '*/') {
+			i++;
+			insideComment = 0;
+			offset = i + 1;
+			continue;
+		}
+	}
+
+	return ret + (insideComment ? '' : str.substr(offset));
+}
+
+function gulpUncomment(options) {
+    return main(options, uncomment);
+}
+
+function main(options, func) {
+    return through.obj(function (file, enc, cb) {
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+        if (file.isStream()) {
+            cb(new PluginError("Remove Shader Comments", "Streaming not supported."));
+        }
+        file.contents = new Buffer(func(file.contents.toString(), options));
+        this.push(file);
+        return cb();
+    });
+}
+
+module.exports = gulpUncomment;

+ 4 - 1
materialsLibrary/gulpfile.js

@@ -8,6 +8,7 @@ var cleants = require('gulp-clean-ts-extends');
 var replace = require("gulp-replace");
 var webserver = require('gulp-webserver');
 var uglify = require("gulp-uglify");
+var uncommentShader = require("./gulp-removeShaderComments");
 
 var config = require("./config.json");
 var extendsSearchRegex = /var\s__extends[\s\S]+?\};/g;
@@ -52,7 +53,9 @@ gulp.task('default', ["copyReference"], function () {
                 .pipe(gulp.dest(config.build.dtsOutputDirectory));
         }
         
-        var shader = gulp.src(material.shaderFiles).pipe(srcToVariable("BABYLON.Effect.ShadersStore", true, shadersName));
+        var shader = gulp.src(material.shaderFiles)
+                .pipe(uncommentShader())
+                .pipe(srcToVariable("BABYLON.Effect.ShadersStore", true, shadersName));
 
         return merge2(js, shader)
             .pipe(cleants())

+ 2 - 1
materialsLibrary/materials/pbr/pbr.fragment.fx

@@ -805,7 +805,8 @@ void main(void) {
 
 
     #ifdef BUMP
-        normalW = perturbNormal(viewDirectionW);
+		mat3 TBN = cotangent_frame(vNormalW * vBumpInfos.y, -viewDirectionW, vBumpUV);
+		normalW = perturbNormal(viewDirectionW, TBN, vBumpUV);
     #endif
 
     // Ambient color

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1394 - 1026
materialsLibrary/test/refs/babylon.max.js


+ 1 - 1
readme.md

@@ -18,7 +18,7 @@ You can help by testing or contributing to the next version.
 - **2.4-alpha** can be found [here](https://github.com/BabylonJS/Babylon.js/tree/master/dist/preview%20release)
 - We are not complicated people, but we still have some [coding guidelines](http://doc.babylonjs.com/generals/Approved_Naming_Conventions)
 - Before submitting your PR, just check that everything goes well by [creating the minified version](http://doc.babylonjs.com/generals/Creating_the_Mini-fied_Version)
-- Need help to contribute? We have a [documentation for you](http://pixelcodr.com/tutos/contribute/contribute.html)
+- Need help to contribute? We have a [general purpose documentation for you](http://pixelcodr.com/tutos/contribute/contribute.html) and a [Visual Studio specific one](http://doc.babylonjs.com/generals/setup_visualStudio)
 
 ## Documentation
 - [Documentation](http://doc.babylonjs.com)

+ 37 - 5
src/Animations/babylon.animation.js

@@ -23,18 +23,21 @@ var BABYLON;
     })();
     BABYLON.AnimationEvent = AnimationEvent;
     var Animation = (function () {
-        function Animation(name, targetProperty, framePerSecond, dataType, loopMode) {
+        function Animation(name, targetProperty, framePerSecond, dataType, loopMode, enableBlending) {
             this.name = name;
             this.targetProperty = targetProperty;
             this.framePerSecond = framePerSecond;
             this.dataType = dataType;
             this.loopMode = loopMode;
+            this.enableBlending = enableBlending;
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._stopped = false;
+            this._blendingFactor = 0;
             // The set of event that will be linked to this animation
             this._events = new Array();
             this.allowMatricesInterpolation = false;
+            this.blendingSpeed = 0.01;
             this._ranges = {};
             this.targetPropertyPath = targetProperty.split(".");
             this.dataType = dataType;
@@ -127,6 +130,8 @@ var BABYLON;
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this.currentFrame = 0;
+            this._blendingFactor = 0;
+            this._originalBlendValue = null;
         };
         Animation.prototype.isStopped = function () {
             return this._stopped;
@@ -277,17 +282,43 @@ var BABYLON;
             }
             return this._getKeyValue(this._keys[this._keys.length - 1].value);
         };
-        Animation.prototype.setValue = function (currentValue) {
+        Animation.prototype.setValue = function (currentValue, blend) {
+            if (blend === void 0) { blend = false; }
             // Set value
+            var path;
+            var destination;
             if (this.targetPropertyPath.length > 1) {
                 var property = this._target[this.targetPropertyPath[0]];
                 for (var index = 1; index < this.targetPropertyPath.length - 1; index++) {
                     property = property[this.targetPropertyPath[index]];
                 }
-                property[this.targetPropertyPath[this.targetPropertyPath.length - 1]] = currentValue;
+                path = this.targetPropertyPath[this.targetPropertyPath.length - 1];
+                destination = property;
             }
             else {
-                this._target[this.targetPropertyPath[0]] = currentValue;
+                path = this.targetPropertyPath[0];
+                destination = this._target;
+            }
+            // Blending
+            if (this.enableBlending && this._blendingFactor <= 1.0) {
+                if (!this._originalBlendValue) {
+                    this._originalBlendValue = destination[path];
+                }
+                if (this._originalBlendValue.prototype) {
+                    if (this._originalBlendValue.prototype.Lerp) {
+                        destination[path] = this._originalBlendValue.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                    }
+                    else {
+                        destination[path] = currentValue;
+                    }
+                }
+                else {
+                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                }
+                this._blendingFactor += this.blendingSpeed;
+            }
+            else {
+                destination[path] = currentValue;
             }
             if (this._target.markAsDirty) {
                 this._target.markAsDirty(this.targetProperty);
@@ -303,7 +334,8 @@ var BABYLON;
             var currentValue = this._interpolate(frame, 0, this.loopMode);
             this.setValue(currentValue);
         };
-        Animation.prototype.animate = function (delay, from, to, loop, speedRatio) {
+        Animation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
+            if (blend === void 0) { blend = false; }
             if (!this.targetPropertyPath || this.targetPropertyPath.length < 1) {
                 this._stopped = true;
                 return false;

+ 38 - 5
src/Animations/babylon.animation.ts

@@ -19,6 +19,7 @@
         private _highLimitsCache = {};
         private _stopped = false;
         public _target;
+        private _blendingFactor = 0;
         private _easingFunction: IEasingFunction;
 
         // The set of event that will be linked to this animation
@@ -29,6 +30,9 @@
 
         public allowMatricesInterpolation = false;
 
+        public blendingSpeed = 0.01;
+        private _originalBlendValue: any;
+
         private _ranges: { [name: string]: AnimationRange; } = {};
 
         static _PrepareAnimation(name: string, targetProperty: string, framePerSecond: number, totalFrame: number,
@@ -85,7 +89,7 @@
             return node.getScene().beginAnimation(node, 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
         }
 
-        constructor(public name: string, public targetProperty: string, public framePerSecond: number, public dataType: number, public loopMode?: number) {
+        constructor(public name: string, public targetProperty: string, public framePerSecond: number, public dataType: number, public loopMode?: number, public enableBlending?: boolean) {
             this.targetPropertyPath = targetProperty.split(".");
             this.dataType = dataType;
             this.loopMode = loopMode === undefined ? Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
@@ -144,6 +148,8 @@
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this.currentFrame = 0;
+            this._blendingFactor = 0;
+            this._originalBlendValue = null;
         }
 
         public isStopped(): boolean {
@@ -323,8 +329,11 @@
             return this._getKeyValue(this._keys[this._keys.length - 1].value);
         }
 
-        public setValue(currentValue: any): void {
+        public setValue(currentValue: any, blend: boolean = false): void {
             // Set value
+            var path: any;
+            var destination: any;
+
             if (this.targetPropertyPath.length > 1) {
                 var property = this._target[this.targetPropertyPath[0]];
 
@@ -332,9 +341,33 @@
                     property = property[this.targetPropertyPath[index]];
                 }
 
-                property[this.targetPropertyPath[this.targetPropertyPath.length - 1]] = currentValue;
+                path = this.targetPropertyPath[this.targetPropertyPath.length - 1]
+                destination = property;
+            } else {
+                path = this.targetPropertyPath[0];
+                destination = this._target;
+            }
+
+            // Blending
+            if (this.enableBlending && this._blendingFactor <= 1.0) {
+                if (!this._originalBlendValue) {
+                    this._originalBlendValue = destination[path];
+                }
+
+                if (this._originalBlendValue.prototype) { // Complex value
+                    
+                    if (this._originalBlendValue.prototype.Lerp) { // Lerp supported
+                        destination[path] = this._originalBlendValue.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                    } else { // Blending not supported
+                        destination[path] = currentValue;
+                    }
+
+                } else { // Direct value
+                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                }
+                this._blendingFactor += this.blendingSpeed;
             } else {
-                this._target[this.targetPropertyPath[0]] = currentValue;
+                destination[path] = currentValue;
             }
 
             if (this._target.markAsDirty) {
@@ -354,7 +387,7 @@
             this.setValue(currentValue);
         }
 
-        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number): boolean {
+        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, blend: boolean = false): boolean {
             if (!this.targetPropertyPath || this.targetPropertyPath.length < 1) {
                 this._stopped = true;
                 return false;

+ 12 - 6
src/Cameras/babylon.arcRotateCamera.js

@@ -75,7 +75,7 @@ var BABYLON;
                 if (sinb === 0) {
                     sinb = 0.0001;
                 }
-                var target = _this.target;
+                var target = _this._getTargetPosition();
                 target.addToRef(new BABYLON.Vector3(_this.radius * cosa * sinb, _this.radius * cosb, _this.radius * sina * sinb), _this._newPosition);
                 _this.position.copyFrom(_this._newPosition);
                 var up = _this.upVector;
@@ -88,7 +88,7 @@ var BABYLON;
                 _this._viewMatrix.m[13] += _this.targetScreenOffset.y;
                 _this._collisionTriggered = false;
             };
-            if (!this.target) {
+            if (!target) {
                 this.target = BABYLON.Vector3.Zero();
             }
             else {
@@ -127,12 +127,18 @@ var BABYLON;
             if (!ignoreParentClass) {
                 _super.prototype._updateCache.call(this);
             }
-            this._cache.target.copyFrom(this.target);
+            this._cache.target.copyFrom(this._getTargetPosition());
             this._cache.alpha = this.alpha;
             this._cache.beta = this.beta;
             this._cache.radius = this.radius;
             this._cache.targetScreenOffset.copyFrom(this.targetScreenOffset);
         };
+        ArcRotateCamera.prototype._getTargetPosition = function () {
+            if (this.target.getAbsolutePosition) {
+                return this.target.getAbsolutePosition();
+            }
+            return this.target;
+        };
         // Synchronized
         ArcRotateCamera.prototype._isSynchronizedViewMatrix = function () {
             if (!_super.prototype._isSynchronizedViewMatrix.call(this))
@@ -461,7 +467,7 @@ var BABYLON;
             }
         };
         ArcRotateCamera.prototype.rebuildAnglesAndRadius = function () {
-            var radiusv3 = this.position.subtract(this.target);
+            var radiusv3 = this.position.subtract(this._getTargetPosition());
             this.radius = radiusv3.length();
             // Alpha
             this.alpha = Math.acos(radiusv3.x / Math.sqrt(Math.pow(radiusv3.x, 2) + Math.pow(radiusv3.z, 2)));
@@ -480,7 +486,7 @@ var BABYLON;
             this.rebuildAnglesAndRadius();
         };
         ArcRotateCamera.prototype.setTarget = function (target) {
-            if (this.target.equals(target)) {
+            if (this._getTargetPosition().equals(target)) {
                 return;
             }
             this.target = target;
@@ -495,7 +501,7 @@ var BABYLON;
             if (sinb === 0) {
                 sinb = 0.0001;
             }
-            var target = this.target;
+            var target = this._getTargetPosition();
             target.addToRef(new BABYLON.Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
             if (this.getScene().collisionsEnabled && this.checkCollisions) {
                 this._collider.radius = this.collisionRadius;

+ 14 - 6
src/Cameras/babylon.arcRotateCamera.ts

@@ -138,7 +138,7 @@
         constructor(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene: Scene) {
             super(name, Vector3.Zero(), scene);
 
-            if (!this.target) {
+            if (!target) {
                 this.target = Vector3.Zero();
             } else {
                 this.target = target;
@@ -166,13 +166,21 @@
                 super._updateCache();
             }
 
-            this._cache.target.copyFrom(this.target);
+            this._cache.target.copyFrom(this._getTargetPosition());
             this._cache.alpha = this.alpha;
             this._cache.beta = this.beta;
             this._cache.radius = this.radius;
             this._cache.targetScreenOffset.copyFrom(this.targetScreenOffset);
         }
 
+        private _getTargetPosition(): Vector3 {
+            if ((<any>this.target).getAbsolutePosition) {
+                return (<any>this.target).getAbsolutePosition();
+            }
+
+            return this.target;
+        }
+
         // Synchronized
         public _isSynchronizedViewMatrix(): boolean {
             if (!super._isSynchronizedViewMatrix())
@@ -551,7 +559,7 @@
         }
 
         public rebuildAnglesAndRadius() {
-            var radiusv3 = this.position.subtract(this.target);
+            var radiusv3 = this.position.subtract(this._getTargetPosition());
             this.radius = radiusv3.length();
 
             // Alpha
@@ -577,7 +585,7 @@
         }
 
         public setTarget(target: Vector3): void {
-            if (this.target.equals(target)) {
+            if (this._getTargetPosition().equals(target)) {
                 return;
             }
             this.target = target;
@@ -595,7 +603,7 @@
                 sinb = 0.0001;
             }
 
-            var target = this.target;
+            var target = this._getTargetPosition();
             target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
             if (this.getScene().collisionsEnabled && this.checkCollisions) {
                 this._collider.radius = this.collisionRadius;
@@ -644,7 +652,7 @@
                 sinb = 0.0001;
             }
 
-            var target = this.target;
+            var target = this._getTargetPosition();
             target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
             this.position.copyFrom(this._newPosition);
 

+ 2 - 1
src/Loading/babylon.sceneLoader.js

@@ -97,11 +97,12 @@ var BABYLON;
                     importMeshFromData(data);
                 }, progressCallBack, database);
             };
-            if (scene.getEngine().enableOfflineSupport) {
+            if (scene.getEngine().enableOfflineSupport && !(sceneFilename.substr && sceneFilename.substr(0, 5) === "data:")) {
                 // Checking if a manifest file has been set for this scene and if offline mode has been requested
                 var database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
             }
             else {
+                // If the scene is a data stream or offline support is not enabled, it's a direct load
                 manifestChecked(true);
             }
         };

+ 4 - 3
src/Loading/babylon.sceneLoader.ts

@@ -123,11 +123,12 @@
                 }, progressCallBack, database);
             };
 
-            if (scene.getEngine().enableOfflineSupport) {
+            if (scene.getEngine().enableOfflineSupport && !(sceneFilename.substr && sceneFilename.substr(0, 5) === "data:")) {
                 // Checking if a manifest file has been set for this scene and if offline mode has been requested
                 var database = new Database(rootUrl + sceneFilename, manifestChecked);
             }
             else {
+                // If the scene is a data stream or offline support is not enabled, it's a direct load
                 manifestChecked(true);
             }
         }
@@ -187,7 +188,7 @@
                     scene.executeWhenReady(() => {
                         scene.getEngine().hideLoadingUI();
                     });
-                }                
+                }
             };
 
             var manifestChecked = success => {
@@ -215,4 +216,4 @@
             }
         }
     };
-}
+}

+ 27 - 1
src/Materials/babylon.standardMaterial.js

@@ -23,6 +23,8 @@ var BABYLON;
             this.EMISSIVE = false;
             this.SPECULAR = false;
             this.BUMP = false;
+            this.PARALLAX = false;
+            this.PARALLAXOCCLUSION = false;
             this.SPECULAROVERALPHA = false;
             this.CLIPPLANE = false;
             this.ALPHATEST = false;
@@ -119,6 +121,9 @@ var BABYLON;
             this.useSpecularOverAlpha = false;
             this.useReflectionOverAlpha = false;
             this.disableLighting = false;
+            this.useParallax = false;
+            this.useParallaxOcclusion = false;
+            this.parallaxScaleBias = 0.05;
             this.roughness = 0;
             this.indexOfRefraction = 0.98;
             this.invertRefractionY = true;
@@ -308,6 +313,12 @@ var BABYLON;
                     else {
                         needUVs = true;
                         this._defines.BUMP = true;
+                        if (this.useParallax) {
+                            this._defines.PARALLAX = true;
+                            if (this.useParallaxOcclusion) {
+                                this._defines.PARALLAXOCCLUSION = true;
+                            }
+                        }
                     }
                 }
                 if (this.refractionTexture && StandardMaterial.RefractionTextureEnabled) {
@@ -426,6 +437,12 @@ var BABYLON;
                 if (this._defines.BUMP) {
                     fallbacks.addFallback(0, "BUMP");
                 }
+                if (this._defines.PARALLAX) {
+                    fallbacks.addFallback(1, "PARALLAX");
+                }
+                if (this._defines.PARALLAXOCCLUSION) {
+                    fallbacks.addFallback(0, "PARALLAXOCCLUSION");
+                }
                 if (this._defines.SPECULAROVERALPHA) {
                     fallbacks.addFallback(0, "SPECULAROVERALPHA");
                 }
@@ -594,7 +611,7 @@ var BABYLON;
                     }
                     if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled) {
                         this._effect.setTexture("bumpSampler", this.bumpTexture);
-                        this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level);
+                        this._effect.setFloat3("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level, this.parallaxScaleBias);
                         this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
                     }
                     if (this.refractionTexture && StandardMaterial.RefractionTextureEnabled) {
@@ -793,6 +810,15 @@ var BABYLON;
         ], StandardMaterial.prototype, "disableLighting", void 0);
         __decorate([
             BABYLON.serialize()
+        ], StandardMaterial.prototype, "useParallax", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], StandardMaterial.prototype, "useParallaxOcclusion", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], StandardMaterial.prototype, "parallaxScaleBias", void 0);
+        __decorate([
+            BABYLON.serialize()
         ], StandardMaterial.prototype, "roughness", void 0);
         __decorate([
             BABYLON.serialize()

+ 29 - 3
src/Materials/babylon.standardMaterial.ts

@@ -1,4 +1,4 @@
-module BABYLON {   
+module BABYLON {
     class StandardMaterialDefines extends MaterialDefines {
         public DIFFUSE = false;
         public AMBIENT = false;
@@ -8,6 +8,8 @@
         public EMISSIVE = false;
         public SPECULAR = false;
         public BUMP = false;
+        public PARALLAX = false;
+        public PARALLAXOCCLUSION = false;
         public SPECULAROVERALPHA = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
@@ -155,6 +157,15 @@
         public disableLighting = false;
 
         @serialize()
+        public useParallax = false;
+
+        @serialize()
+        public useParallaxOcclusion = false;
+
+        @serialize()
+        public parallaxScaleBias = 0.05;
+
+        @serialize()
         public roughness = 0;
 
         @serialize()
@@ -398,6 +409,13 @@
                     } else {
                         needUVs = true;
                         this._defines.BUMP = true;
+
+                        if (this.useParallax) {
+                            this._defines.PARALLAX = true;
+                            if (this.useParallaxOcclusion) {
+                                this._defines.PARALLAXOCCLUSION = true;
+                            }
+                        }
                     }
                 }
 
@@ -544,6 +562,14 @@
                     fallbacks.addFallback(0, "BUMP");
                 }
 
+                if (this._defines.PARALLAX) {
+                    fallbacks.addFallback(1, "PARALLAX");
+                }
+
+                if (this._defines.PARALLAXOCCLUSION) {
+                    fallbacks.addFallback(0, "PARALLAXOCCLUSION");
+                }
+
                 if (this._defines.SPECULAROVERALPHA) {
                     fallbacks.addFallback(0, "SPECULAROVERALPHA");
                 }
@@ -766,7 +792,7 @@
                     if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled) {
                         this._effect.setTexture("bumpSampler", this.bumpTexture);
 
-                        this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level);
+                        this._effect.setFloat3("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level, this.parallaxScaleBias);
                         this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
                     }
 
@@ -937,4 +963,4 @@
         public static LightmapTextureEnabled = true;
         public static RefractionTextureEnabled = true;
     }
-} 
+} 

+ 1 - 1
src/Math/babylon.math.ts

@@ -591,6 +591,7 @@
     export class Vector3 {
 
         constructor(public x: number, public y: number, public z: number) {
+            
         }
 
         public toString(): string {
@@ -1520,7 +1521,6 @@
 
     export class Quaternion {
         constructor(public x: number = 0, public y: number = 0, public z: number = 0, public w: number = 1) {
-
         }
 
         public toString(): string {

+ 89 - 56
src/Mesh/babylon.abstractMesh.js

@@ -14,8 +14,8 @@ var BABYLON;
             // 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._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,47 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(AbstractMesh.prototype, "rotation", {
+            /**
+             * Getting the rotation object.
+             * If rotation quaternion is set, this vector will (almost always) be the Zero vector!
+             */
+            get: function () {
+                return this._rotation;
+            },
+            set: function (newRotation) {
+                this._rotation = newRotation;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(AbstractMesh.prototype, "scaling", {
+            get: function () {
+                return this._scaling;
+            },
+            set: function (newScaling) {
+                this._scaling = newScaling;
+                if (this.physicsImpostor) {
+                    this.physicsImpostor.forceUpdate();
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(AbstractMesh.prototype, "rotationQuaternion", {
+            get: function () {
+                return this._rotationQuaternion;
+            },
+            set: function (quaternion) {
+                this._rotationQuaternion = quaternion;
+                //reset the rotation vector. 
+                if (this.rotation.length()) {
+                    this.rotation.copyFromFloats(0, 0, 0);
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         AbstractMesh.prototype.updatePoseMatrix = function (matrix) {
             this._poseMatrix.copyFrom(matrix);
@@ -446,6 +485,14 @@ var BABYLON;
             // Scaling
             BABYLON.Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, BABYLON.Tmp.Matrix[1]);
             // Rotation
+            //rotate, if quaternion is set and rotation was used
+            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);
+                }
+            }
             if (this.rotationQuaternion) {
                 this.rotationQuaternion.toRotationMatrix(BABYLON.Tmp.Matrix[0]);
                 this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
@@ -603,61 +650,38 @@ var BABYLON;
             return this._boundingInfo.intersectsPoint(point);
         };
         // Physics
+        /**
+         *  @Deprecated. Use new PhysicsImpostor instead.
+         * */
         AbstractMesh.prototype.setPhysicsState = function (impostor, options) {
-            var physicsEngine = this.getScene().getPhysicsEngine();
-            if (!physicsEngine) {
-                return null;
-            }
-            impostor = impostor || BABYLON.PhysicsEngine.NoImpostor;
+            //legacy support
             if (impostor.impostor) {
-                // Old API
                 options = impostor;
                 impostor = impostor.impostor;
             }
-            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
-                physicsEngine._unregisterMesh(this);
-                return null;
-            }
-            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;
-            }
-            this._physicImpostor = impostor;
-            this._physicsMass = options.mass;
-            this._physicsFriction = options.friction;
-            this._physicRestitution = options.restitution;
-            return physicsEngine._registerMesh(this, impostor, options);
+            this.physicsImpostor = new BABYLON.PhysicsImpostor(this, impostor, options);
+            return this.physicsImpostor.physicsBody;
         };
         AbstractMesh.prototype.getPhysicsImpostor = function () {
-            if (!this._physicImpostor) {
-                return BABYLON.PhysicsEngine.NoImpostor;
-            }
-            return this._physicImpostor;
+            return this.physicsImpostor;
         };
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("mass");
+         */
         AbstractMesh.prototype.getPhysicsMass = function () {
-            if (!this._physicsMass) {
-                return 0;
-            }
-            return this._physicsMass;
+            return this.physicsImpostor.getParam("mass");
         };
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("friction");
+         */
         AbstractMesh.prototype.getPhysicsFriction = function () {
-            if (!this._physicsFriction) {
-                return 0;
-            }
-            return this._physicsFriction;
+            return this.physicsImpostor.getParam("friction");
         };
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("restitution");
+         */
         AbstractMesh.prototype.getPhysicsRestitution = function () {
-            if (!this._physicRestitution) {
-                return 0;
-            }
-            return this._physicRestitution;
+            return this.physicsImpostor.getParam("resitution");
         };
         AbstractMesh.prototype.getPositionInCameraSpace = function (camera) {
             if (!camera) {
@@ -672,26 +696,35 @@ var BABYLON;
             return this.absolutePosition.subtract(camera.position).length();
         };
         AbstractMesh.prototype.applyImpulse = function (force, contactPoint) {
-            if (!this._physicImpostor) {
+            if (!this.physicsImpostor) {
                 return;
             }
-            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
+            this.physicsImpostor.applyImpulse(force, contactPoint);
         };
         AbstractMesh.prototype.setPhysicsLinkWith = function (otherMesh, pivot1, pivot2, options) {
-            if (!this._physicImpostor) {
+            if (!this.physicsImpostor || !otherMesh.physicsImpostor) {
                 return;
             }
-            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2, options);
+            this.physicsImpostor.createJoint(otherMesh.physicsImpostor, BABYLON.PhysicsJoint.HingeJoint, {
+                mainPivot: pivot1,
+                connectedPivot: pivot2,
+                nativeParams: options
+            });
         };
+        /**
+         * @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
@@ -870,8 +903,8 @@ var BABYLON;
             // Animations
             this.getScene().stopAnimation(this);
             // Physics
-            if (this.getPhysicsImpostor() !== BABYLON.PhysicsEngine.NoImpostor) {
-                this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
+            if (this.physicsImpostor) {
+                this.physicsImpostor.dispose(!doNotRecurse);
             }
             // Intersections in progress
             for (index = 0; index < this._intersectionsInProgress.length; index++) {

+ 91 - 75
src/Mesh/babylon.abstractMesh.ts

@@ -30,9 +30,9 @@
         // 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 _rotation = new Vector3(0, 0, 0);
+        public _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 physicsImpostor: BABYLON.PhysicsImpostor;
+        //Deprecated, Legacy support
         public onPhysicsCollide: (collidedMesh: AbstractMesh, contact: any) => void; 
 
         // Collisions
@@ -158,6 +156,41 @@
             scene.addMesh(this);
         }
 
+        /**
+         * Getting the rotation object. 
+         * If rotation quaternion is set, this vector will (almost always) be the Zero vector!
+         */
+        public get rotation(): Vector3 {
+            return this._rotation;
+        }
+
+        public set rotation(newRotation: Vector3) {
+            this._rotation = newRotation;
+        }
+
+        public get scaling(): Vector3 {
+            return this._scaling;
+        }
+
+        public set scaling(newScaling: Vector3) {
+            this._scaling = newScaling;
+            if (this.physicsImpostor) {
+                this.physicsImpostor.forceUpdate();
+            }
+        }
+
+        public get rotationQuaternion() {
+            return this._rotationQuaternion;
+        }
+
+        public set rotationQuaternion(quaternion: Quaternion) {
+            this._rotationQuaternion = quaternion;
+            //reset the rotation vector. 
+            if (this.rotation.length()) {
+                this.rotation.copyFromFloats(0, 0, 0);
+            }
+        }
+
         // Methods
         public updatePoseMatrix(matrix: Matrix) {
             this._poseMatrix.copyFrom(matrix);
@@ -495,6 +528,16 @@
             Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
 
             // Rotation
+            
+            //rotate, if quaternion is set and rotation was used
+            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);
+                }
+            }
+
             if (this.rotationQuaternion) {
                 this.rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
                 this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
@@ -693,73 +736,42 @@
         }
 
         // Physics
-        public setPhysicsState(impostor?: any, options?: PhysicsBodyCreationOptions): any {
-            var physicsEngine = this.getScene().getPhysicsEngine();
-
-            if (!physicsEngine) {
-                return null;
-            }
-
-            impostor = impostor || PhysicsEngine.NoImpostor;
-
+        /**
+         *  @Deprecated. Use new PhysicsImpostor instead.
+         * */
+        public setPhysicsState(impostor?: any, options?: PhysicsImpostorParameters): any {
+            //legacy support
             if (impostor.impostor) {
-                // Old API
                 options = impostor;
                 impostor = impostor.impostor;
             }
-
-            if (impostor === PhysicsEngine.NoImpostor) {
-                physicsEngine._unregisterMesh(this);
-                return null;
-            }
-
-            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;
-            }
-
-            this._physicImpostor = impostor;
-            this._physicsMass = options.mass;
-            this._physicsFriction = options.friction;
-            this._physicRestitution = options.restitution;
-
-
-            return physicsEngine._registerMesh(this, impostor, options);
+            this.physicsImpostor = new PhysicsImpostor(this, impostor, options);
+            return this.physicsImpostor.physicsBody;
         }
 
-        public getPhysicsImpostor(): number {
-            if (!this._physicImpostor) {
-                return PhysicsEngine.NoImpostor;
-            }
-
-            return this._physicImpostor;
+        public getPhysicsImpostor(): PhysicsImpostor {
+            return this.physicsImpostor;
         }
 
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("mass");
+         */
         public getPhysicsMass(): number {
-            if (!this._physicsMass) {
-                return 0;
-            }
-
-            return this._physicsMass;
+            return this.physicsImpostor.getParam("mass")
         }
 
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("friction");
+         */
         public getPhysicsFriction(): number {
-            if (!this._physicsFriction) {
-                return 0;
-            }
-
-            return this._physicsFriction;
+            return this.physicsImpostor.getParam("friction")
         }
 
+        /**
+         * @Deprecated. Use getPhysicsImpostor().getParam("restitution");
+         */
         public getPhysicsRestitution(): number {
-            if (!this._physicRestitution) {
-                return 0;
-            }
-
-            return this._physicRestitution;
+            return this.physicsImpostor.getParam("resitution")
         }
 
         public getPositionInCameraSpace(camera?: Camera): Vector3 {
@@ -779,31 +791,40 @@
         }
 
         public applyImpulse(force: Vector3, contactPoint: Vector3): void {
-            if (!this._physicImpostor) {
+            if (!this.physicsImpostor) {
                 return;
             }
 
-            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
+            this.physicsImpostor.applyImpulse(force, contactPoint);
         }
 
         public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): void {
-            if (!this._physicImpostor) {
+            if (!this.physicsImpostor || !otherMesh.physicsImpostor) {
                 return;
             }
 
-            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2, options);
+            this.physicsImpostor.createJoint(otherMesh.physicsImpostor, PhysicsJoint.HingeJoint, {
+                mainPivot: pivot1,
+                connectedPivot: pivot2,
+                nativeParams: options
+            })
         }
 
+        /**
+         * @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
         }
 
 
@@ -1039,8 +1060,8 @@
             this.getScene().stopAnimation(this);
 
             // Physics
-            if (this.getPhysicsImpostor() !== PhysicsEngine.NoImpostor) {
-                this.setPhysicsState(PhysicsEngine.NoImpostor);
+            if (this.physicsImpostor) {
+                this.physicsImpostor.dispose(!doNotRecurse);
             }
 
             // Intersections in progress
@@ -1101,9 +1122,4 @@
             }
         }
     }
-}
-
-
-
-
-
+}

+ 17 - 13
src/Mesh/babylon.geometry.js

@@ -657,10 +657,11 @@ var BABYLON;
             /// Abstract class
             var _Primitive = (function (_super) {
                 __extends(_Primitive, _super);
-                function _Primitive(id, scene, vertexData, canBeRegenerated, mesh) {
+                function _Primitive(id, scene, _canBeRegenerated, mesh) {
+                    _super.call(this, id, scene, null, false, mesh); // updatable = false to be sure not to update vertices
+                    this._canBeRegenerated = _canBeRegenerated;
                     this._beingRegenerated = true;
-                    this._canBeRegenerated = canBeRegenerated;
-                    _super.call(this, id, scene, vertexData, false, mesh); // updatable = false to be sure not to update vertices
+                    this.regenerate();
                     this._beingRegenerated = false;
                 }
                 _Primitive.prototype.canBeRegenerated = function () {
@@ -708,14 +709,15 @@ var BABYLON;
             Primitives._Primitive = _Primitive;
             var Ribbon = (function (_super) {
                 __extends(Ribbon, _super);
+                // Members
                 function Ribbon(id, scene, pathArray, closeArray, closePath, offset, canBeRegenerated, mesh, side) {
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.pathArray = pathArray;
                     this.closeArray = closeArray;
                     this.closePath = closePath;
                     this.offset = offset;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Ribbon.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateRibbon({ pathArray: this.pathArray, closeArray: this.closeArray, closePath: this.closePath, offset: this.offset, sideOrientation: this.side });
@@ -728,11 +730,12 @@ var BABYLON;
             Primitives.Ribbon = Ribbon;
             var Box = (function (_super) {
                 __extends(Box, _super);
+                // Members
                 function Box(id, scene, size, canBeRegenerated, mesh, side) {
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.size = size;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Box.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateBox({ size: this.size, sideOrientation: this.side });
@@ -761,10 +764,10 @@ var BABYLON;
                 __extends(Sphere, _super);
                 function Sphere(id, scene, segments, diameter, canBeRegenerated, mesh, side) {
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.segments = segments;
                     this.diameter = diameter;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Sphere.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateSphere({ segments: this.segments, diameter: this.diameter, sideOrientation: this.side });
@@ -792,12 +795,13 @@ var BABYLON;
             Primitives.Sphere = Sphere;
             var Disc = (function (_super) {
                 __extends(Disc, _super);
+                // Members
                 function Disc(id, scene, radius, tessellation, canBeRegenerated, mesh, side) {
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.radius = radius;
                     this.tessellation = tessellation;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Disc.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateDisc({ radius: this.radius, tessellation: this.tessellation, sideOrientation: this.side });
@@ -813,13 +817,13 @@ var BABYLON;
                 function Cylinder(id, scene, height, diameterTop, diameterBottom, tessellation, subdivisions, canBeRegenerated, mesh, side) {
                     if (subdivisions === void 0) { subdivisions = 1; }
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.height = height;
                     this.diameterTop = diameterTop;
                     this.diameterBottom = diameterBottom;
                     this.tessellation = tessellation;
                     this.subdivisions = subdivisions;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Cylinder.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateCylinder({ height: this.height, diameterTop: this.diameterTop, diameterBottom: this.diameterBottom, tessellation: this.tessellation, subdivisions: this.subdivisions, sideOrientation: this.side });
@@ -851,11 +855,11 @@ var BABYLON;
                 __extends(Torus, _super);
                 function Torus(id, scene, diameter, thickness, tessellation, canBeRegenerated, mesh, side) {
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.diameter = diameter;
                     this.thickness = thickness;
                     this.tessellation = tessellation;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Torus.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateTorus({ diameter: this.diameter, thickness: this.thickness, tessellation: this.tessellation, sideOrientation: this.side });
@@ -885,10 +889,10 @@ var BABYLON;
             var Ground = (function (_super) {
                 __extends(Ground, _super);
                 function Ground(id, scene, width, height, subdivisions, canBeRegenerated, mesh) {
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.width = width;
                     this.height = height;
                     this.subdivisions = subdivisions;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Ground.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateGround({ width: this.width, height: this.height, subdivisions: this.subdivisions });
@@ -918,13 +922,13 @@ var BABYLON;
             var TiledGround = (function (_super) {
                 __extends(TiledGround, _super);
                 function TiledGround(id, scene, xmin, zmin, xmax, zmax, subdivisions, precision, canBeRegenerated, mesh) {
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.xmin = xmin;
                     this.zmin = zmin;
                     this.xmax = xmax;
                     this.zmax = zmax;
                     this.subdivisions = subdivisions;
                     this.precision = precision;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 TiledGround.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateTiledGround({ xmin: this.xmin, zmin: this.zmin, xmax: this.xmax, zmax: this.zmax, subdivisions: this.subdivisions, precision: this.precision });
@@ -939,9 +943,9 @@ var BABYLON;
                 __extends(Plane, _super);
                 function Plane(id, scene, size, canBeRegenerated, mesh, side) {
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.size = size;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 Plane.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreatePlane({ size: this.size, sideOrientation: this.side });
@@ -970,6 +974,7 @@ var BABYLON;
                 __extends(TorusKnot, _super);
                 function TorusKnot(id, scene, radius, tube, radialSegments, tubularSegments, p, q, canBeRegenerated, mesh, side) {
                     if (side === void 0) { side = BABYLON.Mesh.DEFAULTSIDE; }
+                    _super.call(this, id, scene, canBeRegenerated, mesh);
                     this.radius = radius;
                     this.tube = tube;
                     this.radialSegments = radialSegments;
@@ -977,7 +982,6 @@ var BABYLON;
                     this.p = p;
                     this.q = q;
                     this.side = side;
-                    _super.call(this, id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
                 }
                 TorusKnot.prototype._regenerateVertexData = function () {
                     return BABYLON.VertexData.CreateTorusKnot({ radius: this.radius, tube: this.tube, radialSegments: this.radialSegments, tubularSegments: this.tubularSegments, p: this.p, q: this.q, sideOrientation: this.side });

+ 26 - 126
src/Mesh/babylon.geometry.ts

@@ -820,14 +820,13 @@
 
         /// Abstract class
         export class _Primitive extends Geometry {
-            // Private
+
             private _beingRegenerated: boolean;
-            private _canBeRegenerated: boolean;
 
-            constructor(id: string, scene: Scene, vertexData?: VertexData, canBeRegenerated?: boolean, mesh?: Mesh) {
+            constructor(id: string, scene: Scene, private _canBeRegenerated?: boolean, mesh?: Mesh) {
+                super(id, scene, null, false, mesh); // updatable = false to be sure not to update vertices
                 this._beingRegenerated = true;
-                this._canBeRegenerated = canBeRegenerated;
-                super(id, scene, vertexData, false, mesh); // updatable = false to be sure not to update vertices
+                this.regenerate();
                 this._beingRegenerated = false;
             }
 
@@ -884,20 +883,9 @@
 
         export class Ribbon extends _Primitive {
             // Members
-            public pathArray: Vector3[][];
-            public closeArray: boolean;
-            public closePath: boolean;
-            public offset: number;
-            public side: number;
-
-            constructor(id: string, scene: Scene, pathArray: Vector3[][], closeArray: boolean, closePath: boolean, offset: number, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.pathArray = pathArray;
-                this.closeArray = closeArray;
-                this.closePath = closePath;
-                this.offset = offset;
-                this.side = side;
 
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public pathArray: Vector3[][], public closeArray: boolean, public closePath: boolean, public offset: number, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -911,14 +899,8 @@
 
         export class Box extends _Primitive {
             // Members
-            public size: number;
-            public side: number;
-
-            constructor(id: string, scene: Scene, size: number, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.size = size;
-                this.side = side;
-
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public size: number, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -952,17 +934,9 @@
         }
 
         export class Sphere extends _Primitive {
-            // Members
-            public segments: number;
-            public diameter: number;
-            public side: number;
 
-            constructor(id: string, scene: Scene, segments: number, diameter: number, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.segments = segments;
-                this.diameter = diameter;
-                this.side = side;
-
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public segments: number, public diameter: number, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -998,16 +972,9 @@
 
         export class Disc extends _Primitive {
             // Members
-            public radius: number;
-            public tessellation: number;
-            public side: number;
-
-            constructor(id: string, scene: Scene, radius: number, tessellation: number, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.radius = radius;
-                this.tessellation = tessellation;
-                this.side = side;
 
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public radius: number, public tessellation: number, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -1021,23 +988,9 @@
 
 
         export class Cylinder extends _Primitive {
-            // Members
-            public height: number;
-            public diameterTop: number;
-            public diameterBottom: number;
-            public tessellation: number;
-            public subdivisions: number;
-            public side: number;
 
-            constructor(id: string, scene: Scene, height: number, diameterTop: number, diameterBottom: number, tessellation: number, subdivisions: number = 1, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.height = height;
-                this.diameterTop = diameterTop;
-                this.diameterBottom = diameterBottom;
-                this.tessellation = tessellation;
-                this.subdivisions = subdivisions;
-                this.side = side;
-
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public height: number, public diameterTop: number, public diameterBottom: number, public tessellation: number, public subdivisions: number = 1, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -1074,19 +1027,9 @@
         }
 
         export class Torus extends _Primitive {
-            // Members
-            public diameter: number;
-            public thickness: number;
-            public tessellation: number;
-            public side: number;
 
-            constructor(id: string, scene: Scene, diameter: number, thickness: number, tessellation: number, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.diameter = diameter;
-                this.thickness = thickness;
-                this.tessellation = tessellation;
-                this.side = side;
-
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public diameter: number, public thickness: number, public tessellation: number, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -1122,17 +1065,9 @@
         }
 
         export class Ground extends _Primitive {
-            // Members
-            public width: number;
-            public height: number;
-            public subdivisions: number;
-
-            constructor(id: string, scene: Scene, width: number, height: number, subdivisions: number, canBeRegenerated?: boolean, mesh?: Mesh) {
-                this.width = width;
-                this.height = height;
-                this.subdivisions = subdivisions;
 
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public width: number, public height: number, public subdivisions: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -1168,23 +1103,9 @@
         }
 
         export class TiledGround extends _Primitive {
-            // Members
-            public xmin: number;
-            public zmin: number;
-            public xmax: number;
-            public zmax: number;
-            public subdivisions: { w: number; h: number; };
-            public precision: { w: number; h: number; };
-
-            constructor(id: string, scene: Scene, xmin: number, zmin: number, xmax: number, zmax: number, subdivisions: { w: number; h: number; }, precision: { w: number; h: number; }, canBeRegenerated?: boolean, mesh?: Mesh) {
-                this.xmin = xmin;
-                this.zmin = zmin;
-                this.xmax = xmax;
-                this.zmax = zmax;
-                this.subdivisions = subdivisions;
-                this.precision = precision;
 
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public xmin: number, public zmin: number, public xmax: number, public zmax: number, public subdivisions: { w: number; h: number; }, public precision: { w: number; h: number; }, canBeRegenerated?: boolean, mesh?: Mesh) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -1197,15 +1118,9 @@
         }
 
         export class Plane extends _Primitive {
-            // Members
-            public size: number;
-            public side: number;
-
-            constructor(id: string, scene: Scene, size: number, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.size = size;
-                this.side = side;
 
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+            constructor(id: string, scene: Scene, public size: number, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -1239,25 +1154,9 @@
         }
 
         export class TorusKnot extends _Primitive {
-            // Members
-            public radius: number;
-            public tube: number;
-            public radialSegments: number;
-            public tubularSegments: number;
-            public p: number;
-            public q: number;
-            public side: number;
-
-            constructor(id: string, scene: Scene, radius: number, tube: number, radialSegments: number, tubularSegments: number, p: number, q: number, canBeRegenerated?: boolean, mesh?: Mesh, side: number = Mesh.DEFAULTSIDE) {
-                this.radius = radius;
-                this.tube = tube;
-                this.radialSegments = radialSegments;
-                this.tubularSegments = tubularSegments;
-                this.p = p;
-                this.q = q;
-                this.side = side;
-
-                super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
+
+            constructor(id: string, scene: Scene, public radius: number, public tube: number, public radialSegments: number, public tubularSegments: number, public p: number, public q: number, canBeRegenerated?: boolean, mesh?: Mesh, public side: number = Mesh.DEFAULTSIDE) {
+                super(id, scene, canBeRegenerated, mesh);
             }
 
             public _regenerateVertexData(): VertexData {
@@ -1297,3 +1196,4 @@
     }
 }
 
+

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

@@ -715,16 +715,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;
@@ -1246,13 +1236,6 @@ var BABYLON;
                     mesh.numBoneInfluencers = parsedMesh.numBoneInfluencers;
                 }
             }
-            // Physics
-            if (parsedMesh.physicsImpostor) {
-                if (!scene.isPhysicsEnabled()) {
-                    scene.enablePhysics();
-                }
-                mesh.setPhysicsState({ impostor: parsedMesh.physicsImpostor, mass: parsedMesh.physicsMass, friction: parsedMesh.physicsFriction, restitution: parsedMesh.physicsRestitution });
-            }
             // Animations
             if (parsedMesh.animations) {
                 for (var animationIndex = 0; animationIndex < parsedMesh.animations.length; animationIndex++) {

+ 1 - 21
src/Mesh/babylon.mesh.ts

@@ -724,6 +724,7 @@
             if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
             }
+
             var callbackIndex: number;
             for (callbackIndex = 0; callbackIndex < this._onBeforeRenderCallbacks.length; callbackIndex++) {
                 this._onBeforeRenderCallbacks[callbackIndex](this);
@@ -822,18 +823,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();
@@ -1472,15 +1461,6 @@
                 }
             }
 
-            // Physics
-            if (parsedMesh.physicsImpostor) {
-                if (!scene.isPhysicsEnabled()) {
-                    scene.enablePhysics();
-                }
-
-                mesh.setPhysicsState({ impostor: parsedMesh.physicsImpostor, mass: parsedMesh.physicsMass, friction: parsedMesh.physicsFriction, restitution: parsedMesh.physicsRestitution });
-            }
-
             // Animations
             if (parsedMesh.animations) {
                 for (var animationIndex = 0; animationIndex < parsedMesh.animations.length; animationIndex++) {

+ 211 - 248
src/Physics/Plugins/babylon.cannonJSPlugin.js

@@ -1,124 +1,203 @@
 var BABYLON;
 (function (BABYLON) {
     var CannonJSPlugin = (function () {
-        function CannonJSPlugin(_useDeltaForWorldStep) {
+        function CannonJSPlugin(_useDeltaForWorldStep, iterations) {
             if (_useDeltaForWorldStep === void 0) { _useDeltaForWorldStep = true; }
+            if (iterations === void 0) { iterations = 10; }
             this._useDeltaForWorldStep = _useDeltaForWorldStep;
-            this._registeredMeshes = [];
+            this.name = "CannonJSPlugin";
             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;
-                    }
-                }
-            };
+            //See https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
+            this._currentCollisionGroup = 2;
+            this._minus90X = new BABYLON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
+            this._plus90X = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+            this._tmpPosition = BABYLON.Vector3.Zero();
+            this._tmpQuaternion = new BABYLON.Quaternion();
+            this._tmpDeltaPosition = BABYLON.Vector3.Zero();
+            this._tmpDeltaRotation = new BABYLON.Quaternion();
+            this._tmpUnityRotation = new BABYLON.Quaternion();
+            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.initialize = function (iterations) {
-            if (iterations === void 0) { iterations = 10; }
-            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._checkWithEpsilon = function (value) {
-            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        CannonJSPlugin.prototype.executeStep = function (delta, impostors) {
+            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
         };
-        CannonJSPlugin.prototype.runOneStep = function (delta) {
-            var _this = this;
-            this._world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
-            this._registeredMeshes.forEach(function (registeredMesh) {
-                // Body position
-                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);
+        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();
                 }
-                //is the physics collision callback is set?
-                if (registeredMesh.mesh.onPhysicsCollide) {
-                    if (!registeredMesh.collisionFunction) {
-                        registeredMesh.collisionFunction = function (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);
-                                }
-                            }
-                        };
-                        registeredMesh.body.addEventListener("collide", registeredMesh.collisionFunction);
-                    }
+                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(impostor);
                 }
-                else {
-                    //unregister, in case the function was removed for some reason
-                    if (registeredMesh.collisionFunction) {
-                        registeredMesh.body.removeEventListener("collide", registeredMesh.collisionFunction);
+                //create the body and material
+                var material = this._addMaterial("mat-" + impostor.mesh.uniqueId, impostor.getParam("friction"), impostor.getParam("restitution"));
+                var bodyCreationObject = {
+                    mass: impostor.getParam("mass"),
+                    material: material
+                };
+                // A simple extend, in case native options were used.
+                var nativeOptions = impostor.getParam("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);
         };
-        CannonJSPlugin.prototype.setGravity = function (gravity) {
-            this._gravity = gravity;
-            this._world.gravity.set(gravity.x, gravity.y, gravity.z);
+        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.getGravity = function () {
-            return this._gravity;
+        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.registerMesh = function (mesh, impostor, options) {
-            this.unregisterMesh(mesh);
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+        CannonJSPlugin.prototype.generateJoint = function (impostorJoint) {
+            var mainBody = impostorJoint.mainImpostor.physicsBody;
+            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
+            if (!mainBody || !connectedBody) {
+                return;
             }
-            mesh.computeWorldMatrix(true);
-            var shape = this._createShape(mesh, impostor);
-            return this._createRigidBodyFromShape(shape, mesh, options);
+            var constraint;
+            var jointData = impostorJoint.joint.jointData;
+            //TODO - https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
+            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
+            };
+            if (!jointData.collision) {
+                //add 1st body to a collision group of its own, if it is not in 1
+                if (mainBody.collisionFilterGroup === 1) {
+                    mainBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                if (connectedBody.collisionFilterGroup === 1) {
+                    connectedBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                //add their mask to the collisionFilterMask of each other:
+                connectedBody.collisionFilterMask = connectedBody.collisionFilterMask | ~mainBody.collisionFilterGroup;
+                mainBody.collisionFilterMask = mainBody.collisionFilterMask | ~connectedBody.collisionFilterGroup;
+            }
+            switch (impostorJoint.joint.type) {
+                case BABYLON.PhysicsJoint.HingeJoint:
+                    constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
+                    break;
+                case BABYLON.PhysicsJoint.DistanceJoint:
+                    constraint = new CANNON.DistanceConstraint(mainBody, connectedBody, jointData.maxDistance || 2);
+                    break;
+                default:
+                    constraint = new CANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
+                    break;
+            }
+            impostorJoint.joint.physicsJoint = constraint;
+            this.world.addConstraint(constraint);
         };
-        CannonJSPlugin.prototype._createShape = function (mesh, impostor) {
+        CannonJSPlugin.prototype.removeJoint = function (joint) {
+            //TODO
+        };
+        CannonJSPlugin.prototype._addMaterial = function (name, 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");
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
+            this._physicsMaterials.push(currentMat);
+            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) {
+            switch (impostor.type) {
                 case BABYLON.PhysicsEngine.SphereImpostor:
                     var bbox = mesh.getBoundingInfo().boundingBox;
                     var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
@@ -137,14 +216,14 @@ var BABYLON;
                     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");
+                    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); //this._createConvexPolyhedron(rawVerts, rawFaces, mesh);
+                    returnValue = new CANNON.Trimesh(rawVerts, rawFaces);
                     break;
                 case BABYLON.PhysicsEngine.HeightmapImpostor:
                     returnValue = this._createHeightmap(mesh);
@@ -153,23 +232,6 @@ var BABYLON;
             mesh.rotationQuaternion = oldQuaternion;
             return returnValue;
         };
-        CannonJSPlugin.prototype._createConvexPolyhedron = function (rawVerts, rawFaces, mesh) {
-            var verts = [], faces = [];
-            mesh.computeWorldMatrix(true);
-            //reuse this variable
-            var transformed = BABYLON.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);
-                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);
             var matrix = [];
@@ -217,52 +279,28 @@ var BABYLON;
             shape.minY = minY;
             return shape;
         };
-        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._createRigidBodyFromShape = function (shape, mesh, options) {
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
+        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 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);
+            this._tmpDeltaPosition.copyFrom(mesh.position.subtract(bbox.center));
+            var quaternion = mesh.rotationQuaternion;
+            this._tmpPosition.copyFrom(mesh.getBoundingInfo().boundingBox.center);
             //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) {
+            if (impostor.type === BABYLON.PhysicsEngine.PlaneImpostor || impostor.type === BABYLON.PhysicsEngine.HeightmapImpostor) {
                 //-90 DEG in X, precalculated
-                var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                body.quaternion = body.quaternion.mult(tmpQ);
+                quaternion = quaternion.multiply(this._minus90X);
                 //Invert! (Precalculated, 90 deg in X)
-                deltaRotation = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+                //No need to clone. this will never change.
+                impostor.setDeltaRotation(this._plus90X);
             }
             //If it is a heightfield, if should be centered.
-            if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
+            if (impostor.type === BABYLON.PhysicsEngine.HeightmapImpostor) {
                 //calculate the correct body position:
                 var rotationQuaternion = mesh.rotationQuaternion;
-                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.rotationQuaternion = this._tmpUnityRotation;
                 mesh.computeWorldMatrix(true);
                 //get original center with no rotation
                 var center = mesh.getBoundingInfo().boundingBox.center.clone();
@@ -275,113 +313,38 @@ var BABYLON;
                 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);
+                this._tmpPosition.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;
+                this._tmpDeltaPosition.copyFrom(mesh.getBoundingInfo().boundingBox.center.subtract(center));
+                this._tmpDeltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
                 mesh.setPivotMatrix(oldPivot);
                 mesh.computeWorldMatrix(true);
             }
-            else if (shape.type === CANNON.Shape.types.TRIMESH) {
-                deltaPosition = BABYLON.Vector3.Zero();
+            else if (impostor.type === BABYLON.PhysicsEngine.MeshImpostor) {
+                this._tmpDeltaPosition.copyFromFloats(0, 0, 0);
+                this._tmpPosition.copyFrom(mesh.position);
             }
-            //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;
+            impostor.setDeltaPosition(this._tmpDeltaPosition);
+            //Now update the impostor object
+            impostor.physicsBody.position.copy(this._tmpPosition);
+            impostor.physicsBody.quaternion.copy(quaternion);
         };
-        CannonJSPlugin.prototype.registerMeshesAsCompound = function (parts, options) {
-            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.setTransformationFromPhysicsBody = function (impostor) {
+            impostor.mesh.position.copyFrom(impostor.physicsBody.position);
+            impostor.mesh.rotationQuaternion.copyFrom(impostor.physicsBody.quaternion);
         };
-        CannonJSPlugin.prototype._unbindBody = function (body) {
-            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;
-                    registeredMesh.delta = null;
-                    registeredMesh.deltaRotation = null;
-                }
-            }
-        };
-        CannonJSPlugin.prototype.unregisterMesh = function (mesh) {
-            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) {
-            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) {
-            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) {
-                    body2 = registeredMesh.body;
-                    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 () {
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
+        CannonJSPlugin.prototype.setPhysicsBodyTransformation = function (impostor, newPosition, newRotation) {
+            impostor.physicsBody.position.copy(newPosition);
+            impostor.physicsBody.quaternion.copy(newRotation);
         };
         CannonJSPlugin.prototype.isSupported = function () {
             return window.CANNON !== undefined;
         };
-        CannonJSPlugin.prototype.getWorldObject = function () {
-            return this._world;
+        CannonJSPlugin.prototype.setVelocity = function (impostor, velocity) {
+            impostor.physicsBody.velocity.copy(velocity);
         };
-        CannonJSPlugin.prototype.getPhysicsBodyOfMesh = function (mesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
-                }
-            }
-            return null;
+        CannonJSPlugin.prototype.dispose = function () {
+            //nothing to do, actually.
         };
         return CannonJSPlugin;
     })();

+ 229 - 311
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -1,109 +1,216 @@
 module BABYLON {
     declare var CANNON;
 
-    interface IRegisteredMesh {
-        mesh: AbstractMesh;
-        body: any; //Cannon body
-        material: any;
-        delta: Vector3;
-        deltaRotation: Quaternion;
-        type: any;
-        collisionFunction?: (event: any) => void;
-
-    }
-
     export class CannonJSPlugin implements IPhysicsEnginePlugin {
 
-        private _world: any;
-        private _registeredMeshes: Array<IRegisteredMesh> = [];
+        public world: any; //CANNON.World
+        public name: string = "CannonJSPlugin";
         private _physicsMaterials = [];
-        private _gravity: Vector3;
         private _fixedTimeStep: number = 1 / 60;
-        //private _maxSubSteps : number = 15;
-
-        public name = "CannonJS";
-
-        public constructor(private _useDeltaForWorldStep: boolean = true) {
+        //See https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
+        private _currentCollisionGroup = 2;
 
+        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 initialize(iterations: number = 10): void {
-            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);
         }
 
-        private _checkWithEpsilon(value: number): number {
-            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
+        public executeStep(delta: number, impostors: Array<PhysicsImpostor>): void {
+            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
         }
 
-        public runOneStep(delta: number): void {
+        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);
+        }
 
-            this._world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
+        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);
 
-            this._registeredMeshes.forEach((registeredMesh) => {
+            impostor.physicsBody.applyImpulse(impulse, worldPoint);
+        }
 
-                // Body position
-                var bodyX = registeredMesh.body.position.x,
-                    bodyY = registeredMesh.body.position.y,
-                    bodyZ = registeredMesh.body.position.z;
+        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;
+            }
 
-                registeredMesh.mesh.position.x = bodyX + registeredMesh.delta.x;
-                registeredMesh.mesh.position.y = bodyY + registeredMesh.delta.y;
-                registeredMesh.mesh.position.z = bodyZ + registeredMesh.delta.z;
+            //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);
+                }
 
-                registeredMesh.mesh.rotationQuaternion.copyFrom(registeredMesh.body.quaternion);
-                if (registeredMesh.deltaRotation) {
-                    registeredMesh.mesh.rotationQuaternion.multiplyInPlace(registeredMesh.deltaRotation);
+                var shape = this._createShape(impostor);
+                
+                //unregister events, if body is being changed
+                var oldBody = impostor.physicsBody;
+                if (oldBody) {
+                    this.removePhysicsBody(impostor);
                 }
+                
+                //create the body and material
+                var material = this._addMaterial("mat-" + impostor.mesh.uniqueId, impostor.getParam("friction"), impostor.getParam("restitution"));
+
+                var bodyCreationObject = {
+                    mass: impostor.getParam("mass"),
+                    material: material
+                };
+                // A simple extend, in case native options were used.
+                var nativeOptions = impostor.getParam("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);
+        }
 
-                //is the physics collision callback is set?
-                if (registeredMesh.mesh.onPhysicsCollide) {
-                    if (!registeredMesh.collisionFunction) {
-                        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);
-                                }
+        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");
                         }
-                        registeredMesh.body.addEventListener("collide", registeredMesh.collisionFunction);
-                    }
-                } else {
-                    //unregister, in case the function was removed for some reason
-                    if (registeredMesh.collisionFunction) {
-                        registeredMesh.body.removeEventListener("collide", registeredMesh.collisionFunction);
                     }
+                    mesh.getChildMeshes().forEach(processMesh.bind(this, mesh.position));
                 }
-            });
+                meshChildren.forEach(processMesh.bind(this, Vector3.Zero()));
+            }
         }
 
-        public setGravity(gravity: Vector3): void {
-            this._gravity = gravity;
-            this._world.gravity.set(gravity.x, gravity.y, gravity.z);
+        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 getGravity(): Vector3 {
-            return this._gravity;
+        public generateJoint(impostorJoint: PhysicsImpostorJoint) {
+            var mainBody = impostorJoint.mainImpostor.physicsBody;
+            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
+            if (!mainBody || !connectedBody) {
+                return;
+            }
+            var constraint;
+            var jointData = impostorJoint.joint.jointData;
+            //TODO - https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
+            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
+            };
+            if (!jointData.collision) {
+                //add 1st body to a collision group of its own, if it is not in 1
+                if (mainBody.collisionFilterGroup === 1) {
+                    mainBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                if (connectedBody.collisionFilterGroup === 1) {
+                    connectedBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                //add their mask to the collisionFilterMask of each other:
+                connectedBody.collisionFilterMask = connectedBody.collisionFilterMask | ~mainBody.collisionFilterGroup;
+                mainBody.collisionFilterMask = mainBody.collisionFilterMask | ~connectedBody.collisionFilterGroup;
+            }
+            switch (impostorJoint.joint.type) {
+                case PhysicsJoint.HingeJoint:
+                    constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
+                    break;
+                case PhysicsJoint.DistanceJoint:
+                    constraint = new CANNON.DistanceConstraint(mainBody, connectedBody, (<DistanceJointData>jointData).maxDistance || 2)
+                    break;
+                default:
+                    constraint = new CANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
+                    break;
+            }
+            impostorJoint.joint.physicsJoint = constraint;
+            this.world.addConstraint(constraint);
         }
 
-        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsBodyCreationOptions): any {
-            this.unregisterMesh(mesh);
+        public removeJoint(joint: PhysicsImpostorJoint) {
+            //TODO
+        }
+
+        private _addMaterial(name: string, friction: number, restitution: number) {
+            var index;
+            var mat;
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
 
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+                if (mat.friction === friction && mat.restitution === restitution) {
+                    return mat;
+                }
             }
 
-            mesh.computeWorldMatrix(true);
+            var currentMat = new CANNON.Material("mat");
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
 
-            var shape = this._createShape(mesh, impostor);
+            this._physicsMaterials.push(currentMat);
+            return currentMat;
+        }
 
-            return this._createRigidBodyFromShape(shape, mesh, options);
+        private _checkWithEpsilon(value: number): number {
+            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
         }
 
-        private _createShape(mesh: AbstractMesh, impostor: number) {
-		
+        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);
@@ -111,7 +218,7 @@
 
             var returnValue;
 
-            switch (impostor) {
+            switch (impostor.type) {
                 case PhysicsEngine.SphereImpostor:
                     var bbox = mesh.getBoundingInfo().boundingBox;
                     var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
@@ -132,14 +239,14 @@
                     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, Cannon.js PlaneImposter might not behave as you wish. Consider using BoxImposter instead");
+                    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); //this._createConvexPolyhedron(rawVerts, rawFaces, mesh);
+                    returnValue = new CANNON.Trimesh(rawVerts, rawFaces);
                     break;
                 case PhysicsEngine.HeightmapImpostor:
                     returnValue = this._createHeightmap(mesh);
@@ -152,29 +259,6 @@
             return returnValue;
         }
 
-        private _createConvexPolyhedron(rawVerts: number[] | Float32Array, rawFaces: number[] | Int32Array, mesh: AbstractMesh): any {
-            var verts = [], faces = [];
-
-            mesh.computeWorldMatrix(true);
-
-            //reuse this variable
-            var transformed = Vector3.Zero();
-            // Get vertices
-            for (var i = 0; i < rawVerts.length; i += 3) {
-                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;
-        }
-
         private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
             var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
             var matrix = [];
@@ -235,65 +319,39 @@
             return shape;
         }
 
-        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 _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsBodyCreationOptions): any {
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-            
+        private _minus90X = new Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
+        private _plus90X = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+        private _tmpPosition: Vector3 = Vector3.Zero();
+        private _tmpQuaternion: Quaternion = new Quaternion();
+        private _tmpDeltaPosition: Vector3 = Vector3.Zero();
+        private _tmpDeltaRotation: Quaternion = new Quaternion();
+        private _tmpUnityRotation: Quaternion = new Quaternion();
+
+        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 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)
-            });
+            this._tmpDeltaPosition.copyFrom(mesh.position.subtract(bbox.center));
 
-            body.quaternion = new CANNON.Quaternion(mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z, mesh.rotationQuaternion.w);
+            var quaternion = mesh.rotationQuaternion;
+            this._tmpPosition.copyFrom(mesh.getBoundingInfo().boundingBox.center);
             //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) {
+            if (impostor.type === PhysicsEngine.PlaneImpostor || impostor.type === PhysicsEngine.HeightmapImpostor) {
                 //-90 DEG in X, precalculated
-                var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                body.quaternion = body.quaternion.mult(tmpQ);
+                quaternion = quaternion.multiply(this._minus90X);
                 //Invert! (Precalculated, 90 deg in X)
-                deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+                //No need to clone. this will never change.
+                impostor.setDeltaRotation(this._plus90X);
             }
             
             //If it is a heightfield, if should be centered.
-            if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
+            if (impostor.type === PhysicsEngine.HeightmapImpostor) {
                 
                 //calculate the correct body position:
                 var rotationQuaternion = mesh.rotationQuaternion;
-                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.rotationQuaternion = this._tmpUnityRotation;
                 mesh.computeWorldMatrix(true);
                 
                 //get original center with no rotation
@@ -312,195 +370,55 @@
                 //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);
+                this._tmpPosition.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;
+                this._tmpDeltaPosition.copyFrom(mesh.getBoundingInfo().boundingBox.center.subtract(center));
+                this._tmpDeltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
 
                 mesh.setPivotMatrix(oldPivot);
                 mesh.computeWorldMatrix(true);
-            } else if (shape.type === CANNON.Shape.types.TRIMESH) {
-                deltaPosition = 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;
-        }
-
-        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));
+            } else if (impostor.type === PhysicsEngine.MeshImpostor) {
+                this._tmpDeltaPosition.copyFromFloats(0, 0, 0);
+                this._tmpPosition.copyFrom(mesh.position);
             }
 
-            return body;
+            impostor.setDeltaPosition(this._tmpDeltaPosition);
+            //Now update the impostor object
+            impostor.physicsBody.position.copy(this._tmpPosition);
+            impostor.physicsBody.quaternion.copy(quaternion);
         }
 
-        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;
-                    registeredMesh.delta = null;
-                    registeredMesh.deltaRotation = null;
-                }
-            }
+        public setTransformationFromPhysicsBody(impostor: PhysicsImpostor) {
+            impostor.mesh.position.copyFrom(impostor.physicsBody.position);
+            impostor.mesh.rotationQuaternion.copyFrom(impostor.physicsBody.quaternion);
         }
 
-        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;
-                }
-            }
-        }
-
-        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;
-                }
-            }
-        }
-
-        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 BABYLON.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) {
-                    body2 = registeredMesh.body;
-                    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;
-        }
-
-        public dispose(): void {
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
+        public setPhysicsBodyTransformation(impostor: PhysicsImpostor, newPosition: Vector3, newRotation: Quaternion) {
+            impostor.physicsBody.position.copy(newPosition);
+            impostor.physicsBody.quaternion.copy(newRotation);
         }
 
         public isSupported(): boolean {
             return window.CANNON !== undefined;
         }
 
-        public getWorldObject(): any {
-            return this._world;
+        public setVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+            impostor.physicsBody.velocity.copy(velocity);
+        }
+        
+        public sleepBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.sleep();    
+        }
+        
+        public wakeUpBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.wakeUp(); 
         }
 
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
-                }
-            }
-            return null;
+        public dispose() {
+            //nothing to do, actually.
         }
     }
 }
 
+
+

+ 219 - 289
src/Physics/Plugins/babylon.oimoJSPlugin.js

@@ -1,279 +1,246 @@
 var BABYLON;
 (function (BABYLON) {
     var OimoJSPlugin = (function () {
-        function OimoJSPlugin() {
-            this._registeredMeshes = [];
-            this.name = "oimo";
-            /**
-             * Update the body position according to the mesh position
-             * @param mesh
-             */
-            this.updateBodyPosition = function (mesh) {
-                for (var index = 0; index < this._registeredMeshes.length; index++) {
-                    var registeredMesh = this._registeredMeshes[index];
-                    var body = registeredMesh.body.body;
-                    var updated = false;
-                    var newPosition;
-                    if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                        mesh.computeWorldMatrix(true);
-                        newPosition = mesh.getBoundingInfo().boundingBox.center;
-                        updated = true;
-                    }
-                    else if (registeredMesh.mesh.parent === mesh) {
-                        mesh.computeWorldMatrix(true);
-                        registeredMesh.mesh.computeWorldMatrix(true);
-                        newPosition = registeredMesh.mesh.getAbsolutePosition();
-                        updated = true;
-                    }
-                    if (updated) {
-                        body.setPosition(new OIMO.Vec3(newPosition.x, newPosition.y, newPosition.z));
-                        body.setQuaternion(mesh.rotationQuaternion);
-                        body.sleeping = false;
-                        //force Oimo to update the body's position
-                        body.updatePosition(1);
-                    }
-                }
-            };
+        function OimoJSPlugin(iterations) {
+            this.name = "OimoJSPlugin";
+            this._tmpImpostorsArray = [];
+            this._tmpPositionVector = BABYLON.Vector3.Zero();
+            this.world = new OIMO.World(1 / 60, 2, iterations, true);
+            this.world.clear();
+            //making sure no stats are calculated
+            this.world.isNoStat = true;
         }
-        OimoJSPlugin.prototype._checkWithEpsilon = function (value) {
-            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
-        };
-        OimoJSPlugin.prototype.initialize = function (iterations) {
-            this._world = new OIMO.World(null, null, iterations);
-            this._world.clear();
-        };
         OimoJSPlugin.prototype.setGravity = function (gravity) {
-            this._gravity = this._world.gravity = gravity;
-        };
-        OimoJSPlugin.prototype.getGravity = function () {
-            return this._gravity;
+            this.world.gravity.copy(gravity);
         };
-        OimoJSPlugin.prototype.registerMesh = function (mesh, impostor, options) {
-            this.unregisterMesh(mesh);
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-            mesh.computeWorldMatrix(true);
-            var bbox = mesh.getBoundingInfo().boundingBox;
-            // The delta between the mesh position and the mesh bounding box center
-            var deltaPosition = mesh.position.subtract(bbox.center);
-            //calculate rotation to fit Oimo's needs (Euler...)
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-            //get the correct bounding box
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-            var bodyConfig = {
-                name: mesh.uniqueId,
-                pos: [bbox.center.x, bbox.center.y, bbox.center.z],
-                rot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD],
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                world: this._world
-            };
-            // register mesh
-            switch (impostor) {
-                case BABYLON.PhysicsEngine.SphereImpostor:
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-                    var size = Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2;
-                    bodyConfig.type = 'sphere';
-                    bodyConfig.size = [size];
-                    break;
-                case BABYLON.PhysicsEngine.PlaneImpostor:
-                //Oimo "fakes" a cylinder as a box, so why don't we!
-                case BABYLON.PhysicsEngine.CylinderImpostor:
-                case BABYLON.PhysicsEngine.BoxImpostor:
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
-                    bodyConfig.type = 'box';
-                    bodyConfig.size = [sizeX, sizeY, sizeZ];
-                    break;
-            }
-            var body = new OIMO.Body(bodyConfig);
-            //We have to access the rigid body's properties to set the quaternion. 
-            //The setQuaternion function of Oimo only sets the newOrientation that is only set after an impulse is given or a collision.
-            //body.body.orientation = new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z);
-            //TEST
-            //body.body.resetQuaternion(new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z));
-            //update the internal rotation matrix
-            //body.body.syncShapes();
-            this._registeredMeshes.push({
-                mesh: mesh,
-                body: body,
-                delta: deltaPosition
-            });
-            //for the sake of consistency.
-            mesh.rotationQuaternion = oldQuaternion;
-            return body;
-        };
-        OimoJSPlugin.prototype.registerMeshesAsCompound = function (parts, options) {
-            var types = [], sizes = [], positions = [], rotations = [];
-            var initialMesh = parts[0].mesh;
-            for (var index = 0; index < parts.length; index++) {
-                var part = parts[index];
-                var bodyParameters = this._createBodyAsCompound(part, options, initialMesh);
-                types.push(bodyParameters.type);
-                sizes.push.apply(sizes, bodyParameters.size);
-                positions.push.apply(positions, bodyParameters.pos);
-                rotations.push.apply(rotations, bodyParameters.rot);
-            }
-            var body = new OIMO.Body({
-                name: initialMesh.uniqueId,
-                type: types,
-                size: sizes,
-                pos: positions,
-                rot: rotations,
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                world: this._world
+        OimoJSPlugin.prototype.executeStep = function (delta, impostors) {
+            var _this = this;
+            impostors.forEach(function (impostor) {
+                impostor.beforeStep();
             });
-            //Reset the body's rotation to be of the initial mesh's.
-            var rot = new OIMO.Euler().setFromQuaternion({ x: initialMesh.rotationQuaternion.x, y: initialMesh.rotationQuaternion.y, z: initialMesh.rotationQuaternion.z, s: initialMesh.rotationQuaternion.w });
-            body.resetRotation(rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD);
-            this._registeredMeshes.push({
-                mesh: initialMesh,
-                body: body
+            this.world.step();
+            impostors.forEach(function (impostor) {
+                impostor.afterStep();
+                //update the ordered impostors array
+                _this._tmpImpostorsArray[impostor.mesh.uniqueId] = impostor;
             });
-            return body;
-        };
-        OimoJSPlugin.prototype._createBodyAsCompound = function (part, options, initialMesh) {
-            var mesh = part.mesh;
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-            // We need the bounding box/sphere info to compute the physics body
-            mesh.computeWorldMatrix(true);
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-            var bodyParameters = {
-                name: mesh.uniqueId,
-                pos: [mesh.position.x, mesh.position.y, mesh.position.z],
-                //A bug in Oimo (Body class) prevents us from using rot directly.
-                rot: [0, 0, 0],
-                //For future reference, if the bug will ever be fixed.
-                realRot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD]
-            };
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-            switch (part.impostor) {
-                case BABYLON.PhysicsEngine.SphereImpostor:
-                    var bbox = mesh.getBoundingInfo().boundingBox;
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-                    var size = Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2;
-                    bodyParameters.type = 'sphere';
-                    bodyParameters.size = [size, size, size];
-                    break;
-                case BABYLON.PhysicsEngine.PlaneImpostor:
-                case BABYLON.PhysicsEngine.CylinderImpostor:
-                case BABYLON.PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
-                    bodyParameters.type = 'box';
-                    bodyParameters.size = [sizeX, sizeY, sizeZ];
-                    break;
-            }
-            mesh.rotationQuaternion = oldQuaternion;
-            return bodyParameters;
-        };
-        OimoJSPlugin.prototype.unregisterMesh = function (mesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    if (registeredMesh.body) {
-                        this._world.removeRigidBody(registeredMesh.body.body);
-                        this._unbindBody(registeredMesh.body);
-                    }
-                    this._registeredMeshes.splice(index, 1);
-                    return;
+            //check for collisions
+            var contact = this.world.contacts;
+            while (contact !== null) {
+                if (contact.touching && !contact.body1.sleeping && !contact.body2.sleeping) {
+                    contact = contact.next;
+                    continue;
                 }
-            }
-        };
-        OimoJSPlugin.prototype._unbindBody = function (body) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.body === body) {
-                    registeredMesh.body = null;
+                //is this body colliding with any other? get the impostor
+                var mainImpostor = this._tmpImpostorsArray[+contact.body1.name];
+                var collidingImpostor = this._tmpImpostorsArray[+contact.body2.name];
+                if (!mainImpostor || !collidingImpostor) {
+                    contact = contact.next;
+                    continue;
                 }
+                mainImpostor.onCollide({ body: collidingImpostor.physicsBody });
+                collidingImpostor.onCollide({ body: mainImpostor.physicsBody });
+                contact = contact.next;
             }
         };
-        OimoJSPlugin.prototype.applyImpulse = function (mesh, force, contactPoint) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    // Get object mass to have a behaviour similar to cannon.js
-                    var mass = registeredMesh.body.body.massInfo.mass;
-                    // The force is scaled with the mass of object
-                    registeredMesh.body.body.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
-                    return;
+        OimoJSPlugin.prototype.applyImpulse = function (impostor, force, contactPoint) {
+            var mass = impostor.physicsBody.massInfo.mass;
+            impostor.physicsBody.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
+        };
+        OimoJSPlugin.prototype.applyForce = function (impostor, force, contactPoint) {
+            BABYLON.Tools.Warn("Oimo doesn't support applying force. Using impule instead.");
+            this.applyImpulse(impostor, force, contactPoint);
+        };
+        OimoJSPlugin.prototype.generatePhysicsBody = function (impostor) {
+            var _this = this;
+            //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;
             }
-        };
-        OimoJSPlugin.prototype.createLink = function (mesh1, mesh2, pivot1, pivot2, options) {
-            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.body;
+            impostor.mesh.computeWorldMatrix(true);
+            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 bodyConfig = {
+                    name: impostor.mesh.uniqueId,
+                    //Oimo must have mass, also for static objects.
+                    config: [impostor.getParam("mass") || 1, impostor.getParam("friction"), impostor.getParam("restitution")],
+                    size: [],
+                    type: [],
+                    pos: [],
+                    rot: [],
+                    move: impostor.getParam("mass") !== 0,
+                    //Supporting older versions of Oimo
+                    world: this.world
+                };
+                var impostors = [impostor];
+                function addToArray(parent) {
+                    parent.getChildMeshes().forEach(function (m) {
+                        if (m.physicsImpostor) {
+                            impostors.push(m.physicsImpostor);
+                            m.physicsImpostor._init();
+                        }
+                    });
                 }
-                else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body.body;
+                addToArray(impostor.mesh);
+                function checkWithEpsilon(value) {
+                    return Math.max(value, BABYLON.PhysicsEngine.Epsilon);
                 }
+                impostors.forEach(function (i) {
+                    //get the correct bounding box
+                    var oldQuaternion = i.mesh.rotationQuaternion;
+                    var rot = new OIMO.Euler().setFromQuaternion({ x: impostor.mesh.rotationQuaternion.x, y: impostor.mesh.rotationQuaternion.y, z: impostor.mesh.rotationQuaternion.z, s: impostor.mesh.rotationQuaternion.w });
+                    i.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+                    i.mesh.computeWorldMatrix(true);
+                    var bbox = i.mesh.getBoundingInfo().boundingBox;
+                    if (i === impostor) {
+                        impostor.mesh.position.subtractToRef(impostor.mesh.getBoundingInfo().boundingBox.center, _this._tmpPositionVector);
+                        //Can also use Array.prototype.push.apply
+                        bodyConfig.pos.push(bbox.center.x);
+                        bodyConfig.pos.push(bbox.center.y);
+                        bodyConfig.pos.push(bbox.center.z);
+                        //tmp solution
+                        bodyConfig.rot.push(rot.x / (OIMO.degtorad || OIMO.TO_RAD));
+                        bodyConfig.rot.push(rot.y / (OIMO.degtorad || OIMO.TO_RAD));
+                        bodyConfig.rot.push(rot.z / (OIMO.degtorad || OIMO.TO_RAD));
+                    }
+                    else {
+                        bodyConfig.pos.push(i.mesh.position.x);
+                        bodyConfig.pos.push(i.mesh.position.y);
+                        bodyConfig.pos.push(i.mesh.position.z);
+                        //tmp solution until https://github.com/lo-th/Oimo.js/pull/37 is merged
+                        bodyConfig.rot.push(0);
+                        bodyConfig.rot.push(0);
+                        bodyConfig.rot.push(0);
+                    }
+                    // register mesh
+                    switch (i.type) {
+                        case BABYLON.PhysicsEngine.SphereImpostor:
+                            var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
+                            var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
+                            var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
+                            var size = Math.max(checkWithEpsilon(radiusX), checkWithEpsilon(radiusY), checkWithEpsilon(radiusZ)) / 2;
+                            bodyConfig.type.push('sphere');
+                            //due to the way oimo works with compounds, add 3 times
+                            bodyConfig.size.push(size);
+                            bodyConfig.size.push(size);
+                            bodyConfig.size.push(size);
+                            break;
+                        case BABYLON.PhysicsEngine.PlaneImpostor:
+                        //TODO Oimo now supports cylinder!
+                        case BABYLON.PhysicsEngine.CylinderImpostor:
+                        case BABYLON.PhysicsEngine.BoxImpostor:
+                        default:
+                            var min = bbox.minimumWorld;
+                            var max = bbox.maximumWorld;
+                            var box = max.subtract(min);
+                            var sizeX = checkWithEpsilon(box.x);
+                            var sizeY = checkWithEpsilon(box.y);
+                            var sizeZ = checkWithEpsilon(box.z);
+                            bodyConfig.type.push('box');
+                            bodyConfig.size.push(sizeX);
+                            bodyConfig.size.push(sizeY);
+                            bodyConfig.size.push(sizeZ);
+                            break;
+                    }
+                    //actually not needed, but hey...
+                    i.mesh.rotationQuaternion = oldQuaternion;
+                });
+                impostor.physicsBody = new OIMO.Body(bodyConfig).body; //this.world.add(bodyConfig);
             }
-            if (!body1 || !body2) {
-                return false;
+            else {
+                this._tmpPositionVector.copyFromFloats(0, 0, 0);
             }
-            if (!options) {
-                options = {};
+            impostor.setDeltaPosition(this._tmpPositionVector);
+            //this._tmpPositionVector.addInPlace(impostor.mesh.getBoundingInfo().boundingBox.center);
+            //this.setPhysicsBodyTransformation(impostor, this._tmpPositionVector, impostor.mesh.rotationQuaternion);
+        };
+        OimoJSPlugin.prototype.removePhysicsBody = function (impostor) {
+            //impostor.physicsBody.dispose();
+            //Same as : (older oimo versions)
+            this.world.removeRigidBody(impostor.physicsBody);
+        };
+        OimoJSPlugin.prototype.generateJoint = function (impostorJoint) {
+            var mainBody = impostorJoint.mainImpostor.physicsBody;
+            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
+            if (!mainBody || !connectedBody) {
+                return;
             }
-            new OIMO.Link({
-                type: options.type,
-                body1: body1,
-                body2: body2,
+            var jointData = impostorJoint.joint.jointData;
+            var options = jointData.nativeParams || {};
+            var type;
+            var nativeJointData = {
+                body1: mainBody,
+                body2: connectedBody,
+                axe1: options.axe1 || (jointData.mainAxis ? jointData.mainAxis.asArray() : null),
+                axe2: options.axe2 || (jointData.connectedAxis ? jointData.connectedAxis.asArray() : null),
+                pos1: options.pos1 || (jointData.mainPivot ? jointData.mainPivot.asArray() : null),
+                pos2: options.pos2 || (jointData.connectedPivot ? jointData.connectedPivot.asArray() : null),
                 min: options.min,
                 max: options.max,
-                axe1: options.axe1,
-                axe2: options.axe2,
-                pos1: [pivot1.x, pivot1.y, pivot1.z],
-                pos2: [pivot2.x, pivot2.y, pivot2.z],
-                collision: options.collision,
+                collision: options.collision || jointData.collision,
                 spring: options.spring,
-                world: this._world
-            });
-            return true;
-        };
-        OimoJSPlugin.prototype.dispose = function () {
-            this._world.clear();
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
+                //supporting older version of Oimo
+                world: this.world
+            };
+            switch (impostorJoint.joint.type) {
+                case BABYLON.PhysicsJoint.BallAndSocketJoint:
+                    type = "jointBall";
+                    break;
+                case BABYLON.PhysicsJoint.DistanceJoint:
+                    type = "jointDistance";
+                    nativeJointData.max = jointData.maxDistance;
+                    break;
+                case BABYLON.PhysicsJoint.PrismaticJoint:
+                    type = "jointPrisme";
+                    break;
+                case BABYLON.PhysicsJoint.SliderJoint:
+                    type = "jointSlide";
+                    break;
+                case BABYLON.PhysicsJoint.WheelJoint:
+                    type = "jointWheel";
+                    break;
+                case BABYLON.PhysicsJoint.HingeJoint:
+                default:
+                    type = "jointHinge";
+                    break;
             }
+            nativeJointData.type = type;
+            impostorJoint.joint.physicsJoint = new OIMO.Link(nativeJointData).joint; //this.world.add(nativeJointData);
+        };
+        OimoJSPlugin.prototype.removeJoint = function (joint) {
+            joint.joint.physicsJoint.dispose();
         };
         OimoJSPlugin.prototype.isSupported = function () {
             return OIMO !== undefined;
         };
-        OimoJSPlugin.prototype.getWorldObject = function () {
-            return this._world;
-        };
-        OimoJSPlugin.prototype.getPhysicsBodyOfMesh = function (mesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
+        OimoJSPlugin.prototype.setTransformationFromPhysicsBody = function (impostor) {
+            if (!impostor.physicsBody.sleeping) {
+                //TODO check that
+                if (impostor.physicsBody.shapes.next) {
+                    var parentShape = this._getLastShape(impostor.physicsBody);
+                    impostor.mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
+                    impostor.mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
+                    impostor.mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
                 }
+                else {
+                    impostor.mesh.position.copyFrom(impostor.physicsBody.getPosition());
+                }
+                impostor.mesh.rotationQuaternion.copyFrom(impostor.physicsBody.getQuaternion());
             }
-            return null;
+        };
+        OimoJSPlugin.prototype.setPhysicsBodyTransformation = function (impostor, newPosition, newRotation) {
+            var body = impostor.physicsBody;
+            body.position.init(newPosition.x * OIMO.INV_SCALE, newPosition.y * OIMO.INV_SCALE, newPosition.z * OIMO.INV_SCALE);
+            body.orientation.init(newRotation.w, newRotation.x, newRotation.y, newRotation.z);
+            body.syncShapes();
+            body.awake();
         };
         OimoJSPlugin.prototype._getLastShape = function (body) {
             var lastShape = body.shapes;
@@ -282,48 +249,11 @@ var BABYLON;
             }
             return lastShape;
         };
-        OimoJSPlugin.prototype.runOneStep = function (time) {
-            this._world.step();
-            // Update the position of all registered meshes
-            var i = this._registeredMeshes.length;
-            var m;
-            while (i--) {
-                var body = this._registeredMeshes[i].body.body;
-                var mesh = this._registeredMeshes[i].mesh;
-                if (!this._registeredMeshes[i].delta) {
-                    this._registeredMeshes[i].delta = BABYLON.Vector3.Zero();
-                }
-                if (!body.sleeping) {
-                    //TODO check that
-                    if (body.shapes.next) {
-                        var parentShape = this._getLastShape(body);
-                        mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
-                        mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
-                        mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
-                    }
-                    else {
-                        mesh.position.copyFrom(body.getPosition()).addInPlace(this._registeredMeshes[i].delta);
-                    }
-                    mesh.rotationQuaternion.copyFrom(body.getQuaternion());
-                    mesh.computeWorldMatrix();
-                }
-                //check if the collide callback is set. 
-                if (mesh.onPhysicsCollide) {
-                    var meshUniqueName = mesh.uniqueId;
-                    var contact = this._world.contacts;
-                    while (contact !== null) {
-                        //is this body colliding with any other?
-                        if ((contact.body1.name == mesh.uniqueId || contact.body2.name == mesh.uniqueId) && contact.touching && !contact.body1.sleeping && !contact.body2.sleeping) {
-                            var otherUniqueId = contact.body1.name == mesh.uniqueId ? contact.body2.name : contact.body1.name;
-                            //get the mesh and execute the callback
-                            var otherMesh = mesh.getScene().getMeshByUniqueID(otherUniqueId);
-                            if (otherMesh)
-                                mesh.onPhysicsCollide(otherMesh, contact);
-                        }
-                        contact = contact.next;
-                    }
-                }
-            }
+        OimoJSPlugin.prototype.setVelocity = function (impostor, velocity) {
+            impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
+        };
+        OimoJSPlugin.prototype.dispose = function () {
+            this.world.clear();
         };
         return OimoJSPlugin;
     })();

+ 252 - 340
src/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -1,356 +1,301 @@
 module BABYLON {
     declare var OIMO;
 
-    export class OimoJSPlugin implements IPhysicsEnginePlugin {
-        private _world;
-        private _registeredMeshes = [];
+    export class OimoJSPlugin {
 
-        public name = "oimo";
+        public world: any;
+        public name: string = "OimoJSPlugin";
 
-        private _gravity: Vector3;
-
-        private _checkWithEpsilon(value: number): number {
-            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
-        }
-
-        public initialize(iterations?: number): void {
-            this._world = new OIMO.World(null, null, iterations);
-            this._world.clear();
+        constructor(iterations?: number) {
+            this.world = new OIMO.World(1 / 60, 2, iterations, true);
+            this.world.clear();
+            //making sure no stats are calculated
+            this.world.isNoStat = true;
         }
 
-        public setGravity(gravity: Vector3): void {
-            this._gravity = this._world.gravity = gravity;
+        public setGravity(gravity: Vector3) {
+            this.world.gravity.copy(gravity);
         }
 
-        public getGravity(): Vector3 {
-            return this._gravity;
-        }
-
-        public registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
-            this.unregisterMesh(mesh);
+        private _tmpImpostorsArray: Array<PhysicsImpostor> = [];
 
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
+        public executeStep(delta: number, impostors: Array<PhysicsImpostor>) {
 
-            mesh.computeWorldMatrix(true);
+            impostors.forEach(function (impostor) {
+                impostor.beforeStep();
+            });
 
-            var bbox = mesh.getBoundingInfo().boundingBox;
+            this.world.step();
 
-            // The delta between the mesh position and the mesh bounding box center
-            var deltaPosition = mesh.position.subtract(bbox.center);
+            impostors.forEach((impostor) => {
+                impostor.afterStep();
+                //update the ordered impostors array
+                this._tmpImpostorsArray[impostor.mesh.uniqueId] = impostor;
+            });
             
-            //calculate rotation to fit Oimo's needs (Euler...)
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-
-            //get the correct bounding box
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            var bodyConfig: any = {
-                name: mesh.uniqueId,
-                pos: [bbox.center.x, bbox.center.y, bbox.center.z],
-                rot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD],
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                world: this._world
-            };
-
-            // register mesh
-            switch (impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    var size = Math.max(
-                        this._checkWithEpsilon(radiusX),
-                        this._checkWithEpsilon(radiusY),
-                        this._checkWithEpsilon(radiusZ)) / 2;
-
-                    bodyConfig.type = 'sphere';
-                    bodyConfig.size = [size];
-                    break;
+            //check for collisions
+            var contact = this.world.contacts;
 
-                case PhysicsEngine.PlaneImpostor:
-                //Oimo "fakes" a cylinder as a box, so why don't we!
-                case PhysicsEngine.CylinderImpostor:
-                case PhysicsEngine.BoxImpostor:
+            while (contact !== null) {
+                if (contact.touching && !contact.body1.sleeping && !contact.body2.sleeping) {
+                    contact = contact.next;
+                    continue;
+                }
+                //is this body colliding with any other? get the impostor
+                var mainImpostor = this._tmpImpostorsArray[+contact.body1.name];
+                var collidingImpostor = this._tmpImpostorsArray[+contact.body2.name];
 
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
+                if (!mainImpostor || !collidingImpostor) {
+                    contact = contact.next;
+                    continue;
+                }
 
-                    bodyConfig.type = 'box';
-                    bodyConfig.size = [sizeX, sizeY, sizeZ];
-                    break;
+                mainImpostor.onCollide({ body: collidingImpostor.physicsBody });
+                collidingImpostor.onCollide({ body: mainImpostor.physicsBody });
+                contact = contact.next;
             }
 
-            var body = new OIMO.Body(bodyConfig);
-
-            //We have to access the rigid body's properties to set the quaternion. 
-            //The setQuaternion function of Oimo only sets the newOrientation that is only set after an impulse is given or a collision.
-            //body.body.orientation = new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z);
-            //TEST
-            //body.body.resetQuaternion(new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z));
-            //update the internal rotation matrix
-            //body.body.syncShapes();
-            
-            this._registeredMeshes.push({
-                mesh: mesh,
-                body: body,
-                delta: deltaPosition
-            });
-			
-            //for the sake of consistency.
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return body;
         }
 
-        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-            var types = [],
-                sizes = [],
-                positions = [],
-                rotations = [];
-
-            var initialMesh = parts[0].mesh;
-
-            for (var index = 0; index < parts.length; index++) {
-                var part = parts[index];
-                var bodyParameters = this._createBodyAsCompound(part, options, initialMesh);
-                types.push(bodyParameters.type);
-                sizes.push.apply(sizes, bodyParameters.size);
-                positions.push.apply(positions, bodyParameters.pos);
-                rotations.push.apply(rotations, bodyParameters.rot);
+        public applyImpulse(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3) {
+            var mass = impostor.physicsBody.massInfo.mass;
+            impostor.physicsBody.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
+        }
+        public applyForce(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3) {
+            Tools.Warn("Oimo doesn't support applying force. Using impule instead.");
+            this.applyImpulse(impostor, force, contactPoint);
+        }
+        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;
             }
 
-            var body = new OIMO.Body({
-                name: initialMesh.uniqueId,
-                type: types,
-                size: sizes,
-                pos: positions,
-                rot: rotations,
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                world: this._world
-            });
-            
-            //Reset the body's rotation to be of the initial mesh's.
-            var rot = new OIMO.Euler().setFromQuaternion({ x: initialMesh.rotationQuaternion.x, y: initialMesh.rotationQuaternion.y, z: initialMesh.rotationQuaternion.z, s: initialMesh.rotationQuaternion.w });
+            impostor.mesh.computeWorldMatrix(true);
 
-            body.resetRotation(rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD);
-
-            this._registeredMeshes.push({
-                mesh: initialMesh,
-                body: body
-            });
-
-            return body;
-        }
+            if (impostor.isBodyInitRequired()) {
+                if (!impostor.mesh.rotationQuaternion) {
+                    impostor.mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(impostor.mesh.rotation.y, impostor.mesh.rotation.x, impostor.mesh.rotation.z);
+                }
 
-        private _createBodyAsCompound(part: PhysicsCompoundBodyPart, options: PhysicsBodyCreationOptions, initialMesh: AbstractMesh): any {
-            var mesh = part.mesh;
 
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-			
-            // We need the bounding box/sphere info to compute the physics body
-            mesh.computeWorldMatrix(true);
-
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-
-            var bodyParameters: any = {
-                name: mesh.uniqueId,
-                pos: [mesh.position.x, mesh.position.y, mesh.position.z],
-                //A bug in Oimo (Body class) prevents us from using rot directly.
-                rot: [0, 0, 0],
-                //For future reference, if the bug will ever be fixed.
-                realRot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD]
-            };
-
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            switch (part.impostor) {
-                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;
-
-                    var size = Math.max(
-                        this._checkWithEpsilon(radiusX),
-                        this._checkWithEpsilon(radiusY),
-                        this._checkWithEpsilon(radiusZ)) / 2;
-
-                    bodyParameters.type = 'sphere';
-                    bodyParameters.size = [size, size, size];
+                var bodyConfig: any = {
+                    name: impostor.mesh.uniqueId,
+                    //Oimo must have mass, also for static objects.
+                    config: [impostor.getParam("mass") || 1, impostor.getParam("friction"), impostor.getParam("restitution")],
+                    size: [],
+                    type: [],
+                    pos: [],
+                    rot: [],
+                    move: impostor.getParam("mass") !== 0,
+                    //Supporting older versions of Oimo
+                    world: this.world
+                };
+
+                var impostors = [impostor];
+                function addToArray(parent: AbstractMesh) {
+                    parent.getChildMeshes().forEach(function (m) {
+                        if (m.physicsImpostor) {
+                            impostors.push(m.physicsImpostor);
+                            m.physicsImpostor._init();
+                        }
+                    });
+                }
+                addToArray(impostor.mesh)
 
-                    break;
+                function checkWithEpsilon(value: number): number {
+                    return Math.max(value, PhysicsEngine.Epsilon);
+                }
 
-                case PhysicsEngine.PlaneImpostor:
-                case PhysicsEngine.CylinderImpostor:
-                case PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
+                impostors.forEach((i) => {
+                    
+                    //get the correct bounding box
+                    var oldQuaternion = i.mesh.rotationQuaternion;
+                    var rot = new OIMO.Euler().setFromQuaternion({ x: impostor.mesh.rotationQuaternion.x, y: impostor.mesh.rotationQuaternion.y, z: impostor.mesh.rotationQuaternion.z, s: impostor.mesh.rotationQuaternion.w });
 
-                    bodyParameters.type = 'box';
-                    bodyParameters.size = [sizeX, sizeY, sizeZ];
+                    i.mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
+                    i.mesh.computeWorldMatrix(true);
 
-                    break;
-            }
+                    var bbox = i.mesh.getBoundingInfo().boundingBox;
 
-            mesh.rotationQuaternion = oldQuaternion;
+                    if (i === impostor) {
 
-            return bodyParameters;
-        }
+                        impostor.mesh.position.subtractToRef(impostor.mesh.getBoundingInfo().boundingBox.center, this._tmpPositionVector);
 
-        public unregisterMesh(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) {
-                    if (registeredMesh.body) {
-                        this._world.removeRigidBody(registeredMesh.body.body);
-                        this._unbindBody(registeredMesh.body);
+                        //Can also use Array.prototype.push.apply
+                        bodyConfig.pos.push(bbox.center.x);
+                        bodyConfig.pos.push(bbox.center.y);
+                        bodyConfig.pos.push(bbox.center.z);
+                        
+                        //tmp solution
+                        bodyConfig.rot.push(rot.x / (OIMO.degtorad || OIMO.TO_RAD));
+                        bodyConfig.rot.push(rot.y / (OIMO.degtorad || OIMO.TO_RAD));
+                        bodyConfig.rot.push(rot.z / (OIMO.degtorad || OIMO.TO_RAD));
+                    } else {
+                        bodyConfig.pos.push(i.mesh.position.x);
+                        bodyConfig.pos.push(i.mesh.position.y);
+                        bodyConfig.pos.push(i.mesh.position.z);
+                        
+                        //tmp solution until https://github.com/lo-th/Oimo.js/pull/37 is merged
+                        bodyConfig.rot.push(0);
+                        bodyConfig.rot.push(0);
+                        bodyConfig.rot.push(0);
                     }
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
-        }
-
-        private _unbindBody(body: any): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.body === body) {
-                    registeredMesh.body = null;
-                }
-            }
-        }
+                    
+                    // register mesh
+                    switch (i.type) {
+                        case PhysicsEngine.SphereImpostor:
+                            var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
+                            var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
+                            var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
+
+                            var size = Math.max(
+                                checkWithEpsilon(radiusX),
+                                checkWithEpsilon(radiusY),
+                                checkWithEpsilon(radiusZ)) / 2;
+
+                            bodyConfig.type.push('sphere');
+                            //due to the way oimo works with compounds, add 3 times
+                            bodyConfig.size.push(size);
+                            bodyConfig.size.push(size);
+                            bodyConfig.size.push(size);
+                            break;
+
+                        case PhysicsEngine.PlaneImpostor:
+                        //TODO Oimo now supports cylinder!
+                        case PhysicsEngine.CylinderImpostor:
+                        case PhysicsEngine.BoxImpostor:
+                        default:
+
+                            var min = bbox.minimumWorld;
+                            var max = bbox.maximumWorld;
+                            var box = max.subtract(min);
+                            var sizeX = checkWithEpsilon(box.x);
+                            var sizeY = checkWithEpsilon(box.y);
+                            var sizeZ = checkWithEpsilon(box.z);
+
+                            bodyConfig.type.push('box');
+                            bodyConfig.size.push(sizeX);
+                            bodyConfig.size.push(sizeY);
+                            bodyConfig.size.push(sizeZ);
+                            break;
+                    }
+                    
+                    //actually not needed, but hey...
+                    i.mesh.rotationQuaternion = oldQuaternion;
+                });
 
-        /**
-         * Update the body position according to the mesh position
-         * @param mesh
-         */
-        public updateBodyPosition = function (mesh: AbstractMesh): void {
+                impostor.physicsBody = new OIMO.Body(bodyConfig).body//this.world.add(bodyConfig);
 
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                var body = registeredMesh.body.body;
-                var updated: boolean = false;
-                var newPosition: Vector3;
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    mesh.computeWorldMatrix(true);
+            } else {
+                this._tmpPositionVector.copyFromFloats(0, 0, 0);
+            }
 
-                    newPosition = mesh.getBoundingInfo().boundingBox.center;
+            impostor.setDeltaPosition(this._tmpPositionVector);
 
-                    updated = true;
-                }
-                // Case where the parent has been updated
-                else if (registeredMesh.mesh.parent === mesh) {
-                    mesh.computeWorldMatrix(true);
-                    registeredMesh.mesh.computeWorldMatrix(true);
-
-                    newPosition = registeredMesh.mesh.getAbsolutePosition();
+            //this._tmpPositionVector.addInPlace(impostor.mesh.getBoundingInfo().boundingBox.center);
+            //this.setPhysicsBodyTransformation(impostor, this._tmpPositionVector, impostor.mesh.rotationQuaternion);
+        }
 
-                    updated = true;
-                }
+        private _tmpPositionVector: Vector3 = Vector3.Zero();
 
-                if (updated) {
-                    body.setPosition(new OIMO.Vec3(newPosition.x, newPosition.y, newPosition.z));
-                    body.setQuaternion(mesh.rotationQuaternion);
-                    body.sleeping = false;
-                    //force Oimo to update the body's position
-                    body.updatePosition(1);
-                }
-            }
+        public removePhysicsBody(impostor: PhysicsImpostor) {
+            //impostor.physicsBody.dispose();
+            //Same as : (older oimo versions)
+            this.world.removeRigidBody(impostor.physicsBody);
         }
 
-        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    // Get object mass to have a behaviour similar to cannon.js
-                    var mass = registeredMesh.body.body.massInfo.mass;
-                    // The force is scaled with the mass of object
-                    registeredMesh.body.body.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
-                    return;
-                }
-            }
-        }
+        public generateJoint(impostorJoint: PhysicsImpostorJoint) {
+            var mainBody = impostorJoint.mainImpostor.physicsBody;
+            var connectedBody = impostorJoint.connectedImpostor.physicsBody;
 
-        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): 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.body;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body.body;
-                }
-            }
-            if (!body1 || !body2) {
-                return false;
-            }
-            if (!options) {
-                options = {};
+            if (!mainBody || !connectedBody) {
+                return;
             }
+            var jointData = impostorJoint.joint.jointData;
+            var options = jointData.nativeParams || {};
+            var type;
+            var nativeJointData: any = {
+                body1: mainBody,
+                body2: connectedBody,
+
+                axe1: options.axe1 || (jointData.mainAxis ? jointData.mainAxis.asArray() : null),
+                axe2: options.axe2 || (jointData.connectedAxis ? jointData.connectedAxis.asArray() : null),
+                pos1: options.pos1 || (jointData.mainPivot ? jointData.mainPivot.asArray() : null),
+                pos2: options.pos2 || (jointData.connectedPivot ? jointData.connectedPivot.asArray() : null),
 
-            new OIMO.Link({
-                type: options.type,
-                body1: body1,
-                body2: body2,
                 min: options.min,
                 max: options.max,
-                axe1: options.axe1,
-                axe2: options.axe2,
-                pos1: [pivot1.x, pivot1.y, pivot1.z],
-                pos2: [pivot2.x, pivot2.y, pivot2.z],
-                collision: options.collision,
+                collision: options.collision || jointData.collision,
                 spring: options.spring,
-                world: this._world
-            });
-
-            return true;
+                
+                //supporting older version of Oimo
+                world: this.world
 
+            }
+            switch (impostorJoint.joint.type) {
+                case PhysicsJoint.BallAndSocketJoint:
+                    type = "jointBall";
+                    break;
+                case PhysicsJoint.DistanceJoint:
+                    type = "jointDistance";
+                    nativeJointData.max = (<DistanceJointData>jointData).maxDistance
+                    break;
+                case PhysicsJoint.PrismaticJoint:
+                    type = "jointPrisme";
+                    break;
+                case PhysicsJoint.SliderJoint:
+                    type = "jointSlide";
+                    break;
+                case PhysicsJoint.WheelJoint:
+                    type = "jointWheel";
+                    break;
+                case PhysicsJoint.HingeJoint:
+                default:
+                    type = "jointHinge";
+                    break;
+            }
+            nativeJointData.type = type;
+            impostorJoint.joint.physicsJoint = new OIMO.Link(nativeJointData).joint//this.world.add(nativeJointData);
         }
 
-        public dispose(): void {
-            this._world.clear();
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
+        public removeJoint(joint: PhysicsImpostorJoint) {
+            joint.joint.physicsJoint.dispose();
         }
 
         public isSupported(): boolean {
             return OIMO !== undefined;
         }
 
-        public getWorldObject(): any {
-            return this._world;
-        }
+        public setTransformationFromPhysicsBody(impostor: PhysicsImpostor) {
+            if (!impostor.physicsBody.sleeping) {
+                //TODO check that
+                if (impostor.physicsBody.shapes.next) {
+                    var parentShape = this._getLastShape(impostor.physicsBody);
+                    impostor.mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
+                    impostor.mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
+                    impostor.mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
+                } else {
+                    impostor.mesh.position.copyFrom(impostor.physicsBody.getPosition());
 
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
                 }
+                impostor.mesh.rotationQuaternion.copyFrom(impostor.physicsBody.getQuaternion());
             }
-            return null;
+        }
+
+        public setPhysicsBodyTransformation(impostor: PhysicsImpostor, newPosition: Vector3, newRotation: Quaternion) {
+            var body = impostor.physicsBody;
+
+            body.position.init(newPosition.x * OIMO.INV_SCALE, newPosition.y * OIMO.INV_SCALE, newPosition.z * OIMO.INV_SCALE);
+
+            body.orientation.init(newRotation.w, newRotation.x, newRotation.y, newRotation.z);
+            body.syncShapes();
+            body.awake();
         }
 
         private _getLastShape(body: any): any {
@@ -361,53 +306,20 @@ module BABYLON {
             return lastShape;
         }
 
-        public runOneStep(time: number): void {
-            this._world.step();
-
-            // Update the position of all registered meshes
-            var i = this._registeredMeshes.length;
-            var m;
-            while (i--) {
-
-                var body = this._registeredMeshes[i].body.body;
-                var mesh = this._registeredMeshes[i].mesh;
-
-                if (!this._registeredMeshes[i].delta) {
-                    this._registeredMeshes[i].delta = Vector3.Zero();
-                }
-
-                if (!body.sleeping) {
-                    //TODO check that
-                    if (body.shapes.next) {
-                        var parentShape = this._getLastShape(body);
-                        mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
-                        mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
-                        mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
-                    } else {
-                        mesh.position.copyFrom(body.getPosition()).addInPlace(this._registeredMeshes[i].delta);
+        public setVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+            impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
+        }
+        
+        public sleepBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.sleep();    
+        }
+        
+        public wakeUpBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.awake(); 
+        }
 
-                    }
-                    mesh.rotationQuaternion.copyFrom(body.getQuaternion());
-                    mesh.computeWorldMatrix();
-                }
-                
-                //check if the collide callback is set. 
-                if (mesh.onPhysicsCollide) {
-                    var meshUniqueName = mesh.uniqueId;
-                    var contact = this._world.contacts;
-                    while (contact !== null) {
-                        //is this body colliding with any other?
-                        if ((contact.body1.name == mesh.uniqueId || contact.body2.name == mesh.uniqueId) && contact.touching && /* !contact.sleeping*/ !contact.body1.sleeping && !contact.body2.sleeping) {
-                            var otherUniqueId = contact.body1.name == mesh.uniqueId ? contact.body2.name : contact.body1.name;
-                            //get the mesh and execute the callback
-                            var otherMesh = mesh.getScene().getMeshByUniqueID(otherUniqueId);
-                            if (otherMesh)
-                                mesh.onPhysicsCollide(otherMesh, contact); 
-                        }
-                        contact = contact.next;
-                    }
-                }
-            }
+        public dispose() {
+            this.world.clear();
         }
     }
-}
+}

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

@@ -1,73 +1,113 @@
 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 (_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);
+            gravity = gravity || new BABYLON.Vector3(0, -9.807, 0);
+            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);
+            //if no parent, generate the body
+            if (!impostor.parent) {
+                this._physicsPlugin.generatePhysicsBody(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 will also remove it from the world.
+                    removed[0].physicsBody = null;
+                }
+            }
         };
-        PhysicsEngine.prototype.dispose = function () {
-            this._currentPlugin.dispose();
+        PhysicsEngine.prototype.addJoint = function (mainImpostor, connectedImpostor, joint) {
+            var impostorJoint = {
+                mainImpostor: mainImpostor,
+                connectedImpostor: connectedImpostor,
+                joint: joint
+            };
+            this._joints.push(impostorJoint);
+            this._physicsPlugin.generateJoint(impostorJoint);
         };
-        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);
+        /**
+         * Called by the scene. no need to call it.
+         */
+        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.isBodyInitRequired()) {
+                    _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;
     })();

+ 125 - 89
src/Physics/babylon.physicsEngine.ts

@@ -1,121 +1,157 @@
 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;
 
-        constructor(plugin?: IPhysicsEnginePlugin) {
-            this._currentPlugin = plugin || new OimoJSPlugin();
-        }
-
-        public _initialize(gravity?: Vector3) {
-            this._currentPlugin.initialize();
-            this._setGravity(gravity);
-        }
+        public gravity: Vector3;
 
-        public _runOneStep(delta: number): void {
-            if (delta > 0.1) {
-                delta = 0.1;
-            } else if (delta <= 0) {
-                delta = 1.0 / 60.0;
+        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.")
             }
-
-            this._currentPlugin.runOneStep(delta);
+            gravity = gravity || new Vector3(0, -9.807, 0)
+            this.setGravity(gravity);
         }
 
-        public _setGravity(gravity: Vector3): void {
-            this.gravity = gravity || new Vector3(0, -9.807, 0);
-            this._currentPlugin.setGravity(this.gravity);
+        public setGravity(gravity: Vector3): void {
+            this.gravity = gravity;
+            this._physicsPlugin.setGravity(this.gravity);
         }
 
-        public _getGravity(): Vector3 {
-            return this._currentPlugin.getGravity();
-        }
-
-        public _registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
-            return this._currentPlugin.registerMesh(mesh, impostor, options);
+        public dispose(): void {
+            this._impostors.forEach(function(impostor) {
+                impostor.dispose();
+            })
+            this._physicsPlugin.dispose();
         }
 
-        public _registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-            return this._currentPlugin.registerMeshesAsCompound(parts, options);
-        }
+        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 _unregisterMesh(mesh: AbstractMesh): void {
-            this._currentPlugin.unregisterMesh(mesh);
+        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);
+            //if no parent, generate the body
+            if (!impostor.parent) {
+                this._physicsPlugin.generatePhysicsBody(impostor);
+            }
         }
 
-        public _applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            this._currentPlugin.applyImpulse(mesh, force, contactPoint);
+        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 will also remove it from the world.
+                    removed[0].physicsBody = null;
+                }
+            }
         }
 
-        public _createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean {
-            return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2, options);
+        public addJoint(mainImpostor: PhysicsImpostor, connectedImpostor: PhysicsImpostor, joint: PhysicsJoint) {
+            var impostorJoint = {
+                mainImpostor: mainImpostor,
+                connectedImpostor: connectedImpostor,
+                joint: joint
+            }
+            this._joints.push(impostorJoint);
+            this._physicsPlugin.generateJoint(impostorJoint);
+        }
+
+        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 _updateBodyPosition(mesh: AbstractMesh): void {
-            this._currentPlugin.updateBodyPosition(mesh);
-        }
+        /**
+         * Called by the scene. no need to call it.
+         */
+        public _step(delta: number) {
+            //check if any mesh has no body / requires an update
+            this._impostors.forEach((impostor) => {
 
-        public dispose(): void {
-            this._currentPlugin.dispose();
-        }
+                if (impostor.isBodyInitRequired()) {
+                    this._physicsPlugin.generatePhysicsBody(impostor);
+                }
+            });
 
-        public isSupported(): boolean {
-            return this._currentPlugin.isSupported();
-        }
+            if (delta > 0.1) {
+                delta = 0.1;
+            } else if (delta <= 0) {
+                delta = 1.0 / 60.0;
+            }
 
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            return this._currentPlugin.getPhysicsBodyOfMesh(mesh);
+            this._physicsPlugin.executeStep(delta, this._impostors);
         }
 
-        public getPhysicsPluginName(): string {
-            return this._currentPlugin.name;
+        public getPhysicsPlugin(): IPhysicsEnginePlugin {
+            return this._physicsPlugin;
         }
 
-        public getWorldObject(): any {
-            return this._currentPlugin.getWorldObject();
+        public getImpostorWithPhysicsBody(body: any): PhysicsImpostor {
+            for (var i = 0; i < this._impostors.length; ++i) {
+                if (this._impostors[i].physicsBody === body) {
+                    return this._impostors[i];
+                }
+            }
         }
+    }
 
-        // 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;
+        setTransformationFromPhysicsBody(impostor: PhysicsImpostor);
+        setPhysicsBodyTransformation(impostor: PhysicsImpostor, newPosition: Vector3, newRotation: Quaternion);
+        setVelocity(impostor: PhysicsImpostor, velocity: Vector3);
+        sleepBody(impostor: PhysicsImpostor);
+        wakeUpBody(impostor: PhysicsImpostor);
+        dispose();
     }
 }

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

@@ -0,0 +1,278 @@
+var BABYLON;
+(function (BABYLON) {
+    var PhysicsImpostor = (function () {
+        function PhysicsImpostor(_mesh, type, _options) {
+            var _this = this;
+            if (_options === void 0) { _options = { mass: 0 }; }
+            this._mesh = _mesh;
+            this.type = type;
+            this._options = _options;
+            this._bodyUpdateRequired = false;
+            this._onBeforePhysicsStepCallbacks = new Array();
+            this._onAfterPhysicsStepCallbacks = new Array();
+            this._onPhysicsCollideCallbacks = [];
+            this._deltaPosition = BABYLON.Vector3.Zero();
+            this._deltaRotation = new BABYLON.Quaternion();
+            this._tmpPositionWithDelta = BABYLON.Vector3.Zero();
+            this._tmpRotationWithDelta = new BABYLON.Quaternion();
+            /**
+             * this function is executed by the physics engine.
+             */
+            this.beforeStep = function () {
+                _this.mesh.position.subtractToRef(_this._deltaPosition, _this._tmpPositionWithDelta);
+                //conjugate deltaRotation
+                _this._tmpRotationWithDelta.copyFrom(_this._deltaRotation);
+                _this._tmpRotationWithDelta.multiplyInPlace(_this.mesh.rotationQuaternion);
+                _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, _this._tmpPositionWithDelta, _this._tmpRotationWithDelta);
+                _this._onBeforePhysicsStepCallbacks.forEach(function (func) {
+                    func(_this);
+                });
+            };
+            /**
+             * this function is executed by the physics engine.
+             */
+            this.afterStep = function () {
+                _this._onAfterPhysicsStepCallbacks.forEach(function (func) {
+                    func(_this);
+                });
+                _this._physicsEngine.getPhysicsPlugin().setTransformationFromPhysicsBody(_this);
+                _this.mesh.position.addInPlace(_this._deltaPosition);
+                _this.mesh.rotationQuaternion.multiplyInPlace(_this._deltaRotation);
+            };
+            //event and body object due to cannon's event-based architecture.
+            this.onCollide = function (e) {
+                var otherImpostor = _this._physicsEngine.getImpostorWithPhysicsBody(e.body);
+                if (otherImpostor) {
+                    _this._onPhysicsCollideCallbacks.filter(function (obj) {
+                        return obj.otherImpostor === otherImpostor;
+                    }).forEach(function (obj) {
+                        obj.callback(_this, obj.otherImpostor);
+                    });
+                }
+            };
+            //default options params
+            this._options.mass = (_options.mass === void 0) ? 0 : _options.mass;
+            this._options.friction = (_options.friction === void 0) ? 0.2 : _options.friction;
+            this._options.restitution = (_options.restitution === void 0) ? 0.2 : _options.restitution;
+            this._physicsEngine = this._mesh.getScene().getPhysicsEngine();
+            this._joints = [];
+            //If the mesh has a parent, don't initialize the physicsBody. Instead wait for the parent to do that.
+            if (!this._mesh.parent) {
+                this._init();
+            }
+        }
+        /**
+         * This function will completly initialize this impostor.
+         * It will create a new body - but only if this mesh has no parent.
+         * If it has, this impostor will not be used other than to define the impostor
+         * of the child mesh.
+         */
+        PhysicsImpostor.prototype._init = function () {
+            this._physicsEngine.removeImpostor(this);
+            this.physicsBody = null;
+            this._parent = this._parent || this._getPhysicsParent();
+            if (!this.parent) {
+                this._physicsEngine.addImpostor(this);
+            }
+        };
+        PhysicsImpostor.prototype._getPhysicsParent = function () {
+            if (this.mesh.parent instanceof BABYLON.AbstractMesh) {
+                var parentMesh = this.mesh.parent;
+                return parentMesh.getPhysicsImpostor();
+            }
+            return;
+        };
+        /**
+         * Should a new body be generated.
+         */
+        PhysicsImpostor.prototype.isBodyInitRequired = function () {
+            return this._bodyUpdateRequired || (!this._physicsBody && !this._parent);
+        };
+        PhysicsImpostor.prototype.setScalingUpdated = function (updated) {
+            this.forceUpdate();
+        };
+        /**
+         * Force a regeneration of this or the parent's impostor's body.
+         * Use under cautious - This will remove all joints already implemented.
+         */
+        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", {
+            /**
+             * Gets the body that holds this impostor. Either its own, or its parent.
+             */
+            get: function () {
+                return this._parent ? this._parent.physicsBody : this._physicsBody;
+            },
+            /**
+             * Set the physics body. Used mainly by the physics engine/plugin
+             */
+            set: function (physicsBody) {
+                if (this._physicsBody) {
+                    this._physicsEngine.getPhysicsPlugin().removePhysicsBody(this);
+                }
+                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._bodyUpdateRequired = false;
+        };
+        /**
+         * Get a specific parametes from the options parameter.
+         */
+        PhysicsImpostor.prototype.getParam = function (paramName) {
+            return this._options[paramName];
+        };
+        /**
+         * Sets a specific parameter in the options given to the physics plugin
+         */
+        PhysicsImpostor.prototype.setParam = function (paramName, value) {
+            this._options[paramName] = value;
+            this._bodyUpdateRequired = true;
+        };
+        /**
+         * Set the body's velocity.
+         */
+        PhysicsImpostor.prototype.setVelocity = function (velocity) {
+            this._physicsEngine.getPhysicsPlugin().setVelocity(this, velocity);
+        };
+        /**
+         * Execute a function with the physics plugin native code.
+         * Provide a function the will have two variables - the world object and the physics body object.
+         */
+        PhysicsImpostor.prototype.executeNativeFunction = function (func) {
+            func(this._physicsEngine.getPhysicsPlugin().world, this.physicsBody);
+        };
+        /**
+         * Register a function that will be executed before the physics world is stepping forward.
+         */
+        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");
+            }
+        };
+        /**
+         * Register a function that will be executed after the physics step
+         */
+        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");
+            }
+        };
+        /**
+         * register a function that will be executed when this impostor collides against a different body.
+         */
+        PhysicsImpostor.prototype.registerOnPhysicsCollide = function (collideAgainst, func) {
+            this._onPhysicsCollideCallbacks.push({ callback: func, otherImpostor: collideAgainst });
+        };
+        PhysicsImpostor.prototype.unregisterOnPhysicsCollide = function (collideAgainst, func) {
+            var index = this._onPhysicsCollideCallbacks.indexOf({ callback: func, otherImpostor: collideAgainst });
+            if (index > -1) {
+                this._onPhysicsCollideCallbacks.splice(index, 1);
+            }
+            else {
+                BABYLON.Tools.Warn("Function to remove was not found");
+            }
+        };
+        /**
+         * Apply a force
+         */
+        PhysicsImpostor.prototype.applyForce = function (force, contactPoint) {
+            this._physicsEngine.getPhysicsPlugin().applyForce(this, force, contactPoint);
+        };
+        /**
+         * Apply an impulse
+         */
+        PhysicsImpostor.prototype.applyImpulse = function (force, contactPoint) {
+            this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
+        };
+        /**
+         * A help function to create a joint.
+         */
+        PhysicsImpostor.prototype.createJoint = function (otherImpostor, jointType, jointData) {
+            var joint = new BABYLON.PhysicsJoint(jointType, jointData);
+            this.addJoint(otherImpostor, joint);
+        };
+        /**
+         * Add a joint to this impostor with a different impostor.
+         */
+        PhysicsImpostor.prototype.addJoint = function (otherImpostor, joint) {
+            this._joints.push({
+                otherImpostor: otherImpostor,
+                joint: joint
+            });
+            this._physicsEngine.addJoint(this, otherImpostor, joint);
+        };
+        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.physicsImpostor) {
+                        if (disposeChildren) {
+                            mesh.physicsImpostor.dispose();
+                            mesh.physicsImpostor = null;
+                        }
+                    }
+                });
+            }
+        };
+        PhysicsImpostor.prototype.setDeltaPosition = function (position) {
+            this._deltaPosition.copyFrom(position);
+        };
+        PhysicsImpostor.prototype.setDeltaRotation = function (rotation) {
+            this._deltaRotation.copyFrom(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 = {}));

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

@@ -0,0 +1,333 @@
+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 _bodyUpdateRequired: boolean = false;
+
+        private _onBeforePhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
+        private _onAfterPhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
+        private _onPhysicsCollideCallbacks: Array<{ callback: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor) => void, otherImpostors: Array<PhysicsImpostor> }> = []
+
+        private _deltaPosition: Vector3 = Vector3.Zero();
+        private _deltaRotation: Quaternion = new 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 = { mass: 0 }) {
+            //default options params
+            this._options.mass = (_options.mass === void 0) ? 0 : _options.mass
+            this._options.friction = (_options.friction === void 0) ? 0.2 : _options.friction
+            this._options.restitution = (_options.restitution === void 0) ? 0.2 : _options.restitution
+            this._physicsEngine = this._mesh.getScene().getPhysicsEngine();
+            this._joints = [];
+            //If the mesh has a parent, don't initialize the physicsBody. Instead wait for the parent to do that.
+            if (!this._mesh.parent) {
+                this._init();
+            }
+        }
+
+        /**
+         * This function will completly initialize this impostor.
+         * It will create a new body - but only if this mesh has no parent.
+         * If it has, this impostor will not be used other than to define the impostor
+         * of the child mesh.
+         */
+        public _init() {
+            this._physicsEngine.removeImpostor(this);
+            this.physicsBody = null;
+            this._parent = this._parent || this._getPhysicsParent();
+            if (!this.parent) {
+                this._physicsEngine.addImpostor(this);
+            }
+        }
+
+        private _getPhysicsParent(): PhysicsImpostor {
+            if (this.mesh.parent instanceof AbstractMesh) {
+                var parentMesh: AbstractMesh = <AbstractMesh>this.mesh.parent;
+                return parentMesh.getPhysicsImpostor();
+            }
+            return;
+        }
+
+        /**
+         * Should a new body be generated.
+         */
+        public isBodyInitRequired(): boolean {
+            return this._bodyUpdateRequired || (!this._physicsBody && !this._parent);
+        }
+
+        public setScalingUpdated(updated: boolean) {
+            this.forceUpdate();
+        }
+
+        /**
+         * Force a regeneration of this or the parent's impostor's body.
+         * Use under cautious - This will remove all joints already implemented.
+         */
+        public forceUpdate() {
+            this._init();
+            if (this.parent) {
+                this.parent.forceUpdate();
+            }
+        }
+
+        public get mesh(): AbstractMesh {
+            return this._mesh;
+        }
+
+        /**
+         * Gets the body that holds this impostor. Either its own, or its parent.
+         */
+        public get physicsBody(): any {
+            return this._parent ? this._parent.physicsBody : this._physicsBody;
+        }
+
+        public get parent() {
+            return this._parent;
+        }
+
+        /**
+         * Set the physics body. Used mainly by the physics engine/plugin
+         */
+        public set physicsBody(physicsBody: any) {
+            if (this._physicsBody) {
+                this._physicsEngine.getPhysicsPlugin().removePhysicsBody(this);
+            }
+            this._physicsBody = physicsBody;
+            this.resetUpdateFlags();
+        }
+
+        public resetUpdateFlags() {
+            this._bodyUpdateRequired = false;
+        }
+
+        /**
+         * Get a specific parametes from the options parameter.
+         */
+        public getParam(paramName: string) {
+            return this._options[paramName];
+        }
+
+        /**
+         * Sets a specific parameter in the options given to the physics plugin
+         */
+        public setParam(paramName: string, value: number) {
+            this._options[paramName] = value;
+            this._bodyUpdateRequired = true;
+        }
+
+        /**
+         * Set the body's velocity.
+         */
+        public setVelocity(velocity: Vector3) {
+            this._physicsEngine.getPhysicsPlugin().setVelocity(this, velocity);
+        }
+        
+        /**
+         * Execute a function with the physics plugin native code.
+         * Provide a function the will have two variables - the world object and the physics body object.
+         */
+        public executeNativeFunction(func: (world: any, physicsBody: any) => void) {
+            func(this._physicsEngine.getPhysicsPlugin().world, this.physicsBody);
+        }
+
+        /**
+         * Register a function that will be executed before the physics world is stepping forward.
+         */
+        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");
+            }
+        }
+
+        /**
+         * Register a function that will be executed after the physics step
+         */
+        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");
+            }
+        }
+
+        /**
+         * register a function that will be executed when this impostor collides against a different body.
+         */
+        public registerOnPhysicsCollide(collideAgainst: PhysicsImpostor | Array<PhysicsImpostor>, func: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor) => void): void {
+            var collidedAgainstList : Array<PhysicsImpostor> = collideAgainst instanceof Array ? <Array<PhysicsImpostor>> collideAgainst : [<PhysicsImpostor>collideAgainst]
+            this._onPhysicsCollideCallbacks.push({ callback: func, otherImpostors: collidedAgainstList });
+        }
+
+        public unregisterOnPhysicsCollide(collideAgainst: PhysicsImpostor | Array<PhysicsImpostor>, func: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor | Array<PhysicsImpostor>) => void): void {
+            var collidedAgainstList : Array<PhysicsImpostor> = collideAgainst instanceof Array ? <Array<PhysicsImpostor>> collideAgainst : [<PhysicsImpostor>collideAgainst]
+            var index = this._onPhysicsCollideCallbacks.indexOf({ callback: func, otherImpostors: collidedAgainstList });
+
+            if (index > -1) {
+                this._onPhysicsCollideCallbacks.splice(index, 1);
+            } else {
+                Tools.Warn("Function to remove was not found");
+            }
+        }
+
+        private _tmpPositionWithDelta: Vector3 = Vector3.Zero();
+        private _tmpRotationWithDelta: Quaternion = new Quaternion();
+
+        /**
+         * this function is executed by the physics engine.
+         */
+        public beforeStep = () => {
+
+            this.mesh.position.subtractToRef(this._deltaPosition, this._tmpPositionWithDelta);
+            //conjugate deltaRotation
+            this._tmpRotationWithDelta.copyFrom(this._deltaRotation);
+            this._tmpRotationWithDelta.multiplyInPlace(this.mesh.rotationQuaternion);
+
+            this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(this, this._tmpPositionWithDelta, this._tmpRotationWithDelta);
+
+            this._onBeforePhysicsStepCallbacks.forEach((func) => {
+                func(this);
+            });
+        }
+
+        /**
+         * this function is executed by the physics engine.
+         */
+        public afterStep = () => {
+            this._onAfterPhysicsStepCallbacks.forEach((func) => {
+                func(this);
+            });
+
+            this._physicsEngine.getPhysicsPlugin().setTransformationFromPhysicsBody(this);
+
+            this.mesh.position.addInPlace(this._deltaPosition)
+            this.mesh.rotationQuaternion.multiplyInPlace(this._deltaRotation);
+        }
+        
+        //event and body object due to cannon's event-based architecture.
+        public onCollide = (e: { body: any }) => {
+            var otherImpostor = this._physicsEngine.getImpostorWithPhysicsBody(e.body);
+            if (otherImpostor) {
+                this._onPhysicsCollideCallbacks.filter((obj) => {
+                    return obj.otherImpostors.indexOf(otherImpostor) !== -1
+                }).forEach((obj) => {
+                    obj.callback(this, otherImpostor);
+                })
+            }
+        }
+
+        /**
+         * Apply a force 
+         */
+        public applyForce(force: Vector3, contactPoint: Vector3) {
+            this._physicsEngine.getPhysicsPlugin().applyForce(this, force, contactPoint);
+        }
+
+        /**
+         * Apply an impulse
+         */
+        public applyImpulse(force: Vector3, contactPoint: Vector3) {
+            this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
+        }
+
+        /**
+         * A help function to create a joint.
+         */
+        public createJoint(otherImpostor: PhysicsImpostor, jointType: number, jointData: PhysicsJointData) {
+            var joint = new PhysicsJoint(jointType, jointData);
+            this.addJoint(otherImpostor, joint);
+        }
+
+        /**
+         * Add a joint to this impostor with a different impostor.
+         */
+        public addJoint(otherImpostor: PhysicsImpostor, joint: PhysicsJoint) {
+            this._joints.push({
+                otherImpostor: otherImpostor,
+                joint: joint
+            })
+            this._physicsEngine.addJoint(this, otherImpostor, joint);
+        }
+        
+        /**
+         * Will keep this body still, in a sleep mode.
+         */
+        public sleep() {
+            this._physicsEngine.getPhysicsPlugin().sleepBody(this);
+        }
+        
+        /**
+         * Wake the body up.
+         */
+        public wakeUp() {
+            this._physicsEngine.getPhysicsPlugin().wakeUpBody(this);
+        }
+
+        public dispose(disposeChildren: boolean = true) {
+            this.physicsBody = null;
+            if (this.parent) {
+                this.parent.forceUpdate();
+            } else {
+                this.mesh.getChildMeshes().forEach(function (mesh) {
+                    if (mesh.physicsImpostor) {
+                        if (disposeChildren) {
+                            mesh.physicsImpostor.dispose();
+                            mesh.physicsImpostor = null;
+                        }
+                    }
+                })
+            }
+        }
+
+        public setDeltaPosition(position: Vector3) {
+            this._deltaPosition.copyFrom(position);
+        }
+
+        public setDeltaRotation(rotation: Quaternion) {
+            this._deltaRotation.copyFrom(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 = {}));

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

@@ -0,0 +1,61 @@
+module BABYLON {
+
+    export interface PhysicsJointData {
+        //Important for some engines, optional!
+        mainPivot?: Vector3;
+        connectedPivot?: Vector3;
+        mainAxis?: Vector3,
+        connectedAxis?: Vector3,
+        collision?: boolean //native in oimo, needs this - https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html in cannon
+        //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
+    }
+}

+ 9 - 8
src/PostProcess/babylon.tonemapPostProcess.js

@@ -15,23 +15,24 @@ var BABYLON;
     ;
     var TonemapPostProcess = (function (_super) {
         __extends(TonemapPostProcess, _super);
-        function TonemapPostProcess(name, operator, exposureAdjustment, camera, samplingMode, engine, textureFormat) {
+        function TonemapPostProcess(name, _operator, exposureAdjustment, camera, samplingMode, engine, textureFormat) {
             var _this = this;
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE; }
             if (textureFormat === void 0) { textureFormat = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
-            this._operator = operator;
+            _super.call(this, name, "tonemap", ["_ExposureAdjustment"], null, 1.0, camera, samplingMode, engine, true, defines, textureFormat);
+            this._operator = _operator;
             this.exposureAdjustment = exposureAdjustment;
-            var params = ["_ExposureAdjustment"];
             var defines = "#define ";
-            if (operator === TonemappingOperator.Hable)
+            if (this._operator === TonemappingOperator.Hable)
                 defines += "HABLE_TONEMAPPING";
-            else if (operator === TonemappingOperator.Reinhard)
+            else if (this._operator === TonemappingOperator.Reinhard)
                 defines += "REINHARD_TONEMAPPING";
-            else if (operator === TonemappingOperator.HejiDawson)
+            else if (this._operator === TonemappingOperator.HejiDawson)
                 defines += "OPTIMIZED_HEJIDAWSON_TONEMAPPING";
-            else if (operator === TonemappingOperator.Photographic)
+            else if (this._operator === TonemappingOperator.Photographic)
                 defines += "PHOTOGRAPHIC_TONEMAPPING";
-            _super.call(this, name, "tonemap", params, null, 1.0, camera, samplingMode, engine, true, defines, textureFormat);
+            //sadly a second call to create the effect.
+            this.updateEffect(defines);
             this.onApply = function (effect) {
                 effect.setFloat("_ExposureAdjustment", _this.exposureAdjustment);
             };

+ 14 - 21
src/PostProcess/babylon.tonemapPostProcess.ts

@@ -1,41 +1,34 @@
-module BABYLON
-{
-    export enum TonemappingOperator
-    {
+module BABYLON {
+    export enum TonemappingOperator {
         Hable = 0,
         Reinhard = 1,
         HejiDawson = 2,
         Photographic = 3,
     };
 
-    export class TonemapPostProcess extends PostProcess
-    {
-        private _operator : TonemappingOperator;
-        public exposureAdjustment : number;
+    export class TonemapPostProcess extends PostProcess {
 
-        constructor(name: string, operator: TonemappingOperator, exposureAdjustment: number, camera: Camera, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, textureFormat = Engine.TEXTURETYPE_UNSIGNED_INT)
-        {
-            this._operator = operator;
-            this.exposureAdjustment = exposureAdjustment;
+        constructor(name: string, private _operator: TonemappingOperator, public exposureAdjustment: number, camera: Camera, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, textureFormat = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            super(name, "tonemap", ["_ExposureAdjustment"], null, 1.0, camera, samplingMode, engine, true, defines, textureFormat);
 
-            var params = ["_ExposureAdjustment"];
             var defines = "#define ";
 
-            if (operator === TonemappingOperator.Hable)
+            if (this._operator === TonemappingOperator.Hable)
                 defines += "HABLE_TONEMAPPING";
-            else if (operator === TonemappingOperator.Reinhard)
+            else if (this._operator === TonemappingOperator.Reinhard)
                 defines += "REINHARD_TONEMAPPING";
-            else if (operator === TonemappingOperator.HejiDawson)
+            else if (this._operator === TonemappingOperator.HejiDawson)
                 defines += "OPTIMIZED_HEJIDAWSON_TONEMAPPING";
-            else if (operator === TonemappingOperator.Photographic)
+            else if (this._operator === TonemappingOperator.Photographic)
                 defines += "PHOTOGRAPHIC_TONEMAPPING";
+                
+            //sadly a second call to create the effect.
+            this.updateEffect(defines);
 
-            super(name, "tonemap", params, null, 1.0, camera, samplingMode, engine, true, defines, textureFormat);
 
-            this.onApply = (effect: Effect) =>
-            {
+            this.onApply = (effect: Effect) => {
                 effect.setFloat("_ExposureAdjustment", this.exposureAdjustment);
             };
         }
     }
-}
+}

+ 31 - 0
src/Shaders/ShadersInclude/bumpFragment.fx

@@ -0,0 +1,31 @@
+#ifdef BUMP
+	vec2 bumpUV = vBumpUV;
+#endif
+
+#if defined(BUMP) || defined(PARALLAX)
+	mat3 TBN = cotangent_frame(normalW * vBumpInfos.y, -viewDirectionW, bumpUV);
+#endif
+
+#ifdef PARALLAX
+	mat3 invTBN = transposeMat3(TBN);
+
+	#ifdef PARALLAXOCCLUSION
+		vec2 uvOffset = parallaxOcclusion(invTBN * -viewDirectionW, invTBN * normalW, bumpUV, vBumpInfos.z);
+	#else
+		vec2 uvOffset = parallaxOffset(invTBN * viewDirectionW, vBumpInfos.z);
+	#endif
+
+	diffuseUV += uvOffset;
+	bumpUV += uvOffset;
+
+	// Note from Loic: won't be nice with wrapping textures...
+	#ifdef PARALLAXOCCLUSION
+		if (diffuseUV.x > 1.0 || diffuseUV.y > 1.0 || diffuseUV.x < 0.0 || diffuseUV.y < 0.0) {
+			discard;
+		}
+	#endif
+#endif
+
+#ifdef BUMP
+	normalW = perturbNormal(viewDirectionW, TBN, bumpUV);
+#endif

+ 64 - 5
src/Shaders/ShadersInclude/bumpFragmentFunctions.fx

@@ -1,6 +1,6 @@
 #ifdef BUMP
 	varying vec2 vBumpUV;
-	uniform vec2 vBumpInfos;
+	uniform vec3 vBumpInfos;
 	uniform sampler2D bumpSampler;
 
 	// Thanks to http://www.thetenthplanet.de/archives/1180
@@ -23,11 +23,70 @@
 		return mat3(tangent * invmax, binormal * invmax, normal);
 	}
 
-	vec3 perturbNormal(vec3 viewDir)
+	vec3 perturbNormal(vec3 viewDir, mat3 cotangentFrame, vec2 uv)
 	{
-		vec3 map = texture2D(bumpSampler, vBumpUV).xyz;
+		vec3 map = texture2D(bumpSampler, uv).xyz;
 		map = map * 255. / 127. - 128. / 127.;
-		mat3 TBN = cotangent_frame(vNormalW * vBumpInfos.y, -viewDir, vBumpUV);
-		return normalize(TBN * map);
+		return normalize(cotangentFrame * map);
 	}
+
+	#ifdef PARALLAX
+		const float minSamples = 4.;
+		const float maxSamples = 15.;
+		const int iMaxSamples = 15;
+
+		// http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/a-closer-look-at-parallax-occlusion-mapping-r3262
+		vec2 parallaxOcclusion(vec3 vViewDirCoT, vec3 vNormalCoT, vec2 texCoord, float parallaxScale) {
+
+			float parallaxLimit = length(vViewDirCoT.xy) / vViewDirCoT.z;
+			parallaxLimit *= parallaxScale;
+			vec2 vOffsetDir = normalize(vViewDirCoT.xy);
+			vec2 vMaxOffset = vOffsetDir * parallaxLimit;
+			float numSamples = maxSamples + (dot(vViewDirCoT, vNormalCoT) * (minSamples - maxSamples));
+			float stepSize = 1.0 / numSamples;
+
+			// Initialize the starting view ray height and the texture offsets.
+			float currRayHeight = 1.0;
+			vec2 vCurrOffset = vec2(0, 0);
+			vec2 vLastOffset = vec2(0, 0);
+
+			float lastSampledHeight = 1.0;
+			float currSampledHeight = 1.0;
+
+			for (int i = 0; i < iMaxSamples; i++)
+			{
+				currSampledHeight = texture2D(bumpSampler, vBumpUV + vCurrOffset).w;
+
+				// Test if the view ray has intersected the surface.
+				if (currSampledHeight > currRayHeight)
+				{
+					float delta1 = currSampledHeight - currRayHeight;
+					float delta2 = (currRayHeight + stepSize) - lastSampledHeight;
+					float ratio = delta1 / (delta1 + delta2);
+					vCurrOffset = (ratio)* vLastOffset + (1.0 - ratio) * vCurrOffset;
+
+					// Force the exit of the loop
+					break;
+				}
+				else
+				{
+					currRayHeight -= stepSize;
+					vLastOffset = vCurrOffset;
+					vCurrOffset += stepSize * vMaxOffset;
+
+					lastSampledHeight = currSampledHeight;
+				}
+			}
+
+			return vCurrOffset;
+		}
+
+		vec2 parallaxOffset(vec3 viewDir, float heightScale)
+		{
+			// calculate amount of offset for Parallax Mapping With Offset Limiting
+			float height = texture2D(bumpSampler, vBumpUV).w;
+			vec2 texCoordOffset = heightScale * viewDir.xy * height;
+			return -texCoordOffset;
+		}
+	#endif
 #endif

+ 13 - 0
src/Shaders/ShadersInclude/helperFunctions.fx

@@ -0,0 +1,13 @@
+mat3 transposeMat3(mat3 inMatrix) {
+	vec3 i0 = inMatrix[0];
+	vec3 i1 = inMatrix[1];
+	vec3 i2 = inMatrix[2];
+
+	mat3 outMatrix = mat3(
+		vec3(i0.x, i1.x, i2.x),
+		vec3(i0.y, i1.y, i2.y),
+		vec3(i0.z, i1.z, i2.z)
+		);
+
+	return outMatrix;
+}

+ 23 - 19
src/Shaders/default.fragment.fx

@@ -30,6 +30,9 @@ varying vec3 vNormalW;
 varying vec4 vColor;
 #endif
 
+// Helper functions
+#include<helperFunctions>
+
 // Lights
 #include<light0FragmentDeclaration>
 #include<light1FragmentDeclaration>
@@ -161,8 +164,21 @@ void main(void) {
 	// Alpha
 	float alpha = vDiffuseColor.a;
 
+	// Bump
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = vec3(1.0, 1.0, 1.0);
+#endif
+
+#ifdef DIFFUSE
+	vec2 diffuseUV = vDiffuseUV;
+#endif
+
+#include<bumpFragment>
+
 #ifdef DIFFUSE
-	baseColor = texture2D(diffuseSampler, vDiffuseUV);
+	baseColor = texture2D(diffuseSampler, diffuseUV);
 
 #ifdef ALPHATEST
 	if (baseColor.a < 0.4)
@@ -180,18 +196,6 @@ void main(void) {
 	baseColor.rgb *= vColor.rgb;
 #endif
 
-	// Bump
-#ifdef NORMAL
-	vec3 normalW = normalize(vNormalW);
-#else
-	vec3 normalW = vec3(1.0, 1.0, 1.0);
-#endif
-
-
-#ifdef BUMP
-	normalW = perturbNormal(viewDirectionW);
-#endif
-
 	// Ambient color
 	vec3 baseAmbientColor = vec3(1., 1., 1.);
 
@@ -259,15 +263,15 @@ void main(void) {
 
 #ifdef REFLECTIONMAP_3D
 #ifdef ROUGHNESS
-	 float bias = vReflectionInfos.y;
+	float bias = vReflectionInfos.y;
 
-	#ifdef SPECULARTERM
+#ifdef SPECULARTERM
 	#ifdef SPECULAR
-	#ifdef GLOSSINESS
-		bias *= (1.0 - specularMapColor.a);
-	#endif
-	#endif
+		#ifdef GLOSSINESS
+			bias *= (1.0 - specularMapColor.a);
+		#endif
 	#endif
+#endif
 
 	reflectionColor = textureCube(reflectionCubeSampler, vReflectionUVW, bias).rgb * vReflectionInfos.x;
 #else

+ 1 - 1
src/Shaders/default.vertex.fx

@@ -61,7 +61,7 @@ uniform mat4 specularMatrix;
 
 #ifdef BUMP
 varying vec2 vBumpUV;
-uniform vec2 vBumpInfos;
+uniform vec3 vBumpInfos;
 uniform mat4 bumpMatrix;
 #endif
 

+ 16 - 5
src/Tools/babylon.decorators.js

@@ -24,12 +24,16 @@ var BABYLON;
         return generateSerializableMember(3, sourceName); // fresnel parameters member
     }
     BABYLON.serializeAsFresnelParameters = serializeAsFresnelParameters;
+    function serializeAsVector2(sourceName) {
+        return generateSerializableMember(4, sourceName); // vector2 member
+    }
+    BABYLON.serializeAsVector2 = serializeAsVector2;
     function serializeAsVector3(sourceName) {
-        return generateSerializableMember(4, sourceName); // vector3 member
+        return generateSerializableMember(5, sourceName); // vector3 member
     }
     BABYLON.serializeAsVector3 = serializeAsVector3;
     function serializeAsMeshReference(sourceName) {
-        return generateSerializableMember(5, sourceName); // mesh reference member
+        return generateSerializableMember(6, sourceName); // mesh reference member
     }
     BABYLON.serializeAsMeshReference = serializeAsMeshReference;
     var SerializationHelper = (function () {
@@ -65,6 +69,9 @@ var BABYLON;
                             serializationObject[targetPropertyName] = sourceProperty.asArray();
                             break;
                         case 5:
+                            serializationObject[targetPropertyName] = sourceProperty.asArray();
+                            break;
+                        case 6:
                             serializationObject[targetPropertyName] = sourceProperty.id;
                             break;
                     }
@@ -96,9 +103,12 @@ var BABYLON;
                             destination[property] = BABYLON.FresnelParameters.Parse(sourceProperty);
                             break;
                         case 4:
-                            destination[property] = BABYLON.Vector3.FromArray(sourceProperty);
+                            destination[property] = BABYLON.Vector2.FromArray(sourceProperty);
                             break;
                         case 5:
+                            destination[property] = BABYLON.Vector3.FromArray(sourceProperty);
+                            break;
+                        case 6:
                             destination[property] = scene.getLastMeshByID(sourceProperty);
                             break;
                     }
@@ -118,13 +128,14 @@ var BABYLON;
                 if (sourceProperty !== undefined && sourceProperty !== null) {
                     switch (propertyType) {
                         case 0: // Value
-                        case 5:
+                        case 6:
                             destination[property] = sourceProperty;
                             break;
                         case 1: // Texture
                         case 2: // Color3
                         case 3: // FresnelParameters
-                        case 4:
+                        case 4: // Vector2
+                        case 5:
                             destination[property] = sourceProperty.clone();
                             break;
                     }

+ 20 - 9
src/Tools/babylon.decorators.ts

@@ -5,7 +5,7 @@
                 target.__serializableMembers = {};
             }
 
-            target.__serializableMembers[propertyKey] = { type: type, sourceName: sourceName }; 
+            target.__serializableMembers[propertyKey] = { type: type, sourceName: sourceName };
         }
     }
 
@@ -25,12 +25,16 @@
         return generateSerializableMember(3, sourceName); // fresnel parameters member
     }
 
+    export function serializeAsVector2(sourceName?: string) {
+        return generateSerializableMember(4, sourceName); // vector2 member
+    }
+
     export function serializeAsVector3(sourceName?: string) {
-        return generateSerializableMember(4, sourceName); // vector3 member
+        return generateSerializableMember(5, sourceName); // vector3 member
     }
 
     export function serializeAsMeshReference(sourceName?: string) {
-        return generateSerializableMember(5, sourceName); // mesh reference member
+        return generateSerializableMember(6, sourceName); // mesh reference member
     }
 
     export class SerializationHelper {
@@ -64,10 +68,13 @@
                         case 3:     // FresnelParameters
                             serializationObject[targetPropertyName] = sourceProperty.serialize();
                             break;
-                        case 4:     // Vector3
+                        case 4:     // Vector2
                             serializationObject[targetPropertyName] = sourceProperty.asArray();
                             break;
-                        case 5:     // Mesh reference
+                        case 5:     // Vector3
+                            serializationObject[targetPropertyName] = sourceProperty.asArray();
+                            break;
+                        case 6:     // Mesh reference
                             serializationObject[targetPropertyName] = sourceProperty.id;
                             break;
                     }
@@ -103,10 +110,13 @@
                         case 3:     // FresnelParameters
                             destination[property] = FresnelParameters.Parse(sourceProperty);
                             break;
-                        case 4:     // Vector3
+                        case 4:     // Vector2
+                            destination[property] = Vector2.FromArray(sourceProperty);
+                            break;
+                        case 5:     // Vector3
                             destination[property] = Vector3.FromArray(sourceProperty);
                             break;
-                        case 5:     // Mesh reference
+                        case 6:     // Mesh reference
                             destination[property] = scene.getLastMeshByID(sourceProperty);
                             break;
                     }
@@ -131,13 +141,14 @@
                 if (sourceProperty !== undefined && sourceProperty !== null) {
                     switch (propertyType) {
                         case 0:     // Value
-                        case 5:     // Mesh reference
+                        case 6:     // Mesh reference
                             destination[property] = sourceProperty;
                             break;
                         case 1:     // Texture
                         case 2:     // Color3
                         case 3:     // FresnelParameters
-                        case 4:     // Vector3
+                        case 4:     // Vector2
+                        case 5:     // Vector3
                             destination[property] = sourceProperty.clone();
                             break;
                     }

+ 1 - 1
src/Tools/babylon.gamepads.js

@@ -63,7 +63,7 @@ var BABYLON;
             // Remove the gamepad from the list of gamepads to monitor.
             for (var i in this.babylonGamepads) {
                 if (this.babylonGamepads[i].index == evt.gamepad.index) {
-                    this.babylonGamepads.splice(i, 1);
+                    this.babylonGamepads.splice(+i, 1);
                     break;
                 }
             }

+ 5 - 16
src/Tools/babylon.gamepads.ts

@@ -5,8 +5,8 @@
 
         private isMonitoring: boolean = false;
         private gamepadEventSupported: boolean = 'GamepadEvent' in window;
-        private gamepadSupportAvailable: boolean = <boolean> (navigator.getGamepads ||
-        !!navigator.webkitGetGamepads || !!navigator.msGetGamepads || !!navigator.webkitGamepads);
+        private gamepadSupportAvailable: boolean = <boolean>(navigator.getGamepads ||
+            !!navigator.webkitGetGamepads || !!navigator.msGetGamepads || !!navigator.webkitGamepads);
 
         private _callbackGamepadConnected: (gamepad: Gamepad) => void;
 
@@ -68,7 +68,7 @@
             // Remove the gamepad from the list of gamepads to monitor.
             for (var i in this.babylonGamepads) {
                 if (this.babylonGamepads[i].index == evt.gamepad.index) {
-                    this.babylonGamepads.splice(i, 1);
+                    this.babylonGamepads.splice(+i, 1);
                     break;
                 }
             }
@@ -187,7 +187,7 @@
     }
 
     export class GenericPad extends Gamepad {
-        private _buttons: Array<number>; 
+        private _buttons: Array<number>;
         private _onbuttondown: (buttonPressed: number) => void;
         private _onbuttonup: (buttonReleased: number) => void;
 
@@ -442,20 +442,9 @@
     }
 }
 
-// Mixins
-//interface Window {
-//    webkitRequestAnimationFrame(func: any): any;
-//    mozRequestAnimationFrame(func: any): any;
-//    oRequestAnimationFrame(func: any): any;
-//    WebGLRenderingContext: WebGLRenderingContext;
-//    MSGesture: MSGesture;
-//    ongamepadconnected(func?: any): any;
-//}
-
 interface Navigator {
     getGamepads(func?: any): any;
     webkitGetGamepads(func?: any): any
     msGetGamepads(func?: any): any;
     webkitGamepads(func?: any): any;
-}
-
+}

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

+ 9 - 5
src/babylon.engine.js

@@ -938,11 +938,13 @@ var BABYLON;
             // Use program
             this._gl.useProgram(effect.getProgram());
             for (var i in this._vertexAttribArrays) {
-                if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[i]) {
+                //make sure this is a number)
+                var iAsNumber = +i;
+                if (iAsNumber > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[iAsNumber]) {
                     continue;
                 }
-                this._vertexAttribArrays[i] = false;
-                this._gl.disableVertexAttribArray(i);
+                this._vertexAttribArrays[iAsNumber] = false;
+                this._gl.disableVertexAttribArray(iAsNumber);
             }
             var attributesCount = effect.getAttributesCount();
             for (var index = 0; index < attributesCount; index++) {
@@ -1798,10 +1800,12 @@ var BABYLON;
             }
             // Unbind
             for (var i in this._vertexAttribArrays) {
-                if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[i]) {
+                //making sure this is a string
+                var iAsNumber = +i;
+                if (iAsNumber > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[iAsNumber]) {
                     continue;
                 }
-                this._gl.disableVertexAttribArray(i);
+                this._gl.disableVertexAttribArray(iAsNumber);
             }
             this._gl = null;
             // Events

+ 10 - 5
src/babylon.engine.ts

@@ -1134,11 +1134,13 @@
             this._gl.useProgram(effect.getProgram());
 
             for (var i in this._vertexAttribArrays) {
-                if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[i]) {
+                //make sure this is a number)
+                var iAsNumber = +i;
+                if (iAsNumber > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[iAsNumber]) {
                     continue;
                 }
-                this._vertexAttribArrays[i] = false;
-                this._gl.disableVertexAttribArray(i);
+                this._vertexAttribArrays[iAsNumber] = false;
+                this._gl.disableVertexAttribArray(iAsNumber);
             }
 
             var attributesCount = effect.getAttributesCount();
@@ -2217,10 +2219,12 @@
 
             // Unbind
             for (var i in this._vertexAttribArrays) {
-                if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[i]) {
+                //making sure this is a string
+                var iAsNumber = +i;
+                if (iAsNumber > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[iAsNumber]) {
                     continue;
                 }
-                this._gl.disableVertexAttribArray(i);
+                this._gl.disableVertexAttribArray(iAsNumber);
             }
 
             this._gl = null;
@@ -2317,3 +2321,4 @@
 
 
 
+

+ 22 - 6
src/babylon.node.js

@@ -131,10 +131,11 @@ var BABYLON;
             }
             return false;
         };
-        Node.prototype._getDescendants = function (list, results) {
+        Node.prototype._getDescendants = function (list, results, directDecendantsOnly) {
+            if (directDecendantsOnly === void 0) { directDecendantsOnly = false; }
             for (var index = 0; index < list.length; index++) {
                 var item = list[index];
-                if (item.isDescendantOf(this)) {
+                if ((directDecendantsOnly && item.parent === this) || (!directDecendantsOnly && item.isDescendantOf(this))) {
                     results.push(item);
                 }
             }
@@ -143,11 +144,26 @@ var BABYLON;
          * Will return all nodes that have this node as parent.
          * @return {BABYLON.Node[]} all children nodes of all types.
          */
-        Node.prototype.getDescendants = function () {
+        Node.prototype.getDescendants = function (directDecendantsOnly) {
             var results = [];
-            this._getDescendants(this._scene.meshes, results);
-            this._getDescendants(this._scene.lights, results);
-            this._getDescendants(this._scene.cameras, results);
+            this._getDescendants(this._scene.meshes, results, directDecendantsOnly);
+            this._getDescendants(this._scene.lights, results, directDecendantsOnly);
+            this._getDescendants(this._scene.cameras, results, directDecendantsOnly);
+            return results;
+        };
+        /**
+         * @Deprecated, legacy support.
+         * use getDecendants instead.
+         */
+        Node.prototype.getChildren = function () {
+            return this.getDescendants(true);
+        };
+        /**
+         * Get all child-meshes of this node.
+         */
+        Node.prototype.getChildMeshes = function (directDecendantsOnly) {
+            var results = [];
+            this._getDescendants(this._scene.meshes, results, false);
             return results;
         };
         Node.prototype._setReady = function (state) {

+ 24 - 8
src/babylon.node.ts

@@ -171,16 +171,15 @@
                     return true;
                 }
 
-
                 return this.parent.isDescendantOf(ancestor);
             }
             return false;
         }
 
-        public _getDescendants(list: Node[], results: Node[]): void {
+        public _getDescendants(list: Node[], results: Node[], directDecendantsOnly: boolean = false): void {
             for (var index = 0; index < list.length; index++) {
                 var item = list[index];
-                if (item.isDescendantOf(this)) {
+                if ((directDecendantsOnly && item.parent === this) || (!directDecendantsOnly && item.isDescendantOf(this))) {
                     results.push(item);
                 }
             }
@@ -190,14 +189,31 @@
          * Will return all nodes that have this node as parent.
          * @return {BABYLON.Node[]} all children nodes of all types.
          */
-        public getDescendants(): Node[] {
+        public getDescendants(directDecendantsOnly?: boolean): Node[] {
             var results = [];
-            this._getDescendants(this._scene.meshes, results);
-            this._getDescendants(this._scene.lights, results);
-            this._getDescendants(this._scene.cameras, results);
+            this._getDescendants(this._scene.meshes, results, directDecendantsOnly);
+            this._getDescendants(this._scene.lights, results, directDecendantsOnly);
+            this._getDescendants(this._scene.cameras, results, directDecendantsOnly);
 
             return results;
         }
+        
+        /**
+         * @Deprecated, legacy support.
+         * use getDecendants instead.
+         */
+        public getChildren(): Node[] {
+            return this.getDescendants(true);
+        }
+        
+        /**
+         * Get all child-meshes of this node.
+         */
+        public getChildMeshes(directDecendantsOnly?: boolean): AbstractMesh[] {
+            var results: Array<AbstractMesh> = [];
+            this._getDescendants(this._scene.meshes, results, false);
+            return results;
+        }
 
         public _setReady(state: boolean): void {
             if (state === this._isReady) {
@@ -283,4 +299,4 @@
             }
         }
     }
-} 
+} 

+ 27 - 21
src/babylon.scene.js

@@ -1488,7 +1488,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
@@ -1992,13 +1992,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) {
@@ -2011,38 +2012,43 @@ 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("Scene.createCompoundImpostor 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.physicsImpostor = 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;
+                if (mesh.parent !== mainMesh) {
+                    mesh.position = mesh.position.subtract(mainMesh.position);
+                    mesh.parent = mainMesh;
+                }
+                mesh.physicsImpostor = new BABYLON.PhysicsImpostor(mesh, parts[index].impostor, options);
             }
-            return this._physicsEngine._registerMeshesAsCompound(parts, options);
+            mainMesh.physicsImpostor.forceUpdate();
         };
         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.physicsImpostor.dispose(true);
+            mesh.physicsImpostor = null;
         };
         // Misc.
         Scene.prototype.createDefaultCameraOrLight = function () {

+ 30 - 28
src/babylon.scene.ts

@@ -556,7 +556,7 @@
 
                         if (pickResult.pickedMesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger)) {
                             var that = this;
-                            window.setTimeout(function () {
+                            window.setTimeout(function() {
                                 var pickResult = that.pick(that._unTranslatedPointerX, that._unTranslatedPointerY,
                                     (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger),
                                     false, that.cameraToUseForPointers);
@@ -1880,7 +1880,7 @@
             // Physics
             if (this._physicsEngine) {
                 Tools.StartPerformanceCounter("Physics");
-                this._physicsEngine._runOneStep(deltaTime / 1000.0);
+                this._physicsEngine._step(deltaTime / 1000.0);
                 Tools.EndPerformanceCounter("Physics");
             }
 
@@ -2491,16 +2491,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 {
@@ -2517,45 +2515,49 @@
         }
 
         /**
+         * 
          * 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("Scene.createCompoundImpostor is deprecated. Please use PhysicsImpostor parent/child")
+
             if (parts.parts) { // Old API
                 options = parts;
                 parts = parts.parts;
             }
 
-            if (!this._physicsEngine) {
-                return null;
-            }
-
-            for (var index = 0; index < parts.length; index++) {
-                var mesh = parts[index].mesh;
+            var mainMesh: AbstractMesh = parts[0].mesh;
+            mainMesh.physicsImpostor = new PhysicsImpostor(mainMesh, parts[0].impostor, options)
+            for (var index = 1; index < parts.length; index++) {
+                var mesh: AbstractMesh = parts[index].mesh;
+                if (mesh.parent !== mainMesh) {
+                    mesh.position = mesh.position.subtract(mainMesh.position);
+                    mesh.parent = mainMesh;
+                }
+                mesh.physicsImpostor = new PhysicsImpostor(mesh, parts[index].impostor, options)
 
-                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);
+            mainMesh.physicsImpostor.forceUpdate();
         }
 
         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.physicsImpostor.dispose(true);
+            mesh.physicsImpostor = null;
         }
 
         // Misc.