Browse Source

Merge pull request #1 from BabylonJS/master

test sync
Vousk-prod. 11 năm trước cách đây
mục cha
commit
fed793e585
43 tập tin đã thay đổi với 2542 bổ sung150 xóa
  1. 24 0
      Babylon/Cameras/Controllers/babylon.globalAxisFactorsFilter.js
  2. 20 0
      Babylon/Cameras/Controllers/babylon.gravityInputController.js
  3. 41 0
      Babylon/Cameras/Controllers/babylon.inputCollisionFilter.js
  4. 119 0
      Babylon/Cameras/Controllers/babylon.inputController.js
  5. 133 0
      Babylon/Cameras/Controllers/babylon.keyboardMoveController.js
  6. 53 0
      Babylon/Cameras/Controllers/babylon.oculusController.js
  7. 35 2
      Babylon/Cameras/babylon.arcRotateCamera.js
  8. 2 2
      Babylon/Cameras/babylon.camera.js
  9. 164 0
      Babylon/Cameras/babylon.oculusOrientedCamera.js
  10. 36 0
      Babylon/Cameras/babylon.virtualJoysticksCamera.js
  11. 0 34
      Babylon/Collisions/babylon.collisionPlane.js
  12. 1 1
      Babylon/LensFlare/babylon.lensFlareSystem.js
  13. 1 1
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  14. 1 1
      Babylon/Loading/babylon.sceneLoader.js
  15. 4 0
      Babylon/Materials/babylon.effect.js
  16. 5 4
      Babylon/Materials/textures/babylon.cubeTexture.js
  17. 3 2
      Babylon/Materials/textures/babylon.videoTexture.js
  18. 33 8
      Babylon/Math/babylon.math.js
  19. 619 0
      Babylon/Mesh/babylon.csg.js
  20. 31 0
      Babylon/Mesh/babylon.mesh.js
  21. 1 1
      Babylon/Physics/babylon.physicsEngine.js
  22. 13 4
      Babylon/PostProcess/babylon.convolutionPostProcess.js
  23. 18 0
      Babylon/PostProcess/babylon.filterPostProcess.js
  24. 32 0
      Babylon/PostProcess/babylon.oculusDistortionCorrectionPostProcess.js
  25. 30 5
      Babylon/Shaders/convolution.fragment.fx
  26. 17 0
      Babylon/Shaders/filter.fragment.fx
  27. 31 0
      Babylon/Shaders/oculusDistortionCorrection.fragment.fx
  28. 142 0
      Babylon/Tools/babylon.tools.dds.js
  29. 7 3
      Babylon/Tools/babylon.tools.js
  30. 341 0
      Babylon/Tools/babylon.virtualJoystick.js
  31. 83 45
      Babylon/babylon.engine.js
  32. 29 6
      Babylon/babylon.scene.js
  33. 301 0
      Exporters/Cheetah3d/Babylon file export.js
  34. 39 0
      Exporters/Cheetah3d/README.md
  35. 4 2
      Tools/BuildOurOwnBabylonJS/BabylonJS/BabylonJS.csproj
  36. 16 21
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS.sln
  37. 9 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml
  38. 5 3
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/BuildOurOwnBabylonJSServer.csproj
  39. 28 2
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/Controllers/OurDemoController.cs
  40. 15 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/ViewModel/OurDemoViewModel.cs
  41. 47 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/Views/OurDemo/sample.cshtml
  42. 5 3
      babylon.1.9.0.js
  43. 4 0
      readme.md

+ 24 - 0
Babylon/Cameras/Controllers/babylon.globalAxisFactorsFilter.js

@@ -0,0 +1,24 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+	BABYLON.GlobalAxisFactorsFilter = function (scene, target, xFactor, yFactor, zFactor) {
+		BABYLON.inputFilter.call(this, scene,target);
+		this.xFactor = xFactor;
+		this.yFactor = yFactor;
+		this.zFactor = zFactor;
+
+		this._globalMovement = new BABYLON.Vector3(0, 0, 0);
+	};
+	BABYLON.GlobalAxisFactorsFilter.prototype = Object.create(BABYLON.inputFilter.prototype);
+	BABYLON.GlobalAxisFactorsFilter.prototype.moveRelative = function (relativeMovement) {
+		var orientation = this.getOrientation();
+		BABYLON.Vector3.TransformNormalToRef(relativeMovement, this.getOrientationMatrix(), this._globalMovement);
+		this._globalMovement.x *= this.xFactor;
+		this._globalMovement.y *= this.yFactor;
+		this._globalMovement.z *= this.zFactor;
+		BABYLON.Vector3.TransformNormalToRef(this._globalMovement, this.getInvertOrientationMatrix(), relativeMovement);
+		this.target.moveRelative(relativeMovement);
+	};
+})();

+ 20 - 0
Babylon/Cameras/Controllers/babylon.gravityInputController.js

@@ -0,0 +1,20 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.GravityInputController = function (scene, target) {
+        BABYLON.InputController.call(this, scene, target);
+        this._moveVectorGlobal = new BABYLON.Vector3(0, 0, 0);
+        this._moveVectorLocal = new BABYLON.Vector3(0, 0, 0);
+        this._fallSpeed = .6;
+    };
+    BABYLON.GravityInputController.prototype = Object.create(BABYLON.InputController.prototype);
+    BABYLON.GravityInputController.prototype.update = function () {
+        this._moveVectorGlobal.x = 0;
+        this._moveVectorGlobal.y = -this._fallSpeed * BABYLON.Tools.GetDeltaTime() / 1000.0;
+        this._moveVectorGlobal.z = 0;
+        BABYLON.Vector3.TransformNormalToRef(this._moveVectorGlobal, this.target.getInvertOrientationMatrix(), this._moveVectorLocal);
+        this.target.moveRelative(this._moveVectorLocal);
+    };
+})();

+ 41 - 0
Babylon/Cameras/Controllers/babylon.inputCollisionFilter.js

@@ -0,0 +1,41 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+	BABYLON.InputCollisionFilter = function (scene, target, ellipsoid) {
+		BABYLON.inputFilter.call(this, scene, target);
+		this._transformedDirection = new BABYLON.Vector3();
+		this._tempNewPosition = new BABYLON.Vector3();
+		this._tempNewPosition2 = new BABYLON.Vector3();
+		this._ellipsoid = ellipsoid || new BABYLON.Vector3(.5,.5,.5);
+		this._collider = new BABYLON.Collider();
+		this._collidedPosition = new BABYLON.Vector3(0, 0, 0);
+		this._cameraHeight = 1.7;
+		this._positionBottom = new BABYLON.Vector3(0, 0, 0);
+	};
+	BABYLON.InputCollisionFilter.prototype = Object.create(BABYLON.inputFilter.prototype);
+	BABYLON.InputCollisionFilter.prototype.moveRelative = function (relativeMovement) {
+		var rotation = this.getOrientation();
+		BABYLON.Vector3.TransformNormalToRef(relativeMovement, this.getOrientationMatrix(), this._transformedDirection);
+		this.getPosition().addToRef(this._transformedDirection, this._tempNewPosition);
+		//this._tempNewPosition.y -= this._ellipsoid.y;
+		this._collider.radius = this._ellipsoid;
+		var p = this.getPosition();
+		this._positionBottom.x = p.x;
+		this._positionBottom.y = p.y;
+		this._positionBottom.z = p.z;
+		this._positionBottom.y +=  this._ellipsoid.y - this._cameraHeight;
+
+		this.scene._getNewPosition(this._positionBottom, this._transformedDirection, this._collider, 3, this._collidedPosition);
+
+
+		this._collidedPosition.subtractToRef(this._positionBottom, this._tempNewPosition2);
+		if (this._tempNewPosition2.length() > BABYLON.Engine.collisionsEpsilon * 5) {
+
+		    BABYLON.Vector3.TransformNormalToRef(this._tempNewPosition2, this.getInvertOrientationMatrix(), this._tempNewPosition);
+		    this.target.moveRelative(this._tempNewPosition);
+		} 
+
+	};
+})();

+ 119 - 0
Babylon/Cameras/Controllers/babylon.inputController.js

@@ -0,0 +1,119 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+
+	BABYLON.InputControllerTarget = function () {
+		this._position = new BABYLON.Vector3(0, 0, 0);
+		this._orientation = { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+	};
+
+	BABYLON.InputControllerTarget.prototype.getPosition = function () {
+		return this._position;
+	};
+	BABYLON.InputControllerTarget.prototype.getOrientation = function () {
+		return this._orientation;
+	};
+	BABYLON.InputControllerTarget.prototype.moveRelative = function (movementVector) {
+
+	};
+	
+	BABYLON.InputControllerTarget.prototype.rotateRelative = function (relativeOrientation) {
+
+	};
+	BABYLON.InputControllerTarget.prototype.getOrientationMatrix = function () { return new BABYLON.Matrix(); };
+	BABYLON.InputControllerTarget.prototype.getInvertOrientationMatrix = function () { return new BABYLON.Matrix(); };
+
+	BABYLON.InputControllerMultiTarget = function (targets) {
+	    this.targets = targets;
+	    var mainTarget = this.targets[0];
+	    if (!mainTarget.controllers) {
+	        mainTarget.controllers = [this];
+	    } else {
+	        mainTarget.controllers.push(this);
+	    }
+	};
+
+	BABYLON.InputControllerMultiTarget.prototype.getPosition = function () {
+		return this.targets[0].getPosition();
+	};
+	BABYLON.InputControllerMultiTarget.prototype.getOrientation = function () {
+		return this.targets[0].getOrientation();
+	};
+
+
+	BABYLON.InputControllerMultiTarget.prototype.getOrientationMatrix = function () { return this.targets[0].getOrientationMatrix(); };
+	BABYLON.InputControllerMultiTarget.prototype.getInvertOrientationMatrix = function () { return this.targets[0].getInvertOrientationMatrix(); };
+
+	BABYLON.InputControllerMultiTarget.prototype.moveRelative = function (movementVector) {
+		for (var i = 0; i < this.targets.length; ++i) {
+			this.targets[i].moveRelative(movementVector);
+		}
+	};
+
+	BABYLON.InputControllerMultiTarget.prototype.rotateRelative = function (relativeOrientation) {
+		for (var i = 0; i < this.targets.length; ++i) {
+			this.targets[i].rotateRelative(relativeOrientation);
+		}
+	};
+
+	BABYLON.InputControllerMultiTarget.prototype.update = function () {
+		if (this.controllers) {
+			for (var i = 0; i < this.controllers.length; ++i) {
+				this.controllers[i].update();
+			}
+		}
+	};
+	
+	BABYLON.InputController = function (scene, target) {
+		this.scene = scene;
+		this.target = target;
+		if (!this.target.controllers) {
+			this.target.controllers = [this];
+		} else {
+			this.target.controllers.push(this);
+		}
+	};
+	BABYLON.InputController.prototype.attachToCanvas = function (canvas) {
+
+	};
+	BABYLON.InputController.prototype.detachFromCanvas = function (canvas) {
+
+	};
+	BABYLON.InputController.prototype.update = function () {
+
+	};
+
+	BABYLON.InputController.prototype.dispose = function () {
+
+	};
+
+	BABYLON.inputFilter = function (scene, target) {
+	    BABYLON.InputController.call(this, scene, target);
+	};
+	BABYLON.inputFilter.prototype = Object.create(BABYLON.InputController.prototype);
+	BABYLON.inputFilter.prototype.update = function () {
+	    if (this.controllers) {
+	        for (var i = 0; i < this.controllers.length; ++i) {
+	            this.controllers[i].update();
+	        }
+	    }
+	};
+
+	BABYLON.inputFilter.prototype.getPosition = function () {
+	    return this.target.getPosition();
+	};
+	BABYLON.inputFilter.prototype.getOrientation = function () {
+	    return this.target.getOrientation();
+	};
+	BABYLON.inputFilter.prototype.getOrientationMatrix = function () { return this.target.getOrientationMatrix(); };
+	BABYLON.inputFilter.prototype.getInvertOrientationMatrix = function () { return this.target.getInvertOrientationMatrix(); };
+	BABYLON.inputFilter.prototype.moveRelative = function (movementVector) {
+	    this.target.moveRelative(movementVector);
+	};
+
+	BABYLON.inputFilter.prototype.rotateRelative = function (relativeOrientation) {
+	    this.target.rotateRelative(relativeOrientation);
+	};
+})();

+ 133 - 0
Babylon/Cameras/Controllers/babylon.keyboardMoveController.js

@@ -0,0 +1,133 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+	BABYLON.KeyboardMoveController = function (scene, target) {
+		BABYLON.InputController.call(this, scene, target);
+		this._keys = [];
+		this.keysUp = [38];
+		this.keysDown = [40];
+		this.keysLeft = [37];
+		this.keysRight = [39];
+		this._currentSpeed = new BABYLON.Vector3(0, 0, 0);
+		this._lastFrameSpeed = new BABYLON.Vector3(0, 0, 0);
+		this._currentAcceleration = new BABYLON.Vector3(0, 0, 0);
+		this._tempSpeed = new BABYLON.Vector3(0, 0, 0);
+		this._tempSpeed2 = new BABYLON.Vector3(0, 0, 0);
+		this.maxAbsoluteSpeed = 2; // 2 meters per second
+		this.maxAbsoluteAcceleration = 5; // 2 meters per second²
+		this._targetSpeed = new BABYLON.Vector3(0, 0, 0);
+	};
+	BABYLON.KeyboardMoveController.prototype = Object.create(BABYLON.InputController.prototype);
+	BABYLON.KeyboardMoveController.prototype.attachToCanvas = function (canvas) {
+		var that = this;
+		this._canvas = canvas;
+
+		this._onKeyDown = function (evt) {
+			if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
+				that.keysDown.indexOf(evt.keyCode) !== -1 ||
+				that.keysLeft.indexOf(evt.keyCode) !== -1 ||
+				that.keysRight.indexOf(evt.keyCode) !== -1) {
+				var index = that._keys.indexOf(evt.keyCode);
+
+				if (index === -1) {
+					that._keys.push(evt.keyCode);
+				}
+			}
+		};
+
+		this._onKeyUp = function (evt) {
+			if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
+				that.keysDown.indexOf(evt.keyCode) !== -1 ||
+				that.keysLeft.indexOf(evt.keyCode) !== -1 ||
+				that.keysRight.indexOf(evt.keyCode) !== -1) {
+				var index = that._keys.indexOf(evt.keyCode);
+
+				if (index >= 0) {
+					that._keys.splice(index, 1);
+				}
+			}
+		};
+
+		this._onLostFocus = function () {
+			that._keys = [];
+		};
+
+		window.addEventListener("keydown", this._onKeyDown, false);
+		window.addEventListener("keyup", this._onKeyUp, false);
+		window.addEventListener("blur", this._onLostFocus, false);
+	};
+	BABYLON.KeyboardMoveController.prototype.detachFromCanvas = function (canvas) {
+		window.removeEventListener("keydown", this._onKeyDown, false);
+		window.removeEventListener("keyup", this._onKeyUp, false);
+		window.removeEventListener("blur", this._onLostFocus, false);
+	};
+	BABYLON.KeyboardMoveController.prototype.updateCurrentSpeed = function () {
+		this._lastFrameSpeed.x = this._currentSpeed.x;
+		this._lastFrameSpeed.y = this._currentSpeed.y;
+		this._lastFrameSpeed.z = this._currentSpeed.z;
+		if (this._currentSpeed.equals(this._targetSpeed)) {
+			this._currentAcceleration.x = 0;
+			this._currentAcceleration.y = 0;
+			this._currentAcceleration.z = 0;
+			return;
+		}
+		var dt = BABYLON.Tools.GetDeltaTime()/1000.0;
+		
+		var dv = this._tempSpeed;
+		this._targetSpeed.subtractToRef(this._lastFrameSpeed, dv);
+		var absoluteAccToTarget = dv.length() / dt;
+		if (absoluteAccToTarget < this.maxAbsoluteAcceleration) {
+			this._currentSpeed.x = this._targetSpeed.x;
+			this._currentSpeed.y = this._targetSpeed.y;
+			this._currentSpeed.z = this._targetSpeed.z;
+			dv.normalize();
+			dv.scaleToRef(absoluteAccToTarget, this._currentAcceleration);
+		} else {
+			dv.normalize();
+			dv.scaleToRef(this.maxAbsoluteAcceleration, this._currentAcceleration);
+			dv.scaleInPlace(this.maxAbsoluteAcceleration * dt);
+		
+			this._currentSpeed.addInPlace(dv);
+		}
+	};
+	BABYLON.KeyboardMoveController.prototype.update = function () {
+		this._targetSpeed.x = 0;
+		this._targetSpeed.y = 0;
+		this._targetSpeed.z = 0;
+		// update target speed from input
+		for (var index = 0; index < this._keys.length; index++) {
+			var keyCode = this._keys[index];
+			if (this.keysLeft.indexOf(keyCode) !== -1) {
+				this._targetSpeed.x -= 1;
+			} else if (this.keysUp.indexOf(keyCode) !== -1) {
+				this._targetSpeed.z += 1;
+			} else if (this.keysRight.indexOf(keyCode) !== -1) {
+				this._targetSpeed.x += 1;
+			} else if (this.keysDown.indexOf(keyCode) !== -1) {
+				this._targetSpeed.z -= 1;
+			}
+		}
+		if (this._targetSpeed.x != 0 || this._targetSpeed.z != 0) {
+			this._targetSpeed.normalize();
+			this._targetSpeed.scaleInPlace(this.maxAbsoluteSpeed);
+		}
+
+		this.updateCurrentSpeed();
+
+		if (this._lastFrameSpeed.x == 0 && this._lastFrameSpeed.z == 0 && this._currentAcceleration.x == 0 && this._currentAcceleration.z == 0) {
+			return;
+		}
+
+		// dv = (dt * v0) + 1/2 * dt² * a
+
+		var dt = BABYLON.Tools.GetDeltaTime() / 1000.0;
+		this._lastFrameSpeed.scaleToRef(dt, this._tempSpeed);
+		this._currentAcceleration.scaleToRef(dt * dt * 0.5, this._tempSpeed2);
+		this._tempSpeed.addInPlace(this._tempSpeed2);
+		if (this._tempSpeed.x != 0 || this._tempSpeed.z != 0) {
+			this.target.moveRelative(this._tempSpeed);
+		}
+	};
+})();

+ 53 - 0
Babylon/Cameras/Controllers/babylon.oculusController.js

@@ -0,0 +1,53 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.OculusController = function (scene, target) {
+        BABYLON.InputController.call(this, scene, target);
+        this._deviceOrientationHandler = this.onOrientationEvent.bind(this);
+        this._tempOrientation = { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        this._relativeOrientation = { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+    };
+
+    BABYLON.OculusController.prototype = Object.create(BABYLON.InputController.prototype);
+
+    BABYLON.OculusController.prototype.onOrientationEvent = function (ev) {
+        this._tempOrientation.yaw = ev.alpha / 180 * Math.PI;
+        this._tempOrientation.pitch = ev.beta / 180 * Math.PI;
+        this._tempOrientation.roll = ev.gamma / 180 * Math.PI;
+
+        if (!this._lastOrientation) {
+            this._lastOrientation = Object.create(this._tempOrientation);
+        }
+        else {
+            this._relativeOrientation.yaw = this._tempOrientation.yaw - this._lastOrientation.yaw;
+            this._relativeOrientation.pitch = this._tempOrientation.pitch - this._lastOrientation.pitch;
+            this._relativeOrientation.roll = this._tempOrientation.roll - this._lastOrientation.roll;
+
+            var temp = this._tempOrientation;
+            this._tempOrientation = this._lastOrientation;
+            this._lastOrientation = temp;
+            this.target.rotateRelative(this._relativeOrientation);
+        }
+    };
+    BABYLON.OculusController.prototype.dispose = function () {
+        window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
+    };
+
+    BABYLON.OculusController.CameraSettings_OculusRiftDevKit2013_Metric = {
+        HResolution: 1280,
+        VResolution: 800,
+        HScreenSize: 0.149759993,
+        VScreenSize: 0.0935999975,
+        VScreenCenter: 0.0467999987,
+        EyeToScreenDistance: 0.0410000011,
+        LensSeparationDistance: 0.0635000020,
+        InterpupillaryDistance: 0.0640000030,
+        DistortionK: [1.0, 0.219999999, 0.239999995, 0.0],
+        ChromaAbCorrection: [0.995999992, -0.00400000019, 1.01400006, 0.0],
+        PostProcessScaleFactor: 1.714605507808412,
+        LensCenterOffset: 0.151976421
+    };
+})();

+ 35 - 2
Babylon/Cameras/babylon.arcRotateCamera.js

@@ -39,6 +39,7 @@ var BABYLON = BABYLON || {};
     BABYLON.ArcRotateCamera.prototype.lowerRadiusLimit = null;
     BABYLON.ArcRotateCamera.prototype.upperRadiusLimit = null;
     BABYLON.ArcRotateCamera.prototype.angularSensibility = 1000.0;
+    BABYLON.ArcRotateCamera.prototype.wheelPrecision = 3.0;
 
     BABYLON.ArcRotateCamera.prototype._getTargetPosition = function () {
         return this.target.position || this.target;
@@ -158,9 +159,9 @@ var BABYLON = BABYLON || {};
             this._wheel = function (event) {
                 var delta = 0;
                 if (event.wheelDelta) {
-                    delta = event.wheelDelta / 120;
+                    delta = event.wheelDelta / (that.wheelPrecision * 40);
                 } else if (event.detail) {
-                    delta = -event.detail / 3;
+                    delta = -event.detail / that.wheelPrecision;
                 }
 
                 if (delta)
@@ -370,5 +371,37 @@ var BABYLON = BABYLON || {};
 
         return this._viewMatrix;
     };
+
+    BABYLON.ArcRotateCamera.ZOOM_ON_FACTOR = 1;
+    BABYLON.ArcRotateCamera.prototype.zoomOn = function (meshes) {
+        meshes = meshes || this._scene.meshes;
+
+        var minMaxVector = BABYLON.Mesh.MinMax(meshes);
+        var distance = BABYLON.Vector3.Distance(minMaxVector.min, minMaxVector.max);
+
+        this.radius = distance * BABYLON.ArcRotateCamera.ZOOM_ON_FACTOR;
+
+        this.focusOn({min: minMaxVector.min, max: minMaxVector.max, distance: distance});
+    };
+
+    BABYLON.ArcRotateCamera.prototype.focusOn = function (meshesOrMinMaxVectorAndDistance) {
+        var meshesOrMinMaxVector;
+        var distance;
+
+        if (meshesOrMinMaxVectorAndDistance.min === undefined) { // meshes
+            meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance || this._scene.meshes;
+            meshesOrMinMaxVector = BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
+            distance = BABYLON.Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
+        }
+        else { //minMaxVector and distance
+            meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance;
+            distance = meshesOrMinMaxVectorAndDistance.distance;
+        }
+        
+        this.target = BABYLON.Mesh.Center(meshesOrMinMaxVector);
+        
+        this.maxZ = distance * 2;
+    };
+
 })();
 

+ 2 - 2
Babylon/Cameras/babylon.camera.js

@@ -203,7 +203,7 @@ var BABYLON = BABYLON || {};
             this._postProcessesTakenIndices.push(insertAt);
         }
 
-        result = insertAt + add;
+        var result = insertAt + add;
 
         this._postProcesses[result] = postProcess;
 
@@ -325,4 +325,4 @@ var BABYLON = BABYLON || {};
             this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
         }
     };
-})();
+})();

+ 164 - 0
Babylon/Cameras/babylon.oculusOrientedCamera.js

@@ -0,0 +1,164 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.OculusOrientedCamera = function (name, position, scene, isLeftEye, ovrSettings, neutralOrientation) {
+        BABYLON.Camera.call(this, name, position, scene);
+        this._referenceDirection = new BABYLON.Vector3(0, 0, 1);
+        this._referenceUp = new BABYLON.Vector3(0, 1, 0);
+        this._actualDirection = new BABYLON.Vector3(1, 0, 0);
+        this._actualUp = new BABYLON.Vector3(0, 1, 0);
+        this._currentTargetPoint = new BABYLON.Vector3(0, 0, 0);
+        this._currentOrientation = Object.create(neutralOrientation || { yaw: 0.0, pitch: 0.0, roll: 0.0 });
+        this._currentViewMatrix = new BABYLON.Matrix();
+        this._currentOrientationMatrix = new BABYLON.Matrix();
+        this._currentInvertOrientationMatrix = new BABYLON.Matrix();
+        this._tempMatrix = new BABYLON.Matrix();
+        
+        if (isLeftEye) {
+            this.viewport = new BABYLON.Viewport(0, 0, 0.5, 1.0);
+        } else {
+            this.viewport = new BABYLON.Viewport(0.5, 0, 0.5, 1.0);
+        }
+
+        this._aspectRatioAspectRatio = ovrSettings.HResolution / (2 * ovrSettings.VResolution);
+        this._aspectRatioFov = (2 * Math.atan((ovrSettings.PostProcessScaleFactor * ovrSettings.VScreenSize) / (2 * ovrSettings.EyeToScreenDistance)));
+        var hMeters = (ovrSettings.HScreenSize / 4) - (ovrSettings.LensSeparationDistance / 2);
+        var h = (4 * hMeters) / ovrSettings.HScreenSize;
+        this._hMatrix = BABYLON.Matrix.Translation(isLeftEye ? h : -h, 0, 0);
+
+        this._projectionMatrix = new BABYLON.Matrix();
+        this._preViewMatrix = BABYLON.Matrix.Translation(isLeftEye ? .5 * ovrSettings.InterpupillaryDistance : -.5 * ovrSettings.InterpupillaryDistance, 0, 0);
+        new BABYLON.OculusDistortionCorrectionPostProcess("Oculus Distortion", this, !isLeftEye, ovrSettings);
+        this.resetProjectionMatrix();
+        this.resetViewMatrix();
+    };
+    
+    BABYLON.OculusOrientedCamera.BuildOculusStereoCamera = function (scene, name, canvas, minZ, maxZ, position, neutralOrientation, useFXAA, disableGravity,disableCollisions, ovrSettings) {
+        position = position || new BABYLON.Vector2(0, 0);
+        neutralOrientation = neutralOrientation || { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        //var controller =  new BABYLON.OculusController();
+        ovrSettings = ovrSettings || BABYLON.OculusController.CameraSettings_OculusRiftDevKit2013_Metric;
+
+        var leftCamera = new BABYLON.OculusOrientedCamera(name + "_left", position, scene, true, ovrSettings, neutralOrientation);
+        leftCamera.minZ = minZ;
+        leftCamera.maxZ = maxZ;
+        if (useFXAA) {
+            new BABYLON.FxaaPostProcess("fxaa_left", 1.0, leftCamera);
+        }
+
+        var rightCamera = new BABYLON.OculusOrientedCamera(name + "_right", position, scene, false, ovrSettings, neutralOrientation);
+        rightCamera.minZ = minZ;
+        rightCamera.maxZ = maxZ;
+        if (useFXAA) {
+            new BABYLON.FxaaPostProcess("fxaa_right", 1.0, rightCamera);
+        }
+        scene.activeCameras = [];
+        scene.activeCameras.push(leftCamera);
+        scene.activeCameras.push(rightCamera);
+        leftCamera.attachControl(canvas);
+        rightCamera.attachControl(canvas);
+        var multiTarget = new BABYLON.InputControllerMultiTarget([leftCamera, rightCamera]);
+        var controller = new BABYLON.OculusController(scene, multiTarget);
+        var moveTarget = multiTarget;
+        if (!disableCollisions) {
+            var collisionFilter = new BABYLON.InputCollisionFilter(scene, multiTarget);
+            moveTarget = collisionFilter;
+        }
+        if (!disableGravity) {
+
+            var globalAxisFactorFilter = new BABYLON.GlobalAxisFactorsFilter(scene, moveTarget, 1, 0, 1);
+            var gravityController = new BABYLON.GravityInputController(scene, moveTarget);
+            moveTarget = globalAxisFactorFilter;
+        }
+        var moveController = new BABYLON.KeyboardMoveController(scene, moveTarget);
+        moveController.attachToCanvas(canvas);
+        var result = {
+            leftCamera: leftCamera, rightCamera: rightCamera, intermediateControllerTarget: multiTarget,
+            oculusController: controller,
+            keyboardController: moveController
+        };
+        result.dispose = function () {
+            this.leftCamera.detachControl(canvas);
+            this.rightCamera.detachControl(canvas);
+            this.leftCamera.dispose();
+            this.rightCamera.dispose();
+            this.oculusController.dispose();
+            this.keyboardController.detachFromCanvas(canvas);
+            this.keyboardController.dispose();
+        }.bind(result);
+        return result;
+    };
+    
+    BABYLON.OculusOrientedCamera.prototype = Object.create(BABYLON.Camera.prototype);
+
+    BABYLON.OculusOrientedCamera.prototype.resetViewMatrix = function () {
+        BABYLON.Matrix.RotationYawPitchRollToRef(
+            this._currentOrientation.yaw,
+            this._currentOrientation.pitch,
+            -this._currentOrientation.roll
+            , this._currentOrientationMatrix);
+        this._currentOrientationMatrix.invertToRef(this._currentInvertOrientationMatrix);
+
+        BABYLON.Vector3.TransformNormalToRef(this._referenceDirection, this._currentOrientationMatrix, this._actualDirection);
+        BABYLON.Vector3.TransformNormalToRef(this._referenceUp, this._currentOrientationMatrix, this._actualUp);
+
+        BABYLON.Vector3.FromFloatsToRef(this.position.x + this._actualDirection.x, this.position.y + this._actualDirection.y, this.position.z + this._actualDirection.z, this._currentTargetPoint);
+        BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTargetPoint, this._actualUp, this._tempMatrix);
+        this._tempMatrix.multiplyToRef(this._preViewMatrix, this._currentViewMatrix);
+        return this._currentViewMatrix;
+    };
+    BABYLON.OculusOrientedCamera.prototype.getViewMatrix = function () {
+
+        return this._currentViewMatrix;
+    };
+
+    BABYLON.OculusOrientedCamera.prototype._update = function () {
+        if (this.controllers) {
+            for (var i = 0; i < this.controllers.length; ++i) {
+                this.controllers[i].update();
+            }
+        }
+    };
+
+    BABYLON.OculusOrientedCamera.prototype.getOrientationMatrix = function () {
+        return this._currentOrientationMatrix;
+    };
+
+    BABYLON.OculusOrientedCamera.prototype.getInvertOrientationMatrix = function () {
+        return this._currentInvertOrientationMatrix;
+    };
+
+    BABYLON.OculusOrientedCamera.prototype.resetProjectionMatrix = function () {
+        BABYLON.Matrix.PerspectiveFovLHToRef(this._aspectRatioFov, this._aspectRatioAspectRatio, this.minZ, this.maxZ, this._tempMatrix);
+        this._tempMatrix.multiplyToRef(this._hMatrix, this._projectionMatrix);
+        return this._projectionMatrix;
+    };
+
+    BABYLON.OculusOrientedCamera.prototype.getProjectionMatrix = function (force) {
+        return this._projectionMatrix;
+    };
+
+    // implementation of InputControllerTarget
+    BABYLON.OculusOrientedCamera.prototype.getOrientation = function () {
+        return this._currentOrientation;
+    };
+    BABYLON.OculusOrientedCamera.prototype.getPosition = function () {
+        return this.position;
+    };
+    BABYLON.OculusOrientedCamera.prototype.moveRelative = function (movementVector) {
+        if (!this._tempMoveVector) {
+            this._tempMoveVector = new BABYLON.Vector3(0, 0, 0);
+        }
+        BABYLON.Vector3.TransformNormalToRef(movementVector, this._currentOrientationMatrix, this._tempMoveVector);
+        this.position.addInPlace(this._tempMoveVector);
+        this.resetViewMatrix();
+    };
+    BABYLON.OculusOrientedCamera.prototype.rotateRelative = function (rotation) {
+        this._currentOrientation.yaw += rotation.yaw;
+        this._currentOrientation.pitch += rotation.pitch;
+        this._currentOrientation.roll += rotation.roll;
+        this.resetViewMatrix();
+    };
+})();

+ 36 - 0
Babylon/Cameras/babylon.virtualJoysticksCamera.js

@@ -0,0 +1,36 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.VirtualJoysticksCamera = function (name, position, scene) {
+        BABYLON.FreeCamera.call(this, name, position, scene);
+        this.leftjoystick = new BABYLON.VirtualJoystick(true);
+        this.leftjoystick.setAxisForUD("Z");
+        this.leftjoystick.setAxisForLR("X");
+        this.leftjoystick.setJoystickSensibility(0.15);
+        this.rightjoystick = new BABYLON.VirtualJoystick(false);
+        this.rightjoystick.setAxisForUD("X");
+        this.rightjoystick.setAxisForLR("Y");
+        this.rightjoystick.reverseUpDown = true;
+        this.rightjoystick.setJoystickSensibility(0.05);
+        this.rightjoystick.setJoystickColor("yellow");
+    };
+
+    // We're mainly based on the logic defined into the FreeCamera code
+    BABYLON.VirtualJoysticksCamera.prototype = Object.create(BABYLON.FreeCamera.prototype);
+    BABYLON.VirtualJoysticksCamera.prototype._checkInputs = function () {
+        var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+        var deltaTransform = BABYLON.Vector3.TransformCoordinates(this.leftjoystick.deltaPosition, cameraTransform);
+        this.cameraDirection = this.cameraDirection.add(deltaTransform);
+        this.cameraRotation = this.cameraRotation.add(this.rightjoystick.deltaPosition);
+        if (!this.leftjoystick.pressed) {
+            this.leftjoystick.deltaPosition = this.leftjoystick.deltaPosition.scale(0.9);
+        }
+        if (!this.rightjoystick.pressed) {
+            this.rightjoystick.deltaPosition = this.rightjoystick.deltaPosition.scale(0.9);
+        }
+    };
+
+    BABYLON.VirtualJoysticksCamera.prototype.dispose = function () {
+        this.leftjoystick.releaseCanvas();
+    };
+})();

+ 0 - 34
Babylon/Collisions/babylon.collisionPlane.js

@@ -1,34 +0,0 @@
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.CollisionPlane = function (origin, normal) {
-        this.normal = normal;
-        this.origin = origin;
-
-        normal.normalize();
-
-        this.equation = [];
-        this.equation[0] = normal.x;
-        this.equation[1] = normal.y;
-        this.equation[2] = normal.z;
-        this.equation[3] = -(normal.x * origin.x + normal.y * origin.y + normal.z * origin.z);
-    };
-
-    // Methods
-    BABYLON.CollisionPlane.prototype.isFrontFacingTo = function (direction, epsilon) {
-        var dot = BABYLON.Vector3.Dot(this.normal, direction);
-
-        return (dot <= epsilon);
-    };
-
-    BABYLON.CollisionPlane.prototype.signedDistanceTo = function (point) {
-        return BABYLON.Vector3.Dot(point, this.normal) + this.equation[3];
-    };
-
-    // Statics
-    BABYLON.CollisionPlane.CreateFromPoints = function (p1, p2, p3) {
-        var normal = BABYLON.Vector3.Cross(p2.subtract(p1), p3.subtract(p1));
-
-        return new BABYLON.CollisionPlane(p1, normal);
-    };
-})();

+ 1 - 1
Babylon/LensFlare/babylon.lensFlareSystem.js

@@ -164,7 +164,7 @@ var BABYLON = BABYLON || {};
             var y = centerY - (distY * flare.position);
             
             var cw = flare.size;
-            var ch = flare.size * engine.getAspectRatio();
+            var ch = flare.size * engine.getAspectRatio(this._scene.activeCamera);
             var cx = 2 * (x / globalViewport.width) - 1.0;
             var cy = 1.0 - 2 * (y / globalViewport.height);
             

+ 1 - 1
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -651,7 +651,7 @@ var BABYLON = BABYLON || {};
             }
 
             if (parsedData.activeCameraID) {
-                scene.activeCameraByID(parsedData.activeCameraID);
+                scene.setActiveCameraByID(parsedData.activeCameraID);
             }
 
             // Materials

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

@@ -55,7 +55,7 @@ var BABYLON = BABYLON || {};
 
         Load: function (rootUrl, sceneFilename, engine, onsuccess, progressCallBack, onerror) {
 
-            var plugin = this._getPluginForFilename(sceneFilename);
+            var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
             var database;
 
             var loadSceneFromData = function (data) {

+ 4 - 0
Babylon/Materials/babylon.effect.js

@@ -193,6 +193,10 @@ var BABYLON = BABYLON || {};
         this._valueCache[uniformName][2] = z;
         this._valueCache[uniformName][3] = w;
     };
+    
+    BABYLON.Effect.prototype.setArray = function (uniformName, array) {
+        this._engine.setArray(this.getUniform(uniformName), array);
+    };
 
     BABYLON.Effect.prototype.setMatrices = function (uniformName, matrices) {
         this._engine.setMatrices(this.getUniform(uniformName), matrices);

+ 5 - 4
Babylon/Materials/textures/babylon.cubeTexture.js

@@ -3,16 +3,17 @@
 var BABYLON = BABYLON || {};
 
 (function () {    
-    BABYLON.CubeTexture = function (rootUrl, scene, extensions) {
+    BABYLON.CubeTexture = function (rootUrl, scene, extensions, noMipmap) {
         this._scene = scene;
         this._scene.textures.push(this);
         
         this.name = rootUrl;
         this.url = rootUrl;
+        this._noMipmap = noMipmap;
         this.hasAlpha = false;
         this.coordinatesMode = BABYLON.Texture.CUBIC_MODE;
 
-        this._texture = this._getFromCache(rootUrl);
+        this._texture = this._getFromCache(rootUrl, noMipmap);
 
         if (!extensions) {
             extensions = ["_px.jpg", "_py.jpg", "_pz.jpg", "_nx.jpg", "_ny.jpg", "_nz.jpg"];
@@ -22,7 +23,7 @@ var BABYLON = BABYLON || {};
         
         if (!this._texture) {
             if (!scene.useDelayedTextureLoading) {
-                this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, extensions);
+                this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, extensions, noMipmap);
             } else {
                 this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NOTLOADED;
             }            
@@ -42,7 +43,7 @@ var BABYLON = BABYLON || {};
         }
 
         this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
-        this._texture = this._getFromCache(this.url);
+        this._texture = this._getFromCache(this.url, this._noMipmap);
 
         if (!this._texture) {
             this._texture = this._scene.getEngine().createCubeTexture(this.url, this._scene, this._extensions);

+ 3 - 2
Babylon/Materials/textures/babylon.videoTexture.js

@@ -3,11 +3,12 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.VideoTexture = function (name, urls, size, scene, generateMipMaps) {
+    BABYLON.VideoTexture = function (name, urls, size, scene, generateMipMaps, invertY) {
         this._scene = scene;
         this._scene.textures.push(this);
 
         this.name = name;
+        this._invertY = invertY;
 
         this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
         this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
@@ -54,7 +55,7 @@ var BABYLON = BABYLON || {};
         }
 
         this._lastUpdate = now;
-        this._scene.getEngine().updateVideoTexture(this._texture, this.video);
+        this._scene.getEngine().updateVideoTexture(this._texture, this.video, this._invertY);
         return true;
     };
 })();

+ 33 - 8
Babylon/Math/babylon.math.js

@@ -247,6 +247,10 @@ var BABYLON = BABYLON || {};
     BABYLON.Color3.FromArray = function (array) {
         return new BABYLON.Color3(array[0], array[1], array[2]);
     };
+    
+    BABYLON.Color3.FromInts = function (r, g, b) {
+        return new BABYLON.Color3(r / 255.0, g / 255.0, b / 255.0);
+    };
 
     ////////////////////////////////// Color4 //////////////////////////////////
 
@@ -340,6 +344,11 @@ var BABYLON = BABYLON || {};
 
         return new BABYLON.Color4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
     };
+    
+    BABYLON.Color4.FromInts = function (r, g, b, a) {
+        return new BABYLON.Color4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
+    };
+
 
     ////////////////////////////////// Vector2 //////////////////////////////////
 
@@ -647,6 +656,18 @@ var BABYLON = BABYLON || {};
         result.z = this.z / otherVector.z;
     };
 
+    BABYLON.Vector3.prototype.MinimizeInPlace = function (other) {
+        if (other.x < this.x) this.x = other.x;
+        if (other.y < this.y) this.y = other.y;
+        if (other.z < this.z) this.z = other.z;
+    };
+
+    BABYLON.Vector3.prototype.MaximizeInPlace = function (other) {
+        if (other.x > this.x) this.x = other.x;
+        if (other.y > this.y) this.y = other.y;
+        if (other.z > this.z) this.z = other.z;
+    };
+
     // Properties
     BABYLON.Vector3.prototype.length = function () {
         return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
@@ -889,17 +910,15 @@ var BABYLON = BABYLON || {};
     };
 
     BABYLON.Vector3.Minimize = function (left, right) {
-        var x = (left.x < right.x) ? left.x : right.x;
-        var y = (left.y < right.y) ? left.y : right.y;
-        var z = (left.z < right.z) ? left.z : right.z;
-        return new BABYLON.Vector3(x, y, z);
+        var min = left.clone();
+        min.MinimizeInPlace(right);
+        return min;
     };
 
     BABYLON.Vector3.Maximize = function (left, right) {
-        var x = (left.x > right.x) ? left.x : right.x;
-        var y = (left.y > right.y) ? left.y : right.y;
-        var z = (left.z > right.z) ? left.z : right.z;
-        return new BABYLON.Vector3(x, y, z);
+        var max = left.clone();
+        max.MaximizeInPlace(right);
+        return max;
     };
 
     BABYLON.Vector3.Distance = function (value1, value2) {
@@ -914,6 +933,12 @@ var BABYLON = BABYLON || {};
         return (x * x) + (y * y) + (z * z);
     };
 
+    BABYLON.Vector3.Center = function (value1, value2) {
+        var center = value1.add(value2);
+        center.scaleInPlace(0.5);
+        return center;
+    };
+
     ////////////////////////////////// Quaternion //////////////////////////////////
 
     BABYLON.Quaternion = function (initialX, initialY, initialZ, initialW) {

+ 619 - 0
Babylon/Mesh/babylon.csg.js

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

+ 31 - 0
Babylon/Mesh/babylon.mesh.js

@@ -896,6 +896,11 @@ var BABYLON = BABYLON || {};
             this._indexBuffer = null;
         }
 
+        // Physics
+        if (this.getPhysicsImpostor() != BABYLON.PhysicsEngine.NoImpostor) {
+            this.setPhysicsState({ impostor: BABYLON.PhysicsEngine.NoImpostor });
+        }
+
         // Remove from scene
         var index = this._scene.meshes.indexOf(this);
         this._scene.meshes.splice(index, 1);
@@ -1592,4 +1597,30 @@ var BABYLON = BABYLON || {};
             normals[index * 3 + 2] = normal.z;
         }
     };
+
+    BABYLON.Mesh.MinMax = function(meshes) {
+        var minVector;
+        var maxVector;
+        for(var i in meshes) {
+            var mesh = meshes[i];
+            var boundingBox = mesh.getBoundingInfo().boundingBox;
+            if (!minVector) {
+                minVector = boundingBox.minimumWorld;
+                maxVector = boundingBox.maximumWorld;
+                continue;
+            }
+            minVector.MinimizeInPlace(boundingBox.minimumWorld);
+            maxVector.MaximizeInPlace(boundingBox.maximumWorld);
+        }
+
+        return {
+            min: minVector,
+            max: maxVector
+        };
+    };
+
+    BABYLON.Mesh.Center = function(meshesOrMinMaxVector) {
+        var minMaxVector = meshesOrMinMaxVector.min !== undefined ? meshesOrMinMaxVector : BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
+        return BABYLON.Vector3.Center(minMaxVector.min, minMaxVector.max);
+    };
 })();

+ 1 - 1
Babylon/Physics/babylon.physicsEngine.js

@@ -267,7 +267,7 @@ var BABYLON = BABYLON || {};
 
     // Statics
     BABYLON.PhysicsEngine.IsSupported = function () {
-        return CANNON !== undefined;
+        return window.CANNON !== undefined;
     };
 
     BABYLON.PhysicsEngine.NoImpostor = 0;

+ 13 - 4
Babylon/PostProcess/babylon.convolutionPostProcess.js

@@ -3,16 +3,25 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.ConvolutionPostProcess = function (name, kernelMatrix, ratio, camera, samplingMode, engine, reusable) {
-        BABYLON.PostProcess.call(this, name, "convolution", ["kernelMatrix"], null, ratio, camera, samplingMode, engine, reusable);
+    BABYLON.ConvolutionPostProcess = function (name, kernel, ratio, camera, samplingMode, engine, reusable) {
+        BABYLON.PostProcess.call(this, name, "convolution", ["kernel", "screenSize"], null, ratio, camera, samplingMode, engine, reusable);
         
-        this.kernelMatrix = kernelMatrix;
+        this.kernel = kernel;
         var that = this;
         this.onApply = function (effect) {
-            effect.setMatrix("kernelMatrix", that.kernelMatrix);
+            effect.setFloat2("screenSize", that.width, that.height);
+            effect.setArray("kernel", that.kernel);
         };
     };
     
     BABYLON.ConvolutionPostProcess.prototype = Object.create(BABYLON.PostProcess.prototype);
+    
+    // Based on http://en.wikipedia.org/wiki/Kernel_(image_processing)
+    BABYLON.ConvolutionPostProcess.EdgeDetect0Kernel = [1, 0, -1, 0, 0, 0, -1, 0, 1];
+    BABYLON.ConvolutionPostProcess.EdgeDetect1Kernel = [0, 1, 0, 1, -4, 1, 0, 1, 0];
+    BABYLON.ConvolutionPostProcess.EdgeDetect2Kernel = [-1, -1, -1, -1, 8, -1, -1, -1, -1];
+    BABYLON.ConvolutionPostProcess.SharpenKernel = [0, -1, 0, -1, 5, -1, 0, -1, 0];
+    BABYLON.ConvolutionPostProcess.EmbossKernel = [-2, -1, 0, -1, 1, 1, 0, 1, 2];
+    BABYLON.ConvolutionPostProcess.GaussianKernel = [0, 1, 0, 1, 1, 1, 0, 1, 0];
 
 })();

+ 18 - 0
Babylon/PostProcess/babylon.filterPostProcess.js

@@ -0,0 +1,18 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.FilterPostProcess = function (name, kernelMatrix, ratio, camera, samplingMode, engine, reusable) {
+        BABYLON.PostProcess.call(this, name, "filter", ["kernelMatrix"], null, ratio, camera, samplingMode, engine, reusable);
+        
+        this.kernelMatrix = kernelMatrix;
+        var that = this;
+        this.onApply = function (effect) {
+            effect.setMatrix("kernelMatrix", that.kernelMatrix);
+        };
+    };
+    
+    BABYLON.FilterPostProcess.prototype = Object.create(BABYLON.PostProcess.prototype);
+
+})();

+ 32 - 0
Babylon/PostProcess/babylon.oculusDistortionCorrectionPostProcess.js

@@ -0,0 +1,32 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.OculusDistortionCorrectionPostProcess = function (name, camera, isRightEye, cameraSettings) {
+        BABYLON.PostProcess.call(this, name, "oculusDistortionCorrection", [
+			'LensCenter',
+		    'Scale',
+		    'ScaleIn',
+		    'HmdWarpParam'
+        ], null, cameraSettings.PostProcessScaleFactor, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, null, null);
+        this._isRightEye = isRightEye;
+        this._distortionFactors = cameraSettings.DistortionK;
+        this._postProcessScaleFactor = cameraSettings.PostProcessScaleFactor;
+        this._lensCenterOffset = cameraSettings.LensCenterOffset;
+    };
+
+    BABYLON.OculusDistortionCorrectionPostProcess.prototype = Object.create(BABYLON.PostProcess.prototype);
+    BABYLON.OculusDistortionCorrectionPostProcess.prototype.onSizeChanged = function () {
+        this.aspectRatio = this.width * .5 / this.height;
+        this._scaleIn = new BABYLON.Vector2(2, 2 / this.aspectRatio);
+        this._scaleFactor = new BABYLON.Vector2(.5 * (1/this._postProcessScaleFactor), .5 * (1/this._postProcessScaleFactor) * this.aspectRatio);
+        this._lensCenter = new BABYLON.Vector2(this._isRightEye ? 0.5 - this._lensCenterOffset * 0.5 : 0.5 + this._lensCenterOffset * 0.5, 0.5);
+    };
+    BABYLON.OculusDistortionCorrectionPostProcess.prototype.onApply = function (effect) {
+        effect.setFloat2("LensCenter", this._lensCenter.x, this._lensCenter.y);
+        effect.setFloat2("Scale", this._scaleFactor.x, this._scaleFactor.y);
+        effect.setFloat2("ScaleIn", this._scaleIn.x, this._scaleIn.y);
+        effect.setFloat4("HmdWarpParam", this._distortionFactors[0], this._distortionFactors[1], this._distortionFactors[2], this._distortionFactors[3]);
+    };
+})();

+ 30 - 5
Babylon/Shaders/convolution.fragment.fx

@@ -6,12 +6,37 @@ precision mediump float;
 varying vec2 vUV;
 uniform sampler2D textureSampler;
 
-uniform mat4 kernelMatrix;
+uniform vec2 screenSize;
+uniform float kernel[9];
 
-void main(void) 
+void main(void)
 {
-	vec3 baseColor = texture2D(textureSampler, vUV).rgb;
-	vec3 updatedColor = (kernelMatrix * vec4(baseColor, 1.0)).rgb;
+	vec2 onePixel = vec2(1.0, 1.0) / screenSize;
+	vec4 colorSum =
+		texture2D(textureSampler, vUV + onePixel * vec2(-1, -1)) * kernel[0] +
+		texture2D(textureSampler, vUV + onePixel * vec2(0, -1)) * kernel[1] +
+		texture2D(textureSampler, vUV + onePixel * vec2(1, -1)) * kernel[2] +
+		texture2D(textureSampler, vUV + onePixel * vec2(-1, 0)) * kernel[3] +
+		texture2D(textureSampler, vUV + onePixel * vec2(0, 0)) * kernel[4] +
+		texture2D(textureSampler, vUV + onePixel * vec2(1, 0)) * kernel[5] +
+		texture2D(textureSampler, vUV + onePixel * vec2(-1, 1)) * kernel[6] +
+		texture2D(textureSampler, vUV + onePixel * vec2(0, 1)) * kernel[7] +
+		texture2D(textureSampler, vUV + onePixel * vec2(1, 1)) * kernel[8];
 
-	gl_FragColor = vec4(updatedColor, 1.0);
+	float kernelWeight =
+		kernel[0] +
+		kernel[1] +
+		kernel[2] +
+		kernel[3] +
+		kernel[4] +
+		kernel[5] +
+		kernel[6] +
+		kernel[7] +
+		kernel[8];
+
+	if (kernelWeight <= 0.0) {
+		kernelWeight = 1.0;
+	}
+
+	gl_FragColor = vec4((colorSum / kernelWeight).rgb, 1);
 }

+ 17 - 0
Babylon/Shaders/filter.fragment.fx

@@ -0,0 +1,17 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+uniform mat4 kernelMatrix;
+
+void main(void)
+{
+	vec3 baseColor = texture2D(textureSampler, vUV).rgb;
+	vec3 updatedColor = (kernelMatrix * vec4(baseColor, 1.0)).rgb;
+
+	gl_FragColor = vec4(updatedColor, 1.0);
+}

+ 31 - 0
Babylon/Shaders/oculusDistortionCorrection.fragment.fx

@@ -0,0 +1,31 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+uniform vec2 LensCenter;
+uniform vec2 Scale;
+uniform vec2 ScaleIn;
+uniform vec4 HmdWarpParam;
+
+vec2 HmdWarp(vec2 in01) {
+
+	vec2 theta = (in01 - LensCenter) * ScaleIn; // Scales to [-1, 1]
+	float rSq = theta.x * theta.x + theta.y * theta.y;
+	vec2 rvector = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);
+	return LensCenter + Scale * rvector;
+}
+
+
+
+void main(void)
+{
+	vec2 tc = HmdWarp(vUV);
+	if (tc.x <0.0 || tc.x>1.0 || tc.y<0.0 || tc.y>1.0)
+		gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+	else{
+		gl_FragColor = vec4(texture2D(textureSampler, tc).rgb, 1.0);
+	}
+}

+ 142 - 0
Babylon/Tools/babylon.tools.dds.js

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

+ 7 - 3
Babylon/Tools/babylon.tools.js

@@ -3,7 +3,7 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.Tools = {};
+    BABYLON.Tools = BABYLON.Tools || {};
 
     BABYLON.Tools.GetFilename = function (path) {
         var index = path.lastIndexOf("/");
@@ -215,18 +215,22 @@ var BABYLON = BABYLON || {};
         return img;
     };
 
-    BABYLON.Tools.LoadFile = function (url, callback, progressCallBack, database) {
+    BABYLON.Tools.LoadFile = function (url, callback, progressCallBack, database, useArrayBuffer) {
         var noIndexedDB = function () {
             var request = new XMLHttpRequest();
             var loadUrl = BABYLON.Tools.BaseUrl + url;
             request.open('GET', loadUrl, true);
+            
+            if (useArrayBuffer) {
+                request.responseType = "arraybuffer";
+            }
 
             request.onprogress = progressCallBack;
 
             request.onreadystatechange = function () {
                 if (request.readyState == 4) {
                     if (request.status == 200) {
-                        callback(request.responseText);
+                        callback(!useArrayBuffer ? request.responseText : request.response);
                     } else { // Failed
                         throw new Error(request.status, "Unable to load " + loadUrl);
                     }

+ 341 - 0
Babylon/Tools/babylon.virtualJoystick.js

@@ -0,0 +1,341 @@
+/// <reference path="../../babylon.js" />
+
+// Mainly based on these 2 articles : 
+// Creating an universal virtual touch joystick working for all Touch models thanks to Hand.JS : http://blogs.msdn.com/b/davrous/archive/2013/02/22/creating-an-universal-virtual-touch-joystick-working-for-all-touch-models-thanks-to-hand-js.aspx
+// & on Seb Lee-Delisle original work: http://seb.ly/2011/04/multi-touch-game-controller-in-javascripthtml5-for-ipad/ 
+
+"use strict";
+
+// shim layer with setTimeout fallback
+window.requestAnimationFrame = (function () {
+    return window.requestAnimationFrame ||
+          window.webkitRequestAnimationFrame ||
+          window.mozRequestAnimationFrame ||
+          function (callback) {
+              window.setTimeout(callback, 1000 / 60);
+          };
+})();
+
+(function (BABYLON) {
+    var VirtualJoystick = (function () {
+        var vjCanvas, vjCanvasContext, vjCanvasWidth, vjCanvasHeight, halfWidth, halfHeight;
+        var globalJoystickIndex = 0;
+
+        function VirtualJoystick(leftJoystick) {
+            if (leftJoystick) {
+                this._leftJoystick = true;
+            }
+            else {
+                this._leftJoystick = false;
+            }
+
+            this.joystickIndex = globalJoystickIndex;
+            globalJoystickIndex++;
+
+            // By default left & right arrow keys are moving the X
+            // and up & down keys are moving the Y
+            this._axisTargetedByLeftAndRight = "X";
+            this._axisTargetedByUpAndDown = "Y";
+
+            this.reverseLeftRight = false;
+            this.reverseUpDown = false;
+
+            // collections of pointers
+            this._touches = new BABYLON.VirtualJoystick.Collection();
+            this.deltaPosition = BABYLON.Vector3.Zero();
+
+            this._joystickSensibility = 25;
+            this._inversedSensibility = 1 / (this._joystickSensibility / 1000);
+            this._rotationSpeed = 25;
+            this._inverseRotationSpeed = 1 / (this._rotationSpeed / 1000);
+            this._rotateOnAxisRelativeToMesh = false;
+
+            var that = this;
+
+            // injecting a canvas element on top of the canvas 3D game
+            if (!vjCanvas) {
+                window.addEventListener("resize", function () {
+                    vjCanvasWidth = window.innerWidth;
+                    vjCanvasHeight = window.innerHeight;
+                    vjCanvas.width = vjCanvasWidth;
+                    vjCanvas.height = vjCanvasHeight;
+                    halfWidth = vjCanvasWidth / 2;
+                    halfHeight = vjCanvasHeight / 2;
+                }, false);
+                vjCanvas = document.createElement("canvas");
+                vjCanvasWidth = window.innerWidth;
+                vjCanvasHeight = window.innerHeight;
+                vjCanvas.width = window.innerWidth;
+                vjCanvas.height = window.innerHeight;
+                vjCanvas.style.width = "100%";
+                vjCanvas.style.height = "100%";
+                vjCanvas.style.position = "absolute";
+                vjCanvas.style.backgroundColor = "transparent";
+                vjCanvas.style.top = "0px";
+                vjCanvas.style.left = "0px";
+                vjCanvas.style.zIndex = 5;
+                vjCanvas.style.msTouchAction = "none";
+                vjCanvasContext = vjCanvas.getContext('2d');
+                vjCanvasContext.strokeStyle = "#ffffff";
+                vjCanvasContext.lineWidth = 2;
+                document.body.appendChild(vjCanvas);
+            }
+            halfWidth = vjCanvas.width / 2;
+            halfHeight = vjCanvas.height / 2;
+            this.pressed = false;
+            // default joystick color
+            this._joystickColor = "cyan";
+
+            this.joystickPointerID = -1;
+            // current joystick position
+            this.joystickPointerPos = new BABYLON.Vector2(0, 0);
+            // origin joystick position
+            this.joystickPointerStartPos = new BABYLON.Vector2(0, 0);
+            this.deltaJoystickVector = new BABYLON.Vector2(0, 0);
+
+            vjCanvas.addEventListener('pointerdown', function (evt) {
+                that.onPointerDown(evt);
+            }, false);
+            vjCanvas.addEventListener('pointermove', function (evt) {
+                that.onPointerMove(evt);
+            }, false);
+            vjCanvas.addEventListener('pointerup', function (evt) {
+                that.onPointerUp(evt);
+            }, false);
+            vjCanvas.addEventListener('pointerout', function (evt) {
+                that.onPointerUp(evt);
+            }, false);
+            vjCanvas.addEventListener("contextmenu", function (e) {
+                e.preventDefault();    // Disables system menu
+            }, false);
+            requestAnimationFrame(function () {
+                that.drawVirtualJoystick();
+            });
+        }
+
+        VirtualJoystick.prototype.setJoystickSensibility = function (newJoystickSensibility) {
+            this._joystickSensibility = newJoystickSensibility;
+            this._inversedSensibility = 1 / (this._joystickSensibility / 1000);
+        };
+
+        VirtualJoystick.prototype.onPointerDown = function (e) {
+            e.preventDefault();
+            var newPointer = { identifier: e.pointerId, x: e.clientX, y: e.clientY, type: this.givePointerType(e) };
+            var positionOnScreenCondition;
+            if (this._leftJoystick === true) {
+                positionOnScreenCondition = (e.clientX < halfWidth);
+            }
+            else {
+                positionOnScreenCondition = (e.clientX > halfWidth);
+            }
+
+            if (positionOnScreenCondition && this.joystickPointerID < 0) {
+                // First contact will be dedicated to the virtual joystick
+                this.joystickPointerID = e.pointerId;
+                this.joystickPointerStartPos.x = e.clientX;
+                this.joystickPointerStartPos.y = e.clientY;
+                this.joystickPointerPos = this.joystickPointerStartPos.clone();
+                this.deltaJoystickVector.x = 0;
+                this.deltaJoystickVector.y = 0;
+                this.pressed = true;
+                this._touches.add(e.pointerId, newPointer);
+            }
+            else {
+                // You can only trigger the action buttons with a joystick declared
+                if (globalJoystickIndex < 2 && this._action) {
+                    this._action();
+                    this._touches.add(e.pointerId, newPointer);
+                }
+            }
+        };
+
+        VirtualJoystick.prototype.onPointerMove = function (e) {
+            // If the current pointer is the one associated to the joystick (first touch contact)
+            if (this.joystickPointerID == e.pointerId) {
+                this.joystickPointerPos.x = e.clientX;
+                this.joystickPointerPos.y = e.clientY;
+                this.deltaJoystickVector = this.joystickPointerPos.clone();
+                this.deltaJoystickVector = this.deltaJoystickVector.subtract(this.joystickPointerStartPos);
+
+                var directionLeftRight = this.reverseLeftRight ? -1 : 1;
+                var deltaJoystickX = directionLeftRight * this.deltaJoystickVector.x / this._inversedSensibility;
+                switch (this._axisTargetedByLeftAndRight) {
+                    case "X":
+                        this.deltaPosition.x = Math.min(1, Math.max(-1, deltaJoystickX));
+                        break;
+                    case "Y":
+                        this.deltaPosition.y = Math.min(1, Math.max(-1, deltaJoystickX));
+                        break;
+                    case "Z":
+                        this.deltaPosition.z = Math.min(1, Math.max(-1, deltaJoystickX));
+                        break;
+                }
+                var directionUpDown = this.reverseUpDown ? 1 : -1;
+                var deltaJoystickY = directionUpDown * this.deltaJoystickVector.y / this._inversedSensibility;
+                switch (this._axisTargetedByUpAndDown) {
+                    case "X":
+                        this.deltaPosition.x = Math.min(1, Math.max(-1, deltaJoystickY));
+                        break;
+                    case "Y":
+                        this.deltaPosition.y = Math.min(1, Math.max(-1, deltaJoystickY));
+                        break;
+                    case "Z":
+                        this.deltaPosition.z = Math.min(1, Math.max(-1, deltaJoystickY));
+                        break;
+                }
+            }
+            else {
+                if (this._touches.item(e.pointerId)) {
+                    this._touches.item(e.pointerId).x = e.clientX;
+                    this._touches.item(e.pointerId).y = e.clientY;
+                }
+            }
+        };
+
+        VirtualJoystick.prototype.onPointerUp = function (e) {
+            if (this.joystickPointerID == e.pointerId) {
+                this.joystickPointerID = -1;
+                this.pressed = false;
+            }
+            this.deltaJoystickVector.x = 0;
+            this.deltaJoystickVector.y = 0;
+
+            this._touches.remove(e.pointerId);
+        };
+
+        VirtualJoystick.prototype.setJoystickColor = function (newColor) {
+            this._joystickColor = newColor;
+        };
+
+        VirtualJoystick.prototype.setActionOnTouch = function (action) {
+            this._action = action;
+        };
+
+        // Define which axis you'd like to control for left & right 
+        VirtualJoystick.prototype.setAxisForLR = function (axisLetter) {
+            switch (axisLetter) {
+                case "X":
+                case "Y":
+                case "Z":
+                    this._axisTargetedByLeftAndRight = axisLetter;
+                    break;
+                default:
+                    this._axisTargetedByLeftAndRight = "X";
+                    break;
+            }
+        };
+
+        // Define which axis you'd like to control for up & down 
+        VirtualJoystick.prototype.setAxisForUD = function (axisLetter) {
+            switch (axisLetter) {
+                case "X":
+                case "Y":
+                case "Z":
+                    this._axisTargetedByUpAndDown = axisLetter;
+                    break;
+                default:
+                    this._axisTargetedByUpAndDown = "Y";
+                    break;
+            }
+        };
+
+        VirtualJoystick.prototype.drawVirtualJoystick = function () {
+            var that = this;
+
+            if (that._leftJoystick) {
+                vjCanvasContext.clearRect(0, 0, vjCanvasWidth / 2, vjCanvasHeight);
+            }
+            else {
+                vjCanvasContext.clearRect(vjCanvasWidth / 2, 0, vjCanvasWidth, vjCanvasHeight);
+            }
+            this._touches.forEach(function (touch) {
+                if (touch.identifier === that.joystickPointerID) {
+                    vjCanvasContext.beginPath();
+                    vjCanvasContext.strokeStyle = that._joystickColor;
+                    vjCanvasContext.lineWidth = 6;
+                    vjCanvasContext.arc(that.joystickPointerStartPos.x, that.joystickPointerStartPos.y, 40, 0, Math.PI * 2, true);
+                    vjCanvasContext.stroke();
+                    vjCanvasContext.beginPath();
+                    vjCanvasContext.strokeStyle = that._joystickColor;
+                    vjCanvasContext.lineWidth = 2;
+                    vjCanvasContext.arc(that.joystickPointerStartPos.x, that.joystickPointerStartPos.y, 60, 0, Math.PI * 2, true);
+                    vjCanvasContext.stroke();
+                    vjCanvasContext.beginPath();
+                    vjCanvasContext.strokeStyle = that._joystickColor;
+                    vjCanvasContext.arc(that.joystickPointerPos.x, that.joystickPointerPos.y, 40, 0, Math.PI * 2, true);
+                    vjCanvasContext.stroke();
+                }
+                else {
+                    vjCanvasContext.beginPath();
+                    vjCanvasContext.fillStyle = "white";
+                    vjCanvasContext.beginPath();
+                    vjCanvasContext.strokeStyle = "red";
+                    vjCanvasContext.lineWidth = "6";
+                    vjCanvasContext.arc(touch.x, touch.y, 40, 0, Math.PI * 2, true);
+                    vjCanvasContext.stroke();
+                };
+            });
+            requestAnimationFrame(function () {
+                that.drawVirtualJoystick();
+            });
+        };
+
+        VirtualJoystick.prototype.givePointerType = function (event) {
+            switch (event.pointerType) {
+                case event.POINTER_TYPE_MOUSE:
+                    return "MOUSE";
+                    break;
+                case event.POINTER_TYPE_PEN:
+                    return "PEN";
+                    break;
+                case event.POINTER_TYPE_TOUCH:
+                    return "TOUCH";
+                    break;
+            }
+        };
+
+        VirtualJoystick.prototype.releaseCanvas = function () {
+            if (vjCanvas) {
+                document.body.removeChild(vjCanvas);
+                vjCanvas = null;
+            };
+        };
+
+        return VirtualJoystick;
+    })();
+    BABYLON.VirtualJoystick = VirtualJoystick;
+
+    var Collection = (function () {
+        function Collection() {
+            this.count = 0;
+            this.collection = {};
+        };
+        Collection.prototype.add = function (key, item) {
+            if (this.collection[key] != undefined) {
+                return undefined;
+            }
+            this.collection[key] = item;
+            return ++this.count;
+        };
+        Collection.prototype.remove = function (key) {
+            if (this.collection[key] == undefined) {
+                return undefined;
+            }
+            delete this.collection[key];
+            return --this.count;
+        };
+        Collection.prototype.item = function (key) {
+            return this.collection[key];
+        };
+        Collection.prototype.forEach = function (block) {
+            var key;
+            for (key in this.collection) {
+                if (this.collection.hasOwnProperty(key)) {
+                    block(this.collection[key]);
+                }
+            }
+        };
+        return Collection;
+    })();
+    BABYLON.VirtualJoystick.Collection = Collection;
+})(BABYLON || (BABYLON = {}));

+ 83 - 45
Babylon/babylon.engine.js

@@ -3,12 +3,15 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.Engine = function (canvas, antialias) {
+    BABYLON.Engine = function (canvas, antialias, options) {
         this._renderingCanvas = canvas;
 
+        options = options || {};
+        options.antialias = antialias;
+
         // GL
         try {
-            this._gl = canvas.getContext("webgl", { antialias: antialias }) || canvas.getContext("experimental-webgl", { antialias: antialias });
+            this._gl = canvas.getContext("webgl", options) || canvas.getContext("experimental-webgl", options);
         } catch (e) {
             throw new Error("WebGL not supported");
         }
@@ -41,6 +44,7 @@ var BABYLON = BABYLON || {};
 
         // Extensions
         this._caps.standardDerivatives = (this._gl.getExtension('OES_standard_derivatives') !== null);
+        this._caps.s3tc = this._gl.getExtension('WEBGL_compressed_texture_s3tc');
         this._caps.textureFloat = (this._gl.getExtension('OES_texture_float') !== null);        
         this._caps.textureAnisotropicFilterExtension = this._gl.getExtension('EXT_texture_filter_anisotropic') || this._gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || this._gl.getExtension('MOZ_EXT_texture_filter_anisotropic');
         this._caps.maxAnisotropy = this._caps.textureAnisotropicFilterExtension ? this._gl.getParameter(this._caps.textureAnisotropicFilterExtension.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0;
@@ -454,6 +458,13 @@ var BABYLON = BABYLON || {};
 
         this._currentEffect = effect;
     };
+    
+    BABYLON.Engine.prototype.setArray = function (uniform, array) {
+        if (!uniform)
+            return;
+
+        this._gl.uniform1fv(uniform, array);
+    };
 
     BABYLON.Engine.prototype.setMatrices = function (uniform, matrices) {
         if (!uniform)
@@ -603,56 +614,80 @@ var BABYLON = BABYLON || {};
         return count;
     };
 
-    BABYLON.Engine.prototype.createTexture = function (url, noMipmap, invertY, scene) {
-        var texture = this._gl.createTexture();
-        var that = this;
-        
-        var onload = function (img) {
-            var potWidth = getExponantOfTwo(img.width, that._caps.maxTextureSize);
-            var potHeight = getExponantOfTwo(img.height, that._caps.maxTextureSize);
-            var isPot = (img.width == potWidth && img.height == potHeight);
 
-            if (!isPot) {
-                that._workingCanvas.width = potWidth;
-                that._workingCanvas.height = potHeight;
+    var prepareWebGLTexture = function (texture, scene, width, height, invertY, noMipmap, processFunction) {
+        var engine = scene.getEngine();
+        var potWidth = getExponantOfTwo(width, engine._caps.maxTextureSize);
+        var potHeight = getExponantOfTwo(height, engine._caps.maxTextureSize);
 
-                that._workingContext.drawImage(img, 0, 0, img.width, img.height, 0, 0, potWidth, potHeight);
-            };
-            
-            that._gl.bindTexture(that._gl.TEXTURE_2D, texture);
-            that._gl.pixelStorei(that._gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? true : invertY);
-            that._gl.texImage2D(that._gl.TEXTURE_2D, 0, that._gl.RGBA, that._gl.RGBA, that._gl.UNSIGNED_BYTE, isPot ? img : that._workingCanvas);
-            that._gl.texParameteri(that._gl.TEXTURE_2D, that._gl.TEXTURE_MAG_FILTER, that._gl.LINEAR);
+        engine._gl.bindTexture(engine._gl.TEXTURE_2D, texture);
+        engine._gl.pixelStorei(engine._gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? true : invertY);
 
-            if (noMipmap) {
-                that._gl.texParameteri(that._gl.TEXTURE_2D, that._gl.TEXTURE_MIN_FILTER, that._gl.LINEAR);
-            } else {
-                that._gl.texParameteri(that._gl.TEXTURE_2D, that._gl.TEXTURE_MIN_FILTER, that._gl.LINEAR_MIPMAP_LINEAR);
-                that._gl.generateMipmap(that._gl.TEXTURE_2D);
-            }
-            that._gl.bindTexture(that._gl.TEXTURE_2D, null);
+        processFunction(potWidth, potHeight);
 
-            that._activeTexturesCache = [];
-            texture._baseWidth = img.width;
-            texture._baseHeight = img.height;
-            texture._width = potWidth;
-            texture._height = potHeight;
-            texture.isReady = true;
-            scene._removePendingData(texture);
-        };
+        engine._gl.texParameteri(engine._gl.TEXTURE_2D, engine._gl.TEXTURE_MAG_FILTER, engine._gl.LINEAR);
 
-        var onerror = function () {
-            scene._removePendingData(texture);
-        };
+        if (noMipmap) {
+            engine._gl.texParameteri(engine._gl.TEXTURE_2D, engine._gl.TEXTURE_MIN_FILTER, engine._gl.LINEAR);
+        } else {
+            engine._gl.texParameteri(engine._gl.TEXTURE_2D, engine._gl.TEXTURE_MIN_FILTER, engine._gl.LINEAR_MIPMAP_LINEAR);
+            engine._gl.generateMipmap(engine._gl.TEXTURE_2D);
+        }
+        engine._gl.bindTexture(engine._gl.TEXTURE_2D, null);
 
-        scene._addPendingData(texture);
-        BABYLON.Tools.LoadImage(url, onload, onerror, scene.database);
+        engine._activeTexturesCache = [];
+        texture._baseWidth = width;
+        texture._baseHeight = height;
+        texture._width = potWidth;
+        texture._height = potHeight;
+        texture.isReady = true;
+        scene._removePendingData(texture);
+    };
 
+    BABYLON.Engine.prototype.createTexture = function (url, noMipmap, invertY, scene) {
+        var texture = this._gl.createTexture();
+        var that = this;
+        var isDDS = this.getCaps().s3tc && (url.substr(url.length - 4, 4).toLowerCase() === ".dds");
+
+        scene._addPendingData(texture);
         texture.url = url;
         texture.noMipmap = noMipmap;
         texture.references = 1;
         this._loadedTexturesCache.push(texture);
 
+        if (isDDS) {
+            BABYLON.Tools.LoadFile(url, function (data) {
+                var info = BABYLON.Tools.GetDDSInfo(data);
+
+                var loadMipmap = info.mipmapCount > 1 && !noMipmap;
+
+                prepareWebGLTexture(texture, scene, info.width, info.height, invertY, !loadMipmap, function (potWidth, potHeight) {
+                    BABYLON.Tools.UploadDDSLevels(that._gl, that.getCaps().s3tc, data, loadMipmap);
+                });
+            }, null, scene.database, true);
+        } else {
+            var onload = function(img) {
+                prepareWebGLTexture(texture, scene, img.width, img.height, invertY, noMipmap, function (potWidth, potHeight) {
+                    var isPot = (img.width == potWidth && img.height == potHeight);
+                    if (!isPot) {
+                        that._workingCanvas.width = potWidth;
+                        that._workingCanvas.height = potHeight;
+
+                        that._workingContext.drawImage(img, 0, 0, img.width, img.height, 0, 0, potWidth, potHeight);
+                    }
+
+                    that._gl.texImage2D(that._gl.TEXTURE_2D, 0, that._gl.RGBA, that._gl.RGBA, that._gl.UNSIGNED_BYTE, isPot ? img : that._workingCanvas);
+
+                });
+            };
+
+            var onerror = function() {
+                scene._removePendingData(texture);
+            };
+
+            BABYLON.Tools.LoadImage(url, onload, onerror, scene.database);
+        }
+
         return texture;
     };
 
@@ -698,9 +733,9 @@ var BABYLON = BABYLON || {};
         texture.isReady = true;
     };
 
-    BABYLON.Engine.prototype.updateVideoTexture = function (texture, video) {
+    BABYLON.Engine.prototype.updateVideoTexture = function (texture, video, invertY) {
         this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
-        this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, false);
+        this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, invertY ? false : true); // Video are upside down by default
 
         // Scale the video if it is a NPOT
         if (video.videoWidth !== texture._width || video.videoHeight !== texture._height) {
@@ -830,7 +865,7 @@ var BABYLON = BABYLON || {};
         scene._addPendingData(img);
     };
 
-    BABYLON.Engine.prototype.createCubeTexture = function (rootUrl, scene, extensions) {
+    BABYLON.Engine.prototype.createCubeTexture = function (rootUrl, scene, extensions, noMipmap) {
         var gl = this._gl;
 
         var texture = gl.createTexture();
@@ -860,9 +895,12 @@ var BABYLON = BABYLON || {};
                 gl.texImage2D(faces[index], 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, that._workingCanvas);
             }
 
-            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+            if (!noMipmap) {
+                gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+            }
+            
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
+            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, noMipmap ? gl.LINEAR : gl.LINEAR_MIPMAP_LINEAR);
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 

+ 29 - 6
Babylon/babylon.scene.js

@@ -326,13 +326,26 @@ var BABYLON = BABYLON || {};
     };
 
     // Methods
-    BABYLON.Scene.prototype.activeCameraByID = function (id) {
-        for (var index = 0; index < this.cameras.length; index++) {
-            if (this.cameras[index].id === id) {
-                this.activeCamera = this.cameras[index];
-                return;
-            }
+    BABYLON.Scene.prototype.setActiveCameraByID = function (id) {
+        var camera = this.getCameraByID(id);
+
+        if (camera) {
+            this.activeCamera = camera;
+            return camera;
         }
+
+        return null;
+    };
+
+    BABYLON.Scene.prototype.setActiveCameraByName = function (name) {
+        var camera = this.getCameraByName(name);
+
+        if (camera) {
+            this.activeCamera = camera;
+            return camera;
+        }
+
+        return null;
     };
 
     BABYLON.Scene.prototype.getMaterialByID = function (id) {
@@ -355,6 +368,16 @@ var BABYLON = BABYLON || {};
         return null;
     };
 
+    BABYLON.Scene.prototype.getCameraByID = function (id) {
+        for (var index = 0; index < this.cameras.length; index++) {
+            if (this.cameras[index].id === id) {
+                return this.cameras[index];
+            }
+        }
+
+        return null;
+    };
+
     BABYLON.Scene.prototype.getCameraByName = function (name) {
         for (var index = 0; index < this.cameras.length; index++) {
             if (this.cameras[index].name === name) {

+ 301 - 0
Exporters/Cheetah3d/Babylon file export.js

@@ -0,0 +1,301 @@
+var meshes = [];
+var cameras = [];
+var lights = [];
+var materials = [];
+
+var BabylonMesh = function(obj)
+{
+	var core = obj.core();
+	if(core == null)
+	{
+		this.notMesh = true;
+		return;
+	}
+    if(obj.materialTags() && obj.materialTags().length > 0)
+    {
+        var matId = obj.materialTags()[0].linkedToMaterial();
+        this.materialId = materials[matId].id;
+        if(materials[matId].diffuseTexture)
+        {        
+            var vec2 = obj.materialTags()[0].getParameter("UVOffset");
+            materials[matId].diffuseTexture.uOffset = vec2.x;
+            materials[matId].diffuseTexture.vOffset = vec2.y;
+            vec2 = obj.materialTags()[0].getParameter("UVScale");
+            materials[matId].diffuseTexture.uScale = vec2.x;
+            materials[matId].diffuseTexture.vScale = vec2.y;
+            var vec3 = obj.materialTags()[0].getParameter("shadingRotation");
+            materials[matId].diffuseTexture.uAng = vec3.x;
+            materials[matId].diffuseTexture.vAng = vec3.y;
+            materials[matId].diffuseTexture.wAng = vec3.z;
+        } 
+    } else
+        this.materialId = "";
+
+	this.name = obj.getParameter("name");
+    this.id = obj.getParameter("name");
+    var vec3 = obj.getParameter("position");
+    this.position = [-vec3.x, vec3.y, vec3.z];
+    vec3 = obj.getParameter("rotation");
+    this.rotation = [vec3.y* Math.PI/ 180, -vec3.x* Math.PI/ 180, -vec3.z* Math.PI/ 180];
+    vec3 = obj.getParameter("scale");
+    this.scaling = [vec3.x, vec3.y, vec3.z];
+    this.isVisible = true;
+    this.isEnabled = true;
+    this.checkCollisions = false;
+    this.billboardMode = 0;
+    this.receiveShadows = true;
+
+    this.positions = [];
+    this.indices = [];
+    this.uvs = [];
+    this.uvs2 = [];
+    this.normals = [];
+    var tmpnormals = [];
+    var tmpuv = [];
+
+    for (var v = 0; v < core.vertexCount(); v++) {
+    	var vertex = core.vertex(v);
+    	this.positions.push(vertex.x);
+    	this.positions.push(vertex.y);
+    	this.positions.push(vertex.z);
+    };
+
+    for (var p = 0; p < core.polygonCount(); p++) {
+    	for (var t = 0; t < core.polygonSize(p) - 2; t++) {
+    		var triangle = core.triangle(p,t);
+    		for (var i = 0; i < 3; i++) {
+    			this.indices.push(core.vertexIndex(p,triangle[i]));
+    			tmpnormals[core.vertexIndex(p,triangle[i])] = core.normal(p,triangle[i]);
+                // textcoord0 is [x,y], textcoord1 is [z,w]. Awesome doc work btw Cheetah3D
+                tmpuv[core.vertexIndex(p,triangle[i])] = core.uvCoord(p, triangle[i]);
+    		};
+    	};
+    };
+
+    for (var n = 0; n < tmpnormals.length; n++) {
+    	var normal = tmpnormals[n];
+    	if(normal == null) // sometimes normals get randomly nulled, wth cheetah3d
+    	{
+    		normal = {};
+    		normal.x = 0;
+    		normal.y = 0;
+    		normal.z = 0;
+    	}
+    	this.normals.push(normal.x);
+    	this.normals.push(normal.y);
+    	this.normals.push(normal.z);
+    };
+    for (var n = 0; n < tmpuv.length; n++) {
+        var uvCoords = tmpuv[n];
+        if(uvCoords == null) // sometimes normals get randomly nulled, wth cheetah3d
+        {
+            uvCoords = {};
+            uvCoords.x = 0;
+            uvCoords.y = 0;
+            uvCoords.z = 0;
+            uvCoords.w = 0;
+        }
+        this.uvs.push(1 - uvCoords.x);
+        this.uvs.push(1 - uvCoords.y);
+        this.uvs2.push(1- uvCoords.z);
+        this.uvs2.push(1 - uvCoords.w);
+    };
+    // no multiple submesh for now
+    this.subMeshes = [
+                {
+                    "materialIndex": 0,
+                    "verticesStart": 0,
+                    "verticesCount": core.vertexCount(),
+                    "indexStart": 0,
+                    "indexCount": core.triangleCount() * 3
+                }
+            ];
+}
+
+var BabylonCamera = function(cheetahCam)
+{
+    this.name=cheetahCam.getParameter("name");
+    this.id=cheetahCam.getParameter("name");
+    var vec3 = cheetahCam.getParameter("position");
+    this.position = [-vec3.x, vec3.y, vec3.z];
+    this.fov=cheetahCam.getParameter("fieldOfView") * Math.PI/ 180;
+    this.minZ=cheetahCam.getParameter("clipNear");
+    this.maxZ=cheetahCam.getParameter("clipFar");
+    // default values until we can find if cheetah3d has such data
+    this.target=[0,0,0];
+    this.speed=1;
+    this.inertia=0.9;
+    this.checkCollisions=false;
+    this.applyGravity=false;
+    this.ellipsoid=[
+        0.2,
+        0.9,
+        0.2
+    ];  
+}
+
+var BabylonLight = function(cheetahLight, type)
+{
+    this.name = cheetahLight.getParameter("name");
+    this.id = cheetahLight.getParameter("name");
+    this.type = type;
+    var vec3 = cheetahLight.getParameter("position");
+    this.position = [-vec3.x, vec3.y, vec3.z];
+
+    vec3 = cheetahLight.getParameter("rotation");
+    var angles = [vec3.y* Math.PI/ 180, -vec3.x* Math.PI/ 180, -vec3.z* Math.PI/ 180];
+    // shamefully copied from http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/
+    // using quaternion x vector multiplication from http://molecularmusings.wordpress.com/2013/05/24/a-faster-quaternion-vector-multiplication/
+    var c1 = Math.cos(angles[1]);
+    var s1 = Math.sin(angles[1]);
+    var c2 = Math.cos(angles[2]);
+    var s2 = Math.sin(angles[2]);
+    var c3 = Math.cos(angles[0]);
+    var s3 = Math.sin(angles[0]);
+    var w = Math.sqrt(1.0 + c1 * c2 + c1*c3 - s1 * s2 * s3 + c2*c3) / 2.0;
+    var w4 = (4.0 * w);
+    var x = (c2 * s3 + c1 * s3 + s1 * s2 * c3) / w4 ;
+    var y = (s1 * c2 + s1 * c3 + c1 * s2 * s3) / w4 ;
+    var z = (-s1 * s3 + c1 * s2 * c3 +s2) / w4 ;
+    var qv = new Vec3D(x,y,z);
+    var up = new Vec3D(0,1,0);
+    var t = qv.cross(up).multiply(2);
+    var vf = up.add(t.multiply(w).add(qv.cross(t)));
+    this.direction = [-vf.x,-vf.y,-vf.z];
+    this.intensity = cheetahLight.getParameter("intensity");
+    var color4 = cheetahLight.getParameter("color");
+    this.diffuse = [color4.x,color4.y,color4.z];
+    this.groundColor = [color4.x, color4.y, color4.z];
+    this.specular = [1,1,1];
+    if(type == 2)
+    {
+        this.angle = cheetahLight.getParameter("cutOffAngle")* Math.PI/ 180;
+        this.exponent = cheetahLight.getParameter("cutOffAttenuation");
+    }
+}
+
+var BabylonMaterial = function(material)
+{
+    this.name = material.getParameter("name");
+    this.id = material.getParameter("name");
+    this.ambient =[1,1,1]; // ambient does not exist in cheetah3d
+    var color4 = material.color();
+    this.diffuse = [color4.x, color4.y, color4.z];
+    color4 = material.specular();
+    this.specular = [color4.x, color4.y, color4.z];
+    this.specularPower = material.shininess();
+    color4 = material.emission();
+    this.emissive = [color4.x, color4.y, color4.z];
+    this.alpha = 1;
+    this.backFaceCulling = true;
+
+    // diffuse texture info available only... this is edgy
+    if(material.colorMap() != "none")
+    {
+        var name = material.colorMap().split("/");
+        this.diffuseTexture = {
+            name: name[name.length - 1],
+            level: 1,
+            hasAlpha: 0,
+            coordinatesMode: 0,
+            uOffset: 0,
+            vOffset: 0,
+            uScale: 1,
+            vScale: 1,
+            uAng: 0,
+            vAng: 0,
+            wAng: 0,
+            wrapU: true,
+            wrapV: true,
+            coordinatesIndex: 0
+        };}
+}
+
+function getChildren(obj, parentId)
+{
+	for (var i = 0; i < obj.childCount(); i++) {
+		var child = obj.childAtIndex(i);
+        switch(child.type())
+        {
+            case LIGHT:
+                switch(child.getParameter("lightType"))
+                {
+                    case 0:
+                        var light = new BabylonLight(child, 3);
+                        lights.push(light);
+                        break;
+                    case 2:
+                        var light = new BabylonLight(child, 1);
+                        lights.push(light);
+                        break;
+                    case 4:
+                        var light = new BabylonLight(child, 2);
+                        lights.push(light);
+                        break;
+                    default:
+                        var light = new BabylonLight(child, 0);
+                        lights.push(light);
+                        break;
+                }
+                break;
+            case CAMERA:
+                var camera = new BabylonCamera(child);
+                cameras.push(camera);
+                break;
+            default:
+                var mesh = new BabylonMesh(child);
+                if(parentId)
+                    mesh.parentId = parentId;
+                parentId = mesh.id;
+                if(!mesh.notMesh)
+                {
+                    meshes.push(mesh);
+                }
+                break;
+        }
+		if(child.childCount() > 0)
+			getChildren(child, parentId);
+	};
+}
+
+function main(doc){
+	var obj = doc.root();
+
+    for(var i = 0; i < doc.materialCount(); i++)
+    {
+        var mat = new BabylonMaterial(doc.materialAtIndex(i));
+        materials.push(mat);
+    }
+    getChildren(obj, 0);
+
+    var scene = {};
+	scene.autoClear=true;
+	scene.clearColor=[1,1,1];
+	scene.ambientColor=[0,0,0];
+	scene.gravity=[0,0,0];
+	scene.cameras=cameras;
+	scene.activeCamera_=cameras[0].id;
+	scene.lights=lights;
+	scene.materials = materials;
+	scene.meshes=meshes;
+	scene.multiMaterials=[];
+	scene.shadowGenerators=[];
+	scene.skeletons=[];
+
+    var path=OS.runSavePanel("babylon");
+    if(path==null){
+	return;
+	}
+    
+    //open file
+    var file = new File(path);
+    file.open(WRITE_MODE);
+    file.write(JSON.stringify(scene));
+    file.close();
+
+    print(materials.length + " materials");
+    print(meshes.length + " meshes");
+    print(cameras.length + " cameras");
+    print(lights.length + " lights");
+    print("\n\n");
+}

+ 39 - 0
Exporters/Cheetah3d/README.md

@@ -0,0 +1,39 @@
+Cheetah2Babylon
+===============
+
+[Cheetah 3D](http://www.cheetah3d.com/) exporter for [Babylon.JS](http://babylonjs.com) .babylon scene files. Currently supports the following :
+
+* mesh export with functional transform, naming and parenting
+* multicamera export (only perspective, no support for orthogonal right now)
+* light export with all babylon type managed :
+    * Cheetah3D spot light is a babylon spot (duh)
+    * Cheetah3D distant light is a babylon directional light
+    * Cheetah3D ambiant light is a babylon hemispheric light
+    * every other type is a babylon point light
+    * supports diffuse and specular color
+    * rotations must be on the -Y axis
+* materials export:
+    * supports diffuse, emissive and specular color (plus specular power as "shininess")
+    * supports only diffuse textures, Cheetah3D api is realy sparse on that
+
+More info on [my blog](http://cubeslam.net).
+
+Install
+-------
+
+Put js script in this folder :
+	
+	/Users/YOUR_USER/Library/Application Support/Cheetah3D/Scripts/Macro/
+
+Usage
+-----
+
+Just load your scene and go to Tools/Scripts/Macro/Babylon file export. Choose a destination, and load your scene inside Babylon.JS!
+
+License
+-------
+
+	DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+	TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+	0. You just DO WHAT THE FUCK YOU WANT TO.

+ 4 - 2
Tools/BuildOurOwnBabylonJS/BabylonJS/BabylonJS.csproj

@@ -15,20 +15,22 @@
     <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
     <UseIISExpress>false</UseIISExpress>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\</OutputPath>
     <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <PlatformTarget>x86</PlatformTarget>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\</OutputPath>
     <DefineConstants>TRACE</DefineConstants>
+    <PlatformTarget>x86</PlatformTarget>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>

+ 16 - 21
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS.sln

@@ -17,29 +17,24 @@ Global
 		Release|x86 = Release|x86
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|Any CPU.Build.0 = Release|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|Mixed Platforms.Build.0 = Release|Any CPU
-		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|x86.ActiveCfg = Release|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|Any CPU.Build.0 = Release|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
-		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|x86.ActiveCfg = Release|Any CPU
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|x86.ActiveCfg = Debug|x86
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Debug|x86.Build.0 = Debug|x86
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|Any CPU.ActiveCfg = Release|x86
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|x86.ActiveCfg = Release|x86
+		{0263AD0D-56E6-4439-BC05-6EC957200F52}.Release|x86.Build.0 = Release|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|x86.ActiveCfg = Debug|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Debug|x86.Build.0 = Debug|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|Any CPU.ActiveCfg = Release|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|x86.ActiveCfg = Release|x86
+		{93EF5B02-72EB-4B55-831E-E5051269EDA6}.Release|x86.Build.0 = Release|x86
 		{CFBE5149-1605-4824-8BD2-55C9B3C1DA60}.Debug|Any CPU.ActiveCfg = Debug|x86
 		{CFBE5149-1605-4824-8BD2-55C9B3C1DA60}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
-		{CFBE5149-1605-4824-8BD2-55C9B3C1DA60}.Debug|Mixed Platforms.Build.0 = Debug|x86
 		{CFBE5149-1605-4824-8BD2-55C9B3C1DA60}.Debug|x86.ActiveCfg = Debug|x86
 		{CFBE5149-1605-4824-8BD2-55C9B3C1DA60}.Debug|x86.Build.0 = Debug|x86
 		{CFBE5149-1605-4824-8BD2-55C9B3C1DA60}.Release|Any CPU.ActiveCfg = Release|x86

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

@@ -1,5 +1,13 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <files xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="babylonJS.xsd">
+  <script src="Babylon/Cameras/babylon.virtualJoysticksCamera.js"></script>
+  <script src="Babylon/Tools/babylon.virtualJoystick.js"></script>
+  <script src="Babylon/Cameras/babylon.oculusOrientedCamera.js"></script>
+  <script src="Babylon/PostProcess/babylon.oculusDistortionCorrectionPostProcess.js"></script>
+  <script src="Babylon/Cameras/Controllers/babylon.oculusController.js"></script>
+  <script src="Babylon/Cameras/Controllers/babylon.keyboardMoveController.js"></script>
+  <script src="Babylon/Cameras/Controllers/babylon.inputController.js"></script>
+  <script src="Babylon/Mesh/babylon.csg.js"></script>
   <script src="Babylon/Tools/babylon.sceneSerializer.js"></script>
   <script src="Babylon/Physics/babylon.physicsEngine.js"></script>
   <script src="Babylon/Tools/babylon.filesInput.js"></script>
@@ -7,6 +15,7 @@
   <script src="Babylon/LensFlare/babylon.lensFlareSystem.js"></script>
   <script src="Babylon/LensFlare/babylon.lensFlare.js"></script>
   <script src="Babylon/PostProcess/babylon.fxaaPostProcess.js"></script>
+  <script src="Babylon/PostProcess/babylon.filterPostProcess.js"></script>
   <script src="Babylon/PostProcess/babylon.convolutionPostProcess.js"></script>
   <script src="Babylon/PostProcess/babylon.blackAndWhitePostProcess.js"></script>
   <script src="Babylon/PostProcess/babylon.refractionPostProcess.js"></script>

+ 5 - 3
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/BuildOurOwnBabylonJSServer.csproj

@@ -16,20 +16,22 @@
     <MvcBuildViews>false</MvcBuildViews>
     <UseIISExpress>false</UseIISExpress>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\</OutputPath>
     <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <PlatformTarget>x86</PlatformTarget>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\</OutputPath>
     <DefineConstants>TRACE</DefineConstants>
+    <PlatformTarget>x86</PlatformTarget>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
@@ -64,6 +66,7 @@
   <ItemGroup>
     <Compile Include="Controllers\BabylonJSDemoController.cs" />
     <Compile Include="Controllers\OurDemoController.cs" />
+    <Compile Include="ViewModel\OurDemoViewModel.cs" />
     <Compile Include="WebViewPageExtensions.cs" />
     <Compile Include="Controllers\HomeController.cs" />
     <Compile Include="Controllers\BuildOurOwnBabylonJSController.cs" />
@@ -152,7 +155,6 @@
       <Private>True</Private>
     </ProjectReference>
   </ItemGroup>
-  <ItemGroup />
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 28 - 2
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/Controllers/OurDemoController.cs

@@ -3,14 +3,40 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 using System.Web.Mvc;
+using System.IO;
+using BuildOurOwnBabylonJSServer.ViewModels;
 
 namespace BuildOurOwnBabylonJSServer.Controllers
 {
     public class OurDemoController : Controller
     {
-        public ActionResult Show(string demo)
+        public ActionResult Show(string viewName, 
+            string folder = "")
         {
-            return View(demo);
+            var form = Request.Form;
+            var queryString = Request.QueryString;
+            var dictionary = new Dictionary<string, string>(form.Count + queryString.Count);
+
+            var keys = form.AllKeys;
+            
+            foreach(var k in keys)
+            {
+                if (k == "viewName" || k == "folder")
+                    continue;
+                dictionary.Add(k, form.GetValues(k).First());
+            }
+
+            keys = queryString.AllKeys;
+
+            foreach (var k in keys)
+            {
+                if (k == "viewName" || k == "folder")
+                    continue;
+                dictionary.Add(k, queryString.GetValues(k).First());
+            }
+
+            return View(Path.Combine(folder, viewName),
+                new OurDemoViewModel { Folder = folder, Dictionary = dictionary });
         }
     }
 }

+ 15 - 0
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/ViewModel/OurDemoViewModel.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Mvc;
+using System.IO;
+
+namespace BuildOurOwnBabylonJSServer.ViewModels
+{
+    public class OurDemoViewModel
+    {
+        public string Folder { get; set; }
+        public IDictionary<string, string> Dictionary { get; set; }
+    }
+}

+ 47 - 0
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/Views/OurDemo/sample.cshtml

@@ -0,0 +1,47 @@
+@model OurDemoViewModel
+@using BuildOurOwnBabylonJSServer.ViewModels
+@using System.Text.RegularExpressions
+
+@{
+    ViewBag.Title = "Our Own BabylonJS";
+    ViewBag.BabylonJSFolder = "..\\..\\..\\";
+
+    var myRegex = new Regex(@"[\\]", RegexOptions.Singleline);
+
+    Model.Folder = myRegex.Replace(Model.Folder, @"/");
+    Model.Folder = Model.Folder.Trim('/');
+
+    if (!String.IsNullOrEmpty(Model.Folder))
+    {
+        Model.Folder += "/";
+    }
+}
+
+<script type="text/javascript">
+    $(document).ready(function () {
+        BABYLON.SceneLoader.Load("/Content/@Model.Folder", "@Model.Dictionary["fileBJS"]" + ".babylon", OURBABYLON.engine, function (scene) {
+
+            scene.activeCamera = new BABYLON.ArcRotateCamera("defaultCamera", 0, 0, 100, BABYLON.Vector3.Zero(), scene);
+
+            scene.activeCamera.zoomOn();
+            scene.activeCamera.attachControl(OURBABYLON.canvas);
+
+            var material = new BABYLON.StandardMaterial("default", scene);
+            material.emissiveColor = new BABYLON.Color3(0.7, 0.7, 0.7);
+
+            for (var m in scene.meshes) {
+                scene.meshes[m].material = material;
+            }
+
+            // Render loop
+            var renderLoop = function () {
+                scene.render();
+            };
+
+            // Launch render loop
+            scene.getEngine().runRenderLoop(renderLoop);
+
+            OURBABYLON.currentScene = scene;
+        });
+    });
+</script>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 5 - 3
babylon.1.9.0.js


+ 4 - 0
readme.md

@@ -61,14 +61,18 @@ Online [sandbox](http://www.babylonjs.com/sandbox) where you can test your .baby
  - Render target textures
  - Dynamic textures (canvas)
  - Video textures
+ - Compressed (DDS) textures
 -  Cameras (Perspective and orthographic):
  - Arc rotate camera
  - Free camera
  - Touch camera
+ - Virtual Joysticks camera
+ - Oculus Rift camera
 -  Meshes: 
  - Mesh cloning
  - Dynamic meshes
  - Height maps
+ - Constructive solid geometries
 -  Import: 
  - Babylon scene file can be converted from .OBJ, .FBX, .MXB
  - Exporter for Blender