소스 검색

Merge pull request #1 from BabylonJS/master

refreshing fork
jahow 10 년 전
부모
커밋
185c5f7345
100개의 변경된 파일2937개의 추가작업 그리고 1412개의 파일을 삭제
  1. 5 0
      Babylon/Animations/babylon.animatable.js
  2. 8 2
      Babylon/Animations/babylon.animatable.ts
  3. 8 2
      Babylon/Animations/babylon.animation.js
  4. 10 2
      Babylon/Animations/babylon.animation.ts
  5. 1 1
      Babylon/Audio/babylon.audioEngine.js
  6. 20 14
      Babylon/Audio/babylon.sound.js
  7. 21 15
      Babylon/Audio/babylon.sound.ts
  8. 59 110
      Babylon/Cameras/babylon.arcRotateCamera.js
  9. 84 152
      Babylon/Cameras/babylon.arcRotateCamera.ts
  10. 12 3
      Babylon/Cameras/babylon.camera.js
  11. 13 3
      Babylon/Cameras/babylon.camera.ts
  12. 3 3
      Babylon/Cameras/babylon.followCamera.ts
  13. 0 141
      Babylon/Cameras/babylon.oculusCamera.js
  14. 1 1
      Babylon/Cameras/babylon.targetCamera.js
  15. 27 27
      Babylon/Cameras/babylon.targetCamera.ts
  16. 0 37
      Babylon/Cameras/babylon.vrDeviceOrientationCamera.js
  17. 7 6
      Babylon/Debug/babylon.debugLayer.js
  18. 1 0
      Babylon/Debug/babylon.debugLayer.js.map
  19. 7 6
      Babylon/Debug/babylon.debugLayer.ts
  20. 37 9
      Babylon/Lights/Shadows/babylon.shadowGenerator.js
  21. 37 15
      Babylon/Lights/Shadows/babylon.shadowGenerator.ts
  22. 1 1
      Babylon/Lights/babylon.directionalLight.js
  23. 1 1
      Babylon/Lights/babylon.directionalLight.ts
  24. 6 3
      Babylon/Lights/babylon.light.js
  25. 8 4
      Babylon/Lights/babylon.light.ts
  26. 22 7
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  27. 23 7
      Babylon/Loading/Plugins/babylon.babylonFileLoader.ts
  28. 3 0
      Babylon/Loading/babylon.sceneLoader.js
  29. 5 0
      Babylon/Loading/babylon.sceneLoader.ts
  30. 0 4
      Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.js
  31. 1 1
      Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.ts
  32. 11 5
      Babylon/Materials/Textures/babylon.texture.js
  33. 28 20
      Babylon/Materials/Textures/babylon.texture.ts
  34. 1 3
      Babylon/Materials/babylon.standardMaterial.js
  35. 3 3
      Babylon/Materials/babylon.standardMaterial.ts
  36. 294 6
      Babylon/Math/babylon.math.js
  37. 378 29
      Babylon/Math/babylon.math.ts
  38. 15 18
      Babylon/Mesh/babylon.abstractMesh.js
  39. 77 79
      Babylon/Mesh/babylon.abstractMesh.ts
  40. 11 1
      Babylon/Mesh/babylon.geometry.js
  41. 16 3
      Babylon/Mesh/babylon.geometry.ts
  42. 2 2
      Babylon/Mesh/babylon.groundMesh.ts
  43. 1 1
      Babylon/Mesh/babylon.instancedMesh.js
  44. 44 8
      Babylon/Mesh/babylon.mesh.js
  45. 64 26
      Babylon/Mesh/babylon.mesh.ts
  46. 121 139
      Babylon/Mesh/babylon.meshSimplification.js
  47. 132 143
      Babylon/Mesh/babylon.meshSimplification.ts
  48. 1 0
      Babylon/Mesh/babylon.subMesh.js
  49. 3 2
      Babylon/Mesh/babylon.subMesh.ts
  50. 0 1
      Babylon/Physics/Plugins/babylon.cannonJSPlugin.ts
  51. 0 2
      Babylon/Physics/babylon.physicsEngine.ts
  52. 39 0
      Babylon/PostProcess/babylon.colorCorrectionPostProcess.js
  53. 33 0
      Babylon/PostProcess/babylon.colorCorrectionPostProcess.ts
  54. 1 2
      Babylon/PostProcess/babylon.oculusDistortionCorrectionPostProcess.ts
  55. 6 1
      Babylon/PostProcess/babylon.postProcess.js
  56. 6 2
      Babylon/PostProcess/babylon.postProcess.ts
  57. 0 1
      Babylon/PostProcess/babylon.postProcessManager.ts
  58. 32 4
      Babylon/PostProcess/babylon.ssaoRenderingPipeline.js
  59. 37 4
      Babylon/PostProcess/babylon.ssaoRenderingPipeline.ts
  60. 49 7
      Babylon/PostProcess/babylon.volumetricLightScatteringPostProcess.js
  61. 57 9
      Babylon/PostProcess/babylon.volumetricLightScatteringPostProcess.ts
  62. 37 0
      Babylon/Shaders/colorCorrection.fragment.fx
  63. 23 19
      Babylon/Shaders/default.fragment.fx
  64. 2 2
      Babylon/Shaders/depth.vertex.fx
  65. 3 3
      Babylon/Shaders/shadowMap.fragment.fx
  66. 6 6
      Babylon/Shaders/sprites.vertex.fx
  67. 8 7
      Babylon/Shaders/ssao.fragment.fx
  68. 23 6
      Babylon/Shaders/volumetricLightScatteringPass.fragment.fx
  69. 13 1
      Babylon/Sprites/babylon.sprite.js
  70. 11 1
      Babylon/Sprites/babylon.sprite.ts
  71. 22 22
      Babylon/Sprites/babylon.spriteManager.js
  72. 27 27
      Babylon/Sprites/babylon.spriteManager.ts
  73. 18 16
      Babylon/Tools/babylon.sceneSerializer.js
  74. 54 51
      Babylon/Tools/babylon.sceneSerializer.ts
  75. 92 0
      Babylon/Tools/babylon.smartCollection.js
  76. 106 0
      Babylon/Tools/babylon.smartCollection.ts
  77. 16 9
      Babylon/babylon.engine.js
  78. 21 12
      Babylon/babylon.engine.ts
  79. 2 0
      Babylon/babylon.mixins.ts
  80. 9 1
      Babylon/babylon.node.js
  81. 12 1
      Babylon/babylon.node.ts
  82. 85 19
      Babylon/babylon.scene.js
  83. 99 23
      Babylon/babylon.scene.ts
  84. 16 1
      Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs
  85. 39 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonActions.cs
  86. 2 2
      Exporters/3ds Max/BabylonExport.Entities/BabylonAnimation.cs
  87. 1 2
      Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs
  88. 6 19
      Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj
  89. 19 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonIAnimatable.cs
  90. 1 1
      Exporters/3ds Max/BabylonExport.Entities/BabylonLight.cs
  91. 3 16
      Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs
  92. 44 22
      Exporters/3ds Max/BabylonExport.Entities/BabylonScene.cs
  93. 12 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs
  94. 86 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonSound.cs
  95. 36 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonVector3.cs
  96. 66 17
      Exporters/3ds Max/Max2Babylon/2015/Max2Babylon2015.csproj
  97. 0 5
      Exporters/3ds Max/Max2Babylon/2015/packages.config
  98. 0 1
      Exporters/3ds Max/Max2Babylon/BabylonExportActionItem.cs
  99. 24 2
      Exporters/3ds Max/Max2Babylon/Exporter/ActionBuilder/ActionsBuilder/action.js
  100. 0 0
      Exporters/3ds Max/Max2Babylon/Exporter/ActionBuilder/ActionsBuilder/actionkinds.js

+ 5 - 0
Babylon/Animations/babylon.animatable.js

@@ -78,6 +78,11 @@ var BABYLON;
                 var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this.speedRatio);
                 running = running || isRunning;
             }
+            if (!running) {
+                // Remove from active animatables
+                index = this._scene._activeAnimatables.indexOf(this);
+                this._scene._activeAnimatables.splice(index, 1);
+            }
             if (!running && this.onAnimationEnd) {
                 this.onAnimationEnd();
             }

+ 8 - 2
Babylon/Animations/babylon.animatable.ts

@@ -23,8 +23,8 @@
                 var animation = animations[index];
 
                 animation._target = target;
-                this._animations.push(animation);    
-            }            
+                this._animations.push(animation);
+            }
         }
 
         public getAnimationByTargetProperty(property: string) {
@@ -87,6 +87,12 @@
                 running = running || isRunning;
             }
 
+            if (!running) {
+                // Remove from active animatables
+                index = this._scene._activeAnimatables.indexOf(this);
+                this._scene._activeAnimatables.splice(index, 1);
+            }
+
             if (!running && this.onAnimationEnd) {
                 this.onAnimationEnd();
             }

+ 8 - 2
Babylon/Animations/babylon.animation.js

@@ -106,8 +106,14 @@ var BABYLON;
                 return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
             }
             this.currentFrame = currentFrame;
-            for (var key = 0; key < this._keys.length; key++) {
-                // for each frame, we need the key just before the frame superior
+            // Try to get a hash to find the right key
+            var startKey = Math.max(0, Math.min(this._keys.length - 1, Math.floor(this._keys.length * (currentFrame - this._keys[0].frame) / (this._keys[this._keys.length - 1].frame - this._keys[0].frame)) - 1));
+            if (this._keys[startKey].frame >= currentFrame) {
+                while (startKey - 1 >= 0 && this._keys[startKey].frame >= currentFrame) {
+                    startKey--;
+                }
+            }
+            for (var key = startKey; key < this._keys.length; key++) {
                 if (this._keys[key + 1].frame >= currentFrame) {
                     var startValue = this._getKeyValue(this._keys[key].value);
                     var endValue = this._getKeyValue(this._keys[key + 1].value);

+ 10 - 2
Babylon/Animations/babylon.animation.ts

@@ -137,8 +137,16 @@
 
             this.currentFrame = currentFrame;
 
-            for (var key = 0; key < this._keys.length; key++) {
-                // for each frame, we need the key just before the frame superior
+            // Try to get a hash to find the right key
+            var startKey = Math.max(0, Math.min(this._keys.length - 1, Math.floor(this._keys.length * (currentFrame - this._keys[0].frame) / (this._keys[this._keys.length - 1].frame - this._keys[0].frame)) - 1));
+
+            if (this._keys[startKey].frame >= currentFrame) {
+                while (startKey - 1 >= 0 && this._keys[startKey].frame >= currentFrame) {
+                    startKey--;
+                }
+            }
+
+            for (var key = startKey; key < this._keys.length ; key++) {
                 if (this._keys[key + 1].frame >= currentFrame) {
 
                     var startValue = this._getKeyValue(this._keys[key].value);

+ 1 - 1
Babylon/Audio/babylon.audioEngine.js

@@ -66,4 +66,4 @@ var BABYLON;
     })();
     BABYLON.AudioEngine = AudioEngine;
 })(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.audioengine.js.map
+//# sourceMappingURL=babylon.audioEngine.js.map

+ 20 - 14
Babylon/Audio/babylon.sound.js

@@ -18,7 +18,7 @@ var BABYLON;
             this.rolloffFactor = 1;
             this.maxDistance = 100;
             this.distanceModel = "linear";
-            this.panningModel = "HRTF";
+            this._panningModel = "equalpower";
             this._playbackRate = 1;
             this._startTime = 0;
             this._startOffset = 0;
@@ -60,7 +60,6 @@ var BABYLON;
                 this.rolloffFactor = options.rolloffFactor || 1;
                 this.refDistance = options.refDistance || 1;
                 this.distanceModel = options.distanceModel || "linear";
-                this.panningModel = options.panningModel || "HRTF";
                 this._playbackRate = options.playbackRate || 1;
             }
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
@@ -97,6 +96,9 @@ var BABYLON;
                     BABYLON.Tools.Error("Web Audio is not supported by your browser.");
                     BABYLON.Engine.audioEngine.WarnedWebAudioUnsupported = true;
                 }
+                if (this._readyToPlayCallback) {
+                    this._readyToPlayCallback();
+                }
             }
         }
         Sound.prototype.dispose = function () {
@@ -160,12 +162,14 @@ var BABYLON;
                 this.rolloffFactor = options.rolloffFactor || this.rolloffFactor;
                 this.refDistance = options.refDistance || this.refDistance;
                 this.distanceModel = options.distanceModel || this.distanceModel;
-                this.panningModel = options.panningModel || this.panningModel;
                 this._playbackRate = options.playbackRate || this._playbackRate;
             }
         };
         Sound.prototype._createSpatialParameters = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
+                if (this._scene.headphone) {
+                    this._panningModel = "HRTF";
+                }
                 this._soundPanner = BABYLON.Engine.audioEngine.audioContext.createPanner();
                 if (this.useCustomAttenuation) {
                     // Tricks to disable in a way embedded Web Audio attenuation 
@@ -173,28 +177,30 @@ var BABYLON;
                     this._soundPanner.maxDistance = Number.MAX_VALUE;
                     this._soundPanner.refDistance = 1;
                     this._soundPanner.rolloffFactor = 1;
-                    this._soundPanner.panningModel = "HRTF";
+                    this._soundPanner.panningModel = this._panningModel;
                 }
                 else {
                     this._soundPanner.distanceModel = this.distanceModel;
                     this._soundPanner.maxDistance = this.maxDistance;
                     this._soundPanner.refDistance = this.refDistance;
                     this._soundPanner.rolloffFactor = this.rolloffFactor;
-                    this._soundPanner.panningModel = this.panningModel;
+                    this._soundPanner.panningModel = this._panningModel;
                 }
                 this._soundPanner.connect(this._ouputAudioNode);
                 this._inputAudioNode = this._soundPanner;
             }
         };
         Sound.prototype.switchPanningModelToHRTF = function () {
-            this._switchPanningModel("HRTF");
+            this._panningModel = "HRTF";
+            this._switchPanningModel();
         };
         Sound.prototype.switchPanningModelToEqualPower = function () {
-            this._switchPanningModel("equalpower");
+            this._panningModel = "equalpower";
+            this._switchPanningModel();
         };
-        Sound.prototype._switchPanningModel = function (newModel) {
+        Sound.prototype._switchPanningModel = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this.spatialSound) {
-                this._soundPanner.panningModel = newModel;
+                this._soundPanner.panningModel = this._panningModel;
             }
         };
         Sound.prototype.connectToSoundTrackAudioNode = function (soundTrackAudioNode) {
@@ -225,13 +231,13 @@ var BABYLON;
         };
         Sound.prototype.setPosition = function (newPosition) {
             this._position = newPosition;
-            if (this.isPlaying && this.spatialSound) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this.spatialSound) {
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         };
         Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
             this._localDirection = newLocalDirection;
-            if (this._connectedMesh && this.isPlaying) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
                 this._updateDirection();
             }
         };
@@ -242,7 +248,7 @@ var BABYLON;
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         };
         Sound.prototype.updateDistanceFromListener = function () {
-            if (this._connectedMesh && this.useCustomAttenuation) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation) {
                 var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
@@ -318,7 +324,7 @@ var BABYLON;
             }
         };
         Sound.prototype.setVolume = function (newVolume, time) {
-            if (BABYLON.Engine.audioEngine.canUseWebAudio) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && !this.spatialSound) {
                 if (time) {
                     this._soundGain.gain.linearRampToValueAtTime(this._volume, BABYLON.Engine.audioEngine.audioContext.currentTime);
                     this._soundGain.gain.linearRampToValueAtTime(newVolume, time);
@@ -355,7 +361,7 @@ var BABYLON;
         };
         Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (connectedMesh) {
             this.setPosition(connectedMesh.getBoundingInfo().boundingSphere.centerWorld);
-            if (this._isDirectional && this.isPlaying) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._isDirectional && this.isPlaying) {
                 this._updateDirection();
             }
         };

+ 21 - 15
Babylon/Audio/babylon.sound.ts

@@ -10,7 +10,7 @@
         public rolloffFactor: number = 1;
         public maxDistance: number = 100;
         public distanceModel: string = "linear";
-        public panningModel: string = "HRTF";
+        private _panningModel: string = "equalpower";
         public onended: () => any;
         private _playbackRate: number = 1;
         private _startTime: number = 0;
@@ -73,7 +73,6 @@
                 this.rolloffFactor = options.rolloffFactor || 1;
                 this.refDistance = options.refDistance || 1;
                 this.distanceModel = options.distanceModel || "linear";
-                this.panningModel = options.panningModel || "HRTF";
                 this._playbackRate = options.playbackRate || 1;
             }
 
@@ -90,7 +89,7 @@
                 if (urlOrArrayBuffer) {
                     // If it's an URL
                     if (typeof (urlOrArrayBuffer) === "string") {
-                        Tools.LoadFile(urlOrArrayBuffer,(data) => { this._soundLoaded(data); }, null, null, true);
+                        Tools.LoadFile(urlOrArrayBuffer, (data) => { this._soundLoaded(data); }, null, null, true);
                     }
                     else {
                         if (urlOrArrayBuffer instanceof ArrayBuffer) {
@@ -109,6 +108,9 @@
                     BABYLON.Tools.Error("Web Audio is not supported by your browser.");
                     Engine.audioEngine.WarnedWebAudioUnsupported = true;
                 }
+                if (this._readyToPlayCallback) {
+                    this._readyToPlayCallback();
+                }
             }
         }
 
@@ -170,13 +172,15 @@
                 this.rolloffFactor = options.rolloffFactor || this.rolloffFactor;
                 this.refDistance = options.refDistance || this.refDistance;
                 this.distanceModel = options.distanceModel || this.distanceModel;
-                this.panningModel = options.panningModel || this.panningModel;
                 this._playbackRate = options.playbackRate || this._playbackRate;
             }
         }
 
         private _createSpatialParameters() {
             if (Engine.audioEngine.canUseWebAudio) {
+                if (this._scene.headphone) {
+                    this._panningModel = "HRTF";
+                }
                 this._soundPanner = Engine.audioEngine.audioContext.createPanner();
 
                 if (this.useCustomAttenuation) {
@@ -185,14 +189,14 @@
                     this._soundPanner.maxDistance = Number.MAX_VALUE;
                     this._soundPanner.refDistance = 1;
                     this._soundPanner.rolloffFactor = 1;
-                    this._soundPanner.panningModel = "HRTF";
+                    this._soundPanner.panningModel = this._panningModel;
                 }
                 else {
                     this._soundPanner.distanceModel = this.distanceModel;
                     this._soundPanner.maxDistance = this.maxDistance;
                     this._soundPanner.refDistance = this.refDistance;
                     this._soundPanner.rolloffFactor = this.rolloffFactor;
-                    this._soundPanner.panningModel = this.panningModel;
+                    this._soundPanner.panningModel = this._panningModel;
                 }
                 this._soundPanner.connect(this._ouputAudioNode);
                 this._inputAudioNode = this._soundPanner;
@@ -200,16 +204,18 @@
         }
 
         public switchPanningModelToHRTF() {
-            this._switchPanningModel("HRTF");    
+            this._panningModel = "HRTF";
+            this._switchPanningModel();    
         }
 
         public switchPanningModelToEqualPower() {
-            this._switchPanningModel("equalpower");
+            this._panningModel = "equalpower";
+            this._switchPanningModel();
         }
 
-        private _switchPanningModel(newModel: string) {
+        private _switchPanningModel() {
             if (Engine.audioEngine.canUseWebAudio && this.spatialSound) {
-                this._soundPanner.panningModel = newModel;
+                this._soundPanner.panningModel = this._panningModel;
             }
         }
 
@@ -245,7 +251,7 @@
         public setPosition(newPosition: Vector3) {
             this._position = newPosition;
 
-            if (this.isPlaying && this.spatialSound) {
+            if (Engine.audioEngine.canUseWebAudio && this.spatialSound) {
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         }
@@ -253,7 +259,7 @@
         public setLocalDirectionToMesh(newLocalDirection: Vector3) {
             this._localDirection = newLocalDirection;
 
-            if (this._connectedMesh && this.isPlaying) {
+            if (Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
                 this._updateDirection();
             }
         }
@@ -266,7 +272,7 @@
         }
 
         public updateDistanceFromListener() {
-            if (this._connectedMesh && this.useCustomAttenuation) {
+            if (Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation) {
                 var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
@@ -345,7 +351,7 @@
         }
 
         public setVolume(newVolume: number, time?: number) {
-            if (Engine.audioEngine.canUseWebAudio) {
+            if (Engine.audioEngine.canUseWebAudio && !this.spatialSound) {
                 if (time) {
                     this._soundGain.gain.linearRampToValueAtTime(this._volume, Engine.audioEngine.audioContext.currentTime);
                     this._soundGain.gain.linearRampToValueAtTime(newVolume, time);
@@ -385,7 +391,7 @@
 
         private _onRegisterAfterWorldMatrixUpdate(connectedMesh: AbstractMesh) {
             this.setPosition(connectedMesh.getBoundingInfo().boundingSphere.centerWorld);
-            if (this._isDirectional && this.isPlaying) {
+            if (Engine.audioEngine.canUseWebAudio && this._isDirectional && this.isPlaying) {
                 this._updateDirection();
             }
         }

+ 59 - 110
Babylon/Cameras/babylon.arcRotateCamera.js

@@ -26,6 +26,7 @@ var BABYLON;
             this.upperRadiusLimit = null;
             this.angularSensibility = 1000.0;
             this.wheelPrecision = 3.0;
+            this.pinchPrecision = 2.0;
             this.keysUp = [38];
             this.keysDown = [40];
             this.keysLeft = [37];
@@ -40,10 +41,9 @@ var BABYLON;
             this._previousPosition = BABYLON.Vector3.Zero();
             this._collisionVelocity = BABYLON.Vector3.Zero();
             this._newPosition = BABYLON.Vector3.Zero();
-            // Pinch
-            // value for pinch step scaling
-            // set to 20 by default
-            this.pinchPrecision = 20;
+            if (!this.target) {
+                this.target = BABYLON.Vector3.Zero();
+            }
             this.getViewMatrix();
         }
         ArcRotateCamera.prototype._getTargetPosition = function () {
@@ -77,13 +77,9 @@ var BABYLON;
         // Methods
         ArcRotateCamera.prototype.attachControl = function (element, noPreventDefault) {
             var _this = this;
-            var previousPosition;
-            var pointerId;
-            // to know if pinch started
-            var pinchStarted = false;
-            // two pinch point on X
-            // that will use for find if user action is pinch open or pinch close
-            var pinchPointX1, pinchPointX2;
+            var cacheSoloPointer; // cache pointer object for better perf on camera rotation
+            var previousPinchDistance = 0;
+            var pointers = new BABYLON.SmartCollection();
             if (this._attachedElement) {
                 return;
             }
@@ -91,56 +87,68 @@ var BABYLON;
             var engine = this.getEngine();
             if (this._onPointerDown === undefined) {
                 this._onPointerDown = function (evt) {
-                    if (pointerId) {
-                        return;
-                    }
-                    pointerId = evt.pointerId;
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
+                    pointers.add(evt.pointerId, { x: evt.clientX, y: evt.clientY, type: evt.pointerType });
+                    cacheSoloPointer = pointers.item(evt.pointerId);
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
                 };
                 this._onPointerUp = function (evt) {
-                    previousPosition = null;
-                    pointerId = null;
+                    cacheSoloPointer = null;
+                    previousPinchDistance = 0;
+                    pointers.remove(evt.pointerId);
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
                 };
                 this._onPointerMove = function (evt) {
-                    if (!previousPosition) {
-                        return;
-                    }
-                    if (pointerId !== evt.pointerId) {
-                        return;
-                    }
-                    // return pinch is started
-                    if (pinchStarted) {
-                        return;
-                    }
-                    var offsetX = evt.clientX - previousPosition.x;
-                    var offsetY = evt.clientY - previousPosition.y;
-                    _this.inertialAlphaOffset -= offsetX / _this.angularSensibility;
-                    _this.inertialBetaOffset -= offsetY / _this.angularSensibility;
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
+                    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;
+                        case 2:
+                            //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 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);
+                            if (previousPinchDistance === 0) {
+                                previousPinchDistance = pinchSquaredDistance;
+                                return;
+                            }
+                            if (pinchSquaredDistance !== previousPinchDistance) {
+                                if (pinchSquaredDistance > previousPinchDistance) {
+                                    direction = -1;
+                                }
+                                _this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (_this.pinchPrecision * _this.wheelPrecision * _this.angularSensibility);
+                                previousPinchDistance = pinchSquaredDistance;
+                            }
+                            break;
+                        default:
+                            if (pointers.item(evt.pointerId)) {
+                                pointers.item(evt.pointerId).x = evt.clientX;
+                                pointers.item(evt.pointerId).y = evt.clientY;
+                            }
+                    }
                 };
                 this._onMouseMove = function (evt) {
                     if (!engine.isPointerLock) {
                         return;
                     }
-                    // return pinch is started
-                    if (pinchStarted) {
-                        return;
-                    }
                     var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
                     var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
                     _this.inertialAlphaOffset -= offsetX / _this.angularSensibility;
@@ -193,7 +201,9 @@ var BABYLON;
                 };
                 this._onLostFocus = function () {
                     _this._keys = [];
-                    pointerId = null;
+                    pointers.empty();
+                    previousPinchDistance = 0;
+                    cacheSoloPointer = null;
                 };
                 this._onGestureStart = function (e) {
                     if (window.MSGesture === undefined) {
@@ -219,62 +229,9 @@ var BABYLON;
                     _this.inertialAlphaOffset = 0;
                     _this.inertialBetaOffset = 0;
                     _this.inertialRadiusOffset = 0;
-                    previousPosition = null;
-                    pointerId = null;
-                };
-                this._touchStart = function (event) {
-                    if (event.touches.length === 2) {
-                        //-- start pinch if two fingers on the screen
-                        pinchStarted = true;
-                        _this._pinchStart(event);
-                    }
-                };
-                this._touchMove = function (event) {
-                    if (pinchStarted) {
-                        //-- make scaling
-                        _this._pinchMove(event);
-                    }
-                };
-                this._touchEnd = function (event) {
-                    if (pinchStarted) {
-                        //-- end of pinch
-                        _this._pinchEnd(event);
-                    }
-                };
-                this._pinchStart = function (event) {
-                    // save origin touch point
-                    pinchPointX1 = event.touches[0].clientX;
-                    pinchPointX2 = event.touches[1].clientX;
-                    // block the camera 
-                    // if not it rotate around target during pinch
-                    pinchStarted = true;
-                };
-                this._pinchMove = function (event) {
-                    // variable for new camera's radius
-                    var delta = 0;
-                    // variables to know if pinch open or pinch close
-                    var direction = 1;
-                    var distanceXOrigine, distanceXNow;
-                    if (event.touches.length !== 2)
-                        return;
-                    // calculate absolute distances of the two fingers
-                    distanceXOrigine = Math.abs(pinchPointX1 - pinchPointX2);
-                    distanceXNow = Math.abs(event.touches[0].clientX - event.touches[1].clientX);
-                    // if distanceXNow < distanceXOrigine -> pinch close so direction = -1
-                    if (distanceXNow < distanceXOrigine) {
-                        direction = -1;
-                    }
-                    // calculate new radius
-                    delta = (_this.pinchPrecision / (_this.wheelPrecision * 40)) * direction;
-                    // set new radius
-                    _this.inertialRadiusOffset -= delta;
-                    // save origin touch point
-                    pinchPointX1 = event.touches[0].clientX;
-                    pinchPointX2 = event.touches[1].clientX;
-                };
-                this._pinchEnd = function (event) {
-                    // cancel pinch and deblock camera rotation
-                    pinchStarted = false;
+                    pointers.empty();
+                    previousPinchDistance = 0;
+                    cacheSoloPointer = null;
                 };
             }
             element.addEventListener(eventPrefix + "down", this._onPointerDown, false);
@@ -286,10 +243,6 @@ var BABYLON;
             element.addEventListener("MSGestureChange", this._onGesture, false);
             element.addEventListener('mousewheel', this._wheel, false);
             element.addEventListener('DOMMouseScroll', this._wheel, false);
-            // pinch
-            element.addEventListener('touchstart', this._touchStart, false);
-            element.addEventListener('touchmove', this._touchMove, false);
-            element.addEventListener('touchend', this._touchEnd, false);
             BABYLON.Tools.RegisterTopRootEvents([
                 { name: "keydown", handler: this._onKeyDown },
                 { name: "keyup", handler: this._onKeyUp },
@@ -297,7 +250,7 @@ var BABYLON;
             ]);
         };
         ArcRotateCamera.prototype.detachControl = function (element) {
-            if (this._attachedElement != element) {
+            if (this._attachedElement !== element) {
                 return;
             }
             element.removeEventListener(eventPrefix + "down", this._onPointerDown);
@@ -309,10 +262,6 @@ var BABYLON;
             element.removeEventListener("MSGestureChange", this._onGesture);
             element.removeEventListener('mousewheel', this._wheel);
             element.removeEventListener('DOMMouseScroll', this._wheel);
-            // pinch
-            element.removeEventListener('touchstart', this._touchStart);
-            element.removeEventListener('touchmove', this._touchMove);
-            element.removeEventListener('touchend', this._touchEnd);
             BABYLON.Tools.UnregisterTopRootEvents([
                 { name: "keydown", handler: this._onKeyDown },
                 { name: "keyup", handler: this._onKeyUp },
@@ -341,7 +290,7 @@ var BABYLON;
                 }
             }
             // Inertia
-            if (this.inertialAlphaOffset != 0 || this.inertialBetaOffset != 0 || this.inertialRadiusOffset != 0) {
+            if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset != 0) {
                 this.alpha += this.inertialAlphaOffset;
                 this.beta += this.inertialBetaOffset;
                 this.radius -= this.inertialRadiusOffset;

+ 84 - 152
Babylon/Cameras/babylon.arcRotateCamera.ts

@@ -13,16 +13,17 @@
         public upperRadiusLimit = null;
         public angularSensibility = 1000.0;
         public wheelPrecision = 3.0;
+        public pinchPrecision = 2.0;
         public keysUp = [38];
         public keysDown = [40];
         public keysLeft = [37];
         public keysRight = [39];
         public zoomOnFactor = 1;
-		public targetScreenOffset = Vector2.Zero();
-		
-		
+        public targetScreenOffset = Vector2.Zero();
+
+
         private _keys = [];
-        private _viewMatrix = new BABYLON.Matrix();
+        private _viewMatrix = new Matrix();
         private _attachedElement: HTMLElement;
 
         private _onPointerDown: (e: PointerEvent) => void;
@@ -50,21 +51,12 @@
         private _previousBeta: number;
         private _previousRadius: number;
 
-        // Pinch
-        // value for pinch step scaling
-        // set to 20 by default
-        public pinchPrecision = 20;
-        // Event for pinch
-        private _touchStart: (e: any) => void;
-        private _touchMove: (e: any) => void;
-        private _touchEnd: (e: any) => void;
-        // Method for pinch
-        private _pinchStart: (e: any) => void;
-        private _pinchMove: (e: any) => void;
-        private _pinchEnd: (e: any) => void;
-
         constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: any, scene: Scene) {
-            super(name, BABYLON.Vector3.Zero(), scene);
+            super(name, Vector3.Zero(), scene);
+
+            if (!this.target) {
+                this.target = Vector3.Zero();
+            }
 
             this.getViewMatrix();
         }
@@ -76,11 +68,11 @@
         // Cache
         public _initCache(): void {
             super._initCache();
-            this._cache.target = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.target = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             this._cache.alpha = undefined;
             this._cache.beta = undefined;
             this._cache.radius = undefined;
-			this._cache.targetScreenOffset = undefined;
+            this._cache.targetScreenOffset = undefined;
         }
 
         public _updateCache(ignoreParentClass?: boolean): void {
@@ -92,7 +84,7 @@
             this._cache.alpha = this.alpha;
             this._cache.beta = this.beta;
             this._cache.radius = this.radius;
-			this._cache.targetScreenOffset = this.targetScreenOffset.clone();
+            this._cache.targetScreenOffset = this.targetScreenOffset.clone();
         }
 
         // Synchronized
@@ -104,18 +96,14 @@
                 && this._cache.alpha === this.alpha
                 && this._cache.beta === this.beta
                 && this._cache.radius === this.radius
-				&& this._cache.targetScreenOffset.equals(this.targetScreenOffset);
+                && this._cache.targetScreenOffset.equals(this.targetScreenOffset);
         }
 
         // Methods
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            var previousPosition;
-            var pointerId;
-            // to know if pinch started
-            var pinchStarted = false;
-            // two pinch point on X
-            // that will use for find if user action is pinch open or pinch close
-            var pinchPointX1, pinchPointX2;
+            var cacheSoloPointer; // cache pointer object for better perf on camera rotation
+            var previousPinchDistance = 0;
+            var pointers = new SmartCollection();
 
             if (this._attachedElement) {
                 return;
@@ -126,59 +114,69 @@
 
             if (this._onPointerDown === undefined) {
                 this._onPointerDown = evt => {
-
-                    if (pointerId) {
-                        return;
-                    }
-
-                    pointerId = evt.pointerId;
-
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
-
+                    pointers.add(evt.pointerId, { x: evt.clientX, y: evt.clientY, type: evt.pointerType });
+                    cacheSoloPointer = pointers.item(evt.pointerId);
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
                 };
 
                 this._onPointerUp = evt => {
-                    previousPosition = null;
-                    pointerId = null;
+                    cacheSoloPointer = null;
+                    previousPinchDistance = 0;
+                    pointers.remove(evt.pointerId);
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
                 };
 
-
                 this._onPointerMove = evt => {
-                    if (!previousPosition) {
-                        return;
-                    }
-
-                    if (pointerId !== evt.pointerId) {
-                        return;
-                    }
-
-                    // return pinch is started
-                    if (pinchStarted) {
-                        return;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
                     }
 
-                    var offsetX = evt.clientX - previousPosition.x;
-                    var offsetY = evt.clientY - previousPosition.y;
-
-                    this.inertialAlphaOffset -= offsetX / this.angularSensibility;
-                    this.inertialBetaOffset -= offsetY / this.angularSensibility;
+                    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;
+
+                        case 2: //pinch
+                            //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 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);
+                            if (previousPinchDistance === 0) {
+                                previousPinchDistance = pinchSquaredDistance;
+                                return;
+                            }
 
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
+                            if (pinchSquaredDistance !== previousPinchDistance) {
+                                if (pinchSquaredDistance > previousPinchDistance) {
+                                    direction = -1;
+                                }
+                                this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (this.pinchPrecision * this.wheelPrecision * this.angularSensibility);
+                                previousPinchDistance = pinchSquaredDistance;
+                            }
+                            break;
 
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
+                        default:
+                            if (pointers.item(evt.pointerId)) {
+                                pointers.item(evt.pointerId).x = evt.clientX;
+                                pointers.item(evt.pointerId).y = evt.clientY;
+                            }
                     }
                 };
 
@@ -187,11 +185,6 @@
                         return;
                     }
 
-                    // return pinch is started
-                    if (pinchStarted) {
-                        return;
-                    }
-
                     var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
                     var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
 
@@ -261,7 +254,9 @@
 
                 this._onLostFocus = () => {
                     this._keys = [];
-                    pointerId = null;
+                    pointers.empty();
+                    previousPinchDistance = 0;
+                    cacheSoloPointer = null;
                 };
 
                 this._onGestureStart = e => {
@@ -294,67 +289,12 @@
                     this.inertialAlphaOffset = 0;
                     this.inertialBetaOffset = 0;
                     this.inertialRadiusOffset = 0;
-                    previousPosition = null;
-                    pointerId = null;
+                    pointers.empty();
+                    previousPinchDistance = 0;
+                    cacheSoloPointer = null;
                 };
 
-                this._touchStart = event => {
-                    if (event.touches.length === 2) {
-                        //-- start pinch if two fingers on the screen
-                        pinchStarted = true;
-                        this._pinchStart(event);
-                    }
-                };
-                this._touchMove = event => {
-                    if (pinchStarted) {
-                        //-- make scaling
-                        this._pinchMove(event);
-                    }
-                };
-                this._touchEnd = event => {
-                    if (pinchStarted) {
-                        //-- end of pinch
-                        this._pinchEnd(event);
-                    }
-                };
-
-                this._pinchStart = event => {
-                    // save origin touch point
-                    pinchPointX1 = event.touches[0].clientX;
-                    pinchPointX2 = event.touches[1].clientX;
-                    // block the camera 
-                    // if not it rotate around target during pinch
-                    pinchStarted = true;
-                };
-                this._pinchMove = event => {
-                    // variable for new camera's radius
-                    var delta = 0;
-                    // variables to know if pinch open or pinch close
-                    var direction = 1;
-                    var distanceXOrigine, distanceXNow;
 
-                    if (event.touches.length !== 2)
-                        return;
-                    // calculate absolute distances of the two fingers
-                    distanceXOrigine = Math.abs(pinchPointX1 - pinchPointX2);
-                    distanceXNow = Math.abs(event.touches[0].clientX - event.touches[1].clientX);
-
-                    // if distanceXNow < distanceXOrigine -> pinch close so direction = -1
-                    if (distanceXNow < distanceXOrigine) {
-                        direction = -1;
-                    }
-                    // calculate new radius
-                    delta = (this.pinchPrecision / (this.wheelPrecision * 40)) * direction;
-                    // set new radius
-                    this.inertialRadiusOffset -= delta;
-                    // save origin touch point
-                    pinchPointX1 = event.touches[0].clientX;
-                    pinchPointX2 = event.touches[1].clientX;
-                };
-                this._pinchEnd = event => {
-                    // cancel pinch and deblock camera rotation
-                    pinchStarted = false;
-                };
             }
 
             element.addEventListener(eventPrefix + "down", this._onPointerDown, false);
@@ -366,10 +306,6 @@
             element.addEventListener("MSGestureChange", this._onGesture, false);
             element.addEventListener('mousewheel', this._wheel, false);
             element.addEventListener('DOMMouseScroll', this._wheel, false);
-            // pinch
-            element.addEventListener('touchstart', this._touchStart, false);
-            element.addEventListener('touchmove', this._touchMove, false);
-            element.addEventListener('touchend', this._touchEnd, false);
 
             Tools.RegisterTopRootEvents([
                 { name: "keydown", handler: this._onKeyDown },
@@ -379,7 +315,7 @@
         }
 
         public detachControl(element: HTMLElement): void {
-            if (this._attachedElement != element) {
+            if (this._attachedElement !== element) {
                 return;
             }
 
@@ -392,10 +328,6 @@
             element.removeEventListener("MSGestureChange", this._onGesture);
             element.removeEventListener('mousewheel', this._wheel);
             element.removeEventListener('DOMMouseScroll', this._wheel);
-            // pinch
-            element.removeEventListener('touchstart', this._touchStart);
-            element.removeEventListener('touchmove', this._touchMove);
-            element.removeEventListener('touchend', this._touchEnd);
 
             Tools.UnregisterTopRootEvents([
                 { name: "keydown", handler: this._onKeyDown },
@@ -428,7 +360,7 @@
             }
 
             // Inertia
-            if (this.inertialAlphaOffset != 0 || this.inertialBetaOffset != 0 || this.inertialRadiusOffset != 0) {
+            if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset != 0) {
 
                 this.alpha += this.inertialAlphaOffset;
                 this.beta += this.inertialBetaOffset;
@@ -438,13 +370,13 @@
                 this.inertialBetaOffset *= this.inertia;
                 this.inertialRadiusOffset *= this.inertia;
 
-                if (Math.abs(this.inertialAlphaOffset) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialAlphaOffset) < Engine.Epsilon)
                     this.inertialAlphaOffset = 0;
 
-                if (Math.abs(this.inertialBetaOffset) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialBetaOffset) < Engine.Epsilon)
                     this.inertialBetaOffset = 0;
 
-                if (Math.abs(this.inertialRadiusOffset) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialRadiusOffset) < Engine.Epsilon)
                     this.inertialRadiusOffset = 0;
             }
 
@@ -493,7 +425,7 @@
 
             var target = this._getTargetPosition();
 
-            target.addToRef(new BABYLON.Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this.position);
+            target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this.position);
 
             if (this.checkCollisions) {
                 this._collider.radius = this.collisionRadius;
@@ -521,17 +453,17 @@
             this._previousRadius = this.radius;
             this._previousPosition.copyFrom(this.position);
 
-			this._viewMatrix.m[12] += this.targetScreenOffset.x;
-			this._viewMatrix.m[13] += this.targetScreenOffset.y;
-						
+            this._viewMatrix.m[12] += this.targetScreenOffset.x;
+            this._viewMatrix.m[13] += this.targetScreenOffset.y;
+
             return this._viewMatrix;
         }
 
         public zoomOn(meshes?: AbstractMesh[]): void {
             meshes = meshes || this.getScene().meshes;
 
-            var minMaxVector = BABYLON.Mesh.MinMax(meshes);
-            var distance = BABYLON.Vector3.Distance(minMaxVector.min, minMaxVector.max);
+            var minMaxVector = Mesh.MinMax(meshes);
+            var distance = Vector3.Distance(minMaxVector.min, minMaxVector.max);
 
             this.radius = distance * this.zoomOnFactor;
 
@@ -544,8 +476,8 @@
 
             if (meshesOrMinMaxVectorAndDistance.min === undefined) { // meshes
                 meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance || this.getScene().meshes;
-                meshesOrMinMaxVector = BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
-                distance = BABYLON.Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
+                meshesOrMinMaxVector = Mesh.MinMax(meshesOrMinMaxVector);
+                distance = Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
             }
             else { //minMaxVector and distance
                 meshesOrMinMaxVector = meshesOrMinMaxVectorAndDistance;
@@ -557,4 +489,4 @@
             this.maxZ = distance * 2;
         }
     }
-} 
+} 

+ 12 - 3
Babylon/Cameras/babylon.camera.js

@@ -32,7 +32,8 @@ var BABYLON;
             this._postProcesses = new Array();
             this._postProcessesTakenIndices = [];
             this._activeMeshes = new BABYLON.SmartArray(256);
-            scene.cameras.push(this);
+            this._globalPosition = BABYLON.Vector3.Zero();
+            scene.addCamera(this);
             if (!scene.activeCamera) {
                 scene.activeCamera = this;
             }
@@ -65,6 +66,13 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(Camera.prototype, "globalPosition", {
+            get: function () {
+                return this._globalPosition;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Camera.prototype.getActiveMeshes = function () {
             return this._activeMeshes;
         };
@@ -221,6 +229,7 @@ var BABYLON;
         Camera.prototype.getViewMatrix = function () {
             this._computedViewMatrix = this._computeViewMatrix();
             if (!this.parent || !this.parent.getWorldMatrix || this.isSynchronized()) {
+                this._globalPosition.copyFrom(this.position);
                 return this._computedViewMatrix;
             }
             if (!this._worldMatrix) {
@@ -230,6 +239,7 @@ var BABYLON;
             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) {
@@ -261,8 +271,7 @@ var BABYLON;
         };
         Camera.prototype.dispose = function () {
             // Remove from scene
-            var index = this.getScene().cameras.indexOf(this);
-            this.getScene().cameras.splice(index, 1);
+            this.getScene().removeCamera(this);
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
             }

+ 13 - 3
Babylon/Cameras/babylon.camera.ts

@@ -48,16 +48,22 @@
 
         public _activeMeshes = new SmartArray<Mesh>(256);
 
+        private _globalPosition = Vector3.Zero();
+
         constructor(name: string, public position: Vector3, scene: Scene) {
             super(name, scene);
 
-            scene.cameras.push(this);
+            scene.addCamera(this);
 
             if (!scene.activeCamera) {
                 scene.activeCamera = this;
             }
         }
 
+        public get globalPosition(): Vector3 {
+            return this._globalPosition;
+        }
+
         public getActiveMeshes(): SmartArray<Mesh> {
             return this._activeMeshes;
         }
@@ -281,6 +287,9 @@
             if (!this.parent
                 || !this.parent.getWorldMatrix
                 || this.isSynchronized()) {
+
+                this._globalPosition.copyFrom(this.position);
+
                 return this._computedViewMatrix;
             }
 
@@ -295,6 +304,8 @@
             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;
         }
 
@@ -333,8 +344,7 @@
 
         public dispose(): void {
             // Remove from scene
-            var index = this.getScene().cameras.indexOf(this);
-            this.getScene().cameras.splice(index, 1);
+            this.getScene().removeCamera(this);
 
             // Postprocesses
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {

+ 3 - 3
Babylon/Cameras/babylon.followCamera.ts

@@ -6,7 +6,7 @@
         public heightOffset:number = 4;
         public cameraAcceleration:number = 0.05;
         public maxCameraSpeed:number = 20;
-        public target:BABYLON.AbstractMesh;
+        public target:AbstractMesh;
 
         constructor(name:string, position:Vector3, scene:Scene) {
             super(name, position, scene);
@@ -16,7 +16,7 @@
             return degrees * Math.PI / 180;
         }
 
-        private follow(cameraTarget:BABYLON.AbstractMesh) {
+        private follow(cameraTarget:AbstractMesh) {
             if (!cameraTarget)
                 return;
 
@@ -43,7 +43,7 @@
                 vz = vz < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
             }
 
-            this.position = new BABYLON.Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
+            this.position = new Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
             this.setTarget(cameraTarget.position);
         }
 

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

@@ -1,141 +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

+ 1 - 1
Babylon/Cameras/babylon.targetCamera.js

@@ -147,7 +147,7 @@ var BABYLON;
         TargetCamera.prototype._getViewMatrix = function () {
             if (!this.lockedTarget) {
                 // Compute
-                if (this.upVector.x != 0 || this.upVector.y != 1.0 || this.upVector.z != 0) {
+                if (this.upVector.x !== 0 || this.upVector.y !== 1.0 || this.upVector.z !== 0) {
                     BABYLON.Matrix.LookAtLHToRef(BABYLON.Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
                     BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
                     this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);

+ 27 - 27
Babylon/Cameras/babylon.targetCamera.ts

@@ -1,23 +1,23 @@
 module BABYLON {
     export class TargetCamera extends Camera {
 
-        public cameraDirection = new BABYLON.Vector3(0, 0, 0);
-        public cameraRotation = new BABYLON.Vector2(0, 0);
-        public rotation = new BABYLON.Vector3(0, 0, 0);
+        public cameraDirection = new Vector3(0, 0, 0);
+        public cameraRotation = new Vector2(0, 0);
+        public rotation = new Vector3(0, 0, 0);
 
         public speed = 2.0;
         public noRotationConstraint = false;
         public lockedTarget = null;
 
-        public _currentTarget = BABYLON.Vector3.Zero();
-        public _viewMatrix = BABYLON.Matrix.Zero();
-        public _camMatrix = BABYLON.Matrix.Zero();
-        public _cameraTransformMatrix = BABYLON.Matrix.Zero();
-        public _cameraRotationMatrix = BABYLON.Matrix.Zero();
-        public _referencePoint = new BABYLON.Vector3(0, 0, 1);
-        public _transformedReferencePoint = BABYLON.Vector3.Zero();
-        public _lookAtTemp = BABYLON.Matrix.Zero();
-        public _tempMatrix = BABYLON.Matrix.Zero();
+        public _currentTarget = Vector3.Zero();
+        public _viewMatrix = Matrix.Zero();
+        public _camMatrix = Matrix.Zero();
+        public _cameraTransformMatrix = Matrix.Zero();
+        public _cameraRotationMatrix = Matrix.Zero();
+        public _referencePoint = new Vector3(0, 0, 1);
+        public _transformedReferencePoint = Vector3.Zero();
+        public _lookAtTemp = Matrix.Zero();
+        public _tempMatrix = Matrix.Zero();
 
         public _reset:() => void;
 
@@ -38,8 +38,8 @@
         // Cache
         public _initCache() {
             super._initCache();
-            this._cache.lockedTarget = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-            this._cache.rotation = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.lockedTarget = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.rotation = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
         }
 
         public _updateCache(ignoreParentClass?:boolean):void {
@@ -85,7 +85,7 @@
         public setTarget(target:Vector3):void {
             this.upVector.normalize();
 
-            BABYLON.Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
+            Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
             this._camMatrix.invert();
 
             this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
@@ -98,7 +98,7 @@
                 this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
             }
 
-            this.rotation.z = -Math.acos(BABYLON.Vector3.Dot(new BABYLON.Vector3(0, 1.0, 0), this.upVector));
+            this.rotation.z = -Math.acos(Vector3.Dot(new Vector3(0, 1.0, 0), this.upVector));
 
             if (isNaN(this.rotation.x)) {
                 this.rotation.x = 0;
@@ -153,26 +153,26 @@
 
             // Inertia
             if (needToMove) {
-                if (Math.abs(this.cameraDirection.x) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.x) < Engine.Epsilon) {
                     this.cameraDirection.x = 0;
                 }
 
-                if (Math.abs(this.cameraDirection.y) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.y) < Engine.Epsilon) {
                     this.cameraDirection.y = 0;
                 }
 
-                if (Math.abs(this.cameraDirection.z) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.z) < Engine.Epsilon) {
                     this.cameraDirection.z = 0;
                 }
 
                 this.cameraDirection.scaleInPlace(this.inertia);
             }
             if (needToRotate) {
-                if (Math.abs(this.cameraRotation.x) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraRotation.x) < Engine.Epsilon) {
                     this.cameraRotation.x = 0;
                 }
 
-                if (Math.abs(this.cameraRotation.y) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraRotation.y) < Engine.Epsilon) {
                     this.cameraRotation.y = 0;
                 }
                 this.cameraRotation.scaleInPlace(this.inertia);
@@ -183,19 +183,19 @@
         public _getViewMatrix():Matrix {
             if (!this.lockedTarget) {
                 // Compute
-                if (this.upVector.x != 0 || this.upVector.y != 1.0 || this.upVector.z != 0) {
-                    BABYLON.Matrix.LookAtLHToRef(BABYLON.Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
-                    BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+                if (this.upVector.x !== 0 || this.upVector.y !== 1.0 || this.upVector.z !== 0) {
+                    Matrix.LookAtLHToRef(Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
+                    Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
 
 
                     this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);
                     this._lookAtTemp.invert();
                     this._tempMatrix.multiplyToRef(this._lookAtTemp, this._cameraRotationMatrix);
                 } else {
-                    BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+                    Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
                 }
 
-                BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+                Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
 
                 // Computing target and final matrix
                 this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
@@ -203,7 +203,7 @@
                 this._currentTarget.copyFrom(this._getLockedTargetPosition());
             }
 
-            BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
+            Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
             return this._viewMatrix;
         }
     }

+ 0 - 37
Babylon/Cameras/babylon.vrDeviceOrientationCamera.js

@@ -1,37 +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 VRDeviceOrientationCamera = (function (_super) {
-        __extends(VRDeviceOrientationCamera, _super);
-        function VRDeviceOrientationCamera(name, position, scene) {
-            _super.call(this, name, position, scene);
-            this._alpha = 0;
-            this._beta = 0;
-            this._gamma = 0;
-        }
-        VRDeviceOrientationCamera.prototype._onOrientationEvent = function (evt) {
-            this._alpha = +evt.alpha | 0;
-            this._beta = +evt.beta | 0;
-            this._gamma = +evt.gamma | 0;
-
-            if (this._gamma < 0) {
-                this._gamma = 90 + this._gamma;
-            } else {
-                // 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;
-        };
-        return VRDeviceOrientationCamera;
-    })(BABYLON.OculusCamera);
-    BABYLON.VRDeviceOrientationCamera = VRDeviceOrientationCamera;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.vrDeviceOrientationCamera.js.map

+ 7 - 6
Babylon/Debug/babylon.debugLayer.js

@@ -355,8 +355,9 @@ var BABYLON;
             if (tag === void 0) { tag = null; }
             var button = document.createElement("button");
             button.innerHTML = title;
-            button.style.height = "20px";
-            button.style.color = "#222222";
+            button.style.height = "24px";
+            button.style.color = "#444444";
+            button.style.border = "1px solid white";
             button.className = "debugLayerButton";
             button.addEventListener("click", function (evt) {
                 task(evt.target, tag);
@@ -581,14 +582,14 @@ var BABYLON;
                 if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                     this._optionsSubsetDiv.appendChild(document.createElement("br"));
                     this._generateTexBox(this._optionsSubsetDiv, "<b>Audio:</b>", this.accentColor);
-                    this._generateRadio(this._optionsSubsetDiv, "Headphones", "panningModel", true, function (element) {
+                    this._generateRadio(this._optionsSubsetDiv, "Headphones", "panningModel", this._scene.headphone, function (element) {
                         if (element.checked) {
-                            _this._scene.switchAudioModeForHeadphones();
+                            _this._scene.headphone = true;
                         }
                     });
-                    this._generateRadio(this._optionsSubsetDiv, "Normal Speakers", "panningModel", false, function (element) {
+                    this._generateRadio(this._optionsSubsetDiv, "Normal Speakers", "panningModel", !this._scene.headphone, function (element) {
                         if (element.checked) {
-                            _this._scene.switchAudioModeForNormalSpeakers();
+                            _this._scene.headphone = false;
                         }
                     });
                     this._generateCheckBox(this._optionsSubsetDiv, "Disable audio", !this._scene.audioEnabled, function (element) {

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


+ 7 - 6
Babylon/Debug/babylon.debugLayer.ts

@@ -482,8 +482,9 @@
         private _generateButton(root: HTMLDivElement, title: string, task: (element, tag) => void, tag: any = null): void {
             var button = document.createElement("button");
             button.innerHTML = title;
-            button.style.height = "20px";
-            button.style.color = "#222222";
+            button.style.height = "24px";
+            button.style.color = "#444444";
+            button.style.border = "1px solid white"; 
             button.className = "debugLayerButton";
 
             button.addEventListener("click",(evt: Event) => {
@@ -673,14 +674,14 @@
                 if (Engine.audioEngine.canUseWebAudio) {
                     this._optionsSubsetDiv.appendChild(document.createElement("br"));
                     this._generateTexBox(this._optionsSubsetDiv, "<b>Audio:</b>", this.accentColor);
-                    this._generateRadio(this._optionsSubsetDiv, "Headphones", "panningModel", true, (element) => {
+                    this._generateRadio(this._optionsSubsetDiv, "Headphones", "panningModel", this._scene.headphone, (element) => {
                         if (element.checked) {
-                            this._scene.switchAudioModeForHeadphones();
+                            this._scene.headphone = true;
                         }
                     });
-                    this._generateRadio(this._optionsSubsetDiv, "Normal Speakers", "panningModel", false, (element) => {
+                    this._generateRadio(this._optionsSubsetDiv, "Normal Speakers", "panningModel", !this._scene.headphone, (element) => {
                         if (element.checked) {
-                            this._scene.switchAudioModeForNormalSpeakers();
+                            this._scene.headphone = false;
                         }
                     });
                     this._generateCheckBox(this._optionsSubsetDiv, "Disable audio", !this._scene.audioEnabled, (element) => {

+ 37 - 9
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -4,11 +4,11 @@ var BABYLON;
         function ShadowGenerator(mapSize, light) {
             var _this = this;
             // Members
-            this.filter = ShadowGenerator.FILTER_NONE;
+            this._filter = ShadowGenerator.FILTER_NONE;
             this.blurScale = 2;
             this._blurBoxOffset = 0;
-            this._darkness = 0;
             this._bias = 0.00005;
+            this._darkness = 0;
             this._transparencyShadow = false;
             this._viewMatrix = BABYLON.Matrix.Zero();
             this._projectionMatrix = BABYLON.Matrix.Zero();
@@ -22,6 +22,8 @@ var BABYLON;
             this._shadowMap = new BABYLON.RenderTargetTexture(light.name + "_shadowMap", mapSize, this._scene, false);
             this._shadowMap.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+            this._shadowMap.anisotropicFilteringLevel = 1;
+            this._shadowMap.updateSamplingMode(BABYLON.Texture.NEAREST_SAMPLINGMODE);
             this._shadowMap.renderParticles = false;
             this._shadowMap.onAfterUnbind = function () {
                 if (!_this.useBlurVarianceShadowMap) {
@@ -31,7 +33,8 @@ var BABYLON;
                     _this._shadowMap2 = new BABYLON.RenderTargetTexture(light.name + "_shadowMap", mapSize, _this._scene, false);
                     _this._shadowMap2.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
                     _this._shadowMap2.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                    _this._downSamplePostprocess = new BABYLON.PassPostProcess("downScale", 1.0 / _this.blurScale, null, BABYLON.Texture.NEAREST_SAMPLINGMODE, _this._scene.getEngine());
+                    _this._shadowMap2.updateSamplingMode(BABYLON.Texture.TRILINEAR_SAMPLINGMODE);
+                    _this._downSamplePostprocess = new BABYLON.PassPostProcess("downScale", 1.0 / _this.blurScale, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, _this._scene.getEngine());
                     _this._downSamplePostprocess.onApply = function (effect) {
                         effect.setTexture("textureSampler", _this._shadowMap);
                     };
@@ -127,6 +130,16 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(ShadowGenerator.prototype, "bias", {
+            get: function () {
+                return this._bias;
+            },
+            set: function (bias) {
+                this._bias = bias;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(ShadowGenerator.prototype, "blurBoxOffset", {
             get: function () {
                 return this._blurBoxOffset;
@@ -148,6 +161,27 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(ShadowGenerator.prototype, "filter", {
+            get: function () {
+                return this._filter;
+            },
+            set: function (value) {
+                if (this._filter === value) {
+                    return;
+                }
+                this._filter = value;
+                if (this.useVarianceShadowMap || this.useBlurVarianceShadowMap) {
+                    this._shadowMap.anisotropicFilteringLevel = 16;
+                    this._shadowMap.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE);
+                }
+                else {
+                    this._shadowMap.anisotropicFilteringLevel = 1;
+                    this._shadowMap.updateSamplingMode(BABYLON.Texture.NEAREST_SAMPLINGMODE);
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(ShadowGenerator.prototype, "useVarianceShadowMap", {
             get: function () {
                 return this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP && this._light.supportsVSM();
@@ -265,12 +299,6 @@ var BABYLON;
             else
                 this._darkness = darkness;
         };
-        ShadowGenerator.prototype.getBias = function () {
-            return this._bias;
-        };
-        ShadowGenerator.prototype.setBias = function (bias) {
-            this._bias = bias;
-        };
         ShadowGenerator.prototype.setTransparencyShadow = function (hasShadow) {
             this._transparencyShadow = hasShadow;
         };

+ 37 - 15
Babylon/Lights/Shadows/babylon.shadowGenerator.ts

@@ -23,15 +23,23 @@
         }
 
         // Members
-        public filter = ShadowGenerator.FILTER_NONE;
+        private _filter = ShadowGenerator.FILTER_NONE;
         public blurScale = 2;
         private _blurBoxOffset = 0;
+        private _bias = 0.00005;
+
+        public get bias(): number {
+            return this._bias;
+        }
 
+        public set bias(bias: number) {
+            this._bias = bias;
+        }
         public get blurBoxOffset(): number {
             return this._blurBoxOffset;
         }
 
-        public set blurBoxOffset(value:number) {
+        public set blurBoxOffset(value: number) {
             if (this._blurBoxOffset === value) {
                 return;
             }
@@ -48,6 +56,26 @@
             };
         }
 
+        public get filter(): number {
+            return this._filter;
+        }
+
+        public set filter(value: number) {
+            if (this._filter === value) {
+                return;
+            }
+
+            this._filter = value;
+
+            if (this.useVarianceShadowMap || this.useBlurVarianceShadowMap) {
+                this._shadowMap.anisotropicFilteringLevel = 16;
+                this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
+            } else {
+                this._shadowMap.anisotropicFilteringLevel = 1;
+                this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
+            }
+        }
+
         public get useVarianceShadowMap(): boolean {
             return this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP && this._light.supportsVSM();
         }
@@ -60,7 +88,7 @@
                 (!this._light.supportsVSM() && (
                     this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP ||
                     this.filter === ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP
-                ));
+                    ));
         }
         public set usePoissonSampling(value: boolean) {
             this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
@@ -78,7 +106,6 @@
         private _shadowMap: RenderTargetTexture;
         private _shadowMap2: RenderTargetTexture;
         private _darkness = 0;
-        private _bias = 0.00005;
         private _transparencyShadow = false;
         private _effect: Effect;
 
@@ -105,6 +132,8 @@
             this._shadowMap = new RenderTargetTexture(light.name + "_shadowMap", mapSize, this._scene, false);
             this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this._shadowMap.anisotropicFilteringLevel = 1;
+            this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
             this._shadowMap.renderParticles = false;
 
             this._shadowMap.onAfterUnbind = () => {
@@ -116,8 +145,9 @@
                     this._shadowMap2 = new RenderTargetTexture(light.name + "_shadowMap", mapSize, this._scene, false);
                     this._shadowMap2.wrapU = Texture.CLAMP_ADDRESSMODE;
                     this._shadowMap2.wrapV = Texture.CLAMP_ADDRESSMODE;
-                    
-                    this._downSamplePostprocess = new PassPostProcess("downScale", 1.0 / this.blurScale, null, Texture.NEAREST_SAMPLINGMODE, this._scene.getEngine());
+                    this._shadowMap2.updateSamplingMode(Texture.TRILINEAR_SAMPLINGMODE);
+
+                    this._downSamplePostprocess = new PassPostProcess("downScale", 1.0 / this.blurScale, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
                     this._downSamplePostprocess.onApply = effect => {
                         effect.setTexture("textureSampler", this._shadowMap);
                     };
@@ -316,19 +346,11 @@
                 this._darkness = darkness;
         }
 
-        public getBias(): number {
-            return this._bias;
-        }
-
-        public setBias(bias: number): void {
-            this._bias = bias;
-        }
-
         public setTransparencyShadow(hasShadow: boolean): void {
             this._transparencyShadow = hasShadow;
         }
 
-        private _packHalf(depth: number): Vector2 { 
+        private _packHalf(depth: number): Vector2 {
             var scale = depth * 255.0;
             var fract = scale - Math.floor(scale);
 

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

@@ -11,7 +11,7 @@ var BABYLON;
         function DirectionalLight(name, direction, scene) {
             _super.call(this, name, scene);
             this.direction = direction;
-            this.shadowOrthoScale = 0.1;
+            this.shadowOrthoScale = 0.5;
             this.position = direction.scale(-1);
         }
         DirectionalLight.prototype.getAbsolutePosition = function () {

+ 1 - 1
Babylon/Lights/babylon.directionalLight.ts

@@ -6,7 +6,7 @@
         public transformedPosition: Vector3;
         private _worldMatrix: Matrix;
 
-        public shadowOrthoScale = 0.1;
+        public shadowOrthoScale = 0.5;
 
         constructor(name: string, public direction: Vector3, scene: Scene) {
             super(name, scene);

+ 6 - 3
Babylon/Lights/babylon.light.js

@@ -14,11 +14,12 @@ var BABYLON;
             this.specular = new BABYLON.Color3(1.0, 1.0, 1.0);
             this.intensity = 1.0;
             this.range = Number.MAX_VALUE;
+            this.includeOnlyWithLayerMask = 0;
             this.includedOnlyMeshes = new Array();
             this.excludedMeshes = new Array();
             this._excludedMeshesIds = new Array();
             this._includedOnlyMeshesIds = new Array();
-            scene.lights.push(this);
+            scene.addLight(this);
         }
         Light.prototype.getShadowGenerator = function () {
             return this._shadowGenerator;
@@ -41,6 +42,9 @@ var BABYLON;
             if (this.excludedMeshes.length > 0 && this.excludedMeshes.indexOf(mesh) !== -1) {
                 return false;
             }
+            if (this.includeOnlyWithLayerMask !== 0 && this.includeOnlyWithLayerMask !== mesh.layerMask) {
+                return false;
+            }
             return true;
         };
         Light.prototype.getWorldMatrix = function () {
@@ -61,8 +65,7 @@ var BABYLON;
                 this._shadowGenerator = null;
             }
             // Remove from scene
-            var index = this.getScene().lights.indexOf(this);
-            this.getScene().lights.splice(index, 1);
+            this.getScene().removeLight(this);
         };
         return Light;
     })(BABYLON.Node);

+ 8 - 4
Babylon/Lights/babylon.light.ts

@@ -22,6 +22,7 @@
         public specular = new Color3(1.0, 1.0, 1.0);
         public intensity = 1.0;
         public range = Number.MAX_VALUE;
+        public includeOnlyWithLayerMask = 0;
         public includedOnlyMeshes = new Array<AbstractMesh>();
         public excludedMeshes = new Array<AbstractMesh>();
 
@@ -33,7 +34,7 @@
         constructor(name: string, scene: Scene) {
             super(name, scene);
 
-            scene.lights.push(this);
+            scene.addLight(this);
         }
 
         public getShadowGenerator(): ShadowGenerator {
@@ -43,7 +44,7 @@
         public getAbsolutePosition(): Vector3 {
             return Vector3.Zero();
         }
-       
+
         public transferToEffect(effect: Effect, uniformName0?: string, uniformName1?: string): void {
         }
 
@@ -64,6 +65,10 @@
                 return false;
             }
 
+            if (this.includeOnlyWithLayerMask !== 0 && this.includeOnlyWithLayerMask !== mesh.layerMask) {
+                return false;
+            }
+
             return true;
         }
 
@@ -92,8 +97,7 @@
             }
 
             // Remove from scene
-            var index = this.getScene().lights.indexOf(this);
-            this.getScene().lights.splice(index, 1);
+            this.getScene().removeLight(this);
         }
     }
 } 

+ 22 - 7
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -220,9 +220,15 @@ var BABYLON;
             }
             else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
                 shadowGenerator.useBlurVarianceShadowMap = true;
+                if (parsedShadowGenerator.blurScale) {
+                    shadowGenerator.blurScale = parsedShadowGenerator.blurScale;
+                }
+                if (parsedShadowGenerator.blurBoxOffset) {
+                    shadowGenerator.blurBoxOffset = parsedShadowGenerator.blurBoxOffset;
+                }
             }
-            if (parsedShadowGenerator.bias) {
-                shadowGenerator.setBias(parsedShadowGenerator.bias);
+            if (parsedShadowGenerator.bias !== undefined) {
+                shadowGenerator.bias = parsedShadowGenerator.bias;
             }
             return shadowGenerator;
         };
@@ -373,7 +379,13 @@ var BABYLON;
             }
             // Target
             if (parsedCamera.target) {
-                camera.setTarget(BABYLON.Vector3.FromArray(parsedCamera.target));
+                if (camera.setTarget) {
+                    camera.setTarget(BABYLON.Vector3.FromArray(parsedCamera.target));
+                }
+                else {
+                    //For ArcRotate
+                    camera.target = BABYLON.Vector3.FromArray(parsedCamera.target);
+                }
             }
             else {
                 camera.rotation = BABYLON.Vector3.FromArray(parsedCamera.rotation);
@@ -768,12 +780,16 @@ var BABYLON;
                 var triggerParams;
                 var trigger = parsedActions.children[i];
                 if (trigger.properties.length > 0) {
-                    triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: scene.getMeshByName(trigger.properties[0].value) };
+                    var param = trigger.properties[0].value;
+                    var value = trigger.properties[0].targetType == null ? param : scene.getMeshByName(param);
+                    triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: value };
                 }
                 else
                     triggerParams = BABYLON.ActionManager[trigger.name];
-                for (var j = 0; j < trigger.children.length; j++)
-                    traverse(trigger.children[j], triggerParams, null, null);
+                for (var j = 0; j < trigger.children.length; j++) {
+                    if (!trigger.detached)
+                        traverse(trigger.children[j], triggerParams, null, null);
+                }
             }
         };
         var parseSound = function (parsedSound, scene, rootUrl) {
@@ -788,7 +804,6 @@ var BABYLON;
                 rolloffFactor: parsedSound.rolloffFactor,
                 refDistance: parsedSound.refDistance,
                 distanceModel: parsedSound.distanceModel,
-                panningModel: parsedSound.panningModel,
                 playbackRate: parsedSound.playbackRate
             };
             var newSound = new BABYLON.Sound(soundName, soundUrl, scene, function () {

+ 23 - 7
Babylon/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -273,10 +273,18 @@
             shadowGenerator.useVarianceShadowMap = true;
         } else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
             shadowGenerator.useBlurVarianceShadowMap = true;
+
+            if (parsedShadowGenerator.blurScale) {
+                shadowGenerator.blurScale = parsedShadowGenerator.blurScale;
+            }
+
+            if (parsedShadowGenerator.blurBoxOffset) {
+                shadowGenerator.blurBoxOffset = parsedShadowGenerator.blurBoxOffset;
+            }
         }
 
-        if (parsedShadowGenerator.bias) {
-            shadowGenerator.setBias(parsedShadowGenerator.bias);
+        if (parsedShadowGenerator.bias !== undefined) {
+            shadowGenerator.bias = parsedShadowGenerator.bias;
         }
 
         return shadowGenerator;
@@ -454,7 +462,12 @@
 
         // Target
         if (parsedCamera.target) {
-            camera.setTarget(BABYLON.Vector3.FromArray(parsedCamera.target));
+            if (camera.setTarget) {
+                camera.setTarget(BABYLON.Vector3.FromArray(parsedCamera.target));
+            } else {
+                //For ArcRotate
+                camera.target = BABYLON.Vector3.FromArray(parsedCamera.target);
+            }
         } else {
             camera.rotation = BABYLON.Vector3.FromArray(parsedCamera.rotation);
         }
@@ -958,13 +971,17 @@
             var trigger = parsedActions.children[i];
 
             if (trigger.properties.length > 0) {
-                triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: scene.getMeshByName(trigger.properties[0].value) };
+                var param = trigger.properties[0].value;
+                var value = trigger.properties[0].targetType == null ? param : scene.getMeshByName(param);
+                triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: value };
             }
             else
                 triggerParams = BABYLON.ActionManager[trigger.name];
 
-            for (var j = 0; j < trigger.children.length; j++)
-                traverse(trigger.children[j], triggerParams, null, null);
+            for (var j = 0; j < trigger.children.length; j++) {
+                if (!trigger.detached)
+                    traverse(trigger.children[j], triggerParams, null, null);
+            }
         }
 
     };
@@ -979,7 +996,6 @@
             rolloffFactor: parsedSound.rolloffFactor,
             refDistance: parsedSound.refDistance,
             distanceModel: parsedSound.distanceModel,
-            panningModel: parsedSound.panningModel,
             playbackRate: parsedSound.playbackRate
         };
 

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

@@ -26,6 +26,9 @@ var BABYLON;
         SceneLoader._getPluginForFilename = function (sceneFilename) {
             var dotPosition = sceneFilename.lastIndexOf(".");
             var queryStringPosition = sceneFilename.indexOf("?");
+            if (queryStringPosition === -1) {
+                queryStringPosition = sceneFilename.length;
+            }
             var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
             for (var index = 0; index < this._registeredPlugins.length; index++) {
                 var plugin = this._registeredPlugins[index];

+ 5 - 0
Babylon/Loading/babylon.sceneLoader.ts

@@ -33,6 +33,11 @@
             var dotPosition = sceneFilename.lastIndexOf(".");
 
             var queryStringPosition = sceneFilename.indexOf("?");
+
+            if (queryStringPosition === -1) {
+                queryStringPosition = sceneFilename.length;
+            }
+
             var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
 
             for (var index = 0; index < this._registeredPlugins.length; index++) {

+ 0 - 4
Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.js

@@ -321,10 +321,6 @@ var BABYLON;
             get: function () {
                 return this._numberOfBricksHeight;
             },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(BrickProceduralTexture.prototype, "cloudColor", {
             set: function (value) {
                 this._numberOfBricksHeight = value;
                 this.updateShaderUniforms();

+ 1 - 1
Babylon/Materials/Textures/Procedurals/babylon.standardProceduralTexture.ts

@@ -285,7 +285,7 @@
             return this._numberOfBricksHeight;
         }
 
-        public set cloudColor(value: number) {
+        public set numberOfBricksHeight(value: number) {
             this._numberOfBricksHeight = value;
             this.updateShaderUniforms();
         }

+ 11 - 5
Babylon/Materials/Textures/babylon.texture.js

@@ -46,7 +46,7 @@ var BABYLON;
             }
         }
         Texture.prototype.delayLoad = function () {
-            if (this.delayLoadState != BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
+            if (this.delayLoadState !== BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
                 return;
             }
             this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
@@ -58,6 +58,12 @@ var BABYLON;
                 }
             }
         };
+        Texture.prototype.updateSamplingMode = function (samplingMode) {
+            if (!this._texture) {
+                return;
+            }
+            this.getScene().getEngine().updateTextureSamplingMode(samplingMode, this._texture);
+        };
         Texture.prototype._prepareRowForTextureGeneration = function (x, y, z, t) {
             x -= this.uOffset + 0.5;
             y -= this.vOffset + 0.5;
@@ -115,21 +121,21 @@ var BABYLON;
             }
             this._cachedCoordinatesMode = this.coordinatesMode;
             switch (this.coordinatesMode) {
-                case BABYLON.Texture.SPHERICAL_MODE:
+                case Texture.SPHERICAL_MODE:
                     BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);
                     this._cachedTextureMatrix[0] = -0.5 * this.uScale;
                     this._cachedTextureMatrix[5] = -0.5 * this.vScale;
                     this._cachedTextureMatrix[12] = 0.5 + this.uOffset;
                     this._cachedTextureMatrix[13] = 0.5 + this.vOffset;
                     break;
-                case BABYLON.Texture.PLANAR_MODE:
+                case Texture.PLANAR_MODE:
                     BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);
                     this._cachedTextureMatrix[0] = this.uScale;
                     this._cachedTextureMatrix[5] = this.vScale;
                     this._cachedTextureMatrix[12] = this.uOffset;
                     this._cachedTextureMatrix[13] = this.vOffset;
                     break;
-                case BABYLON.Texture.PROJECTION_MODE:
+                case Texture.PROJECTION_MODE:
                     BABYLON.Matrix.IdentityToRef(this._projectionModeMatrix);
                     this._projectionModeMatrix.m[0] = 0.5;
                     this._projectionModeMatrix.m[5] = -0.5;
@@ -147,7 +153,7 @@ var BABYLON;
             return this._cachedTextureMatrix;
         };
         Texture.prototype.clone = function () {
-            var newTexture = new BABYLON.Texture(this._texture.url, this.getScene(), this._noMipmap, this._invertY, this._samplingMode);
+            var newTexture = new Texture(this._texture.url, this.getScene(), this._noMipmap, this._invertY, this._samplingMode);
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;
             newTexture.level = this.level;

+ 28 - 20
Babylon/Materials/Textures/babylon.texture.ts

@@ -71,17 +71,17 @@
                         delete this._buffer;
                     }
                 } else {
-                    this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NOTLOADED;
+                    this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
                 }
             }
         }
 
         public delayLoad(): void {
-            if (this.delayLoadState != BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
+            if (this.delayLoadState !== Engine.DELAYLOADSTATE_NOTLOADED) {
                 return;
             }
 
-            this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
+            this.delayLoadState = Engine.DELAYLOADSTATE_LOADED;
             this._texture = this._getFromCache(this.url, this._noMipmap, this._samplingMode);
 
             if (!this._texture) {
@@ -92,6 +92,14 @@
             }
         }
 
+        public updateSamplingMode(samplingMode: number): void {
+            if (!this._texture) {
+                return;
+            }
+
+            this.getScene().getEngine().updateTextureSamplingMode(samplingMode, this._texture);
+        }
+
         private _prepareRowForTextureGeneration(x: number, y: number, z: number, t: Vector3): void {
             x -= this.uOffset + 0.5;
             y -= this.vOffset + 0.5;
@@ -128,14 +136,14 @@
             this._cachedWAng = this.wAng;
 
             if (!this._cachedTextureMatrix) {
-                this._cachedTextureMatrix = BABYLON.Matrix.Zero();
-                this._rowGenerationMatrix = new BABYLON.Matrix();
-                this._t0 = BABYLON.Vector3.Zero();
-                this._t1 = BABYLON.Vector3.Zero();
-                this._t2 = BABYLON.Vector3.Zero();
+                this._cachedTextureMatrix = Matrix.Zero();
+                this._rowGenerationMatrix = new Matrix();
+                this._t0 = Vector3.Zero();
+                this._t1 = Vector3.Zero();
+                this._t2 = Vector3.Zero();
             }
 
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.vAng, this.uAng, this.wAng, this._rowGenerationMatrix);
+            Matrix.RotationYawPitchRollToRef(this.vAng, this.uAng, this.wAng, this._rowGenerationMatrix);
 
             this._prepareRowForTextureGeneration(0, 0, 0, this._t0);
             this._prepareRowForTextureGeneration(1.0, 0, 0, this._t1);
@@ -144,7 +152,7 @@
             this._t1.subtractInPlace(this._t0);
             this._t2.subtractInPlace(this._t0);
 
-            BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);
+            Matrix.IdentityToRef(this._cachedTextureMatrix);
             this._cachedTextureMatrix.m[0] = this._t1.x; this._cachedTextureMatrix.m[1] = this._t1.y; this._cachedTextureMatrix.m[2] = this._t1.z;
             this._cachedTextureMatrix.m[4] = this._t2.x; this._cachedTextureMatrix.m[5] = this._t2.y; this._cachedTextureMatrix.m[6] = this._t2.z;
             this._cachedTextureMatrix.m[8] = this._t0.x; this._cachedTextureMatrix.m[9] = this._t0.y; this._cachedTextureMatrix.m[10] = this._t0.z;
@@ -163,29 +171,29 @@
             }
 
             if (!this._cachedTextureMatrix) {
-                this._cachedTextureMatrix = BABYLON.Matrix.Zero();
-                this._projectionModeMatrix = BABYLON.Matrix.Zero();
+                this._cachedTextureMatrix = Matrix.Zero();
+                this._projectionModeMatrix = Matrix.Zero();
             }
 
             this._cachedCoordinatesMode = this.coordinatesMode;
 
             switch (this.coordinatesMode) {
-                case BABYLON.Texture.SPHERICAL_MODE:
-                    BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);
+                case Texture.SPHERICAL_MODE:
+                    Matrix.IdentityToRef(this._cachedTextureMatrix);
                     this._cachedTextureMatrix[0] = -0.5 * this.uScale;
                     this._cachedTextureMatrix[5] = -0.5 * this.vScale;
                     this._cachedTextureMatrix[12] = 0.5 + this.uOffset;
                     this._cachedTextureMatrix[13] = 0.5 + this.vOffset;
                     break;
-                case BABYLON.Texture.PLANAR_MODE:
-                    BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);
+                case Texture.PLANAR_MODE:
+                    Matrix.IdentityToRef(this._cachedTextureMatrix);
                     this._cachedTextureMatrix[0] = this.uScale;
                     this._cachedTextureMatrix[5] = this.vScale;
                     this._cachedTextureMatrix[12] = this.uOffset;
                     this._cachedTextureMatrix[13] = this.vOffset;
                     break;
-                case BABYLON.Texture.PROJECTION_MODE:
-                    BABYLON.Matrix.IdentityToRef(this._projectionModeMatrix);
+                case Texture.PROJECTION_MODE:
+                    Matrix.IdentityToRef(this._projectionModeMatrix);
 
                     this._projectionModeMatrix.m[0] = 0.5;
                     this._projectionModeMatrix.m[5] = -0.5;
@@ -198,14 +206,14 @@
                     this.getScene().getProjectionMatrix().multiplyToRef(this._projectionModeMatrix, this._cachedTextureMatrix);
                     break;
                 default:
-                    BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);
+                    Matrix.IdentityToRef(this._cachedTextureMatrix);
                     break;
             }
             return this._cachedTextureMatrix;
         }
 
         public clone(): Texture {
-            var newTexture = new BABYLON.Texture(this._texture.url, this.getScene(), this._noMipmap, this._invertY, this._samplingMode);
+            var newTexture = new Texture(this._texture.url, this.getScene(), this._noMipmap, this._invertY, this._samplingMode);
 
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;

+ 1 - 3
Babylon/Materials/babylon.standardMaterial.js

@@ -61,13 +61,11 @@ var BABYLON;
         StandardMaterial.prototype.isReady = function (mesh, useInstances) {
             if (this.checkReadyOnlyOnce) {
                 if (this._wasPreviouslyReady) {
-                    return true;
                 }
             }
             var scene = this.getScene();
             if (!this.checkReadyOnEveryCall) {
                 if (this._renderId === scene.getRenderId()) {
-                    return true;
                 }
             }
             var engine = scene.getEngine();
@@ -477,7 +475,7 @@ var BABYLON;
                         if (mesh.receiveShadows && shadowGenerator) {
                             this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
                             this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
-                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.getBias());
+                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.bias);
                         }
                     }
                     lightIndex++;

+ 3 - 3
Babylon/Materials/babylon.standardMaterial.ts

@@ -74,7 +74,7 @@
         public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
             if (this.checkReadyOnlyOnce) {
                 if (this._wasPreviouslyReady) {
-                    return true;
+                 //   return true;
                 }
             }
 
@@ -82,7 +82,7 @@
 
             if (!this.checkReadyOnEveryCall) {
                 if (this._renderId === scene.getRenderId()) {
-                    return true;
+                  //  return true;
                 }
             }
 
@@ -585,7 +585,7 @@
                         if (mesh.receiveShadows && shadowGenerator) {
                             this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
                             this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
-                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.getBias());
+                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.bias);
                         }
                     }
 

+ 294 - 6
Babylon/Math/babylon.math.js

@@ -630,6 +630,28 @@ var BABYLON;
             result.y = ry / rw;
             result.z = rz / rw;
         };
+        Vector3.TransformCoordinatesToRefSIMD = function (vector, transformation, result) {
+            var v = SIMD.float32x4.loadXYZ(vector._data, 0);
+            var m0 = SIMD.float32x4.load(transformation.m, 0);
+            var m1 = SIMD.float32x4.load(transformation.m, 4);
+            var m2 = SIMD.float32x4.load(transformation.m, 8);
+            var m3 = SIMD.float32x4.load(transformation.m, 12);
+            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 0, 0, 0, 0), m0), SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 1, 1, 1, 1), m1)), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 2, 2, 2, 2), m2), m3));
+            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
+            SIMD.float32x4.storeXYZ(result._data, 0, r);
+        };
+        Vector3.TransformCoordinatesFromFloatsToRefSIMD = function (x, y, z, transformation, result) {
+            var v0 = SIMD.float32x4.splat(x);
+            var v1 = SIMD.float32x4.splat(y);
+            var v2 = SIMD.float32x4.splat(z);
+            var m0 = SIMD.float32x4.load(transformation.m, 0);
+            var m1 = SIMD.float32x4.load(transformation.m, 4);
+            var m2 = SIMD.float32x4.load(transformation.m, 8);
+            var m3 = SIMD.float32x4.load(transformation.m, 12);
+            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(v0, m0), SIMD.float32x4.mul(v1, m1)), SIMD.float32x4.add(SIMD.float32x4.mul(v2, m2), m3));
+            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
+            SIMD.float32x4.storeXYZ(result._data, 0, r);
+        };
         Vector3.TransformNormal = function (vector, transformation) {
             var result = Vector3.Zero();
             Vector3.TransformNormalToRef(vector, transformation, result);
@@ -1371,6 +1393,112 @@ var BABYLON;
             other.m[15] = (((l1 * l36) - (l2 * l38)) + (l3 * l39)) * l27;
             return this;
         };
+        Matrix.prototype.invertToRefSIMD = function (other) {
+            var src = this.m;
+            var dest = other.m;
+            var row0, row1, row2, row3;
+            var tmp1;
+            var minor0, minor1, minor2, minor3;
+            var det;
+            // Load the 4 rows
+            var src0 = SIMD.float32x4.load(src, 0);
+            var src1 = SIMD.float32x4.load(src, 4);
+            var src2 = SIMD.float32x4.load(src, 8);
+            var src3 = SIMD.float32x4.load(src, 12);
+            // Transpose the source matrix.  Sort of.  Not a true transpose operation
+            tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
+            row1 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
+            row0 = SIMD.float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);
+            row1 = SIMD.float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);
+            tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
+            row3 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
+            row2 = SIMD.float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);
+            row3 = SIMD.float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);
+            // This is a true transposition, but it will lead to an incorrect result
+            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
+            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
+            //row0  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
+            //row1  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
+            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
+            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
+            //row2  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
+            //row3  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
+            // ----
+            tmp1 = SIMD.float32x4.mul(row2, row3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor0 = SIMD.float32x4.mul(row1, tmp1);
+            minor1 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(SIMD.float32x4.mul(row1, tmp1), minor0);
+            minor1 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor1);
+            minor1 = SIMD.float32x4.swizzle(minor1, 2, 3, 0, 1); // 0x4E = 01001110
+            // ----
+            tmp1 = SIMD.float32x4.mul(row1, row2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor0);
+            minor3 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row3, tmp1));
+            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor3);
+            minor3 = SIMD.float32x4.swizzle(minor3, 2, 3, 0, 1); // 0x4E = 01001110
+            // ----
+            tmp1 = SIMD.float32x4.mul(SIMD.float32x4.swizzle(row1, 2, 3, 0, 1), row3); // 0x4E = 01001110
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            row2 = SIMD.float32x4.swizzle(row2, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor0);
+            minor2 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row2, tmp1));
+            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor2);
+            minor2 = SIMD.float32x4.swizzle(minor2, 2, 3, 0, 1); // 0x4E = 01001110
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor2);
+            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row2, tmp1), minor3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row3, tmp1), minor2);
+            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row2, tmp1));
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row2, tmp1));
+            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor1);
+            minor2 = SIMD.float32x4.sub(minor2, SIMD.float32x4.mul(row1, tmp1));
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor1);
+            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row1, tmp1));
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row3, tmp1));
+            minor3 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor3);
+            // Compute determinant
+            det = SIMD.float32x4.mul(row0, minor0);
+            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 2, 3, 0, 1), det); // 0x4E = 01001110
+            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 1, 0, 3, 2), det); // 0xB1 = 10110001
+            tmp1 = SIMD.float32x4.reciprocal(det);
+            det = SIMD.float32x4.sub(SIMD.float32x4.add(tmp1, tmp1), SIMD.float32x4.mul(det, SIMD.float32x4.mul(tmp1, tmp1)));
+            det = SIMD.float32x4.swizzle(det, 0, 0, 0, 0);
+            // These shuffles aren't necessary if the faulty transposition is done
+            // up at the top of this function.
+            //minor0 = SIMD.float32x4.swizzle(minor0, 2, 1, 0, 3);
+            //minor1 = SIMD.float32x4.swizzle(minor1, 2, 1, 0, 3);
+            //minor2 = SIMD.float32x4.swizzle(minor2, 2, 1, 0, 3);
+            //minor3 = SIMD.float32x4.swizzle(minor3, 2, 1, 0, 3);
+            // Compute final values by multiplying with 1/det
+            minor0 = SIMD.float32x4.mul(det, minor0);
+            minor1 = SIMD.float32x4.mul(det, minor1);
+            minor2 = SIMD.float32x4.mul(det, minor2);
+            minor3 = SIMD.float32x4.mul(det, minor3);
+            SIMD.float32x4.store(dest, 0, minor0);
+            SIMD.float32x4.store(dest, 4, minor1);
+            SIMD.float32x4.store(dest, 8, minor2);
+            SIMD.float32x4.store(dest, 12, minor3);
+            return this;
+        };
         Matrix.prototype.setTranslation = function (vector3) {
             this.m[12] = vector3.x;
             this.m[13] = vector3.y;
@@ -1450,6 +1578,23 @@ var BABYLON;
             result[offset + 15] = tm12 * om3 + tm13 * om7 + tm14 * om11 + tm15 * om15;
             return this;
         };
+        Matrix.prototype.multiplyToArraySIMD = function (other, result, offset) {
+            if (offset === void 0) { offset = 0; }
+            var tm = this.m;
+            var om = other.m;
+            var om0 = SIMD.float32x4.load(om, 0);
+            var om1 = SIMD.float32x4.load(om, 4);
+            var om2 = SIMD.float32x4.load(om, 8);
+            var om3 = SIMD.float32x4.load(om, 12);
+            var tm0 = SIMD.float32x4.load(tm, 0);
+            SIMD.float32x4.store(result, offset + 0, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 0, 0, 0, 0), om0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 1, 1, 1, 1), om1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 2, 2, 2, 2), om2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 3, 3, 3, 3), om3)))));
+            var tm1 = SIMD.float32x4.load(tm, 4);
+            SIMD.float32x4.store(result, offset + 4, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 0, 0, 0, 0), om0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 1, 1, 1, 1), om1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 2, 2, 2, 2), om2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 3, 3, 3, 3), om3)))));
+            var tm2 = SIMD.float32x4.load(tm, 8);
+            SIMD.float32x4.store(result, offset + 8, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 0, 0, 0, 0), om0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 1, 1, 1, 1), om1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 2, 2, 2, 2), om2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 3, 3, 3, 3), om3)))));
+            var tm3 = SIMD.float32x4.load(tm, 12);
+            SIMD.float32x4.store(result, offset + 12, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 0, 0, 0, 0), om0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 1, 1, 1, 1), om1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 2, 2, 2, 2), om2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 3, 3, 3, 3), om3)))));
+        };
         Matrix.prototype.equals = function (value) {
             return value && (this.m[0] === value.m[0] && this.m[1] === value.m[1] && this.m[2] === value.m[2] && this.m[3] === value.m[3] && this.m[4] === value.m[4] && this.m[5] === value.m[5] && this.m[6] === value.m[6] && this.m[7] === value.m[7] && this.m[8] === value.m[8] && this.m[9] === value.m[9] && this.m[10] === value.m[10] && this.m[11] === value.m[11] && this.m[12] === value.m[12] && this.m[13] === value.m[13] && this.m[14] === value.m[14] && this.m[15] === value.m[15]);
         };
@@ -1708,6 +1853,66 @@ var BABYLON;
             var ez = -Vector3.Dot(this._zAxis, eye);
             return Matrix.FromValuesToRef(this._xAxis.x, this._yAxis.x, this._zAxis.x, 0, this._xAxis.y, this._yAxis.y, this._zAxis.y, 0, this._xAxis.z, this._yAxis.z, this._zAxis.z, 0, ex, ey, ez, 1, result);
         };
+        Matrix.LookAtLHToRefSIMD = function (eyeRef, targetRef, upRef, result) {
+            var out = result.m;
+            var center = SIMD.float32x4(targetRef.x, targetRef.y, targetRef.z, 0);
+            var eye = SIMD.float32x4(eyeRef.x, eyeRef.y, eyeRef.z, 0);
+            var up = SIMD.float32x4(upRef.x, upRef.y, upRef.z, 0);
+            // cc.kmVec3Subtract(f, pCenter, pEye);
+            var f = SIMD.float32x4.sub(center, eye);
+            // cc.kmVec3Normalize(f, f);    
+            var tmp = SIMD.float32x4.mul(f, f);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            f = SIMD.float32x4.mul(f, SIMD.float32x4.reciprocalSqrt(tmp));
+            // cc.kmVec3Assign(up, pUp);
+            // cc.kmVec3Normalize(up, up);
+            tmp = SIMD.float32x4.mul(up, up);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            up = SIMD.float32x4.mul(up, SIMD.float32x4.reciprocalSqrt(tmp));
+            // cc.kmVec3Cross(s, f, up);
+            var s = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 1, 2, 0, 3), SIMD.float32x4.swizzle(up, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 2, 0, 1, 3), SIMD.float32x4.swizzle(up, 1, 2, 0, 3)));
+            // cc.kmVec3Normalize(s, s);
+            tmp = SIMD.float32x4.mul(s, s);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrt(tmp));
+            // cc.kmVec3Cross(u, s, f);
+            var u = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 1, 2, 0, 3), SIMD.float32x4.swizzle(f, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 2, 0, 1, 3), SIMD.float32x4.swizzle(f, 1, 2, 0, 3)));
+            // cc.kmVec3Normalize(s, s);
+            tmp = SIMD.float32x4.mul(s, s);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrt(tmp));
+            //cc.kmMat4Identity(pOut);
+            //pOut.mat[0] = s.x;
+            //pOut.mat[4] = s.y;
+            //pOut.mat[8] = s.z;
+            //pOut.mat[1] = u.x;
+            //pOut.mat[5] = u.y;
+            //pOut.mat[9] = u.z;
+            //pOut.mat[2] = -f.x;
+            //pOut.mat[6] = -f.y;
+            //pOut.mat[10] = -f.z;
+            var zero = SIMD.float32x4.splat(0.0);
+            s = SIMD.float32x4.neg(s);
+            var tmp01 = SIMD.float32x4.shuffle(s, u, 0, 1, 4, 5);
+            var tmp23 = SIMD.float32x4.shuffle(f, zero, 0, 1, 4, 5);
+            var a0 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
+            var a1 = SIMD.float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);
+            tmp01 = SIMD.float32x4.shuffle(s, u, 2, 3, 6, 7);
+            tmp23 = SIMD.float32x4.shuffle(f, zero, 2, 3, 6, 7);
+            var a2 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
+            var a3 = SIMD.float32x4(0.0, 0.0, 0.0, 1.0);
+            // cc.kmMat4Translation(translate, -pEye.x, -pEye.y, -pEye.z);
+            var b0 = SIMD.float32x4(1.0, 0.0, 0.0, 0.0);
+            var b1 = SIMD.float32x4(0.0, 1.0, 0.0, 0.0);
+            var b2 = SIMD.float32x4(0.0, 0.0, 1.0, 0.0);
+            var b3 = SIMD.float32x4.neg(eye);
+            b3 = SIMD.float32x4.withW(b3, 1.0);
+            // cc.kmMat4Multiply(pOut, pOut, translate);
+            SIMD.float32x4.store(out, 0, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 4, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 8, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 12, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 3, 3, 3, 3), a3)))));
+        };
         Matrix.OrthoLH = function (width, height, znear, zfar) {
             var matrix = Matrix.Zero();
             Matrix.OrthoLHToRef(width, height, znear, zfar, matrix);
@@ -2323,7 +2528,7 @@ var BABYLON;
     BABYLON.PathCursor = PathCursor;
     var Path2 = (function () {
         function Path2(x, y) {
-            this._points = [];
+            this._points = new Array();
             this._length = 0;
             this.closed = false;
             this._points.push(new Vector2(x, y));
@@ -2409,11 +2614,11 @@ var BABYLON;
     var Path3D = (function () {
         function Path3D(path) {
             this.path = path;
-            this._curve = [];
-            this._distances = [];
-            this._tangents = [];
-            this._normals = [];
-            this._binormals = [];
+            this._curve = new Array();
+            this._distances = new Array();
+            this._tangents = new Array();
+            this._normals = new Array();
+            this._binormals = new Array();
             this._curve = path.slice(); // copy array         
             var l = this._curve.length;
             // first and last tangents
@@ -2490,5 +2695,88 @@ var BABYLON;
         return Path3D;
     })();
     BABYLON.Path3D = Path3D;
+    var Curve3 = (function () {
+        function Curve3(points) {
+            this._points = points;
+        }
+        // QuadraticBezier(origin_V3, control_V3, destination_V3 )
+        Curve3.CreateQuadraticBezier = function (v0, v1, v2, nbPoints) {
+            nbPoints = nbPoints > 2 ? nbPoints : 3;
+            var bez = new Array();
+            var step = 1 / nbPoints;
+            var equation = function (t, val0, val1, val2) {
+                var res = (1 - t) * (1 - t) * val0 + 2 * t * (1 - t) * val1 + t * t * val2;
+                return res;
+            };
+            for (var i = 0; i <= 1; i += step) {
+                bez.push(new Vector3(equation(i, v0.x, v1.x, v2.x), equation(i, v0.y, v1.y, v2.y), equation(i, v0.z, v1.z, v2.z)));
+            }
+            return new Curve3(bez);
+        };
+        // CubicBezier(origin_V3, control1_V3, control2_V3, destination_V3)
+        Curve3.CreateCubicBezier = function (v0, v1, v2, v3, nbPoints) {
+            nbPoints = nbPoints > 3 ? nbPoints : 4;
+            var bez = new Array();
+            var step = 1 / nbPoints;
+            var equation = function (t, val0, val1, val2, val3) {
+                var res = (1 - t) * (1 - t) * (1 - t) * val0 + 3 * t * (1 - t) * (1 - t) * val1 + 3 * t * t * (1 - t) * val2 + t * t * t * val3;
+                return res;
+            };
+            for (var i = 0; i <= 1; i += step) {
+                bez.push(new Vector3(equation(i, v0.x, v1.x, v2.x, v3.x), equation(i, v0.y, v1.y, v2.y, v3.y), equation(i, v0.z, v1.z, v2.z, v3.z)));
+            }
+            return new Curve3(bez);
+        };
+        Curve3.prototype.getPoints = function () {
+            return this._points;
+        };
+        Curve3.prototype.continue = function (curve) {
+            var lastPoint = this._points[this._points.length - 1];
+            var continuedPoints = this._points.slice();
+            var curvePoints = curve.getPoints();
+            for (var i = 1; i < curvePoints.length; i++) {
+                continuedPoints.push(curvePoints[i].add(lastPoint));
+            }
+            return new Curve3(continuedPoints);
+        };
+        return Curve3;
+    })();
+    BABYLON.Curve3 = Curve3;
+    // SIMD
+    if (window.SIMD !== undefined) {
+        // Replace functions
+        Matrix.prototype.multiplyToArray = Matrix.prototype.multiplyToArraySIMD;
+        Matrix.prototype.invertToRef = Matrix.prototype.invertToRefSIMD;
+        Matrix.LookAtLHToRef = Matrix.LookAtLHToRefSIMD;
+        Vector3.TransformCoordinatesToRef = Vector3.TransformCoordinatesToRefSIMD;
+        Vector3.TransformCoordinatesFromFloatsToRef = Vector3.TransformCoordinatesFromFloatsToRefSIMD;
+        Object.defineProperty(BABYLON.Vector3.prototype, "x", {
+            get: function () {
+                return this._data[0];
+            },
+            set: function (value) {
+                if (!this._data) {
+                    this._data = new Float32Array(3);
+                }
+                this._data[0] = value;
+            }
+        });
+        Object.defineProperty(BABYLON.Vector3.prototype, "y", {
+            get: function () {
+                return this._data[1];
+            },
+            set: function (value) {
+                this._data[1] = value;
+            }
+        });
+        Object.defineProperty(BABYLON.Vector3.prototype, "z", {
+            get: function () {
+                return this._data[2];
+            },
+            set: function (value) {
+                this._data[2] = value;
+            }
+        });
+    }
 })(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.math.js.map

+ 378 - 29
Babylon/Math/babylon.math.ts

@@ -1,4 +1,7 @@
 module BABYLON {
+
+    declare var SIMD;
+
     export class Color3 {
         constructor(public r: number = 0, public g: number = 0, public b: number = 0) {
         }
@@ -777,6 +780,30 @@
             result.z = rz / rw;
         }
 
+        public static TransformCoordinatesToRefSIMD(vector: Vector3, transformation: Matrix, result: Vector3): void {
+            var v = SIMD.float32x4.loadXYZ((<any>vector)._data, 0);
+            var m0 = SIMD.float32x4.load(transformation.m, 0);
+            var m1 = SIMD.float32x4.load(transformation.m, 4);
+            var m2 = SIMD.float32x4.load(transformation.m, 8);
+            var m3 = SIMD.float32x4.load(transformation.m, 12);
+            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 0, 0, 0, 0), m0), SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 1, 1, 1, 1), m1)), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 2, 2, 2, 2), m2), m3));
+            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
+            SIMD.float32x4.storeXYZ((<any>result)._data, 0, r);
+        }
+
+        public static TransformCoordinatesFromFloatsToRefSIMD(x: number, y: number, z: number, transformation: Matrix, result: Vector3): void {
+            var v0 = SIMD.float32x4.splat(x);
+            var v1 = SIMD.float32x4.splat(y);
+            var v2 = SIMD.float32x4.splat(z);
+            var m0 = SIMD.float32x4.load(transformation.m, 0);
+            var m1 = SIMD.float32x4.load(transformation.m, 4);
+            var m2 = SIMD.float32x4.load(transformation.m, 8);
+            var m3 = SIMD.float32x4.load(transformation.m, 12);
+            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(v0, m0), SIMD.float32x4.mul(v1, m1)), SIMD.float32x4.add(SIMD.float32x4.mul(v2, m2), m3));
+            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
+            SIMD.float32x4.storeXYZ((<any>result)._data, 0, r);
+        }
+
         public static TransformNormal(vector: Vector3, transformation: Matrix): Vector3 {
             var result = Vector3.Zero();
 
@@ -1580,7 +1607,7 @@
                 num2 = flag ? ((-Math.sin(num * num5)) * num6) : ((Math.sin(num * num5)) * num6);
             }
 
-            return new Quaternion((num3 * left.x) + (num2 * right.x), (num3 * left.y) + (num2 * right.y), (num3 * left.z) + (num2 * right.z), (num3 * left.w) + (num2 * right.w));
+            return new Quaternion((num3 * left.x) + (num2 * right.x),(num3 * left.y) + (num2 * right.y),(num3 * left.z) + (num2 * right.z),(num3 * left.w) + (num2 * right.w));
         }
     }
 
@@ -1695,6 +1722,131 @@
             return this;
         }
 
+        public invertToRefSIMD(other: Matrix): Matrix {
+            var src = this.m;
+            var dest = other.m;
+            var row0, row1, row2, row3;
+            var tmp1;
+            var minor0, minor1, minor2, minor3;
+            var det;
+
+            // Load the 4 rows
+            var src0 = SIMD.float32x4.load(src, 0);
+            var src1 = SIMD.float32x4.load(src, 4);
+            var src2 = SIMD.float32x4.load(src, 8);
+            var src3 = SIMD.float32x4.load(src, 12);
+
+            // Transpose the source matrix.  Sort of.  Not a true transpose operation
+
+            tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
+            row1 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
+            row0 = SIMD.float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);
+            row1 = SIMD.float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);
+
+            tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
+            row3 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
+            row2 = SIMD.float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);
+            row3 = SIMD.float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);
+
+            // This is a true transposition, but it will lead to an incorrect result
+
+            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
+            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
+            //row0  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
+            //row1  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
+
+            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
+            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
+            //row2  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
+            //row3  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row2, row3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor0 = SIMD.float32x4.mul(row1, tmp1);
+            minor1 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(SIMD.float32x4.mul(row1, tmp1), minor0);
+            minor1 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor1);
+            minor1 = SIMD.float32x4.swizzle(minor1, 2, 3, 0, 1); // 0x4E = 01001110
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row1, row2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor0);
+            minor3 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row3, tmp1));
+            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor3);
+            minor3 = SIMD.float32x4.swizzle(minor3, 2, 3, 0, 1); // 0x4E = 01001110
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(SIMD.float32x4.swizzle(row1, 2, 3, 0, 1), row3); // 0x4E = 01001110
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            row2 = SIMD.float32x4.swizzle(row2, 2, 3, 0, 1);  // 0x4E = 01001110
+            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor0);
+            minor2 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row2, tmp1));
+            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor2);
+            minor2 = SIMD.float32x4.swizzle(minor2, 2, 3, 0, 1); // 0x4E = 01001110
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor2);
+            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row2, tmp1), minor3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row3, tmp1), minor2);
+            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row2, tmp1));
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row2, tmp1));
+            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor1);
+            minor2 = SIMD.float32x4.sub(minor2, SIMD.float32x4.mul(row1, tmp1));
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor1);
+            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row1, tmp1));
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row3, tmp1));
+            minor3 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor3);
+
+            // Compute determinant
+            det = SIMD.float32x4.mul(row0, minor0);
+            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 2, 3, 0, 1), det); // 0x4E = 01001110
+            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 1, 0, 3, 2), det); // 0xB1 = 10110001
+            tmp1 = SIMD.float32x4.reciprocal(det);
+            det = SIMD.float32x4.sub(SIMD.float32x4.add(tmp1, tmp1), SIMD.float32x4.mul(det, SIMD.float32x4.mul(tmp1, tmp1)));
+            det = SIMD.float32x4.swizzle(det, 0, 0, 0, 0);
+
+            // These shuffles aren't necessary if the faulty transposition is done
+            // up at the top of this function.
+            //minor0 = SIMD.float32x4.swizzle(minor0, 2, 1, 0, 3);
+            //minor1 = SIMD.float32x4.swizzle(minor1, 2, 1, 0, 3);
+            //minor2 = SIMD.float32x4.swizzle(minor2, 2, 1, 0, 3);
+            //minor3 = SIMD.float32x4.swizzle(minor3, 2, 1, 0, 3);
+
+            // Compute final values by multiplying with 1/det
+            minor0 = SIMD.float32x4.mul(det, minor0);
+            minor1 = SIMD.float32x4.mul(det, minor1);
+            minor2 = SIMD.float32x4.mul(det, minor2);
+            minor3 = SIMD.float32x4.mul(det, minor3);
+
+            SIMD.float32x4.store(dest, 0, minor0);
+            SIMD.float32x4.store(dest, 4, minor1);
+            SIMD.float32x4.store(dest, 8, minor2);
+            SIMD.float32x4.store(dest, 12, minor3);
+
+            return this;
+        }
+
         public setTranslation(vector3: Vector3): Matrix {
             this.m[12] = vector3.x;
             this.m[13] = vector3.y;
@@ -1734,7 +1886,6 @@
         }
 
         public multiplyToArray(other: Matrix, result: Float32Array, offset: number): Matrix {
-
             var tm0 = this.m[0];
             var tm1 = this.m[1];
             var tm2 = this.m[2];
@@ -1792,12 +1943,57 @@
             return this;
         }
 
+        public multiplyToArraySIMD(other: Matrix, result: Matrix, offset = 0): void {
+            var tm = this.m;
+            var om = other.m;
+            var om0 = SIMD.float32x4.load(om, 0);
+            var om1 = SIMD.float32x4.load(om, 4);
+            var om2 = SIMD.float32x4.load(om, 8);
+            var om3 = SIMD.float32x4.load(om, 12);
+
+            var tm0 = SIMD.float32x4.load(tm, 0);
+            SIMD.float32x4.store(result, offset + 0, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 3, 3, 3, 3), om3)))));
+
+            var tm1 = SIMD.float32x4.load(tm, 4);
+            SIMD.float32x4.store(result, offset + 4, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 3, 3, 3, 3), om3)))));
+
+            var tm2 = SIMD.float32x4.load(tm, 8);
+            SIMD.float32x4.store(result, offset + 8, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 3, 3, 3, 3), om3)))));
+
+            var tm3 = SIMD.float32x4.load(tm, 12);
+            SIMD.float32x4.store(result, offset + 12, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 3, 3, 3, 3), om3)))));
+        }
+
         public equals(value: Matrix): boolean {
             return value &&
                 (this.m[0] === value.m[0] && this.m[1] === value.m[1] && this.m[2] === value.m[2] && this.m[3] === value.m[3] &&
-                this.m[4] === value.m[4] && this.m[5] === value.m[5] && this.m[6] === value.m[6] && this.m[7] === value.m[7] &&
-                this.m[8] === value.m[8] && this.m[9] === value.m[9] && this.m[10] === value.m[10] && this.m[11] === value.m[11] &&
-                this.m[12] === value.m[12] && this.m[13] === value.m[13] && this.m[14] === value.m[14] && this.m[15] === value.m[15]);
+                    this.m[4] === value.m[4] && this.m[5] === value.m[5] && this.m[6] === value.m[6] && this.m[7] === value.m[7] &&
+                    this.m[8] === value.m[8] && this.m[9] === value.m[9] && this.m[10] === value.m[10] && this.m[11] === value.m[11] &&
+                    this.m[12] === value.m[12] && this.m[13] === value.m[13] && this.m[14] === value.m[14] && this.m[15] === value.m[15]);
         }
 
         public clone(): Matrix {
@@ -2165,6 +2361,72 @@
                 ex, ey, ez, 1, result);
         }
 
+        public static LookAtLHToRefSIMD(eyeRef: Vector3, targetRef: Vector3, upRef: Vector3, result: Matrix): void {
+            var out = result.m;
+            var center = SIMD.float32x4(targetRef.x, targetRef.y, targetRef.z, 0);
+            var eye = SIMD.float32x4(eyeRef.x, eyeRef.y, eyeRef.z, 0);
+            var up = SIMD.float32x4(upRef.x, upRef.y, upRef.z, 0);
+
+            // cc.kmVec3Subtract(f, pCenter, pEye);
+            var f = SIMD.float32x4.sub(center, eye);
+            // cc.kmVec3Normalize(f, f);    
+            var tmp = SIMD.float32x4.mul(f, f);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            f = SIMD.float32x4.mul(f, SIMD.float32x4.reciprocalSqrt(tmp));
+
+            // cc.kmVec3Assign(up, pUp);
+            // cc.kmVec3Normalize(up, up);
+            tmp = SIMD.float32x4.mul(up, up);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            up = SIMD.float32x4.mul(up, SIMD.float32x4.reciprocalSqrt(tmp));
+            // cc.kmVec3Cross(s, f, up);
+            var s = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 1, 2, 0, 3), SIMD.float32x4.swizzle(up, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 2, 0, 1, 3), SIMD.float32x4.swizzle(up, 1, 2, 0, 3)));
+            // cc.kmVec3Normalize(s, s);
+            tmp = SIMD.float32x4.mul(s, s);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrt(tmp));
+            // cc.kmVec3Cross(u, s, f);
+            var u = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 1, 2, 0, 3), SIMD.float32x4.swizzle(f, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 2, 0, 1, 3), SIMD.float32x4.swizzle(f, 1, 2, 0, 3)));
+            // cc.kmVec3Normalize(s, s);
+            tmp = SIMD.float32x4.mul(s, s);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrt(tmp));
+
+            //cc.kmMat4Identity(pOut);
+            //pOut.mat[0] = s.x;
+            //pOut.mat[4] = s.y;
+            //pOut.mat[8] = s.z;
+            //pOut.mat[1] = u.x;
+            //pOut.mat[5] = u.y;
+            //pOut.mat[9] = u.z;
+            //pOut.mat[2] = -f.x;
+            //pOut.mat[6] = -f.y;
+            //pOut.mat[10] = -f.z;
+
+            var zero = SIMD.float32x4.splat(0.0);
+            s = SIMD.float32x4.neg(s);
+            var tmp01 = SIMD.float32x4.shuffle(s, u, 0, 1, 4, 5);
+            var tmp23 = SIMD.float32x4.shuffle(f, zero, 0, 1, 4, 5);
+            var a0 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
+            var a1 = SIMD.float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);
+            tmp01 = SIMD.float32x4.shuffle(s, u, 2, 3, 6, 7);
+            tmp23 = SIMD.float32x4.shuffle(f, zero, 2, 3, 6, 7);
+            var a2 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
+            var a3 = SIMD.float32x4(0.0, 0.0, 0.0, 1.0);
+            // cc.kmMat4Translation(translate, -pEye.x, -pEye.y, -pEye.z);
+            var b0 = SIMD.float32x4(1.0, 0.0, 0.0, 0.0);
+            var b1 = SIMD.float32x4(0.0, 1.0, 0.0, 0.0);
+            var b2 = SIMD.float32x4(0.0, 0.0, 1.0, 0.0);
+            var b3 = SIMD.float32x4.neg(eye);
+            b3 = SIMD.float32x4.withW(b3, 1.0);
+            // cc.kmMat4Multiply(pOut, pOut, translate);
+            SIMD.float32x4.store(out, 0, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 4, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 8, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 12, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 3, 3, 3, 3), a3)))));
+        }
+
+
         public static OrthoLH(width: number, height: number, znear: number, zfar: number): Matrix {
             var matrix = Matrix.Zero();
 
@@ -2911,9 +3173,10 @@
     }
 
     export class Path2 {
-        private _points: Vector2[] = [];
-        private _length: number = 0;
-        closed: boolean = false;
+        private _points = new Array<Vector2>();
+        private _length = 0;
+
+        public closed = false;
 
         constructor(x: number, y: number) {
             this._points.push(new Vector2(x, y));
@@ -3015,25 +3278,25 @@
     }
 
     export class Path3D {
-        private _curve: Vector3[] = [];
-        private _distances: number[] = [];
-        private _tangents: Vector3[] = [];
-        private _normals: Vector3[] = [];
-        private _binormals: Vector3[] = [];
+        private _curve = new Array<Vector3>();
+        private _distances = new Array<number>();
+        private _tangents = new Array<Vector3>();
+        private _normals = new Array<Vector3>();
+        private _binormals = new Array<Vector3>();
 
         constructor(public path: Vector3[]) {
             this._curve = path.slice();   // copy array         
-            var l: number = this._curve.length;
+            var l = this._curve.length;
 
             // first and last tangents
             this._tangents[0] = this._curve[1].subtract(this._curve[0]);
             this._tangents[0].normalize();
-            this._tangents[l-1] = this._curve[l-1].subtract(this._curve[l-2]);
+            this._tangents[l - 1] = this._curve[l - 1].subtract(this._curve[l - 2]);
             this._tangents[l - 1].normalize();
             
             // normals and binormals at first point : arbitrary vector with _normalVector()
-            var tg0: Vector3 = this._tangents[0];
-            var pp0: Vector3 = this._normalVector(this._curve[0], tg0);
+            var tg0 = this._tangents[0];
+            var pp0 = this._normalVector(this._curve[0], tg0);
             this._normals[0] = pp0;
             this._normals[0].normalize();
             this._binormals[0] = Vector3.Cross(tg0, this._normals[0]);
@@ -3047,21 +3310,21 @@
             var prevNorm: Vector3;    // previous normal
             var prevBinor: Vector3;   // previous binormal
 
-            for(var i: number = 1; i < l; i++) {
+            for (var i = 1; i < l; i++) {
                 // tangents
-                prev = this._curve[i].subtract(this._curve[i-1]);
-                if (i < l-1) {
-                    cur = this._curve[i+1].subtract(this._curve[i]);
+                prev = this._curve[i].subtract(this._curve[i - 1]);
+                if (i < l - 1) {
+                    cur = this._curve[i + 1].subtract(this._curve[i]);
                     this._tangents[i] = prev.add(cur);
-                    this._tangents[i].normalize();               
+                    this._tangents[i].normalize();
                 }
                 this._distances[i] = this._distances[i - 1] + prev.length();   
                       
                 // normals and binormals
                 // http://www.cs.cmu.edu/afs/andrew/scs/cs/15-462/web/old/asst2camera.html
                 curTang = this._tangents[i];
-                prevNorm = this._normals[i-1];
-                prevBinor = this._binormals[i-1];
+                prevNorm = this._normals[i - 1];
+                prevBinor = this._binormals[i - 1];
                 this._normals[i] = Vector3.Cross(prevBinor, curTang);
                 this._normals[i].normalize();
                 this._binormals[i] = Vector3.Cross(curTang, this._normals[i]);
@@ -3092,20 +3355,106 @@
         // private function normalVector(v0, vt) :
         // returns an arbitrary point in the plane defined by the point v0 and the vector vt orthogonal to this plane
         private _normalVector(v0: Vector3, vt: Vector3): Vector3 {
-            var point: Vector3; 
+            var point: Vector3;
 
             if (vt.x !== 1) {     // search for a point in the plane
-                point = new Vector3(1, 0, 0);   
+                point = new Vector3(1, 0, 0);
             }
             else if (vt.y !== 1) {
-                point = new Vector3(0, 1, 0);  
+                point = new Vector3(0, 1, 0);
             }
             else if (vt.z !== 1) {
-                point = new Vector3(0, 0, 1);  
+                point = new Vector3(0, 0, 1);
             }
             var normal0: Vector3 = Vector3.Cross(vt, point);
             normal0.normalize();
-            return normal0;        
+            return normal0;
+        }
+    }
+
+    export class Curve3 {
+        private _points: Vector3[];
+
+        // QuadraticBezier(origin_V3, control_V3, destination_V3 )
+        public static CreateQuadraticBezier(v0: Vector3, v1: Vector3, v2: Vector3, nbPoints: number): Curve3 {
+            nbPoints = nbPoints > 2 ? nbPoints : 3;
+            var bez = new Array<Vector3>();
+            var step = 1 / nbPoints;
+            var equation = (t: number, val0: number, val1: number, val2: number) => {
+                var res = (1 - t) * (1 - t) * val0 + 2 * t * (1 - t) * val1 + t * t * val2;
+                return res;
+            }
+            for (var i = 0; i <= 1; i += step) {
+                bez.push(new Vector3(equation(i, v0.x, v1.x, v2.x), equation(i, v0.y, v1.y, v2.y), equation(i, v0.z, v1.z, v2.z)));
+            }
+            return new Curve3(bez);
+        }
+
+        // CubicBezier(origin_V3, control1_V3, control2_V3, destination_V3)
+        public static CreateCubicBezier(v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3, nbPoints: number): Curve3 {
+            nbPoints = nbPoints > 3 ? nbPoints : 4;
+            var bez = new Array<Vector3>();
+            var step = 1 / nbPoints;
+            var equation = (t: number, val0: number, val1: number, val2: number, val3: number) => {
+                var res = (1 - t) * (1 - t) * (1 - t) * val0 + 3 * t * (1 - t) * (1 - t) * val1 + 3 * t * t * (1 - t) * val2 + t * t * t * val3;
+                return res;
+            }
+            for (var i = 0; i <= 1; i += step) {
+                bez.push(new Vector3(equation(i, v0.x, v1.x, v2.x, v3.x), equation(i, v0.y, v1.y, v2.y, v3.y), equation(i, v0.z, v1.z, v2.z, v3.z)));
+            }
+            return new Curve3(bez);
         }
+
+        constructor(points: Vector3[]) {
+            this._points = points;
+        }
+
+        public getPoints() {
+            return this._points;
+        }
+
+        public continue(curve: Curve3): Curve3 {
+            var lastPoint = this._points[this._points.length - 1];
+            var continuedPoints = this._points.slice();
+            var curvePoints = curve.getPoints();
+            for (var i = 1; i < curvePoints.length; i++) {
+                continuedPoints.push(curvePoints[i].add(lastPoint));
+            }
+            return new Curve3(continuedPoints);
+        }
+    }
+
+    // SIMD
+    if (window.SIMD !== undefined) {
+        // Replace functions
+        Matrix.prototype.multiplyToArray = <any>Matrix.prototype.multiplyToArraySIMD;
+        Matrix.prototype.invertToRef = <any>Matrix.prototype.invertToRefSIMD;
+        Matrix.LookAtLHToRef = <any>Matrix.LookAtLHToRefSIMD;
+        Vector3.TransformCoordinatesToRef = <any>Vector3.TransformCoordinatesToRefSIMD;
+        Vector3.TransformCoordinatesFromFloatsToRef = <any>Vector3.TransformCoordinatesFromFloatsToRefSIMD;
+
+        Object.defineProperty(BABYLON.Vector3.prototype, "x", {
+            get: function () { return this._data[0]; },
+            set: function (value: number) {
+                if (!this._data) {
+                    this._data = new Float32Array(3);
+                }
+                this._data[0] = value;
+            }
+        });
+
+        Object.defineProperty(BABYLON.Vector3.prototype, "y", {
+            get: function () { return this._data[1]; },
+            set: function (value: number) {
+                this._data[1] = value;
+            }
+        });
+
+        Object.defineProperty(BABYLON.Vector3.prototype, "z", {
+            get: function () { return this._data[2]; },
+            set: function (value: number) {
+                this._data[2] = value;
+            }
+        });
     }
 }

+ 15 - 18
Babylon/Mesh/babylon.abstractMesh.js

@@ -40,7 +40,7 @@ var BABYLON;
             this.useOctreeForRenderingSelection = true;
             this.useOctreeForPicking = true;
             this.useOctreeForCollisions = true;
-            this.layerMask = 0xFFFFFFFF;
+            this.layerMask = 0x0FFFFFFF;
             // Physics
             this._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
             // Collisions
@@ -69,7 +69,7 @@ var BABYLON;
             this._renderId = 0;
             this._intersectionsInProgress = new Array();
             this._onAfterWorldMatrixUpdate = new Array();
-            scene.meshes.push(this);
+            scene.addMesh(this);
         }
         Object.defineProperty(AbstractMesh, "BILLBOARDMODE_NONE", {
             get: function () {
@@ -178,7 +178,7 @@ var BABYLON;
                 this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
                 this.rotation = BABYLON.Vector3.Zero();
             }
-            if (!space || space == 0 /* LOCAL */) {
+            if (!space || space === 0 /* LOCAL */) {
                 var rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
                 this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
             }
@@ -194,7 +194,7 @@ var BABYLON;
         };
         AbstractMesh.prototype.translate = function (axis, distance, space) {
             var displacementVector = axis.scale(distance);
-            if (!space || space == 0 /* LOCAL */) {
+            if (!space || space === 0 /* LOCAL */) {
                 var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
                 this.setPositionWithLocalVector(tempV3);
             }
@@ -352,7 +352,7 @@ var BABYLON;
             }
         };
         AbstractMesh.prototype.computeWorldMatrix = function (force) {
-            if (!force && (this._currentRenderId == this.getScene().getRenderId() || this.isSynchronized(true))) {
+            if (!force && (this._currentRenderId === this.getScene().getRenderId() || this.isSynchronized(true))) {
                 return this._worldMatrix;
             }
             this._cache.position.copyFrom(this.position);
@@ -396,11 +396,11 @@ var BABYLON;
                     zero = this.getScene().activeCamera.position;
                 }
                 else {
-                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_X)
+                    if (this.billboardMode & AbstractMesh.BILLBOARDMODE_X)
                         zero.x = localPosition.x + BABYLON.Engine.Epsilon;
-                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Y)
+                    if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Y)
                         zero.y = localPosition.y + 0.001;
-                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Z)
+                    if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Z)
                         zero.z = localPosition.z + 0.001;
                 }
                 BABYLON.Matrix.LookAtLHToRef(localPosition, zero, BABYLON.Vector3.Up(), this._localBillboard);
@@ -412,7 +412,7 @@ var BABYLON;
             // Local world
             this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
             // Parent
-            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === BABYLON.AbstractMesh.BILLBOARDMODE_NONE) {
+            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === AbstractMesh.BILLBOARDMODE_NONE) {
                 this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
             }
             else {
@@ -456,7 +456,7 @@ var BABYLON;
         };
         AbstractMesh.prototype.lookAt = function (targetPoint, yawCor, pitchCor, rollCor) {
             /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
-            /// <param name="targetPoint" type="BABYLON.Vector3">The position (must be in same space as current mesh) to look at</param>
+            /// <param name="targetPoint" type="Vector3">The position (must be in same space as current mesh) to look at</param>
             /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
             /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
             /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
@@ -739,8 +739,9 @@ var BABYLON;
             }
         };
         AbstractMesh.prototype.dispose = function (doNotRecurse) {
+            var index;
             // Physics
-            if (this.getPhysicsImpostor() != BABYLON.PhysicsEngine.NoImpostor) {
+            if (this.getPhysicsImpostor() !== BABYLON.PhysicsEngine.NoImpostor) {
                 this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
             }
             for (index = 0; index < this._intersectionsInProgress.length; index++) {
@@ -752,14 +753,10 @@ var BABYLON;
             // SubMeshes
             this.releaseSubMeshes();
             // Remove from scene
-            var index = this.getScene().meshes.indexOf(this);
-            if (index != -1) {
-                // Remove from the scene if mesh found 
-                this.getScene().meshes.splice(index, 1);
-            }
+            this.getScene().removeMesh(this);
             if (!doNotRecurse) {
                 for (index = 0; index < this.getScene().particleSystems.length; index++) {
-                    if (this.getScene().particleSystems[index].emitter == this) {
+                    if (this.getScene().particleSystems[index].emitter === this) {
                         this.getScene().particleSystems[index].dispose();
                         index--;
                     }
@@ -767,7 +764,7 @@ var BABYLON;
                 // Children
                 var objects = this.getScene().meshes.slice(0);
                 for (index = 0; index < objects.length; index++) {
-                    if (objects[index].parent == this) {
+                    if (objects[index].parent === this) {
                         objects[index].dispose();
                     }
                 }

+ 77 - 79
Babylon/Mesh/babylon.abstractMesh.ts

@@ -50,10 +50,10 @@
         public receiveShadows = false;
         public actionManager: ActionManager;
         public renderOutline = false;
-        public outlineColor = BABYLON.Color3.Red();
+        public outlineColor = Color3.Red();
         public outlineWidth = 0.02;
         public renderOverlay = false;
-        public overlayColor = BABYLON.Color3.Red();
+        public overlayColor = Color3.Red();
         public overlayAlpha = 0.5;
         public hasVertexAlpha = false;
         public useVertexColors = true;
@@ -63,7 +63,7 @@
         public useOctreeForPicking = true;
         public useOctreeForCollisions = true;
 
-        public layerMask: number = 0xFFFFFFFF;
+        public layerMask: number = 0x0FFFFFFF;
 
         // Physics
         public _physicImpostor = PhysicsEngine.NoImpostor;
@@ -72,32 +72,32 @@
         public _physicRestitution: number;
 
         // Collisions
-        public ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
-        public ellipsoidOffset = new BABYLON.Vector3(0, 0, 0);
+        public ellipsoid = new Vector3(0.5, 1, 0.5);
+        public ellipsoidOffset = new Vector3(0, 0, 0);
         private _collider = new Collider();
-        private _oldPositionForCollisions = new BABYLON.Vector3(0, 0, 0);
-        private _diffPositionForCollisions = new BABYLON.Vector3(0, 0, 0);
-        private _newPositionForCollisions = new BABYLON.Vector3(0, 0, 0);
+        private _oldPositionForCollisions = new Vector3(0, 0, 0);
+        private _diffPositionForCollisions = new Vector3(0, 0, 0);
+        private _newPositionForCollisions = new Vector3(0, 0, 0);
 
         // Cache
-        private _localScaling = BABYLON.Matrix.Zero();
-        private _localRotation = BABYLON.Matrix.Zero();
-        private _localTranslation = BABYLON.Matrix.Zero();
-        private _localBillboard = BABYLON.Matrix.Zero();
-        private _localPivotScaling = BABYLON.Matrix.Zero();
-        private _localPivotScalingRotation = BABYLON.Matrix.Zero();
-        private _localWorld = BABYLON.Matrix.Zero();
-        public _worldMatrix = BABYLON.Matrix.Zero();
-        private _rotateYByPI = BABYLON.Matrix.RotationY(Math.PI);
-        private _absolutePosition = BABYLON.Vector3.Zero();
-        private _collisionsTransformMatrix = BABYLON.Matrix.Zero();
-        private _collisionsScalingMatrix = BABYLON.Matrix.Zero();
+        private _localScaling = Matrix.Zero();
+        private _localRotation = Matrix.Zero();
+        private _localTranslation = Matrix.Zero();
+        private _localBillboard = Matrix.Zero();
+        private _localPivotScaling = Matrix.Zero();
+        private _localPivotScalingRotation = Matrix.Zero();
+        private _localWorld = Matrix.Zero();
+        public _worldMatrix = Matrix.Zero();
+        private _rotateYByPI = Matrix.RotationY(Math.PI);
+        private _absolutePosition = Vector3.Zero();
+        private _collisionsTransformMatrix = Matrix.Zero();
+        private _collisionsScalingMatrix = Matrix.Zero();
         public _positions: Vector3[];
         private _isDirty = false;
         public _masterMesh: AbstractMesh;
 
         public _boundingInfo: BoundingInfo;
-        private _pivotMatrix = BABYLON.Matrix.Identity();
+        private _pivotMatrix = Matrix.Identity();
         public _isDisposed = false;
         public _renderId = 0;
 
@@ -105,7 +105,7 @@
         public _submeshesOctree: Octree<SubMesh>;
         public _intersectionsInProgress = new Array<AbstractMesh>();
 
-        private _onAfterWorldMatrixUpdate = new Array<(mesh: BABYLON.AbstractMesh) => void>();
+        private _onAfterWorldMatrixUpdate = new Array<(mesh: AbstractMesh) => void>();
 
         // Loading properties
         public _waitingActions: any;
@@ -113,7 +113,7 @@
         constructor(name: string, scene: Scene) {
             super(name, scene);
 
-            scene.meshes.push(this);
+            scene.addMesh(this);
         }
 
         // Methods
@@ -184,12 +184,12 @@
 
         public rotate(axis: Vector3, amount: number, space: Space): void {
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
+                this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
+                this.rotation = Vector3.Zero();
             }
 
-            if (!space || space == BABYLON.Space.LOCAL) {
-                var rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
+            if (!space || space === Space.LOCAL) {
+                var rotationQuaternion = Quaternion.RotationAxis(axis, amount);
                 this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
             }
             else {
@@ -197,9 +197,9 @@
                     var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
                     invertParentWorldMatrix.invert();
 
-                    axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
+                    axis = Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
-                rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
+                rotationQuaternion = Quaternion.RotationAxis(axis, amount);
                 this.rotationQuaternion = rotationQuaternion.multiply(this.rotationQuaternion);
             }
         }
@@ -207,7 +207,7 @@
         public translate(axis: Vector3, distance: number, space: Space): void {
             var displacementVector = axis.scale(distance);
 
-            if (!space || space == BABYLON.Space.LOCAL) {
+            if (!space || space === Space.LOCAL) {
                 var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
                 this.setPositionWithLocalVector(tempV3);
             }
@@ -248,9 +248,9 @@
                 var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
                 invertParentWorldMatrix.invert();
 
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
+                var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
 
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
             } else {
                 this.position.x = absolutePositionX;
                 this.position.y = absolutePositionY;
@@ -278,14 +278,14 @@
          * @param {number} amountUp
          * @param {number} amountForward
          */
-        public calcMovePOV(amountRight : number, amountUp : number, amountForward : number) : BABYLON.Vector3 {
-            var rotMatrix = new BABYLON.Matrix();
-            var rotQuaternion = (this.rotationQuaternion) ? this.rotationQuaternion : BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
+        public calcMovePOV(amountRight : number, amountUp : number, amountForward : number) : Vector3 {
+            var rotMatrix = new Matrix();
+            var rotQuaternion = (this.rotationQuaternion) ? this.rotationQuaternion : Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
             rotQuaternion.toRotationMatrix(rotMatrix);
             
-            var translationDelta = BABYLON.Vector3.Zero();
+            var translationDelta = Vector3.Zero();
             var defForwardMult = this.definedFacingForward ? -1 : 1;
-            BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(amountRight * defForwardMult, amountUp, amountForward * defForwardMult, rotMatrix, translationDelta);
+            Vector3.TransformCoordinatesFromFloatsToRef(amountRight * defForwardMult, amountUp, amountForward * defForwardMult, rotMatrix, translationDelta);
             return translationDelta;
         }
         // ================================== Point of View Rotation =================================
@@ -307,9 +307,9 @@
          * @param {number} twirlClockwise
          * @param {number} tiltRight
          */
-        public calcRotatePOV(flipBack : number, twirlClockwise : number, tiltRight : number) : BABYLON.Vector3 {
+        public calcRotatePOV(flipBack : number, twirlClockwise : number, tiltRight : number) : Vector3 {
             var defForwardMult = this.definedFacingForward ? 1 : -1;
-            return new BABYLON.Vector3(flipBack * defForwardMult, twirlClockwise, tiltRight * defForwardMult);
+            return new Vector3(flipBack * defForwardMult, twirlClockwise, tiltRight * defForwardMult);
         }
         
         public setPivotMatrix(matrix: Matrix): void {
@@ -358,10 +358,10 @@
             super._initCache();
 
             this._cache.localMatrixUpdated = false;
-            this._cache.position = BABYLON.Vector3.Zero();
-            this._cache.scaling = BABYLON.Vector3.Zero();
-            this._cache.rotation = BABYLON.Vector3.Zero();
-            this._cache.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 0);
+            this._cache.position = Vector3.Zero();
+            this._cache.scaling = Vector3.Zero();
+            this._cache.rotation = Vector3.Zero();
+            this._cache.rotationQuaternion = new Quaternion(0, 0, 0, 0);
         }
 
         public markAsDirty(property: string): void {
@@ -373,7 +373,7 @@
         }
 
         public _updateBoundingInfo(): void {
-            this._boundingInfo = this._boundingInfo || new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition);
+            this._boundingInfo = this._boundingInfo || new BoundingInfo(this.absolutePosition, this.absolutePosition);
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
@@ -393,7 +393,7 @@
         }
 
         public computeWorldMatrix(force?: boolean): Matrix {
-            if (!force && (this._currentRenderId == this.getScene().getRenderId() || this.isSynchronized(true))) {
+            if (!force && (this._currentRenderId === this.getScene().getRenderId() || this.isSynchronized(true))) {
                 return this._worldMatrix;
             }
 
@@ -404,14 +404,14 @@
             this._isDirty = false;
 
             // Scaling
-            BABYLON.Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
+            Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
 
             // Rotation
             if (this.rotationQuaternion) {
                 this.rotationQuaternion.toRotationMatrix(this._localRotation);
                 this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
             } else {
-                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
+                Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
                 this._cache.rotation.copyFrom(this.rotation);
             }
 
@@ -420,12 +420,12 @@
                 var camera = this.getScene().activeCamera;
                 var cameraWorldMatrix = camera.getWorldMatrix();
 
-                var cameraGlobalPosition = new BABYLON.Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
+                var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
 
-                BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
+                Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
                     this.position.z + cameraGlobalPosition.z, this._localTranslation);
             } else {
-                BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
+                Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
             }
 
             // Composing transformations
@@ -439,21 +439,21 @@
 
                 if (this.parent && (<any>this.parent).position) {
                     localPosition.addInPlace((<any>this.parent).position);
-                    BABYLON.Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, this._localTranslation);
+                    Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, this._localTranslation);
                 }
 
                 if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) === AbstractMesh.BILLBOARDMODE_ALL) {
                     zero = this.getScene().activeCamera.position;
                 } else {
-                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_X)
-                        zero.x = localPosition.x + BABYLON.Engine.Epsilon;
-                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Y)
+                    if (this.billboardMode & AbstractMesh.BILLBOARDMODE_X)
+                        zero.x = localPosition.x + Engine.Epsilon;
+                    if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Y)
                         zero.y = localPosition.y + 0.001;
-                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Z)
+                    if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Z)
                         zero.z = localPosition.z + 0.001;
                 }
 
-                BABYLON.Matrix.LookAtLHToRef(localPosition, zero, BABYLON.Vector3.Up(), this._localBillboard);
+                Matrix.LookAtLHToRef(localPosition, zero, Vector3.Up(), this._localBillboard);
                 this._localBillboard.m[12] = this._localBillboard.m[13] = this._localBillboard.m[14] = 0;
 
                 this._localBillboard.invert();
@@ -466,7 +466,7 @@
             this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
 
             // Parent
-            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === BABYLON.AbstractMesh.BILLBOARDMODE_NONE) {
+            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === AbstractMesh.BILLBOARDMODE_NONE) {
                 this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
             } else {
                 this._worldMatrix.copyFrom(this._localWorld);
@@ -490,11 +490,11 @@
         * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
         * @param func: callback function to add
         */
-        public registerAfterWorldMatrixUpdate(func: (mesh: BABYLON.AbstractMesh) => void): void {
+        public registerAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void {
             this._onAfterWorldMatrixUpdate.push(func);
         }
 
-        public unregisterAfterWorldMatrixUpdate(func: (mesh: BABYLON.AbstractMesh) => void): void {
+        public unregisterAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void {
             var index = this._onAfterWorldMatrixUpdate.indexOf(func);
 
             if (index > -1) {
@@ -505,7 +505,7 @@
         public setPositionWithLocalVector(vector3: Vector3): void {
             this.computeWorldMatrix();
 
-            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
+            this.position = Vector3.TransformNormal(vector3, this._localWorld);
         }
 
         public getPositionExpressedInLocalSpace(): Vector3 {
@@ -513,18 +513,18 @@
             var invLocalWorldMatrix = this._localWorld.clone();
             invLocalWorldMatrix.invert();
 
-            return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
+            return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         }
 
         public locallyTranslate(vector3: Vector3): void {
             this.computeWorldMatrix();
 
-            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
+            this.position = Vector3.TransformCoordinates(vector3, this._localWorld);
         }
 
         public lookAt(targetPoint: Vector3, yawCor: number, pitchCor: number, rollCor: number): void {
             /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
-            /// <param name="targetPoint" type="BABYLON.Vector3">The position (must be in same space as current mesh) to look at</param>
+            /// <param name="targetPoint" type="Vector3">The position (must be in same space as current mesh) to look at</param>
             /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
             /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
             /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
@@ -538,7 +538,7 @@
             var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
             var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
             var pitch = Math.atan2(dv.y, len);
-            this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
+            this.rotationQuaternion = Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
         }
 
         public isInFrustum(frustumPlanes: Plane[]): boolean {
@@ -556,7 +556,7 @@
 
             var transformMatrix = camera.getViewMatrix().multiply(camera.getProjectionMatrix());
 
-            if (!this._boundingInfo.isCompletelyInFrustum(BABYLON.Frustum.GetPlanes(transformMatrix))) {
+            if (!this._boundingInfo.isCompletelyInFrustum(Frustum.GetPlanes(transformMatrix))) {
                 return false;
             }
 
@@ -595,7 +595,7 @@
                 impostor = impostor.impostor;
             }
 
-            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
+            if (impostor === PhysicsEngine.NoImpostor) {
                 physicsEngine._unregisterMesh(this);
                 return;
             }
@@ -619,7 +619,7 @@
 
         public getPhysicsImpostor(): number {
             if (!this._physicImpostor) {
-                return BABYLON.PhysicsEngine.NoImpostor;
+                return PhysicsEngine.NoImpostor;
             }
 
             return this._physicImpostor;
@@ -713,7 +713,7 @@
         */
         public createOrUpdateSubmeshesOctree(maxCapacity = 64, maxDepth = 2): Octree<SubMesh> {
             if (!this._submeshesOctree) {
-                this._submeshesOctree = new BABYLON.Octree<SubMesh>(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
+                this._submeshesOctree = new Octree<SubMesh>(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
             }
 
             this.computeWorldMatrix(true);
@@ -736,7 +736,7 @@
                 var start = subMesh.verticesStart;
                 var end = (subMesh.verticesStart + subMesh.verticesCount);
                 for (var i = start; i < end; i++) {
-                    subMesh._lastColliderWorldVertices.push(BABYLON.Vector3.TransformCoordinates(this._positions[i], transformMatrix));
+                    subMesh._lastColliderWorldVertices.push(Vector3.TransformCoordinates(this._positions[i], transformMatrix));
                 }
             }
             // Collide
@@ -776,7 +776,7 @@
                 return;
 
             // Transformation matrix
-            BABYLON.Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
+            Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
             this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
 
             this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
@@ -788,7 +788,7 @@
         }
 
         public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
-            var pickingInfo = new BABYLON.PickingInfo();
+            var pickingInfo = new PickingInfo();
 
             if (!this.subMeshes || !this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
                 return pickingInfo;
@@ -876,8 +876,10 @@
         }
 
         public dispose(doNotRecurse?: boolean): void {
+            var index: number;
+
             // Physics
-            if (this.getPhysicsImpostor() != PhysicsEngine.NoImpostor) {
+            if (this.getPhysicsImpostor() !== PhysicsEngine.NoImpostor) {
                 this.setPhysicsState(PhysicsEngine.NoImpostor);
             }
 
@@ -895,16 +897,12 @@
             this.releaseSubMeshes();
 
             // Remove from scene
-            var index = this.getScene().meshes.indexOf(this);
-            if (index != -1) {
-                // Remove from the scene if mesh found 
-                this.getScene().meshes.splice(index, 1);
-            }
+            this.getScene().removeMesh(this);
 
             if (!doNotRecurse) {
                 // Particles
                 for (index = 0; index < this.getScene().particleSystems.length; index++) {
-                    if (this.getScene().particleSystems[index].emitter == this) {
+                    if (this.getScene().particleSystems[index].emitter === this) {
                         this.getScene().particleSystems[index].dispose();
                         index--;
                     }
@@ -913,7 +911,7 @@
                 // Children
                 var objects = this.getScene().meshes.slice(0);
                 for (index = 0; index < objects.length; index++) {
-                    if (objects[index].parent == this) {
+                    if (objects[index].parent === this) {
                         objects[index].dispose();
                     }
                 }

+ 11 - 1
Babylon/Mesh/babylon.geometry.js

@@ -11,6 +11,7 @@ var BABYLON;
             this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
             this._totalVertices = 0;
             this._indices = [];
+            this._isDisposed = false;
             this.id = id;
             this._engine = scene.getEngine();
             this._meshes = [];
@@ -89,6 +90,10 @@ var BABYLON;
                     mesh._resetPointsArrayCache();
                     if (updateExtends) {
                         mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
+                            var subMesh = mesh.subMeshes[subIndex];
+                            subMesh.refreshBoundingInfo();
+                        }
                     }
                 }
             }
@@ -267,6 +272,9 @@ var BABYLON;
             }, function () {
             }, scene.database);
         };
+        Geometry.prototype.isDisposed = function () {
+            return this._isDisposed;
+        };
         Geometry.prototype.dispose = function () {
             var meshes = this._meshes;
             var numOfMeshes = meshes.length;
@@ -295,6 +303,7 @@ var BABYLON;
             if (index > -1) {
                 geometries.splice(index, 1);
             }
+            this._isDisposed = true;
         };
         Geometry.prototype.copy = function (id) {
             var vertexData = new BABYLON.VertexData();
@@ -306,7 +315,8 @@ var BABYLON;
             var updatable = false;
             var stopChecking = false;
             for (var kind in this._vertexBuffers) {
-                vertexData.set(this.getVerticesData(kind), kind);
+                // using slice() to make a copy of the array and not just reference it
+                vertexData.set(this.getVerticesData(kind).slice(0), kind);
                 if (!stopChecking) {
                     updatable = this.getVertexBuffer(kind).isUpdatable();
                     stopChecking = !updatable;

+ 16 - 3
Babylon/Mesh/babylon.geometry.ts

@@ -12,6 +12,7 @@
         private _totalVertices = 0;
         private _indices = [];
         private _vertexBuffers;
+        private _isDisposed = false;
         public _delayInfo; //ANY
         private _indexBuffer;
         public _boundingInfo: BoundingInfo;
@@ -122,6 +123,12 @@
                     mesh._resetPointsArrayCache();
                     if (updateExtends) {
                         mesh._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
+
+                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
+                            var subMesh = mesh.subMeshes[subIndex];
+
+                            subMesh.refreshBoundingInfo();
+                        }
                     }
                 }
             }
@@ -341,7 +348,11 @@
                 if (onLoaded) {
                     onLoaded();
                 }
-            }, () => { }, scene.database);
+            },() => { }, scene.database);
+        }
+
+        public isDisposed(): boolean {
+            return this._isDisposed;
         }
 
         public dispose(): void {
@@ -378,6 +389,7 @@
             if (index > -1) {
                 geometries.splice(index, 1);
             }
+            this._isDisposed = true;
         }
 
         public copy(id: string): Geometry {
@@ -394,7 +406,8 @@
             var stopChecking = false;
 
             for (var kind in this._vertexBuffers) {
-                vertexData.set(this.getVerticesData(kind), kind);
+                // using slice() to make a copy of the array and not just reference it
+                vertexData.set(this.getVerticesData(kind).slice(0), kind);
 
                 if (!stopChecking) {
                     updatable = this.getVertexBuffer(kind).isUpdatable();
@@ -729,4 +742,4 @@
             }
         }
     }
-} 
+} 

+ 2 - 2
Babylon/Mesh/babylon.groundMesh.ts

@@ -19,11 +19,11 @@
         }
 
         public getHeightAtCoordinates(x: number, z: number): number {
-            var ray = new BABYLON.Ray(new BABYLON.Vector3(x, this.getBoundingInfo().boundingBox.maximumWorld.y + 1, z), new BABYLON.Vector3(0, -1, 0));
+            var ray = new Ray(new Vector3(x, this.getBoundingInfo().boundingBox.maximumWorld.y + 1, z), new BABYLON.Vector3(0, -1, 0));
 
             this.getWorldMatrix().invertToRef(this._worldInverse);
 
-            ray = BABYLON.Ray.Transform(ray, this._worldInverse);
+            ray = Ray.Transform(ray, this._worldInverse);
 
             var pickInfo = this.intersects(ray);
 

+ 1 - 1
Babylon/Mesh/babylon.instancedMesh.js

@@ -150,4 +150,4 @@ var BABYLON;
     })(BABYLON.AbstractMesh);
     BABYLON.InstancedMesh = InstancedMesh;
 })(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.instancedMesh.js.map
+//# sourceMappingURL=babylon.instancedMesh.js.map

+ 44 - 8
Babylon/Mesh/babylon.mesh.js

@@ -878,7 +878,7 @@ var BABYLON;
          * @param settings a collection of simplification settings.
          * @param parallelProcessing should all levels calculate parallel or one after the other.
          * @param type the type of simplification to run.
-         * successCallback optional success callback to be called after the simplification finished processing all settings.
+         * @param successCallback optional success callback to be called after the simplification finished processing all settings.
          */
         Mesh.prototype.simplify = function (settings, parallelProcessing, simplificationType, successCallback) {
             if (parallelProcessing === void 0) { parallelProcessing = true; }
@@ -891,6 +891,44 @@ var BABYLON;
                 successCallback: successCallback
             });
         };
+        /**
+         * Optimization of the mesh's indices, in case a mesh has duplicated vertices.
+         * The function will only reorder the indices and will not remove unused vertices to avoid problems with submeshes.
+         * This should be used together with the simplification to avoid disappearing triangles.
+         * @param successCallback an optional success callback to be called after the optimization finished.
+         */
+        Mesh.prototype.optimizeIndices = function (successCallback) {
+            var _this = this;
+            var indices = this.getIndices();
+            var positions = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            var vectorPositions = [];
+            for (var pos = 0; pos < positions.length; pos = pos + 3) {
+                vectorPositions.push(BABYLON.Vector3.FromArray(positions, pos));
+            }
+            var dupes = [];
+            BABYLON.AsyncLoop.SyncAsyncForLoop(vectorPositions.length, 40, function (iteration) {
+                var realPos = vectorPositions.length - 1 - iteration;
+                var testedPosition = vectorPositions[realPos];
+                for (var j = 0; j < realPos; ++j) {
+                    var againstPosition = vectorPositions[j];
+                    if (testedPosition.equals(againstPosition)) {
+                        dupes[realPos] = j;
+                        break;
+                    }
+                }
+            }, function () {
+                for (var i = 0; i < indices.length; ++i) {
+                    indices[i] = dupes[indices[i]] || indices[i];
+                }
+                //indices are now reordered
+                var originalSubMeshes = _this.subMeshes.slice(0);
+                _this.setIndices(indices);
+                _this.subMeshes = originalSubMeshes;
+                if (successCallback) {
+                    successCallback(_this);
+                }
+            });
+        };
         // Statics
         Mesh.CreateRibbon = function (name, pathArray, closeArray, closePath, offset, scene, updatable, sideOrientation) {
             if (sideOrientation === void 0) { sideOrientation = Mesh.DEFAULTSIDE; }
@@ -959,11 +997,9 @@ var BABYLON;
             var extruded = Mesh._ExtrudeShapeGeneric(name, shape, path, scale, rotation, null, null, false, false, false, scene, updatable, sideOrientation);
             return extruded;
         };
-        Mesh.ExtrudeShapeCustom = function (name, shape, path, scaleFunction, rotateFunction, ribbonCloseArray, ribbonClosePath, scene, updatable, sideOrientation) {
+        Mesh.ExtrudeShapeCustom = function (name, shape, path, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, scene, updatable, sideOrientation) {
             if (sideOrientation === void 0) { sideOrientation = Mesh.DEFAULTSIDE; }
-            ribbonCloseArray = ribbonCloseArray || false;
-            ribbonClosePath = ribbonClosePath || false;
-            var extrudedCustom = Mesh._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotateFunction, ribbonCloseArray, ribbonClosePath, true, scene, updatable, sideOrientation);
+            var extrudedCustom = Mesh._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, true, scene, updatable, sideOrientation);
             return extrudedCustom;
         };
         Mesh._ExtrudeShapeGeneric = function (name, shape, curve, scale, rotation, scaleFunction, rotateFunction, rbCA, rbCP, custom, scene, updtbl, side) {
@@ -986,8 +1022,8 @@ var BABYLON;
                 var shapePath = new Array();
                 var angleStep = rotate(i, distances[i]);
                 var scaleRatio = scl(i, distances[i]);
-                var rotationMatrix = BABYLON.Matrix.RotationAxis(tangents[i], angle);
                 for (var p = 0; p < shape.length; p++) {
+                    var rotationMatrix = BABYLON.Matrix.RotationAxis(tangents[i], angle);
                     var planed = ((tangents[i].scale(shape[p].z)).add(normals[i].scale(shape[p].x)).add(binormals[i].scale(shape[p].y)));
                     var rotated = BABYLON.Vector3.TransformCoordinates(planed, rotationMatrix).scaleInPlace(scaleRatio).add(curve[i]);
                     shapePath.push(rotated);
@@ -1059,7 +1095,7 @@ var BABYLON;
             var step = pi2 / tesselation;
             var returnRadius = function (i, distance) { return radius; };
             var radiusFunctionFinal = radiusFunction || returnRadius;
-            var circlePaths = [];
+            var circlePaths = new Array();
             var circlePath;
             var rad;
             var normal;
@@ -1067,7 +1103,7 @@ var BABYLON;
             var rotationMatrix;
             for (var i = 0; i < path.length; i++) {
                 rad = radiusFunctionFinal(i, distances[i]); // current radius
-                circlePath = []; // current circle array
+                circlePath = Array(); // current circle array
                 normal = normals[i]; // current normal  
                 for (var ang = 0; ang < pi2; ang += step) {
                     rotationMatrix = BABYLON.Matrix.RotationAxis(tangents[i], ang);

+ 64 - 26
Babylon/Mesh/babylon.mesh.ts

@@ -766,7 +766,7 @@
 
                     this.delayLoadState = Engine.DELAYLOADSTATE_LOADED;
                     scene._removePendingData(this);
-                }, () => { }, scene.database, getBinaryData);
+                },() => { }, scene.database, getBinaryData);
             }
         }
 
@@ -923,7 +923,7 @@
                 }
             };
 
-            Tools.LoadImage(url, onload, () => { }, scene.database);
+            Tools.LoadImage(url, onload,() => { }, scene.database);
         }
 
         public applyDisplacementMapFromBuffer(buffer: Uint8Array, heightMapWidth: number, heightMapHeight: number, minHeight: number, maxHeight: number): void {
@@ -944,7 +944,7 @@
             for (var index = 0; index < positions.length; index += 3) {
                 Vector3.FromArrayToRef(positions, index, position);
                 Vector3.FromArrayToRef(normals, index, normal);
-                Vector2.FromArrayToRef(uvs, (index / 3) * 2, uv);
+                Vector2.FromArrayToRef(uvs,(index / 3) * 2, uv);
 
                 // Compute height
                 var u = ((Math.abs(uv.x) * heightMapWidth) % heightMapWidth) | 0;
@@ -1025,8 +1025,8 @@
                 indices[index + 2] = index + 2;
 
                 var p1 = Vector3.FromArray(positions, index * 3);
-                var p2 = Vector3.FromArray(positions, (index + 1) * 3);
-                var p3 = Vector3.FromArray(positions, (index + 2) * 3);
+                var p2 = Vector3.FromArray(positions,(index + 1) * 3);
+                var p3 = Vector3.FromArray(positions,(index + 2) * 3);
 
                 var p1p2 = p1.subtract(p2);
                 var p3p2 = p3.subtract(p2);
@@ -1078,7 +1078,7 @@
          * @param settings a collection of simplification settings.
          * @param parallelProcessing should all levels calculate parallel or one after the other.
          * @param type the type of simplification to run.
-         * successCallback optional success callback to be called after the simplification finished processing all settings.
+         * @param successCallback optional success callback to be called after the simplification finished processing all settings.
          */
         public simplify(settings: Array<ISimplificationSettings>, parallelProcessing: boolean = true, simplificationType: SimplificationType = SimplificationType.QUADRATIC, successCallback?: (mesh?: Mesh, submeshIndex?: number) => void) {
             this.getScene().simplificationQueue.addTask({
@@ -1090,6 +1090,46 @@
             });
         }
 
+        /**
+         * Optimization of the mesh's indices, in case a mesh has duplicated vertices.
+         * The function will only reorder the indices and will not remove unused vertices to avoid problems with submeshes.
+         * This should be used together with the simplification to avoid disappearing triangles.
+         * @param successCallback an optional success callback to be called after the optimization finished.
+         */
+        public optimizeIndices(successCallback?: (mesh?: Mesh) => void) {
+            var indices = this.getIndices();
+            var positions = this.getVerticesData(VertexBuffer.PositionKind);
+            var vectorPositions = [];
+            for (var pos = 0; pos < positions.length; pos = pos + 3) {
+                vectorPositions.push(Vector3.FromArray(positions, pos));
+            }
+            var dupes = [];
+
+            AsyncLoop.SyncAsyncForLoop(vectorPositions.length, 40,(iteration) => {
+                var realPos = vectorPositions.length - 1 - iteration;
+                var testedPosition = vectorPositions[realPos];
+                for (var j = 0; j < realPos; ++j) {
+                    var againstPosition = vectorPositions[j];
+                    if (testedPosition.equals(againstPosition)) {
+                        dupes[realPos] = j;
+                        break;
+                    }
+                }
+            },() => {
+                    for (var i = 0; i < indices.length; ++i) {
+                        indices[i] = dupes[indices[i]] || indices[i];
+                    }
+
+                    //indices are now reordered
+                    var originalSubMeshes = this.subMeshes.slice(0);
+                    this.setIndices(indices);
+                    this.subMeshes = originalSubMeshes;
+                    if (successCallback) {
+                        successCallback(this);
+                    }
+                });
+        }
+
         // Statics
         public static CreateRibbon(name: string, pathArray: Vector3[][], closeArray: boolean, closePath: boolean, offset: number, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
             var ribbon = new Mesh(name, scene);
@@ -1175,10 +1215,8 @@
             return extruded;
         }
 
-        public static ExtrudeShapeCustom(name: string, shape: Vector3[], path: Vector3[], scaleFunction, rotateFunction, ribbonCloseArray: boolean, ribbonClosePath: boolean, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
-            ribbonCloseArray = ribbonCloseArray || false;
-            ribbonClosePath = ribbonClosePath || false;
-            var extrudedCustom = Mesh._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotateFunction, ribbonCloseArray, ribbonClosePath, true, scene, updatable, sideOrientation);
+        public static ExtrudeShapeCustom(name: string, shape: Vector3[], path: Vector3[], scaleFunction, rotationFunction, ribbonCloseArray: boolean, ribbonClosePath: boolean, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
+            var extrudedCustom = Mesh._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, true, scene, updatable, sideOrientation);
             return extrudedCustom;
         }
 
@@ -1190,17 +1228,17 @@
             var distances = path3D.getDistances();
             var shapePaths = new Array<Array<Vector3>>();
             var angle = 0;
-            var returnScale: { (i: number, distance: number): number; } = function (i, distance) { return scale; };
-            var returnRotation: { (i: number, distance: number): number; } = function (i, distance) { return rotation; };
+            var returnScale: { (i: number, distance: number): number; } = (i, distance) => { return scale; };
+            var returnRotation: { (i: number, distance: number): number; } = (i, distance) => { return rotation; };
             var rotate: { (i: number, distance: number): number; } = custom ? rotateFunction : returnRotation;
             var scl: { (i: number, distance: number): number; } = custom ? scaleFunction : returnScale;
 
-            for (var i: number = 0; i < curve.length; i++) {
+            for (var i = 0; i < curve.length; i++) {
                 var shapePath = new Array<Vector3>();
                 var angleStep = rotate(i, distances[i]);
                 var scaleRatio = scl(i, distances[i]);
-                var rotationMatrix = Matrix.RotationAxis(tangents[i], angle);
                 for (var p = 0; p < shape.length; p++) {
+                    var rotationMatrix = Matrix.RotationAxis(tangents[i], angle);
                     var planed = ((tangents[i].scale(shape[p].z)).add(normals[i].scale(shape[p].x)).add(binormals[i].scale(shape[p].y)));
                     var rotated = Vector3.TransformCoordinates(planed, rotationMatrix).scaleInPlace(scaleRatio).add(curve[i]);
                     shapePath.push(rotated);
@@ -1279,32 +1317,32 @@
                 }
             };
 
-            Tools.LoadImage(url, onload, () => { }, scene.database);
+            Tools.LoadImage(url, onload,() => { }, scene.database);
 
             return ground;
         }
 
         public static CreateTube(name: string, path: Vector3[], radius: number, tesselation: number, radiusFunction: { (i: number, distance: number): number; }, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
-            var path3D: Path3D = new Path3D(path);
-            var tangents: Vector3[] = path3D.getTangents();
-            var normals: Vector3[] = path3D.getNormals();
-            var distances: number[] = path3D.getDistances();
-            var pi2: number = Math.PI * 2;
-            var step: number = pi2 / tesselation;
+            var path3D = new Path3D(path);
+            var tangents = path3D.getTangents();
+            var normals = path3D.getNormals();
+            var distances = path3D.getDistances();
+            var pi2 = Math.PI * 2;
+            var step = pi2 / tesselation;
             var returnRadius: { (i: number, distance: number): number; } = (i, distance) => radius;
             var radiusFunctionFinal: { (i: number, distance: number): number; } = radiusFunction || returnRadius;
 
-            var circlePaths: Vector3[][] = [];
+            var circlePaths = new Array<Array<Vector3>>();
             var circlePath: Vector3[];
             var rad: number;
             var normal: Vector3;
             var rotated: Vector3;
             var rotationMatrix: Matrix;
-            for (var i: number = 0; i < path.length; i++) {
-                rad = radiusFunctionFinal(i, distances[i]);      // current radius
-                circlePath = [];                            // current circle array
+            for (var i = 0; i < path.length; i++) {
+                rad = radiusFunctionFinal(i, distances[i]); // current radius
+                circlePath = Array<Vector3>();              // current circle array
                 normal = normals[i];                        // current normal  
-                for (var ang: number = 0; ang < pi2; ang += step) {
+                for (var ang = 0; ang < pi2; ang += step) {
                     rotationMatrix = Matrix.RotationAxis(tangents[i], ang);
                     rotated = Vector3.TransformCoordinates(normal, rotationMatrix).scaleInPlace(rad).add(path[i]);
                     circlePath.push(rotated);

+ 121 - 139
Babylon/Mesh/babylon.meshSimplification.js

@@ -1,9 +1,10 @@
 var BABYLON;
 (function (BABYLON) {
     var SimplificationSettings = (function () {
-        function SimplificationSettings(quality, distance) {
+        function SimplificationSettings(quality, distance, optimizeMesh) {
             this.quality = quality;
             this.distance = distance;
+            this.optimizeMesh = optimizeMesh;
         }
         return SimplificationSettings;
     })();
@@ -28,14 +29,13 @@ var BABYLON;
         };
         SimplificationQueue.prototype.runSimplification = function (task) {
             var _this = this;
-            function setLODLevel(distance, mesh) {
-            }
             if (task.parallelProcessing) {
                 //parallel simplifier
                 task.settings.forEach(function (setting) {
                     var simplifier = _this.getSimplifier(task);
                     simplifier.simplify(setting, function (newMesh) {
                         task.mesh.addLODLevel(setting.distance, newMesh);
+                        newMesh.isVisible = true;
                         //check if it is the last
                         if (setting.quality === task.settings[task.settings.length - 1].quality && task.successCallback) {
                             //all done, run the success callback.
@@ -51,6 +51,7 @@ var BABYLON;
                 var runDecimation = function (setting, callback) {
                     simplifier.simplify(setting, function (newMesh) {
                         task.mesh.addLODLevel(setting.distance, newMesh);
+                        newMesh.isVisible = true;
                         //run the next quality level
                         callback();
                     });
@@ -92,22 +93,25 @@ var BABYLON;
             this.error = new Array(4);
             this.deleted = false;
             this.isDirty = false;
+            this.deletePending = false;
             this.borderFactor = 0;
         }
         return DecimationTriangle;
     })();
     BABYLON.DecimationTriangle = DecimationTriangle;
     var DecimationVertex = (function () {
-        function DecimationVertex(position, normal, uv, id) {
+        function DecimationVertex(position, id) {
             this.position = position;
-            this.normal = normal;
-            this.uv = uv;
             this.id = id;
             this.isBorder = true;
             this.q = new QuadraticMatrix();
             this.triangleCount = 0;
             this.triangleStart = 0;
+            this.originalOffsets = [];
         }
+        DecimationVertex.prototype.updatePosition = function (newPosition) {
+            this.position.copyFrom(newPosition);
+        };
         return DecimationVertex;
     })();
     BABYLON.DecimationVertex = DecimationVertex;
@@ -171,7 +175,7 @@ var BABYLON;
     var QuadraticErrorSimplification = (function () {
         function QuadraticErrorSimplification(_mesh) {
             this._mesh = _mesh;
-            this.initialised = false;
+            this.initialized = false;
             this.syncIterations = 5000;
             this.aggressiveness = 7;
             this.decimationIterations = 100;
@@ -182,14 +186,13 @@ var BABYLON;
             this.initDecimatedMesh();
             //iterating through the submeshes array, one after the other.
             BABYLON.AsyncLoop.Run(this._mesh.subMeshes.length, function (loop) {
-                _this.initWithMesh(_this._mesh, loop.index, function () {
+                _this.initWithMesh(loop.index, function () {
                     _this.runDecimation(settings, loop.index, function () {
                         loop.executeNext();
                     });
-                });
+                }, settings.optimizeMesh);
             }, function () {
                 setTimeout(function () {
-                    _this._reconstructedMesh.isVisible = true;
                     successCallback(_this._reconstructedMesh);
                 }, 0);
             });
@@ -197,9 +200,9 @@ var BABYLON;
         QuadraticErrorSimplification.prototype.isTriangleOnBoundingBox = function (triangle) {
             var _this = this;
             var gCount = 0;
-            triangle.vertices.forEach(function (vId) {
+            triangle.vertices.forEach(function (vertex) {
                 var count = 0;
-                var vPos = _this.vertices[vId].position;
+                var vPos = vertex.position;
                 var bbox = _this._mesh.getBoundingInfo().boundingBox;
                 if (bbox.maximum.x - vPos.x < _this.boundingBoxEpsilon || vPos.x - bbox.minimum.x > _this.boundingBoxEpsilon)
                     ++count;
@@ -243,10 +246,8 @@ var BABYLON;
                             if (t.error[j] < threshold) {
                                 var deleted0 = [];
                                 var deleted1 = [];
-                                var i0 = t.vertices[j];
-                                var i1 = t.vertices[(j + 1) % 3];
-                                var v0 = _this.vertices[i0];
-                                var v1 = _this.vertices[i1];
+                                var v0 = t.vertices[j];
+                                var v1 = t.vertices[(j + 1) % 3];
                                 if (v0.isBorder !== v1.isBorder)
                                     continue;
                                 var p = BABYLON.Vector3.Zero();
@@ -255,27 +256,27 @@ var BABYLON;
                                 var color = new BABYLON.Color4(0, 0, 0, 1);
                                 _this.calculateError(v0, v1, p, n, uv, color);
                                 var delTr = [];
-                                if (_this.isFlipped(v0, i1, p, deleted0, t.borderFactor, delTr))
+                                if (_this.isFlipped(v0, v1, p, deleted0, t.borderFactor, delTr))
                                     continue;
-                                if (_this.isFlipped(v1, i0, p, deleted1, t.borderFactor, delTr))
+                                if (_this.isFlipped(v1, v0, p, deleted1, t.borderFactor, delTr))
                                     continue;
-                                if (delTr.length == 2 || delTr[0] === delTr[1]) {
-                                    continue;
-                                }
-                                v0.normal = n;
-                                if (v0.uv)
-                                    v0.uv = uv;
-                                else if (v0.color)
-                                    v0.color = color;
-                                v0.q = v1.q.add(v0.q);
                                 if (deleted0.indexOf(true) < 0 || deleted1.indexOf(true) < 0)
                                     continue;
-                                if (p.equals(v0.position))
+                                var uniqueArray = [];
+                                delTr.forEach(function (deletedT) {
+                                    if (uniqueArray.indexOf(deletedT) === -1) {
+                                        deletedT.deletePending = true;
+                                        uniqueArray.push(deletedT);
+                                    }
+                                });
+                                if (uniqueArray.length % 2 != 0) {
                                     continue;
-                                v0.position = p;
+                                }
+                                v0.q = v1.q.add(v0.q);
+                                v0.updatePosition(p);
                                 var tStart = _this.references.length;
-                                deletedTriangles = _this.updateTriangles(v0.id, v0, deleted0, deletedTriangles);
-                                deletedTriangles = _this.updateTriangles(v0.id, v1, deleted1, deletedTriangles);
+                                deletedTriangles = _this.updateTriangles(v0, v0, deleted0, deletedTriangles);
+                                deletedTriangles = _this.updateTriangles(v0, v1, deleted1, deletedTriangles);
                                 var tCount = _this.references.length - tStart;
                                 if (tCount <= v0.triangleCount) {
                                     if (tCount) {
@@ -313,41 +314,48 @@ var BABYLON;
                 }, 0);
             });
         };
-        QuadraticErrorSimplification.prototype.initWithMesh = function (mesh, submeshIndex, callback) {
+        QuadraticErrorSimplification.prototype.initWithMesh = function (submeshIndex, callback, optimizeMesh) {
             var _this = this;
-            if (!mesh)
-                return;
             this.vertices = [];
             this.triangles = [];
-            this._mesh = mesh;
-            //It is assumed that a mesh has positions, normals and either uvs or colors.
             var positionData = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            var normalData = this._mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
-            var uvs = this._mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
-            var colorsData = this._mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
-            var indices = mesh.getIndices();
-            var submesh = mesh.subMeshes[submeshIndex];
+            var indices = this._mesh.getIndices();
+            var submesh = this._mesh.subMeshes[submeshIndex];
+            var findInVertices = function (positionToSearch) {
+                if (optimizeMesh) {
+                    for (var ii = 0; ii < _this.vertices.length; ++ii) {
+                        if (_this.vertices[ii].position.equals(positionToSearch)) {
+                            return _this.vertices[ii];
+                        }
+                    }
+                }
+                return null;
+            };
+            var vertexReferences = [];
             var vertexInit = function (i) {
                 var offset = i + submesh.verticesStart;
-                var vertex = new DecimationVertex(BABYLON.Vector3.FromArray(positionData, offset * 3), BABYLON.Vector3.FromArray(normalData, offset * 3), null, i);
-                if (_this._mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                    vertex.uv = BABYLON.Vector2.FromArray(uvs, offset * 2);
-                }
-                else if (_this._mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                    vertex.color = BABYLON.Color4.FromArray(colorsData, offset * 4);
+                var position = BABYLON.Vector3.FromArray(positionData, offset * 3);
+                var vertex = findInVertices(position) || new DecimationVertex(position, _this.vertices.length);
+                vertex.originalOffsets.push(offset);
+                if (vertex.id == _this.vertices.length) {
+                    _this.vertices.push(vertex);
                 }
-                _this.vertices.push(vertex);
+                vertexReferences.push(vertex.id);
             };
             //var totalVertices = mesh.getTotalVertices();
             var totalVertices = submesh.verticesCount;
-            BABYLON.AsyncLoop.SyncAsyncForLoop(totalVertices, this.syncIterations, vertexInit, function () {
+            BABYLON.AsyncLoop.SyncAsyncForLoop(totalVertices, (this.syncIterations / 4) >> 0, vertexInit, function () {
                 var indicesInit = function (i) {
                     var offset = (submesh.indexStart / 3) + i;
                     var pos = (offset * 3);
-                    var i0 = indices[pos + 0] - submesh.verticesStart;
-                    var i1 = indices[pos + 1] - submesh.verticesStart;
-                    var i2 = indices[pos + 2] - submesh.verticesStart;
-                    var triangle = new DecimationTriangle([_this.vertices[i0].id, _this.vertices[i1].id, _this.vertices[i2].id]);
+                    var i0 = indices[pos + 0];
+                    var i1 = indices[pos + 1];
+                    var i2 = indices[pos + 2];
+                    var v0 = _this.vertices[vertexReferences[i0 - submesh.verticesStart]];
+                    var v1 = _this.vertices[vertexReferences[i1 - submesh.verticesStart]];
+                    var v2 = _this.vertices[vertexReferences[i2 - submesh.verticesStart]];
+                    var triangle = new DecimationTriangle([v0, v1, v2]);
+                    triangle.originalOffset = pos;
                     _this.triangles.push(triangle);
                 };
                 BABYLON.AsyncLoop.SyncAsyncForLoop(submesh.indexCount / 3, _this.syncIterations, indicesInit, function () {
@@ -359,21 +367,21 @@ var BABYLON;
             var _this = this;
             var triangleInit1 = function (i) {
                 var t = _this.triangles[i];
-                t.normal = BABYLON.Vector3.Cross(_this.vertices[t.vertices[1]].position.subtract(_this.vertices[t.vertices[0]].position), _this.vertices[t.vertices[2]].position.subtract(_this.vertices[t.vertices[0]].position)).normalize();
+                t.normal = BABYLON.Vector3.Cross(t.vertices[1].position.subtract(t.vertices[0].position), t.vertices[2].position.subtract(t.vertices[0].position)).normalize();
                 for (var j = 0; j < 3; j++) {
-                    _this.vertices[t.vertices[j]].q.addArrayInPlace(QuadraticMatrix.DataFromNumbers(t.normal.x, t.normal.y, t.normal.z, -(BABYLON.Vector3.Dot(t.normal, _this.vertices[t.vertices[0]].position))));
+                    t.vertices[j].q.addArrayInPlace(QuadraticMatrix.DataFromNumbers(t.normal.x, t.normal.y, t.normal.z, -(BABYLON.Vector3.Dot(t.normal, t.vertices[0].position))));
                 }
             };
             BABYLON.AsyncLoop.SyncAsyncForLoop(this.triangles.length, this.syncIterations, triangleInit1, function () {
                 var triangleInit2 = function (i) {
                     var t = _this.triangles[i];
                     for (var j = 0; j < 3; ++j) {
-                        t.error[j] = _this.calculateError(_this.vertices[t.vertices[j]], _this.vertices[t.vertices[(j + 1) % 3]]);
+                        t.error[j] = _this.calculateError(t.vertices[j], t.vertices[(j + 1) % 3]);
                     }
                     t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]);
                 };
                 BABYLON.AsyncLoop.SyncAsyncForLoop(_this.triangles.length, _this.syncIterations, triangleInit2, function () {
-                    _this.initialised = true;
+                    _this.initialized = true;
                     callback();
                 });
             });
@@ -390,52 +398,42 @@ var BABYLON;
                 if (!this.triangles[i].deleted) {
                     t = this.triangles[i];
                     for (j = 0; j < 3; ++j) {
-                        this.vertices[t.vertices[j]].triangleCount = 1;
+                        t.vertices[j].triangleCount = 1;
                     }
                     newTriangles.push(t);
                 }
             }
-            var newVerticesOrder = [];
-            //compact vertices, get the IDs of the vertices used.
-            var dst = 0;
-            for (i = 0; i < this.vertices.length; ++i) {
-                if (this.vertices[i].triangleCount) {
-                    this.vertices[i].triangleStart = dst;
-                    this.vertices[dst].position = this.vertices[i].position;
-                    this.vertices[dst].normal = this.vertices[i].normal;
-                    this.vertices[dst].uv = this.vertices[i].uv;
-                    this.vertices[dst].color = this.vertices[i].color;
-                    newVerticesOrder.push(i);
-                    dst++;
-                }
-            }
-            for (i = 0; i < newTriangles.length; ++i) {
-                t = newTriangles[i];
-                for (j = 0; j < 3; ++j) {
-                    t.vertices[j] = this.vertices[t.vertices[j]].triangleStart;
-                }
-            }
-            this.vertices = this.vertices.slice(0, dst);
             var newPositionData = this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.PositionKind) || [];
             var newNormalData = this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.NormalKind) || [];
             var newUVsData = this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.UVKind) || [];
             var newColorsData = this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.ColorKind) || [];
-            for (i = 0; i < newVerticesOrder.length; ++i) {
-                newPositionData.push(this.vertices[i].position.x);
-                newPositionData.push(this.vertices[i].position.y);
-                newPositionData.push(this.vertices[i].position.z);
-                newNormalData.push(this.vertices[i].normal.x);
-                newNormalData.push(this.vertices[i].normal.y);
-                newNormalData.push(this.vertices[i].normal.z);
-                if (this.vertices[i].uv) {
-                    newUVsData.push(this.vertices[i].uv.x);
-                    newUVsData.push(this.vertices[i].uv.y);
-                }
-                else if (this.vertices[i].color) {
-                    newColorsData.push(this.vertices[i].color.r);
-                    newColorsData.push(this.vertices[i].color.g);
-                    newColorsData.push(this.vertices[i].color.b);
-                    newColorsData.push(this.vertices[i].color.a);
+            var normalData = this._mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+            var uvs = this._mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+            var colorsData = this._mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+            var vertexCount = 0;
+            for (i = 0; i < this.vertices.length; ++i) {
+                var vertex = this.vertices[i];
+                vertex.id = vertexCount;
+                if (vertex.triangleCount) {
+                    vertex.originalOffsets.forEach(function (originalOffset) {
+                        newPositionData.push(vertex.position.x);
+                        newPositionData.push(vertex.position.y);
+                        newPositionData.push(vertex.position.z);
+                        newNormalData.push(normalData[originalOffset * 3]);
+                        newNormalData.push(normalData[(originalOffset * 3) + 1]);
+                        newNormalData.push(normalData[(originalOffset * 3) + 2]);
+                        if (uvs && uvs.length) {
+                            newUVsData.push(uvs[(originalOffset * 2)]);
+                            newUVsData.push(uvs[(originalOffset * 2) + 1]);
+                        }
+                        else if (colorsData && colorsData.length) {
+                            newColorsData.push(colorsData[(originalOffset * 4)]);
+                            newColorsData.push(colorsData[(originalOffset * 4) + 1]);
+                            newColorsData.push(colorsData[(originalOffset * 4) + 2]);
+                            newColorsData.push(colorsData[(originalOffset * 4) + 3]);
+                        }
+                        ++vertexCount;
+                    });
                 }
             }
             var startingIndex = this._reconstructedMesh.getTotalIndices();
@@ -443,10 +441,17 @@ var BABYLON;
             var submeshesArray = this._reconstructedMesh.subMeshes;
             this._reconstructedMesh.subMeshes = [];
             var newIndicesArray = this._reconstructedMesh.getIndices(); //[];
+            var originalIndices = this._mesh.getIndices();
             for (i = 0; i < newTriangles.length; ++i) {
-                newIndicesArray.push(newTriangles[i].vertices[0] + startingVertex);
-                newIndicesArray.push(newTriangles[i].vertices[1] + startingVertex);
-                newIndicesArray.push(newTriangles[i].vertices[2] + startingVertex);
+                var t = newTriangles[i];
+                //now get the new referencing point for each vertex
+                [0, 1, 2].forEach(function (idx) {
+                    var id = originalIndices[t.originalOffset + idx];
+                    var offset = t.vertices[idx].originalOffsets.indexOf(id);
+                    if (offset < 0)
+                        offset = 0;
+                    newIndicesArray.push(t.vertices[idx].id + offset + startingVertex);
+                });
             }
             //overwriting the old vertex buffers and indices.
             this._reconstructedMesh.setIndices(newIndicesArray);
@@ -463,7 +468,7 @@ var BABYLON;
                 submeshesArray.forEach(function (submesh) {
                     new BABYLON.SubMesh(submesh.materialIndex, submesh.verticesStart, submesh.verticesCount, submesh.indexStart, submesh.indexCount, submesh.getMesh());
                 });
-                var newSubmesh = new BABYLON.SubMesh(originalSubmesh.materialIndex, startingVertex, newVerticesOrder.length, startingIndex, newTriangles.length * 3, this._reconstructedMesh);
+                var newSubmesh = new BABYLON.SubMesh(originalSubmesh.materialIndex, startingVertex, vertexCount, startingIndex, newTriangles.length * 3, this._reconstructedMesh);
             }
         };
         QuadraticErrorSimplification.prototype.initDecimatedMesh = function () {
@@ -472,22 +477,22 @@ var BABYLON;
             this._reconstructedMesh.parent = this._mesh.parent;
             this._reconstructedMesh.isVisible = false;
         };
-        QuadraticErrorSimplification.prototype.isFlipped = function (vertex1, index2, point, deletedArray, borderFactor, delTr) {
+        QuadraticErrorSimplification.prototype.isFlipped = function (vertex1, vertex2, point, deletedArray, borderFactor, delTr) {
             for (var i = 0; i < vertex1.triangleCount; ++i) {
                 var t = this.triangles[this.references[vertex1.triangleStart + i].triangleId];
                 if (t.deleted)
                     continue;
                 var s = this.references[vertex1.triangleStart + i].vertexId;
-                var id1 = t.vertices[(s + 1) % 3];
-                var id2 = t.vertices[(s + 2) % 3];
-                if ((id1 === index2 || id2 === index2)) {
+                var v1 = t.vertices[(s + 1) % 3];
+                var v2 = t.vertices[(s + 2) % 3];
+                if ((v1 === vertex2 || v2 === vertex2)) {
                     deletedArray[i] = true;
                     delTr.push(t);
                     continue;
                 }
-                var d1 = this.vertices[id1].position.subtract(point);
+                var d1 = v1.position.subtract(point);
                 d1 = d1.normalize();
-                var d2 = this.vertices[id2].position.subtract(point);
+                var d2 = v2.position.subtract(point);
                 d2 = d2.normalize();
                 if (Math.abs(BABYLON.Vector3.Dot(d1, d2)) > 0.999)
                     return true;
@@ -498,23 +503,23 @@ var BABYLON;
             }
             return false;
         };
-        QuadraticErrorSimplification.prototype.updateTriangles = function (vertexId, vertex, deletedArray, deletedTriangles) {
+        QuadraticErrorSimplification.prototype.updateTriangles = function (origVertex, vertex, deletedArray, deletedTriangles) {
             var newDeleted = deletedTriangles;
             for (var i = 0; i < vertex.triangleCount; ++i) {
                 var ref = this.references[vertex.triangleStart + i];
                 var t = this.triangles[ref.triangleId];
                 if (t.deleted)
                     continue;
-                if (deletedArray[i]) {
+                if (deletedArray[i] && t.deletePending) {
                     t.deleted = true;
                     newDeleted++;
                     continue;
                 }
-                t.vertices[ref.vertexId] = vertexId;
+                t.vertices[ref.vertexId] = origVertex;
                 t.isDirty = true;
-                t.error[0] = this.calculateError(this.vertices[t.vertices[0]], this.vertices[t.vertices[1]]) + (t.borderFactor / 2);
-                t.error[1] = this.calculateError(this.vertices[t.vertices[1]], this.vertices[t.vertices[2]]) + (t.borderFactor / 2);
-                t.error[2] = this.calculateError(this.vertices[t.vertices[2]], this.vertices[t.vertices[0]]) + (t.borderFactor / 2);
+                t.error[0] = this.calculateError(t.vertices[0], t.vertices[1]) + (t.borderFactor / 2);
+                t.error[1] = this.calculateError(t.vertices[1], t.vertices[2]) + (t.borderFactor / 2);
+                t.error[2] = this.calculateError(t.vertices[2], t.vertices[0]) + (t.borderFactor / 2);
                 t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]);
                 this.references.push(ref);
             }
@@ -530,15 +535,15 @@ var BABYLON;
                     var triangle = this.triangles[this.references[v.triangleStart + j].triangleId];
                     for (var ii = 0; ii < 3; ii++) {
                         var ofs = 0;
-                        var id = triangle.vertices[ii];
+                        var vv = triangle.vertices[ii];
                         while (ofs < vCount.length) {
-                            if (vId[ofs] === id)
+                            if (vId[ofs] === vv.id)
                                 break;
                             ++ofs;
                         }
                         if (ofs === vCount.length) {
                             vCount.push(1);
-                            vId.push(id);
+                            vId.push(vv.id);
                         }
                         else {
                             vCount[ofs]++;
@@ -577,7 +582,7 @@ var BABYLON;
             for (i = 0; i < this.triangles.length; ++i) {
                 t = this.triangles[i];
                 for (j = 0; j < 3; ++j) {
-                    v = this.vertices[t.vertices[j]];
+                    v = t.vertices[j];
                     v.triangleCount++;
                 }
             }
@@ -591,7 +596,7 @@ var BABYLON;
             for (i = 0; i < this.triangles.length; ++i) {
                 t = this.triangles[i];
                 for (j = 0; j < 3; ++j) {
-                    v = this.vertices[t.vertices[j]];
+                    v = t.vertices[j];
                     newReferences[v.triangleStart + v.triangleCount] = new Reference(j, i);
                     v.triangleCount++;
                 }
@@ -620,14 +625,6 @@ var BABYLON;
                 pointResult.y = 1 / qDet * (q.det(0, 2, 3, 1, 5, 6, 2, 7, 8));
                 pointResult.z = -1 / qDet * (q.det(0, 1, 3, 1, 4, 6, 2, 5, 8));
                 error = this.vertexError(q, pointResult);
-                //TODO this should be correctly calculated
-                if (normalResult) {
-                    normalResult.copyFrom(vertex1.normal);
-                    if (vertex1.uv)
-                        uvResult.copyFrom(vertex1.uv);
-                    else if (vertex1.color)
-                        colorResult.copyFrom(vertex1.color);
-                }
             }
             else {
                 var p3 = (vertex1.position.add(vertex2.position)).divide(new BABYLON.Vector3(2, 2, 2));
@@ -639,31 +636,16 @@ var BABYLON;
                 if (error === error1) {
                     if (pointResult) {
                         pointResult.copyFrom(vertex1.position);
-                        normalResult.copyFrom(vertex1.normal);
-                        if (vertex1.uv)
-                            uvResult.copyFrom(vertex1.uv);
-                        else if (vertex1.color)
-                            colorResult.copyFrom(vertex1.color);
                     }
                 }
                 else if (error === error2) {
                     if (pointResult) {
                         pointResult.copyFrom(vertex2.position);
-                        normalResult.copyFrom(vertex2.normal);
-                        if (vertex2.uv)
-                            uvResult.copyFrom(vertex2.uv);
-                        else if (vertex2.color)
-                            colorResult.copyFrom(vertex2.color);
                     }
                 }
                 else {
                     if (pointResult) {
                         pointResult.copyFrom(p3);
-                        normalResult.copyFrom(vertex1.normal);
-                        if (vertex1.uv)
-                            uvResult.copyFrom(vertex1.uv);
-                        else if (vertex1.color)
-                            colorResult.copyFrom(vertex1.color);
                     }
                 }
             }

+ 132 - 143
Babylon/Mesh/babylon.meshSimplification.ts

@@ -22,10 +22,11 @@
     export interface ISimplificationSettings {
         quality: number;
         distance: number;
+        optimizeMesh?: boolean;
     }
 
     export class SimplificationSettings implements ISimplificationSettings {
-        constructor(public quality: number, public distance: number) {
+        constructor(public quality: number, public distance: number, public optimizeMesh?: boolean) {
         }
     }
 
@@ -61,17 +62,13 @@
         }
 
         public runSimplification(task: ISimplificationTask) {
-
-            function setLODLevel(distance: number, mesh: Mesh) {
-
-            }
-
             if (task.parallelProcessing) {
                 //parallel simplifier
                 task.settings.forEach((setting) => {
                     var simplifier = this.getSimplifier(task);
                     simplifier.simplify(setting,(newMesh) => {
                         task.mesh.addLODLevel(setting.distance, newMesh);
+                        newMesh.isVisible = true;
                         //check if it is the last
                         if (setting.quality === task.settings[task.settings.length - 1].quality && task.successCallback) {
                             //all done, run the success callback.
@@ -87,6 +84,7 @@
                 var runDecimation = (setting: ISimplificationSettings, callback: () => void) => {
                     simplifier.simplify(setting,(newMesh) => {
                         task.mesh.addLODLevel(setting.distance, newMesh);
+                        newMesh.isVisible = true;
                         //run the next quality level
                         callback();
                     });
@@ -129,11 +127,15 @@
         public deleted: boolean;
         public isDirty: boolean;
         public borderFactor: number;
+        public deletePending: boolean;
+
+        public originalOffset: number;
 
-        constructor(public vertices: Array<number>) {
+        constructor(public vertices: Array<DecimationVertex>) {
             this.error = new Array<number>(4);
             this.deleted = false;
             this.isDirty = false;
+            this.deletePending = false;
             this.borderFactor = 0;
         }
     }
@@ -145,14 +147,18 @@
         public triangleStart: number;
         public triangleCount: number;
 
-        //if color is present instead of uvs.
-        public color: Color4;
+        public originalOffsets: Array<number>;
 
-        constructor(public position: Vector3, public normal: Vector3, public uv: Vector2, public id) {
+        constructor(public position: Vector3, public id) {
             this.isBorder = true;
             this.q = new QuadraticMatrix();
             this.triangleCount = 0;
             this.triangleStart = 0;
+            this.originalOffsets = [];
+        }
+
+        public updatePosition(newPosition: Vector3) {
+            this.position.copyFrom(newPosition);
         }
     }
 
@@ -223,7 +229,7 @@
         private vertices: Array<DecimationVertex>;
         private references: Array<Reference>;
 
-        private initialised: boolean = false;
+        private initialized: boolean = false;
 
         private _reconstructedMesh: Mesh;
 
@@ -238,21 +244,19 @@
             this.aggressiveness = 7;
             this.decimationIterations = 100;
             this.boundingBoxEpsilon = Engine.Epsilon;
-
         }
 
         public simplify(settings: ISimplificationSettings, successCallback: (simplifiedMesh: Mesh) => void) {
             this.initDecimatedMesh();
             //iterating through the submeshes array, one after the other.
             AsyncLoop.Run(this._mesh.subMeshes.length,(loop: AsyncLoop) => {
-                this.initWithMesh(this._mesh, loop.index,() => {
+                this.initWithMesh(loop.index,() => {
                     this.runDecimation(settings, loop.index,() => {
                         loop.executeNext();
                     });
-                });
+                }, settings.optimizeMesh);
             },() => {
                     setTimeout(() => {
-                        this._reconstructedMesh.isVisible = true;
                         successCallback(this._reconstructedMesh);
                     }, 0);
                 });
@@ -260,9 +264,9 @@
 
         private isTriangleOnBoundingBox(triangle: DecimationTriangle): boolean {
             var gCount = 0;
-            triangle.vertices.forEach((vId) => {
+            triangle.vertices.forEach((vertex) => {
                 var count = 0;
-                var vPos = this.vertices[vId].position;
+                var vPos = vertex.position;
                 var bbox = this._mesh.getBoundingInfo().boundingBox;
 
                 if (bbox.maximum.x - vPos.x < this.boundingBoxEpsilon || vPos.x - bbox.minimum.x > this.boundingBoxEpsilon)
@@ -313,10 +317,8 @@
                                 var deleted0: Array<boolean> = [];
                                 var deleted1: Array<boolean> = [];
 
-                                var i0 = t.vertices[j];
-                                var i1 = t.vertices[(j + 1) % 3];
-                                var v0 = this.vertices[i0];
-                                var v1 = this.vertices[i1];
+                                var v0 = t.vertices[j];
+                                var v1 = t.vertices[(j + 1) % 3];
 
                                 if (v0.isBorder !== v1.isBorder) continue;
 
@@ -329,29 +331,32 @@
 
                                 var delTr = [];
 
-                                if (this.isFlipped(v0, i1, p, deleted0, t.borderFactor, delTr)) continue;
-                                if (this.isFlipped(v1, i0, p, deleted1, t.borderFactor, delTr)) continue;
+                                if (this.isFlipped(v0, v1, p, deleted0, t.borderFactor, delTr)) continue;
+                                if (this.isFlipped(v1, v0, p, deleted1, t.borderFactor, delTr)) continue;
+
+                                if (deleted0.indexOf(true) < 0 || deleted1.indexOf(true) < 0)
+                                    continue;
+
+                                var uniqueArray = [];
+                                delTr.forEach(function (deletedT) {
+                                    if (uniqueArray.indexOf(deletedT) === -1) {
+                                        deletedT.deletePending = true;
+                                        uniqueArray.push(deletedT);
+                                    }
+                                });
 
-                                if (delTr.length == 2 || delTr[0] === delTr[1]) {
+                                if (uniqueArray.length % 2 != 0) {
                                     continue;
                                 }
 
-                                v0.normal = n;
-                                if (v0.uv)
-                                    v0.uv = uv;
-                                else if (v0.color)
-                                    v0.color = color;
                                 v0.q = v1.q.add(v0.q);
 
-                                if (deleted0.indexOf(true) < 0 || deleted1.indexOf(true) < 0) continue;
-
-                                if (p.equals(v0.position)) continue;
-                                v0.position = p;
+                                v0.updatePosition(p);
 
                                 var tStart = this.references.length;
 
-                                deletedTriangles = this.updateTriangles(v0.id, v0, deleted0, deletedTriangles);
-                                deletedTriangles = this.updateTriangles(v0.id, v1, deleted1, deletedTriangles);
+                                deletedTriangles = this.updateTriangles(v0, v0, deleted0, deletedTriangles);
+                                deletedTriangles = this.updateTriangles(v0, v1, deleted1, deletedTriangles);
 
                                 var tCount = this.references.length - tStart;
 
@@ -390,42 +395,55 @@
                 });
         }
 
-        private initWithMesh(mesh: Mesh, submeshIndex: number, callback: Function) {
-            if (!mesh) return;
+        private initWithMesh(submeshIndex: number, callback: Function, optimizeMesh?: boolean) {
 
             this.vertices = [];
             this.triangles = [];
 
-            this._mesh = mesh;
-            //It is assumed that a mesh has positions, normals and either uvs or colors.
             var positionData = this._mesh.getVerticesData(VertexBuffer.PositionKind);
-            var normalData = this._mesh.getVerticesData(VertexBuffer.NormalKind);
-            var uvs = this._mesh.getVerticesData(VertexBuffer.UVKind);
-            var colorsData = this._mesh.getVerticesData(VertexBuffer.ColorKind);
-            var indices = mesh.getIndices();
-            var submesh = mesh.subMeshes[submeshIndex];
+
+            var indices = this._mesh.getIndices();
+            var submesh = this._mesh.subMeshes[submeshIndex];
+
+            var findInVertices = (positionToSearch: Vector3) => {
+                if (optimizeMesh) {
+                    for (var ii = 0; ii < this.vertices.length; ++ii) {
+                        if (this.vertices[ii].position.equals(positionToSearch)) {
+                            return this.vertices[ii];
+                        }
+                    }
+                }
+                return null;
+            }
+
+            var vertexReferences: Array<number> = [];
 
             var vertexInit = (i) => {
                 var offset = i + submesh.verticesStart;
-                var vertex = new DecimationVertex(Vector3.FromArray(positionData, offset * 3), Vector3.FromArray(normalData, offset * 3), null, i);
-                if (this._mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                    vertex.uv = Vector2.FromArray(uvs, offset * 2);
-                } else if (this._mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
-                    vertex.color = Color4.FromArray(colorsData, offset * 4);
+                var position = Vector3.FromArray(positionData, offset * 3);
+
+                var vertex = findInVertices(position) || new DecimationVertex(position, this.vertices.length);
+                vertex.originalOffsets.push(offset);
+                if (vertex.id == this.vertices.length) {
+                    this.vertices.push(vertex);
                 }
-                this.vertices.push(vertex);
+                vertexReferences.push(vertex.id);
             };
             //var totalVertices = mesh.getTotalVertices();
             var totalVertices = submesh.verticesCount;
-            AsyncLoop.SyncAsyncForLoop(totalVertices, this.syncIterations, vertexInit,() => {
+            AsyncLoop.SyncAsyncForLoop(totalVertices,(this.syncIterations / 4) >> 0, vertexInit,() => {
 
                 var indicesInit = (i) => {
                     var offset = (submesh.indexStart / 3) + i;
                     var pos = (offset * 3);
-                    var i0 = indices[pos + 0] - submesh.verticesStart;
-                    var i1 = indices[pos + 1] - submesh.verticesStart;
-                    var i2 = indices[pos + 2] - submesh.verticesStart;
-                    var triangle = new DecimationTriangle([this.vertices[i0].id, this.vertices[i1].id, this.vertices[i2].id]);
+                    var i0 = indices[pos + 0];
+                    var i1 = indices[pos + 1];
+                    var i2 = indices[pos + 2];
+                    var v0: DecimationVertex = this.vertices[vertexReferences[i0 - submesh.verticesStart]];
+                    var v1: DecimationVertex = this.vertices[vertexReferences[i1 - submesh.verticesStart]];
+                    var v2: DecimationVertex = this.vertices[vertexReferences[i2 - submesh.verticesStart]];
+                    var triangle = new DecimationTriangle([v0, v1, v2]);
+                    triangle.originalOffset = pos;
                     this.triangles.push(triangle);
                 };
                 AsyncLoop.SyncAsyncForLoop(submesh.indexCount / 3, this.syncIterations, indicesInit,() => {
@@ -437,9 +455,9 @@
         private init(callback: Function) {
             var triangleInit1 = (i) => {
                 var t = this.triangles[i];
-                t.normal = Vector3.Cross(this.vertices[t.vertices[1]].position.subtract(this.vertices[t.vertices[0]].position), this.vertices[t.vertices[2]].position.subtract(this.vertices[t.vertices[0]].position)).normalize();
+                t.normal = Vector3.Cross(t.vertices[1].position.subtract(t.vertices[0].position), t.vertices[2].position.subtract(t.vertices[0].position)).normalize();
                 for (var j = 0; j < 3; j++) {
-                    this.vertices[t.vertices[j]].q.addArrayInPlace(QuadraticMatrix.DataFromNumbers(t.normal.x, t.normal.y, t.normal.z, -(Vector3.Dot(t.normal, this.vertices[t.vertices[0]].position))));
+                    t.vertices[j].q.addArrayInPlace(QuadraticMatrix.DataFromNumbers(t.normal.x, t.normal.y, t.normal.z, -(Vector3.Dot(t.normal, t.vertices[0].position))));
                 }
             };
             AsyncLoop.SyncAsyncForLoop(this.triangles.length, this.syncIterations, triangleInit1,() => {
@@ -447,12 +465,12 @@
                 var triangleInit2 = (i) => {
                     var t = this.triangles[i];
                     for (var j = 0; j < 3; ++j) {
-                        t.error[j] = this.calculateError(this.vertices[t.vertices[j]], this.vertices[t.vertices[(j + 1) % 3]]);
+                        t.error[j] = this.calculateError(t.vertices[j], t.vertices[(j + 1) % 3]);
                     }
                     t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]);
                 };
                 AsyncLoop.SyncAsyncForLoop(this.triangles.length, this.syncIterations, triangleInit2,() => {
-                    this.initialised = true;
+                    this.initialized = true;
                     callback();
                 });
             });
@@ -471,56 +489,44 @@
                 if (!this.triangles[i].deleted) {
                     t = this.triangles[i];
                     for (j = 0; j < 3; ++j) {
-                        this.vertices[t.vertices[j]].triangleCount = 1;
+                        t.vertices[j].triangleCount = 1;
                     }
                     newTriangles.push(t);
                 }
             }
 
-            var newVerticesOrder = [];
-
-            //compact vertices, get the IDs of the vertices used.
-            var dst = 0;
-            for (i = 0; i < this.vertices.length; ++i) {
-                if (this.vertices[i].triangleCount) {
-                    this.vertices[i].triangleStart = dst;
-                    this.vertices[dst].position = this.vertices[i].position;
-                    this.vertices[dst].normal = this.vertices[i].normal;
-                    this.vertices[dst].uv = this.vertices[i].uv;
-                    this.vertices[dst].color = this.vertices[i].color;
-                    newVerticesOrder.push(i);
-                    dst++;
-                }
-            }
-
-            for (i = 0; i < newTriangles.length; ++i) {
-                t = newTriangles[i];
-                for (j = 0; j < 3; ++j) {
-                    t.vertices[j] = this.vertices[t.vertices[j]].triangleStart;
-                }
-            }
-            this.vertices = this.vertices.slice(0, dst);
-
             var newPositionData = this._reconstructedMesh.getVerticesData(VertexBuffer.PositionKind) || [];
             var newNormalData = this._reconstructedMesh.getVerticesData(VertexBuffer.NormalKind) || [];
             var newUVsData = this._reconstructedMesh.getVerticesData(VertexBuffer.UVKind) || [];
             var newColorsData = this._reconstructedMesh.getVerticesData(VertexBuffer.ColorKind) || [];
 
-            for (i = 0; i < newVerticesOrder.length; ++i) {
-                newPositionData.push(this.vertices[i].position.x);
-                newPositionData.push(this.vertices[i].position.y);
-                newPositionData.push(this.vertices[i].position.z);
-                newNormalData.push(this.vertices[i].normal.x);
-                newNormalData.push(this.vertices[i].normal.y);
-                newNormalData.push(this.vertices[i].normal.z);
-                if (this.vertices[i].uv) {
-                    newUVsData.push(this.vertices[i].uv.x);
-                    newUVsData.push(this.vertices[i].uv.y);
-                } else if (this.vertices[i].color) {
-                    newColorsData.push(this.vertices[i].color.r);
-                    newColorsData.push(this.vertices[i].color.g);
-                    newColorsData.push(this.vertices[i].color.b);
-                    newColorsData.push(this.vertices[i].color.a);
+            var normalData = this._mesh.getVerticesData(VertexBuffer.NormalKind);
+            var uvs = this._mesh.getVerticesData(VertexBuffer.UVKind);
+            var colorsData = this._mesh.getVerticesData(VertexBuffer.ColorKind);
+
+            var vertexCount = 0;
+            for (i = 0; i < this.vertices.length; ++i) {
+                var vertex = this.vertices[i];
+                vertex.id = vertexCount;
+                if (vertex.triangleCount) {
+                    vertex.originalOffsets.forEach(function (originalOffset) {
+                        newPositionData.push(vertex.position.x);
+                        newPositionData.push(vertex.position.y);
+                        newPositionData.push(vertex.position.z);
+                        newNormalData.push(normalData[originalOffset * 3]);
+                        newNormalData.push(normalData[(originalOffset * 3) + 1]);
+                        newNormalData.push(normalData[(originalOffset * 3) + 2]);
+                        if (uvs && uvs.length) {
+                            newUVsData.push(uvs[(originalOffset * 2)]);
+                            newUVsData.push(uvs[(originalOffset * 2) + 1]);
+                        } else if (colorsData && colorsData.length) {
+                            newColorsData.push(colorsData[(originalOffset * 4)]);
+                            newColorsData.push(colorsData[(originalOffset * 4) + 1]);
+                            newColorsData.push(colorsData[(originalOffset * 4) + 2]);
+                            newColorsData.push(colorsData[(originalOffset * 4) + 3]);
+                        }
+                        ++vertexCount;
+                    });
                 }
             }
 
@@ -531,10 +537,16 @@
             this._reconstructedMesh.subMeshes = [];
 
             var newIndicesArray: Array<number> = this._reconstructedMesh.getIndices(); //[];
+            var originalIndices = this._mesh.getIndices();
             for (i = 0; i < newTriangles.length; ++i) {
-                newIndicesArray.push(newTriangles[i].vertices[0] + startingVertex);
-                newIndicesArray.push(newTriangles[i].vertices[1] + startingVertex);
-                newIndicesArray.push(newTriangles[i].vertices[2] + startingVertex);
+                var t = newTriangles[i];
+                //now get the new referencing point for each vertex
+                [0, 1, 2].forEach(function (idx) {
+                    var id = originalIndices[t.originalOffset + idx]
+                    var offset = t.vertices[idx].originalOffsets.indexOf(id);
+                    if (offset < 0) offset = 0;
+                    newIndicesArray.push(t.vertices[idx].id + offset + startingVertex);
+                });
             }
 
             //overwriting the old vertex buffers and indices.
@@ -554,7 +566,7 @@
                 submeshesArray.forEach(function (submesh) {
                     new SubMesh(submesh.materialIndex, submesh.verticesStart, submesh.verticesCount,/* 0, newPositionData.length/3, */submesh.indexStart, submesh.indexCount, submesh.getMesh());
                 });
-                var newSubmesh = new SubMesh(originalSubmesh.materialIndex, startingVertex, newVerticesOrder.length,/* 0, newPositionData.length / 3, */startingIndex, newTriangles.length * 3, this._reconstructedMesh);
+                var newSubmesh = new SubMesh(originalSubmesh.materialIndex, startingVertex, vertexCount,/* 0, newPositionData.length / 3, */startingIndex, newTriangles.length * 3, this._reconstructedMesh);
             }
         }
 
@@ -565,7 +577,7 @@
             this._reconstructedMesh.isVisible = false;
         }
 
-        private isFlipped(vertex1: DecimationVertex, index2: number, point: Vector3, deletedArray: Array<boolean>, borderFactor: number, delTr: Array<DecimationTriangle>): boolean {
+        private isFlipped(vertex1: DecimationVertex, vertex2: DecimationVertex, point: Vector3, deletedArray: Array<boolean>, borderFactor: number, delTr: Array<DecimationTriangle>): boolean {
 
             for (var i = 0; i < vertex1.triangleCount; ++i) {
                 var t = this.triangles[this.references[vertex1.triangleStart + i].triangleId];
@@ -573,18 +585,18 @@
 
                 var s = this.references[vertex1.triangleStart + i].vertexId;
 
-                var id1 = t.vertices[(s + 1) % 3];
-                var id2 = t.vertices[(s + 2) % 3];
+                var v1 = t.vertices[(s + 1) % 3];
+                var v2 = t.vertices[(s + 2) % 3];
 
-                if ((id1 === index2 || id2 === index2)/* && !this.isTriangleOnBoundingBox(t)*/) {
+                if ((v1 === vertex2 || v2 === vertex2)/* && !this.isTriangleOnBoundingBox(t)*/) {
                     deletedArray[i] = true;
                     delTr.push(t);
                     continue;
                 }
 
-                var d1 = this.vertices[id1].position.subtract(point);
+                var d1 = v1.position.subtract(point);
                 d1 = d1.normalize();
-                var d2 = this.vertices[id2].position.subtract(point);
+                var d2 = v2.position.subtract(point);
                 d2 = d2.normalize();
                 if (Math.abs(Vector3.Dot(d1, d2)) > 0.999) return true;
                 var normal = Vector3.Cross(d1, d2).normalize();
@@ -595,22 +607,22 @@
             return false;
         }
 
-        private updateTriangles(vertexId: number, vertex: DecimationVertex, deletedArray: Array<boolean>, deletedTriangles: number): number {
+        private updateTriangles(origVertex: DecimationVertex, vertex: DecimationVertex, deletedArray: Array<boolean>, deletedTriangles: number): number {
             var newDeleted = deletedTriangles;
             for (var i = 0; i < vertex.triangleCount; ++i) {
                 var ref = this.references[vertex.triangleStart + i];
                 var t = this.triangles[ref.triangleId];
                 if (t.deleted) continue;
-                if (deletedArray[i]) {
+                if (deletedArray[i] && t.deletePending) {
                     t.deleted = true;
                     newDeleted++;
                     continue;
                 }
-                t.vertices[ref.vertexId] = vertexId;
+                t.vertices[ref.vertexId] = origVertex;
                 t.isDirty = true;
-                t.error[0] = this.calculateError(this.vertices[t.vertices[0]], this.vertices[t.vertices[1]]) + (t.borderFactor / 2);
-                t.error[1] = this.calculateError(this.vertices[t.vertices[1]], this.vertices[t.vertices[2]]) + (t.borderFactor / 2);
-                t.error[2] = this.calculateError(this.vertices[t.vertices[2]], this.vertices[t.vertices[0]]) + (t.borderFactor / 2);
+                t.error[0] = this.calculateError(t.vertices[0], t.vertices[1]) + (t.borderFactor / 2);
+                t.error[1] = this.calculateError(t.vertices[1], t.vertices[2]) + (t.borderFactor / 2);
+                t.error[2] = this.calculateError(t.vertices[2], t.vertices[0]) + (t.borderFactor / 2);
                 t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]);
                 this.references.push(ref);
             }
@@ -628,14 +640,14 @@
                     var triangle = this.triangles[this.references[v.triangleStart + j].triangleId];
                     for (var ii = 0; ii < 3; ii++) {
                         var ofs = 0;
-                        var id = triangle.vertices[ii];
+                        var vv = triangle.vertices[ii];
                         while (ofs < vCount.length) {
-                            if (vId[ofs] === id) break;
+                            if (vId[ofs] === vv.id) break;
                             ++ofs;
                         }
                         if (ofs === vCount.length) {
                             vCount.push(1);
-                            vId.push(id);
+                            vId.push(vv.id);
                         } else {
                             vCount[ofs]++;
                         }
@@ -675,7 +687,7 @@
             for (i = 0; i < this.triangles.length; ++i) {
                 t = this.triangles[i];
                 for (j = 0; j < 3; ++j) {
-                    v = this.vertices[t.vertices[j]];
+                    v = t.vertices[j];
                     v.triangleCount++;
                 }
             }
@@ -692,7 +704,7 @@
             for (i = 0; i < this.triangles.length; ++i) {
                 t = this.triangles[i];
                 for (j = 0; j < 3; ++j) {
-                    v = this.vertices[t.vertices[j]];
+                    v = t.vertices[j];
                     newReferences[v.triangleStart + v.triangleCount] = new Reference(j, i);
                     v.triangleCount++;
                 }
@@ -727,14 +739,6 @@
                 pointResult.y = 1 / qDet * (q.det(0, 2, 3, 1, 5, 6, 2, 7, 8));
                 pointResult.z = -1 / qDet * (q.det(0, 1, 3, 1, 4, 6, 2, 5, 8));
                 error = this.vertexError(q, pointResult);
-                //TODO this should be correctly calculated
-                if (normalResult) {
-                    normalResult.copyFrom(vertex1.normal);
-                    if (vertex1.uv)
-                        uvResult.copyFrom(vertex1.uv);
-                    else if (vertex1.color)
-                        colorResult.copyFrom(vertex1.color);
-                }
             } else {
                 var p3 = (vertex1.position.add(vertex2.position)).divide(new Vector3(2, 2, 2));
                 //var norm3 = (vertex1.normal.add(vertex2.normal)).divide(new Vector3(2, 2, 2)).normalize();
@@ -745,29 +749,14 @@
                 if (error === error1) {
                     if (pointResult) {
                         pointResult.copyFrom(vertex1.position);
-                        normalResult.copyFrom(vertex1.normal);
-                        if (vertex1.uv)
-                            uvResult.copyFrom(vertex1.uv);
-                        else if (vertex1.color)
-                            colorResult.copyFrom(vertex1.color);
                     }
                 } else if (error === error2) {
                     if (pointResult) {
                         pointResult.copyFrom(vertex2.position);
-                        normalResult.copyFrom(vertex2.normal);
-                        if (vertex2.uv)
-                            uvResult.copyFrom(vertex2.uv);
-                        else if (vertex2.color)
-                            colorResult.copyFrom(vertex2.color);
                     }
                 } else {
                     if (pointResult) {
                         pointResult.copyFrom(p3);
-                        normalResult.copyFrom(vertex1.normal);
-                        if (vertex1.uv)
-                            uvResult.copyFrom(vertex1.uv);
-                        else if (vertex1.color)
-                            colorResult.copyFrom(vertex1.color);
                     }
                 }
             }

+ 1 - 0
Babylon/Mesh/babylon.subMesh.js

@@ -15,6 +15,7 @@ var BABYLON;
             this._id = mesh.subMeshes.length - 1;
             if (createBoundingBox) {
                 this.refreshBoundingInfo();
+                mesh.computeWorldMatrix(true);
             }
         }
         SubMesh.prototype.getBoundingInfo = function () {

+ 3 - 2
Babylon/Mesh/babylon.subMesh.ts

@@ -24,6 +24,7 @@
 
             if (createBoundingBox) {
                 this.refreshBoundingInfo();
+                mesh.computeWorldMatrix(true);
             }
         }
 
@@ -67,9 +68,9 @@
             var extend;
 
             if (this.indexStart === 0 && this.indexCount === indices.length) {
-                extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
+                extend = Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
             } else {
-                extend = BABYLON.Tools.ExtractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount);
+                extend = Tools.ExtractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount);
             }
             this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
         }

+ 0 - 1
Babylon/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -1,6 +1,5 @@
 module BABYLON {
     declare var CANNON;
-    declare var window;
 
     export class CannonJSPlugin implements IPhysicsEnginePlugin {
         public checkWithEpsilon: (value: number) => number;

+ 0 - 2
Babylon/Physics/babylon.physicsEngine.ts

@@ -1,6 +1,4 @@
 module BABYLON {
-    declare var CANNON;
-
     export interface IPhysicsEnginePlugin {
         initialize(iterations?: number);
         setGravity(gravity: Vector3): void;

+ 39 - 0
Babylon/PostProcess/babylon.colorCorrectionPostProcess.js

@@ -0,0 +1,39 @@
+//
+//  This post-process allows the modification of rendered colors by using
+//  a 'look-up table' (LUT). This effect is also called Color Grading.
+// 
+//  The object needs to be provided an url to a texture containing the color
+//  look-up table: the texture must be 256 pixels wide and 16 pixels high.
+//  Use an image editing software to tweak the LUT to match your needs.
+// 
+//  For an example of a color LUT, see here:
+//      http://udn.epicgames.com/Three/rsrc/Three/ColorGrading/RGBTable16x1.png
+//  For explanations on color grading, see here:
+//      http://udn.epicgames.com/Three/ColorGrading.html
+//
+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 ColorCorrectionPostProcess = (function (_super) {
+        __extends(ColorCorrectionPostProcess, _super);
+        function ColorCorrectionPostProcess(name, colorTableUrl, ratio, camera, samplingMode, engine, reusable) {
+            var _this = this;
+            _super.call(this, name, 'colorCorrection', null, ['colorTable'], ratio, camera, samplingMode, engine, reusable);
+            this._colorTableTexture = new BABYLON.Texture(colorTableUrl, camera.getScene(), true, false, BABYLON.Texture.TRILINEAR_SAMPLINGMODE);
+            this._colorTableTexture.anisotropicFilteringLevel = 1;
+            this._colorTableTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+            this._colorTableTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+            this.onApply = function (effect) {
+                effect.setTexture("colorTable", _this._colorTableTexture);
+            };
+        }
+        return ColorCorrectionPostProcess;
+    })(BABYLON.PostProcess);
+    BABYLON.ColorCorrectionPostProcess = ColorCorrectionPostProcess;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.colorCorrectionPostProcess.js.map

+ 33 - 0
Babylon/PostProcess/babylon.colorCorrectionPostProcess.ts

@@ -0,0 +1,33 @@
+//
+//  This post-process allows the modification of rendered colors by using
+//  a 'look-up table' (LUT). This effect is also called Color Grading.
+// 
+//  The object needs to be provided an url to a texture containing the color
+//  look-up table: the texture must be 256 pixels wide and 16 pixels high.
+//  Use an image editing software to tweak the LUT to match your needs.
+// 
+//  For an example of a color LUT, see here:
+//      http://udn.epicgames.com/Three/rsrc/Three/ColorGrading/RGBTable16x1.png
+//  For explanations on color grading, see here:
+//      http://udn.epicgames.com/Three/ColorGrading.html
+//
+
+module BABYLON {
+    export class ColorCorrectionPostProcess extends PostProcess {
+
+        private _colorTableTexture: Texture;
+
+        constructor(name: string, colorTableUrl: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, 'colorCorrection', null, ['colorTable'], ratio, camera, samplingMode, engine, reusable);
+
+            this._colorTableTexture = new Texture(colorTableUrl, camera.getScene(), true, false, Texture.TRILINEAR_SAMPLINGMODE);
+            this._colorTableTexture.anisotropicFilteringLevel = 1;
+            this._colorTableTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._colorTableTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+
+            this.onApply = (effect: Effect) => {
+                effect.setTexture("colorTable", this._colorTableTexture);
+            };
+        }
+    }
+}

+ 1 - 2
Babylon/PostProcess/babylon.oculusDistortionCorrectionPostProcess.ts

@@ -24,8 +24,7 @@
             this._postProcessScaleFactor = cameraSettings.PostProcessScaleFactor;
             this._lensCenterOffset = cameraSettings.LensCenterOffset;
 
-
-           this.onSizeChanged = () => {
+            this.onSizeChanged = () => {
                 this.aspectRatio = this.width * .5 / this.height;
                 this._scaleIn = new BABYLON.Vector2(2, 2 / this.aspectRatio);
                 this._scaleFactor = new BABYLON.Vector2(.5 * (1 / this._postProcessScaleFactor), .5 * (1 / this._postProcessScaleFactor) * this.aspectRatio);

+ 6 - 1
Babylon/PostProcess/babylon.postProcess.js

@@ -58,7 +58,12 @@ var BABYLON;
                 this.onActivate(camera);
             }
             // Clear
-            this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
+            if (this.clearColor) {
+                this._engine.clear(this.clearColor, true, true);
+            }
+            else {
+                this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
+            }
             if (this._reusable) {
                 this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;
             }

+ 6 - 2
Babylon/PostProcess/babylon.postProcess.ts

@@ -7,6 +7,7 @@
         public width = -1;
         public height = -1;
         public renderTargetSamplingMode: number;
+        public clearColor: Color4;
 
         private _camera: Camera;
         private _scene: Scene;
@@ -74,7 +75,6 @@
                 if (this.onSizeChanged) {
                     this.onSizeChanged();
                 }
-
             }
 
             this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
@@ -84,7 +84,11 @@
             }
 
             // Clear
-            this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
+            if (this.clearColor) {
+                this._engine.clear(this.clearColor, true, true);
+            } else {
+                this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
+            }
 
             if (this._reusable) {
                 this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;

+ 0 - 1
Babylon/PostProcess/babylon.postProcessManager.ts

@@ -85,7 +85,6 @@
             if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
                 return;
             }
-
             var engine = this._scene.getEngine();
 
             for (var index = 0; index < postProcessesTakenIndices.length; index++) {

+ 32 - 4
Babylon/PostProcess/babylon.ssaoRenderingPipeline.js

@@ -12,7 +12,7 @@ var BABYLON;
          * @constructor
          * @param {string} name - The rendering pipeline name
          * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
+         * @param {any} ratio - The size of the postprocesses. Can be a number shared between passes or an object for more precision: { ssaoRatio: 0.5, combineRatio: 1.0 }
          * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
          */
         function SSAORenderingPipeline(name, scene, ratio, cameras) {
@@ -44,6 +44,30 @@ var BABYLON;
             * @type {string}
             */
             this.SSAOCombineRenderEffect = "SSAOCombineRenderEffect";
+            /**
+            * The output strength of the SSAO post-process. Default value is 1.0.
+            * @type {number}
+            */
+            this.totalStrength = 1.0;
+            /**
+            * The radius around the analyzed pixel used by the SSAO post-process. Default value is 0.0002
+            * @type {number}
+            */
+            this.radius = 0.0002;
+            /**
+            * Related to fallOff, used to interpolate SSAO samples (first interpolate function input) based on the occlusion difference of each pixel
+            * Must not be equal to fallOff and superior to fallOff.
+            * Default value is 0.0075
+            * @type {number}
+            */
+            this.area = 0.0075;
+            /**
+            * Related to area, used to interpolate SSAO samples (second interpolate function input) based on the occlusion difference of each pixel
+            * Must not be equal to area and inferior to area.
+            * Default value is 0.0002
+            * @type {number}
+            */
+            this.fallOff = 0.0002;
             this._firstUpdate = true;
             this._scene = scene;
             // Set up assets
@@ -53,8 +77,8 @@ var BABYLON;
             var combineRatio = ratio.combineRatio || ratio;
             this._originalColorPostProcess = new BABYLON.PassPostProcess("SSAOOriginalSceneColor", combineRatio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
             this._createSSAOPostProcess(ssaoRatio);
-            this._blurHPostProcess = new BABYLON.BlurPostProcess("SSAOBlurH", new BABYLON.Vector2(2.0, 0.0), 1.3, ssaoRatio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
-            this._blurVPostProcess = new BABYLON.BlurPostProcess("SSAOBlurV", new BABYLON.Vector2(0.0, 2.0), 1.3, ssaoRatio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._blurHPostProcess = new BABYLON.BlurPostProcess("SSAOBlurH", new BABYLON.Vector2(2.0, 0.0), 2.0, ssaoRatio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._blurVPostProcess = new BABYLON.BlurPostProcess("SSAOBlurV", new BABYLON.Vector2(0.0, 2.0), 2.0, ssaoRatio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
             this._createSSAOCombinePostProcess(combineRatio);
             // Set up pipeline
             this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), this.SSAOOriginalSceneColorEffect, function () {
@@ -161,7 +185,7 @@ var BABYLON;
                 -0.0271
             ];
             var samplesFactor = 1.0 / 16.0;
-            this._ssaoPostProcess = new BABYLON.PostProcess("ssao", "ssao", ["sampleSphere", "samplesFactor", "randTextureTiles"], ["randomSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false);
+            this._ssaoPostProcess = new BABYLON.PostProcess("ssao", "ssao", ["sampleSphere", "samplesFactor", "randTextureTiles", "totalStrength", "radius", "area", "fallOff"], ["randomSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false);
             this._ssaoPostProcess.onApply = function (effect) {
                 if (_this._firstUpdate) {
                     effect.setArray3("sampleSphere", sampleSphere);
@@ -169,6 +193,10 @@ var BABYLON;
                     effect.setFloat("randTextureTiles", 4.0 / ratio);
                     _this._firstUpdate = false;
                 }
+                effect.setFloat("totalStrength", _this.totalStrength);
+                effect.setFloat("radius", _this.radius);
+                effect.setFloat("area", _this.area);
+                effect.setFloat("fallOff", _this.fallOff);
                 effect.setTexture("textureSampler", _this._depthTexture);
                 effect.setTexture("randomSampler", _this._randomTexture);
             };

+ 37 - 4
Babylon/PostProcess/babylon.ssaoRenderingPipeline.ts

@@ -28,6 +28,34 @@
         */
         public SSAOCombineRenderEffect: string = "SSAOCombineRenderEffect";
 
+        /**
+        * The output strength of the SSAO post-process. Default value is 1.0.
+        * @type {number}
+        */
+        public totalStrength: number = 1.0;
+
+        /**
+        * The radius around the analyzed pixel used by the SSAO post-process. Default value is 0.0002
+        * @type {number}
+        */
+        public radius: number = 0.0002;
+
+        /**
+        * Related to fallOff, used to interpolate SSAO samples (first interpolate function input) based on the occlusion difference of each pixel
+        * Must not be equal to fallOff and superior to fallOff.
+        * Default value is 0.0075
+        * @type {number}
+        */
+        public area: number = 0.0075;
+
+        /**
+        * Related to area, used to interpolate SSAO samples (second interpolate function input) based on the occlusion difference of each pixel
+        * Must not be equal to area and inferior to area.
+        * Default value is 0.0002
+        * @type {number}
+        */
+        public fallOff: number = 0.0002;
+
         private _scene: Scene;
         private _depthTexture: RenderTargetTexture;
         private _randomTexture: DynamicTexture;
@@ -44,7 +72,7 @@
          * @constructor
          * @param {string} name - The rendering pipeline name
          * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
+         * @param {any} ratio - The size of the postprocesses. Can be a number shared between passes or an object for more precision: { ssaoRatio: 0.5, combineRatio: 1.0 }
          * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
          */
         constructor(name: string, scene: Scene, ratio: any, cameras?: Camera[]) {
@@ -61,8 +89,8 @@
 
             this._originalColorPostProcess = new PassPostProcess("SSAOOriginalSceneColor", combineRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
             this._createSSAOPostProcess(ssaoRatio);
-            this._blurHPostProcess = new BlurPostProcess("SSAOBlurH", new Vector2(2.0, 0.0), 1.3, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
-            this._blurVPostProcess = new BlurPostProcess("SSAOBlurV", new Vector2(0.0, 2.0), 1.3, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._blurHPostProcess = new BlurPostProcess("SSAOBlurH", new Vector2(2.0, 0.0), 2.0, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._blurVPostProcess = new BlurPostProcess("SSAOBlurV", new Vector2(0.0, 2.0), 2.0, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
             this._createSSAOCombinePostProcess(combineRatio);
 
             // Set up pipeline
@@ -135,7 +163,7 @@
             ];
             var samplesFactor = 1.0 / 16.0;
 
-            this._ssaoPostProcess = new PostProcess("ssao", "ssao", ["sampleSphere", "samplesFactor", "randTextureTiles"],
+            this._ssaoPostProcess = new PostProcess("ssao", "ssao", ["sampleSphere", "samplesFactor", "randTextureTiles", "totalStrength", "radius", "area", "fallOff"],
                                                     ["randomSampler"],
                                                     ratio, null, Texture.BILINEAR_SAMPLINGMODE,
                                                     this._scene.getEngine(), false);
@@ -148,6 +176,11 @@
                     this._firstUpdate = false;
                 }
 
+                effect.setFloat("totalStrength", this.totalStrength);
+                effect.setFloat("radius", this.radius);
+                effect.setFloat("area", this.area);
+                effect.setFloat("fallOff", this.fallOff);
+
                 effect.setTexture("textureSampler", this._depthTexture);
                 effect.setTexture("randomSampler", this._randomTexture);
             };

+ 49 - 7
Babylon/PostProcess/babylon.volumetricLightScatteringPostProcess.js

@@ -65,16 +65,24 @@ var BABYLON;
             var defines = [];
             var attribs = [BABYLON.VertexBuffer.PositionKind];
             var material = subMesh.getMaterial();
+            var needUV = false;
             // Render this.mesh as default
             if (mesh === this.mesh) {
                 defines.push("#define BASIC_RENDER");
+                defines.push("#define NEED_UV");
+                needUV = true;
             }
             // Alpha test
             if (material) {
                 if (material.needAlphaTesting() || mesh === this.mesh)
                     defines.push("#define ALPHATEST");
-                if (material.opacityTexture !== undefined)
+                if (material.opacityTexture !== undefined) {
                     defines.push("#define OPACITY");
+                    if (material.opacityTexture.getAlphaFromRGB)
+                        defines.push("#define OPACITYRGB");
+                    if (!needUV)
+                        defines.push("#define NEED_UV");
+                }
                 if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
                     attribs.push(BABYLON.VertexBuffer.UVKind);
                     defines.push("#define UV1");
@@ -103,7 +111,7 @@ var BABYLON;
             var join = defines.join("\n");
             if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
-                this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect({ vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" }, attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "far"], ["diffuseSampler", "opacitySampler"], join);
+                this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect({ vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" }, attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "opacityLevel"], ["diffuseSampler", "opacitySampler"], join);
             }
             return this._volumetricLightScatteringPass.isReady();
         };
@@ -180,10 +188,13 @@ var BABYLON;
                     if (material && (mesh === _this.mesh || material.needAlphaTesting() || material.opacityTexture !== undefined)) {
                         var alphaTexture = material.getAlphaTestTexture();
                         _this._volumetricLightScatteringPass.setTexture("diffuseSampler", alphaTexture);
-                        if (_this.mesh.material && alphaTexture)
+                        if (alphaTexture) {
                             _this._volumetricLightScatteringPass.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
-                        if (material.opacityTexture !== undefined)
+                        }
+                        if (material.opacityTexture !== undefined) {
                             _this._volumetricLightScatteringPass.setTexture("opacitySampler", material.opacityTexture);
+                            _this._volumetricLightScatteringPass.setFloat("opacityLevel", material.opacityTexture.level);
+                        }
                     }
                     // Bones
                     if (mesh.useBones) {
@@ -195,7 +206,7 @@ var BABYLON;
             };
             // Render target texture callbacks
             var savedSceneClearColor;
-            var sceneClearColor = new BABYLON.Color3(0.0, 0.0, 0.0);
+            var sceneClearColor = new BABYLON.Color4(0.0, 0.0, 0.0, 1.0);
             this._volumetricLightScatteringRTT.onBeforeRender = function () {
                 savedSceneClearColor = scene.clearColor;
                 scene.clearColor = sceneClearColor;
@@ -204,15 +215,46 @@ var BABYLON;
                 scene.clearColor = savedSceneClearColor;
             };
             this._volumetricLightScatteringRTT.customRenderFunction = function (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes) {
+                var engine = scene.getEngine();
                 var index;
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                     renderSubMesh(opaqueSubMeshes.data[index]);
                 }
+                engine.setAlphaTesting(true);
                 for (index = 0; index < alphaTestSubMeshes.length; index++) {
                     renderSubMesh(alphaTestSubMeshes.data[index]);
                 }
-                for (index = 0; index < transparentSubMeshes.length; index++) {
-                    renderSubMesh(transparentSubMeshes.data[index]);
+                engine.setAlphaTesting(false);
+                if (transparentSubMeshes.length) {
+                    for (index = 0; index < transparentSubMeshes.length; index++) {
+                        var submesh = transparentSubMeshes.data[index];
+                        submesh._alphaIndex = submesh.getMesh().alphaIndex;
+                        submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(scene.activeCamera.position).length();
+                    }
+                    var sortedArray = transparentSubMeshes.data.slice(0, transparentSubMeshes.length);
+                    sortedArray.sort(function (a, b) {
+                        // Alpha index first
+                        if (a._alphaIndex > b._alphaIndex) {
+                            return 1;
+                        }
+                        if (a._alphaIndex < b._alphaIndex) {
+                            return -1;
+                        }
+                        // Then distance to camera
+                        if (a._distanceToCamera < b._distanceToCamera) {
+                            return 1;
+                        }
+                        if (a._distanceToCamera > b._distanceToCamera) {
+                            return -1;
+                        }
+                        return 0;
+                    });
+                    // Render sub meshes
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                    for (index = 0; index < sortedArray.length; index++) {
+                        renderSubMesh(sortedArray[index]);
+                    }
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
                 }
             };
         };

+ 57 - 9
Babylon/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

@@ -76,10 +76,13 @@
             var defines = [];
             var attribs = [VertexBuffer.PositionKind];
             var material: any = subMesh.getMaterial();
+            var needUV: boolean = false;
 
             // Render this.mesh as default
             if (mesh === this.mesh) {
                 defines.push("#define BASIC_RENDER");
+                defines.push("#define NEED_UV");
+                needUV = true;
             }
 
             // Alpha test
@@ -87,8 +90,13 @@
                 if (material.needAlphaTesting() || mesh === this.mesh)
                     defines.push("#define ALPHATEST");
 
-                if (material.opacityTexture !== undefined)
+                if (material.opacityTexture !== undefined) {
                     defines.push("#define OPACITY");
+                    if (material.opacityTexture.getAlphaFromRGB)
+                        defines.push("#define OPACITYRGB");
+                    if (!needUV)
+                        defines.push("#define NEED_UV");
+                }
 
                 if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
                     attribs.push(VertexBuffer.UVKind);
@@ -124,7 +132,7 @@
                 this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect(
                     { vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" },
                     attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "far"],
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "opacityLevel"],
                     ["diffuseSampler", "opacitySampler"], join);
             }
 
@@ -220,11 +228,15 @@
                     if (material && (mesh === this.mesh || material.needAlphaTesting() || material.opacityTexture !== undefined)) {
                         var alphaTexture = material.getAlphaTestTexture();
                         this._volumetricLightScatteringPass.setTexture("diffuseSampler", alphaTexture);
-                        if (this.mesh.material && alphaTexture)
+
+                        if (alphaTexture) {
                             this._volumetricLightScatteringPass.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
+                        }
 
-                        if (material.opacityTexture !== undefined)
+                        if (material.opacityTexture !== undefined) {
                             this._volumetricLightScatteringPass.setTexture("opacitySampler", material.opacityTexture);
+                            this._volumetricLightScatteringPass.setFloat("opacityLevel", material.opacityTexture.level);
+                        }
                     }
 
                     // Bones
@@ -239,8 +251,8 @@
             };
 
             // Render target texture callbacks
-            var savedSceneClearColor: Color3;
-            var sceneClearColor = new Color3(0.0, 0.0, 0.0);
+            var savedSceneClearColor: Color4;
+            var sceneClearColor = new Color4(0.0, 0.0, 0.0, 1.0);
 
             this._volumetricLightScatteringRTT.onBeforeRender = (): void => {
                 savedSceneClearColor = scene.clearColor;
@@ -252,18 +264,54 @@
             };
 
             this._volumetricLightScatteringRTT.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
-                var index;
+                var engine = scene.getEngine();
+                var index: number;
 
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                     renderSubMesh(opaqueSubMeshes.data[index]);
                 }
 
+                engine.setAlphaTesting(true);
                 for (index = 0; index < alphaTestSubMeshes.length; index++) {
                     renderSubMesh(alphaTestSubMeshes.data[index]);
                 }
+                engine.setAlphaTesting(false);
+
+                if (transparentSubMeshes.length) {
+                    // Sort sub meshes
+                    for (index = 0; index < transparentSubMeshes.length; index++) {
+                        var submesh = transparentSubMeshes.data[index];
+                        submesh._alphaIndex = submesh.getMesh().alphaIndex;
+                        submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(scene.activeCamera.position).length();
+                    }
 
-                for (index = 0; index < transparentSubMeshes.length; index++) {
-                    renderSubMesh(transparentSubMeshes.data[index]);
+                    var sortedArray = transparentSubMeshes.data.slice(0, transparentSubMeshes.length);
+                    sortedArray.sort((a, b) => {
+                        // Alpha index first
+                        if (a._alphaIndex > b._alphaIndex) {
+                            return 1;
+                        }
+                        if (a._alphaIndex < b._alphaIndex) {
+                            return -1;
+                        }
+
+                        // Then distance to camera
+                        if (a._distanceToCamera < b._distanceToCamera) {
+                            return 1;
+                        }
+                        if (a._distanceToCamera > b._distanceToCamera) {
+                            return -1;
+                        }
+
+                        return 0;
+                    });
+
+                    // Render sub meshes
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                    for (index = 0; index < sortedArray.length; index++) {
+                        renderSubMesh(sortedArray[index]);
+                    }
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
                 }
             };
         }

+ 37 - 0
Babylon/Shaders/colorCorrection.fragment.fx

@@ -0,0 +1,37 @@
+#ifdef GL_ES
+precision highp float;
+#endif
+
+// samplers
+uniform sampler2D textureSampler;	// screen render
+uniform sampler2D colorTable;		// color table with modified colors
+
+// varyings
+varying vec2 vUV;
+
+// constants
+const float SLICE_COUNT = 16.0;		// how many slices in the color cube; 1 slice = 1 pixel
+// it means the image is 256x16 pixels
+
+vec4 sampleAs3DTexture(sampler2D texture, vec3 uv, float width) {
+	float sliceSize = 1.0 / width;              // space of 1 slice
+	float slicePixelSize = sliceSize / width;           // space of 1 pixel
+	float sliceInnerSize = slicePixelSize * (width - 1.0);  // space of width pixels
+	float zSlice0 = min(floor(uv.z * width), width - 1.0);
+	float zSlice1 = min(zSlice0 + 1.0, width - 1.0);
+	float xOffset = slicePixelSize * 0.5 + uv.x * sliceInnerSize;
+	float s0 = xOffset + (zSlice0 * sliceSize);
+	float s1 = xOffset + (zSlice1 * sliceSize);
+	vec4 slice0Color = texture2D(texture, vec2(s0, uv.y));
+	vec4 slice1Color = texture2D(texture, vec2(s1, uv.y));
+	float zOffset = mod(uv.z * width, 1.0);
+	vec4 result = mix(slice0Color, slice1Color, zOffset);
+	return result;
+}
+
+void main(void)
+{
+	vec4 screen_color = texture2D(textureSampler, vUV);
+	gl_FragColor = sampleAs3DTexture(colorTable, screen_color.rgb, SLICE_COUNT);
+
+}

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

@@ -216,7 +216,8 @@ float unpackHalf(vec2 color)
 float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)
 {
 	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
-	vec2 uv = 0.5 * depth.xy + vec2(0.5, 0.5);
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
 
 	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
 	{
@@ -235,7 +236,8 @@ float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float dark
 float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias)
 {
 	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
-	vec2 uv = 0.5 * depth.xy + vec2(0.5, 0.5);
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
 
 	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
 	{
@@ -251,36 +253,38 @@ float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, flo
 	poissonDisk[3] = vec2(0.34495938, 0.29387760);
 
 	// Poisson Sampling
-	if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] / mapSize)) + bias  <  depth.z) visibility -= 0.25;
-	if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] / mapSize)) + bias  <  depth.z) visibility -= 0.25;
-	if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] / mapSize)) + bias  <  depth.z) visibility -= 0.25;
-	if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] / mapSize)) + bias  <  depth.z) visibility -= 0.25;
+	float biasedDepth = depth.z - bias;
+
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] / mapSize)) < biasedDepth) visibility -= 0.25;
 
 	return visibility;
 }
 
 // Thanks to http://devmaster.net/
-float ChebychevInequality(vec2 moments, float t, float bias)
-{
-	if (t <= moments.x)
-	{
-		return 0.0;
-	}
-
-	float variance = moments.y - (moments.x * moments.x);
-	variance = max(variance, 0.02 + bias);
+float linstep(float low, float high, float v) {
+	return clamp((v - low) / (high - low), 0.0, 1.0);
+}
 
-	float d = t - moments.x;
+float ChebychevInequality(vec2 moments, float compare, float bias)
+{
+	float p = smoothstep(compare - bias, compare, moments.x);
+	float variance = max(moments.y - moments.x * moments.x, 0.02);
+	float d = compare - moments.x;
+	float p_max = linstep(0.2, 1.0, variance / (variance + d * d));
 
-	return clamp(variance / (variance + d * d) - 0.05, 0.0, 1.0);
+	return clamp(max(p, p_max), 0.0, 1.0);
 }
 
 float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias)
 {
 	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
-	vec2 uv = 0.5 * depth.xy + vec2(0.5, 0.5);
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
 
-	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z > 1.0)
+	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0)
 	{
 		return 1.0;
 	}

+ 2 - 2
Babylon/Shaders/depth.vertex.fx

@@ -24,7 +24,7 @@ uniform mat4 viewProjection;
 uniform mat4 mBones[BonesPerMesh];
 #endif
 
-#ifdef ALPHATEST
+#if defined(ALPHATEST) || defined(NEED_UV)
 varying vec2 vUV;
 uniform mat4 diffuseMatrix;
 #ifdef UV1
@@ -54,7 +54,7 @@ void main(void)
 	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
 #endif
 
-#ifdef ALPHATEST
+#if defined(ALPHATEST) || defined(BASIC_RENDER)
 #ifdef UV1
 	vUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));
 #endif

+ 3 - 3
Babylon/Shaders/shadowMap.fragment.fx

@@ -35,15 +35,15 @@ void main(void)
 	if (texture2D(diffuseSampler, vUV).a < 0.4)
 		discard;
 #endif
-
-#ifdef VSM
 	float depth = vPosition.z / vPosition.w;
+	depth = depth * 0.5 + 0.5;
 
+#ifdef VSM
 	float moment1 = depth;
 	float moment2 = moment1 * moment1;
 
 	gl_FragColor = vec4(packHalf(moment1), packHalf(moment2));
 #else
-	gl_FragColor = pack(vPosition.z / vPosition.w);
+	gl_FragColor = pack(depth);
 #endif
 }

+ 6 - 6
Babylon/Shaders/sprites.vertex.fx

@@ -3,7 +3,7 @@ precision highp float;
 #endif
 
 // Attributes
-attribute vec3 position;
+attribute vec4 position;
 attribute vec4 options;
 attribute vec4 cellInfo;
 attribute vec4 color;
@@ -22,15 +22,15 @@ varying float fFogDistance;
 #endif
 
 void main(void) {	
-	vec3 viewPos = (view * vec4(position, 1.0)).xyz; 
-	vec3 cornerPos;
+	vec3 viewPos = (view * vec4(position.xyz, 1.0)).xyz; 
+	vec2 cornerPos;
 	
-	float angle = options.x;
-	float size = options.y;
+	float angle = position.w;
+	vec2 size = vec2(options.x, options.y);
 	vec2 offset = options.zw;
 	vec2 uvScale = textureInfos.xy;
 
-	cornerPos = vec3(offset.x - 0.5, offset.y  - 0.5, 0.) * size;
+	cornerPos = vec2(offset.x - 0.5, offset.y  - 0.5) * size;
 
 	// Rotate
 	vec3 rotatedCorner;

+ 8 - 7
Babylon/Shaders/ssao.fragment.fx

@@ -11,10 +11,15 @@ uniform float randTextureTiles;
 uniform float samplesFactor;
 uniform vec3 sampleSphere[16];
 
+uniform float totalStrength;
+uniform float radius;
+uniform float area;
+uniform float fallOff;
+
 varying vec2 vUV;
 
-const vec2 offset1 = vec2(0.0, 0.01);
-const vec2 offset2 = vec2(0.01, 0.0);
+const vec2 offset1 = vec2(0.0, 0.001);
+const vec2 offset2 = vec2(0.001, 0.0);
 
 vec3 normalFromDepth(const float depth, const vec2 coords) {
 	float depth1 = texture2D(textureSampler, coords + offset1).r;
@@ -31,11 +36,7 @@ vec3 normalFromDepth(const float depth, const vec2 coords) {
 
 void main(void)
 {
-	const float totalStrength = 1.0;
 	const float base = 0.2;
-	const float area = 0.0075;
-	const float fallOff = 0.000001;
-	const float radius = 0.0005;
 
 	vec3 random = texture2D(randomSampler, vUV * randTextureTiles).rgb;
 	float depth = texture2D(textureSampler, vUV).r;
@@ -52,7 +53,7 @@ void main(void)
 	for (int i = 0; i < SAMPLES; i++)
 	{
 		ray = radiusDepth * reflect(sampleSphere[i], random);
-		hemiRay = position + dot(ray, normal) * ray;
+		hemiRay = position + sign(dot(ray, normal)) * ray;
 
 		occlusionDepth = texture2D(textureSampler, clamp(hemiRay.xy, 0.0, 1.0)).r;
 		difference = depth - occlusionDepth;

+ 23 - 6
Babylon/Shaders/volumetricLightScatteringPass.fragment.fx

@@ -12,11 +12,12 @@ uniform sampler2D diffuseSampler;
 
 #if defined(OPACITY)
 uniform sampler2D opacitySampler;
+uniform float opacityLevel;
 #endif
 
 void main(void)
 {
-#if defined(ALPHATEST) || defined(OPACITY) || defined(BASIC_RENDER)
+#if defined(ALPHATEST) || defined(BASIC_RENDER)
 	vec4 diffuseColor = texture2D(diffuseSampler, vUV);
 #endif
 
@@ -25,14 +26,30 @@ void main(void)
 		discard;
 #endif
 
-#ifdef BASIC_RENDER
 #ifdef OPACITY
-	gl_FragColor = diffuseColor * texture2D(opacitySampler, vUV);
-#else
-	gl_FragColor = diffuseColor;
-#endif
+	vec4 opacityColor = texture2D(opacitySampler, vUV);
+	float alpha = 1.0;
+
+	#ifdef OPACITYRGB
+	opacityColor.rgb = opacityColor.rgb * vec3(0.3, 0.59, 0.11);
+	alpha *= (opacityColor.x + opacityColor.y + opacityColor.z) * opacityLevel;
+	#else
+	alpha *= opacityColor.a * opacityLevel;
+	#endif
+
+	#if defined(BASIC_RENDER)
+	gl_FragColor = vec4(diffuseColor.rgb, alpha);
+	#else
+	gl_FragColor = vec4(0.0, 0.0, 0.0, alpha);
+	#endif
+
+	gl_FragColor.a = alpha;
 #else
+	#ifndef BASIC_RENDER
 	gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+	#else
+	gl_FragColor = diffuseColor;
+	#endif
 #endif
 
 }

+ 13 - 1
Babylon/Sprites/babylon.sprite.js

@@ -4,7 +4,8 @@ var BABYLON;
         function Sprite(name, manager) {
             this.name = name;
             this.color = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);
-            this.size = 1.0;
+            this.width = 1.0;
+            this.height = 1.0;
             this.angle = 0;
             this.cellIndex = 0;
             this.invertU = 0;
@@ -22,6 +23,17 @@ var BABYLON;
             this._manager.sprites.push(this);
             this.position = BABYLON.Vector3.Zero();
         }
+        Object.defineProperty(Sprite.prototype, "size", {
+            get: function () {
+                return this.width;
+            },
+            set: function (value) {
+                this.width = value;
+                this.height = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Sprite.prototype.playAnimation = function (from, to, loop, delay) {
             this._fromIndex = from;
             this._toIndex = to;

+ 11 - 1
Babylon/Sprites/babylon.sprite.ts

@@ -2,7 +2,8 @@
     export class Sprite {
         public position: Vector3;
         public color = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);
-        public size = 1.0;
+        public width = 1.0;
+        public height = 1.0;
         public angle = 0;
         public cellIndex = 0;
         public invertU = 0;
@@ -20,6 +21,15 @@
         private _manager: SpriteManager;
         private _time = 0;
 
+        public get size(): number {
+            return this.width;
+        }
+
+        public set size(value: number) {
+            this.width = value;
+            this.height = value;
+        }
+
         constructor(public name: string, manager: SpriteManager) {
             this._manager = manager;
 

+ 22 - 22
Babylon/Sprites/babylon.spriteManager.js

@@ -1,24 +1,23 @@
 var BABYLON;
 (function (BABYLON) {
     var SpriteManager = (function () {
-        function SpriteManager(name, imgUrl, capacity, cellSize, scene, epsilon) {
+        function SpriteManager(name, imgUrl, capacity, cellSize, scene, epsilon, samplingMode) {
+            if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
             this.name = name;
             this.cellSize = cellSize;
             this.sprites = new Array();
             this.renderingGroupId = 0;
             this.fogEnabled = true;
-            this._vertexDeclaration = [3, 4, 4, 4];
-            this._vertexStrideSize = 15 * 4; // 15 floats per sprite (x, y, z, angle, size, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color)
+            this._vertexDeclaration = [4, 4, 4, 4];
+            this._vertexStrideSize = 16 * 4; // 15 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color)
             this._capacity = capacity;
-            this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false);
+            this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false, samplingMode);
             this._spriteTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._spriteTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._epsilon = epsilon === undefined ? 0.01 : epsilon;
             this._scene = scene;
             this._scene.spriteManagers.push(this);
             // VBO
-            this._vertexDeclaration = [3, 4, 4, 4];
-            this._vertexStrideSize = 15 * 4;
             this._vertexBuffer = scene.getEngine().createDynamicVertexBuffer(capacity * this._vertexStrideSize * 4);
             var indices = [];
             var index = 0;
@@ -38,32 +37,33 @@ var BABYLON;
             this._effectFog = this._scene.getEngine().createEffect("sprites", ["position", "options", "cellInfo", "color"], ["view", "projection", "textureInfos", "alphaTest", "vFogInfos", "vFogColor"], ["diffuseSampler"], "#define FOG");
         }
         SpriteManager.prototype._appendSpriteVertex = function (index, sprite, offsetX, offsetY, rowSize) {
-            var arrayOffset = index * 15;
-            if (offsetX == 0)
+            var arrayOffset = index * 16;
+            if (offsetX === 0)
                 offsetX = this._epsilon;
-            else if (offsetX == 1)
+            else if (offsetX === 1)
                 offsetX = 1 - this._epsilon;
-            if (offsetY == 0)
+            if (offsetY === 0)
                 offsetY = this._epsilon;
-            else if (offsetY == 1)
+            else if (offsetY === 1)
                 offsetY = 1 - this._epsilon;
             this._vertices[arrayOffset] = sprite.position.x;
             this._vertices[arrayOffset + 1] = sprite.position.y;
             this._vertices[arrayOffset + 2] = sprite.position.z;
             this._vertices[arrayOffset + 3] = sprite.angle;
-            this._vertices[arrayOffset + 4] = sprite.size;
-            this._vertices[arrayOffset + 5] = offsetX;
-            this._vertices[arrayOffset + 6] = offsetY;
-            this._vertices[arrayOffset + 7] = sprite.invertU ? 1 : 0;
-            this._vertices[arrayOffset + 8] = sprite.invertV ? 1 : 0;
+            this._vertices[arrayOffset + 4] = sprite.width;
+            this._vertices[arrayOffset + 5] = sprite.height;
+            this._vertices[arrayOffset + 6] = offsetX;
+            this._vertices[arrayOffset + 7] = offsetY;
+            this._vertices[arrayOffset + 8] = sprite.invertU ? 1 : 0;
+            this._vertices[arrayOffset + 9] = sprite.invertV ? 1 : 0;
             var offset = (sprite.cellIndex / rowSize) >> 0;
-            this._vertices[arrayOffset + 9] = sprite.cellIndex - offset * rowSize;
-            this._vertices[arrayOffset + 10] = offset;
+            this._vertices[arrayOffset + 10] = sprite.cellIndex - offset * rowSize;
+            this._vertices[arrayOffset + 11] = offset;
             // Color
-            this._vertices[arrayOffset + 11] = sprite.color.r;
-            this._vertices[arrayOffset + 12] = sprite.color.g;
-            this._vertices[arrayOffset + 13] = sprite.color.b;
-            this._vertices[arrayOffset + 14] = sprite.color.a;
+            this._vertices[arrayOffset + 12] = sprite.color.r;
+            this._vertices[arrayOffset + 13] = sprite.color.g;
+            this._vertices[arrayOffset + 14] = sprite.color.b;
+            this._vertices[arrayOffset + 15] = sprite.color.a;
         };
         SpriteManager.prototype.render = function () {
             // Check

+ 27 - 27
Babylon/Sprites/babylon.spriteManager.ts

@@ -11,27 +11,26 @@
 
         private _scene: Scene;
 
-        private _vertexDeclaration = [3, 4, 4, 4];
-        private _vertexStrideSize = 15 * 4; // 15 floats per sprite (x, y, z, angle, size, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color)
-        private _vertexBuffer: WebGLBuffer
+        private _vertexDeclaration = [4, 4, 4, 4];
+        private _vertexStrideSize = 16 * 4; // 15 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color)
+        private _vertexBuffer: WebGLBuffer;
         private _indexBuffer: WebGLBuffer;
         private _vertices: Float32Array;
         private _effectBase: Effect;
         private _effectFog: Effect;
 
-        constructor(public name: string, imgUrl: string, capacity: number, public cellSize: number, scene: Scene, epsilon?: number) {
+        constructor(public name: string, imgUrl: string, capacity: number, public cellSize: number, scene: Scene, epsilon?: number, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
             this._capacity = capacity;
-            this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false);
-            this._spriteTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
-            this._spriteTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+            this._spriteTexture = new Texture(imgUrl, scene, true, false, samplingMode);
+            this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._spriteTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+
             this._epsilon = epsilon === undefined ? 0.01 : epsilon;
 
             this._scene = scene;
             this._scene.spriteManagers.push(this);
 
             // VBO
-            this._vertexDeclaration = [3, 4, 4, 4];
-            this._vertexStrideSize = 15 * 4;
             this._vertexBuffer = scene.getEngine().createDynamicVertexBuffer(capacity * this._vertexStrideSize * 4);
 
             var indices = [];
@@ -62,35 +61,36 @@
         }
 
         private _appendSpriteVertex(index: number, sprite: Sprite, offsetX: number, offsetY: number, rowSize: number): void {
-            var arrayOffset = index * 15;
+            var arrayOffset = index * 16;
 
-            if (offsetX == 0)
+            if (offsetX === 0)
                 offsetX = this._epsilon;
-            else if (offsetX == 1)
+            else if (offsetX === 1)
                 offsetX = 1 - this._epsilon;
 
-            if (offsetY == 0)
+            if (offsetY === 0)
                 offsetY = this._epsilon;
-            else if (offsetY == 1)
+            else if (offsetY === 1)
                 offsetY = 1 - this._epsilon;
 
             this._vertices[arrayOffset] = sprite.position.x;
             this._vertices[arrayOffset + 1] = sprite.position.y;
             this._vertices[arrayOffset + 2] = sprite.position.z;
             this._vertices[arrayOffset + 3] = sprite.angle;
-            this._vertices[arrayOffset + 4] = sprite.size;
-            this._vertices[arrayOffset + 5] = offsetX;
-            this._vertices[arrayOffset + 6] = offsetY;
-            this._vertices[arrayOffset + 7] = sprite.invertU ? 1 : 0;
-            this._vertices[arrayOffset + 8] = sprite.invertV ? 1 : 0;
+            this._vertices[arrayOffset + 4] = sprite.width;
+            this._vertices[arrayOffset + 5] = sprite.height;
+            this._vertices[arrayOffset + 6] = offsetX;
+            this._vertices[arrayOffset + 7] = offsetY;
+            this._vertices[arrayOffset + 8] = sprite.invertU ? 1 : 0;
+            this._vertices[arrayOffset + 9] = sprite.invertV ? 1 : 0;
             var offset = (sprite.cellIndex / rowSize) >> 0;
-            this._vertices[arrayOffset + 9] = sprite.cellIndex - offset * rowSize;
-            this._vertices[arrayOffset + 10] = offset;
+            this._vertices[arrayOffset + 10] = sprite.cellIndex - offset * rowSize;
+            this._vertices[arrayOffset + 11] = offset;
             // Color
-            this._vertices[arrayOffset + 11] = sprite.color.r;
-            this._vertices[arrayOffset + 12] = sprite.color.g;
-            this._vertices[arrayOffset + 13] = sprite.color.b;
-            this._vertices[arrayOffset + 14] = sprite.color.a;
+            this._vertices[arrayOffset + 12] = sprite.color.r;
+            this._vertices[arrayOffset + 13] = sprite.color.g;
+            this._vertices[arrayOffset + 14] = sprite.color.b;
+            this._vertices[arrayOffset + 15] = sprite.color.a;
         }
 
         public render(): void {
@@ -154,9 +154,9 @@
             engine.setColorWrite(true);
             effect.setBool("alphaTest", false);
 
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+            engine.setAlphaMode(Engine.ALPHA_COMBINE);
             engine.draw(true, 0, max * 6);
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+            engine.setAlphaMode(Engine.ALPHA_DISABLE);
         }
 
         public dispose(): void {

+ 18 - 16
Babylon/Tools/babylon.sceneSerializer.js

@@ -46,6 +46,15 @@ var BABYLON;
         serializationObject.power = fresnelParameter.power;
         return serializationObject;
     };
+    var appendAnimations = function (source, destination) {
+        if (source.animations) {
+            destination.animations = [];
+            for (var animationIndex = 0; animationIndex < source.animations.length; animationIndex++) {
+                var animation = source.animations[animationIndex];
+                destination.animations.push(serializeAnimation(animation));
+            }
+        }
+    };
     var serializeCamera = function (camera) {
         var serializationObject = {};
         serializationObject.name = camera.name;
@@ -106,6 +115,9 @@ var BABYLON;
             serializationObject.alpha = arcCamera.alpha;
             serializationObject.beta = arcCamera.beta;
             serializationObject.radius = arcCamera.radius;
+            if (arcCamera.target && arcCamera.target.id) {
+                serializationObject.lockedTargetId = arcCamera.target.id;
+            }
         }
         else if (camera instanceof BABYLON.FollowCamera) {
             var followCam = camera;
@@ -123,6 +135,9 @@ var BABYLON;
         if (camera['speed'] !== undefined) {
             serializationObject.speed = camera['speed'];
         }
+        if (camera['target'] && camera['target'] instanceof BABYLON.Vector3) {
+            serializationObject.target = camera['target'].asArray();
+        }
         // Target
         if (camera['rotation'] && camera['rotation'] instanceof BABYLON.Vector3) {
             serializationObject.rotation = camera['rotation'].asArray();
@@ -131,12 +146,8 @@ var BABYLON;
         if (camera['lockedTarget'] && camera['lockedTarget'].id) {
             serializationObject.lockedTargetId = camera['lockedTarget'].id;
         }
-        if (camera['checkCollisions'] !== undefined) {
-            serializationObject.checkCollisions = camera['checkCollisions'];
-        }
-        if (camera['applyGravity'] !== undefined) {
-            serializationObject.applyGravity = camera['applyGravity'];
-        }
+        serializationObject.checkCollisions = camera['checkCollisions'] || false;
+        serializationObject.applyGravity = camera['applyGravity'] || false;
         if (camera['ellipsoid']) {
             serializationObject.ellipsoid = camera['ellipsoid'].asArray();
         }
@@ -146,15 +157,6 @@ var BABYLON;
         serializationObject.layerMask = camera.layerMask;
         return serializationObject;
     };
-    var appendAnimations = function (source, destination) {
-        if (source.animations) {
-            destination.animations = [];
-            for (var animationIndex = 0; animationIndex < source.animations.length; animationIndex++) {
-                var animation = source.animations[animationIndex];
-                destination.animations.push(serializeAnimation(animation));
-            }
-        }
-    };
     var serializeAnimation = function (animation) {
         var serializationObject = {};
         serializationObject.name = animation.name;
@@ -653,7 +655,7 @@ var BABYLON;
             serializationObject.geometries.vertexData = [];
             serializedGeometries = [];
             var geometries = scene.getGeometries();
-            for (var index = 0; index < geometries.length; index++) {
+            for (index = 0; index < geometries.length; index++) {
                 var geometry = geometries[index];
                 if (geometry.isReady()) {
                     serializeGeometry(geometry, serializationObject.geometries);

+ 54 - 51
Babylon/Tools/babylon.sceneSerializer.ts

@@ -1,7 +1,7 @@
 module BABYLON {
 
     var serializeLight = (light: Light): any => {
-        var serializationObject:any = {};
+        var serializationObject: any = {};
         serializationObject.name = light.name;
         serializationObject.id = light.id;
         serializationObject.tags = Tags.GetTags(light);
@@ -52,8 +52,19 @@
         return serializationObject;
     }
 
+    var appendAnimations = (source: IAnimatable, destination: any): any => {
+        if (source.animations) {
+            destination.animations = [];
+            for (var animationIndex = 0; animationIndex < source.animations.length; animationIndex++) {
+                var animation = source.animations[animationIndex];
+
+                destination.animations.push(serializeAnimation(animation));
+            }
+        }
+    };
+
     var serializeCamera = (camera: Camera): any => {
-        var serializationObject:any = {};
+        var serializationObject: any = {};
         serializationObject.name = camera.name;
         serializationObject.tags = Tags.GetTags(camera);
         serializationObject.id = camera.id;
@@ -105,6 +116,9 @@
             serializationObject.alpha = arcCamera.alpha;
             serializationObject.beta = arcCamera.beta;
             serializationObject.radius = arcCamera.radius;
+            if (arcCamera.target && arcCamera.target.id) {
+                serializationObject.lockedTargetId = arcCamera.target.id;
+            }
         } else if (camera instanceof FollowCamera) {
             var followCam = <FollowCamera> camera;
             serializationObject.radius = followCam.radius;
@@ -122,6 +136,10 @@
             serializationObject.speed = camera['speed'];
         }
 
+        if (camera['target'] && camera['target'] instanceof Vector3) {
+            serializationObject.target = camera['target'].asArray();
+        }
+
         // Target
         if (camera['rotation'] && camera['rotation'] instanceof Vector3) {
             serializationObject.rotation = camera['rotation'].asArray();
@@ -132,12 +150,8 @@
             serializationObject.lockedTargetId = camera['lockedTarget'].id;
         }
 
-        if (camera['checkCollisions'] !== undefined) {
-            serializationObject.checkCollisions = camera['checkCollisions'];
-        }
-        if (camera['applyGravity'] !== undefined) {
-            serializationObject.applyGravity = camera['applyGravity'];
-        }
+        serializationObject.checkCollisions = camera['checkCollisions'] || false;
+        serializationObject.applyGravity = camera['applyGravity'] || false;
 
         if (camera['ellipsoid']) {
             serializationObject.ellipsoid = camera['ellipsoid'].asArray();
@@ -152,19 +166,8 @@
         return serializationObject;
     };
 
-    var appendAnimations = (source: IAnimatable, destination: any): any => {
-        if (source.animations) {
-            destination.animations = [];
-            for (var animationIndex = 0; animationIndex < source.animations.length; animationIndex++) {
-                var animation = source.animations[animationIndex];
-
-                destination.animations.push(serializeAnimation(animation));
-            }
-        }
-    };
-
     var serializeAnimation = (animation: Animation): any => {
-        var serializationObject:any = {};
+        var serializationObject: any = {};
 
         serializationObject.name = animation.name;
         serializationObject.property = animation.targetProperty;
@@ -178,18 +181,18 @@
         for (var index = 0; index < keys.length; index++) {
             var animationKey = keys[index];
 
-            var key:any = {};
+            var key: any = {};
             key.frame = animationKey.frame;
 
             switch (dataType) {
-            case Animation.ANIMATIONTYPE_FLOAT:
-                key.values = [animationKey.value];
-                break;
-            case Animation.ANIMATIONTYPE_QUATERNION:
-            case Animation.ANIMATIONTYPE_MATRIX:
-            case Animation.ANIMATIONTYPE_VECTOR3:
-                key.values = animationKey.value.asArray();
-                break;
+                case Animation.ANIMATIONTYPE_FLOAT:
+                    key.values = [animationKey.value];
+                    break;
+                case Animation.ANIMATIONTYPE_QUATERNION:
+                case Animation.ANIMATIONTYPE_MATRIX:
+                case Animation.ANIMATIONTYPE_VECTOR3:
+                    key.values = animationKey.value.asArray();
+                    break;
             }
 
             serializationObject.keys.push(key);
@@ -199,7 +202,7 @@
     };
 
     var serializeMultiMaterial = (material: MultiMaterial): any => {
-        var serializationObject:any = {};
+        var serializationObject: any = {};
 
         serializationObject.name = material.name;
         serializationObject.id = material.id;
@@ -221,7 +224,7 @@
     };
 
     var serializeMaterial = (material: StandardMaterial): any => {
-        var serializationObject:any = {};
+        var serializationObject: any = {};
 
         serializationObject.name = material.name;
 
@@ -285,7 +288,7 @@
     };
 
     var serializeTexture = (texture: BaseTexture): any => {
-        var serializationObject:any = {};
+        var serializationObject: any = {};
 
         if (!texture.name) {
             return null;
@@ -345,8 +348,8 @@
         return serializationObject;
     };
 
-    var serializeSkeleton = (skeleton:Skeleton): any => {
-        var serializationObject:any = {};
+    var serializeSkeleton = (skeleton: Skeleton): any => {
+        var serializationObject: any = {};
 
         serializationObject.name = skeleton.name;
         serializationObject.id = skeleton.id;
@@ -356,7 +359,7 @@
         for (var index = 0; index < skeleton.bones.length; index++) {
             var bone = skeleton.bones[index];
 
-            var serializedBone:any = {
+            var serializedBone: any = {
                 parentBoneIndex: bone.getParent() ? skeleton.bones.indexOf(bone.getParent()) : -1,
                 name: bone.name,
                 matrix: bone.getLocalMatrix().toArray()
@@ -371,8 +374,8 @@
         return serializationObject;
     };
 
-    var serializeParticleSystem = (particleSystem:ParticleSystem): any => {
-        var serializationObject:any = {};
+    var serializeParticleSystem = (particleSystem: ParticleSystem): any => {
+        var serializationObject: any = {};
 
         serializationObject.emitterId = particleSystem.emitter.id;
         serializationObject.capacity = particleSystem.getCapacity();
@@ -404,8 +407,8 @@
         return serializationObject;
     };
 
-    var serializeLensFlareSystem = (lensFlareSystem:LensFlareSystem):any => {
-        var serializationObject:any = {};
+    var serializeLensFlareSystem = (lensFlareSystem: LensFlareSystem): any => {
+        var serializationObject: any = {};
 
         serializationObject.emitterId = lensFlareSystem.getEmitter().id;
         serializationObject.borderLimit = lensFlareSystem.borderLimit;
@@ -426,8 +429,8 @@
         return serializationObject;
     };
 
-    var serializeShadowGenerator = (light: Light):any => {
-        var serializationObject:any = {};
+    var serializeShadowGenerator = (light: Light): any => {
+        var serializationObject: any = {};
         var shadowGenerator = light.getShadowGenerator();
 
         serializationObject.lightId = light.id;
@@ -607,8 +610,8 @@
         return serializationObject;
     };
 
-    var serializeMesh = (mesh: Mesh, serializationScene: any):any => {
-        var serializationObject:any = {};
+    var serializeMesh = (mesh: Mesh, serializationScene: any): any => {
+        var serializationObject: any = {};
 
         serializationObject.name = mesh.name;
         serializationObject.id = mesh.id;
@@ -690,12 +693,12 @@
             serializationObject.physicsRestitution = mesh.getPhysicsRestitution();
 
             switch (mesh.getPhysicsImpostor()) {
-            case PhysicsEngine.BoxImpostor:
-                serializationObject.physicsImpostor = 1;
-                break;
-            case PhysicsEngine.SphereImpostor:
-                serializationObject.physicsImpostor = 2;
-                break;
+                case PhysicsEngine.BoxImpostor:
+                    serializationObject.physicsImpostor = 1;
+                    break;
+                case PhysicsEngine.SphereImpostor:
+                    serializationObject.physicsImpostor = 2;
+                    break;
             }
         }
 
@@ -728,7 +731,7 @@
 
     export class SceneSerializer {
         public static Serialize(scene: Scene): any {
-            var serializationObject:any = {};
+            var serializationObject: any = {};
 
             // Scene
             serializationObject.useDelayedTextureLoading = scene.useDelayedTextureLoading;
@@ -798,7 +801,7 @@
 
             serializedGeometries = [];
             var geometries = scene.getGeometries();
-            for (var index = 0; index < geometries.length; index++) {
+            for (index = 0; index < geometries.length; index++) {
                 var geometry = geometries[index];
 
                 if (geometry.isReady()) {

+ 92 - 0
Babylon/Tools/babylon.smartCollection.js

@@ -0,0 +1,92 @@
+var BABYLON;
+(function (BABYLON) {
+    var SmartCollection = (function () {
+        function SmartCollection(capacity) {
+            if (capacity === void 0) { capacity = 10; }
+            this.count = 0;
+            this._initialCapacity = capacity;
+            this.items = {};
+            this._keys = new Array(this._initialCapacity);
+        }
+        SmartCollection.prototype.add = function (key, item) {
+            if (this.items[key] != undefined) {
+                return -1;
+            }
+            this.items[key] = item;
+            //literal keys are always strings, but we keep source type of key in _keys array
+            this._keys[this.count++] = key;
+            if (this.count > this._keys.length) {
+                this._keys.length *= 2;
+            }
+            return this.count;
+        };
+        SmartCollection.prototype.remove = function (key) {
+            if (this.items[key] == undefined) {
+                return -1;
+            }
+            return this.removeItemOfIndex(this.indexOf(key));
+        };
+        SmartCollection.prototype.removeItemOfIndex = function (index) {
+            if (index < this.count && index > -1) {
+                delete this.items[this._keys[index]];
+                while (index < this.count) {
+                    this._keys[index] = this._keys[index + 1];
+                    index++;
+                }
+            }
+            else {
+                return -1;
+            }
+            return --this.count;
+        };
+        SmartCollection.prototype.indexOf = function (key) {
+            for (var i = 0; i !== this.count; i++) {
+                if (this._keys[i] === key) {
+                    return i;
+                }
+            }
+            return -1;
+        };
+        SmartCollection.prototype.item = function (key) {
+            return this.items[key];
+        };
+        SmartCollection.prototype.getAllKeys = function () {
+            if (this.count > 0) {
+                var keys = new Array(this.count);
+                for (var i = 0; i < this.count; i++) {
+                    keys[i] = this._keys[i];
+                }
+                return keys;
+            }
+            else {
+                return undefined;
+            }
+        };
+        SmartCollection.prototype.getKeyByIndex = function (index) {
+            if (index < this.count && index > -1) {
+                return this._keys[index];
+            }
+            else {
+                return undefined;
+            }
+        };
+        SmartCollection.prototype.getItemByIndex = function (index) {
+            if (index < this.count && index > -1) {
+                return this.items[this._keys[index]];
+            }
+            else {
+                return undefined;
+            }
+        };
+        SmartCollection.prototype.empty = function () {
+            if (this.count > 0) {
+                this.count = 0;
+                this.items = {};
+                this._keys = new Array(this._initialCapacity);
+            }
+        };
+        return SmartCollection;
+    })();
+    BABYLON.SmartCollection = SmartCollection;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.smartCollection.js.map

+ 106 - 0
Babylon/Tools/babylon.smartCollection.ts

@@ -0,0 +1,106 @@
+module BABYLON {
+    export class SmartCollection {
+        public count = 0;
+        public items: any;
+
+        private _keys: string[];
+        private _initialCapacity: number;
+
+        constructor(capacity: number = 10) {
+            this._initialCapacity = capacity;
+            this.items = {};
+            this._keys = new Array(this._initialCapacity);
+        }
+
+        public add(key: any, item: any): number {
+            if (this.items[key] != undefined) {
+                return -1;
+            }
+            this.items[key] = item;
+            
+            //literal keys are always strings, but we keep source type of key in _keys array
+            this._keys[this.count++] = key;
+            if (this.count > this._keys.length) {
+                this._keys.length *= 2;
+            }
+
+            return this.count;
+        }
+
+        public remove(key: any): number {
+            if (this.items[key] == undefined) {
+                return -1;
+            }
+
+            return this.removeItemOfIndex(this.indexOf(key));
+        }
+
+        public removeItemOfIndex(index: number): number {
+            if (index < this.count && index > -1) {
+                delete this.items[this._keys[index]];
+                    
+                //here, shifting by hand is better optimised than .splice
+                while (index < this.count) {
+                    this._keys[index] = this._keys[index + 1]; index++;
+                }
+            }
+            else {
+                return -1;
+            }
+
+            return --this.count;
+        }
+
+        public indexOf(key: any): number {
+            for (var i = 0; i !== this.count; i++) {
+                if (this._keys[i] === key) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        public item(key: any): any {
+            return this.items[key];
+        }
+
+        public getAllKeys(): any[] {
+            if (this.count > 0) {
+                var keys = new Array(this.count);
+                for (var i = 0; i < this.count; i++) {
+                    keys[i] = this._keys[i];
+                }
+                return keys;
+            }
+            else {
+                return undefined;
+            }
+        }
+
+        public getKeyByIndex(index: number): any {
+            if (index < this.count && index > -1) {
+                return this._keys[index];
+            }
+            else {
+                return undefined;
+            }
+        }
+
+        public getItemByIndex(index: number): any {
+            if (index < this.count && index > -1) {
+                return this.items[this._keys[index]];
+            }
+            else {
+                return undefined;
+            }
+        }
+
+        public empty(): void {
+            if (this.count > 0) {
+                this.count = 0;
+                this.items = {};
+                this._keys = new Array(this._initialCapacity);
+            }
+        }
+    }
+} 

+ 16 - 9
Babylon/babylon.engine.js

@@ -546,7 +546,7 @@ var BABYLON;
         });
         Object.defineProperty(Engine, "Version", {
             get: function () {
-                return "2.0.0";
+                return "2.1.0 alpha";
             },
             enumerable: true,
             configurable: true
@@ -1337,11 +1337,6 @@ var BABYLON;
             var texture = this._gl.createTexture();
             width = BABYLON.Tools.GetExponantOfTwo(width, this._caps.maxTextureSize);
             height = BABYLON.Tools.GetExponantOfTwo(height, this._caps.maxTextureSize);
-            this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
-            var filters = getSamplingParameters(samplingMode, generateMipMaps, this._gl);
-            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, filters.mag);
-            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, filters.min);
-            this._gl.bindTexture(this._gl.TEXTURE_2D, null);
             this._activeTexturesCache = [];
             texture._baseWidth = width;
             texture._baseHeight = height;
@@ -1351,9 +1346,17 @@ var BABYLON;
             texture.generateMipMaps = generateMipMaps;
             texture.references = 1;
             texture.samplingMode = samplingMode;
+            this.updateTextureSamplingMode(samplingMode, texture);
             this._loadedTexturesCache.push(texture);
             return texture;
         };
+        Engine.prototype.updateTextureSamplingMode = function (samplingMode, texture) {
+            var filters = getSamplingParameters(samplingMode, texture.generateMipMaps, this._gl);
+            this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
+            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, filters.mag);
+            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, filters.min);
+            this._gl.bindTexture(this._gl.TEXTURE_2D, null);
+        };
         Engine.prototype.updateDynamicTexture = function (texture, canvas, invertY) {
             this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
             this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, invertY ? 1 : 0);
@@ -1636,9 +1639,13 @@ var BABYLON;
         };
         Engine.prototype._setAnisotropicLevel = function (key, texture) {
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
-            if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== texture.anisotropicFilteringLevel) {
-                this._gl.texParameterf(key, anisotropicFilterExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(texture.anisotropicFilteringLevel, this._caps.maxAnisotropy));
-                texture._cachedAnisotropicFilteringLevel = texture.anisotropicFilteringLevel;
+            var value = texture.anisotropicFilteringLevel;
+            if (texture.getInternalTexture().samplingMode === BABYLON.Texture.NEAREST_SAMPLINGMODE) {
+                value = 1;
+            }
+            if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== value) {
+                this._gl.texParameterf(key, anisotropicFilterExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(value, this._caps.maxAnisotropy));
+                texture._cachedAnisotropicFilteringLevel = value;
             }
         };
         Engine.prototype.readPixels = function (x, y, width, height) {

+ 21 - 12
Babylon/babylon.engine.ts

@@ -431,7 +431,7 @@
         }
 
         public static get Version(): string {
-            return "2.0.0";
+            return "2.1.0 alpha";
         }
 
         // Updatable statics so stick with vars here
@@ -1617,14 +1617,6 @@
             width = Tools.GetExponantOfTwo(width, this._caps.maxTextureSize);
             height = Tools.GetExponantOfTwo(height, this._caps.maxTextureSize);
 
-            this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
-
-            var filters = getSamplingParameters(samplingMode, generateMipMaps, this._gl);
-
-            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, filters.mag);
-            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, filters.min);
-            this._gl.bindTexture(this._gl.TEXTURE_2D, null);
-
             this._activeTexturesCache = [];
             texture._baseWidth = width;
             texture._baseHeight = height;
@@ -1635,11 +1627,23 @@
             texture.references = 1;
             texture.samplingMode = samplingMode;
 
+            this.updateTextureSamplingMode(samplingMode, texture);
+
             this._loadedTexturesCache.push(texture);
 
             return texture;
         }
 
+        public updateTextureSamplingMode(samplingMode: number, texture: WebGLTexture): void {
+            var filters = getSamplingParameters(samplingMode, texture.generateMipMaps, this._gl);
+
+            this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
+
+            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, filters.mag);
+            this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, filters.min);
+            this._gl.bindTexture(this._gl.TEXTURE_2D, null);
+        }
+
         public updateDynamicTexture(texture: WebGLTexture, canvas: HTMLCanvasElement, invertY: boolean): void {
             this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
             this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, invertY ? 1 : 0);
@@ -1976,10 +1980,15 @@
 
         public _setAnisotropicLevel(key: number, texture: BaseTexture) {
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
+            var value = texture.anisotropicFilteringLevel;
+
+            if (texture.getInternalTexture().samplingMode === Texture.NEAREST_SAMPLINGMODE) {
+                value = 1;
+            }
 
-            if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== texture.anisotropicFilteringLevel) {
-                this._gl.texParameterf(key, anisotropicFilterExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(texture.anisotropicFilteringLevel, this._caps.maxAnisotropy));
-                texture._cachedAnisotropicFilteringLevel = texture.anisotropicFilteringLevel;
+            if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== value) {
+                this._gl.texParameterf(key, anisotropicFilterExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(value, this._caps.maxAnisotropy));
+                texture._cachedAnisotropicFilteringLevel = value;
             }
         }
 

+ 2 - 0
Babylon/babylon.mixins.ts

@@ -15,6 +15,8 @@ interface Window {
     oRequestAnimationFrame(func: any): any;
     WebGLRenderingContext: WebGLRenderingContext;
     MSGesture: MSGesture;
+    CANNON: any;
+    SIMD: any;
 }
 
 interface HTMLURL {

+ 9 - 1
Babylon/babylon.node.js

@@ -16,6 +16,7 @@ var BABYLON;
             this._isEnabled = true;
             this._isReady = true;
             this._currentRenderId = -1;
+            this._parentRenderId = -1;
             this.name = name;
             this.id = name;
             this._scene = scene;
@@ -52,7 +53,14 @@ var BABYLON;
             return true;
         };
         Node.prototype.isSynchronizedWithParent = function () {
-            return this.parent ? this.parent._currentRenderId <= this._currentRenderId : true;
+            if (!this.parent) {
+                return true;
+            }
+            if (this._parentRenderId !== this.parent._currentRenderId) {
+                return false;
+            }
+            this._parentRenderId = this.parent._currentRenderId;
+            return this.parent._currentRenderId <= this._currentRenderId && this.parent.isSynchronized();
         };
         Node.prototype.isSynchronized = function (updateCache) {
             var check = this.hasNewParent();

+ 12 - 1
Babylon/babylon.node.ts

@@ -17,6 +17,7 @@
         private _isEnabled = true;
         private _isReady = true;
         public _currentRenderId = -1;
+        private _parentRenderId = -1;
 
         public _waitingParentId: string;
 
@@ -75,7 +76,17 @@
         }
 
         public isSynchronizedWithParent(): boolean {
-            return this.parent ? this.parent._currentRenderId <= this._currentRenderId : true;
+            if (!this.parent) {
+                return true;
+            }
+
+            if (this._parentRenderId !== this.parent._currentRenderId) {
+                return false;
+            }
+
+            this._parentRenderId = this.parent._currentRenderId;
+
+            return this.parent._currentRenderId <= this._currentRenderId && this.parent.isSynchronized();
         }
 
         public isSynchronized(updateCache?: boolean): boolean {

+ 85 - 19
Babylon/babylon.scene.js

@@ -102,6 +102,7 @@ var BABYLON;
             this._proceduralTextures = new Array();
             this.soundTracks = new Array();
             this._audioEnabled = true;
+            this._headphone = false;
             this._totalVertices = 0;
             this._activeVertices = 0;
             this._activeParticles = 0;
@@ -507,10 +508,7 @@ var BABYLON;
             var now = BABYLON.Tools.Now;
             var delay = now - this._animationStartDate;
             for (var index = 0; index < this._activeAnimatables.length; index++) {
-                if (!this._activeAnimatables[index]._animate(delay)) {
-                    this._activeAnimatables.splice(index, 1);
-                    index--;
-                }
+                this._activeAnimatables[index]._animate(delay);
             }
         };
         // Matrix
@@ -529,6 +527,57 @@ var BABYLON;
             this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
         };
         // Methods
+        Scene.prototype.addMesh = function (newMesh) {
+            var position = this.meshes.push(newMesh);
+            if (this.onNewMeshAdded) {
+                this.onNewMeshAdded(newMesh, position, this);
+            }
+        };
+        Scene.prototype.removeMesh = function (toRemove) {
+            var index = this.meshes.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.meshes.splice(index, 1);
+            }
+            if (this.onMeshRemoved) {
+                this.onMeshRemoved(toRemove);
+            }
+            return index;
+        };
+        Scene.prototype.removeLight = function (toRemove) {
+            var index = this.lights.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.lights.splice(index, 1);
+            }
+            if (this.onLightRemoved) {
+                this.onLightRemoved(toRemove);
+            }
+            return index;
+        };
+        Scene.prototype.removeCamera = function (toRemove) {
+            var index = this.cameras.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.cameras.splice(index, 1);
+            }
+            if (this.onCameraRemoved) {
+                this.onCameraRemoved(toRemove);
+            }
+            return index;
+        };
+        Scene.prototype.addLight = function (newLight) {
+            var position = this.lights.push(newLight);
+            if (this.onNewLightAdded) {
+                this.onNewLightAdded(newLight, position, this);
+            }
+        };
+        Scene.prototype.addCamera = function (newCamera) {
+            var position = this.cameras.push(newCamera);
+            if (this.onNewCameraAdded) {
+                this.onNewCameraAdded(newCamera, position, this);
+            }
+        };
         /**
          * sets the active camera of the scene using its ID
          * @param {string} id - the camera's ID
@@ -921,7 +970,8 @@ var BABYLON;
                     var renderTarget = this._renderTargets.data[renderIndex];
                     if (renderTarget._shouldRender()) {
                         this._renderId++;
-                        renderTarget.render(false, this.dumpNextRenderTargets);
+                        var hasSpecialRenderTargetCamera = renderTarget.activeCamera && renderTarget.activeCamera !== this.activeCamera;
+                        renderTarget.render(hasSpecialRenderTargetCamera, this.dumpNextRenderTargets);
                     }
                 }
                 BABYLON.Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0);
@@ -1084,7 +1134,7 @@ var BABYLON;
                         engine.setViewport(this.activeCamera.viewport);
                         // Camera
                         this.updateTransformMatrix();
-                        renderTarget.render(false, this.dumpNextRenderTargets);
+                        renderTarget.render(currentActiveCamera !== this.activeCamera, this.dumpNextRenderTargets);
                     }
                 }
                 BABYLON.Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
@@ -1195,6 +1245,7 @@ var BABYLON;
             }
         };
         Object.defineProperty(Scene.prototype, "audioEnabled", {
+            // Audio
             get: function () {
                 return this._audioEnabled;
             },
@@ -1234,6 +1285,34 @@ var BABYLON;
                 }
             }
         };
+        Object.defineProperty(Scene.prototype, "headphone", {
+            get: function () {
+                return this._headphone;
+            },
+            set: function (value) {
+                this._headphone = value;
+                if (this._headphone) {
+                    this._switchAudioModeForHeadphones();
+                }
+                else {
+                    this._switchAudioModeForNormalSpeakers();
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Scene.prototype._switchAudioModeForHeadphones = function () {
+            this.mainSoundTrack.switchPanningModelToHRTF();
+            for (var i = 0; i < this.soundTracks.length; i++) {
+                this.soundTracks[i].switchPanningModelToHRTF();
+            }
+        };
+        Scene.prototype._switchAudioModeForNormalSpeakers = function () {
+            this.mainSoundTrack.switchPanningModelToEqualPower();
+            for (var i = 0; i < this.soundTracks.length; i++) {
+                this.soundTracks[i].switchPanningModelToEqualPower();
+            }
+        };
         Scene.prototype.enableDepthRenderer = function () {
             if (this._depthRenderer) {
                 return this._depthRenderer;
@@ -1565,19 +1644,6 @@ var BABYLON;
         Scene.prototype.getMaterialByTags = function (tagsQuery, forEach) {
             return this._getByTags(this.materials, tagsQuery, forEach).concat(this._getByTags(this.multiMaterials, tagsQuery, forEach));
         };
-        // Audio
-        Scene.prototype.switchAudioModeForHeadphones = function () {
-            this.mainSoundTrack.switchPanningModelToHRTF();
-            for (var i = 0; i < this.soundTracks.length; i++) {
-                this.soundTracks[i].switchPanningModelToHRTF();
-            }
-        };
-        Scene.prototype.switchAudioModeForNormalSpeakers = function () {
-            this.mainSoundTrack.switchPanningModelToEqualPower();
-            for (var i = 0; i < this.soundTracks.length; i++) {
-                this.soundTracks[i].switchPanningModelToEqualPower();
-            }
-        };
         // Statics
         Scene._FOGMODE_NONE = 0;
         Scene._FOGMODE_EXP = 1;

+ 99 - 23
Babylon/babylon.scene.ts

@@ -102,6 +102,8 @@
         * @type {BABYLON.Light[]}
         */
         public lights = new Array<Light>();
+        public onNewLightAdded: (newLight?: Light, positionInArray?: number, scene?: Scene) => void;
+        public onLightRemoved: (removedLight?: Light) => void;
 
         // Cameras
         /**
@@ -110,6 +112,8 @@
         * @type {BABYLON.Camera[]}
         */
         public cameras = new Array<Camera>();
+        public onNewCameraAdded: (newCamera?: Camera, positionInArray?: number, scene?: Scene) => void;
+        public onCameraRemoved: (removedCamera?: Camera) => void;
         public activeCameras = new Array<Camera>();
         public activeCamera: Camera;
 
@@ -120,6 +124,8 @@
         * @type {BABYLON.AbstractMesh[]}
         */
         public meshes = new Array<AbstractMesh>();
+        public onNewMeshAdded: (newMesh?: AbstractMesh, positionInArray?: number, scene?: Scene) => void;
+        public onMeshRemoved: (removedMesh?: AbstractMesh) => void;
 
         // Geometries
         private _geometries = new Array<Geometry>();
@@ -191,6 +197,7 @@
         public mainSoundTrack: SoundTrack;
         public soundTracks = new Array<SoundTrack>();
         private _audioEnabled = true;
+        private _headphone = false;
 
         //Simplification Queue
         public simplificationQueue: SimplificationQueue;
@@ -685,10 +692,7 @@
             var delay = now - this._animationStartDate;
 
             for (var index = 0; index < this._activeAnimatables.length; index++) {
-                if (!this._activeAnimatables[index]._animate(delay)) {
-                    this._activeAnimatables.splice(index, 1);
-                    index--;
-                }
+                this._activeAnimatables[index]._animate(delay);
             }
         }
 
@@ -714,6 +718,63 @@
 
         // Methods
 
+        public addMesh(newMesh: AbstractMesh) {
+            var position = this.meshes.push(newMesh);
+            if (this.onNewMeshAdded) {
+                this.onNewMeshAdded(newMesh, position, this);
+            }
+        }
+
+        public removeMesh(toRemove: AbstractMesh): number {
+            var index = this.meshes.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.meshes.splice(index, 1);
+            }
+            if (this.onMeshRemoved) {
+                this.onMeshRemoved(toRemove);
+            }
+            return index;
+        }
+
+        public removeLight(toRemove: Light): number {
+            var index = this.lights.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.lights.splice(index, 1);
+            }
+            if (this.onLightRemoved) {
+                this.onLightRemoved(toRemove);
+            }
+            return index;
+        }
+
+        public removeCamera(toRemove: Camera): number {
+            var index = this.cameras.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.cameras.splice(index, 1);
+            }
+            if (this.onCameraRemoved) {
+                this.onCameraRemoved(toRemove);
+            }
+            return index;
+        }
+
+        public addLight(newLight: Light) {
+            var position = this.lights.push(newLight);
+            if (this.onNewLightAdded) {
+                this.onNewLightAdded(newLight, position, this);
+            }
+        }
+
+        public addCamera(newCamera: Camera) {
+            var position = this.cameras.push(newCamera);
+            if (this.onNewCameraAdded) {
+                this.onNewCameraAdded(newCamera, position, this);
+            }
+        }
+
         /**
          * sets the active camera of the scene using its ID
          * @param {string} id - the camera's ID
@@ -1194,7 +1255,8 @@
                     var renderTarget = this._renderTargets.data[renderIndex];
                     if (renderTarget._shouldRender()) {
                         this._renderId++;
-                        renderTarget.render(false, this.dumpNextRenderTargets);
+                        var hasSpecialRenderTargetCamera = renderTarget.activeCamera && renderTarget.activeCamera !== this.activeCamera;
+                        renderTarget.render(hasSpecialRenderTargetCamera, this.dumpNextRenderTargets);
                     }
                 }
                 Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0);
@@ -1396,7 +1458,7 @@
                         // Camera
                         this.updateTransformMatrix();
 
-                        renderTarget.render(false, this.dumpNextRenderTargets);
+                        renderTarget.render(currentActiveCamera !== this.activeCamera, this.dumpNextRenderTargets);
                     }
                 }
                 Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
@@ -1528,6 +1590,7 @@
             }
         }
 
+        // Audio
         public get audioEnabled(): boolean {
             return this._audioEnabled;
         }
@@ -1568,6 +1631,36 @@
             }
         }
 
+        public get headphone(): boolean {
+            return this._headphone;
+        }
+
+        public set headphone(value: boolean) {
+            this._headphone = value;
+            if (this._headphone) {
+                this._switchAudioModeForHeadphones();
+            }
+            else {
+                this._switchAudioModeForNormalSpeakers();
+            }
+        }
+
+        private _switchAudioModeForHeadphones() {
+            this.mainSoundTrack.switchPanningModelToHRTF();
+
+            for (var i = 0; i < this.soundTracks.length; i++) {
+                this.soundTracks[i].switchPanningModelToHRTF();
+            }
+        }
+
+        private _switchAudioModeForNormalSpeakers() {
+            this.mainSoundTrack.switchPanningModelToEqualPower();
+
+            for (var i = 0; i < this.soundTracks.length; i++) {
+                this.soundTracks[i].switchPanningModelToEqualPower();
+            }
+        }
+
         public enableDepthRenderer(): DepthRenderer {
             if (this._depthRenderer) {
                 return this._depthRenderer;
@@ -1998,22 +2091,5 @@
         public getMaterialByTags(tagsQuery: string, forEach?: (material: Material) => void): Material[] {
             return this._getByTags(this.materials, tagsQuery, forEach).concat(this._getByTags(this.multiMaterials, tagsQuery, forEach));
         }
-
-        // Audio
-        public switchAudioModeForHeadphones() {
-            this.mainSoundTrack.switchPanningModelToHRTF();
-
-            for (var i = 0; i < this.soundTracks.length; i++) {
-                this.soundTracks[i].switchPanningModelToHRTF();
-            }
-        }
-
-        public switchAudioModeForNormalSpeakers() {
-            this.mainSoundTrack.switchPanningModelToEqualPower();
-
-            for (var i = 0; i < this.soundTracks.length; i++) {
-                this.soundTracks[i].switchPanningModelToEqualPower();
-            }
-        }
     }
 } 

+ 16 - 1
Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs

@@ -3,7 +3,7 @@
 namespace BabylonExport.Entities
 {
     [DataContract]
-    public class BabylonAbstractMesh
+    public class BabylonAbstractMesh: BabylonIAnimatable
     {
         [DataMember]
         public string name { get; set; }
@@ -21,8 +21,23 @@ namespace BabylonExport.Entities
         public float[] rotationQuaternion { get; set; }
 
         [DataMember]
+        public BabylonActions actions { get; set; }
+
+        [DataMember]
         public BabylonAnimation[] animations { get; set; }
 
+        [DataMember]
+        public bool autoAnimate { get; set; }
+
+        [DataMember]
+        public int autoAnimateFrom { get; set; }
+
+        [DataMember]
+        public int autoAnimateTo { get; set; }
+
+        [DataMember]
+        public bool autoAnimateLoop { get; set; }
+
         public BabylonAbstractMesh()
         {
             position = new[] { 0f, 0f, 0f };

+ 39 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonActions.cs

@@ -0,0 +1,39 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonActionsProperties
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string value { get; set; }
+
+        [DataMember]
+        public string targetType { get; set; }
+    }
+
+    [DataContract]
+    public class BabylonActions
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public int type { get; set; }
+
+        [DataMember]
+        public bool detached { get; set; }
+
+        [DataMember]
+        public BabylonActions[] children { get; set; }
+
+        [DataMember]
+        public BabylonActions[] combine { get; set; }
+
+        [DataMember]
+        public BabylonActionsProperties[] properties { get; set; }
+    }
+}

+ 2 - 2
Exporters/3ds Max/BabylonExport.Entities/BabylonAnimation.cs

@@ -12,10 +12,10 @@ namespace BabylonExport.Entities
         public string property { get; set; }
 
         [DataMember]
-        public DataType dataType { get; set; }
+        public int dataType { get; set; }
 
         [DataMember]
-        public LoopBehavior loopBehavior { get; set; }
+        public int loopBehavior { get; set; }
 
         [DataMember]
         public int framePerSecond { get; set; }

+ 1 - 2
Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs

@@ -3,7 +3,7 @@
 namespace BabylonExport.Entities
 {
     [DataContract]
-    public class BabylonCamera
+    public class BabylonCamera : BabylonIAnimatable
     {
         [DataMember]
         public string name { get; set; }
@@ -68,7 +68,6 @@ namespace BabylonExport.Entities
         [DataMember]
         public BabylonAnimation[] animations { get; set; }
 
-
         public BabylonCamera()
         {
             position = new[] { 0f, 0f, 0f };

+ 6 - 19
Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj

@@ -9,14 +9,13 @@
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>BabylonExport.Entities</RootNamespace>
     <AssemblyName>BabylonExport.Entities</AssemblyName>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <SccProjectName>SAK</SccProjectName>
     <SccLocalPath>SAK</SccLocalPath>
     <SccAuxPath>SAK</SccAuxPath>
     <SccProvider>SAK</SccProvider>
-    <TargetFrameworkProfile />
-    <NuGetPackageImportStamp>a3421fc4</NuGetPackageImportStamp>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -36,26 +35,22 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="SharpDX">
-      <HintPath>$(SharpDXPackageBinDir)\SharpDX.dll</HintPath>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
-    <Reference Include="System.Drawing" />
     <Reference Include="System.Runtime.Serialization" />
-    <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="BabylonActions.cs" />
     <Compile Include="BabylonAnimation.cs" />
     <Compile Include="BabylonAnimationKey.cs" />
     <Compile Include="BabylonBone.cs" />
     <Compile Include="BabylonCamera.cs" />
     <Compile Include="BabylonFresnelParameters.cs" />
+    <Compile Include="BabylonIAnimatable.cs" />
     <Compile Include="BabylonLensFlare.cs" />
     <Compile Include="BabylonLensFlareSystem.cs" />
     <Compile Include="BabylonLight.cs" />
@@ -67,21 +62,13 @@
     <Compile Include="BabylonScene.cs" />
     <Compile Include="BabylonShadowGenerator.cs" />
     <Compile Include="BabylonSkeleton.cs" />
+    <Compile Include="BabylonSound.cs" />
     <Compile Include="BabylonSubMesh.cs" />
     <Compile Include="BabylonTexture.cs" />
+    <Compile Include="BabylonVector3.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="..\packages\SharpDX.2.6.3\build\SharpDX.targets" Condition="Exists('..\packages\SharpDX.2.6.3\build\SharpDX.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('..\packages\SharpDX.2.6.3\build\SharpDX.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SharpDX.2.6.3\build\SharpDX.targets'))" />
-  </Target>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 19 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonIAnimatable.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BabylonExport.Entities
+{
+    public interface BabylonIAnimatable
+    {
+        BabylonAnimation[] animations { get; set; }
+        bool autoAnimate { get; set; }
+
+        int autoAnimateFrom { get; set; }
+
+        int autoAnimateTo { get; set; }
+
+        bool autoAnimateLoop { get; set; }
+    }
+}

+ 1 - 1
Exporters/3ds Max/BabylonExport.Entities/BabylonLight.cs

@@ -3,7 +3,7 @@
 namespace BabylonExport.Entities
 {
     [DataContract]
-    public class BabylonLight
+    public class BabylonLight : BabylonIAnimatable
     {
         [DataMember]
         public string name { get; set; }

+ 3 - 16
Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs

@@ -5,7 +5,6 @@ namespace BabylonExport.Entities
     [DataContract]
     public class BabylonMesh : BabylonAbstractMesh
     {
-
         [DataMember]
         public string id { get; set; }
 
@@ -58,11 +57,11 @@ namespace BabylonExport.Entities
         public bool checkCollisions { get; set; }
 
         [DataMember]
-        public bool receiveShadows { get; set; }
-
+        public bool receiveShadows { get; set; }    
+    
         [DataMember]
         public bool infiniteDistance { get; set; }
-
+        
         [DataMember]
         public int billboardMode { get; set; }
 
@@ -79,18 +78,6 @@ namespace BabylonExport.Entities
         public int skeletonId { get; set; }
 
         [DataMember]
-        public bool autoAnimate { get; set; }
-
-        [DataMember]
-        public int autoAnimateFrom { get; set; }
-
-        [DataMember]
-        public int autoAnimateTo { get; set; }
-
-        [DataMember]
-        public bool autoAnimateLoop { get; set; }
-
-        [DataMember]
         public bool showBoundingBox { get; set; }
 
         [DataMember]

+ 44 - 22
Exporters/3ds Max/BabylonExport.Entities/BabylonScene.cs

@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Runtime.Serialization;
-using SharpDX;
 
 namespace BabylonExport.Entities
 {
@@ -49,6 +48,9 @@ namespace BabylonExport.Entities
         public BabylonMesh[] meshes { get; set; }
 
         [DataMember]
+        public BabylonSound[] sounds { get; set; }
+
+        [DataMember]
         public BabylonMaterial[] materials { get; set; }
 
         [DataMember]
@@ -65,13 +67,17 @@ namespace BabylonExport.Entities
 
         [DataMember]
         public BabylonSkeleton[] skeletons { get; set; }
-        
-        public Vector3 MaxVector { get; set; }
-        public Vector3 MinVector { get; set; }
+
+        [DataMember]
+        public BabylonActions actions { get; set; }
+
+        public BabylonVector3 MaxVector { get; set; }
+        public BabylonVector3 MinVector { get; set; }
 
         public string OutputPath { get; private set; }
 
         public List<BabylonMesh> MeshesList { get; private set; }
+        public List<BabylonSound> SoundsList { get; private set; }
         public List<BabylonCamera> CamerasList { get; private set; }
         public List<BabylonLight> LightsList { get; private set; }
         public List<BabylonMaterial> MaterialsList { get; private set; }
@@ -92,17 +98,22 @@ namespace BabylonExport.Entities
             MultiMaterialsList = new List<BabylonMultiMaterial>();
             ShadowGeneratorsList = new List<BabylonShadowGenerator>();
             SkeletonsList = new List<BabylonSkeleton>();
+            SoundsList = new List<BabylonSound>();
 
             // Default values
             autoClear = true;
             clearColor = new[] { 0.2f, 0.2f, 0.3f };
-            ambientColor = new[] {0f, 0f, 0f };
-            gravity = new[] {0f, 0f, -0.9f};
+            ambientColor = new[] { 0f, 0f, 0f };
+            gravity = new[] { 0f, 0f, -0.9f };
+
+            MaxVector = new BabylonVector3 { X = float.MinValue, Y = float.MinValue, Z = float.MinValue };
+            MinVector = new BabylonVector3 { X = float.MaxValue, Y = float.MaxValue, Z = float.MaxValue };
         }
 
         public void Prepare(bool generateDefaultLight = true)
         {
             meshes = MeshesList.ToArray();
+            sounds = SoundsList.ToArray();
 
             materials = MaterialsList.ToArray();
             multiMaterials = MultiMaterialsList.ToArray();
@@ -111,15 +122,15 @@ namespace BabylonExport.Entities
 
             if (CamerasList.Count == 0)
             {
-                var camera = new BabylonCamera {name = "Default camera", id = Guid.NewGuid().ToString()};
+                var camera = new BabylonCamera { name = "Default camera", id = Guid.NewGuid().ToString() };
 
                 var distanceVector = MaxVector - MinVector;
-                var midPoint = MinVector +distanceVector / 2;
+                var midPoint = MinVector + distanceVector / 2;
                 camera.target = midPoint.ToArray();
                 camera.position = (midPoint + distanceVector).ToArray();
 
                 var distance = distanceVector.Length();
-                camera.speed =  distance/ 50.0f;
+                camera.speed = distance / 50.0f;
                 camera.maxZ = distance * 4f;
 
                 camera.minZ = distance < 100.0f ? 0.1f : 1.0f;
@@ -129,18 +140,19 @@ namespace BabylonExport.Entities
 
             if (LightsList.Count == 0 && generateDefaultLight)
             {
-                var light = new BabylonLight {name = "Default light", id = Guid.NewGuid().ToString()};
-
-                var midPoint = MinVector + (MaxVector - MinVector) / 2;
-                light.type = 0;
-                light.position = (midPoint + (MaxVector - MinVector)).ToArray();
-
-                light.diffuse = new Vector3(1, 1, 1).ToArray();
-                light.specular = new Vector3(1, 1, 1).ToArray();
+                var light = new BabylonLight
+                {
+                    name = "Default light",
+                    id = Guid.NewGuid().ToString(),
+                    type = 3,
+                    groundColor = new float[] {0, 0, 0},
+                    direction = new[] {0, 1.0f, 0},
+                    intensity = 1
+                };
 
                 LightsList.Add(light);
             }
-            
+
             cameras = CamerasList.ToArray();
             lights = LightsList.ToArray();
 
@@ -150,14 +162,24 @@ namespace BabylonExport.Entities
             }
         }
 
-        public void AddTexture(string diffuseTexture)
+        public void AddTexture(string texture)
         {
-            if (exportedTextures.Contains(diffuseTexture))
+            if (exportedTextures.Contains(texture))
                 return;
 
-            exportedTextures.Add(diffuseTexture);
+            exportedTextures.Add(texture);
+
+            File.Copy(texture, Path.Combine(OutputPath, Path.GetFileName(texture)), true);
+        }
+
+        public bool AddTextureCube(string textureName)
+        {
+            if (exportedTextures.Contains(textureName))
+                return false;
+
+            exportedTextures.Add(textureName);
 
-            File.Copy(diffuseTexture, Path.Combine(OutputPath, Path.GetFileName(diffuseTexture)), true);
+            return true;
         }
     }
 }

+ 12 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs

@@ -9,6 +9,9 @@ namespace BabylonExport.Entities
         public int mapSize { get; set; }
 
         [DataMember]
+        public float bias { get; set; }
+
+        [DataMember]
         public string lightId { get; set; }
 
         [DataMember]
@@ -18,6 +21,15 @@ namespace BabylonExport.Entities
         public bool usePoissonSampling { get; set; }
 
         [DataMember]
+        public bool useBlurVarianceShadowMap { get; set; }
+
+        [DataMember]
+        public float blurScale { get; set; }
+
+        [DataMember]
+        public float blurBoxOffset { get; set; }
+
+        [DataMember]
         public string[] renderList { get; set; }
 
     }

+ 86 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonSound.cs

@@ -0,0 +1,86 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonSound
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public float volume { get; set; }
+
+        [DataMember]
+        public float playbackRate { get; set; }
+
+        [DataMember]
+        public bool autoplay { get; set; }
+
+        [DataMember]
+        public bool loop { get; set; }
+
+        [DataMember]
+        public int soundTrackId { get; set; }
+
+        [DataMember]
+        public bool spatialSound { get; set; }
+
+        [DataMember]
+        public float[] position { get; set; }
+
+        [DataMember]
+        public float refDistance { get; set; }
+
+        [DataMember]
+        public float rolloffFactor { get; set; }
+
+        [DataMember]
+        public float maxDistance { get; set; }
+
+        [DataMember]
+        public string distanceModel { get; set; }
+
+        [DataMember]
+        public string panningModel { get; set; }
+
+        [DataMember]
+        public bool isDirectional { get; set; }
+
+        [DataMember]
+        public float coneInnerAngle { get; set; }
+
+        [DataMember]
+        public float coneOuterAngle { get; set; }
+
+        [DataMember]
+        public float coneOuterGain { get; set; }
+
+        [DataMember]
+        public string connectedMeshId { get; set; }
+
+        [DataMember]
+        public float[] localDirectionToMesh { get; set; }
+
+        public BabylonSound()
+        {
+            volume = 1;
+            playbackRate = 1;
+            autoplay = false;
+            loop = false;
+            soundTrackId = -1;
+            spatialSound = false;
+            position = new[] { 0f, 0f, 0f };
+            refDistance = 1;
+            rolloffFactor = 1;
+            maxDistance = 100;
+            distanceModel = "linear";
+            panningModel = "equalpower";
+            isDirectional = false;
+            coneInnerAngle = 360;
+            coneOuterAngle = 360;
+            coneOuterGain = 0;
+            localDirectionToMesh = new[] { 1f, 0f, 0f };
+        }
+    }
+}

+ 36 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonVector3.cs

@@ -0,0 +1,36 @@
+using System;
+
+namespace BabylonExport.Entities
+{
+    public class BabylonVector3
+    {
+        public float X { get; set; }
+        public float Y { get; set; }
+        public float Z { get; set; }
+
+        public float[] ToArray()
+        {
+            return new [] {X, Y, Z};
+        }
+
+        public float Length()
+        {
+            return (float)Math.Sqrt(X * X + Y * Y + Z * Z);
+        }
+
+        public static BabylonVector3 operator +(BabylonVector3 a, BabylonVector3 b)
+        {
+            return new BabylonVector3 {X = a.X + b.X, Y = a.Y + b.Y, Z = a.Z + b.Z};
+        }
+
+        public static BabylonVector3 operator -(BabylonVector3 a, BabylonVector3 b)
+        {
+            return new BabylonVector3 { X = a.X - b.X, Y = a.Y - b.Y, Z = a.Z - b.Z };
+        }
+
+        public static BabylonVector3 operator /(BabylonVector3 a, float b)
+        {
+            return new BabylonVector3 { X = a.X / b, Y = a.Y / b, Z = a.Z / b };
+        }
+    }
+}

+ 66 - 17
Exporters/3ds Max/Max2Babylon/2015/Max2Babylon2015.csproj

@@ -17,7 +17,7 @@
     <SccAuxPath>SAK</SccAuxPath>
     <SccProvider>SAK</SccProvider>
     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
-    <NuGetPackageImportStamp>847376a2</NuGetPackageImportStamp>
+    <RestorePackages>true</RestorePackages>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -38,25 +38,23 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Prefer32Bit>false</Prefer32Bit>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="Autodesk.Max, Version=17.0.630.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>Refs\2015\Autodesk.Max.dll</HintPath>
-      <Private>False</Private>
+      <HintPath>..\..\..\..\..\Repos\Babylon.js\Exporters\3ds Max\Max2Babylon\2015\Refs\Autodesk.Max.dll</HintPath>
     </Reference>
     <Reference Include="BabylonFileConverter, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\Refs\BabylonFileConverter.dll</HintPath>
     </Reference>
-    <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+    <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <HintPath>..\..\packages\Newtonsoft.Json.6.0.7\lib\net45\Newtonsoft.Json.dll</HintPath>
     </Reference>
     <Reference Include="SharpDX, Version=2.4.2.0, Culture=neutral, PublicKeyToken=627a3d6d1956f55a, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>$(SharpDXPackageBinDir)\SharpDX.dll</HintPath>
+      <HintPath>..\..\BabylonExport.Core\Refs\SharpDX.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
@@ -82,6 +80,12 @@
     <Compile Include="..\Descriptor.cs">
       <Link>Descriptor.cs</Link>
     </Compile>
+    <Compile Include="..\Exporter\ActionBuilder\BabylonActionsBuilderActionItem.cs">
+      <Link>Exporter\ActionBuilder\BabylonActionsBuilderActionItem.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\ActionBuilder\BabylonExporter.Action.cs">
+      <Link>Exporter\ActionBuilder\BabylonExporter.Action.cs</Link>
+    </Compile>
     <Compile Include="..\Exporter\BabylonExporter.Animation.cs">
       <Link>Exporter\BabylonExporter.Animation.cs</Link>
     </Compile>
@@ -112,6 +116,14 @@
     <Compile Include="..\Exporter\GlobalVertex.cs">
       <Link>Exporter\GlobalVertex.cs</Link>
     </Compile>
+    <Compile Include="..\Forms\ActionsBuilderForm.cs">
+      <Link>Forms\ActionsBuilderForm.cs</Link>
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="..\Forms\ActionsBuilderForm.designer.cs">
+      <Link>Forms\ActionsBuilderForm.designer.cs</Link>
+      <DependentUpon>ActionsBuilderForm.cs</DependentUpon>
+    </Compile>
     <Compile Include="..\Forms\CameraPropertiesForm.cs">
       <Link>Forms\CameraPropertiesForm.cs</Link>
       <SubType>Form</SubType>
@@ -186,9 +198,49 @@
     </Compile>
   </ItemGroup>
   <ItemGroup>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\action.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\action.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\actionkinds.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\actionkinds.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\contextmenu.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\contextmenu.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\fonts.css">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\fonts.css</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\index.css">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\index.css</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\index.html">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\index.html</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\list.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\list.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\parametersManager.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\parametersManager.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\raphael.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\raphael.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\utils.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\utils.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\viewer.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\viewer.js</Link>
+    </Content>
+    <Content Include="..\Exporter\ActionBuilder\ActionsBuilder\viewsertoolbar.js">
+      <Link>Exporter\ActionBuilder\ActionsBuilder\viewsertoolbar.js</Link>
+    </Content>
     <Content Include="Refs\Autodesk.Max.dll" />
   </ItemGroup>
   <ItemGroup>
+    <EmbeddedResource Include="..\Forms\ActionsBuilderForm.resx">
+      <Link>Forms\ActionsBuilderForm.resx</Link>
+      <DependentUpon>ActionsBuilderForm.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="..\Forms\CameraPropertiesForm.resx">
       <Link>Forms\CameraPropertiesForm.resx</Link>
       <DependentUpon>CameraPropertiesForm.cs</DependentUpon>
@@ -224,17 +276,14 @@
       <Name>BabylonExport.Entities</Name>
     </ProjectReference>
   </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="..\..\packages\SharpDX.2.6.3\build\SharpDX.targets" Condition="Exists('..\..\packages\SharpDX.2.6.3\build\SharpDX.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('..\..\packages\SharpDX.2.6.3\build\SharpDX.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SharpDX.2.6.3\build\SharpDX.targets'))" />
-  </Target>
+  <PropertyGroup>
+    <PostBuildEvent>mkdir "$(OutDir)BabylonActionsBuilder"
+mkdir "$(OutDir)BabylonActionsBuilder\fonts\SinkinSans"
+copy "$(SolutionDir)Max2Babylon\Exporter\ActionBuilder\ActionsBuilder\" "$(OutDir)BabylonActionsBuilder\"
+copy "$(SolutionDir)Max2Babylon\Exporter\ActionBuilder\ActionsBuilder\fonts\SinkinSans" "$(OutDir)BabylonActionsBuilder\fonts\SinkinSans"
+copy "$(SolutionDir)babylon.max.js" "$(OutDir)BabylonActionsBuilder\babylon.max.js"</PostBuildEvent>
+  </PropertyGroup>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 0 - 5
Exporters/3ds Max/Max2Babylon/2015/packages.config

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
-  <package id="SharpDX" version="2.6.3" targetFramework="net45" />
-</packages>

+ 0 - 1
Exporters/3ds Max/Max2Babylon/BabylonExportActionItem.cs

@@ -20,7 +20,6 @@ namespace Max2Babylon
 
         public void Close()
         {
-
             if (form == null)
             {
                 return;

+ 24 - 2
Exporters/3ds Max/Max2Babylon/Exporter/ActionBuilder/ActionsBuilder/action.js

@@ -7,13 +7,21 @@ var AB;
 
     var Node = (function () {
         function Node() {
+            // Members
             this.rect = null;
             this.text = null;
             this.line = null;
 
             this.action = null;
+
+            this.detached = false;
+            this.minimized = false;
         }
 
+        // Get node's object attribute
+        // element: The element to get the attribute
+        // attribute: the attribute name "text, "width", etc.
+        // value: optional, if not reading mode but writing mode
         Node.prototype.attr = function(element, attribute, value) {
             if (value)
                 element.attr(attribute, value);
@@ -21,6 +29,9 @@ var AB;
                 return element.attr(attribute);
         }
 
+        // Returns the point at (x, y) is inside the node
+        // x: the x position of the point
+        // y: the y position of the point
         Node.prototype.isPointInside = function (x, y) {
             return this.rect.isPointInside(x, y) || this.text.isPointInside(x, y);
         }
@@ -35,12 +46,20 @@ var AB;
             this.children = new Array();
             this.node = node;
 
-            this.name = '';
+            // Action
+            this.name = "";
             this.type = AB.ActionsBuilder.Type.OBJECT;
             this.propertiesResults = new Array();
             this.properties = new Array();
+
+            // Extra
+            this.combine = false;
+            this.combineArray = new Array();
+            this.hub = null;
         }
 
+        // Adds a child to the action
+        // object: the child
         Action.prototype.addChild = function (object) {
             if (object == null)
                 return false;
@@ -51,10 +70,12 @@ var AB;
             return true;
         }
 
+        // Removes a child from the action
+        // object: the child to remove
         Action.prototype.removeChild = function (object) {
             var indice = this.children.indexOf(object);
 
-            if (indice != 1) {
+            if (indice != -1) {
                 this.children.splice(indice, 1);
                 return true;
             }
@@ -62,6 +83,7 @@ var AB;
             return false;
         }
 
+        // Clears all the children of the action
         Action.prototype.clearChildren = function () {
             this.children = new Array();
         }

+ 0 - 0
Exporters/3ds Max/Max2Babylon/Exporter/ActionBuilder/ActionsBuilder/actionkinds.js


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