Browse Source

Improved reflection when shadows are on

David Catuhe 9 years ago
parent
commit
f2f01f7f33
38 changed files with 1622 additions and 1148 deletions
  1. 15 15
      dist/preview release/babylon.core.js
  2. 868 862
      dist/preview release/babylon.d.ts
  3. 19 19
      dist/preview release/babylon.js
  4. 216 71
      dist/preview release/babylon.max.js
  5. 22 22
      dist/preview release/babylon.noworker.js
  6. 1 1
      dist/preview release/what's new.md
  7. 64 15
      src/Audio/babylon.sound.js
  8. 65 16
      src/Audio/babylon.sound.ts
  9. 6 0
      src/Bones/babylon.skeleton.js
  10. 8 0
      src/Bones/babylon.skeleton.ts
  11. 3 0
      src/Cameras/babylon.arcRotateCamera.js
  12. 3 0
      src/Cameras/babylon.arcRotateCamera.ts
  13. 2 0
      src/Cameras/babylon.camera.js
  14. 3 0
      src/Cameras/babylon.camera.ts
  15. 2 0
      src/Lights/babylon.light.js
  16. 3 0
      src/Lights/babylon.light.ts
  17. 2 0
      src/Materials/Textures/babylon.baseTexture.js
  18. 3 0
      src/Materials/Textures/babylon.baseTexture.ts
  19. 2 0
      src/Materials/babylon.material.js
  20. 3 0
      src/Materials/babylon.material.ts
  21. 9 10
      src/Materials/babylon.standardMaterial.js
  22. 11 13
      src/Materials/babylon.standardMaterial.ts
  23. 2 0
      src/Mesh/babylon.abstractMesh.js
  24. 3 0
      src/Mesh/babylon.abstractMesh.ts
  25. 3 3
      src/Mesh/babylon.mesh.vertexData.js
  26. 4 3
      src/Mesh/babylon.mesh.vertexData.ts
  27. 2 2
      src/Mesh/babylon.meshBuilder.js
  28. 3 2
      src/Mesh/babylon.meshBuilder.ts
  29. 0 2
      src/Particles/babylon.solidParticle.ts
  30. 29 13
      src/Particles/babylon.solidParticleSystem.js
  31. 31 13
      src/Particles/babylon.solidParticleSystem.ts
  32. 78 27
      src/Physics/Plugins/babylon.cannonJSPlugin.js
  33. 103 34
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  34. 9 5
      src/Shaders/default.fragment.fx
  35. 3 0
      src/Tools/babylon.tags.js
  36. 4 0
      src/Tools/babylon.tags.ts
  37. 8 0
      src/babylon.scene.js
  38. 10 0
      src/babylon.scene.ts

File diff suppressed because it is too large
+ 15 - 15
dist/preview release/babylon.core.js


File diff suppressed because it is too large
+ 868 - 862
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 19 - 19
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 216 - 71
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 22 - 22
dist/preview release/babylon.noworker.js


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

@@ -10,7 +10,7 @@
     - Sprites now can be [picked](http://www.babylonjs-playground.com/#1XMVZW#3) and can use [actions](http://www.babylonjs-playground.com/#9RUHH#3) ([deltakosh](https://github.com/deltakosh))
     - Sprites now can be [picked](http://www.babylonjs-playground.com/#1XMVZW#3) and can use [actions](http://www.babylonjs-playground.com/#9RUHH#3) ([deltakosh](https://github.com/deltakosh))
     - New `Mesh.CreatePolygon()` method ([jerome](https://github.com/jbousquie))
     - New `Mesh.CreatePolygon()` method ([jerome](https://github.com/jbousquie))
     - Introducing [babylon.core.js](http://doc.babylonjs.com/generals/Framework_versions) ([deltakosh](https://github.com/deltakosh))
     - Introducing [babylon.core.js](http://doc.babylonjs.com/generals/Framework_versions) ([deltakosh](https://github.com/deltakosh))
-  - **Updates**
+  - **Updates**    
     - Adding support for equi-rectangular mapping. See [demo here](http://www.babylonjs-playground.com/#27FN5R#8) ([deltakosh](https://github.com/deltakosh))
     - Adding support for equi-rectangular mapping. See [demo here](http://www.babylonjs-playground.com/#27FN5R#8) ([deltakosh](https://github.com/deltakosh))
     - Sprites and particles scheduler updated to be resolved before transparent objects ([deltakosh](https://github.com/deltakosh))
     - Sprites and particles scheduler updated to be resolved before transparent objects ([deltakosh](https://github.com/deltakosh))
     - Added `DirectionalLight.autoUpdateExtends` to prevent directional lights to adapt to scene extends ([deltakosh](https://github.com/deltakosh))
     - Added `DirectionalLight.autoUpdateExtends` to prevent directional lights to adapt to scene extends ([deltakosh](https://github.com/deltakosh))

+ 64 - 15
src/Audio/babylon.sound.js

@@ -20,6 +20,7 @@ var BABYLON;
             this.distanceModel = "linear";
             this.distanceModel = "linear";
             this._panningModel = "equalpower";
             this._panningModel = "equalpower";
             this._playbackRate = 1;
             this._playbackRate = 1;
+            this._streaming = false;
             this._startTime = 0;
             this._startTime = 0;
             this._startOffset = 0;
             this._startOffset = 0;
             this._position = BABYLON.Vector3.Zero();
             this._position = BABYLON.Vector3.Zero();
@@ -62,6 +63,7 @@ var BABYLON;
                 this.refDistance = options.refDistance || 1;
                 this.refDistance = options.refDistance || 1;
                 this.distanceModel = options.distanceModel || "linear";
                 this.distanceModel = options.distanceModel || "linear";
                 this._playbackRate = options.playbackRate || 1;
                 this._playbackRate = options.playbackRate || 1;
+                this._streaming = options.streaming || false;
             }
             }
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 this._soundGain = BABYLON.Engine.audioEngine.audioContext.createGain();
                 this._soundGain = BABYLON.Engine.audioEngine.audioContext.createGain();
@@ -76,7 +78,22 @@ var BABYLON;
                 if (urlOrArrayBuffer) {
                 if (urlOrArrayBuffer) {
                     // If it's an URL
                     // If it's an URL
                     if (typeof (urlOrArrayBuffer) === "string") {
                     if (typeof (urlOrArrayBuffer) === "string") {
-                        BABYLON.Tools.LoadFile(urlOrArrayBuffer, function (data) { _this._soundLoaded(data); }, null, null, true);
+                        // Loading sound using XHR2
+                        if (!this._streaming) {
+                            BABYLON.Tools.LoadFile(urlOrArrayBuffer, function (data) { _this._soundLoaded(data); }, null, null, true);
+                        }
+                        else {
+                            this._htmlAudioElement = new Audio();
+                            this._htmlAudioElement.src = urlOrArrayBuffer;
+                            ;
+                            this._htmlAudioElement.controls = false;
+                            this._htmlAudioElement.loop = this.loop;
+                            this._isReadyToPlay = true;
+                            document.body.appendChild(this._htmlAudioElement);
+                            if (this.autoplay) {
+                                this.play();
+                            }
+                        }
                     }
                     }
                     else {
                     else {
                         if (urlOrArrayBuffer instanceof ArrayBuffer) {
                         if (urlOrArrayBuffer instanceof ArrayBuffer) {
@@ -165,7 +182,12 @@ var BABYLON;
                 this._playbackRate = options.playbackRate || this._playbackRate;
                 this._playbackRate = options.playbackRate || this._playbackRate;
                 this._updateSpatialParameters();
                 this._updateSpatialParameters();
                 if (this.isPlaying) {
                 if (this.isPlaying) {
-                    this._soundSource.playbackRate.value = this._playbackRate;
+                    if (this._streaming) {
+                        this._htmlAudioElement.playbackRate = this._playbackRate;
+                    }
+                    else {
+                        this._soundSource.playbackRate.value = this._playbackRate;
+                    }
                 }
                 }
             }
             }
         };
         };
@@ -277,7 +299,7 @@ var BABYLON;
             if (this._isReadyToPlay && this._scene.audioEnabled) {
             if (this._isReadyToPlay && this._scene.audioEnabled) {
                 try {
                 try {
                     var startTime = time ? BABYLON.Engine.audioEngine.audioContext.currentTime + time : BABYLON.Engine.audioEngine.audioContext.currentTime;
                     var startTime = time ? BABYLON.Engine.audioEngine.audioContext.currentTime + time : BABYLON.Engine.audioEngine.audioContext.currentTime;
-                    if (!this._soundSource) {
+                    if (!this._soundSource || !this._streamingSource) {
                         if (this.spatialSound) {
                         if (this.spatialSound) {
                             this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
                             this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
                             if (this._isDirectional) {
                             if (this._isDirectional) {
@@ -293,14 +315,25 @@ var BABYLON;
                             }
                             }
                         }
                         }
                     }
                     }
-                    this._soundSource = BABYLON.Engine.audioEngine.audioContext.createBufferSource();
-                    this._soundSource.buffer = this._audioBuffer;
-                    this._soundSource.connect(this._inputAudioNode);
-                    this._soundSource.loop = this.loop;
-                    this._soundSource.playbackRate.value = this._playbackRate;
+                    if (this._streaming) {
+                        if (!this.isPaused) {
+                            this._streamingSource = BABYLON.Engine.audioEngine.audioContext.createMediaElementSource(this._htmlAudioElement);
+                            this._streamingSource.connect(this._inputAudioNode);
+                            this._htmlAudioElement.onended = function () { _this._onended(); };
+                            this._htmlAudioElement.playbackRate = this._playbackRate;
+                        }
+                        this._htmlAudioElement.play();
+                    }
+                    else {
+                        this._soundSource = BABYLON.Engine.audioEngine.audioContext.createBufferSource();
+                        this._soundSource.buffer = this._audioBuffer;
+                        this._soundSource.connect(this._inputAudioNode);
+                        this._soundSource.loop = this.loop;
+                        this._soundSource.playbackRate.value = this._playbackRate;
+                        this._soundSource.onended = function () { _this._onended(); };
+                        this._soundSource.start(this._startTime, this.isPaused ? this._startOffset % this._soundSource.buffer.duration : 0);
+                    }
                     this._startTime = startTime;
                     this._startTime = startTime;
-                    this._soundSource.onended = function () { _this._onended(); };
-                    this._soundSource.start(this._startTime, this.isPaused ? this._startOffset % this._soundSource.buffer.duration : 0);
                     this.isPlaying = true;
                     this.isPlaying = true;
                     this.isPaused = false;
                     this.isPaused = false;
                 }
                 }
@@ -321,15 +354,26 @@ var BABYLON;
         */
         */
         Sound.prototype.stop = function (time) {
         Sound.prototype.stop = function (time) {
             if (this.isPlaying) {
             if (this.isPlaying) {
-                var stopTime = time ? BABYLON.Engine.audioEngine.audioContext.currentTime + time : BABYLON.Engine.audioEngine.audioContext.currentTime;
-                this._soundSource.stop(stopTime);
+                if (this._streaming) {
+                    this._htmlAudioElement.pause();
+                    this._htmlAudioElement.currentTime = 0;
+                }
+                else {
+                    var stopTime = time ? BABYLON.Engine.audioEngine.audioContext.currentTime + time : BABYLON.Engine.audioEngine.audioContext.currentTime;
+                    this._soundSource.stop(stopTime);
+                }
                 this.isPlaying = false;
                 this.isPlaying = false;
             }
             }
         };
         };
         Sound.prototype.pause = function () {
         Sound.prototype.pause = function () {
             if (this.isPlaying) {
             if (this.isPlaying) {
-                this.stop(0);
-                this._startOffset += BABYLON.Engine.audioEngine.audioContext.currentTime - this._startTime;
+                if (this._streaming) {
+                    this._htmlAudioElement.pause();
+                }
+                else {
+                    this.stop(0);
+                    this._startOffset += BABYLON.Engine.audioEngine.audioContext.currentTime - this._startTime;
+                }
                 this.isPaused = true;
                 this.isPaused = true;
             }
             }
         };
         };
@@ -348,7 +392,12 @@ var BABYLON;
         Sound.prototype.setPlaybackRate = function (newPlaybackRate) {
         Sound.prototype.setPlaybackRate = function (newPlaybackRate) {
             this._playbackRate = newPlaybackRate;
             this._playbackRate = newPlaybackRate;
             if (this.isPlaying) {
             if (this.isPlaying) {
-                this._soundSource.playbackRate.value = this._playbackRate;
+                if (this._streaming) {
+                    this._htmlAudioElement.playbackRate = this._playbackRate;
+                }
+                else {
+                    this._soundSource.playbackRate.value = this._playbackRate;
+                }
             }
             }
         };
         };
         Sound.prototype.getVolume = function () {
         Sound.prototype.getVolume = function () {

+ 65 - 16
src/Audio/babylon.sound.ts

@@ -13,6 +13,7 @@
         private _panningModel: string = "equalpower";
         private _panningModel: string = "equalpower";
         public onended: () => any;
         public onended: () => any;
         private _playbackRate: number = 1;
         private _playbackRate: number = 1;
+        private _streaming: boolean = false;
         private _startTime: number = 0;
         private _startTime: number = 0;
         private _startOffset: number = 0;
         private _startOffset: number = 0;
         private _position: Vector3 = Vector3.Zero();
         private _position: Vector3 = Vector3.Zero();
@@ -26,6 +27,7 @@
         private _readyToPlayCallback: () => any;
         private _readyToPlayCallback: () => any;
         private _audioBuffer: AudioBuffer;
         private _audioBuffer: AudioBuffer;
         private _soundSource: AudioBufferSourceNode;
         private _soundSource: AudioBufferSourceNode;
+        private _streamingSource: MediaElementAudioSourceNode
         private _soundPanner: PannerNode;
         private _soundPanner: PannerNode;
         private _soundGain: GainNode;
         private _soundGain: GainNode;
         private _inputAudioNode: AudioNode;
         private _inputAudioNode: AudioNode;
@@ -40,6 +42,7 @@
         private _customAttenuationFunction: (currentVolume: number, currentDistance: number, maxDistance: number, refDistance: number, rolloffFactor: number) => number;
         private _customAttenuationFunction: (currentVolume: number, currentDistance: number, maxDistance: number, refDistance: number, rolloffFactor: number) => number;
         private _registerFunc: (connectedMesh: AbstractMesh) => any;
         private _registerFunc: (connectedMesh: AbstractMesh) => any;
         private _isOutputConnected = false;
         private _isOutputConnected = false;
+        private _htmlAudioElement: HTMLAudioElement;
 
 
         /**
         /**
         * Create a sound and attach it to a scene
         * Create a sound and attach it to a scene
@@ -75,6 +78,7 @@
                 this.refDistance = options.refDistance || 1;
                 this.refDistance = options.refDistance || 1;
                 this.distanceModel = options.distanceModel || "linear";
                 this.distanceModel = options.distanceModel || "linear";
                 this._playbackRate = options.playbackRate || 1;
                 this._playbackRate = options.playbackRate || 1;
+                this._streaming = options.streaming || false;
             }
             }
 
 
             if (Engine.audioEngine.canUseWebAudio) {
             if (Engine.audioEngine.canUseWebAudio) {
@@ -90,7 +94,20 @@
                 if (urlOrArrayBuffer) {
                 if (urlOrArrayBuffer) {
                     // If it's an URL
                     // If it's an URL
                     if (typeof (urlOrArrayBuffer) === "string") {
                     if (typeof (urlOrArrayBuffer) === "string") {
-                        Tools.LoadFile(urlOrArrayBuffer, (data) => { this._soundLoaded(data); }, null, null, true);
+                        // Loading sound using XHR2
+                        if (!this._streaming) {
+                            Tools.LoadFile(urlOrArrayBuffer, (data) => { this._soundLoaded(data); }, null, null, true);
+                        }
+                        // Streaming sound using HTML5 Audio tag
+                        else {
+                            this._htmlAudioElement = new Audio();
+                            this._htmlAudioElement.src = urlOrArrayBuffer;;
+                            this._htmlAudioElement.controls = false;
+                            this._htmlAudioElement.loop = this.loop;
+                            this._isReadyToPlay = true;
+                            document.body.appendChild(this._htmlAudioElement);
+                            if (this.autoplay) { this.play(); }
+                        }
                     }
                     }
                     else {
                     else {
                         if (urlOrArrayBuffer instanceof ArrayBuffer) {
                         if (urlOrArrayBuffer instanceof ArrayBuffer) {
@@ -179,7 +196,12 @@
                 this._playbackRate = options.playbackRate || this._playbackRate;
                 this._playbackRate = options.playbackRate || this._playbackRate;
                 this._updateSpatialParameters();
                 this._updateSpatialParameters();
                 if (this.isPlaying) {
                 if (this.isPlaying) {
-                    this._soundSource.playbackRate.value = this._playbackRate;
+                    if (this._streaming) {
+                        this._htmlAudioElement.playbackRate = this._playbackRate;
+                    }
+                    else {
+                        this._soundSource.playbackRate.value = this._playbackRate;
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -306,7 +328,7 @@
             if (this._isReadyToPlay && this._scene.audioEnabled) {
             if (this._isReadyToPlay && this._scene.audioEnabled) {
                 try {
                 try {
                     var startTime = time ? Engine.audioEngine.audioContext.currentTime + time : Engine.audioEngine.audioContext.currentTime;
                     var startTime = time ? Engine.audioEngine.audioContext.currentTime + time : Engine.audioEngine.audioContext.currentTime;
-                    if (!this._soundSource) {
+                    if (!this._soundSource || !this._streamingSource) {
                         if (this.spatialSound) {
                         if (this.spatialSound) {
                             this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
                             this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
                             if (this._isDirectional) {
                             if (this._isDirectional) {
@@ -322,14 +344,25 @@
                             }
                             }
                         }
                         }
                     }
                     }
-                    this._soundSource = Engine.audioEngine.audioContext.createBufferSource();
-                    this._soundSource.buffer = this._audioBuffer;
-                    this._soundSource.connect(this._inputAudioNode);
-                    this._soundSource.loop = this.loop;
-                    this._soundSource.playbackRate.value = this._playbackRate;
+                    if (this._streaming) {
+                        if (!this.isPaused) {
+                            this._streamingSource = Engine.audioEngine.audioContext.createMediaElementSource(this._htmlAudioElement);
+                            this._streamingSource.connect(this._inputAudioNode);
+                            this._htmlAudioElement.onended = () => { this._onended(); };
+                            this._htmlAudioElement.playbackRate = this._playbackRate;
+                        }
+                        this._htmlAudioElement.play();
+                    }
+                    else {
+                        this._soundSource = Engine.audioEngine.audioContext.createBufferSource();
+                        this._soundSource.buffer = this._audioBuffer;
+                        this._soundSource.connect(this._inputAudioNode);
+                        this._soundSource.loop = this.loop;
+                        this._soundSource.playbackRate.value = this._playbackRate;
+                        this._soundSource.onended = () => { this._onended(); };
+                        this._soundSource.start(this._startTime, this.isPaused ? this._startOffset % this._soundSource.buffer.duration : 0);
+                    }
                     this._startTime = startTime;
                     this._startTime = startTime;
-                    this._soundSource.onended = () => { this._onended(); };
-                    this._soundSource.start(this._startTime, this.isPaused ? this._startOffset % this._soundSource.buffer.duration : 0);
                     this.isPlaying = true;
                     this.isPlaying = true;
                     this.isPaused = false;
                     this.isPaused = false;
                 }
                 }
@@ -352,17 +385,28 @@
         */
         */
         public stop(time?: number) {
         public stop(time?: number) {
             if (this.isPlaying) {
             if (this.isPlaying) {
-                var stopTime = time ? Engine.audioEngine.audioContext.currentTime + time : Engine.audioEngine.audioContext.currentTime;
-                this._soundSource.stop(stopTime);
+                if (this._streaming) {
+                    this._htmlAudioElement.pause();
+                    this._htmlAudioElement.currentTime = 0;
+                }
+                else {
+                    var stopTime = time ? Engine.audioEngine.audioContext.currentTime + time : Engine.audioEngine.audioContext.currentTime;
+                    this._soundSource.stop(stopTime);
+                }
                 this.isPlaying = false;
                 this.isPlaying = false;
             }
             }
         }
         }
 
 
         public pause() {
         public pause() {
             if (this.isPlaying) {
             if (this.isPlaying) {
-                this.stop(0);
-                this._startOffset += Engine.audioEngine.audioContext.currentTime - this._startTime;
-                this.isPaused = true;
+                if (this._streaming) {
+                    this._htmlAudioElement.pause();
+                }
+                else {
+                    this.stop(0);
+                    this._startOffset += Engine.audioEngine.audioContext.currentTime - this._startTime;
+                }
+                this.isPaused = true;  
             }
             }
         }
         }
 
 
@@ -382,7 +426,12 @@
         public setPlaybackRate(newPlaybackRate: number) {
         public setPlaybackRate(newPlaybackRate: number) {
             this._playbackRate = newPlaybackRate;
             this._playbackRate = newPlaybackRate;
             if (this.isPlaying) {
             if (this.isPlaying) {
-                this._soundSource.playbackRate.value = this._playbackRate;
+                if (this._streaming) {
+                    this._htmlAudioElement.playbackRate = this._playbackRate;
+                }
+                else {
+                    this._soundSource.playbackRate.value = this._playbackRate;
+                }
             }
             }
         }
         }
 
 

+ 6 - 0
src/Bones/babylon.skeleton.js

@@ -97,6 +97,12 @@ var BABYLON;
             }
             }
             return result;
             return result;
         };
         };
+        Skeleton.prototype.dispose = function () {
+            // Animations
+            this.getScene().stopAnimation(this);
+            // Remove from scene
+            this.getScene().removeSkeleton(this);
+        };
         return Skeleton;
         return Skeleton;
     })();
     })();
     BABYLON.Skeleton = Skeleton;
     BABYLON.Skeleton = Skeleton;

+ 8 - 0
src/Bones/babylon.skeleton.ts

@@ -128,5 +128,13 @@
 
 
             return result;
             return result;
         }
         }
+
+        public dispose() {
+            // Animations
+            this.getScene().stopAnimation(this);
+
+            // Remove from scene
+            this.getScene().removeSkeleton(this);
+        }
     }
     }
 }
 }

+ 3 - 0
src/Cameras/babylon.arcRotateCamera.js

@@ -446,6 +446,9 @@ var BABYLON;
             }
             }
         };
         };
         ArcRotateCamera.prototype.setPosition = function (position) {
         ArcRotateCamera.prototype.setPosition = function (position) {
+            if (this.position.equals(position)) {
+                return;
+            }
             var radiusv3 = position.subtract(this._getTargetPosition());
             var radiusv3 = position.subtract(this._getTargetPosition());
             this.radius = radiusv3.length();
             this.radius = radiusv3.length();
             // Alpha
             // Alpha

+ 3 - 0
src/Cameras/babylon.arcRotateCamera.ts

@@ -487,6 +487,9 @@
         }
         }
 
 
         public setPosition(position: Vector3): void {
         public setPosition(position: Vector3): void {
+            if (this.position.equals(position)) {
+                return;
+            }
             var radiusv3 = position.subtract(this._getTargetPosition());
             var radiusv3 = position.subtract(this._getTargetPosition());
             this.radius = radiusv3.length();
             this.radius = radiusv3.length();
 
 

+ 2 - 0
src/Cameras/babylon.camera.js

@@ -406,6 +406,8 @@ var BABYLON;
             return this._projectionMatrix;
             return this._projectionMatrix;
         };
         };
         Camera.prototype.dispose = function () {
         Camera.prototype.dispose = function () {
+            // Animations
+            this.getScene().stopAnimation(this);
             // Remove from scene
             // Remove from scene
             this.getScene().removeCamera(this);
             this.getScene().removeCamera(this);
             while (this._rigCameras.length > 0) {
             while (this._rigCameras.length > 0) {

+ 3 - 0
src/Cameras/babylon.camera.ts

@@ -450,6 +450,9 @@
         }
         }
 
 
         public dispose(): void {
         public dispose(): void {
+            // Animations
+            this.getScene().stopAnimation(this);
+
             // Remove from scene
             // Remove from scene
             this.getScene().removeCamera(this);
             this.getScene().removeCamera(this);
             while (this._rigCameras.length > 0) {
             while (this._rigCameras.length > 0) {

+ 2 - 0
src/Lights/babylon.light.js

@@ -68,6 +68,8 @@ var BABYLON;
                 this._shadowGenerator.dispose();
                 this._shadowGenerator.dispose();
                 this._shadowGenerator = null;
                 this._shadowGenerator = null;
             }
             }
+            // Animations
+            this.getScene().stopAnimation(this);
             // Remove from scene
             // Remove from scene
             this.getScene().removeLight(this);
             this.getScene().removeLight(this);
         };
         };

+ 3 - 0
src/Lights/babylon.light.ts

@@ -104,6 +104,9 @@
                 this._shadowGenerator = null;
                 this._shadowGenerator = null;
             }
             }
 
 
+            // Animations
+            this.getScene().stopAnimation(this);
+
             // Remove from scene
             // Remove from scene
             this.getScene().removeLight(this);
             this.getScene().removeLight(this);
         }
         }

+ 2 - 0
src/Materials/Textures/babylon.baseTexture.js

@@ -99,6 +99,8 @@ var BABYLON;
             }
             }
         };
         };
         BaseTexture.prototype.dispose = function () {
         BaseTexture.prototype.dispose = function () {
+            // Animations
+            this.getScene().stopAnimation(this);
             // Remove from scene
             // Remove from scene
             var index = this._scene.textures.indexOf(this);
             var index = this._scene.textures.indexOf(this);
             if (index >= 0) {
             if (index >= 0) {

+ 3 - 0
src/Materials/Textures/babylon.baseTexture.ts

@@ -125,6 +125,9 @@
         }
         }
 
 
         public dispose(): void {
         public dispose(): void {
+            // Animations
+            this.getScene().stopAnimation(this);
+
             // Remove from scene
             // Remove from scene
             var index = this._scene.textures.indexOf(this);
             var index = this._scene.textures.indexOf(this);
 
 

+ 2 - 0
src/Materials/babylon.material.js

@@ -190,6 +190,8 @@ var BABYLON;
             return result;
             return result;
         };
         };
         Material.prototype.dispose = function (forceDisposeEffect) {
         Material.prototype.dispose = function (forceDisposeEffect) {
+            // Animations
+            this.getScene().stopAnimation(this);
             // Remove from scene
             // Remove from scene
             var index = this._scene.materials.indexOf(this);
             var index = this._scene.materials.indexOf(this);
             if (index >= 0) {
             if (index >= 0) {

+ 3 - 0
src/Materials/babylon.material.ts

@@ -219,6 +219,9 @@
         }
         }
 
 
         public dispose(forceDisposeEffect?: boolean): void {
         public dispose(forceDisposeEffect?: boolean): void {
+            // Animations
+            this.getScene().stopAnimation(this);
+
             // Remove from scene
             // Remove from scene
             var index = this._scene.materials.indexOf(this);
             var index = this._scene.materials.indexOf(this);
             if (index >= 0) {
             if (index >= 0) {

+ 9 - 10
src/Materials/babylon.standardMaterial.js

@@ -87,6 +87,7 @@ var BABYLON;
             this.GLOSSINESS = false;
             this.GLOSSINESS = false;
             this.ROUGHNESS = false;
             this.ROUGHNESS = false;
             this.EMISSIVEASILLUMINATION = false;
             this.EMISSIVEASILLUMINATION = false;
+            this.LINKEMISSIVEWITHDIFFUSE = false;
             this.REFLECTIONFRESNELFROMSPECULAR = false;
             this.REFLECTIONFRESNELFROMSPECULAR = false;
             this.LIGHTMAP = false;
             this.LIGHTMAP = false;
             this.USELIGHTMAPASSHADOWMAP = false;
             this.USELIGHTMAPASSHADOWMAP = false;
@@ -115,6 +116,7 @@ var BABYLON;
             this.emissiveColor = new BABYLON.Color3(0, 0, 0);
             this.emissiveColor = new BABYLON.Color3(0, 0, 0);
             this.useAlphaFromDiffuseTexture = false;
             this.useAlphaFromDiffuseTexture = false;
             this.useEmissiveAsIllumination = false;
             this.useEmissiveAsIllumination = false;
+            this.linkEmissiveWithDiffuse = false;
             this.useReflectionFresnelFromSpecular = false;
             this.useReflectionFresnelFromSpecular = false;
             this.useSpecularOverAlpha = true;
             this.useSpecularOverAlpha = true;
             this.disableLighting = false;
             this.disableLighting = false;
@@ -304,6 +306,9 @@ var BABYLON;
             if (this.useEmissiveAsIllumination) {
             if (this.useEmissiveAsIllumination) {
                 this._defines.EMISSIVEASILLUMINATION = true;
                 this._defines.EMISSIVEASILLUMINATION = true;
             }
             }
+            if (this.linkEmissiveWithDiffuse) {
+                this._defines.LINKEMISSIVEWITHDIFFUSE = true;
+            }
             if (this.useReflectionFresnelFromSpecular) {
             if (this.useReflectionFresnelFromSpecular) {
                 this._defines.REFLECTIONFRESNELFROMSPECULAR = true;
                 this._defines.REFLECTIONFRESNELFROMSPECULAR = true;
             }
             }
@@ -646,22 +651,16 @@ var BABYLON;
                 }
                 }
                 // Colors
                 // Colors
                 scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
                 scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
-                // Scaling down color according to emissive
-                this._scaledSpecular.r = this.specularColor.r * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.r);
-                this._scaledSpecular.g = this.specularColor.g * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.g);
-                this._scaledSpecular.b = this.specularColor.b * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.b);
                 this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
                 this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
                 this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
                 this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
                 if (this._defines.SPECULARTERM) {
                 if (this._defines.SPECULARTERM) {
-                    this._effect.setColor4("vSpecularColor", this._scaledSpecular, this.specularPower);
+                    this._effect.setColor4("vSpecularColor", this.specularColor, this.specularPower);
                 }
                 }
                 this._effect.setColor3("vEmissiveColor", this.emissiveColor);
                 this._effect.setColor3("vEmissiveColor", this.emissiveColor);
             }
             }
-            // Scaling down color according to emissive
-            this._scaledDiffuse.r = this.diffuseColor.r * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.r);
-            this._scaledDiffuse.g = this.diffuseColor.g * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.g);
-            this._scaledDiffuse.b = this.diffuseColor.b * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.b);
-            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
+            // Diffuse
+            this._effect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
+            // Lights
             if (scene.lightsEnabled && !this.disableLighting) {
             if (scene.lightsEnabled && !this.disableLighting) {
                 var lightIndex = 0;
                 var lightIndex = 0;
                 for (var index = 0; index < scene.lights.length; index++) {
                 for (var index = 0; index < scene.lights.length; index++) {

+ 11 - 13
src/Materials/babylon.standardMaterial.ts

@@ -79,6 +79,7 @@
         public GLOSSINESS = false;
         public GLOSSINESS = false;
         public ROUGHNESS = false;
         public ROUGHNESS = false;
         public EMISSIVEASILLUMINATION = false;
         public EMISSIVEASILLUMINATION = false;
+        public LINKEMISSIVEWITHDIFFUSE = false;
         public REFLECTIONFRESNELFROMSPECULAR = false;
         public REFLECTIONFRESNELFROMSPECULAR = false;
         public LIGHTMAP = false;
         public LIGHTMAP = false;
         public USELIGHTMAPASSHADOWMAP = false;
         public USELIGHTMAPASSHADOWMAP = false;
@@ -115,6 +116,7 @@
         public emissiveColor = new Color3(0, 0, 0);
         public emissiveColor = new Color3(0, 0, 0);
         public useAlphaFromDiffuseTexture = false;
         public useAlphaFromDiffuseTexture = false;
         public useEmissiveAsIllumination = false;
         public useEmissiveAsIllumination = false;
+        public linkEmissiveWithDiffuse = false;
         public useReflectionFresnelFromSpecular = false;
         public useReflectionFresnelFromSpecular = false;
         public useSpecularOverAlpha = true;
         public useSpecularOverAlpha = true;
         public disableLighting = false;
         public disableLighting = false;
@@ -345,6 +347,10 @@
                 this._defines.EMISSIVEASILLUMINATION = true;
                 this._defines.EMISSIVEASILLUMINATION = true;
             }
             }
 
 
+            if (this.linkEmissiveWithDiffuse) {
+                this._defines.LINKEMISSIVEWITHDIFFUSE = true;
+            }
+
             if (this.useReflectionFresnelFromSpecular) {
             if (this.useReflectionFresnelFromSpecular) {
                 this._defines.REFLECTIONFRESNELFROMSPECULAR = true;
                 this._defines.REFLECTIONFRESNELFROMSPECULAR = true;
             }
             }
@@ -780,27 +786,19 @@
                 // Colors
                 // Colors
                 scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
                 scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
 
 
-                // Scaling down color according to emissive
-                this._scaledSpecular.r = this.specularColor.r * Tools.Clamp(1.0 - this.emissiveColor.r);
-                this._scaledSpecular.g = this.specularColor.g * Tools.Clamp(1.0 - this.emissiveColor.g);
-                this._scaledSpecular.b = this.specularColor.b * Tools.Clamp(1.0 - this.emissiveColor.b);
-
                 this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
                 this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
                 this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
                 this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
 
 
                 if (this._defines.SPECULARTERM) {
                 if (this._defines.SPECULARTERM) {
-                    this._effect.setColor4("vSpecularColor", this._scaledSpecular, this.specularPower);
+                    this._effect.setColor4("vSpecularColor", this.specularColor, this.specularPower);
                 }
                 }
                 this._effect.setColor3("vEmissiveColor", this.emissiveColor);
                 this._effect.setColor3("vEmissiveColor", this.emissiveColor);
             }
             }
+            
+            // Diffuse
+            this._effect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
 
 
-            // Scaling down color according to emissive
-            this._scaledDiffuse.r = this.diffuseColor.r * Tools.Clamp(1.0 - this.emissiveColor.r);
-            this._scaledDiffuse.g = this.diffuseColor.g * Tools.Clamp(1.0 - this.emissiveColor.g);
-            this._scaledDiffuse.b = this.diffuseColor.b * Tools.Clamp(1.0 - this.emissiveColor.b);
-
-            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
-
+            // Lights
             if (scene.lightsEnabled && !this.disableLighting) {
             if (scene.lightsEnabled && !this.disableLighting) {
                 var lightIndex = 0;
                 var lightIndex = 0;
                 for (var index = 0; index < scene.lights.length; index++) {
                 for (var index = 0; index < scene.lights.length; index++) {

+ 2 - 0
src/Mesh/babylon.abstractMesh.js

@@ -826,6 +826,8 @@ var BABYLON;
         };
         };
         AbstractMesh.prototype.dispose = function (doNotRecurse) {
         AbstractMesh.prototype.dispose = function (doNotRecurse) {
             var index;
             var index;
+            // Animations
+            this.getScene().stopAnimation(this);
             // Physics
             // Physics
             if (this.getPhysicsImpostor() !== BABYLON.PhysicsEngine.NoImpostor) {
             if (this.getPhysicsImpostor() !== BABYLON.PhysicsEngine.NoImpostor) {
                 this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
                 this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);

+ 3 - 0
src/Mesh/babylon.abstractMesh.ts

@@ -980,6 +980,9 @@
         public dispose(doNotRecurse?: boolean): void {
         public dispose(doNotRecurse?: boolean): void {
             var index: number;
             var index: number;
 
 
+            // Animations
+            this.getScene().stopAnimation(this);
+
             // Physics
             // Physics
             if (this.getPhysicsImpostor() !== PhysicsEngine.NoImpostor) {
             if (this.getPhysicsImpostor() !== PhysicsEngine.NoImpostor) {
                 this.setPhysicsState(PhysicsEngine.NoImpostor);
                 this.setPhysicsState(PhysicsEngine.NoImpostor);

+ 3 - 3
src/Mesh/babylon.mesh.vertexData.js

@@ -567,7 +567,7 @@ var BABYLON;
             var diameterX = options.diameterX || options.diameter || 1;
             var diameterX = options.diameterX || options.diameter || 1;
             var diameterY = options.diameterY || options.diameter || 1;
             var diameterY = options.diameterY || options.diameter || 1;
             var diameterZ = options.diameterZ || options.diameter || 1;
             var diameterZ = options.diameterZ || options.diameter || 1;
-            var arc = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var slice = (options.slice <= 0) ? 1.0 : options.slice || 1.0;
             var slice = (options.slice <= 0) ? 1.0 : options.slice || 1.0;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             var radius = new BABYLON.Vector3(diameterX / 2, diameterY / 2, diameterZ / 2);
             var radius = new BABYLON.Vector3(diameterX / 2, diameterY / 2, diameterZ / 2);
@@ -622,7 +622,7 @@ var BABYLON;
             var diameterBottom = options.diameterBottom || options.diameter || 1;
             var diameterBottom = options.diameterBottom || options.diameter || 1;
             var tessellation = options.tessellation || 24;
             var tessellation = options.tessellation || 24;
             var subdivisions = options.subdivisions || 1;
             var subdivisions = options.subdivisions || 1;
-            var arc = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             var faceUV = options.faceUV || new Array(3);
             var faceUV = options.faceUV || new Array(3);
             var faceColors = options.faceColors;
             var faceColors = options.faceColors;
@@ -1058,7 +1058,7 @@ var BABYLON;
             var uvs = [];
             var uvs = [];
             var radius = options.radius || 0.5;
             var radius = options.radius || 0.5;
             var tessellation = options.tessellation || 64;
             var tessellation = options.tessellation || 64;
-            var arc = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             // positions and uvs
             // positions and uvs
             positions.push(0, 0, 0); // disc center first
             positions.push(0, 0, 0); // disc center first

+ 4 - 3
src/Mesh/babylon.mesh.vertexData.ts

@@ -690,7 +690,7 @@
             var diameterX: number = options.diameterX || options.diameter || 1;
             var diameterX: number = options.diameterX || options.diameter || 1;
             var diameterY: number = options.diameterY || options.diameter || 1;
             var diameterY: number = options.diameterY || options.diameter || 1;
             var diameterZ: number = options.diameterZ || options.diameter || 1;
             var diameterZ: number = options.diameterZ || options.diameter || 1;
-            var arc: number = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc: number = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var slice: number = (options.slice <= 0) ? 1.0 : options.slice || 1.0;
             var slice: number = (options.slice <= 0) ? 1.0 : options.slice || 1.0;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
 
 
@@ -761,7 +761,7 @@
             var diameterBottom: number = options.diameterBottom || options.diameter || 1;
             var diameterBottom: number = options.diameterBottom || options.diameter || 1;
             var tessellation: number = options.tessellation || 24;
             var tessellation: number = options.tessellation || 24;
             var subdivisions: number = options.subdivisions || 1;
             var subdivisions: number = options.subdivisions || 1;
-            var arc: number = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc: number = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var sideOrientation: number = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
             var sideOrientation: number = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
             var faceUV: Vector4[] = options.faceUV || new Array<Vector4>(3);
             var faceUV: Vector4[] = options.faceUV || new Array<Vector4>(3);
             var faceColors: Color4[] = options.faceColors;
             var faceColors: Color4[] = options.faceColors;
@@ -1293,7 +1293,7 @@
 
 
             var radius = options.radius || 0.5;
             var radius = options.radius || 0.5;
             var tessellation = options.tessellation || 64;
             var tessellation = options.tessellation || 64;
-            var arc: number = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc: number = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
             var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
 
 
             // positions and uvs
             // positions and uvs
@@ -1676,3 +1676,4 @@
 
 
 
 
 
 
+

+ 2 - 2
src/Mesh/babylon.meshBuilder.js

@@ -225,7 +225,7 @@ var BABYLON;
             return MeshBuilder._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, cap, true, scene, updatable, sideOrientation, instance);
             return MeshBuilder._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, cap, true, scene, updatable, sideOrientation, instance);
         };
         };
         MeshBuilder.CreateLathe = function (name, options, scene) {
         MeshBuilder.CreateLathe = function (name, options, scene) {
-            var arc = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var closed = (options.closed === undefined) ? true : options.closed;
             var closed = (options.closed === undefined) ? true : options.closed;
             var shape = options.shape;
             var shape = options.shape;
             var radius = options.radius || 1;
             var radius = options.radius || 1;
@@ -336,7 +336,7 @@ var BABYLON;
             var updatable = options.updatable;
             var updatable = options.updatable;
             var sideOrientation = options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             var sideOrientation = options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE;
             var instance = options.instance;
             var instance = options.instance;
-            options.arc = (options.arc < 0) ? 1 : options.arc || 1;
+            options.arc = (options.arc <= 0 || options.arc > 1) ? 1 : options.arc || 1;
             // tube geometry
             // tube geometry
             var tubePathArray = function (path, path3D, circlePaths, radius, tessellation, radiusFunction, cap, arc) {
             var tubePathArray = function (path, path3D, circlePaths, radius, tessellation, radiusFunction, cap, arc) {
                 var tangents = path3D.getTangents();
                 var tangents = path3D.getTangents();

+ 3 - 2
src/Mesh/babylon.meshBuilder.ts

@@ -258,7 +258,7 @@
         }
         }
 
 
         public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, arc?: number, closed?: boolean, updatable?: boolean, sideOrientation?: number }, scene: Scene): Mesh {
         public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, arc?: number, closed?: boolean, updatable?: boolean, sideOrientation?: number }, scene: Scene): Mesh {
-            var arc: number = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
+            var arc: number = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
             var closed: boolean = (options.closed === undefined) ? true : options.closed;
             var closed: boolean = (options.closed === undefined) ? true : options.closed;
             var shape = options.shape;
             var shape = options.shape;
             var radius = options.radius || 1;
             var radius = options.radius || 1;
@@ -399,7 +399,7 @@
             var updatable = options.updatable;
             var updatable = options.updatable;
             var sideOrientation = options.sideOrientation || Mesh.DEFAULTSIDE;
             var sideOrientation = options.sideOrientation || Mesh.DEFAULTSIDE;
             var instance = options.instance;
             var instance = options.instance;
-            options.arc = (options.arc < 0) ? 1 : options.arc || 1;
+            options.arc = (options.arc <= 0 || options.arc > 1) ? 1 : options.arc || 1;
 
 
             // tube geometry
             // tube geometry
             var tubePathArray = (path, path3D, circlePaths, radius, tessellation, radiusFunction, cap, arc) => {
             var tubePathArray = (path, path3D, circlePaths, radius, tessellation, radiusFunction, cap, arc) => {
@@ -794,3 +794,4 @@
 }
 }
 
 
 
 
+

+ 0 - 2
src/Particles/babylon.solidParticle.ts

@@ -13,8 +13,6 @@ module BABYLON {
         public _pos: number;                    // index of this particle in the global "positions" array
         public _pos: number;                    // index of this particle in the global "positions" array
         public _model: ModelShape;              // model shape reference
         public _model: ModelShape;              // model shape reference
         public shapeId: number;                 // model shape id
         public shapeId: number;                 // model shape id
-        public previous: SolidParticle;         // pointer to the previous particle in the global particles array
-        public next: SolidParticle;             // pointer to the next particle in the global particles array
         public idxInShape: number;              // index of the particle in its shape id
         public idxInShape: number;              // index of the particle in its shape id
 
 
         constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number) {
         constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number) {

+ 29 - 13
src/Particles/babylon.solidParticleSystem.js

@@ -1,7 +1,7 @@
 var BABYLON;
 var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     var SolidParticleSystem = (function () {
     var SolidParticleSystem = (function () {
-        function SolidParticleSystem(name, scene) {
+        function SolidParticleSystem(name, scene, options) {
             // public members  
             // public members  
             this.particles = new Array();
             this.particles = new Array();
             this.nbParticles = 0;
             this.nbParticles = 0;
@@ -13,6 +13,7 @@ var BABYLON;
             this._colors = new Array();
             this._colors = new Array();
             this._uvs = new Array();
             this._uvs = new Array();
             this._index = 0; // indices index
             this._index = 0; // indices index
+            this._updatable = true;
             this._shapeCounter = 0;
             this._shapeCounter = 0;
             this._copy = new BABYLON.SolidParticle(null, null, null, null, null);
             this._copy = new BABYLON.SolidParticle(null, null, null, null, null);
             this._color = new BABYLON.Color4(0, 0, 0, 0);
             this._color = new BABYLON.Color4(0, 0, 0, 0);
@@ -47,10 +48,15 @@ var BABYLON;
             this.name = name;
             this.name = name;
             this._scene = scene;
             this._scene = scene;
             this._camera = scene.activeCamera;
             this._camera = scene.activeCamera;
+            if (options && options.updatable) {
+                this._updatable = options.updatable;
+            }
+            else {
+                this._updatable = true;
+            }
         }
         }
         // build the SPS mesh : returns the mesh
         // build the SPS mesh : returns the mesh
-        SolidParticleSystem.prototype.buildMesh = function (upgradable) {
-            if (upgradable === void 0) { upgradable = true; }
+        SolidParticleSystem.prototype.buildMesh = function () {
             if (this.nbParticles === 0) {
             if (this.nbParticles === 0) {
                 var triangle = BABYLON.MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
                 var triangle = BABYLON.MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
                 this.addShape(triangle, 1);
                 this.addShape(triangle, 1);
@@ -73,13 +79,16 @@ var BABYLON;
                 vertexData.set(this._colors32, BABYLON.VertexBuffer.ColorKind);
                 vertexData.set(this._colors32, BABYLON.VertexBuffer.ColorKind);
             }
             }
             var mesh = new BABYLON.Mesh(name, this._scene);
             var mesh = new BABYLON.Mesh(name, this._scene);
-            vertexData.applyToMesh(mesh, upgradable);
+            vertexData.applyToMesh(mesh, this._updatable);
             this.mesh = mesh;
             this.mesh = mesh;
             // free memory
             // free memory
             this._positions = null;
             this._positions = null;
             this._normals = null;
             this._normals = null;
             this._uvs = null;
             this._uvs = null;
             this._colors = null;
             this._colors = null;
+            if (!this._updatable) {
+                this.particles.length = 0;
+            }
             return mesh;
             return mesh;
         };
         };
         //reset copy
         //reset copy
@@ -177,15 +186,9 @@ var BABYLON;
             }
             }
             return shapeUV;
             return shapeUV;
         };
         };
-        // adds a new particle object in the particles array and double links the particle (next/previous)
+        // adds a new particle object in the particles array
         SolidParticleSystem.prototype._addParticle = function (p, idxpos, model, shapeId, idxInShape) {
         SolidParticleSystem.prototype._addParticle = function (p, idxpos, model, shapeId, idxInShape) {
-            this._particle = new BABYLON.SolidParticle(p, idxpos, model, shapeId, idxInShape);
-            this.particles.push(this._particle);
-            this._particle.previous = this._previousParticle;
-            if (this._previousParticle) {
-                this._previousParticle.next = this._particle;
-            }
-            this._previousParticle = this._particle;
+            this.particles.push(new BABYLON.SolidParticle(p, idxpos, model, shapeId, idxInShape));
         };
         };
         // add solid particles from a shape model in the particles array
         // add solid particles from a shape model in the particles array
         SolidParticleSystem.prototype.addShape = function (mesh, nb, options) {
         SolidParticleSystem.prototype.addShape = function (mesh, nb, options) {
@@ -201,7 +204,9 @@ var BABYLON;
             // particles
             // particles
             for (var i = 0; i < nb; i++) {
             for (var i = 0; i < nb; i++) {
                 this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, this.nbParticles + i, i, options);
                 this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, this.nbParticles + i, i, options);
-                this._addParticle(this.nbParticles + i, this._positions.length, modelShape, this._shapeCounter, i);
+                if (this._updatable) {
+                    this._addParticle(this.nbParticles + i, this._positions.length, modelShape, this._shapeCounter, i);
+                }
                 this._index += shape.length;
                 this._index += shape.length;
             }
             }
             this.nbParticles += nb;
             this.nbParticles += nb;
@@ -303,6 +308,7 @@ var BABYLON;
             var uvidx = 0;
             var uvidx = 0;
             var uvIndex = 0;
             var uvIndex = 0;
             // particle loop
             // particle loop
+            end = (end > this.nbParticles - 1) ? this.nbParticles - 1 : end;
             for (var p = start; p <= end; p++) {
             for (var p = start; p <= end; p++) {
                 this._particle = this.particles[p];
                 this._particle = this.particles[p];
                 this._shape = this._particle._model._shape;
                 this._shape = this._particle._model._shape;
@@ -412,6 +418,16 @@ var BABYLON;
         // dispose the SPS
         // dispose the SPS
         SolidParticleSystem.prototype.dispose = function () {
         SolidParticleSystem.prototype.dispose = function () {
             this.mesh.dispose();
             this.mesh.dispose();
+            // drop references to internal big arrays for the GC
+            this._positions = null;
+            this._indices = null;
+            this._normals = null;
+            this._uvs = null;
+            this._colors = null;
+            this._positions32 = null;
+            this._normals32 = null;
+            this._uvs32 = null;
+            this._colors32 = null;
         };
         };
         Object.defineProperty(SolidParticleSystem.prototype, "computeParticleRotation", {
         Object.defineProperty(SolidParticleSystem.prototype, "computeParticleRotation", {
             // getters
             // getters

+ 31 - 13
src/Particles/babylon.solidParticleSystem.ts

@@ -21,6 +21,7 @@ module BABYLON {
         private _colors32: Float32Array;
         private _colors32: Float32Array;
         private _uvs32: Float32Array;
         private _uvs32: Float32Array;
         private _index: number = 0;  // indices index
         private _index: number = 0;  // indices index
+        private _updatable: boolean = true;
         private _shapeCounter: number = 0;
         private _shapeCounter: number = 0;
         private _copy: SolidParticle = new SolidParticle(null, null, null, null, null);
         private _copy: SolidParticle = new SolidParticle(null, null, null, null, null);
         private _shape: Vector3[];
         private _shape: Vector3[];
@@ -38,7 +39,6 @@ module BABYLON {
         private _axisZ: Vector3 = Axis.Z;
         private _axisZ: Vector3 = Axis.Z;
         private _camera: Camera;
         private _camera: Camera;
         private _particle: SolidParticle;
         private _particle: SolidParticle;
-        private _previousParticle: SolidParticle;
         private _fakeCamPos: Vector3 = Vector3.Zero();
         private _fakeCamPos: Vector3 = Vector3.Zero();
         private _rotMatrix: Matrix = new Matrix();
         private _rotMatrix: Matrix = new Matrix();
         private _invertedMatrix: Matrix = new Matrix();
         private _invertedMatrix: Matrix = new Matrix();
@@ -59,14 +59,19 @@ module BABYLON {
         private _cosYaw: number = 0.0;
         private _cosYaw: number = 0.0;
 
 
 
 
-        constructor(name: string, scene: Scene) {
+        constructor(name: string, scene: Scene, options?: { updatable?: boolean }) {
             this.name = name;
             this.name = name;
             this._scene = scene;
             this._scene = scene;
             this._camera = scene.activeCamera;
             this._camera = scene.activeCamera;
+            if (options && options.updatable) {
+                this._updatable = options.updatable;
+            } else {
+                this._updatable = true;
+            }
         }
         }
 
 
         // build the SPS mesh : returns the mesh
         // build the SPS mesh : returns the mesh
-        public buildMesh(upgradable: boolean = true): Mesh {
+        public buildMesh(): Mesh {
             if (this.nbParticles === 0) {
             if (this.nbParticles === 0) {
                 var triangle = MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
                 var triangle = MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
                 this.addShape(triangle, 1);
                 this.addShape(triangle, 1);
@@ -88,7 +93,7 @@ module BABYLON {
                 vertexData.set(this._colors32, VertexBuffer.ColorKind);
                 vertexData.set(this._colors32, VertexBuffer.ColorKind);
             }
             }
             var mesh = new Mesh(name, this._scene);
             var mesh = new Mesh(name, this._scene);
-            vertexData.applyToMesh(mesh, upgradable);
+            vertexData.applyToMesh(mesh, this._updatable);
             this.mesh = mesh;
             this.mesh = mesh;
 
 
             // free memory
             // free memory
@@ -97,6 +102,10 @@ module BABYLON {
             this._uvs = null;
             this._uvs = null;
             this._colors = null;
             this._colors = null;
 
 
+            if (!this._updatable) {
+                this.particles.length = 0;
+            }
+
             return mesh;
             return mesh;
         }
         }
 
 
@@ -204,15 +213,9 @@ module BABYLON {
             return shapeUV;
             return shapeUV;
         }
         }
 
 
-        // adds a new particle object in the particles array and double links the particle (next/previous)
+        // adds a new particle object in the particles array
         private _addParticle(p: number, idxpos: number, model: ModelShape, shapeId: number, idxInShape: number): void {
         private _addParticle(p: number, idxpos: number, model: ModelShape, shapeId: number, idxInShape: number): void {
-            this._particle = new SolidParticle(p, idxpos, model, shapeId, idxInShape);
-            this.particles.push(this._particle);
-            this._particle.previous = this._previousParticle;
-            if (this._previousParticle) {
-                this._previousParticle.next = this._particle;
-            }
-            this._previousParticle = this._particle;
+            this.particles.push(new SolidParticle(p, idxpos, model, shapeId, idxInShape));
         }
         }
 
 
         // add solid particles from a shape model in the particles array
         // add solid particles from a shape model in the particles array
@@ -233,7 +236,9 @@ module BABYLON {
             // particles
             // particles
             for (var i = 0; i < nb; i++) {
             for (var i = 0; i < nb; i++) {
                 this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, this.nbParticles + i, i, options);
                 this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, this.nbParticles + i, i, options);
-                this._addParticle(this.nbParticles + i, this._positions.length, modelShape, this._shapeCounter, i);
+                if (this._updatable) {
+                    this._addParticle(this.nbParticles + i, this._positions.length, modelShape, this._shapeCounter, i);
+                }
                 this._index += shape.length;
                 this._index += shape.length;
             }
             }
             this.nbParticles += nb;
             this.nbParticles += nb;
@@ -348,6 +353,7 @@ module BABYLON {
             var uvIndex = 0;
             var uvIndex = 0;
 
 
             // particle loop
             // particle loop
+            end = (end > this.nbParticles - 1) ? this.nbParticles - 1 : end;
             for (var p = start; p <= end; p++) {
             for (var p = start; p <= end; p++) {
                 this._particle = this.particles[p];
                 this._particle = this.particles[p];
                 this._shape = this._particle._model._shape;
                 this._shape = this._particle._model._shape;
@@ -469,6 +475,16 @@ module BABYLON {
         // dispose the SPS
         // dispose the SPS
         public dispose(): void {
         public dispose(): void {
             this.mesh.dispose();
             this.mesh.dispose();
+            // drop references to internal big arrays for the GC
+            this._positions = null;
+            this._indices = null;
+            this._normals = null;
+            this._uvs = null;
+            this._colors = null;
+            this._positions32 = null;
+            this._normals32 = null;
+            this._uvs32 = null;
+            this._colors32 = null;
         }
         }
 
 
         // Optimizer setters
         // Optimizer setters
@@ -549,3 +565,5 @@ module BABYLON {
 
 
 
 
 
 
+
+

+ 78 - 27
src/Physics/Plugins/babylon.cannonJSPlugin.js

@@ -16,7 +16,29 @@ var BABYLON;
                             var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                             var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                             body.quaternion = body.quaternion.mult(tmpQ);
                             body.quaternion = body.quaternion.mult(tmpQ);
                         }
                         }
-                        //TODO - If the body is heightmap-based, this won't work correctly. find a good fix.
+                        if (registeredMesh.heightmap) {
+                            //calculate the correct body position:
+                            var rotationQuaternion = mesh.rotationQuaternion;
+                            mesh.rotationQuaternion = new BABYLON.Quaternion();
+                            mesh.computeWorldMatrix(true);
+                            //get original center with no rotation
+                            var center = mesh.getBoundingInfo().boundingBox.center.clone();
+                            var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
+                            //rotation is back
+                            mesh.rotationQuaternion = rotationQuaternion;
+                            //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                            var p = BABYLON.Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                            mesh.setPivotMatrix(p);
+                            mesh.computeWorldMatrix(true);
+                            //calculate the translation
+                            var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+                            body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                            //add it inverted to the delta 
+                            registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                            registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+                            mesh.setPivotMatrix(oldPivot);
+                            mesh.computeWorldMatrix(true);
+                        }
                         return;
                         return;
                     }
                     }
                 }
                 }
@@ -104,9 +126,10 @@ var BABYLON;
         CannonJSPlugin.prototype._createConvexPolyhedron = function (rawVerts, rawFaces, mesh) {
         CannonJSPlugin.prototype._createConvexPolyhedron = function (rawVerts, rawFaces, mesh) {
             var verts = [], faces = [];
             var verts = [], faces = [];
             mesh.computeWorldMatrix(true);
             mesh.computeWorldMatrix(true);
+            //reuse this variable
+            var transformed = BABYLON.Vector3.Zero();
             // Get vertices
             // Get vertices
             for (var i = 0; i < rawVerts.length; i += 3) {
             for (var i = 0; i < rawVerts.length; i += 3) {
-                var transformed = BABYLON.Vector3.Zero();
                 BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
                 BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
                 verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
                 verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
             }
             }
@@ -117,41 +140,51 @@ var BABYLON;
             var shape = new CANNON.ConvexPolyhedron(verts, faces);
             var shape = new CANNON.ConvexPolyhedron(verts, faces);
             return shape;
             return shape;
         };
         };
-        CannonJSPlugin.prototype._createHeightmap = function (mesh) {
+        CannonJSPlugin.prototype._createHeightmap = function (mesh, pointDepth) {
             var pos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             var pos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            if (pos[0] !== pos[pos.length - 1]) {
-                console.log("ERROR");
-                return;
-            }
             var matrix = [];
             var matrix = [];
-            //dimension
-            var dim = -pos[0];
-            //array size
-            var arraySize = -1;
-            for (var i = 0; i < pos.length; i = i + 3) {
-                if (pos[i + 2] === pos[2]) {
-                    arraySize++;
-                }
-                else {
-                    break;
-                }
-            }
-            //calculate element size
+            //For now pointDepth will not be used and will be automatically calculated.
+            //Future reference - try and find the best place to add a reference to the pointDepth variable.
+            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
+            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
             var elementSize = dim * 2 / arraySize;
             var elementSize = dim * 2 / arraySize;
-            //calculate the matrix for cannon's heightfield
+            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
             for (var i = 0; i < pos.length; i = i + 3) {
             for (var i = 0; i < pos.length; i = i + 3) {
                 var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
                 var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
                 var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
                 var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
+                var y = pos[i + 1] + minY;
                 if (!matrix[x]) {
                 if (!matrix[x]) {
                     matrix[x] = [];
                     matrix[x] = [];
                 }
                 }
-                matrix[x][z] = pos[i + 1];
+                if (!matrix[x][z]) {
+                    matrix[x][z] = y;
+                }
+                matrix[x][z] = Math.max(y, matrix[x][z]);
+            }
+            for (var x = 0; x <= arraySize; ++x) {
+                if (!matrix[x]) {
+                    var loc = 1;
+                    while (!matrix[(x + loc) % arraySize]) {
+                        loc++;
+                    }
+                    matrix[x] = matrix[(x + loc) % arraySize].slice();
+                }
+                for (var z = 0; z <= arraySize; ++z) {
+                    if (!matrix[x][z]) {
+                        var loc = 1;
+                        var newValue;
+                        while (newValue === undefined) {
+                            newValue = matrix[x][(z + loc++) % arraySize];
+                        }
+                        matrix[x][z] = newValue;
+                    }
+                }
             }
             }
             var shape = new CANNON.Heightfield(matrix, {
             var shape = new CANNON.Heightfield(matrix, {
                 elementSize: elementSize
                 elementSize: elementSize
             });
             });
             //For future reference, needed for body transformation
             //For future reference, needed for body transformation
-            shape.dim = dim;
+            shape.minY = minY;
             return shape;
             return shape;
         };
         };
         CannonJSPlugin.prototype._addMaterial = function (friction, restitution) {
         CannonJSPlugin.prototype._addMaterial = function (friction, restitution) {
@@ -192,19 +225,37 @@ var BABYLON;
                 //-90 DEG in X, precalculated
                 //-90 DEG in X, precalculated
                 var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                 var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                 body.quaternion = body.quaternion.mult(tmpQ);
                 body.quaternion = body.quaternion.mult(tmpQ);
-                //Invert!
+                //Invert! (Precalculated, 90 deg in X)
                 deltaRotation = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
                 deltaRotation = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
             }
             }
             //If it is a heightfield, if should be centered.
             //If it is a heightfield, if should be centered.
             if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
             if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                body.position = new CANNON.Vec3(-shape.dim, 0, shape.dim).vadd(mesh.position);
+                //calculate the correct body position:
+                var rotationQuaternion = mesh.rotationQuaternion;
+                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.computeWorldMatrix(true);
+                //get original center with no rotation
+                var center = mesh.getBoundingInfo().boundingBox.center.clone();
+                var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
+                //rotation is back
+                mesh.rotationQuaternion = rotationQuaternion;
+                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                var p = BABYLON.Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                mesh.setPivotMatrix(p);
+                mesh.computeWorldMatrix(true);
+                //calculate the translation
+                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+                body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
                 //add it inverted to the delta 
                 //add it inverted to the delta 
-                deltaPosition = mesh.position.add(new BABYLON.Vector3(shape.dim, 0, -shape.dim));
+                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+                mesh.setPivotMatrix(oldPivot);
+                mesh.computeWorldMatrix(true);
             }
             }
             //add the shape
             //add the shape
             body.addShape(shape);
             body.addShape(shape);
             this._world.add(body);
             this._world.add(body);
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation });
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation, heightmap: shape.type === CANNON.Shape.types.HEIGHTFIELD });
             return body;
             return body;
         };
         };
         CannonJSPlugin.prototype.registerMeshesAsCompound = function (parts, options) {
         CannonJSPlugin.prototype.registerMeshesAsCompound = function (parts, options) {

+ 103 - 34
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -116,10 +116,10 @@
 
 
             mesh.computeWorldMatrix(true);
             mesh.computeWorldMatrix(true);
 
 
+            //reuse this variable
+            var transformed = Vector3.Zero();
             // Get vertices
             // Get vertices
             for (var i = 0; i < rawVerts.length; i += 3) {
             for (var i = 0; i < rawVerts.length; i += 3) {
-                var transformed = Vector3.Zero();
-
                 Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
                 Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
                 verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
                 verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
             }
             }
@@ -134,40 +134,54 @@
             return shape;
             return shape;
         }
         }
 
 
-        private _createHeightmap(mesh: AbstractMesh) {
-            var pos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-
-            if (pos[0] !== pos[pos.length - 1]) {
-                console.log("ERROR");
-                return;
-            }
-
+        private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
+            var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
             var matrix = [];
             var matrix = [];
-            
-            //dimension
-            var dim = -pos[0];
+    
+            //For now pointDepth will not be used and will be automatically calculated.
+            //Future reference - try and find the best place to add a reference to the pointDepth variable.
+            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
 
 
-            //array size
-            var arraySize = -1;
-            for (var i = 0; i < pos.length; i = i + 3) {
-                if (pos[i + 2] === pos[2]) {
-                    arraySize++;
-                } else {
-                    break;
-                }
-            }
+            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
 
 
-            //calculate element size
             var elementSize = dim * 2 / arraySize;
             var elementSize = dim * 2 / arraySize;
-            
-            //calculate the matrix for cannon's heightfield
+
+            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
+
             for (var i = 0; i < pos.length; i = i + 3) {
             for (var i = 0; i < pos.length; i = i + 3) {
                 var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
                 var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
                 var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
                 var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
+                var y = pos[i + 1] + minY;
                 if (!matrix[x]) {
                 if (!matrix[x]) {
                     matrix[x] = [];
                     matrix[x] = [];
                 }
                 }
-                matrix[x][z] = pos[i + 1];
+                if (!matrix[x][z]) {
+                    matrix[x][z] = y;
+                }
+                matrix[x][z] = Math.max(y, matrix[x][z]);
+            }
+
+
+            for (var x = 0; x <= arraySize; ++x) {
+                if (!matrix[x]) {
+                    var loc = 1;
+                    while (!matrix[(x + loc) % arraySize]) {
+                        loc++;
+                    }
+                    matrix[x] = matrix[(x + loc) % arraySize].slice();
+                    //console.log("missing x", x);
+                }
+                for (var z = 0; z <= arraySize; ++z) {
+                    if (!matrix[x][z]) {
+                        var loc = 1;
+                        var newValue;
+                        while (newValue === undefined) {
+                            newValue = matrix[x][(z + loc++) % arraySize];
+                        }
+                        matrix[x][z] = newValue;
+
+                    }
+                }
             }
             }
 
 
             var shape = new CANNON.Heightfield(matrix, {
             var shape = new CANNON.Heightfield(matrix, {
@@ -175,7 +189,7 @@
             });
             });
             
             
             //For future reference, needed for body transformation
             //For future reference, needed for body transformation
-            shape.dim = dim;
+            shape.minY = minY;
 
 
             return shape;
             return shape;
         }
         }
@@ -229,15 +243,41 @@
                 //-90 DEG in X, precalculated
                 //-90 DEG in X, precalculated
                 var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                 var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                 body.quaternion = body.quaternion.mult(tmpQ);
                 body.quaternion = body.quaternion.mult(tmpQ);
-                //Invert!
+                //Invert! (Precalculated, 90 deg in X)
                 deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
                 deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
             }
             }
             
             
             //If it is a heightfield, if should be centered.
             //If it is a heightfield, if should be centered.
             if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
             if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                body.position = new CANNON.Vec3(-shape.dim, 0, shape.dim).vadd(mesh.position);
+                
+                //calculate the correct body position:
+                var rotationQuaternion = mesh.rotationQuaternion;
+                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.computeWorldMatrix(true);
+                
+                //get original center with no rotation
+                var center = mesh.getBoundingInfo().boundingBox.center.clone();
+
+                var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
+                
+                //rotation is back
+                mesh.rotationQuaternion = rotationQuaternion;
+        
+                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                mesh.setPivotMatrix(p);
+                mesh.computeWorldMatrix(true);
+        
+                //calculate the translation
+                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+
+                body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
                 //add it inverted to the delta 
                 //add it inverted to the delta 
-                deltaPosition = mesh.position.add(new BABYLON.Vector3(shape.dim, 0, -shape.dim));
+                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+                mesh.setPivotMatrix(oldPivot);
+                mesh.computeWorldMatrix(true);
             }
             }
             
             
             //add the shape
             //add the shape
@@ -245,7 +285,7 @@
 
 
             this._world.add(body);
             this._world.add(body);
 
 
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation });
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation, heightmap: shape.type === CANNON.Shape.types.HEIGHTFIELD });
 
 
             return body;
             return body;
         }
         }
@@ -331,9 +371,37 @@
                         var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                         var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
                         body.quaternion = body.quaternion.mult(tmpQ);
                         body.quaternion = body.quaternion.mult(tmpQ);
                     }
                     }
-                    
-                    //TODO - If the body is heightmap-based, this won't work correctly. find a good fix.
-                    
+
+                    if (registeredMesh.heightmap) {
+                        //calculate the correct body position:
+                        var rotationQuaternion = mesh.rotationQuaternion;
+                        mesh.rotationQuaternion = new BABYLON.Quaternion();
+                        mesh.computeWorldMatrix(true);
+                        
+                        //get original center with no rotation
+                        var center = mesh.getBoundingInfo().boundingBox.center.clone();
+
+                        var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
+                        
+                        //rotation is back
+                        mesh.rotationQuaternion = rotationQuaternion;
+                
+                        //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                        var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                        mesh.setPivotMatrix(p);
+                        mesh.computeWorldMatrix(true);
+                
+                        //calculate the translation
+                        var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+
+                        body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                        //add it inverted to the delta 
+                        registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                        registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+                        mesh.setPivotMatrix(oldPivot);
+                        mesh.computeWorldMatrix(true);
+                    }
                     return;
                     return;
                 }
                 }
             }
             }
@@ -390,3 +458,4 @@
 
 
 
 
 
 
+

+ 9 - 5
src/Shaders/default.fragment.fx

@@ -706,12 +706,12 @@ void main(void) {
 #endif
 #endif
 #ifdef SHADOW3
 #ifdef SHADOW3
 #ifdef SHADOWVSM3
 #ifdef SHADOWVSM3
-	shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
+		shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
 #else
 #else
 #ifdef SHADOWPCF3
 #ifdef SHADOWPCF3
-	shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
+		shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
 #else
 #else
-	shadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
+		shadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
 #endif	
 #endif	
 #endif	
 #endif	
 #else
 #else
@@ -745,7 +745,7 @@ void main(void) {
 #endif
 #endif
 #endif
 #endif
 
 
-	reflectionColor = textureCube(reflectionCubeSampler, vReflectionUVW, bias).rgb * vReflectionInfos.x * shadow;
+	reflectionColor = textureCube(reflectionCubeSampler, vReflectionUVW, bias).rgb * vReflectionInfos.x ;
 #else
 #else
 	vec2 coords = vReflectionUVW.xy;
 	vec2 coords = vReflectionUVW.xy;
 
 
@@ -755,7 +755,7 @@ void main(void) {
 
 
 	coords.y = 1.0 - coords.y;
 	coords.y = 1.0 - coords.y;
 
 
-	reflectionColor = texture2D(reflection2DSampler, coords).rgb * vReflectionInfos.x * shadow;
+	reflectionColor = texture2D(reflection2DSampler, coords).rgb * vReflectionInfos.x;
 #endif
 #endif
 
 
 #ifdef REFLECTIONFRESNEL
 #ifdef REFLECTIONFRESNEL
@@ -819,8 +819,12 @@ void main(void) {
 #ifdef EMISSIVEASILLUMINATION
 #ifdef EMISSIVEASILLUMINATION
 	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor + vAmbientColor, 0.0, 1.0) * baseColor.rgb;
 	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor + vAmbientColor, 0.0, 1.0) * baseColor.rgb;
 #else
 #else
+	#ifdef LINKEMISSIVEWITHDIFFUSE
+	vec3 finalDiffuse = clamp((diffuseBase + emissiveColor) * diffuseColor + vAmbientColor, 0.0, 1.0) * baseColor.rgb;
+	#else
 	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor + emissiveColor + vAmbientColor, 0.0, 1.0) * baseColor.rgb;
 	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor + emissiveColor + vAmbientColor, 0.0, 1.0) * baseColor.rgb;
 #endif
 #endif
+#endif
 
 
 #ifdef SPECULARTERM
 #ifdef SPECULARTERM
 	vec3 finalSpecular = specularBase * specularColor;
 	vec3 finalSpecular = specularBase * specularColor;

+ 3 - 0
src/Tools/babylon.tags.js

@@ -44,6 +44,9 @@ var BABYLON;
             if (!tagsString) {
             if (!tagsString) {
                 return;
                 return;
             }
             }
+            if (typeof tagsString !== "string") {
+                return;
+            }
             var tags = tagsString.split(" ");
             var tags = tagsString.split(" ");
             for (var t in tags) {
             for (var t in tags) {
                 Tags._AddTagTo(obj, tags[t]);
                 Tags._AddTagTo(obj, tags[t]);

+ 4 - 0
src/Tools/babylon.tags.ts

@@ -50,6 +50,10 @@
                 return;
                 return;
             }
             }
 
 
+            if (typeof tagsString !== "string") {
+                return;
+            }
+
             var tags = tagsString.split(" ");
             var tags = tagsString.split(" ");
             for (var t in tags) {
             for (var t in tags) {
                 Tags._AddTagTo(obj, tags[t]);
                 Tags._AddTagTo(obj, tags[t]);

+ 8 - 0
src/babylon.scene.js

@@ -657,6 +657,14 @@ var BABYLON;
             }
             }
             return index;
             return index;
         };
         };
+        Scene.prototype.removeSkeleton = function (toRemove) {
+            var index = this.skeletons.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.skeletons.splice(index, 1);
+            }
+            return index;
+        };
         Scene.prototype.removeLight = function (toRemove) {
         Scene.prototype.removeLight = function (toRemove) {
             var index = this.lights.indexOf(toRemove);
             var index = this.lights.indexOf(toRemove);
             if (index !== -1) {
             if (index !== -1) {

+ 10 - 0
src/babylon.scene.ts

@@ -877,6 +877,16 @@
             return index;
             return index;
         }
         }
 
 
+        public removeSkeleton(toRemove: Skeleton): number {
+            var index = this.skeletons.indexOf(toRemove);
+            if (index !== -1) {
+                // Remove from the scene if mesh found 
+                this.skeletons.splice(index, 1);
+            }
+
+            return index;
+        }
+
         public removeLight(toRemove: Light): number {
         public removeLight(toRemove: Light): number {
             var index = this.lights.indexOf(toRemove);
             var index = this.lights.indexOf(toRemove);
             if (index !== -1) {
             if (index !== -1) {