소스 검색

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

olivier.g 10 년 전
부모
커밋
70db5a4f84
100개의 변경된 파일3189개의 추가작업 그리고 1729개의 파일을 삭제
  1. 8 0
      .travis.yml
  2. 27 1
      Babylon/Actions/babylon.actionManager.js
  3. 24 0
      Babylon/Actions/babylon.actionManager.ts
  4. 1 1
      Babylon/Actions/babylon.condition.js
  5. 1 1
      Babylon/Actions/babylon.directActions.js
  6. 1 1
      Babylon/Actions/babylon.directActions.ts
  7. 2 3
      Babylon/Actions/babylon.interpolateValueAction.js
  8. 17 0
      Babylon/Animations/babylon.animation.js
  9. 1 1
      Babylon/Animations/babylon.easing.js
  10. 1 0
      Babylon/Audio/babylon.analyser.js
  11. 1 1
      Babylon/Audio/babylon.analyser.ts
  12. 33 22
      Babylon/Audio/babylon.audioEngine.js
  13. 32 23
      Babylon/Audio/babylon.audioEngine.ts
  14. 16 13
      Babylon/Audio/babylon.sound.js
  15. 14 5
      Babylon/Audio/babylon.sound.ts
  16. 9 9
      Babylon/Audio/babylon.soundtrack.js
  17. 17 16
      Babylon/Audio/babylon.soundtrack.ts
  18. 2 2
      Babylon/Bones/babylon.skeleton.js
  19. 3 3
      Babylon/Bones/babylon.skeleton.ts
  20. 0 115
      Babylon/Cameras/VR/babylon.oculusCamera.js
  21. 0 142
      Babylon/Cameras/VR/babylon.oculusCamera.ts
  22. 0 144
      Babylon/Cameras/VR/babylon.oculusGamepadCamera.js
  23. 0 175
      Babylon/Cameras/VR/babylon.oculusGamepadCamera.ts
  24. 21 8
      Babylon/Cameras/VR/babylon.vrDeviceOrientationCamera.js
  25. 35 14
      Babylon/Cameras/VR/babylon.vrDeviceOrientationCamera.ts
  26. 17 12
      Babylon/Cameras/VR/babylon.webVRCamera.js
  27. 11 6
      Babylon/Cameras/VR/babylon.webVRCamera.ts
  28. 17 62
      Babylon/Cameras/babylon.anaglyphCamera.js
  29. 0 106
      Babylon/Cameras/babylon.anaglyphCamera.ts
  30. 139 41
      Babylon/Cameras/babylon.arcRotateCamera.js
  31. 134 48
      Babylon/Cameras/babylon.arcRotateCamera.ts
  32. 261 20
      Babylon/Cameras/babylon.camera.js
  33. 253 21
      Babylon/Cameras/babylon.camera.ts
  34. 2 1
      Babylon/Cameras/babylon.deviceOrientationCamera.js
  35. 5 3
      Babylon/Cameras/babylon.deviceOrientationCamera.ts
  36. 13 4
      Babylon/Cameras/babylon.followCamera.js
  37. 12 4
      Babylon/Cameras/babylon.followCamera.ts
  38. 35 20
      Babylon/Cameras/babylon.freeCamera.js
  39. 39 28
      Babylon/Cameras/babylon.freeCamera.ts
  40. 19 22
      Babylon/Cameras/babylon.gamepadCamera.js
  41. 24 24
      Babylon/Cameras/babylon.gamepadCamera.ts
  42. 0 175
      Babylon/Cameras/babylon.oculusGamepadCamera.js
  43. 64 0
      Babylon/Cameras/babylon.stereoscopicCameras.js
  44. 44 0
      Babylon/Cameras/babylon.stereoscopicCameras.ts
  45. 71 3
      Babylon/Cameras/babylon.targetCamera.js
  46. 84 1
      Babylon/Cameras/babylon.targetCamera.ts
  47. 2 1
      Babylon/Cameras/babylon.touchCamera.js
  48. 7 5
      Babylon/Cameras/babylon.touchCamera.ts
  49. 6 5
      Babylon/Cameras/babylon.virtualJoysticksCamera.js
  50. 12 10
      Babylon/Cameras/babylon.virtualJoysticksCamera.ts
  51. 0 80
      Babylon/Cameras/babylon.webVRCamera.js
  52. 11 11
      Babylon/Collisions/babylon.collider.js
  53. 50 50
      Babylon/Collisions/babylon.collider.ts
  54. 268 0
      Babylon/Collisions/babylon.collisionCoordinator.js
  55. 411 0
      Babylon/Collisions/babylon.collisionCoordinator.ts
  56. 230 0
      Babylon/Collisions/babylon.collisionWorker.js
  57. 274 0
      Babylon/Collisions/babylon.collisionWorker.ts
  58. 1 0
      Babylon/Culling/Octrees/babylon.octree.js
  59. 3 3
      Babylon/Culling/Octrees/babylon.octree.ts
  60. 2 2
      Babylon/Culling/Octrees/babylon.octreeBlock.ts
  61. 1 1
      Babylon/Culling/babylon.BoundingBox.ts
  62. 2 1
      Babylon/Culling/babylon.boundingBox.js
  63. 13 13
      Babylon/Culling/babylon.boundingInfo.ts
  64. 6 6
      Babylon/Culling/babylon.boundingSphere.ts
  65. 69 88
      Babylon/Debug/babylon.debugLayer.js
  66. 0 1
      Babylon/Debug/babylon.debugLayer.js.map
  67. 1 1
      Babylon/Debug/babylon.debugLayer.ts
  68. 4 4
      Babylon/Layer/babylon.layer.ts
  69. 2 2
      Babylon/LensFlare/babylon.lensFlare.ts
  70. 1 0
      Babylon/LensFlare/babylon.lensFlareSystem.js
  71. 6 6
      Babylon/LensFlare/babylon.lensFlareSystem.ts
  72. 3 1
      Babylon/Lights/Shadows/babylon.shadowGenerator.js
  73. 2 1
      Babylon/Lights/babylon.directionalLight.js
  74. 1 1
      Babylon/Lights/babylon.hemisphericLight.js
  75. 4 4
      Babylon/Lights/babylon.hemisphericLight.ts
  76. 7 2
      Babylon/Lights/babylon.light.js
  77. 11 3
      Babylon/Lights/babylon.light.ts
  78. 1 1
      Babylon/Lights/babylon.pointLight.js
  79. 1 1
      Babylon/Lights/babylon.spotLight.js
  80. 80 28
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  81. 71 20
      Babylon/Loading/Plugins/babylon.babylonFileLoader.ts
  82. 9 0
      Babylon/Loading/babylon.sceneLoader.js
  83. 11 2
      Babylon/Loading/babylon.sceneLoader.ts
  84. 1 1
      Babylon/Materials/Textures/Procedurals/babylon.customProceduralTexture.js
  85. 9 1
      Babylon/Materials/Textures/Procedurals/babylon.proceduralTexture.js
  86. 1 14
      Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.js
  87. 0 11
      Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.ts
  88. 1 1
      Babylon/Materials/Textures/babylon.cubeTexture.js
  89. 1 1
      Babylon/Materials/Textures/babylon.dynamicTexture.js
  90. 2 2
      Babylon/Materials/Textures/babylon.mirrorTexture.js
  91. 5 5
      Babylon/Materials/Textures/babylon.mirrorTexture.ts
  92. 1 1
      Babylon/Materials/Textures/babylon.rawTexture.js
  93. 2 2
      Babylon/Materials/Textures/babylon.renderTargetTexture.js
  94. 1 1
      Babylon/Materials/Textures/babylon.renderTargetTexture.ts
  95. 20 3
      Babylon/Materials/Textures/babylon.texture.js
  96. 6 0
      Babylon/Materials/Textures/babylon.texture.ts
  97. 15 13
      Babylon/Materials/Textures/babylon.videoTexture.js
  98. 12 15
      Babylon/Materials/Textures/babylon.videoTexture.ts
  99. 19 3
      Babylon/Materials/babylon.effect.js
  100. 0 0
      Babylon/Materials/babylon.effect.ts

+ 8 - 0
.travis.yml

@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+  - "0.10"
+before_script:
+  - npm install -g gulp
+  - cd ./Tools/Gulp
+  - npm install
+script: gulp typescript

+ 27 - 1
Babylon/Actions/babylon.actionManager.js

@@ -134,6 +134,13 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(ActionManager, "OnPickUpTrigger", {
+            get: function () {
+                return ActionManager._OnPickUpTrigger;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         ActionManager.prototype.dispose = function () {
             var index = this._scene._actionManagers.indexOf(this);
@@ -158,6 +165,20 @@ var BABYLON;
             }
             return false;
         };
+        /**
+         * Does this action manager handles actions of a given trigger
+         * @param {number} trigger - the trigger to be tested
+         * @return {boolean} whether the trigger is handeled
+         */
+        ActionManager.prototype.hasSpecificTrigger = function (trigger) {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+                if (action.trigger === trigger) {
+                    return true;
+                }
+            }
+            return false;
+        };
         Object.defineProperty(ActionManager.prototype, "hasPointerTriggers", {
             /**
              * Does this action manager has pointer triggers
@@ -169,6 +190,9 @@ var BABYLON;
                     if (action.trigger >= ActionManager._OnPickTrigger && action.trigger <= ActionManager._OnPointerOutTrigger) {
                         return true;
                     }
+                    if (action.trigger == ActionManager._OnPickUpTrigger) {
+                        return true;
+                    }
                 }
                 return false;
             },
@@ -218,7 +242,8 @@ var BABYLON;
             for (var index = 0; index < this.actions.length; index++) {
                 var action = this.actions[index];
                 if (action.trigger === trigger) {
-                    if (trigger === ActionManager.OnKeyUpTrigger || trigger === ActionManager.OnKeyDownTrigger) {
+                    if (trigger === ActionManager.OnKeyUpTrigger
+                        || trigger === ActionManager.OnKeyDownTrigger) {
                         var parameter = action.getTriggerParameter();
                         if (parameter) {
                             var unicode = evt.sourceEvent.charCode ? evt.sourceEvent.charCode : evt.sourceEvent.keyCode;
@@ -256,6 +281,7 @@ var BABYLON;
         ActionManager._OnIntersectionExitTrigger = 9;
         ActionManager._OnKeyDownTrigger = 10;
         ActionManager._OnKeyUpTrigger = 11;
+        ActionManager._OnPickUpTrigger = 12;
         return ActionManager;
     })();
     BABYLON.ActionManager = ActionManager;

+ 24 - 0
Babylon/Actions/babylon.actionManager.ts

@@ -54,6 +54,7 @@
         private static _OnIntersectionExitTrigger = 9;
         private static _OnKeyDownTrigger = 10;
         private static _OnKeyUpTrigger = 11;
+        private static _OnPickUpTrigger = 12;
 
         public static get NothingTrigger(): number {
             return ActionManager._NothingTrigger;
@@ -102,6 +103,9 @@
         public static get OnKeyUpTrigger(): number {
             return ActionManager._OnKeyUpTrigger;
         }
+        public static get OnPickUpTrigger(): number {
+            return ActionManager._OnPickUpTrigger;
+        }
         // Members
         public actions = new Array<Action>();
 
@@ -144,6 +148,23 @@
         }
 
         /**
+         * Does this action manager handles actions of a given trigger
+         * @param {number} trigger - the trigger to be tested
+         * @return {boolean} whether the trigger is handeled 
+         */
+        public hasSpecificTrigger(trigger: number): boolean {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+
+                if (action.trigger === trigger) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /**
          * Does this action manager has pointer triggers
          * @return {boolean} whether or not it has pointer triggers
          */
@@ -154,6 +175,9 @@
                 if (action.trigger >= ActionManager._OnPickTrigger && action.trigger <= ActionManager._OnPointerOutTrigger) {
                     return true;
                 }
+                if (action.trigger == ActionManager._OnPickUpTrigger) {
+                    return true;
+                }
             }
 
             return false;

+ 1 - 1
Babylon/Actions/babylon.condition.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 1 - 1
Babylon/Actions/babylon.directActions.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 1 - 1
Babylon/Actions/babylon.directActions.ts

@@ -166,7 +166,7 @@
             var invertParentWorldMatrix = this._parent.getWorldMatrix().clone();
             invertParentWorldMatrix.invert();
 
-            this._target.position = BABYLON.Vector3.TransformCoordinates(this._target.position, invertParentWorldMatrix);
+            this._target.position = Vector3.TransformCoordinates(this._target.position, invertParentWorldMatrix);
 
             this._target.parent = this._parent;
         }

+ 2 - 3
Babylon/Actions/babylon.interpolateValueAction.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -27,8 +27,7 @@ var BABYLON;
                 {
                     frame: 0,
                     value: this._target[this._property]
-                },
-                {
+                }, {
                     frame: 100,
                     value: this.value
                 }

+ 17 - 0
Babylon/Animations/babylon.animation.js

@@ -124,6 +124,7 @@ var BABYLON;
                         gradient = this._easingFunction.ease(gradient);
                     }
                     switch (this.dataType) {
+                        // Float
                         case Animation.ANIMATIONTYPE_FLOAT:
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
@@ -133,6 +134,7 @@ var BABYLON;
                                     return offsetValue * repeatCount + this.floatInterpolateFunction(startValue, endValue, gradient);
                             }
                             break;
+                        // Quaternion
                         case Animation.ANIMATIONTYPE_QUATERNION:
                             var quaternion = null;
                             switch (loopMode) {
@@ -145,6 +147,7 @@ var BABYLON;
                                     break;
                             }
                             return quaternion;
+                        // Vector3
                         case Animation.ANIMATIONTYPE_VECTOR3:
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
@@ -153,6 +156,7 @@ var BABYLON;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                     return this.vector3InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
                             }
+                        // Vector2
                         case Animation.ANIMATIONTYPE_VECTOR2:
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
@@ -161,6 +165,7 @@ var BABYLON;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                     return this.vector2InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
                             }
+                        // Color3
                         case Animation.ANIMATIONTYPE_COLOR3:
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
@@ -169,10 +174,12 @@ var BABYLON;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                     return this.color3InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
                             }
+                        // Matrix
                         case Animation.ANIMATIONTYPE_MATRIX:
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
+                                // return this.matrixInterpolateFunction(startValue, endValue, gradient);
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                     return startValue;
                             }
@@ -220,16 +227,21 @@ var BABYLON;
                         var fromValue = this._interpolate(from, 0, Animation.ANIMATIONLOOPMODE_CYCLE);
                         var toValue = this._interpolate(to, 0, Animation.ANIMATIONLOOPMODE_CYCLE);
                         switch (this.dataType) {
+                            // Float
                             case Animation.ANIMATIONTYPE_FLOAT:
                                 this._offsetsCache[keyOffset] = toValue - fromValue;
                                 break;
+                            // Quaternion
                             case Animation.ANIMATIONTYPE_QUATERNION:
                                 this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
                                 break;
+                            // Vector3
                             case Animation.ANIMATIONTYPE_VECTOR3:
                                 this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
+                            // Vector2
                             case Animation.ANIMATIONTYPE_VECTOR2:
                                 this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
+                            // Color3
                             case Animation.ANIMATIONTYPE_COLOR3:
                                 this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
                             default:
@@ -243,18 +255,23 @@ var BABYLON;
             }
             if (offsetValue === undefined) {
                 switch (this.dataType) {
+                    // Float
                     case Animation.ANIMATIONTYPE_FLOAT:
                         offsetValue = 0;
                         break;
+                    // Quaternion
                     case Animation.ANIMATIONTYPE_QUATERNION:
                         offsetValue = new BABYLON.Quaternion(0, 0, 0, 0);
                         break;
+                    // Vector3
                     case Animation.ANIMATIONTYPE_VECTOR3:
                         offsetValue = BABYLON.Vector3.Zero();
                         break;
+                    // Vector2
                     case Animation.ANIMATIONTYPE_VECTOR2:
                         offsetValue = BABYLON.Vector2.Zero();
                         break;
+                    // Color3
                     case Animation.ANIMATIONTYPE_COLOR3:
                         offsetValue = BABYLON.Color3.Black();
                 }

+ 1 - 1
Babylon/Animations/babylon.easing.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 1 - 0
Babylon/Audio/babylon.analyser.js

@@ -71,6 +71,7 @@ var BABYLON;
                     var workingArray = this.getByteFrequencyData();
                     this._debugCanvasContext.fillStyle = 'rgb(0, 0, 0)';
                     this._debugCanvasContext.fillRect(0, 0, this.DEBUGCANVASSIZE.width, this.DEBUGCANVASSIZE.height);
+                    // Draw the frequency domain chart.
                     for (var i = 0; i < this.getFrequencyBinCount(); i++) {
                         var value = workingArray[i];
                         var percent = value / this.BARGRAPHAMPLITUDE;

+ 1 - 1
Babylon/Audio/babylon.analyser.ts

@@ -16,7 +16,7 @@ module BABYLON {
         private _registerFunc;
         private _audioEngine: AudioEngine;
 
-        constructor(scene: BABYLON.Scene) {
+        constructor(scene: Scene) {
             this._scene = scene;
             this._audioEngine = Engine.audioEngine;
             if (this._audioEngine.canUseWebAudio) {

+ 33 - 22
Babylon/Audio/babylon.audioEngine.js

@@ -2,37 +2,48 @@ var BABYLON;
 (function (BABYLON) {
     var AudioEngine = (function () {
         function AudioEngine() {
-            this.audioContext = null;
+            this._audioContext = null;
+            this._audioContextInitialized = false;
             this.canUseWebAudio = false;
             this.WarnedWebAudioUnsupported = false;
-            try {
-                if (typeof AudioContext !== 'undefined') {
-                    this.audioContext = new AudioContext();
-                    this.canUseWebAudio = true;
+            if (typeof AudioContext !== 'undefined' || typeof webkitAudioContext !== 'undefined') {
+                window.AudioContext = window.AudioContext || window.webkitAudioContext;
+                this.canUseWebAudio = true;
+            }
+        }
+        Object.defineProperty(AudioEngine.prototype, "audioContext", {
+            get: function () {
+                if (!this._audioContextInitialized) {
+                    this._initializeAudioContext();
                 }
-                else if (typeof webkitAudioContext !== 'undefined') {
-                    this.audioContext = new webkitAudioContext();
-                    this.canUseWebAudio = true;
+                return this._audioContext;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        AudioEngine.prototype._initializeAudioContext = function () {
+            try {
+                if (this.canUseWebAudio) {
+                    this._audioContext = new AudioContext();
+                    // create a global volume gain node 
+                    this.masterGain = this._audioContext.createGain();
+                    this.masterGain.gain.value = 1;
+                    this.masterGain.connect(this._audioContext.destination);
+                    this._audioContextInitialized = true;
                 }
             }
             catch (e) {
                 this.canUseWebAudio = false;
                 BABYLON.Tools.Error("Web Audio: " + e.message);
             }
-            // create a global volume gain node 
-            if (this.canUseWebAudio) {
-                this.masterGain = this.audioContext.createGain();
-                this.masterGain.gain.value = 1;
-                this.masterGain.connect(this.audioContext.destination);
-            }
-        }
+        };
         AudioEngine.prototype.dispose = function () {
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
                 if (this._connectedAnalyser) {
                     this._connectedAnalyser.stopDebugCanvas();
                     this._connectedAnalyser.dispose();
                     this.masterGain.disconnect();
-                    this.masterGain.connect(this.audioContext.destination);
+                    this.masterGain.connect(this._audioContext.destination);
                     this._connectedAnalyser = null;
                 }
                 this.masterGain.gain.value = 1;
@@ -40,7 +51,7 @@ var BABYLON;
             this.WarnedWebAudioUnsupported = false;
         };
         AudioEngine.prototype.getGlobalVolume = function () {
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
                 return this.masterGain.gain.value;
             }
             else {
@@ -48,7 +59,7 @@ var BABYLON;
             }
         };
         AudioEngine.prototype.setGlobalVolume = function (newVolume) {
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
                 this.masterGain.gain.value = newVolume;
             }
         };
@@ -56,10 +67,10 @@ var BABYLON;
             if (this._connectedAnalyser) {
                 this._connectedAnalyser.stopDebugCanvas();
             }
-            this._connectedAnalyser = analyser;
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                this._connectedAnalyser = analyser;
                 this.masterGain.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this.masterGain, this.audioContext.destination);
+                this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);
             }
         };
         return AudioEngine;

+ 32 - 23
Babylon/Audio/babylon.audioEngine.ts

@@ -1,42 +1,51 @@
 module BABYLON {
     export class AudioEngine {
-        public audioContext: AudioContext = null;
+        private _audioContext: AudioContext = null;
+        private _audioContextInitialized = false;
         public canUseWebAudio: boolean = false;
         public masterGain: GainNode;
 
         private _connectedAnalyser: Analyser;
         public WarnedWebAudioUnsupported: boolean = false;
 
+        public get audioContext(): AudioContext {
+            if (!this._audioContextInitialized) {
+                this._initializeAudioContext();
+            }
+            return this._audioContext;
+        }
+
         constructor() {
-            // creating the audio context 
+            if (typeof AudioContext !== 'undefined' || typeof webkitAudioContext !== 'undefined') {
+                window.AudioContext = window.AudioContext || window.webkitAudioContext;
+                this.canUseWebAudio = true;
+            }
+        }
+
+        private _initializeAudioContext() {
             try {
-                if (typeof AudioContext !== 'undefined') {
-                    this.audioContext = new AudioContext();
-                    this.canUseWebAudio = true;
-                } else if (typeof webkitAudioContext !== 'undefined') {
-                    this.audioContext = new webkitAudioContext();
-                    this.canUseWebAudio = true;
+                if (this.canUseWebAudio) {
+                    this._audioContext = new AudioContext();
+                    // create a global volume gain node 
+                    this.masterGain = this._audioContext.createGain();
+                    this.masterGain.gain.value = 1;
+                    this.masterGain.connect(this._audioContext.destination);
+                    this._audioContextInitialized = true;
                 }
-            } catch (e) {
+            }
+            catch (e) {
                 this.canUseWebAudio = false;
                 Tools.Error("Web Audio: " + e.message);
             }
-
-            // create a global volume gain node 
-            if (this.canUseWebAudio) {
-                this.masterGain = this.audioContext.createGain();
-                this.masterGain.gain.value = 1;
-                this.masterGain.connect(this.audioContext.destination);
-            }
         }
 
         public dispose() {
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
                 if (this._connectedAnalyser) {
                     this._connectedAnalyser.stopDebugCanvas();
                     this._connectedAnalyser.dispose();
                     this.masterGain.disconnect();
-                    this.masterGain.connect(this.audioContext.destination);
+                    this.masterGain.connect(this._audioContext.destination);
                     this._connectedAnalyser = null;
                 }
                 this.masterGain.gain.value = 1;
@@ -45,7 +54,7 @@
         }
 
         public getGlobalVolume(): number {
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
                 return this.masterGain.gain.value;
             }
             else {
@@ -54,7 +63,7 @@
         }
 
         public setGlobalVolume(newVolume: number) {
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
                 this.masterGain.gain.value = newVolume;
             }
         }
@@ -63,10 +72,10 @@
             if (this._connectedAnalyser) {
                 this._connectedAnalyser.stopDebugCanvas();
             }
-            this._connectedAnalyser = analyser;
-            if (this.canUseWebAudio) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                this._connectedAnalyser = analyser;
                 this.masterGain.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this.masterGain, this.audioContext.destination);
+                this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);
             }
         }
     }

+ 16 - 13
Babylon/Audio/babylon.sound.js

@@ -75,9 +75,7 @@ var BABYLON;
                 if (urlOrArrayBuffer) {
                     // If it's an URL
                     if (typeof (urlOrArrayBuffer) === "string") {
-                        BABYLON.Tools.LoadFile(urlOrArrayBuffer, function (data) {
-                            _this._soundLoaded(data);
-                        }, null, null, true);
+                        BABYLON.Tools.LoadFile(urlOrArrayBuffer, function (data) { _this._soundLoaded(data); }, null, null, true);
                     }
                     else {
                         if (urlOrArrayBuffer instanceof ArrayBuffer) {
@@ -147,9 +145,7 @@ var BABYLON;
                 if (_this._readyToPlayCallback) {
                     _this._readyToPlayCallback();
                 }
-            }, function (error) {
-                BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
-            });
+            }, function (error) { BABYLON.Tools.Error("Error while decoding audio data: " + error.err); });
         };
         Sound.prototype.setAudioBuffer = function (audioBuffer) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
@@ -166,6 +162,10 @@ var BABYLON;
                 this.refDistance = options.refDistance || this.refDistance;
                 this.distanceModel = options.distanceModel || this.distanceModel;
                 this._playbackRate = options.playbackRate || this._playbackRate;
+                this._updateSpatialParameters();
+                if (this.isPlaying) {
+                    this._soundSource.playbackRate.value = this._playbackRate;
+                }
             }
         };
         Sound.prototype._createSpatialParameters = function () {
@@ -174,6 +174,13 @@ var BABYLON;
                     this._panningModel = "HRTF";
                 }
                 this._soundPanner = BABYLON.Engine.audioEngine.audioContext.createPanner();
+                this._updateSpatialParameters();
+                this._soundPanner.connect(this._ouputAudioNode);
+                this._inputAudioNode = this._soundPanner;
+            }
+        };
+        Sound.prototype._updateSpatialParameters = function () {
+            if (this.spatialSound) {
                 if (this.useCustomAttenuation) {
                     // Tricks to disable in a way embedded Web Audio attenuation 
                     this._soundPanner.distanceModel = "linear";
@@ -189,8 +196,6 @@ var BABYLON;
                     this._soundPanner.rolloffFactor = this.rolloffFactor;
                     this._soundPanner.panningModel = this._panningModel;
                 }
-                this._soundPanner.connect(this._ouputAudioNode);
-                this._inputAudioNode = this._soundPanner;
             }
         };
         Sound.prototype.switchPanningModelToHRTF = function () {
@@ -290,9 +295,7 @@ var BABYLON;
                     this._soundSource.loop = this.loop;
                     this._soundSource.playbackRate.value = this._playbackRate;
                     this._startTime = startTime;
-                    this._soundSource.onended = function () {
-                        _this._onended();
-                    };
+                    this._soundSource.onended = function () { _this._onended(); };
                     this._soundSource.start(this._startTime, this.isPaused ? this._startOffset % this._soundSource.buffer.duration : 0);
                     this.isPlaying = true;
                     this.isPaused = false;
@@ -327,7 +330,7 @@ var BABYLON;
             }
         };
         Sound.prototype.setVolume = function (newVolume, time) {
-            if (BABYLON.Engine.audioEngine.canUseWebAudio && !this.spatialSound) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (time) {
                     this._soundGain.gain.linearRampToValueAtTime(this._volume, BABYLON.Engine.audioEngine.audioContext.currentTime);
                     this._soundGain.gain.linearRampToValueAtTime(newVolume, time);
@@ -351,8 +354,8 @@ var BABYLON;
             var _this = this;
             this._connectedMesh = meshToConnectTo;
             if (!this.spatialSound) {
-                this._createSpatialParameters();
                 this.spatialSound = true;
+                this._createSpatialParameters();
                 if (this.isPlaying && this.loop) {
                     this.stop();
                     this.play();

+ 14 - 5
Babylon/Audio/babylon.sound.ts

@@ -105,7 +105,7 @@
                 // Adding an empty sound to avoid breaking audio calls for non Web Audio browsers
                 this._scene.mainSoundTrack.AddSound(this);
                 if (!Engine.audioEngine.WarnedWebAudioUnsupported) {
-                    BABYLON.Tools.Error("Web Audio is not supported by your browser.");
+                    Tools.Error("Web Audio is not supported by your browser.");
                     Engine.audioEngine.WarnedWebAudioUnsupported = true;
                 }
                 // Simulating a ready to play event to avoid breaking code for non web audio browsers
@@ -176,6 +176,10 @@
                 this.refDistance = options.refDistance || this.refDistance;
                 this.distanceModel = options.distanceModel || this.distanceModel;
                 this._playbackRate = options.playbackRate || this._playbackRate;
+                this._updateSpatialParameters();
+                if (this.isPlaying) {
+                    this._soundSource.playbackRate.value = this._playbackRate;
+                }
             }
         }
 
@@ -185,7 +189,14 @@
                     this._panningModel = "HRTF";
                 }
                 this._soundPanner = Engine.audioEngine.audioContext.createPanner();
+                this._updateSpatialParameters();
+                this._soundPanner.connect(this._ouputAudioNode);
+                this._inputAudioNode = this._soundPanner;
+            }
+        }
 
+        private _updateSpatialParameters() {
+            if (this.spatialSound) {
                 if (this.useCustomAttenuation) {
                     // Tricks to disable in a way embedded Web Audio attenuation 
                     this._soundPanner.distanceModel = "linear";
@@ -201,8 +212,6 @@
                     this._soundPanner.rolloffFactor = this.rolloffFactor;
                     this._soundPanner.panningModel = this._panningModel;
                 }
-                this._soundPanner.connect(this._ouputAudioNode);
-                this._inputAudioNode = this._soundPanner;
             }
         }
 
@@ -354,7 +363,7 @@
         }
 
         public setVolume(newVolume: number, time?: number) {
-            if (Engine.audioEngine.canUseWebAudio && !this.spatialSound) {
+            if (Engine.audioEngine.canUseWebAudio) {
                 if (time) {
                     this._soundGain.gain.linearRampToValueAtTime(this._volume, Engine.audioEngine.audioContext.currentTime);
                     this._soundGain.gain.linearRampToValueAtTime(newVolume, time);
@@ -380,8 +389,8 @@
         public attachToMesh(meshToConnectTo: AbstractMesh) {
             this._connectedMesh = meshToConnectTo;
             if (!this.spatialSound) {
-                this._createSpatialParameters();
                 this.spatialSound = true;
+                this._createSpatialParameters();
                 if (this.isPlaying && this.loop) {
                     this.stop();
                     this.play();

+ 9 - 9
Babylon/Audio/babylon.soundtrack.js

@@ -8,11 +8,11 @@ var BABYLON;
             this._audioEngine = BABYLON.Engine.audioEngine;
             this.soundCollection = new Array();
             if (this._audioEngine.canUseWebAudio) {
-                this._trackGain = this._audioEngine.audioContext.createGain();
-                this._trackGain.connect(this._audioEngine.masterGain);
+                this._outputAudioNode = this._audioEngine.audioContext.createGain();
+                this._outputAudioNode.connect(this._audioEngine.masterGain);
                 if (options) {
                     if (options.volume) {
-                        this._trackGain.gain.value = options.volume;
+                        this._outputAudioNode.gain.value = options.volume;
                     }
                     if (options.mainTrack) {
                         this._isMainTrack = options.mainTrack;
@@ -32,13 +32,13 @@ var BABYLON;
                 while (this.soundCollection.length) {
                     this.soundCollection[0].dispose();
                 }
-                this._trackGain.disconnect();
-                this._trackGain = null;
+                this._outputAudioNode.disconnect();
+                this._outputAudioNode = null;
             }
         };
         SoundTrack.prototype.AddSound = function (sound) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
-                sound.connectToSoundTrackAudioNode(this._trackGain);
+                sound.connectToSoundTrackAudioNode(this._outputAudioNode);
             }
             if (sound.soundTrackId) {
                 if (sound.soundTrackId === -1) {
@@ -59,7 +59,7 @@ var BABYLON;
         };
         SoundTrack.prototype.setVolume = function (newVolume) {
             if (this._audioEngine.canUseWebAudio) {
-                this._trackGain.gain.value = newVolume;
+                this._outputAudioNode.gain.value = newVolume;
             }
         };
         SoundTrack.prototype.switchPanningModelToHRTF = function () {
@@ -82,8 +82,8 @@ var BABYLON;
             }
             this._connectedAnalyser = analyser;
             if (this._audioEngine.canUseWebAudio) {
-                this._trackGain.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this._trackGain, this._audioEngine.masterGain);
+                this._outputAudioNode.disconnect();
+                this._connectedAnalyser.connectAudioNodes(this._outputAudioNode, this._audioEngine.masterGain);
             }
         };
         return SoundTrack;

+ 17 - 16
Babylon/Audio/babylon.soundtrack.ts

@@ -1,24 +1,25 @@
 module BABYLON {
     export class SoundTrack {
-        private _audioEngine: BABYLON.AudioEngine;
-        private _trackGain: GainNode;
+        private _audioEngine: AudioEngine;
+        private _outputAudioNode: GainNode;
+        private _inputAudioNode: AudioNode;
         private _trackConvolver: ConvolverNode;
-        private _scene: BABYLON.Scene;
+        private _scene: Scene;
         public id: number = -1;
-        public soundCollection: Array<BABYLON.Sound>;
+        public soundCollection: Array<Sound>;
         private _isMainTrack: boolean = false;
         private _connectedAnalyser: Analyser;
 
-        constructor(scene: BABYLON.Scene, options?: any) {
+        constructor(scene: Scene, options?: any) {
             this._scene = scene;
             this._audioEngine = Engine.audioEngine;
             this.soundCollection = new Array();
             if (this._audioEngine.canUseWebAudio) {
-                this._trackGain = this._audioEngine.audioContext.createGain();
-                this._trackGain.connect(this._audioEngine.masterGain);
+                this._outputAudioNode = this._audioEngine.audioContext.createGain();
+                this._outputAudioNode.connect(this._audioEngine.masterGain);
 
                 if (options) {
-                    if (options.volume) { this._trackGain.gain.value = options.volume; }
+                    if (options.volume) { this._outputAudioNode.gain.value = options.volume; }
                     if (options.mainTrack) { this._isMainTrack = options.mainTrack; }
                 }
             }
@@ -36,14 +37,14 @@
                 while (this.soundCollection.length) {
                     this.soundCollection[0].dispose();
                 }
-                this._trackGain.disconnect();
-                this._trackGain = null;
+                this._outputAudioNode.disconnect();
+                this._outputAudioNode = null;
             }
         }
 
-        public AddSound(sound: BABYLON.Sound) {
+        public AddSound(sound: Sound) {
             if (Engine.audioEngine.canUseWebAudio) {
-                sound.connectToSoundTrackAudioNode(this._trackGain);
+                sound.connectToSoundTrackAudioNode(this._outputAudioNode);
             }
             if (sound.soundTrackId) {
                 if (sound.soundTrackId === -1) {
@@ -58,7 +59,7 @@
             sound.soundTrackId = this.id;
         }
 
-        public RemoveSound(sound: BABYLON.Sound) {
+        public RemoveSound(sound: Sound) {
             var index = this.soundCollection.indexOf(sound);
             if (index !== -1) {
                 this.soundCollection.splice(index, 1);
@@ -67,7 +68,7 @@
 
         public setVolume(newVolume: number) {
             if (this._audioEngine.canUseWebAudio) {
-                this._trackGain.gain.value = newVolume;
+                this._outputAudioNode.gain.value = newVolume;
             }
         }
 
@@ -93,8 +94,8 @@
             }
             this._connectedAnalyser = analyser;
             if (this._audioEngine.canUseWebAudio) {
-                this._trackGain.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this._trackGain, this._audioEngine.masterGain);
+                this._outputAudioNode.disconnect();
+                this._connectedAnalyser.connectAudioNodes(this._outputAudioNode, this._audioEngine.masterGain);
             }
         }
     }

+ 2 - 2
Babylon/Bones/babylon.skeleton.js

@@ -10,7 +10,7 @@ var BABYLON;
             this.bones = [];
             this._scene = scene;
             scene.skeletons.push(this);
-            this.prepare():
+            this.prepare();
             //make sure it will recalculate the matrix next time prepare is called.
             this._isDirty = true;
         }
@@ -71,4 +71,4 @@ var BABYLON;
     })();
     BABYLON.Skeleton = Skeleton;
 })(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.skeleton.js.map
+//# sourceMappingURL=babylon.skeleton.js.map

+ 3 - 3
Babylon/Bones/babylon.skeleton.ts

@@ -14,10 +14,10 @@
             this._scene = scene;
 
             scene.skeletons.push(this);
-            
+
             this.prepare();
             //make sure it will recalculate the matrix next time prepare is called.
-            this._isDirty = true; 
+            this._isDirty = true;
         }
 
         // Members
@@ -90,4 +90,4 @@
             return result;
         }
     }
-}
+}

+ 0 - 115
Babylon/Cameras/VR/babylon.oculusCamera.js

@@ -1,115 +0,0 @@
-var __extends = this.__extends || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    __.prototype = b.prototype;
-    d.prototype = new __();
-};
-var BABYLON;
-(function (BABYLON) {
-    var 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
-    };
-    var _OculusInnerCamera = (function (_super) {
-        __extends(_OculusInnerCamera, _super);
-        function _OculusInnerCamera(name, position, scene, isLeftEye) {
-            _super.call(this, name, position, scene);
-            this._workMatrix = new BABYLON.Matrix();
-            this._actualUp = new BABYLON.Vector3(0, 0, 0);
-            // Constants
-            this._aspectRatioAspectRatio = OculusRiftDevKit2013_Metric.HResolution / (2 * OculusRiftDevKit2013_Metric.VResolution);
-            this._aspectRatioFov = (2 * Math.atan((OculusRiftDevKit2013_Metric.PostProcessScaleFactor * OculusRiftDevKit2013_Metric.VScreenSize) / (2 * OculusRiftDevKit2013_Metric.EyeToScreenDistance)));
-            var hMeters = (OculusRiftDevKit2013_Metric.HScreenSize / 4) - (OculusRiftDevKit2013_Metric.LensSeparationDistance / 2);
-            var h = (4 * hMeters) / OculusRiftDevKit2013_Metric.HScreenSize;
-            this._hMatrix = BABYLON.Matrix.Translation(isLeftEye ? h : -h, 0, 0);
-            this.viewport = new BABYLON.Viewport(isLeftEye ? 0 : 0.5, 0, 0.5, 1.0);
-            this._preViewMatrix = BABYLON.Matrix.Translation(isLeftEye ? .5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance : -.5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance, 0, 0);
-            // Postprocess
-            var postProcess = new BABYLON.OculusDistortionCorrectionPostProcess("Oculus Distortion", this, !isLeftEye, OculusRiftDevKit2013_Metric);
-        }
-        _OculusInnerCamera.prototype.getProjectionMatrix = function () {
-            BABYLON.Matrix.PerspectiveFovLHToRef(this._aspectRatioFov, this._aspectRatioAspectRatio, this.minZ, this.maxZ, this._workMatrix);
-            this._workMatrix.multiplyToRef(this._hMatrix, this._projectionMatrix);
-            return this._projectionMatrix;
-        };
-        _OculusInnerCamera.prototype._getViewMatrix = function () {
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            BABYLON.Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._actualUp);
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._actualUp, this._workMatrix);
-            this._workMatrix.multiplyToRef(this._preViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        };
-        return _OculusInnerCamera;
-    })(BABYLON.FreeCamera);
-    var OculusCamera = (function (_super) {
-        __extends(OculusCamera, _super);
-        function OculusCamera(name, position, scene) {
-            _super.call(this, name, position, scene);
-            this._leftCamera = new _OculusInnerCamera(name + "_left", position.clone(), scene, true);
-            this._rightCamera = new _OculusInnerCamera(name + "_right", position.clone(), scene, false);
-            this.subCameras.push(this._leftCamera);
-            this.subCameras.push(this._rightCamera);
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
-        }
-        OculusCamera.prototype._update = function () {
-            this._leftCamera.position.copyFrom(this.position);
-            this._rightCamera.position.copyFrom(this.position);
-            this._updateCamera(this._leftCamera);
-            this._updateCamera(this._rightCamera);
-            _super.prototype._update.call(this);
-        };
-        OculusCamera.prototype._updateCamera = function (camera) {
-            camera.minZ = this.minZ;
-            camera.maxZ = this.maxZ;
-            camera.rotation.x = this.rotation.x;
-            camera.rotation.y = this.rotation.y;
-            camera.rotation.z = this.rotation.z;
-        };
-        // Oculus events
-        OculusCamera.prototype._onOrientationEvent = function (evt) {
-            var yaw = evt.alpha / 180 * Math.PI;
-            var pitch = evt.beta / 180 * Math.PI;
-            var roll = evt.gamma / 180 * Math.PI;
-            if (!this._offsetOrientation) {
-                this._offsetOrientation = {
-                    yaw: yaw,
-                    pitch: pitch,
-                    roll: roll
-                };
-                return;
-            }
-            else {
-                this.rotation.y += yaw - this._offsetOrientation.yaw;
-                this.rotation.x += pitch - this._offsetOrientation.pitch;
-                this.rotation.z += this._offsetOrientation.roll - roll;
-                this._offsetOrientation.yaw = yaw;
-                this._offsetOrientation.pitch = pitch;
-                this._offsetOrientation.roll = roll;
-            }
-        };
-        OculusCamera.prototype.attachControl = function (element, noPreventDefault) {
-            _super.prototype.attachControl.call(this, element, noPreventDefault);
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
-        OculusCamera.prototype.detachControl = function (element) {
-            _super.prototype.detachControl.call(this, element);
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
-        return OculusCamera;
-    })(BABYLON.FreeCamera);
-    BABYLON.OculusCamera = OculusCamera;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.oculusCamera.js.map

+ 0 - 142
Babylon/Cameras/VR/babylon.oculusCamera.ts

@@ -1,142 +0,0 @@
-module BABYLON {
-
-    var 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
-    };
-
-    class _OculusInnerCamera extends FreeCamera {
-        private _aspectRatioAspectRatio: number;
-        private _aspectRatioFov: number;
-        private _hMatrix: Matrix;
-        private _workMatrix = new BABYLON.Matrix();
-        private _preViewMatrix: Matrix;
-        private _actualUp = new BABYLON.Vector3(0, 0, 0);
-
-        constructor(name: string, position: Vector3, scene: Scene, isLeftEye: boolean) {
-            super(name, position, scene);
-
-            // Constants
-            this._aspectRatioAspectRatio = OculusRiftDevKit2013_Metric.HResolution / (2 * OculusRiftDevKit2013_Metric.VResolution);
-            this._aspectRatioFov = (2 * Math.atan((OculusRiftDevKit2013_Metric.PostProcessScaleFactor * OculusRiftDevKit2013_Metric.VScreenSize) / (2 * OculusRiftDevKit2013_Metric.EyeToScreenDistance)));
-
-            var hMeters = (OculusRiftDevKit2013_Metric.HScreenSize / 4) - (OculusRiftDevKit2013_Metric.LensSeparationDistance / 2);
-            var h = (4 * hMeters) / OculusRiftDevKit2013_Metric.HScreenSize;
-
-            this._hMatrix = BABYLON.Matrix.Translation(isLeftEye ? h : -h, 0, 0);
-
-            this.viewport = new BABYLON.Viewport(isLeftEye ? 0 : 0.5, 0, 0.5, 1.0);
-
-            this._preViewMatrix = BABYLON.Matrix.Translation(isLeftEye ? .5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance : -.5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance, 0, 0);
-
-            // Postprocess
-            var postProcess = new BABYLON.OculusDistortionCorrectionPostProcess("Oculus Distortion", this, !isLeftEye, OculusRiftDevKit2013_Metric);
-        }
-
-        public getProjectionMatrix(): Matrix {
-            BABYLON.Matrix.PerspectiveFovLHToRef(this._aspectRatioFov, this._aspectRatioAspectRatio, this.minZ, this.maxZ, this._workMatrix);
-            this._workMatrix.multiplyToRef(this._hMatrix, this._projectionMatrix);
-            return this._projectionMatrix;
-        }
-
-        public _getViewMatrix(): Matrix {
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-
-            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            BABYLON.Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._actualUp);
-
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._actualUp, this._workMatrix);
-
-            this._workMatrix.multiplyToRef(this._preViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        }
-    }
-
-    export class OculusCamera extends FreeCamera {
-        private _leftCamera: _OculusInnerCamera;
-        private _rightCamera: _OculusInnerCamera;
-        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
-        private _deviceOrientationHandler;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-
-            this._leftCamera = new _OculusInnerCamera(name + "_left", position.clone(), scene, true);
-            this._rightCamera = new _OculusInnerCamera(name + "_right", position.clone(), scene, false);
-
-            this.subCameras.push(this._leftCamera);
-            this.subCameras.push(this._rightCamera);
-
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
-        }
-
-        public _update(): void {
-            this._leftCamera.position.copyFrom(this.position);
-            this._rightCamera.position.copyFrom(this.position);
-
-            this._updateCamera(this._leftCamera);
-            this._updateCamera(this._rightCamera);
-
-            super._update();
-        }
-
-        public _updateCamera(camera: FreeCamera): void {
-            camera.minZ = this.minZ;
-            camera.maxZ = this.maxZ;
-
-            camera.rotation.x = this.rotation.x;
-            camera.rotation.y = this.rotation.y;
-            camera.rotation.z = this.rotation.z;
-        }
-
-        // Oculus events
-        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
-            var yaw = evt.alpha / 180 * Math.PI;
-            var pitch = evt.beta / 180 * Math.PI;
-            var roll = evt.gamma / 180 * Math.PI;
-
-            if (!this._offsetOrientation) {
-                this._offsetOrientation = {
-                    yaw: yaw,
-                    pitch: pitch,
-                    roll: roll
-                };
-                return;
-            }
-            else {
-                this.rotation.y += yaw - this._offsetOrientation.yaw;
-                this.rotation.x += pitch - this._offsetOrientation.pitch;
-                this.rotation.z += this._offsetOrientation.roll - roll;
-
-                this._offsetOrientation.yaw = yaw;
-                this._offsetOrientation.pitch = pitch;
-                this._offsetOrientation.roll = roll;
-            }
-        }
-
-        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            super.attachControl(element, noPreventDefault);
-
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-
-        public detachControl(element: HTMLElement): void {
-            super.detachControl(element);
-
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-    }
-} 

+ 0 - 144
Babylon/Cameras/VR/babylon.oculusGamepadCamera.js

@@ -1,144 +0,0 @@
-var __extends = this.__extends || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    __.prototype = b.prototype;
-    d.prototype = new __();
-};
-var BABYLON;
-(function (BABYLON) {
-    var 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
-    };
-    var _OculusInnerGamepadCamera = (function (_super) {
-        __extends(_OculusInnerGamepadCamera, _super);
-        function _OculusInnerGamepadCamera(name, position, scene, isLeftEye) {
-            _super.call(this, name, position, scene);
-            this._workMatrix = new BABYLON.Matrix();
-            this._actualUp = new BABYLON.Vector3(0, 0, 0);
-            // Constants
-            this._aspectRatioAspectRatio = OculusRiftDevKit2013_Metric.HResolution / (2 * OculusRiftDevKit2013_Metric.VResolution);
-            this._aspectRatioFov = (2 * Math.atan((OculusRiftDevKit2013_Metric.PostProcessScaleFactor * OculusRiftDevKit2013_Metric.VScreenSize) / (2 * OculusRiftDevKit2013_Metric.EyeToScreenDistance)));
-            var hMeters = (OculusRiftDevKit2013_Metric.HScreenSize / 4) - (OculusRiftDevKit2013_Metric.LensSeparationDistance / 2);
-            var h = (4 * hMeters) / OculusRiftDevKit2013_Metric.HScreenSize;
-            this._hMatrix = BABYLON.Matrix.Translation(isLeftEye ? h : -h, 0, 0);
-            this.viewport = new BABYLON.Viewport(isLeftEye ? 0 : 0.5, 0, 0.5, 1.0);
-            this._preViewMatrix = BABYLON.Matrix.Translation(isLeftEye ? .5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance : -.5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance, 0, 0);
-            // Postprocess
-            var postProcess = new BABYLON.OculusDistortionCorrectionPostProcess("Oculus Distortion", this, !isLeftEye, OculusRiftDevKit2013_Metric);
-        }
-        _OculusInnerGamepadCamera.prototype.getProjectionMatrix = function () {
-            BABYLON.Matrix.PerspectiveFovLHToRef(this._aspectRatioFov, this._aspectRatioAspectRatio, this.minZ, this.maxZ, this._workMatrix);
-            this._workMatrix.multiplyToRef(this._hMatrix, this._projectionMatrix);
-            return this._projectionMatrix;
-        };
-        _OculusInnerGamepadCamera.prototype._getViewMatrix = function () {
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            BABYLON.Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._actualUp);
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._actualUp, this._workMatrix);
-            this._workMatrix.multiplyToRef(this._preViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        };
-        return _OculusInnerGamepadCamera;
-    })(BABYLON.FreeCamera);
-    var OculusGamepadCamera = (function (_super) {
-        __extends(OculusGamepadCamera, _super);
-        function OculusGamepadCamera(name, position, scene) {
-            var _this = this;
-            _super.call(this, name, position, scene);
-            this.angularSensibility = 200;
-            this.moveSensibility = 75;
-            this._leftCamera = new _OculusInnerGamepadCamera(name + "_left", position.clone(), scene, true);
-            this._rightCamera = new _OculusInnerGamepadCamera(name + "_right", position.clone(), scene, false);
-            this.subCameras.push(this._leftCamera);
-            this.subCameras.push(this._rightCamera);
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
-            this._gamepads = new BABYLON.Gamepads(function (gamepad) {
-                _this._onNewGameConnected(gamepad);
-            });
-        }
-        OculusGamepadCamera.prototype._onNewGameConnected = function (gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this._gamepad = gamepad;
-            }
-        };
-        OculusGamepadCamera.prototype._update = function () {
-            this._leftCamera.position.copyFrom(this.position);
-            this._rightCamera.position.copyFrom(this.position);
-            this._updateCamera(this._leftCamera);
-            this._updateCamera(this._rightCamera);
-            _super.prototype._update.call(this);
-        };
-        OculusGamepadCamera.prototype._checkInputs = function () {
-            if (!this._gamepad) {
-                return;
-            }
-            var LSValues = this._gamepad.leftStick;
-            var normalizedLX = LSValues.x / this.moveSensibility;
-            var normalizedLY = LSValues.y / this.moveSensibility;
-            LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-            LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x, 0, -LSValues.y), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-        };
-        OculusGamepadCamera.prototype._updateCamera = function (camera) {
-            camera.minZ = this.minZ;
-            camera.maxZ = this.maxZ;
-            camera.rotation.x = this.rotation.x;
-            camera.rotation.y = this.rotation.y;
-            camera.rotation.z = this.rotation.z;
-        };
-        // Oculus events
-        OculusGamepadCamera.prototype._onOrientationEvent = function (evt) {
-            var yaw = evt.alpha / 180 * Math.PI;
-            var pitch = evt.beta / 180 * Math.PI;
-            var roll = evt.gamma / 180 * Math.PI;
-            if (!this._offsetOrientation) {
-                this._offsetOrientation = {
-                    yaw: yaw,
-                    pitch: pitch,
-                    roll: roll
-                };
-                return;
-            }
-            else {
-                this.rotation.y += yaw - this._offsetOrientation.yaw;
-                this.rotation.x += pitch - this._offsetOrientation.pitch;
-                this.rotation.z += this._offsetOrientation.roll - roll;
-                this._offsetOrientation.yaw = yaw;
-                this._offsetOrientation.pitch = pitch;
-                this._offsetOrientation.roll = roll;
-            }
-        };
-        OculusGamepadCamera.prototype.attachControl = function (element, noPreventDefault) {
-            _super.prototype.attachControl.call(this, element, noPreventDefault);
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
-        OculusGamepadCamera.prototype.detachControl = function (element) {
-            _super.prototype.detachControl.call(this, element);
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
-        OculusGamepadCamera.prototype.dispose = function () {
-            this._gamepads.dispose();
-            _super.prototype.dispose.call(this);
-        };
-        return OculusGamepadCamera;
-    })(BABYLON.FreeCamera);
-    BABYLON.OculusGamepadCamera = OculusGamepadCamera;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.oculusGamepadCamera.js.map

+ 0 - 175
Babylon/Cameras/VR/babylon.oculusGamepadCamera.ts

@@ -1,175 +0,0 @@
-module BABYLON {
-
-    var 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
-    };
-
-    class _OculusInnerGamepadCamera extends FreeCamera {
-        private _aspectRatioAspectRatio: number;
-        private _aspectRatioFov: number;
-        private _hMatrix: Matrix;
-        private _workMatrix = new BABYLON.Matrix();
-        private _preViewMatrix: Matrix;
-        private _actualUp = new BABYLON.Vector3(0, 0, 0);
-
-        constructor(name: string, position: Vector3, scene: Scene, isLeftEye: boolean) {
-            super(name, position, scene);
-
-            // Constants
-            this._aspectRatioAspectRatio = OculusRiftDevKit2013_Metric.HResolution / (2 * OculusRiftDevKit2013_Metric.VResolution);
-            this._aspectRatioFov = (2 * Math.atan((OculusRiftDevKit2013_Metric.PostProcessScaleFactor * OculusRiftDevKit2013_Metric.VScreenSize) / (2 * OculusRiftDevKit2013_Metric.EyeToScreenDistance)));
-
-            var hMeters = (OculusRiftDevKit2013_Metric.HScreenSize / 4) - (OculusRiftDevKit2013_Metric.LensSeparationDistance / 2);
-            var h = (4 * hMeters) / OculusRiftDevKit2013_Metric.HScreenSize;
-
-            this._hMatrix = BABYLON.Matrix.Translation(isLeftEye ? h : -h, 0, 0);
-
-            this.viewport = new BABYLON.Viewport(isLeftEye ? 0 : 0.5, 0, 0.5, 1.0);
-
-            this._preViewMatrix = BABYLON.Matrix.Translation(isLeftEye ? .5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance : -.5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance, 0, 0);
-
-            // Postprocess
-            var postProcess = new BABYLON.OculusDistortionCorrectionPostProcess("Oculus Distortion", this, !isLeftEye, OculusRiftDevKit2013_Metric);
-        }
-
-        public getProjectionMatrix(): Matrix {
-            BABYLON.Matrix.PerspectiveFovLHToRef(this._aspectRatioFov, this._aspectRatioAspectRatio, this.minZ, this.maxZ, this._workMatrix);
-            this._workMatrix.multiplyToRef(this._hMatrix, this._projectionMatrix);
-            return this._projectionMatrix;
-        }
-
-        public _getViewMatrix(): Matrix {
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-
-            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            BABYLON.Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._actualUp);
-
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._actualUp, this._workMatrix);
-
-            this._workMatrix.multiplyToRef(this._preViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        }
-    }
-
-    export class OculusGamepadCamera extends FreeCamera {
-        private _leftCamera: _OculusInnerGamepadCamera;
-        private _rightCamera: _OculusInnerGamepadCamera;
-        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
-        private _deviceOrientationHandler;
-        private _gamepad: BABYLON.Gamepad;
-        private _gamepads: BABYLON.Gamepads;
-        public angularSensibility = 200;
-        public moveSensibility = 75;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-
-            this._leftCamera = new _OculusInnerGamepadCamera(name + "_left", position.clone(), scene, true);
-            this._rightCamera = new _OculusInnerGamepadCamera(name + "_right", position.clone(), scene, false);
-
-            this.subCameras.push(this._leftCamera);
-            this.subCameras.push(this._rightCamera);
-
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
-            this._gamepads = new BABYLON.Gamepads((gamepad: BABYLON.Gamepad) => { this._onNewGameConnected(gamepad); });
-        }
-
-        private _onNewGameConnected(gamepad: BABYLON.Gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this._gamepad = gamepad;
-            }
-        }
-
-        public _update(): void {
-            this._leftCamera.position.copyFrom(this.position);
-            this._rightCamera.position.copyFrom(this.position);
-
-            this._updateCamera(this._leftCamera);
-            this._updateCamera(this._rightCamera);
-
-            super._update();
-        }
-
-        public _checkInputs(): void {
-            if (!this._gamepad) {
-                return;
-            }
-
-            var LSValues = this._gamepad.leftStick;
-            var normalizedLX = LSValues.x / this.moveSensibility;
-            var normalizedLY = LSValues.y / this.moveSensibility;
-            LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-            LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-
-            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x, 0, -LSValues.y), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-        }
-
-        public _updateCamera(camera: FreeCamera): void {
-            camera.minZ = this.minZ;
-            camera.maxZ = this.maxZ;
-
-            camera.rotation.x = this.rotation.x;
-            camera.rotation.y = this.rotation.y;
-            camera.rotation.z = this.rotation.z;
-        }
-
-        // Oculus events
-        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
-            var yaw = evt.alpha / 180 * Math.PI;
-            var pitch = evt.beta / 180 * Math.PI;
-            var roll = evt.gamma / 180 * Math.PI;
-
-            if (!this._offsetOrientation) {
-                this._offsetOrientation = {
-                    yaw: yaw,
-                    pitch: pitch,
-                    roll: roll
-                };
-                return;
-            }
-            else {
-                this.rotation.y += yaw - this._offsetOrientation.yaw;
-                this.rotation.x += pitch - this._offsetOrientation.pitch;
-                this.rotation.z += this._offsetOrientation.roll - roll;
-
-                this._offsetOrientation.yaw = yaw;
-                this._offsetOrientation.pitch = pitch;
-                this._offsetOrientation.roll = roll;
-            }
-        }
-
-        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            super.attachControl(element, noPreventDefault);
-
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-
-        public detachControl(element: HTMLElement): void {
-            super.detachControl(element);
-
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-
-        public dispose(): void {
-            this._gamepads.dispose();
-            super.dispose();
-        }
-    }
-} 

+ 21 - 8
Babylon/Cameras/VR/babylon.vrDeviceOrientationCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -6,15 +6,20 @@ var __extends = this.__extends || function (d, b) {
 };
 var BABYLON;
 (function (BABYLON) {
-    var VRDeviceOrientationCamera = (function (_super) {
-        __extends(VRDeviceOrientationCamera, _super);
-        function VRDeviceOrientationCamera(name, position, scene) {
+    var VRDeviceOrientationFreeCamera = (function (_super) {
+        __extends(VRDeviceOrientationFreeCamera, _super);
+        function VRDeviceOrientationFreeCamera(name, position, scene, compensateDistorsion) {
+            if (compensateDistorsion === void 0) { compensateDistorsion = true; }
             _super.call(this, name, position, scene);
             this._alpha = 0;
             this._beta = 0;
             this._gamma = 0;
+            var metrics = BABYLON.VRCameraMetrics.GetDefault();
+            metrics.compensateDistorsion = compensateDistorsion;
+            this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
+            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
         }
-        VRDeviceOrientationCamera.prototype._onOrientationEvent = function (evt) {
+        VRDeviceOrientationFreeCamera.prototype._onOrientationEvent = function (evt) {
             this._alpha = +evt.alpha | 0;
             this._beta = +evt.beta | 0;
             this._gamma = +evt.gamma | 0;
@@ -29,8 +34,16 @@ var BABYLON;
             this.rotation.y = -this._alpha / 180.0 * Math.PI;
             this.rotation.z = this._beta / 180.0 * Math.PI;
         };
-        return VRDeviceOrientationCamera;
-    })(BABYLON.OculusCamera);
-    BABYLON.VRDeviceOrientationCamera = VRDeviceOrientationCamera;
+        VRDeviceOrientationFreeCamera.prototype.attachControl = function (element, noPreventDefault) {
+            _super.prototype.attachControl.call(this, element, noPreventDefault);
+            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+        };
+        VRDeviceOrientationFreeCamera.prototype.detachControl = function (element) {
+            _super.prototype.detachControl.call(this, element);
+            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
+        };
+        return VRDeviceOrientationFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.VRDeviceOrientationFreeCamera = VRDeviceOrientationFreeCamera;
 })(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.vrDeviceOrientationCamera.js.map

+ 35 - 14
Babylon/Cameras/VR/babylon.vrDeviceOrientationCamera.ts

@@ -1,12 +1,21 @@
 module BABYLON {
-	export class VRDeviceOrientationCamera extends BABYLON.OculusCamera {
-		public _alpha = 0;
-		public _beta = 0;
-		public _gamma = 0;
-	
-		constructor(name: string, position: Vector3, scene: Scene) {
-			super(name, position, scene);
-		}
+    export class VRDeviceOrientationFreeCamera extends FreeCamera {
+        public _alpha = 0;
+        public _beta = 0;
+        public _gamma = 0;
+    
+        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
+        private _deviceOrientationHandler;
+
+        constructor(name: string, position: Vector3, scene: Scene, compensateDistorsion = true) {
+            super(name, position, scene);
+
+            var metrics = VRCameraMetrics.GetDefault();
+            metrics.compensateDistorsion = compensateDistorsion;
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
+
+            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
+        }
 
         public _onOrientationEvent(evt: DeviceOrientationEvent): void {
             this._alpha = +evt.alpha|0;
@@ -14,16 +23,28 @@ module BABYLON {
             this._gamma = +evt.gamma|0;
 
             if (this._gamma < 0) {
-            	this._gamma = 90 + this._gamma;
+                this._gamma = 90 + this._gamma;
             }
             else {
-				// Incline it in the correct angle.
-            	this._gamma = 270 - this._gamma;
+                // Incline it in the correct angle.
+                this._gamma = 270 - this._gamma;
             }
 
             this.rotation.x = this._gamma / 180.0 * Math.PI;   
-			this.rotation.y = -this._alpha / 180.0 * Math.PI;	
-			this.rotation.z	= this._beta / 180.0 * Math.PI;		
+            this.rotation.y = -this._alpha / 180.0 * Math.PI;   
+            this.rotation.z = this._beta / 180.0 * Math.PI;     
+        }
+
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            super.attachControl(element, noPreventDefault);
+
+            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+        }
+
+        public detachControl(element: HTMLElement): void {
+            super.detachControl(element);
+
+            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
         }
-	}
+    }
 }

+ 17 - 12
Babylon/Cameras/VR/babylon.webVRCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -6,9 +6,10 @@ var __extends = this.__extends || function (d, b) {
 };
 var BABYLON;
 (function (BABYLON) {
-    var WebVRCamera = (function (_super) {
-        __extends(WebVRCamera, _super);
-        function WebVRCamera(name, position, scene) {
+    var WebVRFreeCamera = (function (_super) {
+        __extends(WebVRFreeCamera, _super);
+        function WebVRFreeCamera(name, position, scene, compensateDistorsion) {
+            if (compensateDistorsion === void 0) { compensateDistorsion = true; }
             _super.call(this, name, position, scene);
             this._hmdDevice = null;
             this._sensorDevice = null;
@@ -16,14 +17,18 @@ var BABYLON;
             this._cacheQuaternion = new BABYLON.Quaternion();
             this._cacheRotation = BABYLON.Vector3.Zero();
             this._vrEnabled = false;
+            var metrics = BABYLON.VRCameraMetrics.GetDefault();
+            metrics.compensateDistorsion = compensateDistorsion;
+            this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
             this._getWebVRDevices = this._getWebVRDevices.bind(this);
         }
-        WebVRCamera.prototype._getWebVRDevices = function (devices) {
+        WebVRFreeCamera.prototype._getWebVRDevices = function (devices) {
             var size = devices.length;
             var i = 0;
             // Reset devices.
             this._sensorDevice = null;
             this._hmdDevice = null;
+            // Search for a HmdDevice.
             while (i < size && this._hmdDevice === null) {
                 if (devices[i] instanceof HMDVRDevice) {
                     this._hmdDevice = devices[i];
@@ -39,7 +44,7 @@ var BABYLON;
             }
             this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
         };
-        WebVRCamera.prototype._update = function () {
+        WebVRFreeCamera.prototype._checkInputs = function () {
             if (this._vrEnabled) {
                 this._cacheState = this._sensorDevice.getState();
                 this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
@@ -48,9 +53,9 @@ var BABYLON;
                 this.rotation.y = -this._cacheRotation.y;
                 this.rotation.z = this._cacheRotation.x;
             }
-            _super.prototype._update.call(this);
+            _super.prototype._checkInputs.call(this);
         };
-        WebVRCamera.prototype.attachControl = function (element, noPreventDefault) {
+        WebVRFreeCamera.prototype.attachControl = function (element, noPreventDefault) {
             _super.prototype.attachControl.call(this, element, noPreventDefault);
             if (navigator.getVRDevices) {
                 navigator.getVRDevices().then(this._getWebVRDevices);
@@ -59,12 +64,12 @@ var BABYLON;
                 navigator.mozGetVRDevices(this._getWebVRDevices);
             }
         };
-        WebVRCamera.prototype.detachControl = function (element) {
+        WebVRFreeCamera.prototype.detachControl = function (element) {
             _super.prototype.detachControl.call(this, element);
             this._vrEnabled = false;
         };
-        return WebVRCamera;
-    })(BABYLON.OculusCamera);
-    BABYLON.WebVRCamera = WebVRCamera;
+        return WebVRFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.WebVRFreeCamera = WebVRFreeCamera;
 })(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.webVRCamera.js.map

+ 11 - 6
Babylon/Cameras/VR/babylon.webVRCamera.ts

@@ -2,16 +2,21 @@ declare var HMDVRDevice;
 declare var PositionSensorVRDevice;
 
 module BABYLON {
-    export class WebVRCamera extends BABYLON.OculusCamera {
+    export class WebVRFreeCamera extends FreeCamera {
         public _hmdDevice = null;
         public _sensorDevice = null;
         public _cacheState = null;
-        public _cacheQuaternion = new BABYLON.Quaternion();
-        public _cacheRotation = BABYLON.Vector3.Zero();
+        public _cacheQuaternion = new Quaternion();
+        public _cacheRotation = Vector3.Zero();
         public _vrEnabled = false;
 
-        constructor(name: string, position: Vector3, scene: Scene) {
+        constructor(name: string, position: Vector3, scene: Scene, compensateDistorsion = true) {
             super(name, position, scene);
+            
+            var metrics = VRCameraMetrics.GetDefault();
+            metrics.compensateDistorsion = compensateDistorsion;
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
+
             this._getWebVRDevices = this._getWebVRDevices.bind(this);
         }
 
@@ -43,7 +48,7 @@ module BABYLON {
             this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
         }
 
-        public _update(): void {
+        public _checkInputs(): void {
             if (this._vrEnabled) {
                 this._cacheState = this._sensorDevice.getState();
                 this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
@@ -54,7 +59,7 @@ module BABYLON {
                 this.rotation.z = this._cacheRotation.x;
             }
 
-            super._update();
+            super._checkInputs();
         }
 
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {

+ 17 - 62
Babylon/Cameras/babylon.anaglyphCamera.js

@@ -6,77 +6,32 @@ var __extends = this.__extends || function (d, b) {
 };
 var BABYLON;
 (function (BABYLON) {
-    var buildCamera = function (that, name) {
-        that._leftCamera.isIntermediate = true;
-        that.subCameras.push(that._leftCamera);
-        that.subCameras.push(that._rightCamera);
-        that._leftTexture = new BABYLON.PassPostProcess(name + "_leftTexture", 1.0, that._leftCamera);
-        that._anaglyphPostProcess = new BABYLON.AnaglyphPostProcess(name + "_anaglyph", 1.0, that._rightCamera);
-        that._anaglyphPostProcess.onApply = function (effect) {
-            effect.setTextureFromPostProcess("leftSampler", that._leftTexture);
-        };
-        that._update();
-    };
+    var AnaglyphFreeCamera = (function (_super) {
+        __extends(AnaglyphFreeCamera, _super);
+        function AnaglyphFreeCamera(name, position, eyeSpace, scene) {
+            _super.call(this, name, position, scene);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
+        }
+        return AnaglyphFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
     var AnaglyphArcRotateCamera = (function (_super) {
         __extends(AnaglyphArcRotateCamera, _super);
-        // ANY
         function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, eyeSpace, scene) {
             _super.call(this, name, alpha, beta, radius, target, scene);
-            this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
-            this._leftCamera = new BABYLON.ArcRotateCamera(name + "_left", alpha - this._eyeSpace, beta, radius, target, scene);
-            this._rightCamera = new BABYLON.ArcRotateCamera(name + "_right", alpha + this._eyeSpace, beta, radius, target, scene);
-            buildCamera(this, name);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
         }
-        AnaglyphArcRotateCamera.prototype._update = function () {
-            this._updateCamera(this._leftCamera);
-            this._updateCamera(this._rightCamera);
-            this._leftCamera.alpha = this.alpha - this._eyeSpace;
-            this._rightCamera.alpha = this.alpha + this._eyeSpace;
-            _super.prototype._update.call(this);
-        };
-        AnaglyphArcRotateCamera.prototype._updateCamera = function (camera) {
-            camera.beta = this.beta;
-            camera.radius = this.radius;
-            camera.minZ = this.minZ;
-            camera.maxZ = this.maxZ;
-            camera.fov = this.fov;
-            camera.target = this.target;
-        };
         return AnaglyphArcRotateCamera;
     })(BABYLON.ArcRotateCamera);
     BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
-    var AnaglyphFreeCamera = (function (_super) {
-        __extends(AnaglyphFreeCamera, _super);
-        function AnaglyphFreeCamera(name, position, eyeSpace, scene) {
+    var AnaglyphGamepadCamera = (function (_super) {
+        __extends(AnaglyphGamepadCamera, _super);
+        function AnaglyphGamepadCamera(name, position, eyeSpace, scene) {
             _super.call(this, name, position, scene);
-            this._eyeSpace = BABYLON.Tools.ToRadians(eyeSpace);
-            this._transformMatrix = new BABYLON.Matrix();
-            this._leftCamera = new BABYLON.FreeCamera(name + "_left", position.clone(), scene);
-            this._rightCamera = new BABYLON.FreeCamera(name + "_right", position.clone(), scene);
-            buildCamera(this, name);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
         }
-        AnaglyphFreeCamera.prototype._getSubCameraPosition = function (eyeSpace, result) {
-            var target = this.getTarget();
-            BABYLON.Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(BABYLON.Matrix.RotationY(eyeSpace), this._transformMatrix);
-            this._transformMatrix = this._transformMatrix.multiply(BABYLON.Matrix.Translation(target.x, target.y, target.z));
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this._transformMatrix, result);
-        };
-        AnaglyphFreeCamera.prototype._update = function () {
-            this._getSubCameraPosition(-this._eyeSpace, this._leftCamera.position);
-            this._getSubCameraPosition(this._eyeSpace, this._rightCamera.position);
-            this._updateCamera(this._leftCamera);
-            this._updateCamera(this._rightCamera);
-            _super.prototype._update.call(this);
-        };
-        AnaglyphFreeCamera.prototype._updateCamera = function (camera) {
-            camera.minZ = this.minZ;
-            camera.maxZ = this.maxZ;
-            camera.fov = this.fov;
-            camera.viewport = this.viewport;
-            camera.setTarget(this.getTarget());
-        };
-        return AnaglyphFreeCamera;
-    })(BABYLON.FreeCamera);
-    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
+        return AnaglyphGamepadCamera;
+    })(BABYLON.GamepadCamera);
+    BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
 })(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.anaglyphCamera.js.map

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

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

+ 139 - 41
Babylon/Cameras/babylon.arcRotateCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -10,6 +10,7 @@ var BABYLON;
     var ArcRotateCamera = (function (_super) {
         __extends(ArcRotateCamera, _super);
         function ArcRotateCamera(name, alpha, beta, radius, target, scene) {
+            var _this = this;
             _super.call(this, name, BABYLON.Vector3.Zero(), scene);
             this.alpha = alpha;
             this.beta = beta;
@@ -33,6 +34,8 @@ var BABYLON;
             this.keysRight = [39];
             this.zoomOnFactor = 1;
             this.targetScreenOffset = BABYLON.Vector2.Zero();
+            this.pinchInwards = true;
+            this.allowUpsideDown = true;
             this._keys = [];
             this._viewMatrix = new BABYLON.Matrix();
             this.checkCollisions = false;
@@ -41,6 +44,38 @@ var BABYLON;
             this._previousPosition = BABYLON.Vector3.Zero();
             this._collisionVelocity = BABYLON.Vector3.Zero();
             this._newPosition = BABYLON.Vector3.Zero();
+            this._onCollisionPositionChange = function (collisionId, newPosition, collidedMesh) {
+                if (collidedMesh === void 0) { collidedMesh = null; }
+                if (_this.getScene().workerCollisions && _this.checkCollisions) {
+                    newPosition.multiplyInPlace(_this._collider.radius);
+                }
+                if (!collidedMesh) {
+                    _this._previousPosition.copyFrom(_this.position);
+                }
+                else {
+                    _this.setPosition(_this.position);
+                    if (_this.onCollide) {
+                        _this.onCollide(collidedMesh);
+                    }
+                }
+                // Recompute because of constraints
+                var cosa = Math.cos(_this.alpha);
+                var sina = Math.sin(_this.alpha);
+                var cosb = Math.cos(_this.beta);
+                var sinb = Math.sin(_this.beta);
+                var target = _this._getTargetPosition();
+                target.addToRef(new BABYLON.Vector3(_this.radius * cosa * sinb, _this.radius * cosb, _this.radius * sina * sinb), _this._newPosition);
+                _this.position.copyFrom(_this._newPosition);
+                var up = _this.upVector;
+                if (_this.allowUpsideDown && _this.beta < 0) {
+                    var up = up.clone();
+                    up = up.negate();
+                }
+                BABYLON.Matrix.LookAtLHToRef(_this.position, target, up, _this._viewMatrix);
+                _this._viewMatrix.m[12] += _this.targetScreenOffset.x;
+                _this._viewMatrix.m[13] += _this.targetScreenOffset.y;
+                _this._collisionTriggered = false;
+            };
             if (!this.target) {
                 this.target = BABYLON.Vector3.Zero();
             }
@@ -72,7 +107,11 @@ var BABYLON;
         ArcRotateCamera.prototype._isSynchronizedViewMatrix = function () {
             if (!_super.prototype._isSynchronizedViewMatrix.call(this))
                 return false;
-            return this._cache.target.equals(this._getTargetPosition()) && this._cache.alpha === this.alpha && this._cache.beta === this.beta && this._cache.radius === this.radius && this._cache.targetScreenOffset.equals(this.targetScreenOffset);
+            return this._cache.target.equals(this._getTargetPosition())
+                && this._cache.alpha === this.alpha
+                && this._cache.beta === this.beta
+                && this._cache.radius === this.radius
+                && this._cache.targetScreenOffset.equals(this.targetScreenOffset);
         };
         // Methods
         ArcRotateCamera.prototype.attachControl = function (element, noPreventDefault) {
@@ -96,7 +135,11 @@ var BABYLON;
                 this._onPointerUp = function (evt) {
                     cacheSoloPointer = null;
                     previousPinchDistance = 0;
-                    pointers.remove(evt.pointerId);
+                    //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
+                    //but emptying completly pointers collection is required to fix a bug on iPhone : 
+                    //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers  
+                    //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
+                    pointers.empty();
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
@@ -107,14 +150,10 @@ var BABYLON;
                     }
                     switch (pointers.count) {
                         case 1:
-                            //var offsetX = evt.clientX - pointers.item(evt.pointerId).x;
-                            //var offsetY = evt.clientY - pointers.item(evt.pointerId).y;
                             var offsetX = evt.clientX - cacheSoloPointer.x;
                             var offsetY = evt.clientY - cacheSoloPointer.y;
                             _this.inertialAlphaOffset -= offsetX / _this.angularSensibility;
                             _this.inertialBetaOffset -= offsetY / _this.angularSensibility;
-                            //pointers.item(evt.pointerId).x = evt.clientX;
-                            //pointers.item(evt.pointerId).y = evt.clientY;
                             cacheSoloPointer.x = evt.clientX;
                             cacheSoloPointer.y = evt.clientY;
                             break;
@@ -122,7 +161,7 @@ var BABYLON;
                             //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
                             pointers.item(evt.pointerId).x = evt.clientX;
                             pointers.item(evt.pointerId).y = evt.clientY;
-                            var direction = 1;
+                            var direction = _this.pinchInwards ? 1 : -1;
                             var distX = pointers.getItemByIndex(0).x - pointers.getItemByIndex(1).x;
                             var distY = pointers.getItemByIndex(0).y - pointers.getItemByIndex(1).y;
                             var pinchSquaredDistance = (distX * distX) + (distY * distY);
@@ -131,10 +170,7 @@ var BABYLON;
                                 return;
                             }
                             if (pinchSquaredDistance !== previousPinchDistance) {
-                                if (pinchSquaredDistance > previousPinchDistance) {
-                                    direction = -1;
-                                }
-                                _this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (_this.pinchPrecision * _this.wheelPrecision * _this.angularSensibility);
+                                _this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (_this.pinchPrecision * _this.wheelPrecision * _this.angularSensibility * direction);
                                 previousPinchDistance = pinchSquaredDistance;
                             }
                             break;
@@ -174,7 +210,10 @@ var BABYLON;
                     }
                 };
                 this._onKeyDown = function (evt) {
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
                         var index = _this._keys.indexOf(evt.keyCode);
                         if (index === -1) {
                             _this._keys.push(evt.keyCode);
@@ -187,7 +226,10 @@ var BABYLON;
                     }
                 };
                 this._onKeyUp = function (evt) {
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
                         var index = _this._keys.indexOf(evt.keyCode);
                         if (index >= 0) {
                             _this._keys.splice(index, 1);
@@ -273,7 +315,12 @@ var BABYLON;
                 this._reset();
             }
         };
-        ArcRotateCamera.prototype._update = function () {
+        ArcRotateCamera.prototype._checkInputs = function () {
+            //if (async) collision inspection was triggered, don't update the camera's position - until the collision callback was called.
+            if (this._collisionTriggered) {
+                return;
+            }
+            // Keyboard
             for (var index = 0; index < this._keys.length; index++) {
                 var keyCode = this._keys[index];
                 if (this.keysLeft.indexOf(keyCode) !== -1) {
@@ -291,7 +338,7 @@ var BABYLON;
             }
             // Inertia
             if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset != 0) {
-                this.alpha += this.inertialAlphaOffset;
+                this.alpha += this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
                 this.beta += this.inertialBetaOffset;
                 this.radius -= this.inertialRadiusOffset;
                 this.inertialAlphaOffset *= this.inertia;
@@ -305,18 +352,36 @@ var BABYLON;
                     this.inertialRadiusOffset = 0;
             }
             // Limits
+            this._checkLimits();
+            _super.prototype._checkInputs.call(this);
+        };
+        ArcRotateCamera.prototype._checkLimits = function () {
+            if (this.lowerBetaLimit === null || this.lowerBetaLimit === undefined) {
+                if (this.allowUpsideDown && this.beta > Math.PI) {
+                    this.beta = this.beta - (2 * Math.PI);
+                }
+            }
+            else {
+                if (this.beta < this.lowerBetaLimit) {
+                    this.beta = this.lowerBetaLimit;
+                }
+            }
+            if (this.upperBetaLimit === null || this.upperBetaLimit === undefined) {
+                if (this.allowUpsideDown && this.beta < -Math.PI) {
+                    this.beta = this.beta + (2 * Math.PI);
+                }
+            }
+            else {
+                if (this.beta > this.upperBetaLimit) {
+                    this.beta = this.upperBetaLimit;
+                }
+            }
             if (this.lowerAlphaLimit && this.alpha < this.lowerAlphaLimit) {
                 this.alpha = this.lowerAlphaLimit;
             }
             if (this.upperAlphaLimit && this.alpha > this.upperAlphaLimit) {
                 this.alpha = this.upperAlphaLimit;
             }
-            if (this.lowerBetaLimit && this.beta < this.lowerBetaLimit) {
-                this.beta = this.lowerBetaLimit;
-            }
-            if (this.upperBetaLimit && this.beta > this.upperBetaLimit) {
-                this.beta = this.upperBetaLimit;
-            }
             if (this.lowerRadiusLimit && this.radius < this.lowerRadiusLimit) {
                 this.radius = this.lowerRadiusLimit;
             }
@@ -334,6 +399,7 @@ var BABYLON;
             }
             // Beta
             this.beta = Math.acos(radiusv3.y / this.radius);
+            this._checkLimits();
         };
         ArcRotateCamera.prototype._getViewMatrix = function () {
             // Compute
@@ -342,28 +408,24 @@ var BABYLON;
             var cosb = Math.cos(this.beta);
             var sinb = Math.sin(this.beta);
             var target = this._getTargetPosition();
-            target.addToRef(new BABYLON.Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this.position);
-            if (this.checkCollisions) {
+            target.addToRef(new BABYLON.Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
+            if (this.getScene().collisionsEnabled && this.checkCollisions) {
                 this._collider.radius = this.collisionRadius;
-                this.position.subtractToRef(this._previousPosition, this._collisionVelocity);
-                this.getScene()._getNewPosition(this._previousPosition, this._collisionVelocity, this._collider, 3, this._newPosition);
-                if (!this._newPosition.equalsWithEpsilon(this.position)) {
-                    this.position.copyFrom(this._previousPosition);
-                    this.alpha = this._previousAlpha;
-                    this.beta = this._previousBeta;
-                    this.radius = this._previousRadius;
-                    if (this.onCollide) {
-                        this.onCollide(this._collider.collidedMesh);
-                    }
+                this._newPosition.subtractToRef(this.position, this._collisionVelocity);
+                this._collisionTriggered = true;
+                this.getScene().collisionCoordinator.getNewPosition(this.position, this._collisionVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
+            }
+            else {
+                this.position.copyFrom(this._newPosition);
+                var up = this.upVector;
+                if (this.allowUpsideDown && this.beta < 0) {
+                    var up = up.clone();
+                    up = up.negate();
                 }
+                BABYLON.Matrix.LookAtLHToRef(this.position, target, up, this._viewMatrix);
+                this._viewMatrix.m[12] += this.targetScreenOffset.x;
+                this._viewMatrix.m[13] += this.targetScreenOffset.y;
             }
-            BABYLON.Matrix.LookAtLHToRef(this.position, target, this.upVector, this._viewMatrix);
-            this._previousAlpha = this.alpha;
-            this._previousBeta = this.beta;
-            this._previousRadius = this.radius;
-            this._previousPosition.copyFrom(this.position);
-            this._viewMatrix.m[12] += this.targetScreenOffset.x;
-            this._viewMatrix.m[13] += this.targetScreenOffset.y;
             return this._viewMatrix;
         };
         ArcRotateCamera.prototype.zoomOn = function (meshes) {
@@ -388,6 +450,42 @@ var BABYLON;
             this.target = BABYLON.Mesh.Center(meshesOrMinMaxVector);
             this.maxZ = distance * 2;
         };
+        /**
+         * @override
+         * Override Camera.createRigCamera
+         */
+        ArcRotateCamera.prototype.createRigCamera = function (name, cameraIndex) {
+            switch (this.cameraRigMode) {
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case BABYLON.Camera.RIG_MODE_VR:
+                    var alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? 1 : -1);
+                    return new ArcRotateCamera(name, this.alpha + alphaShift, this.beta, this.radius, this.target, this.getScene());
+            }
+        };
+        /**
+         * @override
+         * Override Camera._updateRigCameras
+         */
+        ArcRotateCamera.prototype._updateRigCameras = function () {
+            switch (this.cameraRigMode) {
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case BABYLON.Camera.RIG_MODE_VR:
+                    var camLeft = this._rigCameras[0];
+                    var camRight = this._rigCameras[1];
+                    camLeft.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
+                    camRight.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
+                    camLeft.beta = camRight.beta = this.beta;
+                    camLeft.radius = camRight.radius = this.radius;
+                    break;
+            }
+            _super.prototype._updateRigCameras.call(this);
+        };
         return ArcRotateCamera;
     })(BABYLON.Camera);
     BABYLON.ArcRotateCamera = ArcRotateCamera;

+ 134 - 48
Babylon/Cameras/babylon.arcRotateCamera.ts

@@ -20,7 +20,8 @@
         public keysRight = [39];
         public zoomOnFactor = 1;
         public targetScreenOffset = Vector2.Zero();
-
+        public pinchInwards = true;
+        public allowUpsideDown = true;
 
         private _keys = [];
         private _viewMatrix = new Matrix();
@@ -50,6 +51,8 @@
         private _previousAlpha: number;
         private _previousBeta: number;
         private _previousRadius: number;
+        //due to async collision inspection
+        private _collisionTriggered: boolean;
 
         constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: any, scene: Scene) {
             super(name, Vector3.Zero(), scene);
@@ -124,7 +127,13 @@
                 this._onPointerUp = evt => {
                     cacheSoloPointer = null;
                     previousPinchDistance = 0;
-                    pointers.remove(evt.pointerId);
+                    
+                    //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
+                    //but emptying completly pointers collection is required to fix a bug on iPhone : 
+                    //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers  
+                    //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
+                    pointers.empty();
+                                       
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
@@ -138,14 +147,10 @@
                     switch (pointers.count) {
 
                         case 1: //normal camera rotation
-                            //var offsetX = evt.clientX - pointers.item(evt.pointerId).x;
-                            //var offsetY = evt.clientY - pointers.item(evt.pointerId).y;
                             var offsetX = evt.clientX - cacheSoloPointer.x;
                             var offsetY = evt.clientY - cacheSoloPointer.y;
                             this.inertialAlphaOffset -= offsetX / this.angularSensibility;
                             this.inertialBetaOffset -= offsetY / this.angularSensibility;
-                            //pointers.item(evt.pointerId).x = evt.clientX;
-                            //pointers.item(evt.pointerId).y = evt.clientY;
                             cacheSoloPointer.x = evt.clientX;
                             cacheSoloPointer.y = evt.clientY;
                             break;
@@ -154,7 +159,7 @@
                             //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
                             pointers.item(evt.pointerId).x = evt.clientX;
                             pointers.item(evt.pointerId).y = evt.clientY;
-                            var direction = 1;
+                            var direction = this.pinchInwards ? 1 : -1;
                             var distX = pointers.getItemByIndex(0).x - pointers.getItemByIndex(1).x;
                             var distY = pointers.getItemByIndex(0).y - pointers.getItemByIndex(1).y;
                             var pinchSquaredDistance = (distX * distX) + (distY * distY);
@@ -164,10 +169,7 @@
                             }
 
                             if (pinchSquaredDistance !== previousPinchDistance) {
-                                if (pinchSquaredDistance > previousPinchDistance) {
-                                    direction = -1;
-                                }
-                                this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (this.pinchPrecision * this.wheelPrecision * this.angularSensibility);
+                                this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (this.pinchPrecision * this.wheelPrecision * this.angularSensibility * direction);
                                 previousPinchDistance = pinchSquaredDistance;
                             }
                             break;
@@ -343,11 +345,14 @@
             }
         }
 
-        public _update(): void {
+        public _checkInputs(): void {
+            //if (async) collision inspection was triggered, don't update the camera's position - until the collision callback was called.
+            if (this._collisionTriggered) {
+                return;
+            }
             // Keyboard
             for (var index = 0; index < this._keys.length; index++) {
                 var keyCode = this._keys[index];
-
                 if (this.keysLeft.indexOf(keyCode) !== -1) {
                     this.inertialAlphaOffset -= 0.01;
                 } else if (this.keysUp.indexOf(keyCode) !== -1) {
@@ -357,42 +362,58 @@
                 } else if (this.keysDown.indexOf(keyCode) !== -1) {
                     this.inertialBetaOffset += 0.01;
                 }
-            }
-
+            }			
+			
             // Inertia
             if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset != 0) {
-
-                this.alpha += this.inertialAlphaOffset;
+                this.alpha += this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
                 this.beta += this.inertialBetaOffset;
                 this.radius -= this.inertialRadiusOffset;
-
                 this.inertialAlphaOffset *= this.inertia;
                 this.inertialBetaOffset *= this.inertia;
                 this.inertialRadiusOffset *= this.inertia;
-
                 if (Math.abs(this.inertialAlphaOffset) < Engine.Epsilon)
                     this.inertialAlphaOffset = 0;
-
                 if (Math.abs(this.inertialBetaOffset) < Engine.Epsilon)
                     this.inertialBetaOffset = 0;
-
                 if (Math.abs(this.inertialRadiusOffset) < Engine.Epsilon)
                     this.inertialRadiusOffset = 0;
             }
 
             // Limits
+            this._checkLimits();
+
+            super._checkInputs();
+        }
+
+        private _checkLimits() {
+            if (this.lowerBetaLimit === null || this.lowerBetaLimit === undefined) {
+                if (this.allowUpsideDown && this.beta > Math.PI) {
+                    this.beta = this.beta - (2 * Math.PI);
+                }
+            } else {
+                if (this.beta < this.lowerBetaLimit) {
+                    this.beta = this.lowerBetaLimit;
+                }
+            }
+
+            if (this.upperBetaLimit === null || this.upperBetaLimit === undefined) {
+                if (this.allowUpsideDown && this.beta < -Math.PI) {
+                    this.beta = this.beta + (2 * Math.PI);
+                }
+            } else {
+                if (this.beta > this.upperBetaLimit) {
+                    this.beta = this.upperBetaLimit;
+                }
+            }
+
             if (this.lowerAlphaLimit && this.alpha < this.lowerAlphaLimit) {
                 this.alpha = this.lowerAlphaLimit;
             }
             if (this.upperAlphaLimit && this.alpha > this.upperAlphaLimit) {
                 this.alpha = this.upperAlphaLimit;
             }
-            if (this.lowerBetaLimit && this.beta < this.lowerBetaLimit) {
-                this.beta = this.lowerBetaLimit;
-            }
-            if (this.upperBetaLimit && this.beta > this.upperBetaLimit) {
-                this.beta = this.upperBetaLimit;
-            }
+
             if (this.lowerRadiusLimit && this.radius < this.lowerRadiusLimit) {
                 this.radius = this.lowerRadiusLimit;
             }
@@ -414,6 +435,8 @@
 
             // Beta
             this.beta = Math.acos(radiusv3.y / this.radius);
+
+            this._checkLimits();
         }
 
         public _getViewMatrix(): Matrix {
@@ -424,39 +447,64 @@
             var sinb = Math.sin(this.beta);
 
             var target = this._getTargetPosition();
-
-            target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this.position);
-
-            if (this.checkCollisions) {
+            target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
+            if (this.getScene().collisionsEnabled && this.checkCollisions) {
                 this._collider.radius = this.collisionRadius;
-                this.position.subtractToRef(this._previousPosition, this._collisionVelocity);
+                this._newPosition.subtractToRef(this.position, this._collisionVelocity);
+                this._collisionTriggered = true;
+                this.getScene().collisionCoordinator.getNewPosition(this.position, this._collisionVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
+            } else {
+                this.position.copyFrom(this._newPosition);
+
+                var up = this.upVector;
+                if (this.allowUpsideDown && this.beta < 0) {
+                    var up = up.clone();
+                    up = up.negate();
+                }
 
-                this.getScene()._getNewPosition(this._previousPosition, this._collisionVelocity, this._collider, 3, this._newPosition);
+                Matrix.LookAtLHToRef(this.position, target, up, this._viewMatrix);
+                this._viewMatrix.m[12] += this.targetScreenOffset.x;
+                this._viewMatrix.m[13] += this.targetScreenOffset.y;
+            }
+            return this._viewMatrix;
+        }
 
-                if (!this._newPosition.equalsWithEpsilon(this.position)) {
-                    this.position.copyFrom(this._previousPosition);
+        private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: AbstractMesh = null) => {
 
-                    this.alpha = this._previousAlpha;
-                    this.beta = this._previousBeta;
-                    this.radius = this._previousRadius;
+            if (this.getScene().workerCollisions && this.checkCollisions) {
+                newPosition.multiplyInPlace(this._collider.radius);
+            }
 
-                    if (this.onCollide) {
-                        this.onCollide(this._collider.collidedMesh);
-                    }
+            if (!collidedMesh) {
+                this._previousPosition.copyFrom(this.position);
+            } else {
+                this.setPosition(this.position);
+
+                if (this.onCollide) {
+                    this.onCollide(collidedMesh);
                 }
             }
 
-            Matrix.LookAtLHToRef(this.position, target, this.upVector, this._viewMatrix);
+            // Recompute because of constraints
+            var cosa = Math.cos(this.alpha);
+            var sina = Math.sin(this.alpha);
+            var cosb = Math.cos(this.beta);
+            var sinb = Math.sin(this.beta);
+            var target = this._getTargetPosition();
+            target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
+            this.position.copyFrom(this._newPosition);
 
-            this._previousAlpha = this.alpha;
-            this._previousBeta = this.beta;
-            this._previousRadius = this.radius;
-            this._previousPosition.copyFrom(this.position);
+            var up = this.upVector;
+            if (this.allowUpsideDown && this.beta < 0) {
+                var up = up.clone();
+                up = up.negate();
+            }
 
+            Matrix.LookAtLHToRef(this.position, target, up, this._viewMatrix);
             this._viewMatrix.m[12] += this.targetScreenOffset.x;
             this._viewMatrix.m[13] += this.targetScreenOffset.y;
 
-            return this._viewMatrix;
+            this._collisionTriggered = false;
         }
 
         public zoomOn(meshes?: AbstractMesh[]): void {
@@ -488,5 +536,43 @@
 
             this.maxZ = distance * 2;
         }
+        
+        /**
+         * @override
+         * Override Camera.createRigCamera
+         */
+        public createRigCamera(name: string, cameraIndex: number): Camera {
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case Camera.RIG_MODE_VR:
+                    var alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? 1 : -1);
+                    return new ArcRotateCamera(name, this.alpha + alphaShift, this.beta, this.radius, this.target, this.getScene());
+            }
+        }
+        
+        /**
+         * @override
+         * Override Camera._updateRigCameras
+         */
+        public _updateRigCameras() {
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case Camera.RIG_MODE_VR:
+                    var camLeft = <ArcRotateCamera> this._rigCameras[0];
+                    var camRight = <ArcRotateCamera> this._rigCameras[1];
+                    camLeft.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
+                    camRight.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
+                    camLeft.beta = camRight.beta = this.beta;
+                    camLeft.radius = camRight.radius = this.radius;
+                    break;
+            }
+            super._updateRigCameras();
+        }
     }
-} 
+} 

+ 261 - 20
Babylon/Cameras/babylon.camera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -6,6 +6,75 @@ var __extends = this.__extends || function (d, b) {
 };
 var BABYLON;
 (function (BABYLON) {
+    var VRCameraMetrics = (function () {
+        function VRCameraMetrics() {
+            this.compensateDistorsion = true;
+        }
+        Object.defineProperty(VRCameraMetrics.prototype, "aspectRatio", {
+            get: function () {
+                return this.hResolution / (2 * this.vResolution);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(VRCameraMetrics.prototype, "aspectRatioFov", {
+            get: function () {
+                return (2 * Math.atan((this.postProcessScaleFactor * this.vScreenSize) / (2 * this.eyeToScreenDistance)));
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(VRCameraMetrics.prototype, "leftHMatrix", {
+            get: function () {
+                var meters = (this.hScreenSize / 4) - (this.lensSeparationDistance / 2);
+                var h = (4 * meters) / this.hScreenSize;
+                return BABYLON.Matrix.Translation(h, 0, 0);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(VRCameraMetrics.prototype, "rightHMatrix", {
+            get: function () {
+                var meters = (this.hScreenSize / 4) - (this.lensSeparationDistance / 2);
+                var h = (4 * meters) / this.hScreenSize;
+                return BABYLON.Matrix.Translation(-h, 0, 0);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(VRCameraMetrics.prototype, "leftPreViewMatrix", {
+            get: function () {
+                return BABYLON.Matrix.Translation(0.5 * this.interpupillaryDistance, 0, 0);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(VRCameraMetrics.prototype, "rightPreViewMatrix", {
+            get: function () {
+                return BABYLON.Matrix.Translation(-0.5 * this.interpupillaryDistance, 0, 0);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        VRCameraMetrics.GetDefault = function () {
+            var result = new VRCameraMetrics();
+            result.hResolution = 1280;
+            result.vResolution = 800;
+            result.hScreenSize = 0.149759993;
+            result.vScreenSize = 0.0935999975;
+            result.vScreenCenter = 0.0467999987,
+                result.eyeToScreenDistance = 0.0410000011;
+            result.lensSeparationDistance = 0.0635000020;
+            result.interpupillaryDistance = 0.0640000030;
+            result.distortionK = [1.0, 0.219999999, 0.239999995, 0.0];
+            result.chromaAbCorrection = [0.995999992, -0.00400000019, 1.01400006, 0.0];
+            result.postProcessScaleFactor = 1.714605507808412;
+            result.lensCenterOffset = 0.151976421;
+            return result;
+        };
+        return VRCameraMetrics;
+    })();
+    BABYLON.VRCameraMetrics = VRCameraMetrics;
     var Camera = (function (_super) {
         __extends(Camera, _super);
         function Camera(name, position, scene) {
@@ -24,9 +93,12 @@ var BABYLON;
             this.mode = Camera.PERSPECTIVE_CAMERA;
             this.isIntermediate = false;
             this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
-            this.subCameras = [];
-            this.layerMask = 0xFFFFFFFF;
+            this.layerMask = 0x0FFFFFFF;
             this.fovMode = Camera.FOVMODE_VERTICAL_FIXED;
+            // Camera rig members
+            this.cameraRigMode = Camera.RIG_MODE_NONE;
+            this._rigCameras = new Array();
+            // Cache
             this._computedViewMatrix = BABYLON.Matrix.Identity();
             this._projectionMatrix = new BABYLON.Matrix();
             this._postProcesses = new Array();
@@ -66,6 +138,48 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(Camera, "RIG_MODE_NONE", {
+            get: function () {
+                return Camera._RIG_MODE_NONE;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Camera, "RIG_MODE_STEREOSCOPIC_ANAGLYPH", {
+            get: function () {
+                return Camera._RIG_MODE_STEREOSCOPIC_ANAGLYPH;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Camera, "RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL", {
+            get: function () {
+                return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Camera, "RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED", {
+            get: function () {
+                return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Camera, "RIG_MODE_STEREOSCOPIC_OVERUNDER", {
+            get: function () {
+                return Camera._RIG_MODE_STEREOSCOPIC_OVERUNDER;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Camera, "RIG_MODE_VR", {
+            get: function () {
+                return Camera._RIG_MODE_VR;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Camera.prototype, "globalPosition", {
             get: function () {
                 return this._globalPosition;
@@ -126,19 +240,29 @@ var BABYLON;
         Camera.prototype._isSynchronizedViewMatrix = function () {
             if (!_super.prototype._isSynchronized.call(this))
                 return false;
-            return this._cache.position.equals(this.position) && this._cache.upVector.equals(this.upVector) && this.isSynchronizedWithParent();
+            return this._cache.position.equals(this.position)
+                && this._cache.upVector.equals(this.upVector)
+                && this.isSynchronizedWithParent();
         };
         Camera.prototype._isSynchronizedProjectionMatrix = function () {
-            var check = this._cache.mode === this.mode && this._cache.minZ === this.minZ && this._cache.maxZ === this.maxZ;
+            var check = this._cache.mode === this.mode
+                && this._cache.minZ === this.minZ
+                && this._cache.maxZ === this.maxZ;
             if (!check) {
                 return false;
             }
             var engine = this.getEngine();
             if (this.mode === Camera.PERSPECTIVE_CAMERA) {
-                check = this._cache.fov === this.fov && this._cache.aspectRatio === engine.getAspectRatio(this);
+                check = this._cache.fov === this.fov
+                    && this._cache.aspectRatio === engine.getAspectRatio(this);
             }
             else {
-                check = this._cache.orthoLeft === this.orthoLeft && this._cache.orthoRight === this.orthoRight && this._cache.orthoBottom === this.orthoBottom && this._cache.orthoTop === this.orthoTop && this._cache.renderWidth === engine.getRenderWidth() && this._cache.renderHeight === engine.getRenderHeight();
+                check = this._cache.orthoLeft === this.orthoLeft
+                    && this._cache.orthoRight === this.orthoRight
+                    && this._cache.orthoBottom === this.orthoBottom
+                    && this._cache.orthoTop === this.orthoTop
+                    && this._cache.renderWidth === engine.getRenderWidth()
+                    && this._cache.renderHeight === engine.getRenderHeight();
             }
             return check;
         };
@@ -148,6 +272,12 @@ var BABYLON;
         Camera.prototype.detachControl = function (element) {
         };
         Camera.prototype._update = function () {
+            this._checkInputs();
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
+                this._updateRigCameras();
+            }
+        };
+        Camera.prototype._checkInputs = function () {
         };
         Camera.prototype.attachPostProcess = function (postProcess, insertAt) {
             if (insertAt === void 0) { insertAt = null; }
@@ -226,20 +356,25 @@ var BABYLON;
         Camera.prototype._getViewMatrix = function () {
             return BABYLON.Matrix.Identity();
         };
-        Camera.prototype.getViewMatrix = function () {
-            this._computedViewMatrix = this._computeViewMatrix();
-            if (!this.parent || !this.parent.getWorldMatrix || this.isSynchronized()) {
-                this._globalPosition.copyFrom(this.position);
+        Camera.prototype.getViewMatrix = function (force) {
+            this._computedViewMatrix = this._computeViewMatrix(force);
+            if (!force && this._isSynchronizedViewMatrix()) {
                 return this._computedViewMatrix;
             }
-            if (!this._worldMatrix) {
-                this._worldMatrix = BABYLON.Matrix.Identity();
+            if (!this.parent || !this.parent.getWorldMatrix) {
+                this._globalPosition.copyFrom(this.position);
+            }
+            else {
+                if (!this._worldMatrix) {
+                    this._worldMatrix = BABYLON.Matrix.Identity();
+                }
+                this._computedViewMatrix.invertToRef(this._worldMatrix);
+                this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
+                this._globalPosition.copyFromFloats(this._computedViewMatrix.m[12], this._computedViewMatrix.m[13], this._computedViewMatrix.m[14]);
+                this._computedViewMatrix.invert();
+                this._markSyncedWithParent();
             }
-            this._computedViewMatrix.invertToRef(this._worldMatrix);
-            this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
-            this._computedViewMatrix.invert();
             this._currentRenderId = this.getScene().getRenderId();
-            this._globalPosition.copyFromFloats(this._computedViewMatrix.m[12], this._computedViewMatrix.m[13], this._computedViewMatrix.m[14]);
             return this._computedViewMatrix;
         };
         Camera.prototype._computeViewMatrix = function (force) {
@@ -247,9 +382,7 @@ var BABYLON;
                 return this._computedViewMatrix;
             }
             this._computedViewMatrix = this._getViewMatrix();
-            if (!this.parent || !this.parent.getWorldMatrix) {
-                this._currentRenderId = this.getScene().getRenderId();
-            }
+            this._currentRenderId = this.getScene().getRenderId();
             return this._computedViewMatrix;
         };
         Camera.prototype.getProjectionMatrix = function (force) {
@@ -272,15 +405,123 @@ var BABYLON;
         Camera.prototype.dispose = function () {
             // Remove from scene
             this.getScene().removeCamera(this);
+            while (this._rigCameras.length > 0) {
+                this._rigCameras.pop().dispose();
+            }
+            // Postprocesses
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
             }
         };
+        // ---- Camera rigs section ----
+        Camera.prototype.setCameraRigMode = function (mode, rigParams) {
+            while (this._rigCameras.length > 0) {
+                this._rigCameras.pop().dispose();
+            }
+            this.cameraRigMode = mode;
+            this._cameraRigParams = {};
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    this._cameraRigParams.interaxialDistance = rigParams.interaxialDistance || 0.0637;
+                    //we have to implement stereo camera calcultating left and right viewpoints from interaxialDistance and target, 
+                    //not from a given angle as it is now, but until that complete code rewriting provisional stereoHalfAngle value is introduced
+                    this._cameraRigParams.stereoHalfAngle = BABYLON.Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
+                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
+                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
+                    break;
+            }
+            var postProcesses = new Array();
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                    postProcesses.push(new BABYLON.PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]));
+                    this._rigCameras[0].isIntermediate = true;
+                    postProcesses.push(new BABYLON.AnaglyphPostProcess(this.name + "_anaglyph", 1.0, this._rigCameras[1]));
+                    postProcesses[1].onApply = function (effect) {
+                        effect.setTextureFromPostProcess("leftSampler", postProcesses[0]);
+                    };
+                    break;
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    var isStereoscopicHoriz = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED);
+                    var firstCamIndex = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? 1 : 0;
+                    var secondCamIndex = 1 - firstCamIndex;
+                    postProcesses.push(new BABYLON.PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[firstCamIndex]));
+                    this._rigCameras[firstCamIndex].isIntermediate = true;
+                    postProcesses.push(new BABYLON.StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras[secondCamIndex], postProcesses[0], isStereoscopicHoriz));
+                    break;
+                case Camera.RIG_MODE_VR:
+                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
+                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
+                    var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
+                    this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
+                    this._rigCameras[0].viewport = new BABYLON.Viewport(0, 0, 0.5, 1.0);
+                    this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new BABYLON.Matrix();
+                    this._rigCameras[0]._cameraRigParams.vrHMatrix = metrics.leftHMatrix;
+                    this._rigCameras[0]._cameraRigParams.vrPreViewMatrix = metrics.leftPreViewMatrix;
+                    this._rigCameras[0].getProjectionMatrix = this._rigCameras[0]._getVRProjectionMatrix;
+                    if (metrics.compensateDistorsion) {
+                        postProcesses.push(new BABYLON.VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics));
+                    }
+                    this._rigCameras[1]._cameraRigParams.vrMetrics = this._rigCameras[0]._cameraRigParams.vrMetrics;
+                    this._rigCameras[1].viewport = new BABYLON.Viewport(0.5, 0, 0.5, 1.0);
+                    this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new BABYLON.Matrix();
+                    this._rigCameras[1]._cameraRigParams.vrHMatrix = metrics.rightHMatrix;
+                    this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
+                    this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
+                    if (metrics.compensateDistorsion) {
+                        postProcesses.push(new BABYLON.VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics));
+                    }
+                    break;
+            }
+            this._update();
+        };
+        Camera.prototype._getVRProjectionMatrix = function () {
+            BABYLON.Matrix.PerspectiveFovLHToRef(this._cameraRigParams.vrMetrics.aspectRatioFov, this._cameraRigParams.vrMetrics.aspectRatio, this.minZ, this.maxZ, this._cameraRigParams.vrWorkMatrix);
+            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
+            return this._projectionMatrix;
+        };
+        Camera.prototype.setCameraRigParameter = function (name, value) {
+            this._cameraRigParams[name] = value;
+            //provisionnally:
+            if (name === "interaxialDistance") {
+                this._cameraRigParams.stereoHalfAngle = BABYLON.Tools.ToRadians(value / 0.0637);
+            }
+        };
+        /**
+         * May needs to be overridden by children so sub has required properties to be copied
+         */
+        Camera.prototype.createRigCamera = function (name, cameraIndex) {
+            return null;
+        };
+        /**
+         * May needs to be overridden by children
+         */
+        Camera.prototype._updateRigCameras = function () {
+            for (var i = 0; i < this._rigCameras.length; i++) {
+                this._rigCameras[i].minZ = this.minZ;
+                this._rigCameras[i].maxZ = this.maxZ;
+                this._rigCameras[i].fov = this.fov;
+            }
+            // only update viewport when ANAGLYPH
+            if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
+                this._rigCameras[0].viewport = this._rigCameras[1].viewport = this.viewport;
+            }
+        };
         // Statics
         Camera._PERSPECTIVE_CAMERA = 0;
         Camera._ORTHOGRAPHIC_CAMERA = 1;
         Camera._FOVMODE_VERTICAL_FIXED = 0;
         Camera._FOVMODE_HORIZONTAL_FIXED = 1;
+        Camera._RIG_MODE_NONE = 0;
+        Camera._RIG_MODE_STEREOSCOPIC_ANAGLYPH = 10;
+        Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL = 11;
+        Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED = 12;
+        Camera._RIG_MODE_STEREOSCOPIC_OVERUNDER = 13;
+        Camera._RIG_MODE_VR = 20;
         return Camera;
     })(BABYLON.Node);
     BABYLON.Camera = Camera;

+ 253 - 21
Babylon/Cameras/babylon.camera.ts

@@ -1,4 +1,70 @@
 module BABYLON {
+
+    export class VRCameraMetrics {
+        public hResolution: number;
+        public vResolution: number;
+        public hScreenSize: number;
+        public vScreenSize: number;
+        public vScreenCenter: number;
+        public eyeToScreenDistance: number;
+        public lensSeparationDistance: number;
+        public interpupillaryDistance: number;
+        public distortionK: number[];
+        public chromaAbCorrection: number[];
+        public postProcessScaleFactor: number;
+        public lensCenterOffset: number;
+        public compensateDistorsion = true;
+
+        public get aspectRatio(): number {
+            return this.hResolution / (2 * this.vResolution);
+        }
+
+        public get aspectRatioFov(): number {
+            return (2 * Math.atan((this.postProcessScaleFactor * this.vScreenSize) / (2 * this.eyeToScreenDistance)));
+        }
+
+        public get leftHMatrix(): Matrix {
+            var meters = (this.hScreenSize / 4) - (this.lensSeparationDistance / 2);
+            var h = (4 * meters) / this.hScreenSize;
+
+            return Matrix.Translation(h, 0, 0);
+        }
+
+        public get rightHMatrix(): Matrix {
+            var meters = (this.hScreenSize / 4) - (this.lensSeparationDistance / 2);
+            var h = (4 * meters) / this.hScreenSize;
+
+            return Matrix.Translation(-h, 0, 0);
+        }
+
+        public get leftPreViewMatrix(): Matrix {
+            return Matrix.Translation(0.5 * this.interpupillaryDistance, 0, 0);
+        }
+
+        public get rightPreViewMatrix(): Matrix {
+            return Matrix.Translation(-0.5 * this.interpupillaryDistance, 0, 0);
+        }
+
+        public static GetDefault(): VRCameraMetrics {
+            var result = new VRCameraMetrics();
+
+            result.hResolution = 1280;
+            result.vResolution = 800;
+            result.hScreenSize = 0.149759993;
+            result.vScreenSize = 0.0935999975;
+            result.vScreenCenter = 0.0467999987,
+            result.eyeToScreenDistance = 0.0410000011;
+            result.lensSeparationDistance = 0.0635000020;
+            result.interpupillaryDistance = 0.0640000030;
+            result.distortionK = [1.0, 0.219999999, 0.239999995, 0.0];
+            result.chromaAbCorrection = [0.995999992, -0.00400000019, 1.01400006, 0.0];
+            result.postProcessScaleFactor = 1.714605507808412;
+            result.lensCenterOffset = 0.151976421;
+
+            return result;
+        }
+    }
+
     export class Camera extends Node {
         // Statics
         private static _PERSPECTIVE_CAMERA = 0;
@@ -7,10 +73,17 @@
         private static _FOVMODE_VERTICAL_FIXED = 0;
         private static _FOVMODE_HORIZONTAL_FIXED = 1;
 
+        private static _RIG_MODE_NONE = 0;        
+        private static _RIG_MODE_STEREOSCOPIC_ANAGLYPH = 10;
+        private static _RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL = 11;
+        private static _RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED = 12;
+        private static _RIG_MODE_STEREOSCOPIC_OVERUNDER = 13;
+        private static _RIG_MODE_VR = 20;
+
         public static get PERSPECTIVE_CAMERA(): number {
             return Camera._PERSPECTIVE_CAMERA;
         }
-        
+
         public static get ORTHOGRAPHIC_CAMERA(): number {
             return Camera._ORTHOGRAPHIC_CAMERA;
         }
@@ -23,6 +96,30 @@
             return Camera._FOVMODE_HORIZONTAL_FIXED;
         }
 
+        public static get RIG_MODE_NONE(): number {
+            return Camera._RIG_MODE_NONE;
+        }
+
+        public static get RIG_MODE_STEREOSCOPIC_ANAGLYPH(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_ANAGLYPH;
+        }
+
+        public static get RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL;
+        }
+        
+        public static get RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
+        }
+
+        public static get RIG_MODE_STEREOSCOPIC_OVERUNDER(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_OVERUNDER;
+        }        
+
+        public static get RIG_MODE_VR(): number {
+            return Camera._RIG_MODE_VR;
+        }
+        
         // Members
         public upVector = Vector3.Up();
         public orthoLeft = null;
@@ -36,10 +133,15 @@
         public mode = Camera.PERSPECTIVE_CAMERA;
         public isIntermediate = false;
         public viewport = new Viewport(0, 0, 1.0, 1.0);
-        public subCameras = [];
-        public layerMask: number = 0xFFFFFFFF;
+        public layerMask: number = 0x0FFFFFFF;
         public fovMode: number = Camera.FOVMODE_VERTICAL_FIXED;
+   
+        // Camera rig members
+        public cameraRigMode = Camera.RIG_MODE_NONE;
+        public _cameraRigParams: any;
+        public _rigCameras = new Array<Camera>();
 
+        // Cache
         private _computedViewMatrix = Matrix.Identity();
         public _projectionMatrix = new Matrix();
         private _worldMatrix: Matrix;
@@ -173,6 +275,13 @@
         }
 
         public _update(): void {
+            this._checkInputs();
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
+                this._updateRigCameras();
+            }
+        }
+
+        public _checkInputs(): void {
         }
 
         public attachPostProcess(postProcess: PostProcess, insertAt: number = null): number {
@@ -281,30 +390,31 @@
             return Matrix.Identity();
         }
 
-        public getViewMatrix(): Matrix {
-            this._computedViewMatrix = this._computeViewMatrix();
-
-            if (!this.parent
-                || !this.parent.getWorldMatrix
-                || this.isSynchronized()) {
-
-                this._globalPosition.copyFrom(this.position);
+        public getViewMatrix(force?: boolean): Matrix {
+            this._computedViewMatrix = this._computeViewMatrix(force);
 
+            if (!force && this._isSynchronizedViewMatrix()) {
                 return this._computedViewMatrix;
             }
 
-            if (!this._worldMatrix) {
-                this._worldMatrix = Matrix.Identity();
-            }
+            if (!this.parent || !this.parent.getWorldMatrix) {
+                this._globalPosition.copyFrom(this.position);
+            } else {
+                if (!this._worldMatrix) {
+                    this._worldMatrix = Matrix.Identity();
+                }
 
-            this._computedViewMatrix.invertToRef(this._worldMatrix);
+                this._computedViewMatrix.invertToRef(this._worldMatrix);
 
-            this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
+                this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
+                this._globalPosition.copyFromFloats(this._computedViewMatrix.m[12], this._computedViewMatrix.m[13], this._computedViewMatrix.m[14]);
 
-            this._computedViewMatrix.invert();
+                this._computedViewMatrix.invert();
+
+                this._markSyncedWithParent();
+            }
 
             this._currentRenderId = this.getScene().getRenderId();
-            this._globalPosition.copyFromFloats(this._computedViewMatrix.m[12], this._computedViewMatrix.m[13], this._computedViewMatrix.m[14]);
 
             return this._computedViewMatrix;
         }
@@ -315,9 +425,8 @@
             }
 
             this._computedViewMatrix = this._getViewMatrix();
-            if (!this.parent || !this.parent.getWorldMatrix) {
-                this._currentRenderId = this.getScene().getRenderId();
-            }
+            this._currentRenderId = this.getScene().getRenderId();
+
             return this._computedViewMatrix;
         }
 
@@ -345,11 +454,134 @@
         public dispose(): void {
             // Remove from scene
             this.getScene().removeCamera(this);
+            while (this._rigCameras.length > 0) {
+                this._rigCameras.pop().dispose();
+            }
 
             // Postprocesses
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
             }
         }
+        
+        // ---- Camera rigs section ----
+        public setCameraRigMode(mode: number, rigParams: any): void {
+            while (this._rigCameras.length > 0) {
+                this._rigCameras.pop().dispose();
+            }
+            this.cameraRigMode = mode;
+            this._cameraRigParams = {};
+        
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    this._cameraRigParams.interaxialDistance = rigParams.interaxialDistance || 0.0637;
+                    //we have to implement stereo camera calcultating left and right viewpoints from interaxialDistance and target, 
+                    //not from a given angle as it is now, but until that complete code rewriting provisional stereoHalfAngle value is introduced
+                    this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
+                    
+                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
+                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
+                break;
+            }
+            
+            var postProcesses = new Array<PostProcess>();
+            
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                    postProcesses.push(new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]));
+                    this._rigCameras[0].isIntermediate = true;
+
+                    postProcesses.push(new AnaglyphPostProcess(this.name + "_anaglyph", 1.0, this._rigCameras[1]));
+                    postProcesses[1].onApply = effect => {
+                        effect.setTextureFromPostProcess("leftSampler", postProcesses[0]);
+                    };
+                    break;
+
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    var isStereoscopicHoriz = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED);
+                    var firstCamIndex = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED)? 1 : 0;
+                    var secondCamIndex = 1 - firstCamIndex;
+                    
+                    postProcesses.push(new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[firstCamIndex]));
+                    this._rigCameras[firstCamIndex].isIntermediate = true;
+
+                    postProcesses.push(new StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras[secondCamIndex], postProcesses[0], isStereoscopicHoriz));
+                    break;
+
+                case Camera.RIG_MODE_VR:
+                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
+                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
+                    
+                    var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
+                    this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
+                    this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
+                    this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
+
+                    this._rigCameras[0]._cameraRigParams.vrHMatrix = metrics.leftHMatrix;
+                    this._rigCameras[0]._cameraRigParams.vrPreViewMatrix = metrics.leftPreViewMatrix;
+                    this._rigCameras[0].getProjectionMatrix = this._rigCameras[0]._getVRProjectionMatrix;
+
+                    if (metrics.compensateDistorsion) {
+                        postProcesses.push(new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics));
+                    }
+
+                    this._rigCameras[1]._cameraRigParams.vrMetrics = this._rigCameras[0]._cameraRigParams.vrMetrics;
+                    this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
+                    this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
+                    this._rigCameras[1]._cameraRigParams.vrHMatrix = metrics.rightHMatrix;
+                    this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
+
+                    this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
+
+                    if (metrics.compensateDistorsion) {
+                        postProcesses.push(new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics));
+                    }
+                    break;
+            }
+            
+            this._update();
+        }
+
+        private _getVRProjectionMatrix(): Matrix {
+            Matrix.PerspectiveFovLHToRef(this._cameraRigParams.vrMetrics.aspectRatioFov, this._cameraRigParams.vrMetrics.aspectRatio, this.minZ, this.maxZ, this._cameraRigParams.vrWorkMatrix);
+            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
+            return this._projectionMatrix;
+        }
+
+        public setCameraRigParameter(name: string, value: any) {
+            this._cameraRigParams[name] = value;
+            //provisionnally:
+            if (name === "interaxialDistance") { 
+		this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(value / 0.0637); 
+            }
+        }
+        
+        /**
+         * May needs to be overridden by children so sub has required properties to be copied
+         */
+        public createRigCamera(name: string, cameraIndex: number): Camera {
+            return null;
+        }
+        
+        /**
+         * May needs to be overridden by children
+         */
+        public _updateRigCameras() {
+            for (var i=0 ; i<this._rigCameras.length ; i++) {
+                this._rigCameras[i].minZ = this.minZ;
+                this._rigCameras[i].maxZ = this.maxZ;
+                this._rigCameras[i].fov = this.fov;
+            }
+            
+            // only update viewport when ANAGLYPH
+            if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
+                this._rigCameras[0].viewport = this._rigCameras[1].viewport = this.viewport;
+            }
+        }
     }
 }

+ 2 - 1
Babylon/Cameras/babylon.deviceOrientationCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -64,6 +64,7 @@ var BABYLON;
             var direction = new BABYLON.Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
             BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
             this.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
+            _super.prototype._checkInputs.call(this);
         };
         return DeviceOrientationCamera;
     })(BABYLON.FreeCamera);

+ 5 - 3
Babylon/Cameras/babylon.deviceOrientationCamera.ts

@@ -67,10 +67,12 @@ module BABYLON {
             this.cameraRotation.y -= this._offsetX / this.angularSensibility;
 
             var speed = this._computeLocalCameraSpeed();
-            var direction = new BABYLON.Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
+            var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
 
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-            this.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
+            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
+            this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
+
+            super._checkInputs();
         }
     }
 }

+ 13 - 4
Babylon/Cameras/babylon.followCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -22,7 +22,16 @@ var BABYLON;
         FollowCamera.prototype.follow = function (cameraTarget) {
             if (!cameraTarget)
                 return;
-            var radians = this.getRadians(this.rotationOffset) + cameraTarget.rotation.y;
+            var yRotation;
+            if (cameraTarget.rotationQuaternion) {
+                var rotMatrix = new BABYLON.Matrix();
+                cameraTarget.rotationQuaternion.toRotationMatrix(rotMatrix);
+                yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
+            }
+            else {
+                yRotation = cameraTarget.rotation.y;
+            }
+            var radians = this.getRadians(this.rotationOffset) + yRotation;
             var targetX = cameraTarget.position.x + Math.sin(radians) * this.radius;
             var targetZ = cameraTarget.position.z + Math.cos(radians) * this.radius;
             var dx = targetX - this.position.x;
@@ -43,8 +52,8 @@ var BABYLON;
             this.position = new BABYLON.Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
             this.setTarget(cameraTarget.position);
         };
-        FollowCamera.prototype._update = function () {
-            _super.prototype._update.call(this);
+        FollowCamera.prototype._checkInputs = function () {
+            _super.prototype._checkInputs.call(this);
             this.follow(this.target);
         };
         return FollowCamera;

+ 12 - 4
Babylon/Cameras/babylon.followCamera.ts

@@ -19,8 +19,16 @@
         private follow(cameraTarget:AbstractMesh) {
             if (!cameraTarget)
                 return;
-
-            var radians = this.getRadians(this.rotationOffset) + cameraTarget.rotation.y;
+            
+            var yRotation;
+            if (cameraTarget.rotationQuaternion) {
+                var rotMatrix = new Matrix();
+                cameraTarget.rotationQuaternion.toRotationMatrix(rotMatrix);
+                yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
+            } else {
+                yRotation = cameraTarget.rotation.y;
+            }
+            var radians = this.getRadians(this.rotationOffset) + yRotation;
             var targetX:number = cameraTarget.position.x + Math.sin(radians) * this.radius;
 
             var targetZ:number = cameraTarget.position.z + Math.cos(radians) * this.radius;
@@ -47,8 +55,8 @@
             this.setTarget(cameraTarget.position);
         }
 
-        public _update():void {
-            super._update();
+        public _checkInputs():void {
+            super._checkInputs();
             this.follow(this.target);
         }
     }

+ 35 - 20
Babylon/Cameras/babylon.freeCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -9,6 +9,7 @@ var BABYLON;
     var FreeCamera = (function (_super) {
         __extends(FreeCamera, _super);
         function FreeCamera(name, position, scene) {
+            var _this = this;
             _super.call(this, name, position, scene);
             this.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
             this.keysUp = [38];
@@ -20,10 +21,28 @@ var BABYLON;
             this.angularSensibility = 2000.0;
             this._keys = [];
             this._collider = new BABYLON.Collider();
-            this._needMoveForGravity = true;
+            this._needMoveForGravity = false;
             this._oldPosition = BABYLON.Vector3.Zero();
             this._diffPosition = BABYLON.Vector3.Zero();
             this._newPosition = BABYLON.Vector3.Zero();
+            this._onCollisionPositionChange = function (collisionId, newPosition, collidedMesh) {
+                if (collidedMesh === void 0) { collidedMesh = null; }
+                //TODO move this to the collision coordinator!
+                if (_this.getScene().workerCollisions)
+                    newPosition.multiplyInPlace(_this._collider.radius);
+                var updatePosition = function (newPos) {
+                    _this._newPosition.copyFrom(newPos);
+                    _this._newPosition.subtractToRef(_this._oldPosition, _this._diffPosition);
+                    var oldPosition = _this.position.clone();
+                    if (_this._diffPosition.length() > BABYLON.Engine.CollisionsEpsilon) {
+                        _this.position.addInPlace(_this._diffPosition);
+                        if (_this.onCollide && collidedMesh) {
+                            _this.onCollide(collidedMesh);
+                        }
+                    }
+                };
+                updatePosition(newPosition);
+            };
         }
         // Controls
         FreeCamera.prototype.attachControl = function (element, noPreventDefault) {
@@ -82,7 +101,10 @@ var BABYLON;
                     }
                 };
                 this._onKeyDown = function (evt) {
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
                         var index = _this._keys.indexOf(evt.keyCode);
                         if (index === -1) {
                             _this._keys.push(evt.keyCode);
@@ -93,7 +115,10 @@ var BABYLON;
                     }
                 };
                 this._onKeyUp = function (evt) {
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 || _this.keysDown.indexOf(evt.keyCode) !== -1 || _this.keysLeft.indexOf(evt.keyCode) !== -1 || _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
                         var index = _this._keys.indexOf(evt.keyCode);
                         if (index >= 0) {
                             _this._keys.splice(index, 1);
@@ -151,20 +176,18 @@ var BABYLON;
             }
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
             this._collider.radius = this.ellipsoid;
-            this.getScene()._getNewPosition(this._oldPosition, velocity, this._collider, 3, this._newPosition);
-            this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
-            if (this._diffPosition.length() > BABYLON.Engine.CollisionsEpsilon) {
-                this.position.addInPlace(this._diffPosition);
-                if (this.onCollide) {
-                    this.onCollide(this._collider.collidedMesh);
-                }
+            //add gravity to the velocity to prevent the dual-collision checking
+            if (this.applyGravity) {
+                velocity.addInPlace(this.getScene().gravity);
             }
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, velocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
         };
         FreeCamera.prototype._checkInputs = function () {
             if (!this._localDirection) {
                 this._localDirection = BABYLON.Vector3.Zero();
                 this._transformedDirection = BABYLON.Vector3.Zero();
             }
+            // Keyboard
             for (var index = 0; index < this._keys.length; index++) {
                 var keyCode = this._keys[index];
                 var speed = this._computeLocalCameraSpeed();
@@ -184,6 +207,7 @@ var BABYLON;
                 BABYLON.Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
                 this.cameraDirection.addInPlace(this._transformedDirection);
             }
+            _super.prototype._checkInputs.call(this);
         };
         FreeCamera.prototype._decideIfNeedsToMove = function () {
             return this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
@@ -191,20 +215,11 @@ var BABYLON;
         FreeCamera.prototype._updatePosition = function () {
             if (this.checkCollisions && this.getScene().collisionsEnabled) {
                 this._collideWithWorld(this.cameraDirection);
-                if (this.applyGravity) {
-                    var oldPosition = this.position;
-                    this._collideWithWorld(this.getScene().gravity);
-                    this._needMoveForGravity = (BABYLON.Vector3.DistanceSquared(oldPosition, this.position) != 0);
-                }
             }
             else {
                 this.position.addInPlace(this.cameraDirection);
             }
         };
-        FreeCamera.prototype._update = function () {
-            this._checkInputs();
-            _super.prototype._update.call(this);
-        };
         return FreeCamera;
     })(BABYLON.TargetCamera);
     BABYLON.FreeCamera = FreeCamera;

+ 39 - 28
Babylon/Cameras/babylon.freeCamera.ts

@@ -1,6 +1,6 @@
 module BABYLON {
     export class FreeCamera extends TargetCamera {
-        public ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
+        public ellipsoid = new Vector3(0.5, 1, 0.5);
         public keysUp = [38];
         public keysDown = [40];
         public keysLeft = [37];
@@ -12,10 +12,10 @@
 
         private _keys = [];
         private _collider = new Collider();
-        private _needMoveForGravity = true;
-        private _oldPosition = BABYLON.Vector3.Zero();
-        private _diffPosition = BABYLON.Vector3.Zero();
-        private _newPosition = BABYLON.Vector3.Zero();
+        private _needMoveForGravity = false;
+        private _oldPosition = Vector3.Zero();
+        private _diffPosition = Vector3.Zero();
+        private _newPosition = Vector3.Zero();
         private _attachedElement: HTMLElement;
         private _localDirection: Vector3;
         private _transformedDirection: Vector3;
@@ -138,8 +138,8 @@
                 this._reset = () => {
                     this._keys = [];
                     previousPosition = null;
-                    this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
-                    this.cameraRotation = new BABYLON.Vector2(0, 0);
+                    this.cameraDirection = new Vector3(0, 0, 0);
+                    this.cameraRotation = new Vector2(0, 0);
                 };
             }
 
@@ -181,7 +181,7 @@
             var globalPosition: Vector3;
 
             if (this.parent) {
-                globalPosition = BABYLON.Vector3.TransformCoordinates(this.position, this.parent.getWorldMatrix());
+                globalPosition = Vector3.TransformCoordinates(this.position, this.parent.getWorldMatrix());
             } else {
                 globalPosition = this.position;
             }
@@ -189,21 +189,41 @@
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
             this._collider.radius = this.ellipsoid;
 
-            this.getScene()._getNewPosition(this._oldPosition, velocity, this._collider, 3, this._newPosition);
-            this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
+            //add gravity to the velocity to prevent the dual-collision checking
+            if (this.applyGravity) {
+                velocity.addInPlace(this.getScene().gravity);
+            }
+
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, velocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
+
+        }
+
+        private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: AbstractMesh = null) => {
+            //TODO move this to the collision coordinator!
+            if (this.getScene().workerCollisions)
+                newPosition.multiplyInPlace(this._collider.radius);
+
+            var updatePosition = (newPos) => {
+                this._newPosition.copyFrom(newPos);
+
+                this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
 
-            if (this._diffPosition.length() > Engine.CollisionsEpsilon) {
-                this.position.addInPlace(this._diffPosition);
-                if (this.onCollide) {
-                    this.onCollide(this._collider.collidedMesh);
+                var oldPosition = this.position.clone();
+                if (this._diffPosition.length() > Engine.CollisionsEpsilon) {
+                    this.position.addInPlace(this._diffPosition);
+                    if (this.onCollide && collidedMesh) {
+                        this.onCollide(collidedMesh);
+                    }
                 }
             }
+
+            updatePosition(newPosition);
         }
 
         public _checkInputs(): void {
             if (!this._localDirection) {
-                this._localDirection = BABYLON.Vector3.Zero();
-                this._transformedDirection = BABYLON.Vector3.Zero();
+                this._localDirection = Vector3.Zero();
+                this._transformedDirection = Vector3.Zero();
             }
 
             // Keyboard
@@ -222,9 +242,11 @@
                 }
 
                 this.getViewMatrix().invertToRef(this._cameraTransformMatrix);
-                BABYLON.Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
+                Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
                 this.cameraDirection.addInPlace(this._transformedDirection);
             }
+
+            super._checkInputs();
         }
 
         public _decideIfNeedsToMove(): boolean {
@@ -234,20 +256,9 @@
         public _updatePosition(): void {
             if (this.checkCollisions && this.getScene().collisionsEnabled) {
                 this._collideWithWorld(this.cameraDirection);
-                if (this.applyGravity) {
-                    var oldPosition = this.position;
-                    this._collideWithWorld(this.getScene().gravity);
-                    this._needMoveForGravity = (BABYLON.Vector3.DistanceSquared(oldPosition, this.position) != 0);
-                }
             } else {
                 this.position.addInPlace(this.cameraDirection);
             }
         }
-
-        public _update(): void {
-            this._checkInputs();
-            super._update();
-        }
-
     }
 } 

+ 19 - 22
Babylon/Cameras/babylon.gamepadCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -14,9 +14,7 @@ var BABYLON;
             _super.call(this, name, position, scene);
             this.angularSensibility = 200;
             this.moveSensibility = 75;
-            this._gamepads = new BABYLON.Gamepads(function (gamepad) {
-                _this._onNewGameConnected(gamepad);
-            });
+            this._gamepads = new BABYLON.Gamepads(function (gamepad) { _this._onNewGameConnected(gamepad); });
         }
         GamepadCamera.prototype._onNewGameConnected = function (gamepad) {
             // Only the first gamepad can control the camera
@@ -25,25 +23,24 @@ var BABYLON;
             }
         };
         GamepadCamera.prototype._checkInputs = function () {
-            if (!this._gamepad) {
-                return;
+            if (this._gamepad) {
+                var LSValues = this._gamepad.leftStick;
+                var normalizedLX = LSValues.x / this.moveSensibility;
+                var normalizedLY = LSValues.y / this.moveSensibility;
+                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
+                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
+                var RSValues = this._gamepad.rightStick;
+                var normalizedRX = RSValues.x / this.angularSensibility;
+                var normalizedRY = RSValues.y / this.angularSensibility;
+                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
+                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
+                var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+                var speed = this._computeLocalCameraSpeed() * 50.0;
+                var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
+                this.cameraDirection = this.cameraDirection.add(deltaTransform);
+                this.cameraRotation = this.cameraRotation.add(new BABYLON.Vector2(RSValues.y, RSValues.x));
             }
-            var LSValues = this._gamepad.leftStick;
-            var normalizedLX = LSValues.x / this.moveSensibility;
-            var normalizedLY = LSValues.y / this.moveSensibility;
-            LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-            LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-            var RSValues = this._gamepad.rightStick;
-            var normalizedRX = RSValues.x / this.angularSensibility;
-            var normalizedRY = RSValues.y / this.angularSensibility;
-            RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
-            RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
-            ;
-            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var speed = this._computeLocalCameraSpeed() * 50.0;
-            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-            this.cameraRotation = this.cameraRotation.add(new BABYLON.Vector2(RSValues.y, RSValues.x));
+            _super.prototype._checkInputs.call(this);
         };
         GamepadCamera.prototype.dispose = function () {
             this._gamepads.dispose();

+ 24 - 24
Babylon/Cameras/babylon.gamepadCamera.ts

@@ -1,17 +1,17 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     export class GamepadCamera extends FreeCamera {
-        private _gamepad: BABYLON.Gamepad;
-        private _gamepads: BABYLON.Gamepads;
+        private _gamepad: Gamepad;
+        private _gamepads: Gamepads;
         public angularSensibility = 200;
         public moveSensibility = 75;
 
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
-            this._gamepads = new BABYLON.Gamepads((gamepad: BABYLON.Gamepad) => { this._onNewGameConnected(gamepad); });
+            this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
         }
 
-        private _onNewGameConnected(gamepad: BABYLON.Gamepad) {
+        private _onNewGameConnected(gamepad: Gamepad) {
             // Only the first gamepad can control the camera
             if (gamepad.index === 0) {
                 this._gamepad = gamepad;
@@ -19,28 +19,28 @@ module BABYLON {
         }
 
         public _checkInputs(): void {
-            if (!this._gamepad) {
-                return;
+            if (this._gamepad) {
+                var LSValues = this._gamepad.leftStick;
+                var normalizedLX = LSValues.x / this.moveSensibility;
+                var normalizedLY = LSValues.y / this.moveSensibility;
+                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
+                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
+
+                var RSValues = this._gamepad.rightStick;
+                var normalizedRX = RSValues.x / this.angularSensibility;
+                var normalizedRY = RSValues.y / this.angularSensibility;
+                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
+                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
+
+                var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+
+                var speed = this._computeLocalCameraSpeed() * 50.0;
+                var deltaTransform = Vector3.TransformCoordinates(new Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
+                this.cameraDirection = this.cameraDirection.add(deltaTransform);
+                this.cameraRotation = this.cameraRotation.add(new Vector2(RSValues.y, RSValues.x));
             }
 
-            var LSValues = this._gamepad.leftStick;
-            var normalizedLX = LSValues.x / this.moveSensibility;
-            var normalizedLY = LSValues.y / this.moveSensibility;
-            LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-            LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-
-            var RSValues = this._gamepad.rightStick;
-            var normalizedRX = RSValues.x / this.angularSensibility;
-            var normalizedRY = RSValues.y / this.angularSensibility;
-            RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
-            RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;;
-
-            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-
-            var speed = this._computeLocalCameraSpeed() * 50.0;
-            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-            this.cameraRotation = this.cameraRotation.add(new BABYLON.Vector2(RSValues.y, RSValues.x));
+            super._checkInputs();
         }
 
         public dispose(): void {

+ 0 - 175
Babylon/Cameras/babylon.oculusGamepadCamera.js

@@ -1,175 +0,0 @@
-var __extends = this.__extends || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    __.prototype = b.prototype;
-    d.prototype = new __();
-};
-var BABYLON;
-(function (BABYLON) {
-    var 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
-    };
-
-    var _OculusInnerGamepadCamera = (function (_super) {
-        __extends(_OculusInnerGamepadCamera, _super);
-        function _OculusInnerGamepadCamera(name, position, scene, isLeftEye) {
-            _super.call(this, name, position, scene);
-            this._workMatrix = new BABYLON.Matrix();
-            this._actualUp = new BABYLON.Vector3(0, 0, 0);
-
-            // Constants
-            this._aspectRatioAspectRatio = OculusRiftDevKit2013_Metric.HResolution / (2 * OculusRiftDevKit2013_Metric.VResolution);
-            this._aspectRatioFov = (2 * Math.atan((OculusRiftDevKit2013_Metric.PostProcessScaleFactor * OculusRiftDevKit2013_Metric.VScreenSize) / (2 * OculusRiftDevKit2013_Metric.EyeToScreenDistance)));
-
-            var hMeters = (OculusRiftDevKit2013_Metric.HScreenSize / 4) - (OculusRiftDevKit2013_Metric.LensSeparationDistance / 2);
-            var h = (4 * hMeters) / OculusRiftDevKit2013_Metric.HScreenSize;
-
-            this._hMatrix = BABYLON.Matrix.Translation(isLeftEye ? h : -h, 0, 0);
-
-            this.viewport = new BABYLON.Viewport(isLeftEye ? 0 : 0.5, 0, 0.5, 1.0);
-
-            this._preViewMatrix = BABYLON.Matrix.Translation(isLeftEye ? .5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance : -.5 * OculusRiftDevKit2013_Metric.InterpupillaryDistance, 0, 0);
-
-            // Postprocess
-            var postProcess = new BABYLON.OculusDistortionCorrectionPostProcess("Oculus Distortion", this, !isLeftEye, OculusRiftDevKit2013_Metric);
-        }
-        _OculusInnerGamepadCamera.prototype.getProjectionMatrix = function () {
-            BABYLON.Matrix.PerspectiveFovLHToRef(this._aspectRatioFov, this._aspectRatioAspectRatio, this.minZ, this.maxZ, this._workMatrix);
-            this._workMatrix.multiplyToRef(this._hMatrix, this._projectionMatrix);
-            return this._projectionMatrix;
-        };
-
-        _OculusInnerGamepadCamera.prototype._getViewMatrix = function () {
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-
-            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            BABYLON.Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._actualUp);
-
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._actualUp, this._workMatrix);
-
-            this._workMatrix.multiplyToRef(this._preViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        };
-        return _OculusInnerGamepadCamera;
-    })(BABYLON.FreeCamera);
-
-    var OculusGamepadCamera = (function (_super) {
-        __extends(OculusGamepadCamera, _super);
-        function OculusGamepadCamera(name, position, scene) {
-            var _this = this;
-            _super.call(this, name, position, scene);
-            this.angularSensibility = 200;
-            this.moveSensibility = 75;
-
-            this._leftCamera = new _OculusInnerGamepadCamera(name + "_left", position.clone(), scene, true);
-            this._rightCamera = new _OculusInnerGamepadCamera(name + "_right", position.clone(), scene, false);
-
-            this.subCameras.push(this._leftCamera);
-            this.subCameras.push(this._rightCamera);
-
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
-            this._gamepads = new BABYLON.Gamepads(function (gamepad) {
-                _this._onNewGameConnected(gamepad);
-            });
-        }
-        OculusGamepadCamera.prototype._onNewGameConnected = function (gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this._gamepad = gamepad;
-            }
-        };
-
-        OculusGamepadCamera.prototype._update = function () {
-            this._leftCamera.position.copyFrom(this.position);
-            this._rightCamera.position.copyFrom(this.position);
-
-            this._updateCamera(this._leftCamera);
-            this._updateCamera(this._rightCamera);
-
-            _super.prototype._update.call(this);
-        };
-
-        OculusGamepadCamera.prototype._checkInputs = function () {
-            if (!this._gamepad) {
-                return;
-            }
-
-            var LSValues = this._gamepad.leftStick;
-            var normalizedLX = LSValues.x / this.moveSensibility;
-            var normalizedLY = LSValues.y / this.moveSensibility;
-            LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-            LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-
-            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x, 0, -LSValues.y), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-        };
-
-        OculusGamepadCamera.prototype._updateCamera = function (camera) {
-            camera.minZ = this.minZ;
-            camera.maxZ = this.maxZ;
-
-            camera.rotation.x = this.rotation.x;
-            camera.rotation.y = this.rotation.y;
-            camera.rotation.z = this.rotation.z;
-        };
-
-        // Oculus events
-        OculusGamepadCamera.prototype._onOrientationEvent = function (evt) {
-            var yaw = evt.alpha / 180 * Math.PI;
-            var pitch = evt.beta / 180 * Math.PI;
-            var roll = evt.gamma / 180 * Math.PI;
-
-            if (!this._offsetOrientation) {
-                this._offsetOrientation = {
-                    yaw: yaw,
-                    pitch: pitch,
-                    roll: roll
-                };
-                return;
-            } else {
-                this.rotation.y += yaw - this._offsetOrientation.yaw;
-                this.rotation.x += pitch - this._offsetOrientation.pitch;
-                this.rotation.z += this._offsetOrientation.roll - roll;
-
-                this._offsetOrientation.yaw = yaw;
-                this._offsetOrientation.pitch = pitch;
-                this._offsetOrientation.roll = roll;
-            }
-        };
-
-        OculusGamepadCamera.prototype.attachControl = function (element, noPreventDefault) {
-            _super.prototype.attachControl.call(this, element, noPreventDefault);
-
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
-
-        OculusGamepadCamera.prototype.detachControl = function (element) {
-            _super.prototype.detachControl.call(this, element);
-
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
-
-        OculusGamepadCamera.prototype.dispose = function () {
-            this._gamepads.dispose();
-            _super.prototype.dispose.call(this);
-        };
-        return OculusGamepadCamera;
-    })(BABYLON.FreeCamera);
-    BABYLON.OculusGamepadCamera = OculusGamepadCamera;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.oculusGamepadCamera.js.map

+ 64 - 0
Babylon/Cameras/babylon.stereoscopicCameras.js

@@ -0,0 +1,64 @@
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    var AnaglyphFreeCamera = (function (_super) {
+        __extends(AnaglyphFreeCamera, _super);
+        function AnaglyphFreeCamera(name, position, interaxialDistance, scene) {
+            _super.call(this, name, position, scene);
+            this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+        return AnaglyphFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
+    var AnaglyphArcRotateCamera = (function (_super) {
+        __extends(AnaglyphArcRotateCamera, _super);
+        function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, interaxialDistance, scene) {
+            _super.call(this, name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+        return AnaglyphArcRotateCamera;
+    })(BABYLON.ArcRotateCamera);
+    BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
+    var AnaglyphGamepadCamera = (function (_super) {
+        __extends(AnaglyphGamepadCamera, _super);
+        function AnaglyphGamepadCamera(name, position, interaxialDistance, scene) {
+            _super.call(this, name, position, scene);
+            this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+        return AnaglyphGamepadCamera;
+    })(BABYLON.GamepadCamera);
+    BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
+    var StereoscopicFreeCamera = (function (_super) {
+        __extends(StereoscopicFreeCamera, _super);
+        function StereoscopicFreeCamera(name, position, interaxialDistance, isSideBySide, scene) {
+            _super.call(this, name, position, scene);
+            this.setCameraRigMode(isSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+        return StereoscopicFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.StereoscopicFreeCamera = StereoscopicFreeCamera;
+    var StereoscopicArcRotateCamera = (function (_super) {
+        __extends(StereoscopicArcRotateCamera, _super);
+        function StereoscopicArcRotateCamera(name, alpha, beta, radius, target, interaxialDistance, isSideBySide, scene) {
+            _super.call(this, name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(isSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+        return StereoscopicArcRotateCamera;
+    })(BABYLON.ArcRotateCamera);
+    BABYLON.StereoscopicArcRotateCamera = StereoscopicArcRotateCamera;
+    var StereoscopicGamepadCamera = (function (_super) {
+        __extends(StereoscopicGamepadCamera, _super);
+        function StereoscopicGamepadCamera(name, position, interaxialDistance, isSideBySide, scene) {
+            _super.call(this, name, position, scene);
+            this.setCameraRigMode(isSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+        return StereoscopicGamepadCamera;
+    })(BABYLON.GamepadCamera);
+    BABYLON.StereoscopicGamepadCamera = StereoscopicGamepadCamera;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.stereoscopicCameras.js.map

+ 44 - 0
Babylon/Cameras/babylon.stereoscopicCameras.ts

@@ -0,0 +1,44 @@
+module BABYLON {
+    export class AnaglyphFreeCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class AnaglyphArcRotateCamera extends ArcRotateCamera {
+        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, scene: Scene) {
+            super(name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class AnaglyphGamepadCamera extends GamepadCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+    
+    export class StereoscopicFreeCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
+            super(name, position, scene);
+
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class StereoscopicArcRotateCamera extends ArcRotateCamera {
+        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, isSideBySide: boolean, scene:Scene) {
+            super(name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class StereoscopicGamepadCamera extends GamepadCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+} 

+ 71 - 3
Babylon/Cameras/babylon.targetCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -62,7 +62,8 @@ var BABYLON;
                 return false;
             }
             var lockedTargetPosition = this._getLockedTargetPosition();
-            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition) && this._cache.rotation.equals(this.rotation);
+            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition)
+                && this._cache.rotation.equals(this.rotation);
         };
         // Methods
         TargetCamera.prototype._computeLocalCameraSpeed = function () {
@@ -102,7 +103,7 @@ var BABYLON;
         TargetCamera.prototype._updatePosition = function () {
             this.position.addInPlace(this.cameraDirection);
         };
-        TargetCamera.prototype._update = function () {
+        TargetCamera.prototype._checkInputs = function () {
             var needToMove = this._decideIfNeedsToMove();
             var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
             // Move
@@ -143,6 +144,7 @@ var BABYLON;
                 }
                 this.cameraRotation.scaleInPlace(this.inertia);
             }
+            _super.prototype._checkInputs.call(this);
         };
         TargetCamera.prototype._getViewMatrix = function () {
             if (!this.lockedTarget) {
@@ -167,6 +169,72 @@ var BABYLON;
             BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
             return this._viewMatrix;
         };
+        TargetCamera.prototype._getVRViewMatrix = function () {
+            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+            BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+            BABYLON.Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._cameraRigParams.vrActualUp);
+            // Computing target and final matrix
+            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
+            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._cameraRigParams.vrActualUp, this._cameraRigParams.vrWorkMatrix);
+            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._viewMatrix);
+            return this._viewMatrix;
+        };
+        /**
+         * @override
+         * Override Camera.createRigCamera
+         */
+        TargetCamera.prototype.createRigCamera = function (name, cameraIndex) {
+            if (this.cameraRigMode !== BABYLON.Camera.RIG_MODE_NONE) {
+                var rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
+                if (this.cameraRigMode === BABYLON.Camera.RIG_MODE_VR) {
+                    rigCamera._cameraRigParams = {};
+                    rigCamera._cameraRigParams.vrActualUp = new BABYLON.Vector3(0, 0, 0);
+                    rigCamera._getViewMatrix = rigCamera._getVRViewMatrix;
+                }
+                return rigCamera;
+            }
+            return null;
+        };
+        /**
+         * @override
+         * Override Camera._updateRigCameras
+         */
+        TargetCamera.prototype._updateRigCameras = function () {
+            switch (this.cameraRigMode) {
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case BABYLON.Camera.RIG_MODE_VR:
+                    var camLeft = this._rigCameras[0];
+                    var camRight = this._rigCameras[1];
+                    if (this.cameraRigMode === BABYLON.Camera.RIG_MODE_VR) {
+                        camLeft.rotation.x = camRight.rotation.x = this.rotation.x;
+                        camLeft.rotation.y = camRight.rotation.y = this.rotation.y;
+                        camLeft.rotation.z = camRight.rotation.z = this.rotation.z;
+                        camLeft.position.copyFrom(this.position);
+                        camRight.position.copyFrom(this.position);
+                    }
+                    else {
+                        camLeft.setTarget(this.getTarget());
+                        camRight.setTarget(this.getTarget());
+                        //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
+                        this._getRigCamPosition(-this._cameraRigParams.stereoHalfAngle, camLeft.position);
+                        this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle, camRight.position);
+                    }
+                    break;
+            }
+            _super.prototype._updateRigCameras.call(this);
+        };
+        TargetCamera.prototype._getRigCamPosition = function (halfSpace, result) {
+            if (!this._rigCamTransformMatrix) {
+                this._rigCamTransformMatrix = new BABYLON.Matrix();
+            }
+            var target = this.getTarget();
+            BABYLON.Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(BABYLON.Matrix.RotationY(halfSpace), this._rigCamTransformMatrix);
+            this._rigCamTransformMatrix = this._rigCamTransformMatrix.multiply(BABYLON.Matrix.Translation(target.x, target.y, target.z));
+            BABYLON.Vector3.TransformCoordinatesToRef(this.position, this._rigCamTransformMatrix, result);
+        };
         return TargetCamera;
     })(BABYLON.Camera);
     BABYLON.TargetCamera = TargetCamera;

+ 84 - 1
Babylon/Cameras/babylon.targetCamera.ts

@@ -14,6 +14,8 @@
         public _camMatrix = Matrix.Zero();
         public _cameraTransformMatrix = Matrix.Zero();
         public _cameraRotationMatrix = Matrix.Zero();
+        private _rigCamTransformMatrix: Matrix;
+
         public _referencePoint = new Vector3(0, 0, 1);
         public _transformedReferencePoint = Vector3.Zero();
         public _lookAtTemp = Matrix.Zero();
@@ -125,7 +127,7 @@
         public _updatePosition():void{
             this.position.addInPlace(this.cameraDirection);
         }
-        public _update():void {
+        public _checkInputs():void {
             var needToMove = this._decideIfNeedsToMove();
             var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
 
@@ -177,6 +179,8 @@
                 }
                 this.cameraRotation.scaleInPlace(this.inertia);
             }
+
+            super._checkInputs();
         }
 
 
@@ -206,5 +210,84 @@
             Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
             return this._viewMatrix;
         }
+        
+        public _getVRViewMatrix(): Matrix {
+            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+
+            Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+            Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._cameraRigParams.vrActualUp);
+
+            // Computing target and final matrix
+            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
+
+            Matrix.LookAtLHToRef(this.position, this._currentTarget, this._cameraRigParams.vrActualUp, this._cameraRigParams.vrWorkMatrix);
+
+            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._viewMatrix);
+            return this._viewMatrix;
+        }
+        
+        /**
+         * @override
+         * Override Camera.createRigCamera
+         */
+        public createRigCamera(name: string, cameraIndex: number): Camera {
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
+                var rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
+                if (this.cameraRigMode === Camera.RIG_MODE_VR) {
+                    rigCamera._cameraRigParams = {};
+                    rigCamera._cameraRigParams.vrActualUp = new Vector3(0, 0, 0);
+                    rigCamera._getViewMatrix = rigCamera._getVRViewMatrix;
+                }
+                return rigCamera;
+            }
+            return null;
+        }
+        
+        /**
+         * @override
+         * Override Camera._updateRigCameras
+         */
+        public _updateRigCameras(){
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case Camera.RIG_MODE_VR:
+                    var camLeft = <TargetCamera> this._rigCameras[0];
+                    var camRight = <TargetCamera> this._rigCameras[1];
+
+                    if (this.cameraRigMode === Camera.RIG_MODE_VR) {
+                        camLeft.rotation.x = camRight.rotation.x = this.rotation.x;
+                        camLeft.rotation.y = camRight.rotation.y = this.rotation.y;
+                        camLeft.rotation.z = camRight.rotation.z = this.rotation.z;
+                        
+                        camLeft.position.copyFrom(this.position);
+                        camRight.position.copyFrom(this.position);
+                        
+                    } else {
+                        camLeft.setTarget(this.getTarget());
+                        camRight.setTarget(this.getTarget());
+                        
+                        //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
+                        this._getRigCamPosition(-this._cameraRigParams.stereoHalfAngle, camLeft.position);
+                        this._getRigCamPosition( this._cameraRigParams.stereoHalfAngle, camRight.position);
+                    }
+                    break;
+            }
+            super._updateRigCameras();
+        }
+        
+        private _getRigCamPosition(halfSpace: number, result: Vector3) {
+            if (!this._rigCamTransformMatrix){
+                this._rigCamTransformMatrix = new Matrix();
+            }
+            var target = this.getTarget();
+            Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(Matrix.RotationY(halfSpace), this._rigCamTransformMatrix);
+
+            this._rigCamTransformMatrix = this._rigCamTransformMatrix.multiply(Matrix.Translation(target.x, target.y, target.z));
+
+            Vector3.TransformCoordinatesToRef(this.position, this._rigCamTransformMatrix, result);
+        }
     }
 } 

+ 2 - 1
Babylon/Cameras/babylon.touchCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -109,6 +109,7 @@ var BABYLON;
                 BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
                 this.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
             }
+            _super.prototype._checkInputs.call(this);
         };
         return TouchCamera;
     })(BABYLON.FreeCamera);

+ 7 - 5
Babylon/Cameras/babylon.touchCamera.ts

@@ -95,7 +95,7 @@ module BABYLON {
             canvas.addEventListener("pointerout", this._onPointerUp);
             canvas.addEventListener("pointermove", this._onPointerMove);
 
-            BABYLON.Tools.RegisterTopRootEvents([
+            Tools.RegisterTopRootEvents([
                 { name: "blur", handler: this._onLostFocus }
             ]);
         }
@@ -110,7 +110,7 @@ module BABYLON {
             canvas.removeEventListener("pointerout", this._onPointerUp);
             canvas.removeEventListener("pointermove", this._onPointerMove);
 
-            BABYLON.Tools.UnregisterTopRootEvents([
+            Tools.UnregisterTopRootEvents([
                 { name: "blur", handler: this._onLostFocus }
             ]);
 
@@ -127,11 +127,13 @@ module BABYLON {
                 this.cameraRotation.x += -this._offsetY / this.angularSensibility;
             } else {
                 var speed = this._computeLocalCameraSpeed();
-                var direction = new BABYLON.Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
+                var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
 
-                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-                this.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
+                Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
+                this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
             }
+
+            super._checkInputs();
         }
     }
 }

+ 6 - 5
Babylon/Cameras/babylon.virtualJoysticksCamera.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -12,12 +12,12 @@ var BABYLON;
         function VirtualJoysticksCamera(name, position, scene) {
             _super.call(this, name, position, scene);
             this._leftjoystick = new BABYLON.VirtualJoystick(true);
-            this._leftjoystick.setAxisForUpDown(2 /* Z */);
-            this._leftjoystick.setAxisForLeftRight(0 /* X */);
+            this._leftjoystick.setAxisForUpDown(BABYLON.JoystickAxis.Z);
+            this._leftjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.X);
             this._leftjoystick.setJoystickSensibility(0.15);
             this._rightjoystick = new BABYLON.VirtualJoystick(false);
-            this._rightjoystick.setAxisForUpDown(0 /* X */);
-            this._rightjoystick.setAxisForLeftRight(1 /* Y */);
+            this._rightjoystick.setAxisForUpDown(BABYLON.JoystickAxis.X);
+            this._rightjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.Y);
             this._rightjoystick.reverseUpDown = true;
             this._rightjoystick.setJoystickSensibility(0.05);
             this._rightjoystick.setJoystickColor("yellow");
@@ -33,6 +33,7 @@ var BABYLON;
             if (!this._rightjoystick.pressed) {
                 this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
             }
+            _super.prototype._checkInputs.call(this);
         };
         VirtualJoysticksCamera.prototype.dispose = function () {
             this._leftjoystick.releaseCanvas();

+ 12 - 10
Babylon/Cameras/babylon.virtualJoysticksCamera.ts

@@ -1,26 +1,26 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     export class VirtualJoysticksCamera extends FreeCamera {
-        private _leftjoystick: BABYLON.VirtualJoystick;
-        private _rightjoystick: BABYLON.VirtualJoystick;
+        private _leftjoystick: VirtualJoystick;
+        private _rightjoystick: VirtualJoystick;
 
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
-            this._leftjoystick = new BABYLON.VirtualJoystick(true);
-            this._leftjoystick.setAxisForUpDown(BABYLON.JoystickAxis.Z);
-            this._leftjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.X);
+            this._leftjoystick = new VirtualJoystick(true);
+            this._leftjoystick.setAxisForUpDown(JoystickAxis.Z);
+            this._leftjoystick.setAxisForLeftRight(JoystickAxis.X);
             this._leftjoystick.setJoystickSensibility(0.15);
-            this._rightjoystick = new BABYLON.VirtualJoystick(false);
-            this._rightjoystick.setAxisForUpDown(BABYLON.JoystickAxis.X);
-            this._rightjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.Y);
+            this._rightjoystick = new VirtualJoystick(false);
+            this._rightjoystick.setAxisForUpDown(JoystickAxis.X);
+            this._rightjoystick.setAxisForLeftRight(JoystickAxis.Y);
             this._rightjoystick.reverseUpDown = true;
             this._rightjoystick.setJoystickSensibility(0.05);
             this._rightjoystick.setJoystickColor("yellow");
         }
 
         public _checkInputs(): void {
-            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var deltaTransform = BABYLON.Vector3.TransformCoordinates(this._leftjoystick.deltaPosition, cameraTransform);
+            var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+            var deltaTransform = Vector3.TransformCoordinates(this._leftjoystick.deltaPosition, cameraTransform);
             this.cameraDirection = this.cameraDirection.add(deltaTransform);
             this.cameraRotation = this.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
             if (!this._leftjoystick.pressed) {
@@ -29,6 +29,8 @@
             if (!this._rightjoystick.pressed) {
                 this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
             }
+
+            super._checkInputs();
         }
 
         public dispose(): void {

+ 0 - 80
Babylon/Cameras/babylon.webVRCamera.js

@@ -1,80 +0,0 @@
-var __extends = this.__extends || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    __.prototype = b.prototype;
-    d.prototype = new __();
-};
-var BABYLON;
-(function (BABYLON) {
-    var WebVRCamera = (function (_super) {
-        __extends(WebVRCamera, _super);
-        function WebVRCamera(name, position, scene) {
-            _super.call(this, name, position, scene);
-            this._hmdDevice = null;
-            this._sensorDevice = null;
-            this._cacheState = null;
-            this._cacheQuaternion = new BABYLON.Quaternion();
-            this._cacheRotation = BABYLON.Vector3.Zero();
-            this._vrEnabled = false;
-            this._getWebVRDevices = this._getWebVRDevices.bind(this);
-        }
-        WebVRCamera.prototype._getWebVRDevices = function (devices) {
-            var size = devices.length;
-            var i = 0;
-
-            // Reset devices.
-            this._sensorDevice = null;
-            this._hmdDevice = null;
-
-            while (i < size && this._hmdDevice === null) {
-                if (devices[i] instanceof HMDVRDevice) {
-                    this._hmdDevice = devices[i];
-                }
-                i++;
-            }
-
-            i = 0;
-
-            while (i < size && this._sensorDevice === null) {
-                if (devices[i] instanceof PositionSensorVRDevice && (!this._hmdDevice || devices[i].hardwareUnitId === this._hmdDevice.hardwareUnitId)) {
-                    this._sensorDevice = devices[i];
-                }
-                i++;
-            }
-
-            this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
-        };
-
-        WebVRCamera.prototype._update = function () {
-            if (this._vrEnabled) {
-                this._cacheState = this._sensorDevice.getState();
-                this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
-                this._cacheQuaternion.toEulerAnglesToRef(this._cacheRotation);
-
-                this.rotation.x = -this._cacheRotation.z;
-                this.rotation.y = -this._cacheRotation.y;
-                this.rotation.z = this._cacheRotation.x;
-            }
-
-            _super.prototype._update.call(this);
-        };
-
-        WebVRCamera.prototype.attachControl = function (element, noPreventDefault) {
-            _super.prototype.attachControl.call(this, element, noPreventDefault);
-
-            if (navigator.getVRDevices) {
-                navigator.getVRDevices().then(this._getWebVRDevices);
-            } else if (navigator.mozGetVRDevices) {
-                navigator.mozGetVRDevices(this._getWebVRDevices);
-            }
-        };
-
-        WebVRCamera.prototype.detachControl = function (element) {
-            _super.prototype.detachControl.call(this, element);
-            this._vrEnabled = false;
-        };
-        return WebVRCamera;
-    })(BABYLON.OculusCamera);
-    BABYLON.WebVRCamera = WebVRCamera;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.webVRCamera.js.map

+ 11 - 11
Babylon/Collisions/babylon.collider.js

@@ -96,18 +96,19 @@ var BABYLON;
                 return false;
             return true;
         };
-        Collider.prototype._testTriangle = function (faceIndex, subMesh, p1, p2, p3) {
+        Collider.prototype._testTriangle = function (faceIndex, trianglePlaneArray, p1, p2, p3, hasMaterial) {
             var t0;
             var embeddedInPlane = false;
-            if (!subMesh._trianglePlanes) {
-                subMesh._trianglePlanes = [];
+            //defensive programming, actually not needed.
+            if (!trianglePlaneArray) {
+                trianglePlaneArray = [];
             }
-            if (!subMesh._trianglePlanes[faceIndex]) {
-                subMesh._trianglePlanes[faceIndex] = new BABYLON.Plane(0, 0, 0, 0);
-                subMesh._trianglePlanes[faceIndex].copyFromPoints(p1, p2, p3);
+            if (!trianglePlaneArray[faceIndex]) {
+                trianglePlaneArray[faceIndex] = new BABYLON.Plane(0, 0, 0, 0);
+                trianglePlaneArray[faceIndex].copyFromPoints(p1, p2, p3);
             }
-            var trianglePlane = subMesh._trianglePlanes[faceIndex];
-            if ((!subMesh.getMaterial()) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
+            var trianglePlane = trianglePlaneArray[faceIndex];
+            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
                 return;
             var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
             var normalDotVelocity = BABYLON.Vector3.Dot(trianglePlane.normal, this.velocity);
@@ -241,16 +242,15 @@ var BABYLON;
                     }
                     this.nearestDistance = distToCollision;
                     this.collisionFound = true;
-                    this.collidedMesh = subMesh.getMesh();
                 }
             }
         };
-        Collider.prototype._collide = function (subMesh, pts, indices, indexStart, indexEnd, decal) {
+        Collider.prototype._collide = function (trianglePlaneArray, pts, indices, indexStart, indexEnd, decal, hasMaterial) {
             for (var i = indexStart; i < indexEnd; i += 3) {
                 var p1 = pts[indices[i] - decal];
                 var p2 = pts[indices[i + 1] - decal];
                 var p3 = pts[indices[i + 2] - decal];
-                this._testTriangle(i, subMesh, p3, p2, p1);
+                this._testTriangle(i, trianglePlaneArray, p3, p2, p1, hasMaterial);
             }
         };
         Collider.prototype._getResponse = function (pos, vel) {

+ 50 - 50
Babylon/Collisions/babylon.collider.ts

@@ -54,38 +54,38 @@
     };
 
     export class Collider {
-        public radius = new BABYLON.Vector3(1, 1, 1);
+        public radius = new Vector3(1, 1, 1);
         public retry = 0;
         public velocity: Vector3;
         public basePoint: Vector3;
         public epsilon: number;
         public collisionFound: boolean;
         public velocityWorldLength: number;
-        public basePointWorld = BABYLON.Vector3.Zero();
-        public velocityWorld = BABYLON.Vector3.Zero();
-        public normalizedVelocity = BABYLON.Vector3.Zero();
+        public basePointWorld = Vector3.Zero();
+        public velocityWorld = Vector3.Zero();
+        public normalizedVelocity = Vector3.Zero();
         public initialVelocity: Vector3;
         public initialPosition: Vector3;
         public nearestDistance: number;
         public intersectionPoint: Vector3;
-        public collidedMesh: AbstractMesh
-
-        private _collisionPoint = BABYLON.Vector3.Zero();
-        private _planeIntersectionPoint = BABYLON.Vector3.Zero();
-        private _tempVector = BABYLON.Vector3.Zero();
-        private _tempVector2 = BABYLON.Vector3.Zero();
-        private _tempVector3 = BABYLON.Vector3.Zero();
-        private _tempVector4 = BABYLON.Vector3.Zero();
-        private _edge = BABYLON.Vector3.Zero();
-        private _baseToVertex = BABYLON.Vector3.Zero();
-        private _destinationPoint = BABYLON.Vector3.Zero();
-        private _slidePlaneNormal = BABYLON.Vector3.Zero();
-        private _displacementVector = BABYLON.Vector3.Zero();
+        public collidedMesh: AbstractMesh;
+
+        private _collisionPoint = Vector3.Zero();
+        private _planeIntersectionPoint = Vector3.Zero();
+        private _tempVector = Vector3.Zero();
+        private _tempVector2 = Vector3.Zero();
+        private _tempVector3 = Vector3.Zero();
+        private _tempVector4 = Vector3.Zero();
+        private _edge = Vector3.Zero();
+        private _baseToVertex = Vector3.Zero();
+        private _destinationPoint = Vector3.Zero();
+        private _slidePlaneNormal = Vector3.Zero();
+        private _displacementVector = Vector3.Zero();
 
         // Methods
         public _initialize(source: Vector3, dir: Vector3, e: number): void {
             this.velocity = dir;
-            BABYLON.Vector3.NormalizeToRef(dir, this.normalizedVelocity);
+            Vector3.NormalizeToRef(dir, this.normalizedVelocity);
             this.basePoint = source;
 
             source.multiplyToRef(this.radius, this.basePointWorld);
@@ -101,24 +101,24 @@
             pa.subtractToRef(point, this._tempVector);
             pb.subtractToRef(point, this._tempVector2);
 
-            BABYLON.Vector3.CrossToRef(this._tempVector, this._tempVector2, this._tempVector4);
-            var d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            Vector3.CrossToRef(this._tempVector, this._tempVector2, this._tempVector4);
+            var d = Vector3.Dot(this._tempVector4, n);
             if (d < 0)
                 return false;
 
             pc.subtractToRef(point, this._tempVector3);
-            BABYLON.Vector3.CrossToRef(this._tempVector2, this._tempVector3, this._tempVector4);
-            d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            Vector3.CrossToRef(this._tempVector2, this._tempVector3, this._tempVector4);
+            d = Vector3.Dot(this._tempVector4, n);
             if (d < 0)
                 return false;
 
-            BABYLON.Vector3.CrossToRef(this._tempVector3, this._tempVector, this._tempVector4);
-            d = BABYLON.Vector3.Dot(this._tempVector4, n);
+            Vector3.CrossToRef(this._tempVector3, this._tempVector, this._tempVector4);
+            d = Vector3.Dot(this._tempVector4, n);
             return d >= 0;
         }
 
         public _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean {
-            var distance = BABYLON.Vector3.Distance(this.basePointWorld, sphereCenter);
+            var distance = Vector3.Distance(this.basePointWorld, sphereCenter);
 
             var max = Math.max(this.radius.x, this.radius.y, this.radius.z);
 
@@ -132,26 +132,27 @@
             return true;
         }
 
-        public _testTriangle(faceIndex: number, subMesh: SubMesh, p1: Vector3, p2: Vector3, p3: Vector3): void {
+        public _testTriangle(faceIndex: number, trianglePlaneArray: Array<Plane>, p1: Vector3, p2: Vector3, p3: Vector3, hasMaterial: boolean): void {
             var t0;
             var embeddedInPlane = false;
 
-            if (!subMesh._trianglePlanes) {
-                subMesh._trianglePlanes = [];
+            //defensive programming, actually not needed.
+            if (!trianglePlaneArray) {
+                trianglePlaneArray = [];
             }
 
-            if (!subMesh._trianglePlanes[faceIndex]) {
-                subMesh._trianglePlanes[faceIndex] = new BABYLON.Plane(0, 0, 0, 0);
-                subMesh._trianglePlanes[faceIndex].copyFromPoints(p1, p2, p3);
+            if (!trianglePlaneArray[faceIndex]) {
+                trianglePlaneArray[faceIndex] = new Plane(0, 0, 0, 0);
+                trianglePlaneArray[faceIndex].copyFromPoints(p1, p2, p3);
             }
 
-            var trianglePlane = subMesh._trianglePlanes[faceIndex];
+            var trianglePlane = trianglePlaneArray[faceIndex];
 
-            if ((!subMesh.getMaterial()) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
+            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
                 return;
 
             var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
-            var normalDotVelocity = BABYLON.Vector3.Dot(trianglePlane.normal, this.velocity);
+            var normalDotVelocity = Vector3.Dot(trianglePlane.normal, this.velocity);
 
             if (normalDotVelocity == 0) {
                 if (Math.abs(signedDistToTrianglePlane) >= 1.0)
@@ -201,7 +202,7 @@
                 var a = velocitySquaredLength;
 
                 this.basePoint.subtractToRef(p1, this._tempVector);
-                var b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                var b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
                 var c = this._tempVector.lengthSquared() - 1.0;
 
                 var lowestRoot = getLowestRoot(a, b, c, t);
@@ -212,7 +213,7 @@
                 }
 
                 this.basePoint.subtractToRef(p2, this._tempVector);
-                b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
                 c = this._tempVector.lengthSquared() - 1.0;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -223,7 +224,7 @@
                 }
 
                 this.basePoint.subtractToRef(p3, this._tempVector);
-                b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this._tempVector));
+                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
                 c = this._tempVector.lengthSquared() - 1.0;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -236,11 +237,11 @@
                 p2.subtractToRef(p1, this._edge);
                 p1.subtractToRef(this.basePoint, this._baseToVertex);
                 var edgeSquaredLength = this._edge.lengthSquared();
-                var edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
-                var edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+                var edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                var edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
 
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -258,11 +259,11 @@
                 p3.subtractToRef(p2, this._edge);
                 p2.subtractToRef(this.basePoint, this._baseToVertex);
                 edgeSquaredLength = this._edge.lengthSquared();
-                edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
-                edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
 
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
                 lowestRoot = getLowestRoot(a, b, c, t);
                 if (lowestRoot.found) {
@@ -279,11 +280,11 @@
                 p1.subtractToRef(p3, this._edge);
                 p3.subtractToRef(this.basePoint, this._baseToVertex);
                 edgeSquaredLength = this._edge.lengthSquared();
-                edgeDotVelocity = BABYLON.Vector3.Dot(this._edge, this.velocity);
-                edgeDotBaseToVertex = BABYLON.Vector3.Dot(this._edge, this._baseToVertex);
+                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
 
                 a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
                 c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
 
                 lowestRoot = getLowestRoot(a, b, c, t);
@@ -310,18 +311,17 @@
                     }
                     this.nearestDistance = distToCollision;
                     this.collisionFound = true;
-                    this.collidedMesh = subMesh.getMesh();
                 }
             }
         }
 
-        public _collide(subMesh, pts: Vector3[], indices: number[], indexStart: number, indexEnd: number, decal: number): void {
+        public _collide(trianglePlaneArray: Array<Plane>, pts: Vector3[], indices: number[], indexStart: number, indexEnd: number, decal: number, hasMaterial: boolean): void {
             for (var i = indexStart; i < indexEnd; i += 3) {
                 var p1 = pts[indices[i] - decal];
                 var p2 = pts[indices[i + 1] - decal];
                 var p3 = pts[indices[i + 2] - decal];
 
-                this._testTriangle(i, subMesh, p3, p2, p1);
+                this._testTriangle(i, trianglePlaneArray, p3, p2, p1, hasMaterial);
             }
         }
 
@@ -337,7 +337,7 @@
             pos.addInPlace(this._displacementVector);
             this.intersectionPoint.addInPlace(this._displacementVector);
 
-            this._slidePlaneNormal.scaleInPlace(BABYLON.Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
+            this._slidePlaneNormal.scaleInPlace(Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
             this._destinationPoint.subtractInPlace(this._slidePlaneNormal);
 
             this._destinationPoint.subtractToRef(this.intersectionPoint, vel);

+ 268 - 0
Babylon/Collisions/babylon.collisionCoordinator.js

@@ -0,0 +1,268 @@
+var BABYLON;
+(function (BABYLON) {
+    //WebWorker code will be inserted to this variable.
+    BABYLON.CollisionWorker = "";
+    (function (WorkerTaskType) {
+        WorkerTaskType[WorkerTaskType["INIT"] = 0] = "INIT";
+        WorkerTaskType[WorkerTaskType["UPDATE"] = 1] = "UPDATE";
+        WorkerTaskType[WorkerTaskType["COLLIDE"] = 2] = "COLLIDE";
+    })(BABYLON.WorkerTaskType || (BABYLON.WorkerTaskType = {}));
+    var WorkerTaskType = BABYLON.WorkerTaskType;
+    (function (WorkerReplyType) {
+        WorkerReplyType[WorkerReplyType["SUCCESS"] = 0] = "SUCCESS";
+        WorkerReplyType[WorkerReplyType["UNKNOWN_ERROR"] = 1] = "UNKNOWN_ERROR";
+    })(BABYLON.WorkerReplyType || (BABYLON.WorkerReplyType = {}));
+    var WorkerReplyType = BABYLON.WorkerReplyType;
+    var CollisionCoordinatorWorker = (function () {
+        function CollisionCoordinatorWorker() {
+            var _this = this;
+            this._scaledPosition = BABYLON.Vector3.Zero();
+            this._scaledVelocity = BABYLON.Vector3.Zero();
+            this.onMeshUpdated = function (mesh) {
+                _this._addUpdateMeshesList[mesh.uniqueId] = CollisionCoordinatorWorker.SerializeMesh(mesh);
+            };
+            this.onGeometryUpdated = function (geometry) {
+                _this._addUpdateGeometriesList[geometry.id] = CollisionCoordinatorWorker.SerializeGeometry(geometry);
+            };
+            this._afterRender = function () {
+                if (!_this._init)
+                    return;
+                if (_this._toRemoveGeometryArray.length == 0 && _this._toRemoveMeshesArray.length == 0 && Object.keys(_this._addUpdateGeometriesList).length == 0 && Object.keys(_this._addUpdateMeshesList).length == 0) {
+                    return;
+                }
+                //5 concurrent updates were sent to the web worker and were not yet processed. Abort next update.
+                //TODO make sure update runs as fast as possible to be able to update 60 FPS.
+                if (_this._runningUpdated > 4) {
+                    return;
+                }
+                ++_this._runningUpdated;
+                var payload = {
+                    updatedMeshes: _this._addUpdateMeshesList,
+                    updatedGeometries: _this._addUpdateGeometriesList,
+                    removedGeometries: _this._toRemoveGeometryArray,
+                    removedMeshes: _this._toRemoveMeshesArray
+                };
+                var message = {
+                    payload: payload,
+                    taskType: WorkerTaskType.UPDATE
+                };
+                var serializable = [];
+                for (var id in payload.updatedGeometries) {
+                    if (payload.updatedGeometries.hasOwnProperty(id)) {
+                        //prepare transferables
+                        serializable.push(message.payload.updatedGeometries[id].indices.buffer);
+                        serializable.push(message.payload.updatedGeometries[id].normals.buffer);
+                        serializable.push(message.payload.updatedGeometries[id].positions.buffer);
+                    }
+                }
+                _this._worker.postMessage(message, serializable);
+                _this._addUpdateMeshesList = {};
+                _this._addUpdateGeometriesList = {};
+                _this._toRemoveGeometryArray = [];
+                _this._toRemoveMeshesArray = [];
+            };
+            this._onMessageFromWorker = function (e) {
+                var returnData = e.data;
+                if (returnData.error != WorkerReplyType.SUCCESS) {
+                    //TODO what errors can be returned from the worker?
+                    BABYLON.Tools.Warn("error returned from worker!");
+                    return;
+                }
+                switch (returnData.taskType) {
+                    case WorkerTaskType.INIT:
+                        _this._init = true;
+                        //Update the worked with ALL of the scene's current state
+                        _this._scene.meshes.forEach(function (mesh) {
+                            _this.onMeshAdded(mesh);
+                        });
+                        _this._scene.getGeometries().forEach(function (geometry) {
+                            _this.onGeometryAdded(geometry);
+                        });
+                        break;
+                    case WorkerTaskType.UPDATE:
+                        _this._runningUpdated--;
+                        break;
+                    case WorkerTaskType.COLLIDE:
+                        _this._runningCollisionTask = false;
+                        var returnPayload = returnData.payload;
+                        if (!_this._collisionsCallbackArray[returnPayload.collisionId])
+                            return;
+                        _this._collisionsCallbackArray[returnPayload.collisionId](returnPayload.collisionId, BABYLON.Vector3.FromArray(returnPayload.newPosition), _this._scene.getMeshByUniqueID(returnPayload.collidedMeshUniqueId));
+                        //cleanup
+                        _this._collisionsCallbackArray[returnPayload.collisionId] = undefined;
+                        break;
+                }
+            };
+            this._collisionsCallbackArray = [];
+            this._init = false;
+            this._runningUpdated = 0;
+            this._runningCollisionTask = false;
+            this._addUpdateMeshesList = {};
+            this._addUpdateGeometriesList = {};
+            this._toRemoveGeometryArray = [];
+            this._toRemoveMeshesArray = [];
+        }
+        CollisionCoordinatorWorker.prototype.getNewPosition = function (position, velocity, collider, maximumRetry, excludedMesh, onNewPosition, collisionIndex) {
+            if (!this._init)
+                return;
+            if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000])
+                return;
+            position.divideToRef(collider.radius, this._scaledPosition);
+            velocity.divideToRef(collider.radius, this._scaledVelocity);
+            this._collisionsCallbackArray[collisionIndex] = onNewPosition;
+            var payload = {
+                collider: {
+                    position: this._scaledPosition.asArray(),
+                    velocity: this._scaledVelocity.asArray(),
+                    radius: collider.radius.asArray()
+                },
+                collisionId: collisionIndex,
+                excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
+                maximumRetry: maximumRetry
+            };
+            var message = {
+                payload: payload,
+                taskType: WorkerTaskType.COLLIDE
+            };
+            this._worker.postMessage(message);
+        };
+        CollisionCoordinatorWorker.prototype.init = function (scene) {
+            this._scene = scene;
+            this._scene.registerAfterRender(this._afterRender);
+            var workerUrl = BABYLON.WorkerIncluded ? BABYLON.Engine.CodeRepository + "Collisions/babylon.collisionWorker.js" : URL.createObjectURL(new Blob([BABYLON.CollisionWorker], { type: 'application/javascript' }));
+            this._worker = new Worker(workerUrl);
+            this._worker.onmessage = this._onMessageFromWorker;
+            var message = {
+                payload: {},
+                taskType: WorkerTaskType.INIT
+            };
+            this._worker.postMessage(message);
+        };
+        CollisionCoordinatorWorker.prototype.destroy = function () {
+            this._scene.unregisterAfterRender(this._afterRender);
+            this._worker.terminate();
+        };
+        CollisionCoordinatorWorker.prototype.onMeshAdded = function (mesh) {
+            mesh.registerAfterWorldMatrixUpdate(this.onMeshUpdated);
+            this.onMeshUpdated(mesh);
+        };
+        CollisionCoordinatorWorker.prototype.onMeshRemoved = function (mesh) {
+            this._toRemoveMeshesArray.push(mesh.uniqueId);
+        };
+        CollisionCoordinatorWorker.prototype.onGeometryAdded = function (geometry) {
+            //TODO this will break if the user uses his own function. This should be an array of callbacks!
+            geometry.onGeometryUpdated = this.onGeometryUpdated;
+            this.onGeometryUpdated(geometry);
+        };
+        CollisionCoordinatorWorker.prototype.onGeometryDeleted = function (geometry) {
+            this._toRemoveGeometryArray.push(geometry.id);
+        };
+        CollisionCoordinatorWorker.SerializeMesh = function (mesh) {
+            var submeshes = [];
+            if (mesh.subMeshes) {
+                submeshes = mesh.subMeshes.map(function (sm, idx) {
+                    return {
+                        position: idx,
+                        verticesStart: sm.verticesStart,
+                        verticesCount: sm.verticesCount,
+                        indexStart: sm.indexStart,
+                        indexCount: sm.indexCount,
+                        hasMaterial: !!sm.getMaterial(),
+                        sphereCenter: sm.getBoundingInfo().boundingSphere.centerWorld.asArray(),
+                        sphereRadius: sm.getBoundingInfo().boundingSphere.radiusWorld,
+                        boxMinimum: sm.getBoundingInfo().boundingBox.minimumWorld.asArray(),
+                        boxMaximum: sm.getBoundingInfo().boundingBox.maximumWorld.asArray()
+                    };
+                });
+            }
+            var geometryId = mesh.geometry ? mesh.geometry.id : null;
+            return {
+                uniqueId: mesh.uniqueId,
+                id: mesh.id,
+                name: mesh.name,
+                geometryId: geometryId,
+                sphereCenter: mesh.getBoundingInfo().boundingSphere.centerWorld.asArray(),
+                sphereRadius: mesh.getBoundingInfo().boundingSphere.radiusWorld,
+                boxMinimum: mesh.getBoundingInfo().boundingBox.minimumWorld.asArray(),
+                boxMaximum: mesh.getBoundingInfo().boundingBox.maximumWorld.asArray(),
+                worldMatrixFromCache: mesh.worldMatrixFromCache.asArray(),
+                subMeshes: submeshes,
+                checkCollisions: mesh.checkCollisions
+            };
+        };
+        CollisionCoordinatorWorker.SerializeGeometry = function (geometry) {
+            return {
+                id: geometry.id,
+                positions: new Float32Array(geometry.getVerticesData(BABYLON.VertexBuffer.PositionKind) || []),
+                normals: new Float32Array(geometry.getVerticesData(BABYLON.VertexBuffer.NormalKind) || []),
+                indices: new Int32Array(geometry.getIndices() || []),
+            };
+        };
+        return CollisionCoordinatorWorker;
+    })();
+    BABYLON.CollisionCoordinatorWorker = CollisionCoordinatorWorker;
+    var CollisionCoordinatorLegacy = (function () {
+        function CollisionCoordinatorLegacy() {
+            this._scaledPosition = BABYLON.Vector3.Zero();
+            this._scaledVelocity = BABYLON.Vector3.Zero();
+            this._finalPosition = BABYLON.Vector3.Zero();
+        }
+        CollisionCoordinatorLegacy.prototype.getNewPosition = function (position, velocity, collider, maximumRetry, excludedMesh, onNewPosition, collisionIndex) {
+            position.divideToRef(collider.radius, this._scaledPosition);
+            velocity.divideToRef(collider.radius, this._scaledVelocity);
+            collider.collidedMesh = null;
+            collider.retry = 0;
+            collider.initialVelocity = this._scaledVelocity;
+            collider.initialPosition = this._scaledPosition;
+            this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, this._finalPosition, excludedMesh);
+            this._finalPosition.multiplyInPlace(collider.radius);
+            //run the callback
+            onNewPosition(collisionIndex, this._finalPosition, collider.collidedMesh);
+        };
+        CollisionCoordinatorLegacy.prototype.init = function (scene) {
+            this._scene = scene;
+        };
+        CollisionCoordinatorLegacy.prototype.destroy = function () {
+            //Legacy need no destruction method.
+        };
+        //No update in legacy mode
+        CollisionCoordinatorLegacy.prototype.onMeshAdded = function (mesh) { };
+        CollisionCoordinatorLegacy.prototype.onMeshUpdated = function (mesh) { };
+        CollisionCoordinatorLegacy.prototype.onMeshRemoved = function (mesh) { };
+        CollisionCoordinatorLegacy.prototype.onGeometryAdded = function (geometry) { };
+        CollisionCoordinatorLegacy.prototype.onGeometryUpdated = function (geometry) { };
+        CollisionCoordinatorLegacy.prototype.onGeometryDeleted = function (geometry) { };
+        CollisionCoordinatorLegacy.prototype._collideWithWorld = function (position, velocity, collider, maximumRetry, finalPosition, excludedMesh) {
+            if (excludedMesh === void 0) { excludedMesh = null; }
+            var closeDistance = BABYLON.Engine.CollisionsEpsilon * 10.0;
+            if (collider.retry >= maximumRetry) {
+                finalPosition.copyFrom(position);
+                return;
+            }
+            collider._initialize(position, velocity, closeDistance);
+            // Check all meshes
+            for (var index = 0; index < this._scene.meshes.length; index++) {
+                var mesh = this._scene.meshes[index];
+                if (mesh.isEnabled() && mesh.checkCollisions && mesh.subMeshes && mesh !== excludedMesh) {
+                    mesh._checkCollision(collider);
+                }
+            }
+            if (!collider.collisionFound) {
+                position.addToRef(velocity, finalPosition);
+                return;
+            }
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
+                collider._getResponse(position, velocity);
+            }
+            if (velocity.length() <= closeDistance) {
+                finalPosition.copyFrom(position);
+                return;
+            }
+            collider.retry++;
+            this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
+        };
+        return CollisionCoordinatorLegacy;
+    })();
+    BABYLON.CollisionCoordinatorLegacy = CollisionCoordinatorLegacy;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.collisionCoordinator.js.map

+ 411 - 0
Babylon/Collisions/babylon.collisionCoordinator.ts

@@ -0,0 +1,411 @@
+module BABYLON {
+
+    //WebWorker code will be inserted to this variable.
+    export var CollisionWorker = "";
+
+    export interface ICollisionCoordinator {
+        getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+
+        //Update meshes and geometries
+        onMeshAdded(mesh: AbstractMesh);
+        onMeshUpdated(mesh: AbstractMesh);
+        onMeshRemoved(mesh: AbstractMesh);
+        onGeometryAdded(geometry: Geometry);
+        onGeometryUpdated(geometry: Geometry);
+        onGeometryDeleted(geometry: Geometry);
+    }
+
+    export interface SerializedMesh {
+        id: string;
+        name: string;
+        uniqueId: number;
+        geometryId: string;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+        worldMatrixFromCache: any;
+        subMeshes: Array<SerializedSubMesh>;
+        checkCollisions: boolean;
+    }
+
+    export interface SerializedSubMesh {
+        position: number;
+        verticesStart: number;
+        verticesCount: number;
+        indexStart: number;
+        indexCount: number;
+        hasMaterial: boolean;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+    }
+
+    export interface SerializedGeometry {
+        id: string;
+        positions: Float32Array;
+        indices: Int32Array;
+        normals: Float32Array;
+        //uvs?: Float32Array;
+    }
+
+    export interface BabylonMessage {
+        taskType: WorkerTaskType;
+        payload: InitPayload|CollidePayload|UpdatePayload /*any for TS under 1.4*/;
+    }
+
+    export interface SerializedColliderToWorker {
+        position: Array<number>;
+        velocity: Array<number>;
+        radius: Array<number>;
+    }
+
+    export enum WorkerTaskType {
+        INIT,
+        UPDATE,
+        COLLIDE
+    }
+
+    export interface WorkerReply {
+        error: WorkerReplyType;
+        taskType: WorkerTaskType;
+        payload?: any;
+    }
+
+    export interface CollisionReplyPayload {
+        newPosition: Array<number>;
+        collisionId: number;
+        collidedMeshUniqueId: number;
+    }
+
+    export interface InitPayload {
+
+    }
+
+    export interface CollidePayload {
+        collisionId: number;
+        collider: SerializedColliderToWorker;
+        maximumRetry: number;
+        excludedMeshUniqueId?: number;
+    }
+
+    export interface UpdatePayload {
+        updatedMeshes: { [n: number]: SerializedMesh; };
+        updatedGeometries: { [s: string]: SerializedGeometry; };
+        removedMeshes: Array<number>;
+        removedGeometries: Array<string>;
+    }
+
+    export enum WorkerReplyType {
+        SUCCESS,
+        UNKNOWN_ERROR
+    }
+
+    export class CollisionCoordinatorWorker implements ICollisionCoordinator {
+
+        private _scene: Scene;
+
+        private _scaledPosition = Vector3.Zero();
+        private _scaledVelocity = Vector3.Zero();
+
+        private _collisionsCallbackArray: Array<(collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void>;
+
+        private _init: boolean;
+        private _runningUpdated: number;
+        private _runningCollisionTask: boolean;
+        private _worker: Worker;
+
+        private _addUpdateMeshesList: { [n: number]: SerializedMesh; }
+        private _addUpdateGeometriesList: { [s: string]: SerializedGeometry; };
+        private _toRemoveMeshesArray: Array<number>;
+        private _toRemoveGeometryArray: Array<string>;
+
+        constructor() {
+            this._collisionsCallbackArray = [];
+            this._init = false;
+            this._runningUpdated = 0;
+            this._runningCollisionTask = false;
+
+            this._addUpdateMeshesList = {};
+            this._addUpdateGeometriesList = {};
+            this._toRemoveGeometryArray = [];
+            this._toRemoveMeshesArray = [];
+        }
+
+        public static SerializeMesh = function (mesh: AbstractMesh): SerializedMesh {
+            var submeshes: Array<SerializedSubMesh> = [];
+            if (mesh.subMeshes) {
+                submeshes = mesh.subMeshes.map(function (sm, idx) {
+                    return {
+                        position: idx,
+                        verticesStart: sm.verticesStart,
+                        verticesCount: sm.verticesCount,
+                        indexStart: sm.indexStart,
+                        indexCount: sm.indexCount,
+                        hasMaterial: !!sm.getMaterial(),
+                        sphereCenter: sm.getBoundingInfo().boundingSphere.centerWorld.asArray(),
+                        sphereRadius: sm.getBoundingInfo().boundingSphere.radiusWorld,
+                        boxMinimum: sm.getBoundingInfo().boundingBox.minimumWorld.asArray(),
+                        boxMaximum: sm.getBoundingInfo().boundingBox.maximumWorld.asArray()
+                    }
+                });
+            }
+
+            var geometryId = (<Mesh>mesh).geometry ? (<Mesh>mesh).geometry.id : null;
+
+            return {
+                uniqueId: mesh.uniqueId,
+                id: mesh.id,
+                name: mesh.name,
+                geometryId: geometryId,
+                sphereCenter: mesh.getBoundingInfo().boundingSphere.centerWorld.asArray(),
+                sphereRadius: mesh.getBoundingInfo().boundingSphere.radiusWorld,
+                boxMinimum: mesh.getBoundingInfo().boundingBox.minimumWorld.asArray(),
+                boxMaximum: mesh.getBoundingInfo().boundingBox.maximumWorld.asArray(),
+                worldMatrixFromCache: mesh.worldMatrixFromCache.asArray(),
+                subMeshes: submeshes,
+                checkCollisions: mesh.checkCollisions
+            }
+        }
+
+        public static SerializeGeometry = function (geometry: Geometry): SerializedGeometry {
+            return {
+                id: geometry.id,
+                positions: new Float32Array(geometry.getVerticesData(VertexBuffer.PositionKind) || []),
+                normals: new Float32Array(geometry.getVerticesData(VertexBuffer.NormalKind) || []),
+                indices: new Int32Array(geometry.getIndices() || []),
+                //uvs: new Float32Array(geometry.getVerticesData(VertexBuffer.UVKind) || [])
+            }
+        }
+
+        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
+            if (!this._init) return;
+            if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000]) return;
+
+            position.divideToRef(collider.radius, this._scaledPosition);
+            velocity.divideToRef(collider.radius, this._scaledVelocity);
+
+            this._collisionsCallbackArray[collisionIndex] = onNewPosition;
+
+            var payload: CollidePayload = {
+                collider: {
+                    position: this._scaledPosition.asArray(),
+                    velocity: this._scaledVelocity.asArray(),
+                    radius: collider.radius.asArray()
+                },
+                collisionId: collisionIndex,
+                excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
+                maximumRetry: maximumRetry
+            };
+            var message: BabylonMessage = {
+                payload: payload,
+                taskType: WorkerTaskType.COLLIDE
+            }
+            this._worker.postMessage(message);
+
+        }
+
+        public init(scene: Scene): void {
+            this._scene = scene;
+            this._scene.registerAfterRender(this._afterRender);
+            var workerUrl = BABYLON.WorkerIncluded ? Engine.CodeRepository + "Collisions/babylon.collisionWorker.js" : URL.createObjectURL(new Blob([BABYLON.CollisionWorker], { type: 'application/javascript' }));
+            this._worker = new Worker(workerUrl);
+            this._worker.onmessage = this._onMessageFromWorker;
+            var message: BabylonMessage = {
+                payload: {},
+                taskType: WorkerTaskType.INIT
+            }
+            this._worker.postMessage(message);
+        }
+
+        public destroy(): void {
+            this._scene.unregisterAfterRender(this._afterRender);
+            this._worker.terminate();
+        }
+
+        public onMeshAdded(mesh: AbstractMesh) {
+            mesh.registerAfterWorldMatrixUpdate(this.onMeshUpdated);
+            this.onMeshUpdated(mesh);
+        }
+
+        public onMeshUpdated = (mesh: AbstractMesh) => {
+            this._addUpdateMeshesList[mesh.uniqueId] = CollisionCoordinatorWorker.SerializeMesh(mesh);
+        }
+
+        public onMeshRemoved(mesh: AbstractMesh) {
+            this._toRemoveMeshesArray.push(mesh.uniqueId);
+        }
+
+        public onGeometryAdded(geometry: Geometry) {
+            //TODO this will break if the user uses his own function. This should be an array of callbacks!
+            geometry.onGeometryUpdated = this.onGeometryUpdated;
+            this.onGeometryUpdated(geometry);
+        }
+
+        public onGeometryUpdated = (geometry: Geometry) => {
+            this._addUpdateGeometriesList[geometry.id] = CollisionCoordinatorWorker.SerializeGeometry(geometry);
+        }
+
+        public onGeometryDeleted(geometry: Geometry) {
+            this._toRemoveGeometryArray.push(geometry.id);
+        }
+
+        private _afterRender = () => {
+
+            if (!this._init) return;
+
+            if (this._toRemoveGeometryArray.length == 0 && this._toRemoveMeshesArray.length == 0 && Object.keys(this._addUpdateGeometriesList).length == 0 && Object.keys(this._addUpdateMeshesList).length == 0) {
+                return;
+            }
+
+            //5 concurrent updates were sent to the web worker and were not yet processed. Abort next update.
+            //TODO make sure update runs as fast as possible to be able to update 60 FPS.
+            if (this._runningUpdated > 4) {
+                return;
+            }
+
+            ++this._runningUpdated;
+
+            var payload: UpdatePayload = {
+                updatedMeshes: this._addUpdateMeshesList,
+                updatedGeometries: this._addUpdateGeometriesList,
+                removedGeometries: this._toRemoveGeometryArray,
+                removedMeshes: this._toRemoveMeshesArray
+            };
+            var message: BabylonMessage = {
+                payload: payload,
+                taskType: WorkerTaskType.UPDATE
+            }
+            var serializable = [];
+            for (var id in payload.updatedGeometries) {
+                if (payload.updatedGeometries.hasOwnProperty(id)) {
+                    //prepare transferables
+                    serializable.push((<UpdatePayload> message.payload).updatedGeometries[id].indices.buffer);
+                    serializable.push((<UpdatePayload> message.payload).updatedGeometries[id].normals.buffer);
+                    serializable.push((<UpdatePayload> message.payload).updatedGeometries[id].positions.buffer);
+                }
+            }
+
+            this._worker.postMessage(message, serializable);
+            this._addUpdateMeshesList = {};
+            this._addUpdateGeometriesList = {};
+            this._toRemoveGeometryArray = [];
+            this._toRemoveMeshesArray = [];
+        }
+
+        private _onMessageFromWorker = (e: MessageEvent) => {
+            var returnData = <WorkerReply> e.data;
+            if (returnData.error != WorkerReplyType.SUCCESS) {
+                //TODO what errors can be returned from the worker?
+                Tools.Warn("error returned from worker!");
+                return;
+            }
+
+            switch (returnData.taskType) {
+                case WorkerTaskType.INIT:
+                    this._init = true;
+                    //Update the worked with ALL of the scene's current state
+                    this._scene.meshes.forEach((mesh) => {
+                        this.onMeshAdded(mesh);
+                    });
+
+                    this._scene.getGeometries().forEach((geometry) => {
+                        this.onGeometryAdded(geometry);
+                    });
+
+                    break;
+                case WorkerTaskType.UPDATE:
+                    this._runningUpdated--;
+                    break;
+                case WorkerTaskType.COLLIDE:
+                    this._runningCollisionTask = false;
+                    var returnPayload: CollisionReplyPayload = returnData.payload;
+                    if (!this._collisionsCallbackArray[returnPayload.collisionId]) return;
+
+                    this._collisionsCallbackArray[returnPayload.collisionId](returnPayload.collisionId, Vector3.FromArray(returnPayload.newPosition), this._scene.getMeshByUniqueID(returnPayload.collidedMeshUniqueId));
+                    //cleanup
+                    this._collisionsCallbackArray[returnPayload.collisionId] = undefined;
+                    break;
+            }
+        }
+    }
+
+    export class CollisionCoordinatorLegacy implements ICollisionCoordinator {
+
+        private _scene: Scene;
+
+        private _scaledPosition = Vector3.Zero();
+        private _scaledVelocity = Vector3.Zero();
+
+        private _finalPosition = Vector3.Zero();
+
+        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
+            position.divideToRef(collider.radius, this._scaledPosition);
+            velocity.divideToRef(collider.radius, this._scaledVelocity);
+			collider.collidedMesh = null;
+            collider.retry = 0;
+            collider.initialVelocity = this._scaledVelocity;
+            collider.initialPosition = this._scaledPosition;
+            this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, this._finalPosition, excludedMesh);
+
+            this._finalPosition.multiplyInPlace(collider.radius);
+            //run the callback
+            onNewPosition(collisionIndex, this._finalPosition, collider.collidedMesh);
+        }
+
+        public init(scene: Scene): void {
+            this._scene = scene;
+        }
+
+        public destroy(): void {
+            //Legacy need no destruction method.
+        }
+
+        //No update in legacy mode
+        public onMeshAdded(mesh: AbstractMesh) { }
+        public onMeshUpdated(mesh: AbstractMesh) { }
+        public onMeshRemoved(mesh: AbstractMesh) { }
+        public onGeometryAdded(geometry: Geometry) { }
+        public onGeometryUpdated(geometry: Geometry) { }
+        public onGeometryDeleted(geometry: Geometry) { }
+
+        private _collideWithWorld(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3, excludedMesh: AbstractMesh = null): void {
+            var closeDistance = Engine.CollisionsEpsilon * 10.0;
+
+            if (collider.retry >= maximumRetry) {
+                finalPosition.copyFrom(position);
+                return;
+            }
+
+            collider._initialize(position, velocity, closeDistance);
+
+            // Check all meshes
+            for (var index = 0; index < this._scene.meshes.length; index++) {
+                var mesh = this._scene.meshes[index];
+                if (mesh.isEnabled() && mesh.checkCollisions && mesh.subMeshes && mesh !== excludedMesh) {
+                    mesh._checkCollision(collider);
+                }
+            }
+
+            if (!collider.collisionFound) {
+                position.addToRef(velocity, finalPosition);
+                return;
+            }
+
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
+                collider._getResponse(position, velocity);
+            }
+
+            if (velocity.length() <= closeDistance) {
+                finalPosition.copyFrom(position);
+                return;
+            }
+
+            collider.retry++;
+            this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
+        }
+    }
+}

+ 230 - 0
Babylon/Collisions/babylon.collisionWorker.js

@@ -0,0 +1,230 @@
+var BABYLON;
+(function (BABYLON) {
+    //If this file is included in the main thread, this will be initialized.
+    BABYLON.WorkerIncluded = true;
+    var CollisionCache = (function () {
+        function CollisionCache() {
+            this._meshes = {};
+            this._geometries = {};
+        }
+        CollisionCache.prototype.getMeshes = function () {
+            return this._meshes;
+        };
+        CollisionCache.prototype.getGeometries = function () {
+            return this._geometries;
+        };
+        CollisionCache.prototype.getMesh = function (id) {
+            return this._meshes[id];
+        };
+        CollisionCache.prototype.addMesh = function (mesh) {
+            this._meshes[mesh.uniqueId] = mesh;
+        };
+        CollisionCache.prototype.getGeometry = function (id) {
+            return this._geometries[id];
+        };
+        CollisionCache.prototype.addGeometry = function (geometry) {
+            this._geometries[geometry.id] = geometry;
+        };
+        return CollisionCache;
+    })();
+    BABYLON.CollisionCache = CollisionCache;
+    var CollideWorker = (function () {
+        function CollideWorker(collider, _collisionCache, finalPosition) {
+            this.collider = collider;
+            this._collisionCache = _collisionCache;
+            this.finalPosition = finalPosition;
+            this.collisionsScalingMatrix = BABYLON.Matrix.Zero();
+            this.collisionTranformationMatrix = BABYLON.Matrix.Zero();
+        }
+        CollideWorker.prototype.collideWithWorld = function (position, velocity, maximumRetry, excludedMeshUniqueId) {
+            //TODO CollisionsEpsilon should be defined here and not in the engine.
+            var closeDistance = 0.01;
+            //is initializing here correct? A quick look - looks like it is fine.
+            if (this.collider.retry >= maximumRetry) {
+                this.finalPosition.copyFrom(position);
+                return;
+            }
+            this.collider._initialize(position, velocity, closeDistance);
+            // Check all meshes
+            var meshes = this._collisionCache.getMeshes();
+            var keys = Object.keys(meshes);
+            var len = keys.length;
+            var uniqueId;
+            for (var i = 0; i < len; ++i) {
+                uniqueId = keys[i];
+                if (parseInt(uniqueId) != excludedMeshUniqueId) {
+                    var mesh = meshes[uniqueId];
+                    if (mesh.checkCollisions)
+                        this.checkCollision(mesh);
+                }
+            }
+            if (!this.collider.collisionFound) {
+                position.addToRef(velocity, this.finalPosition);
+                return;
+            }
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
+                this.collider._getResponse(position, velocity);
+            }
+            if (velocity.length() <= closeDistance) {
+                this.finalPosition.copyFrom(position);
+                return;
+            }
+            this.collider.retry++;
+            this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
+        };
+        CollideWorker.prototype.checkCollision = function (mesh) {
+            if (!this.collider._canDoCollision(BABYLON.Vector3.FromArray(mesh.sphereCenter), mesh.sphereRadius, BABYLON.Vector3.FromArray(mesh.boxMinimum), BABYLON.Vector3.FromArray(mesh.boxMaximum))) {
+                return;
+            }
+            ;
+            // Transformation matrix
+            BABYLON.Matrix.ScalingToRef(1.0 / this.collider.radius.x, 1.0 / this.collider.radius.y, 1.0 / this.collider.radius.z, this.collisionsScalingMatrix);
+            var worldFromCache = BABYLON.Matrix.FromArray(mesh.worldMatrixFromCache);
+            worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
+            this.processCollisionsForSubMeshes(this.collisionTranformationMatrix, mesh);
+            //return colTransMat;
+        };
+        CollideWorker.prototype.processCollisionsForSubMeshes = function (transformMatrix, mesh) {
+            var len;
+            var subMeshes;
+            // No Octrees for now
+            //if (this._submeshesOctree && this.useOctreeForCollisions) {
+            //    var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
+            //    var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
+            //    len = intersections.length;
+            //    subMeshes = intersections.data;
+            //} else {
+            subMeshes = mesh.subMeshes;
+            len = subMeshes.length;
+            //}
+            if (!mesh.geometryId) {
+                console.log("no mesh geometry id");
+                return;
+            }
+            var meshGeometry = this._collisionCache.getGeometry(mesh.geometryId);
+            if (!meshGeometry) {
+                console.log("couldn't find geometry", mesh.geometryId);
+                return;
+            }
+            for (var index = 0; index < len; index++) {
+                var subMesh = subMeshes[index];
+                // Bounding test
+                if (len > 1 && !this.checkSubmeshCollision(subMesh))
+                    continue;
+                this.collideForSubMesh(subMesh, transformMatrix, meshGeometry);
+                if (this.collider.collisionFound) {
+                    this.collider.collidedMesh = mesh.uniqueId;
+                }
+            }
+        };
+        CollideWorker.prototype.collideForSubMesh = function (subMesh, transformMatrix, meshGeometry) {
+            if (!meshGeometry['positionsArray']) {
+                meshGeometry['positionsArray'] = [];
+                for (var i = 0, len = meshGeometry.positions.length; i < len; i = i + 3) {
+                    var p = BABYLON.Vector3.FromArray([meshGeometry.positions[i], meshGeometry.positions[i + 1], meshGeometry.positions[i + 2]]);
+                    meshGeometry['positionsArray'].push(p);
+                }
+            }
+            if (!subMesh['_lastColliderWorldVertices'] || !subMesh['_lastColliderTransformMatrix'].equals(transformMatrix)) {
+                subMesh['_lastColliderTransformMatrix'] = transformMatrix.clone();
+                subMesh['_lastColliderWorldVertices'] = [];
+                subMesh['_trianglePlanes'] = [];
+                var start = subMesh.verticesStart;
+                var end = (subMesh.verticesStart + subMesh.verticesCount);
+                for (var i = start; i < end; i++) {
+                    subMesh['_lastColliderWorldVertices'].push(BABYLON.Vector3.TransformCoordinates(meshGeometry['positionsArray'][i], transformMatrix));
+                }
+            }
+            // Collide
+            this.collider._collide(subMesh['_trianglePlanes'], subMesh['_lastColliderWorldVertices'], meshGeometry.indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, subMesh.hasMaterial);
+        };
+        CollideWorker.prototype.checkSubmeshCollision = function (subMesh) {
+            return this.collider._canDoCollision(BABYLON.Vector3.FromArray(subMesh.sphereCenter), subMesh.sphereRadius, BABYLON.Vector3.FromArray(subMesh.boxMinimum), BABYLON.Vector3.FromArray(subMesh.boxMaximum));
+        };
+        return CollideWorker;
+    })();
+    BABYLON.CollideWorker = CollideWorker;
+    var CollisionDetectorTransferable = (function () {
+        function CollisionDetectorTransferable() {
+        }
+        CollisionDetectorTransferable.prototype.onInit = function (payload) {
+            this._collisionCache = new CollisionCache();
+            var reply = {
+                error: BABYLON.WorkerReplyType.SUCCESS,
+                taskType: BABYLON.WorkerTaskType.INIT
+            };
+            postMessage(reply, undefined);
+        };
+        CollisionDetectorTransferable.prototype.onUpdate = function (payload) {
+            for (var id in payload.updatedGeometries) {
+                if (payload.updatedGeometries.hasOwnProperty(id)) {
+                    this._collisionCache.addGeometry(payload.updatedGeometries[id]);
+                }
+            }
+            for (var uniqueId in payload.updatedMeshes) {
+                if (payload.updatedMeshes.hasOwnProperty(uniqueId)) {
+                    this._collisionCache.addMesh(payload.updatedMeshes[uniqueId]);
+                }
+            }
+            var replay = {
+                error: BABYLON.WorkerReplyType.SUCCESS,
+                taskType: BABYLON.WorkerTaskType.UPDATE
+            };
+            postMessage(replay, undefined);
+        };
+        CollisionDetectorTransferable.prototype.onCollision = function (payload) {
+            var finalPosition = BABYLON.Vector3.Zero();
+            //create a new collider
+            var collider = new BABYLON.Collider();
+            collider.radius = BABYLON.Vector3.FromArray(payload.collider.radius);
+            var colliderWorker = new CollideWorker(collider, this._collisionCache, finalPosition);
+            colliderWorker.collideWithWorld(BABYLON.Vector3.FromArray(payload.collider.position), BABYLON.Vector3.FromArray(payload.collider.velocity), payload.maximumRetry, payload.excludedMeshUniqueId);
+            var replyPayload = {
+                collidedMeshUniqueId: collider.collidedMesh,
+                collisionId: payload.collisionId,
+                newPosition: finalPosition.asArray()
+            };
+            var reply = {
+                error: BABYLON.WorkerReplyType.SUCCESS,
+                taskType: BABYLON.WorkerTaskType.COLLIDE,
+                payload: replyPayload
+            };
+            postMessage(reply, undefined);
+        };
+        return CollisionDetectorTransferable;
+    })();
+    BABYLON.CollisionDetectorTransferable = CollisionDetectorTransferable;
+    //check if we are in a web worker, as this code should NOT run on the main UI thread
+    try {
+        if (self && self instanceof WorkerGlobalScope) {
+            //Window hack to allow including babylonjs native code. the <any> is for typescript.
+            window = {};
+            //scripts were not included, standalone worker
+            if (!BABYLON.Collider) {
+                importScripts("./babylon.collisionCoordinator.js");
+                importScripts("./babylon.collider.js");
+                importScripts("../Math/babylon.math.js");
+            }
+            var collisionDetector = new CollisionDetectorTransferable();
+            var onNewMessage = function (event) {
+                var message = event.data;
+                switch (message.taskType) {
+                    case BABYLON.WorkerTaskType.INIT:
+                        collisionDetector.onInit(message.payload);
+                        break;
+                    case BABYLON.WorkerTaskType.COLLIDE:
+                        collisionDetector.onCollision(message.payload);
+                        break;
+                    case BABYLON.WorkerTaskType.UPDATE:
+                        collisionDetector.onUpdate(message.payload);
+                        break;
+                }
+            };
+            self.onmessage = onNewMessage;
+        }
+    }
+    catch (e) {
+        console.log("single worker init");
+    }
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.collisionWorker.js.map

+ 274 - 0
Babylon/Collisions/babylon.collisionWorker.ts

@@ -0,0 +1,274 @@
+module BABYLON {
+
+    //If this file is included in the main thread, this will be initialized.
+    export var WorkerIncluded: boolean = true;
+
+    export class CollisionCache {
+        private _meshes: { [n: number]: SerializedMesh; } = {};
+        private _geometries: { [s: number]: SerializedGeometry; } = {};
+
+        public getMeshes(): { [n: number]: SerializedMesh; } {
+            return this._meshes;
+        }
+
+        public getGeometries(): { [s: number]: SerializedGeometry; } {
+            return this._geometries;
+        }
+
+        public getMesh(id: any): SerializedMesh {
+            return this._meshes[id];
+        }
+
+        public addMesh(mesh: SerializedMesh) {
+            this._meshes[mesh.uniqueId] = mesh;
+        }
+
+        public getGeometry(id: string): SerializedGeometry {
+            return this._geometries[id];
+        }
+
+        public addGeometry(geometry: SerializedGeometry) {
+            this._geometries[geometry.id] = geometry;
+        }
+    }
+
+    export class CollideWorker {
+
+        private collisionsScalingMatrix = Matrix.Zero();
+        private collisionTranformationMatrix = Matrix.Zero();
+
+        constructor(public collider: Collider, private _collisionCache: CollisionCache, private finalPosition: Vector3) {
+
+        }
+
+        public collideWithWorld(position: Vector3, velocity: Vector3, maximumRetry: number, excludedMeshUniqueId?: number) {
+
+            //TODO CollisionsEpsilon should be defined here and not in the engine.
+            var closeDistance = /*Engine.CollisionsEpsilon * 10.0*/ 0.01;
+
+            //is initializing here correct? A quick look - looks like it is fine.
+            if (this.collider.retry >= maximumRetry) {
+                this.finalPosition.copyFrom(position);
+                return;
+            }
+
+            this.collider._initialize(position, velocity, closeDistance);
+
+            // Check all meshes
+            var meshes = this._collisionCache.getMeshes();
+            var keys = Object.keys(meshes);
+            var len = keys.length;
+            var uniqueId;
+
+            for (var i = 0; i < len; ++i) {
+                uniqueId = keys[i];
+                if (parseInt(uniqueId) != excludedMeshUniqueId) {
+                    var mesh: SerializedMesh = meshes[uniqueId];
+                    if (mesh.checkCollisions)
+                        this.checkCollision(mesh);
+                }
+            }
+
+            if (!this.collider.collisionFound) {
+                position.addToRef(velocity, this.finalPosition);
+                return;
+            }
+
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
+                this.collider._getResponse(position, velocity);
+            }
+
+            if (velocity.length() <= closeDistance) {
+                this.finalPosition.copyFrom(position);
+                return;
+            }
+
+            this.collider.retry++;
+            this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
+        }
+
+        private checkCollision(mesh: SerializedMesh) {
+
+            if (!this.collider._canDoCollision(Vector3.FromArray(mesh.sphereCenter), mesh.sphereRadius, Vector3.FromArray(mesh.boxMinimum), Vector3.FromArray(mesh.boxMaximum))) {
+                return;
+            };
+
+            // Transformation matrix
+            Matrix.ScalingToRef(1.0 / this.collider.radius.x, 1.0 / this.collider.radius.y, 1.0 / this.collider.radius.z, this.collisionsScalingMatrix);
+            var worldFromCache = Matrix.FromArray(mesh.worldMatrixFromCache);
+            worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
+
+            this.processCollisionsForSubMeshes(this.collisionTranformationMatrix, mesh);
+            //return colTransMat;
+        }
+
+        private processCollisionsForSubMeshes(transformMatrix: Matrix, mesh: SerializedMesh): void {
+            var len: number;
+            var subMeshes;
+
+            // No Octrees for now
+            //if (this._submeshesOctree && this.useOctreeForCollisions) {
+            //    var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
+            //    var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
+
+            //    len = intersections.length;
+            //    subMeshes = intersections.data;
+            //} else {
+                subMeshes = mesh.subMeshes;
+                len = subMeshes.length;
+            //}
+
+            if (!mesh.geometryId) {
+                console.log("no mesh geometry id");
+                return;
+            }
+
+            var meshGeometry = this._collisionCache.getGeometry(mesh.geometryId);
+            if (!meshGeometry) {
+                console.log("couldn't find geometry", mesh.geometryId);
+                return;
+            }
+
+            for (var index = 0; index < len; index++) {
+                var subMesh = subMeshes[index];
+
+                // Bounding test
+                if (len > 1 && !this.checkSubmeshCollision(subMesh))
+                    continue;
+
+                this.collideForSubMesh(subMesh, transformMatrix, meshGeometry);
+				if (this.collider.collisionFound) {
+					this.collider.collidedMesh = <any> mesh.uniqueId;
+				}
+            }
+        }
+
+        private collideForSubMesh(subMesh: SerializedSubMesh, transformMatrix: Matrix, meshGeometry: SerializedGeometry): void {
+            if (!meshGeometry['positionsArray']) {
+                meshGeometry['positionsArray'] = [];
+                for (var i = 0, len = meshGeometry.positions.length; i < len; i = i + 3) {
+                    var p = Vector3.FromArray([meshGeometry.positions[i], meshGeometry.positions[i + 1], meshGeometry.positions[i + 2]]);
+                    meshGeometry['positionsArray'].push(p);
+                }
+            }
+            
+            if (!subMesh['_lastColliderWorldVertices'] || !subMesh['_lastColliderTransformMatrix'].equals(transformMatrix)) {
+                subMesh['_lastColliderTransformMatrix'] = transformMatrix.clone();
+                subMesh['_lastColliderWorldVertices'] = [];
+                subMesh['_trianglePlanes'] = [];
+                var start = subMesh.verticesStart;
+                var end = (subMesh.verticesStart + subMesh.verticesCount);
+                for (var i = start; i < end; i++) {
+                    subMesh['_lastColliderWorldVertices'].push(Vector3.TransformCoordinates(meshGeometry['positionsArray'][i], transformMatrix));
+                }
+            }        
+
+            // Collide
+            this.collider._collide(subMesh['_trianglePlanes'], subMesh['_lastColliderWorldVertices'], <any> meshGeometry.indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, subMesh.hasMaterial);
+			
+        }
+
+        private checkSubmeshCollision(subMesh: SerializedSubMesh) : boolean {
+            return this.collider._canDoCollision(Vector3.FromArray(subMesh.sphereCenter), subMesh.sphereRadius, Vector3.FromArray(subMesh.boxMinimum), Vector3.FromArray(subMesh.boxMaximum));
+        }
+    }
+
+    export interface ICollisionDetector {
+        onInit(payload: InitPayload): void;
+        onUpdate(payload: UpdatePayload): void;
+        onCollision(payload: CollidePayload): void;
+    }
+
+    export class CollisionDetectorTransferable implements ICollisionDetector {
+        private _collisionCache: CollisionCache;
+
+        public onInit(payload: InitPayload) {
+            this._collisionCache = new CollisionCache();
+            var reply: WorkerReply = {
+                error: WorkerReplyType.SUCCESS,
+                taskType: WorkerTaskType.INIT
+            }
+            postMessage(reply, undefined);
+        }
+
+        public onUpdate(payload: UpdatePayload) {
+            for (var id in payload.updatedGeometries) {
+                if (payload.updatedGeometries.hasOwnProperty(id)) {
+                    this._collisionCache.addGeometry(payload.updatedGeometries[id]);
+                }
+            }
+            for (var uniqueId in payload.updatedMeshes) {
+                if (payload.updatedMeshes.hasOwnProperty(uniqueId)) {
+                    this._collisionCache.addMesh(payload.updatedMeshes[uniqueId]);
+                }
+            }
+
+            var replay: WorkerReply = {
+                error: WorkerReplyType.SUCCESS,
+                taskType: WorkerTaskType.UPDATE
+            }
+            postMessage(replay, undefined);
+        }
+
+        public onCollision(payload: CollidePayload) {
+            var finalPosition = Vector3.Zero();
+            //create a new collider
+            var collider = new Collider();
+            collider.radius = Vector3.FromArray(payload.collider.radius);
+
+            var colliderWorker = new CollideWorker(collider, this._collisionCache, finalPosition);
+            colliderWorker.collideWithWorld(Vector3.FromArray(payload.collider.position), Vector3.FromArray(payload.collider.velocity), payload.maximumRetry, payload.excludedMeshUniqueId);
+            var replyPayload: CollisionReplyPayload = {
+                collidedMeshUniqueId: <any> collider.collidedMesh,
+                collisionId: payload.collisionId,
+                newPosition: finalPosition.asArray()
+            }
+            var reply: WorkerReply = {
+                error: WorkerReplyType.SUCCESS,
+                taskType: WorkerTaskType.COLLIDE,
+                payload: replyPayload
+            }
+            postMessage(reply, undefined);
+        }
+    }
+
+    //TypeScript doesn't know WorkerGlobalScope
+    declare class WorkerGlobalScope { }
+
+    //check if we are in a web worker, as this code should NOT run on the main UI thread
+    try {
+        if (self && self instanceof WorkerGlobalScope) {
+
+            //Window hack to allow including babylonjs native code. the <any> is for typescript.
+            window = <any> {};
+
+            //scripts were not included, standalone worker
+            if (!BABYLON.Collider) {
+                importScripts("./babylon.collisionCoordinator.js");
+                importScripts("./babylon.collider.js");
+                importScripts("../Math/babylon.math.js");
+            }
+
+            var collisionDetector: ICollisionDetector = new CollisionDetectorTransferable();
+
+            var onNewMessage = function (event: MessageEvent) {
+                var message = <BabylonMessage> event.data;
+                switch (message.taskType) {
+                    case WorkerTaskType.INIT:
+                        collisionDetector.onInit(<InitPayload> message.payload);
+                        break;
+                    case WorkerTaskType.COLLIDE:
+                        collisionDetector.onCollision(<CollidePayload> message.payload);
+                        break;
+                    case WorkerTaskType.UPDATE:
+                        collisionDetector.onUpdate(<UpdatePayload> message.payload);
+                        break;
+                }
+            }
+
+            self.onmessage = onNewMessage;
+        }
+    } catch (e) {
+        console.log("single worker init");
+    }
+}

+ 1 - 0
Babylon/Culling/Octrees/babylon.octree.js

@@ -59,6 +59,7 @@ var BABYLON;
         Octree._CreateBlocks = function (worldMin, worldMax, entries, maxBlockCapacity, currentDepth, maxDepth, target, creationFunc) {
             target.blocks = new Array();
             var blockSize = new BABYLON.Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
+            // Segmenting space
             for (var x = 0; x < 2; x++) {
                 for (var y = 0; y < 2; y++) {
                     for (var z = 0; z < 2; z++) {

+ 3 - 3
Babylon/Culling/Octrees/babylon.octree.ts

@@ -13,7 +13,7 @@
 
         constructor(creationFunc: (entry: T, block: OctreeBlock<T>) => void, maxBlockCapacity?: number, public maxDepth = 2) {
             this._maxBlockCapacity = maxBlockCapacity || 64;
-            this._selectionContent = new BABYLON.SmartArray<T>(1024);
+            this._selectionContent = new SmartArray<T>(1024);
             this._creationFunc = creationFunc;
         }
 
@@ -78,7 +78,7 @@
 
         public static _CreateBlocks<T>(worldMin: Vector3, worldMax: Vector3, entries: T[], maxBlockCapacity: number, currentDepth: number, maxDepth: number, target: IOctreeContainer<T>, creationFunc: (entry: T, block: OctreeBlock<T>) => void): void {
             target.blocks = new Array<OctreeBlock<T>>();
-            var blockSize = new BABYLON.Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
+            var blockSize = new Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
 
             // Segmenting space
             for (var x = 0; x < 2; x++) {
@@ -87,7 +87,7 @@
                         var localMin = worldMin.add(blockSize.multiplyByFloats(x, y, z));
                         var localMax = worldMin.add(blockSize.multiplyByFloats(x + 1, y + 1, z + 1));
 
-                        var block = new BABYLON.OctreeBlock<T>(localMin, localMax, maxBlockCapacity, currentDepth + 1, maxDepth, creationFunc);
+                        var block = new OctreeBlock<T>(localMin, localMax, maxBlockCapacity, currentDepth + 1, maxDepth, creationFunc);
                         block.addEntries(entries);
                         target.blocks.push(block);
                     }

+ 2 - 2
Babylon/Culling/Octrees/babylon.octreeBlock.ts

@@ -80,7 +80,7 @@
         }
 
         public select(frustumPlanes: Plane[], selection: SmartArray<T>, allowDuplicate?: boolean): void {
-            if (BABYLON.BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
+            if (BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
                 if (this.blocks) {
                     for (var index = 0; index < this.blocks.length; index++) {
                         var block = this.blocks[index];
@@ -98,7 +98,7 @@
         }
 
         public intersects(sphereCenter: Vector3, sphereRadius: number, selection: SmartArray<T>, allowDuplicate?: boolean): void {
-            if (BABYLON.BoundingBox.IntersectsSphere(this._minPoint, this._maxPoint, sphereCenter, sphereRadius)) {
+            if (BoundingBox.IntersectsSphere(this._minPoint, this._maxPoint, sphereCenter, sphereRadius)) {
                 if (this.blocks) {
                     for (var index = 0; index < this.blocks.length; index++) {
                         var block = this.blocks[index];

+ 1 - 1
Babylon/Culling/babylon.BoundingBox.ts

@@ -96,7 +96,7 @@
         }
 
         public intersectsPoint(point: Vector3): boolean {
-            var delta = Engine.Epsilon;
+            var delta = -Engine.Epsilon;
 
             if (this.maximumWorld.x - point.x < delta || delta > point.x - this.minimumWorld.x)
                 return false;

+ 2 - 1
Babylon/Culling/babylon.boundingBox.js

@@ -25,6 +25,7 @@ var BABYLON;
             this.center = this.maximum.add(this.minimum).scale(0.5);
             this.extendSize = this.maximum.subtract(this.minimum).scale(0.5);
             this.directions = [BABYLON.Vector3.Zero(), BABYLON.Vector3.Zero(), BABYLON.Vector3.Zero()];
+            // World
             for (var index = 0; index < this.vectors.length; index++) {
                 this.vectorsWorld[index] = BABYLON.Vector3.Zero();
             }
@@ -70,7 +71,7 @@ var BABYLON;
             return BoundingBox.IsCompletelyInFrustum(this.vectorsWorld, frustumPlanes);
         };
         BoundingBox.prototype.intersectsPoint = function (point) {
-            var delta = BABYLON.Engine.Epsilon;
+            var delta = -BABYLON.Engine.Epsilon;
             if (this.maximumWorld.x - point.x < delta || delta > point.x - this.minimumWorld.x)
                 return false;
             if (this.maximumWorld.y - point.y < delta || delta > point.y - this.minimumWorld.y)

+ 13 - 13
Babylon/Culling/babylon.boundingInfo.ts

@@ -27,8 +27,8 @@
         public boundingSphere: BoundingSphere;
 
         constructor(public minimum: Vector3, public maximum: Vector3) {
-            this.boundingBox = new BABYLON.BoundingBox(minimum, maximum);
-            this.boundingSphere = new BABYLON.BoundingSphere(minimum, maximum);
+            this.boundingBox = new BoundingBox(minimum, maximum);
+            this.boundingSphere = new BoundingSphere(minimum, maximum);
         }
 
         // Methods
@@ -73,11 +73,11 @@
                 return false;
             }
 
-            if (!BABYLON.BoundingSphere.Intersects(this.boundingSphere, boundingInfo.boundingSphere)) {
+            if (!BoundingSphere.Intersects(this.boundingSphere, boundingInfo.boundingSphere)) {
                 return false;
             }
 
-            if (!BABYLON.BoundingBox.Intersects(this.boundingBox, boundingInfo.boundingBox)) {
+            if (!BoundingBox.Intersects(this.boundingBox, boundingInfo.boundingBox)) {
                 return false;
             }
 
@@ -94,15 +94,15 @@
             if (!axisOverlap(box1.directions[0], box0, box1)) return false;
             if (!axisOverlap(box1.directions[1], box0, box1)) return false;
             if (!axisOverlap(box1.directions[2], box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[0], box1.directions[0]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[0], box1.directions[1]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[0], box1.directions[2]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[1], box1.directions[0]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[1], box1.directions[1]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[1], box1.directions[2]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[2], box1.directions[0]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[2], box1.directions[1]), box0, box1)) return false;
-            if (!axisOverlap(BABYLON.Vector3.Cross(box0.directions[2], box1.directions[2]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[0]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[1]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[2]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[0]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[1]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[2]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[0]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[1]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[2]), box0, box1)) return false;
 
             return true;
         }

+ 6 - 6
Babylon/Culling/babylon.boundingSphere.ts

@@ -8,19 +8,19 @@
         private _tempRadiusVector = Vector3.Zero();
 
         constructor(public minimum: Vector3, public maximum: Vector3) {
-            var distance = BABYLON.Vector3.Distance(minimum, maximum);
+            var distance = Vector3.Distance(minimum, maximum);
 
-            this.center = BABYLON.Vector3.Lerp(minimum, maximum, 0.5);
+            this.center = Vector3.Lerp(minimum, maximum, 0.5);
             this.radius = distance * 0.5;
 
-            this.centerWorld = BABYLON.Vector3.Zero();
-            this._update(BABYLON.Matrix.Identity());
+            this.centerWorld = Vector3.Zero();
+            this._update(Matrix.Identity());
         }
 
         // Methods
         public _update(world: Matrix): void {
-            BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, this._tempRadiusVector);
+            Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
+            Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, this._tempRadiusVector);
             this.radiusWorld = Math.max(Math.abs(this._tempRadiusVector.x), Math.abs(this._tempRadiusVector.y), Math.abs(this._tempRadiusVector.z)) * this.radius;
         }
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 69 - 88
Babylon/Debug/babylon.debugLayer.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 1
Babylon/Debug/babylon.debugLayer.js.map


+ 1 - 1
Babylon/Debug/babylon.debugLayer.ts

@@ -714,7 +714,7 @@
                 + "Total materials: " + scene.materials.length + "<br>"
                 + "Total textures: " + scene.textures.length + "<br>"
                 + "Active meshes: " + scene.getActiveMeshes().length + "<br>"
-                + "Active vertices: " + scene.getActiveVertices() + "<br>"
+                + "Active indices: " + scene.getActiveIndices() + "<br>"
                 + "Active bones: " + scene.getActiveBones() + "<br>"
                 + "Active particles: " + scene.getActiveParticles() + "<br>"
                 + "<b>Draw calls: " + engine.drawCalls + "</b><br><br>"

+ 4 - 4
Babylon/Layer/babylon.layer.ts

@@ -13,9 +13,9 @@
         private _effect: Effect;
 
         constructor(public name: string, imgUrl: string, scene: Scene, isBackground?: boolean, color?: Color4) {
-            this.texture = imgUrl ? new BABYLON.Texture(imgUrl, scene, true) : null;
+            this.texture = imgUrl ? new Texture(imgUrl, scene, true) : null;
             this.isBackground = isBackground === undefined ? true : isBackground;
-            this.color = color === undefined ? new BABYLON.Color4(1, 1, 1, 1) : color;
+            this.color = color === undefined ? new Color4(1, 1, 1, 1) : color;
 
             this._scene = scene;
             this._scene.layers.push(this);
@@ -70,9 +70,9 @@
             engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
 
             // Draw order
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+            engine.setAlphaMode(Engine.ALPHA_COMBINE);
             engine.draw(true, 0, 6);
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+            engine.setAlphaMode(Engine.ALPHA_DISABLE);
         }
 
         public dispose(): void {

+ 2 - 2
Babylon/LensFlare/babylon.lensFlare.ts

@@ -6,8 +6,8 @@
         private _system: LensFlareSystem;
 
         constructor(public size: number, public position: number, color, imgUrl: string, system: LensFlareSystem) {
-            this.color = color || new BABYLON.Color3(1, 1, 1);
-            this.texture = imgUrl ? new BABYLON.Texture(imgUrl, system.getScene(), true) : null;
+            this.color = color || new Color3(1, 1, 1);
+            this.texture = imgUrl ? new Texture(imgUrl, system.getScene(), true) : null;
             this._system = system;
 
             system.lensFlares.push(this);

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

@@ -134,6 +134,7 @@ var BABYLON;
             engine.setAlphaMode(BABYLON.Engine.ALPHA_ADD);
             // VBOs
             engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
+            // Flares
             for (var index = 0; index < this.lensFlares.length; index++) {
                 var flare = this.lensFlares[index];
                 var x = centerX - (distX * flare.position);

+ 6 - 6
Babylon/LensFlare/babylon.lensFlareSystem.ts

@@ -74,12 +74,12 @@
         public computeEffectivePosition(globalViewport: Viewport): boolean {
             var position = this.getEmitterPosition();
 
-            position = BABYLON.Vector3.Project(position, BABYLON.Matrix.Identity(), this._scene.getTransformMatrix(), globalViewport);
+            position = Vector3.Project(position, Matrix.Identity(), this._scene.getTransformMatrix(), globalViewport);
 
             this._positionX = position.x;
             this._positionY = position.y;
 
-            position = BABYLON.Vector3.TransformCoordinates(this.getEmitterPosition(), this._scene.getViewMatrix());
+            position = Vector3.TransformCoordinates(this.getEmitterPosition(), this._scene.getViewMatrix());
 
             if (position.z > 0) {
                 if ((this._positionX > globalViewport.x) && (this._positionX < globalViewport.x + globalViewport.width)) {
@@ -101,7 +101,7 @@
             var distance = direction.length();
             direction.normalize();
 
-            var ray = new BABYLON.Ray(this._scene.activeCamera.position, direction);
+            var ray = new Ray(this._scene.activeCamera.position, direction);
             var pickInfo = this._scene.pickWithRay(ray, this.meshesSelectionPredicate, true);
 
             return !pickInfo.hit || pickInfo.distance > distance;
@@ -169,7 +169,7 @@
             engine.enableEffect(this._effect);
             engine.setState(false);
             engine.setDepthBuffer(false);
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_ADD);
+            engine.setAlphaMode(Engine.ALPHA_ADD);
 
             // VBOs
             engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
@@ -186,7 +186,7 @@
                 var cx = 2 * (x / globalViewport.width) - 1.0;
                 var cy = 1.0 - 2 * (y / globalViewport.height);
 
-                var viewportMatrix = BABYLON.Matrix.FromValues(
+                var viewportMatrix = Matrix.FromValues(
                     cw / 2, 0, 0, 0,
                     0, ch / 2, 0, 0,
                     0, 0, 1, 0,
@@ -205,7 +205,7 @@
             }
 
             engine.setDepthBuffer(true);
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+            engine.setAlphaMode(Engine.ALPHA_DISABLE);
             return true;
         }
 

+ 3 - 1
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -194,7 +194,9 @@ var BABYLON;
         });
         Object.defineProperty(ShadowGenerator.prototype, "usePoissonSampling", {
             get: function () {
-                return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING || (!this._light.supportsVSM() && (this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP || this.filter === ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP));
+                return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING ||
+                    (!this._light.supportsVSM() && (this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP ||
+                        this.filter === ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP));
             },
             set: function (value) {
                 this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);

+ 2 - 1
Babylon/Lights/babylon.directionalLight.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -28,6 +28,7 @@ var BABYLON;
             var orthoBottom = Number.MAX_VALUE;
             var tempVector3 = BABYLON.Vector3.Zero();
             var activeCamera = this.getScene().activeCamera;
+            // Check extends
             for (var meshIndex = 0; meshIndex < renderList.length; meshIndex++) {
                 var mesh = renderList[meshIndex];
                 if (!mesh) {

+ 1 - 1
Babylon/Lights/babylon.hemisphericLight.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 4 - 4
Babylon/Lights/babylon.hemisphericLight.ts

@@ -1,6 +1,6 @@
 module BABYLON {
     export class HemisphericLight extends Light {
-        public groundColor = new BABYLON.Color3(0.0, 0.0, 0.0);
+        public groundColor = new Color3(0.0, 0.0, 0.0);
 
         private _worldMatrix: Matrix;
 
@@ -9,7 +9,7 @@
         }
 
         public setDirectionToTarget(target: Vector3): Vector3 {
-            this.direction = BABYLON.Vector3.Normalize(target.subtract(Vector3.Zero()));
+            this.direction = Vector3.Normalize(target.subtract(Vector3.Zero()));
             return this.direction;
         }
 
@@ -18,14 +18,14 @@
         }
 
         public transferToEffect(effect: Effect, directionUniformName: string, groundColorUniformName: string): void {
-            var normalizeDirection = BABYLON.Vector3.Normalize(this.direction);
+            var normalizeDirection = Vector3.Normalize(this.direction);
             effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, 0);
             effect.setColor3(groundColorUniformName, this.groundColor.scale(this.intensity));
         }
 
         public _getWorldMatrix(): Matrix {
             if (!this._worldMatrix) {
-                this._worldMatrix = BABYLON.Matrix.Identity();
+                this._worldMatrix = Matrix.Identity();
             }
 
             return this._worldMatrix;

+ 7 - 2
Babylon/Lights/babylon.light.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -17,6 +17,7 @@ var BABYLON;
             this.includeOnlyWithLayerMask = 0;
             this.includedOnlyMeshes = new Array();
             this.excludedMeshes = new Array();
+            this.excludeWithLayerMask = 0;
             this._excludedMeshesIds = new Array();
             this._includedOnlyMeshesIds = new Array();
             scene.addLight(this);
@@ -42,7 +43,10 @@ var BABYLON;
             if (this.excludedMeshes.length > 0 && this.excludedMeshes.indexOf(mesh) !== -1) {
                 return false;
             }
-            if (this.includeOnlyWithLayerMask !== 0 && this.includeOnlyWithLayerMask !== mesh.layerMask) {
+            if (this.includeOnlyWithLayerMask !== 0 && (this.includeOnlyWithLayerMask & mesh.layerMask) === 0) {
+                return false;
+            }
+            if (this.excludeWithLayerMask !== 0 && this.excludeWithLayerMask & mesh.layerMask) {
                 return false;
             }
             return true;
@@ -55,6 +59,7 @@ var BABYLON;
                     this._parentedWorldMatrix = BABYLON.Matrix.Identity();
                 }
                 worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._parentedWorldMatrix);
+                this._markSyncedWithParent();
                 return this._parentedWorldMatrix;
             }
             return worldMatrix;

+ 11 - 3
Babylon/Lights/babylon.light.ts

@@ -25,6 +25,7 @@
         public includeOnlyWithLayerMask = 0;
         public includedOnlyMeshes = new Array<AbstractMesh>();
         public excludedMeshes = new Array<AbstractMesh>();
+        public excludeWithLayerMask = 0;
 
         public _shadowGenerator: ShadowGenerator;
         private _parentedWorldMatrix: Matrix;
@@ -65,7 +66,12 @@
                 return false;
             }
 
-            if (this.includeOnlyWithLayerMask !== 0 && this.includeOnlyWithLayerMask !== mesh.layerMask) {
+            if (this.includeOnlyWithLayerMask !== 0 && (this.includeOnlyWithLayerMask & mesh.layerMask) === 0) {
+                return false;
+            }
+
+
+            if (this.excludeWithLayerMask !== 0 && this.excludeWithLayerMask & mesh.layerMask) {
                 return false;
             }
 
@@ -79,11 +85,13 @@
 
             if (this.parent && this.parent.getWorldMatrix) {
                 if (!this._parentedWorldMatrix) {
-                    this._parentedWorldMatrix = BABYLON.Matrix.Identity();
+                    this._parentedWorldMatrix = Matrix.Identity();
                 }
 
                 worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._parentedWorldMatrix);
 
+                this._markSyncedWithParent();
+
                 return this._parentedWorldMatrix;
             }
 
@@ -100,4 +108,4 @@
             this.getScene().removeLight(this);
         }
     }
-} 
+} 

+ 1 - 1
Babylon/Lights/babylon.pointLight.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 1 - 1
Babylon/Lights/babylon.spotLight.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 80 - 28
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -320,16 +320,16 @@ var BABYLON;
                 var beta = parsedCamera.beta;
                 var radius = parsedCamera.radius;
                 if (parsedCamera.type === "AnaglyphArcRotateCamera") {
-                    var eye_space = parsedCamera.eye_space;
-                    camera = new BABYLON.AnaglyphArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, eye_space, scene);
+                    var interaxial_distance = parsedCamera.interaxial_distance;
+                    camera = new BABYLON.AnaglyphArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, interaxial_distance, scene);
                 }
                 else {
                     camera = new BABYLON.ArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, scene);
                 }
             }
             else if (parsedCamera.type === "AnaglyphFreeCamera") {
-                eye_space = parsedCamera.eye_space;
-                camera = new BABYLON.AnaglyphFreeCamera(parsedCamera.name, position, eye_space, scene);
+                interaxial_distance = parsedCamera.interaxial_distance;
+                camera = new BABYLON.AnaglyphFreeCamera(parsedCamera.name, position, interaxial_distance, scene);
             }
             else if (parsedCamera.type === "DeviceOrientationCamera") {
                 camera = new BABYLON.DeviceOrientationCamera(parsedCamera.name, position, scene);
@@ -345,23 +345,17 @@ var BABYLON;
             else if (parsedCamera.type === "GamepadCamera") {
                 camera = new BABYLON.GamepadCamera(parsedCamera.name, position, scene);
             }
-            else if (parsedCamera.type === "OculusCamera") {
-                camera = new BABYLON.OculusCamera(parsedCamera.name, position, scene);
-            }
-            else if (parsedCamera.type === "OculusGamepadCamera") {
-                camera = new BABYLON.OculusGamepadCamera(parsedCamera.name, position, scene);
-            }
             else if (parsedCamera.type === "TouchCamera") {
                 camera = new BABYLON.TouchCamera(parsedCamera.name, position, scene);
             }
             else if (parsedCamera.type === "VirtualJoysticksCamera") {
                 camera = new BABYLON.VirtualJoysticksCamera(parsedCamera.name, position, scene);
             }
-            else if (parsedCamera.type === "WebVRCamera") {
-                camera = new BABYLON.WebVRCamera(parsedCamera.name, position, scene);
+            else if (parsedCamera.type === "WebVRFreeCamera") {
+                camera = new BABYLON.WebVRFreeCamera(parsedCamera.name, position, scene);
             }
-            else if (parsedCamera.type === "VRDeviceOrientationCamera") {
-                camera = new BABYLON.VRDeviceOrientationCamera(parsedCamera.name, position, scene);
+            else if (parsedCamera.type === "VRDeviceOrientationFreeCamera") {
+                camera = new BABYLON.VRDeviceOrientationFreeCamera(parsedCamera.name, position, scene);
             }
             else {
                 // Free Camera is the default value
@@ -683,13 +677,14 @@ var BABYLON;
                 }
                 var effectiveTarget = propertyPath.split(".");
                 var values = value.split(",");
+                // Get effective Target
                 for (var i = 0; i < effectiveTarget.length; i++) {
                     target = target[effectiveTarget[i]];
                 }
                 // Return appropriate value with its type
-                if (target instanceof Boolean)
+                if (typeof (target) === "boolean")
                     return values[0] === "true";
-                if (target instanceof String)
+                if (typeof (target) === "string")
                     return values[0];
                 // Parameters with multiple values such as Vector3 etc.
                 var split = new Array();
@@ -730,8 +725,12 @@ var BABYLON;
                     for (var i = 0; i < parsedAction.properties.length; i++) {
                         var value = parsedAction.properties[i].value;
                         var name = parsedAction.properties[i].name;
+                        var targetType = parsedAction.properties[i].targetType;
                         if (name === "target")
-                            value = target = scene.getNodeByName(value);
+                            if (targetType !== null && targetType === "SceneProperties")
+                                value = target = scene;
+                            else
+                                value = target = scene.getNodeByName(value);
                         else if (name === "parent")
                             value = scene.getNodeByName(value);
                         else if (name === "sound")
@@ -748,7 +747,12 @@ var BABYLON;
                         parameters.push(value);
                     }
                 }
-                parameters.push(condition);
+                if (combineArray === null) {
+                    parameters.push(condition);
+                }
+                else {
+                    parameters.push(null);
+                }
                 // If interpolate value action
                 if (parsedAction.name === "InterpolateValueAction") {
                     var param = parameters[parameters.length - 2];
@@ -776,12 +780,13 @@ var BABYLON;
                 for (var i = 0; i < parsedAction.children.length; i++)
                     traverse(parsedAction.children[i], trigger, condition, newAction, null);
             };
+            // triggers
             for (var i = 0; i < parsedActions.children.length; i++) {
                 var triggerParams;
                 var trigger = parsedActions.children[i];
                 if (trigger.properties.length > 0) {
                     var param = trigger.properties[0].value;
-                    var value = trigger.properties[0].targetType == null ? param : scene.getMeshByName(param);
+                    var value = trigger.properties[0].targetType === null ? param : scene.getMeshByName(param);
                     triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: value };
                 }
                 else
@@ -796,19 +801,14 @@ var BABYLON;
             var soundName = parsedSound.name;
             var soundUrl = rootUrl + soundName;
             var options = {
-                autoplay: parsedSound.autoplay,
-                loop: parsedSound.loop,
-                volume: parsedSound.volume,
-                spatialSound: parsedSound.spatialSound,
-                maxDistance: parsedSound.maxDistance,
+                autoplay: parsedSound.autoplay, loop: parsedSound.loop, volume: parsedSound.volume,
+                spatialSound: parsedSound.spatialSound, maxDistance: parsedSound.maxDistance,
                 rolloffFactor: parsedSound.rolloffFactor,
                 refDistance: parsedSound.refDistance,
                 distanceModel: parsedSound.distanceModel,
                 playbackRate: parsedSound.playbackRate
             };
-            var newSound = new BABYLON.Sound(soundName, soundUrl, scene, function () {
-                scene._removePendingData(newSound);
-            }, options);
+            var newSound = new BABYLON.Sound(soundName, soundUrl, scene, function () { scene._removePendingData(newSound); }, options);
             scene._addPendingData(newSound);
             if (parsedSound.position) {
                 var soundPosition = BABYLON.Vector3.FromArray(parsedSound.position);
@@ -916,7 +916,7 @@ var BABYLON;
                 }
                 if (binaryInfo.colorsAttrDesc && binaryInfo.colorsAttrDesc.count > 0) {
                     var colorsData = new Float32Array(parsedGeometry, binaryInfo.colorsAttrDesc.offset, binaryInfo.colorsAttrDesc.count);
-                    mesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, colorsData, false);
+                    mesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, colorsData, false, binaryInfo.colorsAttrDesc.stride);
                 }
                 if (binaryInfo.matricesIndicesAttrDesc && binaryInfo.matricesIndicesAttrDesc.count > 0) {
                     var matricesIndicesData = new Int32Array(parsedGeometry, binaryInfo.matricesIndicesAttrDesc.offset, binaryInfo.matricesIndicesAttrDesc.count);
@@ -1011,6 +1011,52 @@ var BABYLON;
                             // Remove found mesh name from list.
                             delete meshesNames[meshesNames.indexOf(parsedMesh.name)];
                         }
+                        //Geometry?
+                        if (parsedMesh.geometryId) {
+                            //does the file contain geometries?
+                            if (parsedData.geometries) {
+                                //find the correct geometry and add it to the scene
+                                var found = false;
+                                ["boxes", "spheres", "cylinders", "toruses", "grounds", "planes", "torusKnots", "vertexData"].forEach(function (geometryType) {
+                                    if (found || !parsedData.geometries[geometryType] || !(parsedData.geometries[geometryType] instanceof Array)) {
+                                        return;
+                                    }
+                                    else {
+                                        parsedData.geometries[geometryType].forEach(function (parsedGeometryData) {
+                                            if (parsedGeometryData.id == parsedMesh.geometryId) {
+                                                switch (geometryType) {
+                                                    case "boxes":
+                                                        parseBox(parsedGeometryData, scene);
+                                                        break;
+                                                    case "spheres":
+                                                        parseSphere(parsedGeometryData, scene);
+                                                        break;
+                                                    case "cylinders":
+                                                        parseCylinder(parsedGeometryData, scene);
+                                                        break;
+                                                    case "toruses":
+                                                        parseTorus(parsedGeometryData, scene);
+                                                        break;
+                                                    case "grounds":
+                                                        parseGround(parsedGeometryData, scene);
+                                                        break;
+                                                    case "planes":
+                                                        parsePlane(parsedGeometryData, scene);
+                                                        break;
+                                                    case "torusKnots":
+                                                        parseTorusKnot(parsedGeometryData, scene);
+                                                        break;
+                                                    case "vertexData":
+                                                        parseVertexData(parsedGeometryData, scene, rootUrl);
+                                                        break;
+                                                }
+                                                found = true;
+                                            }
+                                        });
+                                    }
+                                });
+                            }
+                        }
                         // Material ?
                         if (parsedMesh.materialId) {
                             var materialFound = (loadedMaterialsIds.indexOf(parsedMesh.materialId) !== -1);
@@ -1052,6 +1098,7 @@ var BABYLON;
                         meshes.push(mesh);
                     }
                 }
+                // Connecting parents
                 for (index = 0; index < scene.meshes.length; index++) {
                     var currentMesh = scene.meshes[index];
                     if (currentMesh._waitingParentId) {
@@ -1086,6 +1133,7 @@ var BABYLON;
                     scene.fogEnd = parsedData.fogEnd;
                     scene.fogDensity = parsedData.fogDensity;
                 }
+                // Lights
                 for (var index = 0; index < parsedData.lights.length; index++) {
                     var parsedLight = parsedData.lights[index];
                     parseLight(parsedLight, scene);
@@ -1178,10 +1226,12 @@ var BABYLON;
                         }
                     }
                 }
+                // Meshes
                 for (index = 0; index < parsedData.meshes.length; index++) {
                     var parsedMesh = parsedData.meshes[index];
                     parseMesh(parsedMesh, scene, rootUrl);
                 }
+                // Cameras
                 for (index = 0; index < parsedData.cameras.length; index++) {
                     var parsedCamera = parsedData.cameras[index];
                     parseCamera(parsedCamera, scene);
@@ -1189,6 +1239,7 @@ var BABYLON;
                 if (parsedData.activeCameraID) {
                     scene.setActiveCameraByID(parsedData.activeCameraID);
                 }
+                // Browsing all the graph to connect the dots
                 for (index = 0; index < scene.cameras.length; index++) {
                     var camera = scene.cameras[index];
                     if (camera._waitingParentId) {
@@ -1215,6 +1266,7 @@ var BABYLON;
                         }
                     }
                 }
+                // Connect parents & children and parse actions
                 for (index = 0; index < scene.meshes.length; index++) {
                     var mesh = scene.meshes[index];
                     if (mesh._waitingParentId) {

+ 71 - 20
Babylon/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -399,15 +399,15 @@
             var beta = parsedCamera.beta;
             var radius = parsedCamera.radius;
             if (parsedCamera.type === "AnaglyphArcRotateCamera") {
-                var eye_space = parsedCamera.eye_space;
-                camera = new AnaglyphArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, eye_space, scene);
+                var interaxial_distance = parsedCamera.interaxial_distance;
+                camera = new AnaglyphArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, interaxial_distance, scene);
             } else {
                 camera = new ArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, scene);
             }
 
         } else if (parsedCamera.type === "AnaglyphFreeCamera") {
-            eye_space = parsedCamera.eye_space;
-            camera = new AnaglyphFreeCamera(parsedCamera.name, position, eye_space, scene);
+            interaxial_distance = parsedCamera.interaxial_distance;
+            camera = new AnaglyphFreeCamera(parsedCamera.name, position, interaxial_distance, scene);
 
         } else if (parsedCamera.type === "DeviceOrientationCamera") {
             camera = new DeviceOrientationCamera(parsedCamera.name, position, scene);
@@ -423,23 +423,17 @@
         } else if (parsedCamera.type === "GamepadCamera") {
             camera = new GamepadCamera(parsedCamera.name, position, scene);
 
-        } else if (parsedCamera.type === "OculusCamera") {
-            camera = new OculusCamera(parsedCamera.name, position, scene);
-
-        } else if (parsedCamera.type === "OculusGamepadCamera") {
-            camera = new OculusGamepadCamera(parsedCamera.name, position, scene);
-
         } else if (parsedCamera.type === "TouchCamera") {
             camera = new TouchCamera(parsedCamera.name, position, scene);
 
         } else if (parsedCamera.type === "VirtualJoysticksCamera") {
             camera = new VirtualJoysticksCamera(parsedCamera.name, position, scene);
 
-        } else if (parsedCamera.type === "WebVRCamera") {
-            camera = new WebVRCamera(parsedCamera.name, position, scene);
+        } else if (parsedCamera.type === "WebVRFreeCamera") {
+            camera = new WebVRFreeCamera(parsedCamera.name, position, scene);
 
-        } else if (parsedCamera.type === "VRDeviceOrientationCamera") {
-            camera = new VRDeviceOrientationCamera(parsedCamera.name, position, scene);
+        } else if (parsedCamera.type === "VRDeviceOrientationFreeCamera") {
+            camera = new VRDeviceOrientationFreeCamera(parsedCamera.name, position, scene);
 
         } else {
             // Free Camera is the default value
@@ -862,10 +856,10 @@
             }
 
             // Return appropriate value with its type
-            if (target instanceof Boolean)
+            if (typeof (target) === "boolean")
                 return values[0] === "true";
 
-            if (target instanceof String)
+            if (typeof (target) === "string")
                 return values[0];
 
             // Parameters with multiple values such as Vector3 etc.
@@ -915,9 +909,13 @@
                 for (var i = 0; i < parsedAction.properties.length; i++) {
                     var value = parsedAction.properties[i].value;
                     var name = parsedAction.properties[i].name;
+                    var targetType = parsedAction.properties[i].targetType;
 
                     if (name === "target")
-                        value = target = scene.getNodeByName(value);
+                        if (targetType !== null && targetType === "SceneProperties")
+                            value = target = scene;
+                        else
+                            value = target = scene.getNodeByName(value);
                     else if (name === "parent")
                         value = scene.getNodeByName(value);
                     else if (name === "sound")
@@ -934,7 +932,13 @@
                     parameters.push(value);
                 }
             }
-            parameters.push(condition);
+
+            if (combineArray === null) {
+                parameters.push(condition);
+            }
+            else {
+                parameters.push(null);
+            }
 
             // If interpolate value action
             if (parsedAction.name === "InterpolateValueAction") {
@@ -972,7 +976,7 @@
 
             if (trigger.properties.length > 0) {
                 var param = trigger.properties[0].value;
-                var value = trigger.properties[0].targetType == null ? param : scene.getMeshByName(param);
+                var value = trigger.properties[0].targetType === null ? param : scene.getMeshByName(param);
                 triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: value };
             }
             else
@@ -1128,7 +1132,7 @@
 
             if (binaryInfo.colorsAttrDesc && binaryInfo.colorsAttrDesc.count > 0) {
                 var colorsData = new Float32Array(parsedGeometry, binaryInfo.colorsAttrDesc.offset, binaryInfo.colorsAttrDesc.count);
-                mesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, colorsData, false);
+                mesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, colorsData, false, binaryInfo.colorsAttrDesc.stride);
             }
 
             if (binaryInfo.matricesIndicesAttrDesc && binaryInfo.matricesIndicesAttrDesc.count > 0) {
@@ -1245,6 +1249,53 @@
                         delete meshesNames[meshesNames.indexOf(parsedMesh.name)];
                     }
 
+                    //Geometry?
+                    if (parsedMesh.geometryId) {
+                        //does the file contain geometries?
+                        if (parsedData.geometries) {
+                            //find the correct geometry and add it to the scene
+                            var found: boolean = false;
+                            ["boxes", "spheres", "cylinders", "toruses", "grounds", "planes", "torusKnots", "vertexData"].forEach((geometryType: string) => {
+                                if (found || !parsedData.geometries[geometryType] || !(parsedData.geometries[geometryType] instanceof Array)) {
+                                    return;
+                                } else {
+                                    parsedData.geometries[geometryType].forEach((parsedGeometryData) => {
+                                        if (parsedGeometryData.id == parsedMesh.geometryId) {
+                                            switch (geometryType) {
+                                                case "boxes":
+                                                    parseBox(parsedGeometryData, scene);
+                                                    break;
+                                                case "spheres":
+                                                    parseSphere(parsedGeometryData, scene);
+                                                    break;
+                                                case "cylinders":
+                                                    parseCylinder(parsedGeometryData, scene);
+                                                    break;
+                                                case "toruses":
+                                                    parseTorus(parsedGeometryData, scene);
+                                                    break;
+                                                case "grounds":
+                                                    parseGround(parsedGeometryData, scene);
+                                                    break;
+                                                case "planes":
+                                                    parsePlane(parsedGeometryData, scene);
+                                                    break;
+                                                case "torusKnots":
+                                                    parseTorusKnot(parsedGeometryData, scene);
+                                                    break;
+                                                case "vertexData":
+                                                    parseVertexData(parsedGeometryData, scene, rootUrl);
+                                                    break;
+                                            }
+                                            found = true;
+                                        }
+                                    });
+                                    
+                                }
+                            });
+                        }
+                    }
+
                     // Material ?
                     if (parsedMesh.materialId) {
                         var materialFound = (loadedMaterialsIds.indexOf(parsedMesh.materialId) !== -1);

+ 9 - 0
Babylon/Loading/babylon.sceneLoader.js

@@ -48,6 +48,8 @@ var BABYLON;
                 BABYLON.Tools.Error("Wrong sceneFilename parameter");
                 return;
             }
+            var loadingToken = {};
+            scene._addPendingData(loadingToken);
             var manifestChecked = function (success) {
                 scene.database = database;
                 var plugin = SceneLoader._getPluginForFilename(sceneFilename);
@@ -60,6 +62,7 @@ var BABYLON;
                             if (onerror) {
                                 onerror(scene, 'unable to load the scene');
                             }
+                            scene._removePendingData(loadingToken);
                             return;
                         }
                     }
@@ -67,11 +70,13 @@ var BABYLON;
                         if (onerror) {
                             onerror(scene, e);
                         }
+                        scene._removePendingData(loadingToken);
                         return;
                     }
                     if (onsuccess) {
                         scene.importedMeshesFiles.push(rootUrl + sceneFilename);
                         onsuccess(meshes, particleSystems, skeletons);
+                        scene._removePendingData(loadingToken);
                     }
                 };
                 if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
@@ -108,6 +113,8 @@ var BABYLON;
             }
             var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
             var database;
+            var loadingToken = {};
+            scene._addPendingData(loadingToken);
             if (SceneLoader.ShowLoadingScreen) {
                 scene.getEngine().displayLoadingUI();
             }
@@ -117,12 +124,14 @@ var BABYLON;
                     if (onerror) {
                         onerror(scene);
                     }
+                    scene._removePendingData(loadingToken);
                     scene.getEngine().hideLoadingUI();
                     return;
                 }
                 if (onsuccess) {
                     onsuccess(scene);
                 }
+                scene._removePendingData(loadingToken);
                 if (SceneLoader.ShowLoadingScreen) {
                     scene.executeWhenReady(function () {
                         scene.getEngine().hideLoadingUI();

+ 11 - 2
Babylon/Loading/babylon.sceneLoader.ts

@@ -63,6 +63,9 @@
                 return;
             }
 
+            var loadingToken = {};
+            scene._addPendingData(loadingToken);
+
             var manifestChecked = success => {
                 scene.database = database;
 
@@ -78,14 +81,14 @@
                             if (onerror) {
                                 onerror(scene, 'unable to load the scene');
                             }
-
+                            scene._removePendingData(loadingToken);
                             return;
                         }
                     } catch (e) {
                         if (onerror) {
                             onerror(scene, e);
                         }
-
+                        scene._removePendingData(loadingToken);
                         return;
                     }
 
@@ -93,6 +96,7 @@
                     if (onsuccess) {
                         scene.importedMeshesFiles.push(rootUrl + sceneFilename);
                         onsuccess(meshes, particleSystems, skeletons);
+                        scene._removePendingData(loadingToken);
                     }
                 };
 
@@ -137,6 +141,9 @@
             var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
             var database;
 
+            var loadingToken = {};
+            scene._addPendingData(loadingToken);
+
             if (SceneLoader.ShowLoadingScreen) {
                 scene.getEngine().displayLoadingUI();
             }
@@ -149,6 +156,7 @@
                         onerror(scene);
                     }
 
+                    scene._removePendingData(loadingToken);
                     scene.getEngine().hideLoadingUI();
                     return;
                 }
@@ -156,6 +164,7 @@
                 if (onsuccess) {
                     onsuccess(scene);
                 }
+                scene._removePendingData(loadingToken);
 
                 if (SceneLoader.ShowLoadingScreen) {
                     scene.executeWhenReady(() => {

+ 1 - 1
Babylon/Materials/Textures/Procedurals/babylon.customProceduralTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 9 - 1
Babylon/Materials/Textures/Procedurals/babylon.proceduralTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -186,28 +186,36 @@ var BABYLON;
             // Render
             engine.enableEffect(this._effect);
             engine.setState(false);
+            // Texture
             for (var name in this._textures) {
                 this._effect.setTexture(name, this._textures[name]);
             }
+            // Float    
             for (name in this._floats) {
                 this._effect.setFloat(name, this._floats[name]);
             }
+            // Floats   
             for (name in this._floatsArrays) {
                 this._effect.setArray(name, this._floatsArrays[name]);
             }
+            // Color3        
             for (name in this._colors3) {
                 this._effect.setColor3(name, this._colors3[name]);
             }
+            // Color4      
             for (name in this._colors4) {
                 var color = this._colors4[name];
                 this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
             }
+            // Vector2        
             for (name in this._vectors2) {
                 this._effect.setVector2(name, this._vectors2[name]);
             }
+            // Vector3        
             for (name in this._vectors3) {
                 this._effect.setVector3(name, this._vectors3[name]);
             }
+            // Matrix      
             for (name in this._matrices) {
                 this._effect.setMatrix(name, this._matrices[name]);
             }

+ 1 - 14
Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -50,7 +50,6 @@ var BABYLON;
             _super.call(this, name, size, "fire", scene, fallbackTexture, generateMipMaps);
             this._time = 0.0;
             this._speed = new BABYLON.Vector2(0.5, 0.3);
-            this._shift = 1.6;
             this._autoGenerateTime = true;
             this._alphaThreshold = 0.5;
             this._fireColors = FireProceduralTexture.RedFireColors;
@@ -60,7 +59,6 @@ var BABYLON;
         FireProceduralTexture.prototype.updateShaderUniforms = function () {
             this.setFloat("time", this._time);
             this.setVector2("speed", this._speed);
-            this.setFloat("shift", this._shift);
             this.setColor3("c1", this._fireColors[0]);
             this.setColor3("c2", this._fireColors[1]);
             this.setColor3("c3", this._fireColors[2]);
@@ -165,17 +163,6 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        Object.defineProperty(FireProceduralTexture.prototype, "shift", {
-            get: function () {
-                return this._shift;
-            },
-            set: function (value) {
-                this._shift = value;
-                this.updateShaderUniforms();
-            },
-            enumerable: true,
-            configurable: true
-        });
         Object.defineProperty(FireProceduralTexture.prototype, "alphaThreshold", {
             get: function () {
                 return this._alphaThreshold;

+ 0 - 11
Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.ts

@@ -36,7 +36,6 @@
     export class FireProceduralTexture extends ProceduralTexture {
         private _time: number = 0.0;
         private _speed = new Vector2(0.5, 0.3);
-        private _shift: number = 1.6;
         private _autoGenerateTime: boolean = true;
         private _fireColors: Color3[];
         private _alphaThreshold: number = 0.5;
@@ -51,7 +50,6 @@
         public updateShaderUniforms() {
             this.setFloat("time", this._time);
             this.setVector2("speed", this._speed);
-            this.setFloat("shift", this._shift);
             this.setColor3("c1", this._fireColors[0]);
             this.setColor3("c2", this._fireColors[1]);
             this.setColor3("c3", this._fireColors[2]);
@@ -140,15 +138,6 @@
             this.updateShaderUniforms();
         }
 
-        public get shift(): number {
-            return this._shift;
-        }
-
-        public set shift(value: number) {
-            this._shift = value;
-            this.updateShaderUniforms();
-        }
-
         public get alphaThreshold(): number {
             return this._alphaThreshold;
         }

+ 1 - 1
Babylon/Materials/Textures/babylon.cubeTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 1 - 1
Babylon/Materials/Textures/babylon.dynamicTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 2 - 2
Babylon/Materials/Textures/babylon.mirrorTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -30,7 +30,7 @@ var BABYLON;
         }
         MirrorTexture.prototype.clone = function () {
             var textureSize = this.getSize();
-            var newTexture = new BABYLON.MirrorTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
+            var newTexture = new MirrorTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;
             newTexture.level = this.level;

+ 5 - 5
Babylon/Materials/Textures/babylon.mirrorTexture.ts

@@ -1,16 +1,16 @@
 module BABYLON {
     export class MirrorTexture extends RenderTargetTexture {
-        public mirrorPlane = new BABYLON.Plane(0, 1, 0, 1);
+        public mirrorPlane = new Plane(0, 1, 0, 1);
 
-        private _transformMatrix = BABYLON.Matrix.Zero();
-        private _mirrorMatrix = BABYLON.Matrix.Zero();
+        private _transformMatrix = Matrix.Zero();
+        private _mirrorMatrix = Matrix.Zero();
         private _savedViewMatrix: Matrix;
 
         constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean) {
             super(name, size, scene, generateMipMaps, true);
 
             this.onBeforeRender = () => {
-                BABYLON.Matrix.ReflectionToRef(this.mirrorPlane, this._mirrorMatrix);
+                Matrix.ReflectionToRef(this.mirrorPlane, this._mirrorMatrix);
                 this._savedViewMatrix = scene.getViewMatrix();
 
                 this._mirrorMatrix.multiplyToRef(this._savedViewMatrix, this._transformMatrix);
@@ -32,7 +32,7 @@
 
         public clone(): MirrorTexture {
             var textureSize = this.getSize();
-            var newTexture = new BABYLON.MirrorTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
+            var newTexture = new MirrorTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
 
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;

+ 1 - 1
Babylon/Materials/Textures/babylon.rawTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;

+ 2 - 2
Babylon/Materials/Textures/babylon.renderTargetTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -110,7 +110,7 @@ var BABYLON;
                         mesh._activate(scene.getRenderId());
                         for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
                             var subMesh = mesh.subMeshes[subIndex];
-                            scene._activeVertices += subMesh.indexCount;
+                            scene._activeIndices += subMesh.indexCount;
                             this._renderingManager.dispatch(subMesh);
                         }
                     }

+ 1 - 1
Babylon/Materials/Textures/babylon.renderTargetTexture.ts

@@ -131,7 +131,7 @@
 
                         for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
                             var subMesh = mesh.subMeshes[subIndex];
-                            scene._activeVertices += subMesh.indexCount;
+                            scene._activeIndices += subMesh.indexCount;
                             this._renderingManager.dispatch(subMesh);
                         }
                     }

+ 20 - 3
Babylon/Materials/Textures/babylon.texture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -44,6 +44,13 @@ var BABYLON;
                     this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NOTLOADED;
                 }
             }
+            else {
+                BABYLON.Tools.SetImmediate(function () {
+                    if (onLoad) {
+                        onLoad();
+                    }
+                });
+            }
         }
         Texture.prototype.delayLoad = function () {
             if (this.delayLoadState !== BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
@@ -76,7 +83,13 @@ var BABYLON;
             t.z += 0.5;
         };
         Texture.prototype.getTextureMatrix = function () {
-            if (this.uOffset === this._cachedUOffset && this.vOffset === this._cachedVOffset && this.uScale === this._cachedUScale && this.vScale === this._cachedVScale && this.uAng === this._cachedUAng && this.vAng === this._cachedVAng && this.wAng === this._cachedWAng) {
+            if (this.uOffset === this._cachedUOffset &&
+                this.vOffset === this._cachedVOffset &&
+                this.uScale === this._cachedUScale &&
+                this.vScale === this._cachedVScale &&
+                this.uAng === this._cachedUAng &&
+                this.vAng === this._cachedVAng &&
+                this.wAng === this._cachedWAng) {
                 return this._cachedTextureMatrix;
             }
             this._cachedUOffset = this.uOffset;
@@ -112,7 +125,11 @@ var BABYLON;
             return this._cachedTextureMatrix;
         };
         Texture.prototype.getReflectionTextureMatrix = function () {
-            if (this.uOffset === this._cachedUOffset && this.vOffset === this._cachedVOffset && this.uScale === this._cachedUScale && this.vScale === this._cachedVScale && this.coordinatesMode === this._cachedCoordinatesMode) {
+            if (this.uOffset === this._cachedUOffset &&
+                this.vOffset === this._cachedVOffset &&
+                this.uScale === this._cachedUScale &&
+                this.vScale === this._cachedVScale &&
+                this.coordinatesMode === this._cachedCoordinatesMode) {
                 return this._cachedTextureMatrix;
             }
             if (!this._cachedTextureMatrix) {

+ 6 - 0
Babylon/Materials/Textures/babylon.texture.ts

@@ -73,6 +73,12 @@
                 } else {
                     this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
                 }
+            } else {
+                Tools.SetImmediate(() => {
+                    if (onLoad) {
+                        onLoad();
+                    }
+                });
             }
         }
 

+ 15 - 13
Babylon/Materials/Textures/babylon.videoTexture.js

@@ -1,4 +1,4 @@
-var __extends = this.__extends || function (d, b) {
+var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     __.prototype = b.prototype;
@@ -8,27 +8,29 @@ var BABYLON;
 (function (BABYLON) {
     var VideoTexture = (function (_super) {
         __extends(VideoTexture, _super);
-        function VideoTexture(name, urls, size, scene, generateMipMaps, invertY, samplingMode) {
+        function VideoTexture(name, urls, scene, generateMipMaps, invertY, samplingMode) {
             var _this = this;
+            if (generateMipMaps === void 0) { generateMipMaps = false; }
+            if (invertY === void 0) { invertY = false; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
             _super.call(this, null, scene, !generateMipMaps, invertY);
             this._autoLaunch = true;
             this.name = name;
-            this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-            this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
-            var requiredWidth = size.width || size;
-            var requiredHeight = size.height || size;
-            this._texture = scene.getEngine().createDynamicTexture(requiredWidth, requiredHeight, generateMipMaps, samplingMode);
-            var textureSize = this.getSize();
             this.video = document.createElement("video");
-            this.video.width = textureSize.width;
-            this.video.height = textureSize.height;
             this.video.autoplay = false;
             this.video.loop = true;
             this.video.addEventListener("canplaythrough", function () {
-                if (_this._texture) {
-                    _this._texture.isReady = true;
+                if (BABYLON.Tools.IsExponantOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponantOfTwo(_this.video.videoHeight)) {
+                    _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
+                else {
+                    _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    generateMipMaps = false;
+                }
+                _this._texture = scene.getEngine().createDynamicTexture(_this.video.videoWidth, _this.video.videoHeight, generateMipMaps, samplingMode, false);
+                _this._texture.isReady = true;
             });
             urls.forEach(function (url) {
                 //Backwards-compatibility for typescript 1. from 1.3 it should say "SOURCE". see here - https://github.com/Microsoft/TypeScript/issues/1850
@@ -44,7 +46,7 @@ var BABYLON;
                 this.video.play();
             }
             var now = BABYLON.Tools.Now;
-            if (now - this._lastUpdate < 15) {
+            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
                 return false;
             }
             this._lastUpdate = now;

+ 12 - 15
Babylon/Materials/Textures/babylon.videoTexture.ts

@@ -5,30 +5,27 @@
         private _autoLaunch = true;
         private _lastUpdate: number;
 
-        constructor(name: string, urls: string[], size: any, scene: Scene, generateMipMaps: boolean, invertY: boolean, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+        constructor(name: string, urls: string[], scene: Scene, generateMipMaps = false, invertY = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
             super(null, scene, !generateMipMaps, invertY);
 
             this.name = name;
 
-            this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-            this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
-
-            var requiredWidth = size.width || size;
-            var requiredHeight = size.height || size;
-
-            this._texture = scene.getEngine().createDynamicTexture(requiredWidth, requiredHeight, generateMipMaps, samplingMode);
-            var textureSize = this.getSize();
-
             this.video = document.createElement("video");
-            this.video.width = textureSize.width;
-            this.video.height = textureSize.height;
             this.video.autoplay = false;
             this.video.loop = true;
 
             this.video.addEventListener("canplaythrough", () => {
-                if (this._texture) {
-                    this._texture.isReady = true;
+                if (Tools.IsExponantOfTwo(this.video.videoWidth) && Tools.IsExponantOfTwo(this.video.videoHeight)) {
+                    this.wrapU = Texture.WRAP_ADDRESSMODE;
+                    this.wrapV = Texture.WRAP_ADDRESSMODE;
+                } else {
+                    this.wrapU = Texture.CLAMP_ADDRESSMODE;
+                    this.wrapV = Texture.CLAMP_ADDRESSMODE;
+                    generateMipMaps = false;
                 }
+
+                this._texture = scene.getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, generateMipMaps, samplingMode, false);
+                this._texture.isReady = true;
             });
 
             urls.forEach(url => {
@@ -49,7 +46,7 @@
 
             var now = Tools.Now;
 
-            if (now - this._lastUpdate < 15) {
+            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
                 return false;
             }
 

+ 19 - 3
Babylon/Materials/babylon.effect.js

@@ -122,7 +122,7 @@ var BABYLON;
                 return;
             }
             var vertexShaderUrl;
-            if (vertex[0] === ".") {
+            if (vertex[0] === "." || vertex[0] === "/") {
                 vertexShaderUrl = vertex;
             }
             else {
@@ -148,7 +148,7 @@ var BABYLON;
                 return;
             }
             var fragmentShaderUrl;
-            if (fragment[0] === ".") {
+            if (fragment[0] === "." || fragment[0] === "/") {
                 fragmentShaderUrl = fragment;
             }
             else {
@@ -160,6 +160,10 @@ var BABYLON;
         Effect.prototype._prepareEffect = function (vertexSourceCode, fragmentSourceCode, attributesNames, defines, fallbacks) {
             try {
                 var engine = this._engine;
+                if (!engine.getCaps().highPrecisionShaderSupported) {
+                    vertexSourceCode = vertexSourceCode.replace("precision highp float", "precision mediump float");
+                    fragmentSourceCode = fragmentSourceCode.replace("precision highp float", "precision mediump float");
+                }
                 this._program = engine.createShaderProgram(vertexSourceCode, fragmentSourceCode, defines);
                 this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
                 this._attributes = engine.getAttributes(this._program, attributesNames);
@@ -190,7 +194,19 @@ var BABYLON;
                     this._prepareEffect(vertexSourceCode, fragmentSourceCode, attributesNames, defines, fallbacks);
                 }
                 else {
-                    BABYLON.Tools.Error("Unable to compile effect: " + this.name);
+                    BABYLON.Tools.Error("Unable to compile effect: ");
+                    if (this.name.vertexElement) {
+                        BABYLON.Tools.Error("Vertex shader:" + this.name.vertexElement);
+                        BABYLON.Tools.Error("Fragment shader:" + this.name.fragmentElement);
+                    }
+                    else if (this.name.vertex) {
+                        BABYLON.Tools.Error("Vertex shader:" + this.name.vertex);
+                        BABYLON.Tools.Error("Fragment shader:" + this.name.fragment);
+                    }
+                    else {
+                        BABYLON.Tools.Error("Vertex shader:" + this.name);
+                        BABYLON.Tools.Error("Fragment shader:" + this.name);
+                    }
                     BABYLON.Tools.Error("Defines: " + defines);
                     BABYLON.Tools.Error("Error: " + e.message);
                     this._compilationError = e.message;

+ 0 - 0
Babylon/Materials/babylon.effect.ts


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.