Prechádzať zdrojové kódy

Merge remote-tracking branch 'remotes/BabylonJS/master' into ourOwnBabylonJS

Gwenaël Hagenmuller 11 rokov pred
rodič
commit
3619f8cd4e

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

@@ -0,0 +1,85 @@
+"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.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.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 () {
+
+	};
+
+})();

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

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

@@ -0,0 +1,150 @@
+"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 = neutralOrientation || { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        this._currentViewMatrix = new BABYLON.Matrix();
+        this._currentOrientationMatrix = 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, 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 moveController = new BABYLON.keyboardMoveController(scene, multiTarget);
+        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);
+
+        BABYLON.Vector3.TransformCoordinatesToRef(this._referenceDirection, this._currentOrientationMatrix, this._actualDirection);
+        BABYLON.Vector3.TransformCoordinatesToRef(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._referenceOculusOrientation) {
+        //    this._referenceOculusOrientation = { yaw: this._controller._currentOrientation.yaw, pitch: this._controller._currentOrientation.pitch, roll: this._controller._currentOrientation.roll };
+        //}
+        //else {
+        //    this._currentOrientation.yaw = this._controller._currentOrientation.yaw - this._referenceOculusOrientation.yaw;
+        //    this._currentOrientation.pitch = this._controller._currentOrientation.pitch - this._referenceOculusOrientation.pitch;
+        //    this._currentOrientation.roll = this._controller._currentOrientation.roll - this._referenceOculusOrientation.roll;
+        //}
+        if (this.controllers) {
+            for (var i = 0; i < this.controllers.length; ++i) {
+                this.controllers[i].update();
+            }
+        }
+    };
+
+    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.TransformCoordinatesToRef(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();
+    };
+})();

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

+ 134 - 0
Babylon/Cameras/babylon.oculusCamera.js

@@ -0,0 +1,134 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.OculusController = function () {
+        this._currentOrientation = { yaw: 0, pitch: 0, roll: 0 };
+        this._deviceOrientationHandler = this.onOrientationEvent.bind(this);
+        window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+    };
+
+    BABYLON.OculusController.prototype.onOrientationEvent = function (ev) {
+        var yaw = ev.alpha / 180 * Math.PI;
+        if(!this._referenceYaw){
+            this._referenceYaw= yaw;
+        }
+        this._currentOrientation.yaw = yaw - this._referenceYaw;
+        this._currentOrientation.pitch = ev.beta / 180 * Math.PI;
+        this._currentOrientation.roll = ev.gamma / 180 * Math.PI;
+    };
+    BABYLON.OculusController.prototype.dispose = function () {
+        window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
+    };
+
+    BABYLON.OculusController.prototype.getCurrentOrientation = function () {
+        return this._currentOrientation;
+    };
+
+    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
+    };
+
+    BABYLON.OculusOrientedCamera = function (name, position, scene, controller, isLeftEye, ovrSettings, neutralOrientation) {
+        BABYLON.Camera.call(this, name, position, scene);
+        this._controller = controller;
+        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._currentOculusOrientation = { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        this._currentViewMatrix = new BABYLON.Matrix();
+        this._currentOculusOrientationMatrix = new BABYLON.Matrix();
+        this._tempMatrix = new BABYLON.Matrix();
+        neutralOrientation = neutralOrientation || { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        this._neutralOrientation = neutralOrientation;
+        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);
+    };
+    BABYLON.OculusOrientedCamera.buildOculusStereoCamera = function (scene, name, canvas, minZ, maxZ, position, neutralOrientation, useFXAA, controller, ovrSettings) {
+        position = position || new BABYLON.Vector2(0, 0);
+        neutralOrientation = neutralOrientation || { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        controller = controller || new BABYLON.OculusController();
+        ovrSettings = ovrSettings || BABYLON.OculusController.CameraSettings_OculusRiftDevKit2013_Metric;
+
+        var leftCamera = new BABYLON.OculusOrientedCamera(name + "_left", position, scene, controller, 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, controller, 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);
+    };
+    BABYLON.OculusOrientedCamera.prototype = Object.create(BABYLON.Camera.prototype);
+
+    BABYLON.OculusOrientedCamera.prototype.getViewMatrix = function () {
+
+        BABYLON.Matrix.RotationYawPitchRollToRef(
+            this._currentOculusOrientation.yaw + this._neutralOrientation.yaw,
+            this._currentOculusOrientation.pitch + this._neutralOrientation.pitch,
+            -this._currentOculusOrientation.roll + this._neutralOrientation.roll
+            , this._currentOculusOrientationMatrix);
+
+        BABYLON.Vector3.TransformCoordinatesToRef(this._referenceDirection, this._currentOculusOrientationMatrix, this._actualDirection);
+        BABYLON.Vector3.TransformCoordinatesToRef(this._referenceUp, this._currentOculusOrientationMatrix, 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._update = function () {
+        if (!this._referenceOculusOrientation) {
+            this._referenceOculusOrientation = { yaw: this._controller._currentOrientation.yaw, pitch: this._controller._currentOrientation.pitch, roll: this._controller._currentOrientation.roll };
+        }
+        else {
+            this._currentOculusOrientation.yaw = this._controller._currentOrientation.yaw - this._referenceOculusOrientation.yaw;
+            this._currentOculusOrientation.pitch = this._controller._currentOrientation.pitch - this._referenceOculusOrientation.pitch;
+            this._currentOculusOrientation.roll = this._controller._currentOrientation.roll - this._referenceOculusOrientation.roll;
+        }
+    };
+
+    BABYLON.OculusOrientedCamera.prototype.getProjectionMatrix = function (force) {
+        BABYLON.Matrix.PerspectiveFovLHToRef(this._aspectRatioFov, this._aspectRatioAspectRatio, this.minZ, this.maxZ, this._tempMatrix);
+        this._tempMatrix.multiplyToRef(this._hMatrix, this._projectionMatrix);
+        return this._projectionMatrix;
+    };
+})();

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

@@ -0,0 +1,198 @@
+"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
+    };
+
+    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 = neutralOrientation || { yaw: 0.0, pitch: 0.0, roll: 0.0 };
+        this._currentViewMatrix = new BABYLON.Matrix();
+        this._currentOrientationMatrix = 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, 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 moveController = new BABYLON.keyboardMoveController(scene, multiTarget);
+        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);
+
+        BABYLON.Vector3.TransformCoordinatesToRef(this._referenceDirection, this._currentOrientationMatrix, this._actualDirection);
+        BABYLON.Vector3.TransformCoordinatesToRef(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._referenceOculusOrientation) {
+        //    this._referenceOculusOrientation = { yaw: this._controller._currentOrientation.yaw, pitch: this._controller._currentOrientation.pitch, roll: this._controller._currentOrientation.roll };
+        //}
+        //else {
+        //    this._currentOrientation.yaw = this._controller._currentOrientation.yaw - this._referenceOculusOrientation.yaw;
+        //    this._currentOrientation.pitch = this._controller._currentOrientation.pitch - this._referenceOculusOrientation.pitch;
+        //    this._currentOrientation.roll = this._controller._currentOrientation.roll - this._referenceOculusOrientation.roll;
+        //}
+        if (this.controllers) {
+            for (var i = 0; i < this.controllers.length; ++i) {
+                this.controllers[i].update();
+            }
+        }
+    };
+
+    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.TransformCoordinatesToRef(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();
+    };
+})();

+ 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/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);

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

@@ -0,0 +1,595 @@
+"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 });
+                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));
+        },
+
+        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 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);
+            }
+        }
+    };
+
+})();

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

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

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

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

@@ -0,0 +1,340 @@
+/// <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 = 10;
+                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);
+            };
+        };
+
+        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 = {}));

+ 76 - 41
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);
-
-            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);
+        engine._gl.bindTexture(engine._gl.TEXTURE_2D, texture);
+        engine._gl.pixelStorei(engine._gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? true : invertY);
 
-            that._activeTexturesCache = [];
-            texture._baseWidth = img.width;
-            texture._baseHeight = img.height;
-            texture._width = potWidth;
-            texture._height = potHeight;
-            texture.isReady = true;
-            scene._removePendingData(texture);
-        };
+        processFunction(potWidth, potHeight);
 
-        var onerror = function () {
-            scene._removePendingData(texture);
-        };
+        engine._gl.texParameteri(engine._gl.TEXTURE_2D, engine._gl.TEXTURE_MAG_FILTER, engine._gl.LINEAR);
 
-        scene._addPendingData(texture);
-        BABYLON.Tools.LoadImage(url, onload, onerror, scene.database);
+        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);
 
+        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;
     };
 

+ 8 - 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/Controllers/babylon.inputController.js"></script>
+  <script src="Babylon/PostProcess/babylon.oculusDistortionCorrectionPostProcess.js"></script>
+  <script src="Babylon/Tools/babylon.virtualJoystick.js"></script>
+  <script src="Babylon/Cameras/Controllers/babylon.oculusController.js"></script>
+  <script src="Babylon/Cameras/babylon.oculusOrientedCamera.js"></script>
+  <script src="Babylon/Cameras/babylon.virtualJoysticksCamera.js"></script>
+  <script src="Babylon/Cameras/Controllers/babylon.keyboardMoveController.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>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 2
babylon.1.9.0.js