Ver código fonte

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

David Catuhe 7 anos atrás
pai
commit
383e7532e5
44 arquivos alterados com 13889 adições e 12782 exclusões
  1. 4602 4371
      Playground/babylon.d.txt
  2. 15 1
      Viewer/assets/templates/default/error.html
  3. 7623 7392
      dist/preview release/babylon.d.ts
  4. 1 1
      dist/preview release/babylon.js
  5. 282 80
      dist/preview release/babylon.max.js
  6. 282 80
      dist/preview release/babylon.no-module.max.js
  7. 1 1
      dist/preview release/babylon.worker.js
  8. 282 80
      dist/preview release/es6.js
  9. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  10. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  11. 2 566
      dist/preview release/typedocValidationBaseline.json
  12. 19 5
      dist/preview release/viewer/babylon.viewer.d.ts
  13. 2 2
      dist/preview release/viewer/babylon.viewer.js
  14. 4 4
      dist/preview release/viewer/babylon.viewer.max.js
  15. 22 5
      dist/preview release/viewer/babylon.viewer.module.d.ts
  16. 1 1
      dist/preview release/what's new.md
  17. 45 64
      src/Audio/babylon.audioEngine.ts
  18. 135 17
      src/Audio/babylon.sound.ts
  19. 76 11
      src/Audio/babylon.soundtrack.ts
  20. 3 4
      src/Behaviors/Cameras/babylon.framingBehavior.ts
  21. 3 0
      src/Behaviors/Mesh/babylon.multiPointerScaleBehavior.ts
  22. 24 5
      src/Behaviors/Mesh/babylon.pointerDragBehavior.ts
  23. 3 0
      src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts
  24. 1 1
      src/Cameras/Inputs/babylon.arcRotateCameraPointersInput.ts
  25. 8 2
      src/Collisions/babylon.pickingInfo.ts
  26. 32 4
      src/Debug/babylon.debugLayer.ts
  27. 43 4
      src/Debug/babylon.rayHelper.ts
  28. 1 1
      src/Engine/babylon.engine.ts
  29. 50 16
      src/Events/babylon.keyboardEvents.ts
  30. 78 40
      src/Events/babylon.pointerEvents.ts
  31. 16 2
      src/Instrumentation/babylon.engineInstrumentation.ts
  32. 15 1
      src/Instrumentation/babylon.sceneInstrumentation.ts
  33. 1 1
      src/Instrumentation/babylon.timeToken.ts
  34. 66 5
      src/Layer/babylon.layer.ts
  35. 2 0
      src/Materials/Textures/babylon.baseTexture.ts
  36. 6 2
      src/Materials/babylon.material.ts
  37. 3 1
      src/PostProcess/RenderPipeline/Pipelines/babylon.standardRenderingPipeline.ts
  38. 31 1
      src/Rendering/babylon.boundingBoxRenderer.ts
  39. 9 0
      src/Rendering/babylon.edgesRenderer.ts
  40. 6 0
      src/Rendering/babylon.renderingGroup.ts
  41. 32 2
      src/Rendering/babylon.renderingManager.ts
  42. 9 4
      src/Tools/babylon.tools.ts
  43. 3 2
      src/babylon.node.ts
  44. 48 1
      src/babylon.scene.ts

Diferenças do arquivo suprimidas por serem muito extensas
+ 4602 - 4371
Playground/babylon.d.txt


+ 15 - 1
Viewer/assets/templates/default/error.html

@@ -1 +1,15 @@
-Error loading the model
+<style>
+    .narrator-readable-text {
+        border: none;
+        background: none;
+        color: inherit;
+        border: none;
+        padding: 0;
+        font: inherit;
+        cursor: pointer;
+        outline: inherit;
+    }
+</style>
+
+<!-- Accessibility button that a screen narrator will read -->
+<button class="narrator-readable-text">Error loading the model</button>

Diferenças do arquivo suprimidas por serem muito extensas
+ 7623 - 7392
dist/preview release/babylon.d.ts


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/babylon.js


+ 282 - 80
dist/preview release/babylon.max.js

@@ -9208,6 +9208,11 @@ var BABYLON;
                 document.msCancelFullScreen();
             }
         };
+        /**
+         * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
+         * @param url define the url we are trying
+         * @param element define the dom element where to configure the cors policy
+         */
         Tools.SetCorsBehavior = function (url, element) {
             if (url && url.indexOf("data:") === 0) {
                 return;
@@ -10535,14 +10540,14 @@ var BABYLON;
         /**
          * Create and run an async loop.
          * @param iterations the number of iterations.
-         * @param _fn the function to run each iteration
-         * @param _successCallback the callback that will be called upon succesful execution
+         * @param fn the function to run each iteration
+         * @param successCallback the callback that will be called upon succesful execution
          * @param offset starting offset.
          * @returns the created async loop object
          */
-        AsyncLoop.Run = function (iterations, _fn, _successCallback, offset) {
+        AsyncLoop.Run = function (iterations, fn, successCallback, offset) {
             if (offset === void 0) { offset = 0; }
-            var loop = new AsyncLoop(iterations, _fn, _successCallback, offset);
+            var loop = new AsyncLoop(iterations, fn, successCallback, offset);
             loop.executeNext();
             return loop;
         };
@@ -14677,7 +14682,7 @@ var BABYLON;
             var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
             var fromData = url.substr(0, 5) === "data:";
             var fromBlob = url.substr(0, 5) === "blob:";
-            var isBase64 = fromData && url.indexOf("base64") !== -1;
+            var isBase64 = fromData && url.indexOf(";base64,") !== -1;
             var texture = fallback ? fallback : new BABYLON.InternalTexture(this, BABYLON.InternalTexture.DATASOURCE_URL);
             // establish the file extension, if possible
             var lastDot = url.lastIndexOf('.');
@@ -17901,16 +17906,18 @@ var BABYLON;
          * Attach a behavior to the node
          * @see http://doc.babylonjs.com/features/behaviour
          * @param behavior defines the behavior to attach
+         * @param attachImmediately defines that the behavior must be attached even if the scene is still loading
          * @returns the current Node
          */
-        Node.prototype.addBehavior = function (behavior) {
+        Node.prototype.addBehavior = function (behavior, attachImmediately) {
             var _this = this;
+            if (attachImmediately === void 0) { attachImmediately = false; }
             var index = this._behaviors.indexOf(behavior);
             if (index !== -1) {
                 return this;
             }
             behavior.init();
-            if (this._scene.isLoading) {
+            if (this._scene.isLoading && !attachImmediately) {
                 // We defer the attach when the scene will be loaded
                 this._scene.onDataLoadedObservable.addOnce(function () {
                     behavior.attach(_this);
@@ -55581,6 +55588,9 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * @hidden
+     */
     var IntersectionInfo = /** @class */ (function () {
         function IntersectionInfo(bu, bv, distance) {
             this.bu = bu;
@@ -55594,7 +55604,7 @@ var BABYLON;
     BABYLON.IntersectionInfo = IntersectionInfo;
     /**
      * Information about the result of picking within a scene
-     * See https://doc.babylonjs.com/babylon101/picking_collisions
+     * @see https://doc.babylonjs.com/babylon101/picking_collisions
      */
     var PickingInfo = /** @class */ (function () {
         function PickingInfo() {
@@ -62979,15 +62989,36 @@ var BABYLON;
         enumerable: true,
         configurable: true
     });
+    /**
+     * Component responsible of rendering the bounding box of the meshes in a scene.
+     * This is usually used through the mesh.showBoundingBox or the scene.forceShowBoundingBoxes properties
+     *
+     */
     var BoundingBoxRenderer = /** @class */ (function () {
+        /**
+         * Instantiates a new bounding box renderer in a scene.
+         * @param scene the scene the  renderer renders in
+         */
         function BoundingBoxRenderer(scene) {
             /**
              * The component name helpfull to identify the component in the list of scene components.
              */
             this.name = BABYLON.SceneComponentConstants.NAME_BOUNDINGBOXRENDERER;
+            /**
+             * Color of the bounding box lines placed in front of an object
+             */
             this.frontColor = new BABYLON.Color3(1, 1, 1);
+            /**
+             * Color of the bounding box lines placed behind an object
+             */
             this.backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
+            /**
+             * Defines if the renderer should show the back lines or not
+             */
             this.showBackLines = true;
+            /**
+             * @hidden
+             */
             this.renderList = new BABYLON.SmartArray(32);
             this._vertexBuffers = {};
             this.scene = scene;
@@ -63046,6 +63077,9 @@ var BABYLON;
             }
             this._createIndexBuffer();
         };
+        /**
+         * @hidden
+         */
         BoundingBoxRenderer.prototype.reset = function () {
             this.renderList.reset();
         };
@@ -63099,6 +63133,10 @@ var BABYLON;
             engine.setDepthFunctionToLessOrEqual();
             engine.setDepthWrite(true);
         };
+        /**
+         * In case of occlusion queries, we can render the occlusion bounding box through this method
+         * @param mesh Define the mesh to render the occlusion bounding box for
+         */
         BoundingBoxRenderer.prototype.renderOcclusionBoundingBox = function (mesh) {
             this._prepareRessources();
             if (!this._colorShader.isReady() || !mesh._boundingInfo) {
@@ -63126,6 +63164,9 @@ var BABYLON;
             engine.setDepthWrite(true);
             engine.setColorWrite(true);
         };
+        /**
+         * Dispose and release the resources attached to this renderer.
+         */
         BoundingBoxRenderer.prototype.dispose = function () {
             if (!this._colorShader) {
                 return;
@@ -67334,7 +67375,6 @@ var BABYLON;
             var _this = this;
             this._audioContext = null;
             this._audioContextInitialized = false;
-            this._muteButtonDisplayed = false;
             this._muteButton = null;
             /**
              * Gets whether the current host supports Web Audio and thus could create AudioContexts.
@@ -67358,7 +67398,7 @@ var BABYLON;
              * Some Browsers have strong restrictions about Audio and won t autoplay unless
              * a user interaction has happened.
              */
-            this.unlocked = false;
+            this.unlocked = true;
             /**
              * Defines if the audio engine relies on a custom unlocked button.
              * In this case, the embedded button will not be displayed.
@@ -67397,9 +67437,6 @@ var BABYLON;
             catch (e) {
                 // protect error during capability check.
             }
-            if (/iPad|iPhone|iPod/.test(navigator.platform)) {
-                this._unlockiOSaudio();
-            }
         }
         Object.defineProperty(AudioEngine.prototype, "audioContext", {
             /**
@@ -67410,7 +67447,7 @@ var BABYLON;
                     this._initializeAudioContext();
                 }
                 else {
-                    if (!this.unlocked && !this._muteButtonDisplayed) {
+                    if (!this.unlocked && !this._muteButton) {
                         this._displayMuteButton();
                     }
                 }
@@ -67433,35 +67470,12 @@ var BABYLON;
         AudioEngine.prototype.unlock = function () {
             this._triggerRunningState();
         };
-        AudioEngine.prototype._unlockiOSaudio = function () {
-            var _this = this;
-            this._displayMuteButton(true);
-            var unlockaudio = function () {
-                if (!_this.audioContext) {
-                    return;
-                }
-                var buffer = _this.audioContext.createBuffer(1, 1, 22050);
-                var source = _this.audioContext.createBufferSource();
-                source.buffer = buffer;
-                source.connect(_this.audioContext.destination);
-                source.start(0);
-                setTimeout(function () {
-                    if ((source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE)) {
-                        _this._triggerRunningState();
-                        if (_this._muteButton) {
-                            _this._muteButton.removeEventListener('touchend', unlockaudio, false);
-                        }
-                    }
-                }, 0);
-            };
-            if (this._muteButton) {
-                this._muteButton.addEventListener('touchend', unlockaudio, false);
-            }
-        };
         AudioEngine.prototype._resumeAudioContext = function () {
+            var result;
             if (this._audioContext.resume) {
-                this._audioContext.resume();
+                result = this._audioContext.resume();
             }
+            return result || Promise.resolve();
         };
         AudioEngine.prototype._initializeAudioContext = function () {
             var _this = this;
@@ -67474,21 +67488,19 @@ var BABYLON;
                     this.masterGain.connect(this._audioContext.destination);
                     this._audioContextInitialized = true;
                     if (this._audioContext.state === "running") {
+                        // Do not wait for the promise to unlock.
                         this._triggerRunningState();
                     }
                     else {
-                        if (!this._muteButtonDisplayed) {
-                            this._displayMuteButton();
-                        }
-                        // 3 possible states: https://webaudio.github.io/web-audio-api/#BaseAudioContext
-                        this._audioContext.addEventListener("statechange", function () {
-                            if (_this._audioContext.state === "running") {
+                        if (this._audioContext && this._audioContext.resume) {
+                            this._resumeAudioContext().then(function () {
                                 _this._triggerRunningState();
-                            }
-                            else {
-                                _this._triggerSuspendedState();
-                            }
-                        });
+                            }).catch(function () {
+                                // Can not resume automatically
+                                // Needs user action
+                                _this.lock();
+                            });
+                        }
                     }
                 }
             }
@@ -67498,22 +67510,26 @@ var BABYLON;
             }
         };
         AudioEngine.prototype._triggerRunningState = function () {
-            this._resumeAudioContext();
-            this.unlocked = true;
-            if (this._muteButtonDisplayed) {
-                this._hideMuteButton();
-            }
-            // Notify users that the audio stack is unlocked/unmuted
-            this.onAudioUnlockedObservable.notifyObservers(this);
+            var _this = this;
+            this._resumeAudioContext()
+                .then(function () {
+                _this.unlocked = true;
+                if (_this._muteButton) {
+                    _this._hideMuteButton();
+                }
+                // Notify users that the audio stack is unlocked/unmuted
+                _this.onAudioUnlockedObservable.notifyObservers(_this);
+            }).catch(function () {
+                _this.unlocked = false;
+            });
         };
         AudioEngine.prototype._triggerSuspendedState = function () {
             this.unlocked = false;
             this.onAudioLockedObservable.notifyObservers(this);
             this._displayMuteButton();
         };
-        AudioEngine.prototype._displayMuteButton = function (iOS) {
+        AudioEngine.prototype._displayMuteButton = function () {
             var _this = this;
-            if (iOS === void 0) { iOS = false; }
             if (this.useCustomUnlockedButton) {
                 return;
             }
@@ -67528,12 +67544,12 @@ var BABYLON;
             document.getElementsByTagName('head')[0].appendChild(style);
             document.body.appendChild(this._muteButton);
             this._moveButtonToTopLeft();
-            if (!iOS) {
-                this._muteButton.addEventListener('mousedown', function () {
-                    _this._triggerRunningState();
-                }, false);
-            }
-            this._muteButtonDisplayed = true;
+            this._muteButton.addEventListener('mousedown', function () {
+                _this._triggerRunningState();
+            }, false);
+            this._muteButton.addEventListener('touchend', function () {
+                _this._triggerRunningState();
+            }, false);
             window.addEventListener("resize", this._onResize);
         };
         AudioEngine.prototype._moveButtonToTopLeft = function () {
@@ -67543,9 +67559,9 @@ var BABYLON;
             }
         };
         AudioEngine.prototype._hideMuteButton = function () {
-            if (this._muteButtonDisplayed && this._muteButton) {
+            if (this._muteButton) {
                 document.body.removeChild(this._muteButton);
-                this._muteButtonDisplayed = false;
+                this._muteButton = null;
             }
         };
         /**
@@ -67645,18 +67661,43 @@ var BABYLON;
              */
             this.useCustomAttenuation = false;
             /**
+             * Is this sound currently played.
+             */
+            this.isPlaying = false;
+            /**
+             * Is this sound currently paused.
+             */
+            this.isPaused = false;
+            /**
              * Does this sound enables spatial sound.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
              */
             this.spatialSound = false;
+            /**
+             * Define the reference distance the sound should be heard perfectly.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.refDistance = 1;
+            /**
+             * Define the roll off factor of spatial sounds.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.rolloffFactor = 1;
+            /**
+             * Define the max distance the sound should be heard (intensity just became 0 at this point).
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.maxDistance = 100;
+            /**
+             * Define the distance attenuation model the sound will follow.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.distanceModel = "linear";
-            this._panningModel = "equalpower";
             /**
              * Observable event when the current playing sound finishes.
              */
             this.onEndedObservable = new BABYLON.Observable();
+            this._panningModel = "equalpower";
             this._playbackRate = 1;
             this._streaming = false;
             this._startTime = 0;
@@ -67667,8 +67708,6 @@ var BABYLON;
             this._localDirection = new BABYLON.Vector3(1, 0, 0);
             this._volume = 1;
             this._isReadyToPlay = false;
-            this.isPlaying = false;
-            this.isPaused = false;
             this._isDirectional = false;
             // Used if you'd like to create a directional sound.
             // If not set, the sound will be omnidirectional
@@ -67805,6 +67844,7 @@ var BABYLON;
                                                 }
                                             });
                                             document.body.appendChild(this._htmlAudioElement);
+                                            this._htmlAudioElement.load();
                                         }
                                         break;
                                     }
@@ -67854,6 +67894,9 @@ var BABYLON;
                 }
             }
         }
+        /**
+         * Release the sound and its associated resources
+         */
         Sound.prototype.dispose = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this.isPlaying) {
@@ -67893,6 +67936,10 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Gets if the sounds is ready to be played or not.
+         * @returns true if ready, otherwise false
+         */
         Sound.prototype.isReady = function () {
             return this._isReadyToPlay;
         };
@@ -67912,12 +67959,20 @@ var BABYLON;
                 }
             }, function (err) { BABYLON.Tools.Error("Error while decoding audio data for: " + _this.name + " / Error: " + err); });
         };
+        /**
+         * Sets the data of the sound from an audiobuffer
+         * @param audioBuffer The audioBuffer containing the data
+         */
         Sound.prototype.setAudioBuffer = function (audioBuffer) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 this._audioBuffer = audioBuffer;
                 this._isReadyToPlay = true;
             }
         };
+        /**
+         * Updates the current sounds options such as maxdistance, loop...
+         * @param options A JSON object containing values named as the object properties
+         */
         Sound.prototype.updateOptions = function (options) {
             if (options) {
                 this.loop = options.loop || this.loop;
@@ -67970,10 +68025,20 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         Sound.prototype.switchPanningModelToHRTF = function () {
             this._panningModel = "HRTF";
             this._switchPanningModel();
         };
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         Sound.prototype.switchPanningModelToEqualPower = function () {
             this._panningModel = "equalpower";
             this._switchPanningModel();
@@ -67983,6 +68048,10 @@ var BABYLON;
                 this._soundPanner.panningModel = this._panningModel;
             }
         };
+        /**
+         * Connect this sound to a sound track audio node like gain...
+         * @param soundTrackAudioNode the sound track audio node to connect to
+         */
         Sound.prototype.connectToSoundTrackAudioNode = function (soundTrackAudioNode) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this._isOutputConnected) {
@@ -68062,12 +68131,20 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /**
+         * Sets the position of the emitter if spatial sound is enabled
+         * @param newPosition Defines the new posisiton
+         */
         Sound.prototype.setPosition = function (newPosition) {
             this._position = newPosition;
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this.spatialSound && this._soundPanner && !isNaN(this._position.x) && !isNaN(this._position.y) && !isNaN(this._position.z)) {
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         };
+        /**
+         * Sets the local direction of the emitter if spatial sound is enabled
+         * @param newLocalDirection Defines the new local direction
+         */
         Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
             this._localDirection = newLocalDirection;
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
@@ -68083,12 +68160,18 @@ var BABYLON;
             direction.normalize();
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         };
+        /** @hidden */
         Sound.prototype.updateDistanceFromListener = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
                 var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
         };
+        /**
+         * Sets a new custom attenuation function for the sound.
+         * @param callback Defines the function used for the attenuation
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-your-own-custom-attenuation-function
+         */
         Sound.prototype.setAttenuationFunction = function (callback) {
             this._customAttenuationFunction = callback;
         };
@@ -68214,6 +68297,9 @@ var BABYLON;
                 this.isPlaying = false;
             }
         };
+        /**
+         * Put the sound in pause
+         */
         Sound.prototype.pause = function () {
             if (this.isPlaying) {
                 this.isPaused = true;
@@ -68231,6 +68317,11 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Sets a dedicated volume for this sounds
+         * @param newVolume Define the new volume of the sound
+         * @param time Define in how long the sound should be at this value
+         */
         Sound.prototype.setVolume = function (newVolume, time) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._soundGain) {
                 if (time && BABYLON.Engine.audioEngine.audioContext) {
@@ -68244,6 +68335,10 @@ var BABYLON;
             }
             this._volume = newVolume;
         };
+        /**
+         * Set the sound play back rate
+         * @param newPlaybackRate Define the playback rate the sound should be played at
+         */
         Sound.prototype.setPlaybackRate = function (newPlaybackRate) {
             this._playbackRate = newPlaybackRate;
             if (this.isPlaying) {
@@ -68255,9 +68350,18 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Gets the volume of the sound.
+         * @returns the volume of the sound
+         */
         Sound.prototype.getVolume = function () {
             return this._volume;
         };
+        /**
+         * Attach the sound to a dedicated mesh
+         * @param meshToConnectTo The mesh to connect the sound with
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
         Sound.prototype.attachToMesh = function (meshToConnectTo) {
             var _this = this;
             if (this._connectedMesh && this._registerFunc) {
@@ -68277,6 +68381,10 @@ var BABYLON;
             this._registerFunc = function (connectedMesh) { return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh); };
             meshToConnectTo.registerAfterWorldMatrixUpdate(this._registerFunc);
         };
+        /**
+         * Detach the sound from the previously attached mesh
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
         Sound.prototype.detachFromMesh = function () {
             if (this._connectedMesh && this._registerFunc) {
                 this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
@@ -68301,6 +68409,10 @@ var BABYLON;
                 this._updateDirection();
             }
         };
+        /**
+         * Clone the current sound in the scene.
+         * @returns the new sound clone
+         */
         Sound.prototype.clone = function () {
             var _this = this;
             if (!this._streaming) {
@@ -68336,9 +68448,17 @@ var BABYLON;
                 return null;
             }
         };
+        /**
+         * Gets the current underlying audio buffer containing the data
+         * @returns the audio buffer
+         */
         Sound.prototype.getAudioBuffer = function () {
             return this._audioBuffer;
         };
+        /**
+         * Serializes the Sound in a JSON representation
+         * @returns the JSON representation of the sound
+         */
         Sound.prototype.serialize = function () {
             var serializationObject = {
                 name: this.name,
@@ -68369,6 +68489,14 @@ var BABYLON;
             }
             return serializationObject;
         };
+        /**
+         * Parse a JSON representation of a sound to innstantiate in a given scene
+         * @param parsedSound Define the JSON representation of the sound (usually coming from the serialize method)
+         * @param scene Define the scene the new parsed sound should be created in
+         * @param rootUrl Define the rooturl of the load in case we need to fetch relative dependencies
+         * @param sourceSound Define a cound place holder if do not need to instantiate a new one
+         * @returns the newly parsed sound
+         */
         Sound.Parse = function (parsedSound, scene, rootUrl, sourceSound) {
             var soundName = parsedSound.name;
             var soundUrl;
@@ -68435,8 +68563,23 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * It could be useful to isolate your music & sounds on several tracks to better manage volume on a grouped instance of sounds.
+     * It will be also used in a future release to apply effects on a specific track.
+     * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+     */
     var SoundTrack = /** @class */ (function () {
+        /**
+         * Creates a new sound track.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+         * @param scene Define the scene the sound track belongs to
+         * @param options
+         */
         function SoundTrack(scene, options) {
+            if (options === void 0) { options = {}; }
+            /**
+             * The unique identifier of the sound track in the scene.
+             */
             this.id = -1;
             this._isMainTrack = false;
             this._isInitialized = false;
@@ -68463,6 +68606,9 @@ var BABYLON;
                 this._isInitialized = true;
             }
         };
+        /**
+         * Release the sound track and its associated resources
+         */
         SoundTrack.prototype.dispose = function () {
             if (BABYLON.Engine.audioEngine && BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this._connectedAnalyser) {
@@ -68477,6 +68623,11 @@ var BABYLON;
                 this._outputAudioNode = null;
             }
         };
+        /**
+         * Adds a sound to this sound track
+         * @param sound define the cound to add
+         * @ignoreNaming
+         */
         SoundTrack.prototype.AddSound = function (sound) {
             if (!this._isInitialized) {
                 this._initializeSoundTrackAudioGraph();
@@ -68495,17 +68646,31 @@ var BABYLON;
             this.soundCollection.push(sound);
             sound.soundTrackId = this.id;
         };
+        /**
+         * Removes a sound to this sound track
+         * @param sound define the cound to remove
+         * @ignoreNaming
+         */
         SoundTrack.prototype.RemoveSound = function (sound) {
             var index = this.soundCollection.indexOf(sound);
             if (index !== -1) {
                 this.soundCollection.splice(index, 1);
             }
         };
+        /**
+         * Set a global volume for the full sound track.
+         * @param newVolume Define the new volume of the sound track
+         */
         SoundTrack.prototype.setVolume = function (newVolume) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._outputAudioNode) {
                 this._outputAudioNode.gain.value = newVolume;
             }
         };
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         SoundTrack.prototype.switchPanningModelToHRTF = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
@@ -68513,6 +68678,11 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         SoundTrack.prototype.switchPanningModelToEqualPower = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
@@ -68520,6 +68690,12 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Connect the sound track to an audio analyser allowing some amazing
+         * synchornization between the sounds/music and your visualization (VuMeter for instance).
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-the-analyser
+         * @param analyser The analyser to connect to the engine
+         */
         SoundTrack.prototype.connectToAnalyser = function (analyser) {
             if (this._connectedAnalyser) {
                 this._connectedAnalyser.stopDebugCanvas();
@@ -95739,6 +95915,14 @@ var BABYLON;
                 }
                 else if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE) {
                     var pointerId = pointerInfo.event.pointerId;
+                    // If drag was started with anyMouseID specified, set pointerID to the next mouse that moved
+                    if (_this.currentDraggingPointerID === PointerDragBehavior._AnyMouseID && pointerId !== PointerDragBehavior._AnyMouseID && pointerInfo.event.pointerType == "mouse") {
+                        if (_this._lastPointerRay[_this.currentDraggingPointerID]) {
+                            _this._lastPointerRay[pointerId] = _this._lastPointerRay[_this.currentDraggingPointerID];
+                            delete _this._lastPointerRay[_this.currentDraggingPointerID];
+                        }
+                        _this.currentDraggingPointerID = pointerId;
+                    }
                     // Keep track of last pointer ray, this is used simulating the start of a drag in startDrag()
                     if (!_this._lastPointerRay[pointerId]) {
                         _this._lastPointerRay[pointerId] = new BABYLON.Ray(new BABYLON.Vector3(), new BABYLON.Vector3());
@@ -95764,6 +95948,9 @@ var BABYLON;
                 }
             });
         };
+        /**
+         * Force relase the drag action by code.
+         */
         PointerDragBehavior.prototype.releaseDrag = function () {
             this.dragging = false;
             this.onDragEndObservable.notifyObservers({ dragPlanePoint: this.lastDragPosition, pointerId: this.currentDraggingPointerID });
@@ -95776,20 +95963,23 @@ var BABYLON;
         };
         /**
          * Simulates the start of a pointer drag event on the behavior
-         * @param pointerId pointerID of the pointer that should be simulated (Default: 1 for mouse pointer)
+         * @param pointerId pointerID of the pointer that should be simulated (Default: Any mouse pointer ID)
          * @param fromRay initial ray of the pointer to be simulated (Default: Ray from camera to attached mesh)
          * @param startPickedPoint picked point of the pointer to be simulated (Default: attached mesh position)
          */
         PointerDragBehavior.prototype.startDrag = function (pointerId, fromRay, startPickedPoint) {
-            if (pointerId === void 0) { pointerId = 1; }
+            if (pointerId === void 0) { pointerId = PointerDragBehavior._AnyMouseID; }
             this._startDrag(pointerId, fromRay, startPickedPoint);
-            if (this._lastPointerRay[pointerId]) {
+            var lastRay = this._lastPointerRay[pointerId];
+            if (pointerId === PointerDragBehavior._AnyMouseID) {
+                lastRay = this._lastPointerRay[Object.keys(this._lastPointerRay)[0]];
+            }
+            if (lastRay) {
                 // if there was a last pointer ray drag the object there
-                this._moveDrag(this._lastPointerRay[pointerId]);
+                this._moveDrag(lastRay);
             }
         };
         PointerDragBehavior.prototype._startDrag = function (pointerId, fromRay, startPickedPoint) {
-            if (pointerId === void 0) { pointerId = 1; }
             if (!this._scene.activeCamera || this.dragging || !this._attachedNode) {
                 return;
             }
@@ -95933,6 +96123,7 @@ var BABYLON;
                 this._scene.onBeforeRenderObservable.remove(this._beforeRenderObserver);
             }
         };
+        PointerDragBehavior._AnyMouseID = -2;
         return PointerDragBehavior;
     }());
     BABYLON.PointerDragBehavior = PointerDragBehavior;
@@ -95946,6 +96137,9 @@ var BABYLON;
      * A behavior that when attached to a mesh will allow the mesh to be scaled
      */
     var MultiPointerScaleBehavior = /** @class */ (function () {
+        /**
+         * Instantiate a new behavior that when attached to a mesh will allow the mesh to be scaled
+         */
         function MultiPointerScaleBehavior() {
             this._startDistance = 0;
             this._initialScale = new BABYLON.Vector3(0, 0, 0);
@@ -96049,6 +96243,9 @@ var BABYLON;
      * A behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
      */
     var SixDofDragBehavior = /** @class */ (function () {
+        /**
+         * Instantiates a behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
+         */
         function SixDofDragBehavior() {
             this._sceneRenderObserver = null;
             this._targetPosition = new BABYLON.Vector3(0, 0, 0);
@@ -104563,7 +104760,13 @@ var BABYLON;
             if (checkVerticesInsteadOfIndices === void 0) { checkVerticesInsteadOfIndices = false; }
             if (generateEdgesLines === void 0) { generateEdgesLines = true; }
             var _this = this;
+            /**
+             * Define the size of the edges with an orthographic camera
+             */
             this.edgesWidthScalerForOrthographic = 1000.0;
+            /**
+             * Define the size of the edges with a perspective camera
+             */
             this.edgesWidthScalerForPerspective = 50.0;
             this._linesPositions = new Array();
             this._linesNormals = new Array();
@@ -108556,10 +108759,9 @@ var BABYLON;
             this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd);
         };
         /**
-         * Targets the given mesh and updates zoom level accordingly.
-         * @param mesh  The mesh to target.
-         * @param radius Optional. If a cached radius position already exists, overrides default.
-         * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
+         * Targets the bounding box info defined by its extends and updates zoom level accordingly.
+         * @param minimumWorld Determines the smaller position of the bounding box extend
+         * @param maximumWorld Determines the bigger position of the bounding box extend
          * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
          * @param onAnimationEnd Callback triggered at the end of the framing animation
          */

+ 282 - 80
dist/preview release/babylon.no-module.max.js

@@ -9175,6 +9175,11 @@ var BABYLON;
                 document.msCancelFullScreen();
             }
         };
+        /**
+         * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
+         * @param url define the url we are trying
+         * @param element define the dom element where to configure the cors policy
+         */
         Tools.SetCorsBehavior = function (url, element) {
             if (url && url.indexOf("data:") === 0) {
                 return;
@@ -10502,14 +10507,14 @@ var BABYLON;
         /**
          * Create and run an async loop.
          * @param iterations the number of iterations.
-         * @param _fn the function to run each iteration
-         * @param _successCallback the callback that will be called upon succesful execution
+         * @param fn the function to run each iteration
+         * @param successCallback the callback that will be called upon succesful execution
          * @param offset starting offset.
          * @returns the created async loop object
          */
-        AsyncLoop.Run = function (iterations, _fn, _successCallback, offset) {
+        AsyncLoop.Run = function (iterations, fn, successCallback, offset) {
             if (offset === void 0) { offset = 0; }
-            var loop = new AsyncLoop(iterations, _fn, _successCallback, offset);
+            var loop = new AsyncLoop(iterations, fn, successCallback, offset);
             loop.executeNext();
             return loop;
         };
@@ -14644,7 +14649,7 @@ var BABYLON;
             var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
             var fromData = url.substr(0, 5) === "data:";
             var fromBlob = url.substr(0, 5) === "blob:";
-            var isBase64 = fromData && url.indexOf("base64") !== -1;
+            var isBase64 = fromData && url.indexOf(";base64,") !== -1;
             var texture = fallback ? fallback : new BABYLON.InternalTexture(this, BABYLON.InternalTexture.DATASOURCE_URL);
             // establish the file extension, if possible
             var lastDot = url.lastIndexOf('.');
@@ -17868,16 +17873,18 @@ var BABYLON;
          * Attach a behavior to the node
          * @see http://doc.babylonjs.com/features/behaviour
          * @param behavior defines the behavior to attach
+         * @param attachImmediately defines that the behavior must be attached even if the scene is still loading
          * @returns the current Node
          */
-        Node.prototype.addBehavior = function (behavior) {
+        Node.prototype.addBehavior = function (behavior, attachImmediately) {
             var _this = this;
+            if (attachImmediately === void 0) { attachImmediately = false; }
             var index = this._behaviors.indexOf(behavior);
             if (index !== -1) {
                 return this;
             }
             behavior.init();
-            if (this._scene.isLoading) {
+            if (this._scene.isLoading && !attachImmediately) {
                 // We defer the attach when the scene will be loaded
                 this._scene.onDataLoadedObservable.addOnce(function () {
                     behavior.attach(_this);
@@ -55548,6 +55555,9 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * @hidden
+     */
     var IntersectionInfo = /** @class */ (function () {
         function IntersectionInfo(bu, bv, distance) {
             this.bu = bu;
@@ -55561,7 +55571,7 @@ var BABYLON;
     BABYLON.IntersectionInfo = IntersectionInfo;
     /**
      * Information about the result of picking within a scene
-     * See https://doc.babylonjs.com/babylon101/picking_collisions
+     * @see https://doc.babylonjs.com/babylon101/picking_collisions
      */
     var PickingInfo = /** @class */ (function () {
         function PickingInfo() {
@@ -62946,15 +62956,36 @@ var BABYLON;
         enumerable: true,
         configurable: true
     });
+    /**
+     * Component responsible of rendering the bounding box of the meshes in a scene.
+     * This is usually used through the mesh.showBoundingBox or the scene.forceShowBoundingBoxes properties
+     *
+     */
     var BoundingBoxRenderer = /** @class */ (function () {
+        /**
+         * Instantiates a new bounding box renderer in a scene.
+         * @param scene the scene the  renderer renders in
+         */
         function BoundingBoxRenderer(scene) {
             /**
              * The component name helpfull to identify the component in the list of scene components.
              */
             this.name = BABYLON.SceneComponentConstants.NAME_BOUNDINGBOXRENDERER;
+            /**
+             * Color of the bounding box lines placed in front of an object
+             */
             this.frontColor = new BABYLON.Color3(1, 1, 1);
+            /**
+             * Color of the bounding box lines placed behind an object
+             */
             this.backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
+            /**
+             * Defines if the renderer should show the back lines or not
+             */
             this.showBackLines = true;
+            /**
+             * @hidden
+             */
             this.renderList = new BABYLON.SmartArray(32);
             this._vertexBuffers = {};
             this.scene = scene;
@@ -63013,6 +63044,9 @@ var BABYLON;
             }
             this._createIndexBuffer();
         };
+        /**
+         * @hidden
+         */
         BoundingBoxRenderer.prototype.reset = function () {
             this.renderList.reset();
         };
@@ -63066,6 +63100,10 @@ var BABYLON;
             engine.setDepthFunctionToLessOrEqual();
             engine.setDepthWrite(true);
         };
+        /**
+         * In case of occlusion queries, we can render the occlusion bounding box through this method
+         * @param mesh Define the mesh to render the occlusion bounding box for
+         */
         BoundingBoxRenderer.prototype.renderOcclusionBoundingBox = function (mesh) {
             this._prepareRessources();
             if (!this._colorShader.isReady() || !mesh._boundingInfo) {
@@ -63093,6 +63131,9 @@ var BABYLON;
             engine.setDepthWrite(true);
             engine.setColorWrite(true);
         };
+        /**
+         * Dispose and release the resources attached to this renderer.
+         */
         BoundingBoxRenderer.prototype.dispose = function () {
             if (!this._colorShader) {
                 return;
@@ -67301,7 +67342,6 @@ var BABYLON;
             var _this = this;
             this._audioContext = null;
             this._audioContextInitialized = false;
-            this._muteButtonDisplayed = false;
             this._muteButton = null;
             /**
              * Gets whether the current host supports Web Audio and thus could create AudioContexts.
@@ -67325,7 +67365,7 @@ var BABYLON;
              * Some Browsers have strong restrictions about Audio and won t autoplay unless
              * a user interaction has happened.
              */
-            this.unlocked = false;
+            this.unlocked = true;
             /**
              * Defines if the audio engine relies on a custom unlocked button.
              * In this case, the embedded button will not be displayed.
@@ -67364,9 +67404,6 @@ var BABYLON;
             catch (e) {
                 // protect error during capability check.
             }
-            if (/iPad|iPhone|iPod/.test(navigator.platform)) {
-                this._unlockiOSaudio();
-            }
         }
         Object.defineProperty(AudioEngine.prototype, "audioContext", {
             /**
@@ -67377,7 +67414,7 @@ var BABYLON;
                     this._initializeAudioContext();
                 }
                 else {
-                    if (!this.unlocked && !this._muteButtonDisplayed) {
+                    if (!this.unlocked && !this._muteButton) {
                         this._displayMuteButton();
                     }
                 }
@@ -67400,35 +67437,12 @@ var BABYLON;
         AudioEngine.prototype.unlock = function () {
             this._triggerRunningState();
         };
-        AudioEngine.prototype._unlockiOSaudio = function () {
-            var _this = this;
-            this._displayMuteButton(true);
-            var unlockaudio = function () {
-                if (!_this.audioContext) {
-                    return;
-                }
-                var buffer = _this.audioContext.createBuffer(1, 1, 22050);
-                var source = _this.audioContext.createBufferSource();
-                source.buffer = buffer;
-                source.connect(_this.audioContext.destination);
-                source.start(0);
-                setTimeout(function () {
-                    if ((source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE)) {
-                        _this._triggerRunningState();
-                        if (_this._muteButton) {
-                            _this._muteButton.removeEventListener('touchend', unlockaudio, false);
-                        }
-                    }
-                }, 0);
-            };
-            if (this._muteButton) {
-                this._muteButton.addEventListener('touchend', unlockaudio, false);
-            }
-        };
         AudioEngine.prototype._resumeAudioContext = function () {
+            var result;
             if (this._audioContext.resume) {
-                this._audioContext.resume();
+                result = this._audioContext.resume();
             }
+            return result || Promise.resolve();
         };
         AudioEngine.prototype._initializeAudioContext = function () {
             var _this = this;
@@ -67441,21 +67455,19 @@ var BABYLON;
                     this.masterGain.connect(this._audioContext.destination);
                     this._audioContextInitialized = true;
                     if (this._audioContext.state === "running") {
+                        // Do not wait for the promise to unlock.
                         this._triggerRunningState();
                     }
                     else {
-                        if (!this._muteButtonDisplayed) {
-                            this._displayMuteButton();
-                        }
-                        // 3 possible states: https://webaudio.github.io/web-audio-api/#BaseAudioContext
-                        this._audioContext.addEventListener("statechange", function () {
-                            if (_this._audioContext.state === "running") {
+                        if (this._audioContext && this._audioContext.resume) {
+                            this._resumeAudioContext().then(function () {
                                 _this._triggerRunningState();
-                            }
-                            else {
-                                _this._triggerSuspendedState();
-                            }
-                        });
+                            }).catch(function () {
+                                // Can not resume automatically
+                                // Needs user action
+                                _this.lock();
+                            });
+                        }
                     }
                 }
             }
@@ -67465,22 +67477,26 @@ var BABYLON;
             }
         };
         AudioEngine.prototype._triggerRunningState = function () {
-            this._resumeAudioContext();
-            this.unlocked = true;
-            if (this._muteButtonDisplayed) {
-                this._hideMuteButton();
-            }
-            // Notify users that the audio stack is unlocked/unmuted
-            this.onAudioUnlockedObservable.notifyObservers(this);
+            var _this = this;
+            this._resumeAudioContext()
+                .then(function () {
+                _this.unlocked = true;
+                if (_this._muteButton) {
+                    _this._hideMuteButton();
+                }
+                // Notify users that the audio stack is unlocked/unmuted
+                _this.onAudioUnlockedObservable.notifyObservers(_this);
+            }).catch(function () {
+                _this.unlocked = false;
+            });
         };
         AudioEngine.prototype._triggerSuspendedState = function () {
             this.unlocked = false;
             this.onAudioLockedObservable.notifyObservers(this);
             this._displayMuteButton();
         };
-        AudioEngine.prototype._displayMuteButton = function (iOS) {
+        AudioEngine.prototype._displayMuteButton = function () {
             var _this = this;
-            if (iOS === void 0) { iOS = false; }
             if (this.useCustomUnlockedButton) {
                 return;
             }
@@ -67495,12 +67511,12 @@ var BABYLON;
             document.getElementsByTagName('head')[0].appendChild(style);
             document.body.appendChild(this._muteButton);
             this._moveButtonToTopLeft();
-            if (!iOS) {
-                this._muteButton.addEventListener('mousedown', function () {
-                    _this._triggerRunningState();
-                }, false);
-            }
-            this._muteButtonDisplayed = true;
+            this._muteButton.addEventListener('mousedown', function () {
+                _this._triggerRunningState();
+            }, false);
+            this._muteButton.addEventListener('touchend', function () {
+                _this._triggerRunningState();
+            }, false);
             window.addEventListener("resize", this._onResize);
         };
         AudioEngine.prototype._moveButtonToTopLeft = function () {
@@ -67510,9 +67526,9 @@ var BABYLON;
             }
         };
         AudioEngine.prototype._hideMuteButton = function () {
-            if (this._muteButtonDisplayed && this._muteButton) {
+            if (this._muteButton) {
                 document.body.removeChild(this._muteButton);
-                this._muteButtonDisplayed = false;
+                this._muteButton = null;
             }
         };
         /**
@@ -67612,18 +67628,43 @@ var BABYLON;
              */
             this.useCustomAttenuation = false;
             /**
+             * Is this sound currently played.
+             */
+            this.isPlaying = false;
+            /**
+             * Is this sound currently paused.
+             */
+            this.isPaused = false;
+            /**
              * Does this sound enables spatial sound.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
              */
             this.spatialSound = false;
+            /**
+             * Define the reference distance the sound should be heard perfectly.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.refDistance = 1;
+            /**
+             * Define the roll off factor of spatial sounds.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.rolloffFactor = 1;
+            /**
+             * Define the max distance the sound should be heard (intensity just became 0 at this point).
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.maxDistance = 100;
+            /**
+             * Define the distance attenuation model the sound will follow.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.distanceModel = "linear";
-            this._panningModel = "equalpower";
             /**
              * Observable event when the current playing sound finishes.
              */
             this.onEndedObservable = new BABYLON.Observable();
+            this._panningModel = "equalpower";
             this._playbackRate = 1;
             this._streaming = false;
             this._startTime = 0;
@@ -67634,8 +67675,6 @@ var BABYLON;
             this._localDirection = new BABYLON.Vector3(1, 0, 0);
             this._volume = 1;
             this._isReadyToPlay = false;
-            this.isPlaying = false;
-            this.isPaused = false;
             this._isDirectional = false;
             // Used if you'd like to create a directional sound.
             // If not set, the sound will be omnidirectional
@@ -67772,6 +67811,7 @@ var BABYLON;
                                                 }
                                             });
                                             document.body.appendChild(this._htmlAudioElement);
+                                            this._htmlAudioElement.load();
                                         }
                                         break;
                                     }
@@ -67821,6 +67861,9 @@ var BABYLON;
                 }
             }
         }
+        /**
+         * Release the sound and its associated resources
+         */
         Sound.prototype.dispose = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this.isPlaying) {
@@ -67860,6 +67903,10 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Gets if the sounds is ready to be played or not.
+         * @returns true if ready, otherwise false
+         */
         Sound.prototype.isReady = function () {
             return this._isReadyToPlay;
         };
@@ -67879,12 +67926,20 @@ var BABYLON;
                 }
             }, function (err) { BABYLON.Tools.Error("Error while decoding audio data for: " + _this.name + " / Error: " + err); });
         };
+        /**
+         * Sets the data of the sound from an audiobuffer
+         * @param audioBuffer The audioBuffer containing the data
+         */
         Sound.prototype.setAudioBuffer = function (audioBuffer) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 this._audioBuffer = audioBuffer;
                 this._isReadyToPlay = true;
             }
         };
+        /**
+         * Updates the current sounds options such as maxdistance, loop...
+         * @param options A JSON object containing values named as the object properties
+         */
         Sound.prototype.updateOptions = function (options) {
             if (options) {
                 this.loop = options.loop || this.loop;
@@ -67937,10 +67992,20 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         Sound.prototype.switchPanningModelToHRTF = function () {
             this._panningModel = "HRTF";
             this._switchPanningModel();
         };
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         Sound.prototype.switchPanningModelToEqualPower = function () {
             this._panningModel = "equalpower";
             this._switchPanningModel();
@@ -67950,6 +68015,10 @@ var BABYLON;
                 this._soundPanner.panningModel = this._panningModel;
             }
         };
+        /**
+         * Connect this sound to a sound track audio node like gain...
+         * @param soundTrackAudioNode the sound track audio node to connect to
+         */
         Sound.prototype.connectToSoundTrackAudioNode = function (soundTrackAudioNode) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this._isOutputConnected) {
@@ -68029,12 +68098,20 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /**
+         * Sets the position of the emitter if spatial sound is enabled
+         * @param newPosition Defines the new posisiton
+         */
         Sound.prototype.setPosition = function (newPosition) {
             this._position = newPosition;
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this.spatialSound && this._soundPanner && !isNaN(this._position.x) && !isNaN(this._position.y) && !isNaN(this._position.z)) {
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         };
+        /**
+         * Sets the local direction of the emitter if spatial sound is enabled
+         * @param newLocalDirection Defines the new local direction
+         */
         Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
             this._localDirection = newLocalDirection;
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
@@ -68050,12 +68127,18 @@ var BABYLON;
             direction.normalize();
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         };
+        /** @hidden */
         Sound.prototype.updateDistanceFromListener = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
                 var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
         };
+        /**
+         * Sets a new custom attenuation function for the sound.
+         * @param callback Defines the function used for the attenuation
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-your-own-custom-attenuation-function
+         */
         Sound.prototype.setAttenuationFunction = function (callback) {
             this._customAttenuationFunction = callback;
         };
@@ -68181,6 +68264,9 @@ var BABYLON;
                 this.isPlaying = false;
             }
         };
+        /**
+         * Put the sound in pause
+         */
         Sound.prototype.pause = function () {
             if (this.isPlaying) {
                 this.isPaused = true;
@@ -68198,6 +68284,11 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Sets a dedicated volume for this sounds
+         * @param newVolume Define the new volume of the sound
+         * @param time Define in how long the sound should be at this value
+         */
         Sound.prototype.setVolume = function (newVolume, time) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._soundGain) {
                 if (time && BABYLON.Engine.audioEngine.audioContext) {
@@ -68211,6 +68302,10 @@ var BABYLON;
             }
             this._volume = newVolume;
         };
+        /**
+         * Set the sound play back rate
+         * @param newPlaybackRate Define the playback rate the sound should be played at
+         */
         Sound.prototype.setPlaybackRate = function (newPlaybackRate) {
             this._playbackRate = newPlaybackRate;
             if (this.isPlaying) {
@@ -68222,9 +68317,18 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Gets the volume of the sound.
+         * @returns the volume of the sound
+         */
         Sound.prototype.getVolume = function () {
             return this._volume;
         };
+        /**
+         * Attach the sound to a dedicated mesh
+         * @param meshToConnectTo The mesh to connect the sound with
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
         Sound.prototype.attachToMesh = function (meshToConnectTo) {
             var _this = this;
             if (this._connectedMesh && this._registerFunc) {
@@ -68244,6 +68348,10 @@ var BABYLON;
             this._registerFunc = function (connectedMesh) { return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh); };
             meshToConnectTo.registerAfterWorldMatrixUpdate(this._registerFunc);
         };
+        /**
+         * Detach the sound from the previously attached mesh
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
         Sound.prototype.detachFromMesh = function () {
             if (this._connectedMesh && this._registerFunc) {
                 this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
@@ -68268,6 +68376,10 @@ var BABYLON;
                 this._updateDirection();
             }
         };
+        /**
+         * Clone the current sound in the scene.
+         * @returns the new sound clone
+         */
         Sound.prototype.clone = function () {
             var _this = this;
             if (!this._streaming) {
@@ -68303,9 +68415,17 @@ var BABYLON;
                 return null;
             }
         };
+        /**
+         * Gets the current underlying audio buffer containing the data
+         * @returns the audio buffer
+         */
         Sound.prototype.getAudioBuffer = function () {
             return this._audioBuffer;
         };
+        /**
+         * Serializes the Sound in a JSON representation
+         * @returns the JSON representation of the sound
+         */
         Sound.prototype.serialize = function () {
             var serializationObject = {
                 name: this.name,
@@ -68336,6 +68456,14 @@ var BABYLON;
             }
             return serializationObject;
         };
+        /**
+         * Parse a JSON representation of a sound to innstantiate in a given scene
+         * @param parsedSound Define the JSON representation of the sound (usually coming from the serialize method)
+         * @param scene Define the scene the new parsed sound should be created in
+         * @param rootUrl Define the rooturl of the load in case we need to fetch relative dependencies
+         * @param sourceSound Define a cound place holder if do not need to instantiate a new one
+         * @returns the newly parsed sound
+         */
         Sound.Parse = function (parsedSound, scene, rootUrl, sourceSound) {
             var soundName = parsedSound.name;
             var soundUrl;
@@ -68402,8 +68530,23 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * It could be useful to isolate your music & sounds on several tracks to better manage volume on a grouped instance of sounds.
+     * It will be also used in a future release to apply effects on a specific track.
+     * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+     */
     var SoundTrack = /** @class */ (function () {
+        /**
+         * Creates a new sound track.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+         * @param scene Define the scene the sound track belongs to
+         * @param options
+         */
         function SoundTrack(scene, options) {
+            if (options === void 0) { options = {}; }
+            /**
+             * The unique identifier of the sound track in the scene.
+             */
             this.id = -1;
             this._isMainTrack = false;
             this._isInitialized = false;
@@ -68430,6 +68573,9 @@ var BABYLON;
                 this._isInitialized = true;
             }
         };
+        /**
+         * Release the sound track and its associated resources
+         */
         SoundTrack.prototype.dispose = function () {
             if (BABYLON.Engine.audioEngine && BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this._connectedAnalyser) {
@@ -68444,6 +68590,11 @@ var BABYLON;
                 this._outputAudioNode = null;
             }
         };
+        /**
+         * Adds a sound to this sound track
+         * @param sound define the cound to add
+         * @ignoreNaming
+         */
         SoundTrack.prototype.AddSound = function (sound) {
             if (!this._isInitialized) {
                 this._initializeSoundTrackAudioGraph();
@@ -68462,17 +68613,31 @@ var BABYLON;
             this.soundCollection.push(sound);
             sound.soundTrackId = this.id;
         };
+        /**
+         * Removes a sound to this sound track
+         * @param sound define the cound to remove
+         * @ignoreNaming
+         */
         SoundTrack.prototype.RemoveSound = function (sound) {
             var index = this.soundCollection.indexOf(sound);
             if (index !== -1) {
                 this.soundCollection.splice(index, 1);
             }
         };
+        /**
+         * Set a global volume for the full sound track.
+         * @param newVolume Define the new volume of the sound track
+         */
         SoundTrack.prototype.setVolume = function (newVolume) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._outputAudioNode) {
                 this._outputAudioNode.gain.value = newVolume;
             }
         };
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         SoundTrack.prototype.switchPanningModelToHRTF = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
@@ -68480,6 +68645,11 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         SoundTrack.prototype.switchPanningModelToEqualPower = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
@@ -68487,6 +68657,12 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Connect the sound track to an audio analyser allowing some amazing
+         * synchornization between the sounds/music and your visualization (VuMeter for instance).
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-the-analyser
+         * @param analyser The analyser to connect to the engine
+         */
         SoundTrack.prototype.connectToAnalyser = function (analyser) {
             if (this._connectedAnalyser) {
                 this._connectedAnalyser.stopDebugCanvas();
@@ -95706,6 +95882,14 @@ var BABYLON;
                 }
                 else if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE) {
                     var pointerId = pointerInfo.event.pointerId;
+                    // If drag was started with anyMouseID specified, set pointerID to the next mouse that moved
+                    if (_this.currentDraggingPointerID === PointerDragBehavior._AnyMouseID && pointerId !== PointerDragBehavior._AnyMouseID && pointerInfo.event.pointerType == "mouse") {
+                        if (_this._lastPointerRay[_this.currentDraggingPointerID]) {
+                            _this._lastPointerRay[pointerId] = _this._lastPointerRay[_this.currentDraggingPointerID];
+                            delete _this._lastPointerRay[_this.currentDraggingPointerID];
+                        }
+                        _this.currentDraggingPointerID = pointerId;
+                    }
                     // Keep track of last pointer ray, this is used simulating the start of a drag in startDrag()
                     if (!_this._lastPointerRay[pointerId]) {
                         _this._lastPointerRay[pointerId] = new BABYLON.Ray(new BABYLON.Vector3(), new BABYLON.Vector3());
@@ -95731,6 +95915,9 @@ var BABYLON;
                 }
             });
         };
+        /**
+         * Force relase the drag action by code.
+         */
         PointerDragBehavior.prototype.releaseDrag = function () {
             this.dragging = false;
             this.onDragEndObservable.notifyObservers({ dragPlanePoint: this.lastDragPosition, pointerId: this.currentDraggingPointerID });
@@ -95743,20 +95930,23 @@ var BABYLON;
         };
         /**
          * Simulates the start of a pointer drag event on the behavior
-         * @param pointerId pointerID of the pointer that should be simulated (Default: 1 for mouse pointer)
+         * @param pointerId pointerID of the pointer that should be simulated (Default: Any mouse pointer ID)
          * @param fromRay initial ray of the pointer to be simulated (Default: Ray from camera to attached mesh)
          * @param startPickedPoint picked point of the pointer to be simulated (Default: attached mesh position)
          */
         PointerDragBehavior.prototype.startDrag = function (pointerId, fromRay, startPickedPoint) {
-            if (pointerId === void 0) { pointerId = 1; }
+            if (pointerId === void 0) { pointerId = PointerDragBehavior._AnyMouseID; }
             this._startDrag(pointerId, fromRay, startPickedPoint);
-            if (this._lastPointerRay[pointerId]) {
+            var lastRay = this._lastPointerRay[pointerId];
+            if (pointerId === PointerDragBehavior._AnyMouseID) {
+                lastRay = this._lastPointerRay[Object.keys(this._lastPointerRay)[0]];
+            }
+            if (lastRay) {
                 // if there was a last pointer ray drag the object there
-                this._moveDrag(this._lastPointerRay[pointerId]);
+                this._moveDrag(lastRay);
             }
         };
         PointerDragBehavior.prototype._startDrag = function (pointerId, fromRay, startPickedPoint) {
-            if (pointerId === void 0) { pointerId = 1; }
             if (!this._scene.activeCamera || this.dragging || !this._attachedNode) {
                 return;
             }
@@ -95900,6 +96090,7 @@ var BABYLON;
                 this._scene.onBeforeRenderObservable.remove(this._beforeRenderObserver);
             }
         };
+        PointerDragBehavior._AnyMouseID = -2;
         return PointerDragBehavior;
     }());
     BABYLON.PointerDragBehavior = PointerDragBehavior;
@@ -95913,6 +96104,9 @@ var BABYLON;
      * A behavior that when attached to a mesh will allow the mesh to be scaled
      */
     var MultiPointerScaleBehavior = /** @class */ (function () {
+        /**
+         * Instantiate a new behavior that when attached to a mesh will allow the mesh to be scaled
+         */
         function MultiPointerScaleBehavior() {
             this._startDistance = 0;
             this._initialScale = new BABYLON.Vector3(0, 0, 0);
@@ -96016,6 +96210,9 @@ var BABYLON;
      * A behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
      */
     var SixDofDragBehavior = /** @class */ (function () {
+        /**
+         * Instantiates a behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
+         */
         function SixDofDragBehavior() {
             this._sceneRenderObserver = null;
             this._targetPosition = new BABYLON.Vector3(0, 0, 0);
@@ -104530,7 +104727,13 @@ var BABYLON;
             if (checkVerticesInsteadOfIndices === void 0) { checkVerticesInsteadOfIndices = false; }
             if (generateEdgesLines === void 0) { generateEdgesLines = true; }
             var _this = this;
+            /**
+             * Define the size of the edges with an orthographic camera
+             */
             this.edgesWidthScalerForOrthographic = 1000.0;
+            /**
+             * Define the size of the edges with a perspective camera
+             */
             this.edgesWidthScalerForPerspective = 50.0;
             this._linesPositions = new Array();
             this._linesNormals = new Array();
@@ -108523,10 +108726,9 @@ var BABYLON;
             this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd);
         };
         /**
-         * Targets the given mesh and updates zoom level accordingly.
-         * @param mesh  The mesh to target.
-         * @param radius Optional. If a cached radius position already exists, overrides default.
-         * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
+         * Targets the bounding box info defined by its extends and updates zoom level accordingly.
+         * @param minimumWorld Determines the smaller position of the bounding box extend
+         * @param maximumWorld Determines the bigger position of the bounding box extend
          * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
          * @param onAnimationEnd Callback triggered at the end of the framing animation
          */

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/babylon.worker.js


+ 282 - 80
dist/preview release/es6.js

@@ -9175,6 +9175,11 @@ var BABYLON;
                 document.msCancelFullScreen();
             }
         };
+        /**
+         * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
+         * @param url define the url we are trying
+         * @param element define the dom element where to configure the cors policy
+         */
         Tools.SetCorsBehavior = function (url, element) {
             if (url && url.indexOf("data:") === 0) {
                 return;
@@ -10502,14 +10507,14 @@ var BABYLON;
         /**
          * Create and run an async loop.
          * @param iterations the number of iterations.
-         * @param _fn the function to run each iteration
-         * @param _successCallback the callback that will be called upon succesful execution
+         * @param fn the function to run each iteration
+         * @param successCallback the callback that will be called upon succesful execution
          * @param offset starting offset.
          * @returns the created async loop object
          */
-        AsyncLoop.Run = function (iterations, _fn, _successCallback, offset) {
+        AsyncLoop.Run = function (iterations, fn, successCallback, offset) {
             if (offset === void 0) { offset = 0; }
-            var loop = new AsyncLoop(iterations, _fn, _successCallback, offset);
+            var loop = new AsyncLoop(iterations, fn, successCallback, offset);
             loop.executeNext();
             return loop;
         };
@@ -14644,7 +14649,7 @@ var BABYLON;
             var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
             var fromData = url.substr(0, 5) === "data:";
             var fromBlob = url.substr(0, 5) === "blob:";
-            var isBase64 = fromData && url.indexOf("base64") !== -1;
+            var isBase64 = fromData && url.indexOf(";base64,") !== -1;
             var texture = fallback ? fallback : new BABYLON.InternalTexture(this, BABYLON.InternalTexture.DATASOURCE_URL);
             // establish the file extension, if possible
             var lastDot = url.lastIndexOf('.');
@@ -17868,16 +17873,18 @@ var BABYLON;
          * Attach a behavior to the node
          * @see http://doc.babylonjs.com/features/behaviour
          * @param behavior defines the behavior to attach
+         * @param attachImmediately defines that the behavior must be attached even if the scene is still loading
          * @returns the current Node
          */
-        Node.prototype.addBehavior = function (behavior) {
+        Node.prototype.addBehavior = function (behavior, attachImmediately) {
             var _this = this;
+            if (attachImmediately === void 0) { attachImmediately = false; }
             var index = this._behaviors.indexOf(behavior);
             if (index !== -1) {
                 return this;
             }
             behavior.init();
-            if (this._scene.isLoading) {
+            if (this._scene.isLoading && !attachImmediately) {
                 // We defer the attach when the scene will be loaded
                 this._scene.onDataLoadedObservable.addOnce(function () {
                     behavior.attach(_this);
@@ -55548,6 +55555,9 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * @hidden
+     */
     var IntersectionInfo = /** @class */ (function () {
         function IntersectionInfo(bu, bv, distance) {
             this.bu = bu;
@@ -55561,7 +55571,7 @@ var BABYLON;
     BABYLON.IntersectionInfo = IntersectionInfo;
     /**
      * Information about the result of picking within a scene
-     * See https://doc.babylonjs.com/babylon101/picking_collisions
+     * @see https://doc.babylonjs.com/babylon101/picking_collisions
      */
     var PickingInfo = /** @class */ (function () {
         function PickingInfo() {
@@ -62946,15 +62956,36 @@ var BABYLON;
         enumerable: true,
         configurable: true
     });
+    /**
+     * Component responsible of rendering the bounding box of the meshes in a scene.
+     * This is usually used through the mesh.showBoundingBox or the scene.forceShowBoundingBoxes properties
+     *
+     */
     var BoundingBoxRenderer = /** @class */ (function () {
+        /**
+         * Instantiates a new bounding box renderer in a scene.
+         * @param scene the scene the  renderer renders in
+         */
         function BoundingBoxRenderer(scene) {
             /**
              * The component name helpfull to identify the component in the list of scene components.
              */
             this.name = BABYLON.SceneComponentConstants.NAME_BOUNDINGBOXRENDERER;
+            /**
+             * Color of the bounding box lines placed in front of an object
+             */
             this.frontColor = new BABYLON.Color3(1, 1, 1);
+            /**
+             * Color of the bounding box lines placed behind an object
+             */
             this.backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
+            /**
+             * Defines if the renderer should show the back lines or not
+             */
             this.showBackLines = true;
+            /**
+             * @hidden
+             */
             this.renderList = new BABYLON.SmartArray(32);
             this._vertexBuffers = {};
             this.scene = scene;
@@ -63013,6 +63044,9 @@ var BABYLON;
             }
             this._createIndexBuffer();
         };
+        /**
+         * @hidden
+         */
         BoundingBoxRenderer.prototype.reset = function () {
             this.renderList.reset();
         };
@@ -63066,6 +63100,10 @@ var BABYLON;
             engine.setDepthFunctionToLessOrEqual();
             engine.setDepthWrite(true);
         };
+        /**
+         * In case of occlusion queries, we can render the occlusion bounding box through this method
+         * @param mesh Define the mesh to render the occlusion bounding box for
+         */
         BoundingBoxRenderer.prototype.renderOcclusionBoundingBox = function (mesh) {
             this._prepareRessources();
             if (!this._colorShader.isReady() || !mesh._boundingInfo) {
@@ -63093,6 +63131,9 @@ var BABYLON;
             engine.setDepthWrite(true);
             engine.setColorWrite(true);
         };
+        /**
+         * Dispose and release the resources attached to this renderer.
+         */
         BoundingBoxRenderer.prototype.dispose = function () {
             if (!this._colorShader) {
                 return;
@@ -67301,7 +67342,6 @@ var BABYLON;
             var _this = this;
             this._audioContext = null;
             this._audioContextInitialized = false;
-            this._muteButtonDisplayed = false;
             this._muteButton = null;
             /**
              * Gets whether the current host supports Web Audio and thus could create AudioContexts.
@@ -67325,7 +67365,7 @@ var BABYLON;
              * Some Browsers have strong restrictions about Audio and won t autoplay unless
              * a user interaction has happened.
              */
-            this.unlocked = false;
+            this.unlocked = true;
             /**
              * Defines if the audio engine relies on a custom unlocked button.
              * In this case, the embedded button will not be displayed.
@@ -67364,9 +67404,6 @@ var BABYLON;
             catch (e) {
                 // protect error during capability check.
             }
-            if (/iPad|iPhone|iPod/.test(navigator.platform)) {
-                this._unlockiOSaudio();
-            }
         }
         Object.defineProperty(AudioEngine.prototype, "audioContext", {
             /**
@@ -67377,7 +67414,7 @@ var BABYLON;
                     this._initializeAudioContext();
                 }
                 else {
-                    if (!this.unlocked && !this._muteButtonDisplayed) {
+                    if (!this.unlocked && !this._muteButton) {
                         this._displayMuteButton();
                     }
                 }
@@ -67400,35 +67437,12 @@ var BABYLON;
         AudioEngine.prototype.unlock = function () {
             this._triggerRunningState();
         };
-        AudioEngine.prototype._unlockiOSaudio = function () {
-            var _this = this;
-            this._displayMuteButton(true);
-            var unlockaudio = function () {
-                if (!_this.audioContext) {
-                    return;
-                }
-                var buffer = _this.audioContext.createBuffer(1, 1, 22050);
-                var source = _this.audioContext.createBufferSource();
-                source.buffer = buffer;
-                source.connect(_this.audioContext.destination);
-                source.start(0);
-                setTimeout(function () {
-                    if ((source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE)) {
-                        _this._triggerRunningState();
-                        if (_this._muteButton) {
-                            _this._muteButton.removeEventListener('touchend', unlockaudio, false);
-                        }
-                    }
-                }, 0);
-            };
-            if (this._muteButton) {
-                this._muteButton.addEventListener('touchend', unlockaudio, false);
-            }
-        };
         AudioEngine.prototype._resumeAudioContext = function () {
+            var result;
             if (this._audioContext.resume) {
-                this._audioContext.resume();
+                result = this._audioContext.resume();
             }
+            return result || Promise.resolve();
         };
         AudioEngine.prototype._initializeAudioContext = function () {
             var _this = this;
@@ -67441,21 +67455,19 @@ var BABYLON;
                     this.masterGain.connect(this._audioContext.destination);
                     this._audioContextInitialized = true;
                     if (this._audioContext.state === "running") {
+                        // Do not wait for the promise to unlock.
                         this._triggerRunningState();
                     }
                     else {
-                        if (!this._muteButtonDisplayed) {
-                            this._displayMuteButton();
-                        }
-                        // 3 possible states: https://webaudio.github.io/web-audio-api/#BaseAudioContext
-                        this._audioContext.addEventListener("statechange", function () {
-                            if (_this._audioContext.state === "running") {
+                        if (this._audioContext && this._audioContext.resume) {
+                            this._resumeAudioContext().then(function () {
                                 _this._triggerRunningState();
-                            }
-                            else {
-                                _this._triggerSuspendedState();
-                            }
-                        });
+                            }).catch(function () {
+                                // Can not resume automatically
+                                // Needs user action
+                                _this.lock();
+                            });
+                        }
                     }
                 }
             }
@@ -67465,22 +67477,26 @@ var BABYLON;
             }
         };
         AudioEngine.prototype._triggerRunningState = function () {
-            this._resumeAudioContext();
-            this.unlocked = true;
-            if (this._muteButtonDisplayed) {
-                this._hideMuteButton();
-            }
-            // Notify users that the audio stack is unlocked/unmuted
-            this.onAudioUnlockedObservable.notifyObservers(this);
+            var _this = this;
+            this._resumeAudioContext()
+                .then(function () {
+                _this.unlocked = true;
+                if (_this._muteButton) {
+                    _this._hideMuteButton();
+                }
+                // Notify users that the audio stack is unlocked/unmuted
+                _this.onAudioUnlockedObservable.notifyObservers(_this);
+            }).catch(function () {
+                _this.unlocked = false;
+            });
         };
         AudioEngine.prototype._triggerSuspendedState = function () {
             this.unlocked = false;
             this.onAudioLockedObservable.notifyObservers(this);
             this._displayMuteButton();
         };
-        AudioEngine.prototype._displayMuteButton = function (iOS) {
+        AudioEngine.prototype._displayMuteButton = function () {
             var _this = this;
-            if (iOS === void 0) { iOS = false; }
             if (this.useCustomUnlockedButton) {
                 return;
             }
@@ -67495,12 +67511,12 @@ var BABYLON;
             document.getElementsByTagName('head')[0].appendChild(style);
             document.body.appendChild(this._muteButton);
             this._moveButtonToTopLeft();
-            if (!iOS) {
-                this._muteButton.addEventListener('mousedown', function () {
-                    _this._triggerRunningState();
-                }, false);
-            }
-            this._muteButtonDisplayed = true;
+            this._muteButton.addEventListener('mousedown', function () {
+                _this._triggerRunningState();
+            }, false);
+            this._muteButton.addEventListener('touchend', function () {
+                _this._triggerRunningState();
+            }, false);
             window.addEventListener("resize", this._onResize);
         };
         AudioEngine.prototype._moveButtonToTopLeft = function () {
@@ -67510,9 +67526,9 @@ var BABYLON;
             }
         };
         AudioEngine.prototype._hideMuteButton = function () {
-            if (this._muteButtonDisplayed && this._muteButton) {
+            if (this._muteButton) {
                 document.body.removeChild(this._muteButton);
-                this._muteButtonDisplayed = false;
+                this._muteButton = null;
             }
         };
         /**
@@ -67612,18 +67628,43 @@ var BABYLON;
              */
             this.useCustomAttenuation = false;
             /**
+             * Is this sound currently played.
+             */
+            this.isPlaying = false;
+            /**
+             * Is this sound currently paused.
+             */
+            this.isPaused = false;
+            /**
              * Does this sound enables spatial sound.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
              */
             this.spatialSound = false;
+            /**
+             * Define the reference distance the sound should be heard perfectly.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.refDistance = 1;
+            /**
+             * Define the roll off factor of spatial sounds.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.rolloffFactor = 1;
+            /**
+             * Define the max distance the sound should be heard (intensity just became 0 at this point).
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.maxDistance = 100;
+            /**
+             * Define the distance attenuation model the sound will follow.
+             * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+             */
             this.distanceModel = "linear";
-            this._panningModel = "equalpower";
             /**
              * Observable event when the current playing sound finishes.
              */
             this.onEndedObservable = new BABYLON.Observable();
+            this._panningModel = "equalpower";
             this._playbackRate = 1;
             this._streaming = false;
             this._startTime = 0;
@@ -67634,8 +67675,6 @@ var BABYLON;
             this._localDirection = new BABYLON.Vector3(1, 0, 0);
             this._volume = 1;
             this._isReadyToPlay = false;
-            this.isPlaying = false;
-            this.isPaused = false;
             this._isDirectional = false;
             // Used if you'd like to create a directional sound.
             // If not set, the sound will be omnidirectional
@@ -67772,6 +67811,7 @@ var BABYLON;
                                                 }
                                             });
                                             document.body.appendChild(this._htmlAudioElement);
+                                            this._htmlAudioElement.load();
                                         }
                                         break;
                                     }
@@ -67821,6 +67861,9 @@ var BABYLON;
                 }
             }
         }
+        /**
+         * Release the sound and its associated resources
+         */
         Sound.prototype.dispose = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this.isPlaying) {
@@ -67860,6 +67903,10 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Gets if the sounds is ready to be played or not.
+         * @returns true if ready, otherwise false
+         */
         Sound.prototype.isReady = function () {
             return this._isReadyToPlay;
         };
@@ -67879,12 +67926,20 @@ var BABYLON;
                 }
             }, function (err) { BABYLON.Tools.Error("Error while decoding audio data for: " + _this.name + " / Error: " + err); });
         };
+        /**
+         * Sets the data of the sound from an audiobuffer
+         * @param audioBuffer The audioBuffer containing the data
+         */
         Sound.prototype.setAudioBuffer = function (audioBuffer) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 this._audioBuffer = audioBuffer;
                 this._isReadyToPlay = true;
             }
         };
+        /**
+         * Updates the current sounds options such as maxdistance, loop...
+         * @param options A JSON object containing values named as the object properties
+         */
         Sound.prototype.updateOptions = function (options) {
             if (options) {
                 this.loop = options.loop || this.loop;
@@ -67937,10 +67992,20 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         Sound.prototype.switchPanningModelToHRTF = function () {
             this._panningModel = "HRTF";
             this._switchPanningModel();
         };
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         Sound.prototype.switchPanningModelToEqualPower = function () {
             this._panningModel = "equalpower";
             this._switchPanningModel();
@@ -67950,6 +68015,10 @@ var BABYLON;
                 this._soundPanner.panningModel = this._panningModel;
             }
         };
+        /**
+         * Connect this sound to a sound track audio node like gain...
+         * @param soundTrackAudioNode the sound track audio node to connect to
+         */
         Sound.prototype.connectToSoundTrackAudioNode = function (soundTrackAudioNode) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this._isOutputConnected) {
@@ -68029,12 +68098,20 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /**
+         * Sets the position of the emitter if spatial sound is enabled
+         * @param newPosition Defines the new posisiton
+         */
         Sound.prototype.setPosition = function (newPosition) {
             this._position = newPosition;
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this.spatialSound && this._soundPanner && !isNaN(this._position.x) && !isNaN(this._position.y) && !isNaN(this._position.z)) {
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         };
+        /**
+         * Sets the local direction of the emitter if spatial sound is enabled
+         * @param newLocalDirection Defines the new local direction
+         */
         Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
             this._localDirection = newLocalDirection;
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
@@ -68050,12 +68127,18 @@ var BABYLON;
             direction.normalize();
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         };
+        /** @hidden */
         Sound.prototype.updateDistanceFromListener = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
                 var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
         };
+        /**
+         * Sets a new custom attenuation function for the sound.
+         * @param callback Defines the function used for the attenuation
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-your-own-custom-attenuation-function
+         */
         Sound.prototype.setAttenuationFunction = function (callback) {
             this._customAttenuationFunction = callback;
         };
@@ -68181,6 +68264,9 @@ var BABYLON;
                 this.isPlaying = false;
             }
         };
+        /**
+         * Put the sound in pause
+         */
         Sound.prototype.pause = function () {
             if (this.isPlaying) {
                 this.isPaused = true;
@@ -68198,6 +68284,11 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Sets a dedicated volume for this sounds
+         * @param newVolume Define the new volume of the sound
+         * @param time Define in how long the sound should be at this value
+         */
         Sound.prototype.setVolume = function (newVolume, time) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._soundGain) {
                 if (time && BABYLON.Engine.audioEngine.audioContext) {
@@ -68211,6 +68302,10 @@ var BABYLON;
             }
             this._volume = newVolume;
         };
+        /**
+         * Set the sound play back rate
+         * @param newPlaybackRate Define the playback rate the sound should be played at
+         */
         Sound.prototype.setPlaybackRate = function (newPlaybackRate) {
             this._playbackRate = newPlaybackRate;
             if (this.isPlaying) {
@@ -68222,9 +68317,18 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Gets the volume of the sound.
+         * @returns the volume of the sound
+         */
         Sound.prototype.getVolume = function () {
             return this._volume;
         };
+        /**
+         * Attach the sound to a dedicated mesh
+         * @param meshToConnectTo The mesh to connect the sound with
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
         Sound.prototype.attachToMesh = function (meshToConnectTo) {
             var _this = this;
             if (this._connectedMesh && this._registerFunc) {
@@ -68244,6 +68348,10 @@ var BABYLON;
             this._registerFunc = function (connectedMesh) { return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh); };
             meshToConnectTo.registerAfterWorldMatrixUpdate(this._registerFunc);
         };
+        /**
+         * Detach the sound from the previously attached mesh
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
         Sound.prototype.detachFromMesh = function () {
             if (this._connectedMesh && this._registerFunc) {
                 this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
@@ -68268,6 +68376,10 @@ var BABYLON;
                 this._updateDirection();
             }
         };
+        /**
+         * Clone the current sound in the scene.
+         * @returns the new sound clone
+         */
         Sound.prototype.clone = function () {
             var _this = this;
             if (!this._streaming) {
@@ -68303,9 +68415,17 @@ var BABYLON;
                 return null;
             }
         };
+        /**
+         * Gets the current underlying audio buffer containing the data
+         * @returns the audio buffer
+         */
         Sound.prototype.getAudioBuffer = function () {
             return this._audioBuffer;
         };
+        /**
+         * Serializes the Sound in a JSON representation
+         * @returns the JSON representation of the sound
+         */
         Sound.prototype.serialize = function () {
             var serializationObject = {
                 name: this.name,
@@ -68336,6 +68456,14 @@ var BABYLON;
             }
             return serializationObject;
         };
+        /**
+         * Parse a JSON representation of a sound to innstantiate in a given scene
+         * @param parsedSound Define the JSON representation of the sound (usually coming from the serialize method)
+         * @param scene Define the scene the new parsed sound should be created in
+         * @param rootUrl Define the rooturl of the load in case we need to fetch relative dependencies
+         * @param sourceSound Define a cound place holder if do not need to instantiate a new one
+         * @returns the newly parsed sound
+         */
         Sound.Parse = function (parsedSound, scene, rootUrl, sourceSound) {
             var soundName = parsedSound.name;
             var soundUrl;
@@ -68402,8 +68530,23 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * It could be useful to isolate your music & sounds on several tracks to better manage volume on a grouped instance of sounds.
+     * It will be also used in a future release to apply effects on a specific track.
+     * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+     */
     var SoundTrack = /** @class */ (function () {
+        /**
+         * Creates a new sound track.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+         * @param scene Define the scene the sound track belongs to
+         * @param options
+         */
         function SoundTrack(scene, options) {
+            if (options === void 0) { options = {}; }
+            /**
+             * The unique identifier of the sound track in the scene.
+             */
             this.id = -1;
             this._isMainTrack = false;
             this._isInitialized = false;
@@ -68430,6 +68573,9 @@ var BABYLON;
                 this._isInitialized = true;
             }
         };
+        /**
+         * Release the sound track and its associated resources
+         */
         SoundTrack.prototype.dispose = function () {
             if (BABYLON.Engine.audioEngine && BABYLON.Engine.audioEngine.canUseWebAudio) {
                 if (this._connectedAnalyser) {
@@ -68444,6 +68590,11 @@ var BABYLON;
                 this._outputAudioNode = null;
             }
         };
+        /**
+         * Adds a sound to this sound track
+         * @param sound define the cound to add
+         * @ignoreNaming
+         */
         SoundTrack.prototype.AddSound = function (sound) {
             if (!this._isInitialized) {
                 this._initializeSoundTrackAudioGraph();
@@ -68462,17 +68613,31 @@ var BABYLON;
             this.soundCollection.push(sound);
             sound.soundTrackId = this.id;
         };
+        /**
+         * Removes a sound to this sound track
+         * @param sound define the cound to remove
+         * @ignoreNaming
+         */
         SoundTrack.prototype.RemoveSound = function (sound) {
             var index = this.soundCollection.indexOf(sound);
             if (index !== -1) {
                 this.soundCollection.splice(index, 1);
             }
         };
+        /**
+         * Set a global volume for the full sound track.
+         * @param newVolume Define the new volume of the sound track
+         */
         SoundTrack.prototype.setVolume = function (newVolume) {
             if (BABYLON.Engine.audioEngine.canUseWebAudio && this._outputAudioNode) {
                 this._outputAudioNode.gain.value = newVolume;
             }
         };
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         SoundTrack.prototype.switchPanningModelToHRTF = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
@@ -68480,6 +68645,11 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         SoundTrack.prototype.switchPanningModelToEqualPower = function () {
             if (BABYLON.Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
@@ -68487,6 +68657,12 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Connect the sound track to an audio analyser allowing some amazing
+         * synchornization between the sounds/music and your visualization (VuMeter for instance).
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-the-analyser
+         * @param analyser The analyser to connect to the engine
+         */
         SoundTrack.prototype.connectToAnalyser = function (analyser) {
             if (this._connectedAnalyser) {
                 this._connectedAnalyser.stopDebugCanvas();
@@ -95706,6 +95882,14 @@ var BABYLON;
                 }
                 else if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE) {
                     var pointerId = pointerInfo.event.pointerId;
+                    // If drag was started with anyMouseID specified, set pointerID to the next mouse that moved
+                    if (_this.currentDraggingPointerID === PointerDragBehavior._AnyMouseID && pointerId !== PointerDragBehavior._AnyMouseID && pointerInfo.event.pointerType == "mouse") {
+                        if (_this._lastPointerRay[_this.currentDraggingPointerID]) {
+                            _this._lastPointerRay[pointerId] = _this._lastPointerRay[_this.currentDraggingPointerID];
+                            delete _this._lastPointerRay[_this.currentDraggingPointerID];
+                        }
+                        _this.currentDraggingPointerID = pointerId;
+                    }
                     // Keep track of last pointer ray, this is used simulating the start of a drag in startDrag()
                     if (!_this._lastPointerRay[pointerId]) {
                         _this._lastPointerRay[pointerId] = new BABYLON.Ray(new BABYLON.Vector3(), new BABYLON.Vector3());
@@ -95731,6 +95915,9 @@ var BABYLON;
                 }
             });
         };
+        /**
+         * Force relase the drag action by code.
+         */
         PointerDragBehavior.prototype.releaseDrag = function () {
             this.dragging = false;
             this.onDragEndObservable.notifyObservers({ dragPlanePoint: this.lastDragPosition, pointerId: this.currentDraggingPointerID });
@@ -95743,20 +95930,23 @@ var BABYLON;
         };
         /**
          * Simulates the start of a pointer drag event on the behavior
-         * @param pointerId pointerID of the pointer that should be simulated (Default: 1 for mouse pointer)
+         * @param pointerId pointerID of the pointer that should be simulated (Default: Any mouse pointer ID)
          * @param fromRay initial ray of the pointer to be simulated (Default: Ray from camera to attached mesh)
          * @param startPickedPoint picked point of the pointer to be simulated (Default: attached mesh position)
          */
         PointerDragBehavior.prototype.startDrag = function (pointerId, fromRay, startPickedPoint) {
-            if (pointerId === void 0) { pointerId = 1; }
+            if (pointerId === void 0) { pointerId = PointerDragBehavior._AnyMouseID; }
             this._startDrag(pointerId, fromRay, startPickedPoint);
-            if (this._lastPointerRay[pointerId]) {
+            var lastRay = this._lastPointerRay[pointerId];
+            if (pointerId === PointerDragBehavior._AnyMouseID) {
+                lastRay = this._lastPointerRay[Object.keys(this._lastPointerRay)[0]];
+            }
+            if (lastRay) {
                 // if there was a last pointer ray drag the object there
-                this._moveDrag(this._lastPointerRay[pointerId]);
+                this._moveDrag(lastRay);
             }
         };
         PointerDragBehavior.prototype._startDrag = function (pointerId, fromRay, startPickedPoint) {
-            if (pointerId === void 0) { pointerId = 1; }
             if (!this._scene.activeCamera || this.dragging || !this._attachedNode) {
                 return;
             }
@@ -95900,6 +96090,7 @@ var BABYLON;
                 this._scene.onBeforeRenderObservable.remove(this._beforeRenderObserver);
             }
         };
+        PointerDragBehavior._AnyMouseID = -2;
         return PointerDragBehavior;
     }());
     BABYLON.PointerDragBehavior = PointerDragBehavior;
@@ -95913,6 +96104,9 @@ var BABYLON;
      * A behavior that when attached to a mesh will allow the mesh to be scaled
      */
     var MultiPointerScaleBehavior = /** @class */ (function () {
+        /**
+         * Instantiate a new behavior that when attached to a mesh will allow the mesh to be scaled
+         */
         function MultiPointerScaleBehavior() {
             this._startDistance = 0;
             this._initialScale = new BABYLON.Vector3(0, 0, 0);
@@ -96016,6 +96210,9 @@ var BABYLON;
      * A behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
      */
     var SixDofDragBehavior = /** @class */ (function () {
+        /**
+         * Instantiates a behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
+         */
         function SixDofDragBehavior() {
             this._sceneRenderObserver = null;
             this._targetPosition = new BABYLON.Vector3(0, 0, 0);
@@ -104530,7 +104727,13 @@ var BABYLON;
             if (checkVerticesInsteadOfIndices === void 0) { checkVerticesInsteadOfIndices = false; }
             if (generateEdgesLines === void 0) { generateEdgesLines = true; }
             var _this = this;
+            /**
+             * Define the size of the edges with an orthographic camera
+             */
             this.edgesWidthScalerForOrthographic = 1000.0;
+            /**
+             * Define the size of the edges with a perspective camera
+             */
             this.edgesWidthScalerForPerspective = 50.0;
             this._linesPositions = new Array();
             this._linesNormals = new Array();
@@ -108523,10 +108726,9 @@ var BABYLON;
             this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd);
         };
         /**
-         * Targets the given mesh and updates zoom level accordingly.
-         * @param mesh  The mesh to target.
-         * @param radius Optional. If a cached radius position already exists, overrides default.
-         * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
+         * Targets the bounding box info defined by its extends and updates zoom level accordingly.
+         * @param minimumWorld Determines the smaller position of the bounding box extend
+         * @param maximumWorld Determines the bigger position of the bounding box extend
          * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
          * @param onAnimationEnd Callback triggered at the end of the framing animation
          */

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 2 - 566
dist/preview release/typedocValidationBaseline.json

@@ -1,25 +1,7 @@
 {
-  "errors": 2483,
+  "errors": 2389,
   "babylon.typedoc.json": {
-    "errors": 2483,
-    "AsyncLoop": {
-      "Method": {
-        "Run": {
-          "Parameter": {
-            "_fn": {
-              "Naming": {
-                "NotCamelCase": true
-              }
-            },
-            "_successCallback": {
-              "Naming": {
-                "NotCamelCase": true
-              }
-            }
-          }
-        }
-      }
-    },
+    "errors": 2389,
     "BaseSubMesh": {
       "Class": {
         "Comments": {
@@ -331,73 +313,6 @@
         }
       }
     },
-    "BoundingBoxRenderer": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Constructor": {
-        "new BoundingBoxRenderer": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
-      "Property": {
-        "backColor": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "frontColor": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "renderList": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "showBackLines": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Method": {
-        "dispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "renderOcclusionBoundingBox": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "mesh": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "reset": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "BoundingInfo": {
       "Class": {
         "Comments": {
@@ -1360,20 +1275,6 @@
         }
       }
     },
-    "EdgesRenderer": {
-      "Property": {
-        "edgesWidthScalerForOrthographic": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "edgesWidthScalerForPerspective": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "EngineInstrumentation": {
       "Constructor": {
         "new EngineInstrumentation": {
@@ -1527,24 +1428,6 @@
         }
       }
     },
-    "FramingBehavior": {
-      "Method": {
-        "zoomOnBoundingInfo": {
-          "Parameter": {
-            "minimumWorld": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "maximumWorld": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      }
-    },
     "FreeCameraInputsManager": {
       "Method": {
         "addGamepad": {
@@ -2260,64 +2143,6 @@
         }
       }
     },
-    "IntersectionInfo": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Constructor": {
-        "new IntersectionInfo": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "bu": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "bv": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "distance": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
-      "Property": {
-        "bu": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "bv": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "distance": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "faceId": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "subMeshId": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "KeyboardEventTypes": {
       "Class": {
         "Comments": {
@@ -3256,15 +3081,6 @@
         }
       }
     },
-    "MultiPointerScaleBehavior": {
-      "Constructor": {
-        "new MultiPointerScaleBehavior": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "MultiRenderTarget": {
       "Class": {
         "Comments": {
@@ -4841,15 +4657,6 @@
         }
       }
     },
-    "PointerDragBehavior": {
-      "Method": {
-        "releaseDrag": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "PointerEventTypes": {
       "Class": {
         "Comments": {
@@ -8284,15 +8091,6 @@
         }
       }
     },
-    "SixDofDragBehavior": {
-      "Constructor": {
-        "new SixDofDragBehavior": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "Size": {
       "Class": {
         "Comments": {
@@ -8457,351 +8255,6 @@
         }
       }
     },
-    "Sound": {
-      "Property": {
-        "distanceModel": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "isPaused": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "isPlaying": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "maxDistance": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "onended": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "refDistance": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "rolloffFactor": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Method": {
-        "attachToMesh": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "meshToConnectTo": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "clone": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "connectToSoundTrackAudioNode": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "soundTrackAudioNode": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "detachFromMesh": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "dispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getAudioBuffer": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getVolume": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "isReady": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "pause": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "serialize": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "setAttenuationFunction": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "callback": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "setAudioBuffer": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "audioBuffer": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "setLocalDirectionToMesh": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "newLocalDirection": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "setPlaybackRate": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "newPlaybackRate": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "setPosition": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "newPosition": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "setVolume": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "newVolume": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "time": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "switchPanningModelToEqualPower": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "switchPanningModelToHRTF": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "updateDistanceFromListener": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "updateOptions": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "options": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "Parse": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "parsedSound": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "rootUrl": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "sourceSound": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      }
-    },
-    "SoundTrack": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Constructor": {
-        "new SoundTrack": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "options": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
-      "Property": {
-        "id": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "soundCollection": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Method": {
-        "AddSound": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "sound": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "RemoveSound": {
-          "Naming": {
-            "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "sound": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "connectToAnalyser": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "analyser": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "dispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "setVolume": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "newVolume": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "switchPanningModelToEqualPower": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "switchPanningModelToHRTF": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "Sprite": {
       "Class": {
         "Comments": {
@@ -11474,23 +10927,6 @@
             }
           }
         },
-        "SetCorsBehavior": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "url": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "element": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "SetImmediate": {
           "Comments": {
             "MissingText": true

+ 19 - 5
dist/preview release/viewer/babylon.viewer.d.ts

@@ -168,11 +168,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -189,11 +189,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,6 +1558,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {

Diferenças do arquivo suprimidas por serem muito extensas
+ 2 - 2
dist/preview release/viewer/babylon.viewer.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 4 - 4
dist/preview release/viewer/babylon.viewer.max.js


+ 22 - 5
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -200,11 +200,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -221,11 +221,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -985,13 +985,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1662,6 +1663,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

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

@@ -119,7 +119,7 @@
 - Added Video Recorder [Issue 4708](https://github.com/BabylonJS/Babylon.js/issues/4708) ([sebavan](http://www.github.com/sebavan))
 - Added support for main WebGL2 texture formats ([PeapBoy](https://github.com/NicolasBuecher))
 - Added fadeInOutBehavior and tooltipText for holographic buttons ([TrevorDev](https://github.com/TrevorDev))
-- StartDrag method added to pointerDragBehavior to simulate the start of a drag ([TrevorDev](https://github.com/TrevorDev))
+- StartDrag method added to pointerDragBehavior used to simulate the start of a drag ([TrevorDev](https://github.com/TrevorDev))
 - Added EdgesLineRenderer to address [#4919](https://github.com/BabylonJS/Babylon.js/pull/4919) ([barteq100](https://github.com/barteq100))
 - Added ```ambientTextureImpactOnAnalyticalLights``` in PBRMaterial to allow fine grained control of the AmbientTexture on the analytical diffuse light ([sebavan](http://www.github.com/sebavan))
 - BoundingBoxGizmo scalePivot field that can be used to always scale objects from the bottom ([TrevorDev](https://github.com/TrevorDev))

+ 45 - 64
src/Audio/babylon.audioEngine.ts

@@ -81,7 +81,6 @@
     export class AudioEngine implements IAudioEngine{
         private _audioContext: Nullable<AudioContext> = null;
         private _audioContextInitialized = false;
-        private _muteButtonDisplayed = false;
         private _muteButton: Nullable<HTMLButtonElement> = null;
         private _engine: Engine;
 
@@ -118,7 +117,7 @@
          * Some Browsers have strong restrictions about Audio and won t autoplay unless
          * a user interaction has happened.
          */
-        public unlocked: boolean = false;
+        public unlocked: boolean = true;
 
         /**
          * Defines if the audio engine relies on a custom unlocked button.
@@ -144,7 +143,7 @@
                 this._initializeAudioContext();
             }
             else {
-                if (!this.unlocked && !this._muteButtonDisplayed) {
+                if (!this.unlocked && !this._muteButton) {
                     this._displayMuteButton();
                 }
             }
@@ -186,10 +185,6 @@
             catch (e) {
                 // protect error during capability check.
             }
-
-            if (/iPad|iPhone|iPod/.test(navigator.platform)) {
-                this._unlockiOSaudio();
-            }
         }
 
         /** 
@@ -208,38 +203,12 @@
             this._triggerRunningState();
         }
 
-        private _unlockiOSaudio() {
-            this._displayMuteButton(true);
-
-            var unlockaudio = () => {
-                if (!this.audioContext) {
-                    return;
-                }
-                var buffer = this.audioContext.createBuffer(1, 1, 22050);
-                var source = this.audioContext.createBufferSource();
-                source.buffer = buffer;
-                source.connect(this.audioContext.destination);
-                source.start(0);
-  
-                setTimeout(() => {
-                    if (((<any>source).playbackState === (<any>source).PLAYING_STATE || (<any>source).playbackState === (<any>source).FINISHED_STATE)) { 
-                        this._triggerRunningState();
-                        if (this._muteButton) {
-                            this._muteButton.removeEventListener('touchend', unlockaudio, false);
-                        }
-                    }
-                }, 0);
-            };
-
-            if (this._muteButton) {
-                this._muteButton.addEventListener('touchend', unlockaudio, false);
-            }
-        }
-
-        private _resumeAudioContext() {
+        private _resumeAudioContext(): Promise<void> {
+            let result: Promise<void>;
             if (this._audioContext!.resume) {
-                this._audioContext!.resume();
+                result = this._audioContext!.resume();
             }
+            return result! || Promise.resolve();
         }
 
         private _initializeAudioContext() {
@@ -252,21 +221,19 @@
                     this.masterGain.connect(this._audioContext.destination);
                     this._audioContextInitialized = true;
                     if (this._audioContext.state === "running") {
+                        // Do not wait for the promise to unlock.
                         this._triggerRunningState();
                     }
                     else {
-                        if (!this._muteButtonDisplayed) {
-                            this._displayMuteButton();
+                        if (this._audioContext && this._audioContext.resume) {
+                            this._resumeAudioContext().then(() => {
+                                    this._triggerRunningState();
+                                }).catch(() => {
+                                    // Can not resume automatically
+                                    // Needs user action
+                                    this.lock();
+                                });
                         }
-                        // 3 possible states: https://webaudio.github.io/web-audio-api/#BaseAudioContext
-                        this._audioContext.addEventListener("statechange", () => {
-                            if (this._audioContext!.state === "running") {
-                                this._triggerRunningState();
-                            }
-                            else {
-                                this._triggerSuspendedState();
-                            }
-                        });
                     }
                 }
             }
@@ -276,15 +243,26 @@
             }
         }
 
+        private _tryToRun = false;
         private _triggerRunningState() {
-            this._resumeAudioContext();
-
-            this.unlocked = true;
-            if (this._muteButtonDisplayed) {
-               this._hideMuteButton(); 
+            if (this._tryToRun) {
+                return;
             }
-            // Notify users that the audio stack is unlocked/unmuted
-            this.onAudioUnlockedObservable.notifyObservers(this);
+            this._tryToRun = true;
+            this._resumeAudioContext()
+                .then(() => {
+                    this._tryToRun = false;
+                    this.unlocked = true;
+                    if (this._muteButton) {
+                        this._hideMuteButton(); 
+                    }
+
+                    // Notify users that the audio stack is unlocked/unmuted
+                    this.onAudioUnlockedObservable.notifyObservers(this);
+                }).catch(() => {
+                    this._tryToRun = false;
+                    this.unlocked = false;
+                });
         }
 
         private _triggerSuspendedState() {
@@ -293,7 +271,7 @@
             this._displayMuteButton();
         }
 
-        private _displayMuteButton(iOS: boolean = false) {
+        private _displayMuteButton() {
             if (this.useCustomUnlockedButton) {
                 return;
             }
@@ -314,12 +292,15 @@
 
             this._moveButtonToTopLeft();
 
-            if (!iOS) {
-                this._muteButton.addEventListener('mousedown', () => { 
-                    this._triggerRunningState(); 
-                }, false);
-            }
-            this._muteButtonDisplayed = true;
+            this._muteButton.addEventListener('mousedown', () => { 
+                this._triggerRunningState();
+            }, true);
+            this._muteButton.addEventListener('touchend', () => { 
+                this._triggerRunningState();
+            }, true);
+            this._muteButton.addEventListener('click', () => {
+                this._triggerRunningState();
+            }, true);
 
             window.addEventListener("resize", this._onResize);
         }
@@ -336,9 +317,9 @@
         }
 
         private _hideMuteButton() {
-            if (this._muteButtonDisplayed && this._muteButton) {
+            if (this._muteButton) {
                 document.body.removeChild(this._muteButton);
-                this._muteButtonDisplayed = false;
+                this._muteButton = null;
             }
         }
 

+ 135 - 17
src/Audio/babylon.sound.ts

@@ -28,19 +28,50 @@ module BABYLON {
          */
         public soundTrackId: number;
         /**
+         * Is this sound currently played.
+         */
+        public isPlaying: boolean = false;
+        /**
+         * Is this sound currently paused.
+         */
+        public isPaused: boolean = false;
+        /**
          * Does this sound enables spatial sound.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
          */
         public spatialSound: boolean = false;
+        /**
+         * Define the reference distance the sound should be heard perfectly.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         public refDistance: number = 1;
+        /**
+         * Define the roll off factor of spatial sounds.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         public rolloffFactor: number = 1;
+        /**
+         * Define the max distance the sound should be heard (intensity just became 0 at this point).
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         public maxDistance: number = 100;
+        /**
+         * Define the distance attenuation model the sound will follow.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         public distanceModel: string = "linear";
-        private _panningModel: string = "equalpower";
+        /** 
+         * @hidden
+         * Back Compat
+         **/
         public onended: () => any;
+
         /**
          * Observable event when the current playing sound finishes.
          */
         public onEndedObservable = new Observable<Sound>();
+
+        private _panningModel: string = "equalpower";
         private _playbackRate: number = 1;
         private _streaming: boolean = false;
         private _startTime: number = 0;
@@ -51,8 +82,6 @@ module BABYLON {
         private _localDirection: Vector3 = new Vector3(1, 0, 0);
         private _volume: number = 1;
         private _isReadyToPlay: boolean = false;
-        public isPlaying: boolean = false;
-        public isPaused: boolean = false;
         private _isDirectional: boolean = false;
         private _readyToPlayCallback: Nullable<() => any>;
         private _audioBuffer: Nullable<AudioBuffer>;
@@ -214,6 +243,7 @@ module BABYLON {
                                                 }
                                             });
                                             document.body.appendChild(this._htmlAudioElement);
+                                            this._htmlAudioElement.load();
                                         }
                                         break;
                                     }
@@ -265,6 +295,9 @@ module BABYLON {
             }
         }
 
+        /**
+         * Release the sound and its associated resources
+         */
         public dispose() {
             if (Engine.audioEngine.canUseWebAudio) {
                 if (this.isPlaying) {
@@ -308,6 +341,10 @@ module BABYLON {
             }
         }
 
+        /**
+         * Gets if the sounds is ready to be played or not.
+         * @returns true if ready, otherwise false
+         */
         public isReady(): boolean {
             return this._isReadyToPlay;
         }
@@ -324,6 +361,10 @@ module BABYLON {
             }, (err: any) => { Tools.Error("Error while decoding audio data for: " + this.name + " / Error: " + err); });
         }
 
+        /**
+         * Sets the data of the sound from an audiobuffer
+         * @param audioBuffer The audioBuffer containing the data
+         */
         public setAudioBuffer(audioBuffer: AudioBuffer): void {
             if (Engine.audioEngine.canUseWebAudio) {
                 this._audioBuffer = audioBuffer;
@@ -331,7 +372,11 @@ module BABYLON {
             }
         }
 
-        public updateOptions(options: any) {
+        /**
+         * Updates the current sounds options such as maxdistance, loop...
+         * @param options A JSON object containing values named as the object properties
+         */
+        public updateOptions(options: any): void {
             if (options) {
                 this.loop = options.loop || this.loop;
                 this.maxDistance = options.maxDistance || this.maxDistance;
@@ -386,11 +431,21 @@ module BABYLON {
             }
         }
 
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         public switchPanningModelToHRTF() {
             this._panningModel = "HRTF";
             this._switchPanningModel();
         }
 
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
         public switchPanningModelToEqualPower() {
             this._panningModel = "equalpower";
             this._switchPanningModel();
@@ -402,7 +457,11 @@ module BABYLON {
             }
         }
 
-        public connectToSoundTrackAudioNode(soundTrackAudioNode: AudioNode) {
+        /**
+         * Connect this sound to a sound track audio node like gain...
+         * @param soundTrackAudioNode the sound track audio node to connect to
+         */
+        public connectToSoundTrackAudioNode(soundTrackAudioNode: AudioNode): void {
             if (Engine.audioEngine.canUseWebAudio) {
                 if (this._isOutputConnected) {
                     this._outputAudioNode.disconnect();
@@ -418,7 +477,7 @@ module BABYLON {
         * @param coneOuterAngle Size of the outer cone in degree
         * @param coneOuterGain Volume of the sound outside the outer cone (between 0.0 and 1.0)
         */
-        public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number) {
+        public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number): void {
             if (coneOuterAngle < coneInnerAngle) {
                 Tools.Error("setDirectionalCone(): outer angle of the cone must be superior or equal to the inner angle.");
                 return;
@@ -482,7 +541,11 @@ module BABYLON {
             }
         }
 
-        public setPosition(newPosition: Vector3) {
+        /**
+         * Sets the position of the emitter if spatial sound is enabled
+         * @param newPosition Defines the new posisiton
+         */
+        public setPosition(newPosition: Vector3): void {
             this._position = newPosition;
 
             if (Engine.audioEngine.canUseWebAudio && this.spatialSound && this._soundPanner && !isNaN(this._position.x) && !isNaN(this._position.y) && !isNaN(this._position.z)) {
@@ -490,7 +553,11 @@ module BABYLON {
             }
         }
 
-        public setLocalDirectionToMesh(newLocalDirection: Vector3) {
+        /**
+         * Sets the local direction of the emitter if spatial sound is enabled
+         * @param newLocalDirection Defines the new local direction
+         */
+        public setLocalDirectionToMesh(newLocalDirection: Vector3): void {
             this._localDirection = newLocalDirection;
 
             if (Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
@@ -509,6 +576,7 @@ module BABYLON {
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         }
 
+        /** @hidden */
         public updateDistanceFromListener() {
             if (Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
                 var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
@@ -516,7 +584,12 @@ module BABYLON {
             }
         }
 
-        public setAttenuationFunction(callback: (currentVolume: number, currentDistance: number, maxDistance: number, refDistance: number, rolloffFactor: number) => number) {
+        /**
+         * Sets a new custom attenuation function for the sound.
+         * @param callback Defines the function used for the attenuation
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-your-own-custom-attenuation-function
+         */
+        public setAttenuationFunction(callback: (currentVolume: number, currentDistance: number, maxDistance: number, refDistance: number, rolloffFactor: number) => number): void {
             this._customAttenuationFunction = callback;
         }
 
@@ -525,7 +598,7 @@ module BABYLON {
         * @param time (optional) Start the sound after X seconds. Start immediately (0) by default.
         * @param offset (optional) Start the sound setting it at a specific time
         */
-        public play(time?: number, offset?: number) {
+        public play(time?: number, offset?: number): void {
             if (this._isReadyToPlay && this._scene.audioEnabled && Engine.audioEngine.audioContext) {
                 try {
                     if (this._startOffset < 0) {
@@ -619,7 +692,7 @@ module BABYLON {
         * Stop the sound
         * @param time (optional) Stop the sound after X seconds. Stop immediately (0) by default.
         */
-        public stop(time?: number) {
+        public stop(time?: number): void {
             if (this.isPlaying) {
                 if (this._streaming) {
                     if (this._htmlAudioElement) {
@@ -644,7 +717,10 @@ module BABYLON {
             }
         }
 
-        public pause() {
+        /**
+         * Put the sound in pause
+         */
+        public pause(): void {
             if (this.isPlaying) {
                 this.isPaused = true;
                 if (this._streaming) {
@@ -661,7 +737,12 @@ module BABYLON {
             }
         }
 
-        public setVolume(newVolume: number, time?: number) {
+        /**
+         * Sets a dedicated volume for this sounds
+         * @param newVolume Define the new volume of the sound
+         * @param time Define in how long the sound should be at this value
+         */
+        public setVolume(newVolume: number, time?: number): void {
             if (Engine.audioEngine.canUseWebAudio && this._soundGain) {
                 if (time && Engine.audioEngine.audioContext) {
                     this._soundGain.gain.cancelScheduledValues(Engine.audioEngine.audioContext.currentTime);
@@ -675,7 +756,11 @@ module BABYLON {
             this._volume = newVolume;
         }
 
-        public setPlaybackRate(newPlaybackRate: number) {
+        /**
+         * Set the sound play back rate
+         * @param newPlaybackRate Define the playback rate the sound should be played at
+         */
+        public setPlaybackRate(newPlaybackRate: number): void {
             this._playbackRate = newPlaybackRate;
             if (this.isPlaying) {
                 if (this._streaming && this._htmlAudioElement) {
@@ -686,12 +771,21 @@ module BABYLON {
                 }
             }
         }
-         
+
+        /**
+         * Gets the volume of the sound.
+         * @returns the volume of the sound
+         */
         public getVolume(): number { 
             return this._volume; 
         } 
 
-        public attachToMesh(meshToConnectTo: AbstractMesh) {
+        /**
+         * Attach the sound to a dedicated mesh
+         * @param meshToConnectTo The mesh to connect the sound with
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
+        public attachToMesh(meshToConnectTo: AbstractMesh): void {
             if (this._connectedMesh && this._registerFunc) {
                 this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                 this._registerFunc = null;
@@ -710,6 +804,10 @@ module BABYLON {
             meshToConnectTo.registerAfterWorldMatrixUpdate(this._registerFunc);
         }
 
+        /**
+         * Detach the sound from the previously attached mesh
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
+         */
         public detachFromMesh() {
             if (this._connectedMesh && this._registerFunc) {
                 this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
@@ -737,6 +835,10 @@ module BABYLON {
             }
         }
 
+        /**
+         * Clone the current sound in the scene.
+         * @returns the new sound clone
+         */
         public clone(): Nullable<Sound> {
             if (!this._streaming) {
                 var setBufferAndRun = () => {
@@ -773,10 +875,18 @@ module BABYLON {
             }
         }
 
-        public getAudioBuffer() {
+        /**
+         * Gets the current underlying audio buffer containing the data
+         * @returns the audio buffer
+         */
+        public getAudioBuffer(): Nullable<AudioBuffer> {
             return this._audioBuffer;
         }
 
+        /**
+         * Serializes the Sound in a JSON representation
+         * @returns the JSON representation of the sound
+         */
         public serialize(): any {
             var serializationObject: any = {
                 name: this.name,
@@ -812,6 +922,14 @@ module BABYLON {
             return serializationObject;
         }
 
+        /**
+         * Parse a JSON representation of a sound to innstantiate in a given scene
+         * @param parsedSound Define the JSON representation of the sound (usually coming from the serialize method)
+         * @param scene Define the scene the new parsed sound should be created in
+         * @param rootUrl Define the rooturl of the load in case we need to fetch relative dependencies
+         * @param sourceSound Define a cound place holder if do not need to instantiate a new one
+         * @returns the newly parsed sound
+         */
         public static Parse(parsedSound: any, scene: Scene, rootUrl: string, sourceSound?: Sound): Sound {
             var soundName = parsedSound.name;
             var soundUrl;

+ 76 - 11
src/Audio/babylon.soundtrack.ts

@@ -1,15 +1,47 @@
 module BABYLON {
+    /**
+     * Options allowed during the creation of a sound track.
+     */
+    export interface ISoundTrackOptions {
+        /**
+         * The volume the sound track should take during creation
+         */
+        volume?: number;
+        /**
+         * Define if the sound track is the main sound track of the scene
+         */
+        mainTrack?: boolean;
+    }
+
+    /**
+     * It could be useful to isolate your music & sounds on several tracks to better manage volume on a grouped instance of sounds. 
+     * It will be also used in a future release to apply effects on a specific track.
+     * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+     */
     export class SoundTrack {
-        private _outputAudioNode: Nullable<GainNode>;
-        private _scene: Scene;
+        /**
+         * The unique identifier of the sound track in the scene.
+         */
         public id: number = -1;
+        /**
+         * The list of sounds included in the sound track.
+         */
         public soundCollection: Array<Sound>;
+
+        private _outputAudioNode: Nullable<GainNode>;
+        private _scene: Scene;
         private _isMainTrack: boolean = false;
         private _connectedAnalyser: Analyser;
-        private _options: any;
+        private _options: ISoundTrackOptions;
         private _isInitialized = false;
 
-        constructor(scene: Scene, options?: any) {
+        /**
+         * Creates a new sound track.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-sound-tracks
+         * @param scene Define the scene the sound track belongs to
+         * @param options 
+         */
+        constructor(scene: Scene, options: ISoundTrackOptions = { }) {
             this._scene = scene;
             this.soundCollection = new Array();
             this._options = options;
@@ -34,7 +66,10 @@
             }
         }
 
-        public dispose() {
+        /**
+         * Release the sound track and its associated resources
+         */
+        public dispose(): void {
             if (Engine.audioEngine && Engine.audioEngine.canUseWebAudio) {
                 if (this._connectedAnalyser) {
                     this._connectedAnalyser.stopDebugCanvas();
@@ -49,7 +84,12 @@
             }
         }
 
-        public AddSound(sound: Sound) {
+        /**
+         * Adds a sound to this sound track
+         * @param sound define the cound to add
+         * @ignoreNaming 
+         */
+        public AddSound(sound: Sound): void {
             if (!this._isInitialized) {
                 this._initializeSoundTrackAudioGraph();
             }
@@ -69,20 +109,34 @@
             sound.soundTrackId = this.id;
         }
 
-        public RemoveSound(sound: Sound) {
+        /**
+         * Removes a sound to this sound track
+         * @param sound define the cound to remove
+         * @ignoreNaming 
+         */
+        public RemoveSound(sound: Sound): void {
             var index = this.soundCollection.indexOf(sound);
             if (index !== -1) {
                 this.soundCollection.splice(index, 1);
             }
         }
 
-        public setVolume(newVolume: number) {
+        /**
+         * Set a global volume for the full sound track.
+         * @param newVolume Define the new volume of the sound track
+         */
+        public setVolume(newVolume: number): void {
             if (Engine.audioEngine.canUseWebAudio && this._outputAudioNode) {
                 this._outputAudioNode.gain.value = newVolume;
             }
         }
 
-        public switchPanningModelToHRTF() {
+        /**
+         * Switch the panning model to HRTF:
+         * Renders a stereo output of higher quality than equalpower — it uses a convolution with measured impulse responses from human subjects.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
+        public switchPanningModelToHRTF(): void {
             if (Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
                     this.soundCollection[i].switchPanningModelToHRTF();
@@ -90,7 +144,12 @@
             }
         }
 
-        public switchPanningModelToEqualPower() {
+        /**
+         * Switch the panning model to Equal Power:
+         * Represents the equal-power panning algorithm, generally regarded as simple and efficient. equalpower is the default value.
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#creating-a-spatial-3d-sound
+         */
+        public switchPanningModelToEqualPower(): void {
             if (Engine.audioEngine.canUseWebAudio) {
                 for (var i = 0; i < this.soundCollection.length; i++) {
                     this.soundCollection[i].switchPanningModelToEqualPower();
@@ -98,7 +157,13 @@
             }
         }
 
-        public connectToAnalyser(analyser: Analyser) {
+        /**
+         * Connect the sound track to an audio analyser allowing some amazing 
+         * synchornization between the sounds/music and your visualization (VuMeter for instance).
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#using-the-analyser
+         * @param analyser The analyser to connect to the engine
+         */
+        public connectToAnalyser(analyser: Analyser): void {
             if (this._connectedAnalyser) {
                 this._connectedAnalyser.stopDebugCanvas();
             }

+ 3 - 4
src/Behaviors/Cameras/babylon.framingBehavior.ts

@@ -288,10 +288,9 @@ module BABYLON {
         }
 
 		/**
-		 * Targets the given mesh and updates zoom level accordingly.
-		 * @param mesh  The mesh to target.
-		 * @param radius Optional. If a cached radius position already exists, overrides default.
-		 * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
+		 * Targets the bounding box info defined by its extends and updates zoom level accordingly.
+		 * @param minimumWorld Determines the smaller position of the bounding box extend
+         * @param maximumWorld Determines the bigger position of the bounding box extend
 		 * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
 		 * @param onAnimationEnd Callback triggered at the end of the framing animation
 		 */

+ 3 - 0
src/Behaviors/Mesh/babylon.multiPointerScaleBehavior.ts

@@ -11,6 +11,9 @@ module BABYLON {
         private _ownerNode:Mesh;
         private _sceneRenderObserver:Nullable<Observer<Scene>> = null;
 
+        /**
+         * Instantiate a new behavior that when attached to a mesh will allow the mesh to be scaled
+         */
         constructor(){
             this._dragBehaviorA = new BABYLON.PointerDragBehavior({});
             this._dragBehaviorA.moveAttached = false;

+ 24 - 5
src/Behaviors/Mesh/babylon.pointerDragBehavior.ts

@@ -3,6 +3,7 @@ module BABYLON {
      * A behavior that when attached to a mesh will allow the mesh to be dragged around the screen based on pointer events
      */
     export class PointerDragBehavior implements Behavior<Mesh> {
+        private static _AnyMouseID = -2;
         private _attachedNode: Mesh; 
         private _dragPlane: Mesh;
         private _scene:Scene;
@@ -159,6 +160,15 @@ module BABYLON {
                     }
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE){
                     var pointerId = (<PointerEvent>pointerInfo.event).pointerId;
+
+                    // If drag was started with anyMouseID specified, set pointerID to the next mouse that moved
+                    if(this.currentDraggingPointerID === PointerDragBehavior._AnyMouseID && pointerId !== PointerDragBehavior._AnyMouseID && (<PointerEvent>pointerInfo.event).pointerType == "mouse"){
+                        if(this._lastPointerRay[this.currentDraggingPointerID]){
+                            this._lastPointerRay[pointerId] = this._lastPointerRay[this.currentDraggingPointerID];
+                            delete this._lastPointerRay[this.currentDraggingPointerID];
+                        }
+                        this.currentDraggingPointerID = pointerId;
+                    }
                     
                     // Keep track of last pointer ray, this is used simulating the start of a drag in startDrag()
                     if(!this._lastPointerRay[pointerId]){
@@ -188,6 +198,9 @@ module BABYLON {
             });
         }
 
+        /**
+         * Force relase the drag action by code.
+         */
         public releaseDrag(){
             this.dragging = false;
             this.onDragEndObservable.notifyObservers({dragPlanePoint: this.lastDragPosition, pointerId: this.currentDraggingPointerID});
@@ -204,19 +217,25 @@ module BABYLON {
         private _lastPointerRay:{[key: number]: Ray} = {};
         /**
          * Simulates the start of a pointer drag event on the behavior
-         * @param pointerId pointerID of the pointer that should be simulated (Default: 1 for mouse pointer)
+         * @param pointerId pointerID of the pointer that should be simulated (Default: Any mouse pointer ID)
          * @param fromRay initial ray of the pointer to be simulated (Default: Ray from camera to attached mesh)
          * @param startPickedPoint picked point of the pointer to be simulated (Default: attached mesh position)
          */
-        public startDrag(pointerId = 1, fromRay?:Ray, startPickedPoint?:Vector3){
+        public startDrag(pointerId:number = PointerDragBehavior._AnyMouseID, fromRay?:Ray, startPickedPoint?:Vector3){
             this._startDrag(pointerId, fromRay, startPickedPoint);
-            if(this._lastPointerRay[pointerId]){
+            
+            var lastRay =  this._lastPointerRay[pointerId];
+            if(pointerId === PointerDragBehavior._AnyMouseID){
+                lastRay = this._lastPointerRay[<any>Object.keys(this._lastPointerRay)[0]];
+            }
+            
+            if(lastRay){
                 // if there was a last pointer ray drag the object there
-                this._moveDrag(this._lastPointerRay[pointerId]);
+                this._moveDrag(lastRay);
             }
         }
 
-        private _startDrag(pointerId = 1, fromRay?:Ray, startPickedPoint?:Vector3){
+        private _startDrag(pointerId:number, fromRay?:Ray, startPickedPoint?:Vector3){
             if(!this._scene.activeCamera || this.dragging || !this._attachedNode){
                 return;
             }

+ 3 - 0
src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts

@@ -42,6 +42,9 @@ module BABYLON {
          */
         public onDragEndObservable = new Observable<{}>()
         
+        /**
+         * Instantiates a behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
+         */
         constructor(){
         }
         

+ 1 - 1
src/Cameras/Inputs/babylon.arcRotateCameraPointersInput.ts

@@ -281,7 +281,7 @@ module BABYLON {
                 }
             }
 
-            this._observer = this.camera.getScene().onPointerObservable.add(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE | PointerEventTypes._POINTERDOUBLETAP);
+            this._observer = this.camera.getScene().onPointerObservable.add(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE | PointerEventTypes.POINTERDOUBLETAP);
 
             this._onContextMenu = evt => {
                 evt.preventDefault();

+ 8 - 2
src/Collisions/babylon.pickingInfo.ts

@@ -1,15 +1,21 @@
 module BABYLON {
+    /**
+     * @hidden
+     */
     export class IntersectionInfo {
         public faceId = 0;
         public subMeshId = 0;
 
-        constructor(public bu: Nullable<number>, public bv: Nullable<number>, public distance: number) {
+        constructor(
+            public bu: Nullable<number>, 
+            public bv: Nullable<number>, 
+            public distance: number) {
         }
     }
 
     /**
      * Information about the result of picking within a scene
-     * See https://doc.babylonjs.com/babylon101/picking_collisions
+     * @see https://doc.babylonjs.com/babylon101/picking_collisions
      */
     export class PickingInfo {
         /**

+ 32 - 4
src/Debug/babylon.debugLayer.ts

@@ -29,16 +29,37 @@ module BABYLON {
         configurable: true
     });
 
+    /**
+     * The debug layer (aka Inspector) is the go to tool in order to better understand
+     * what is happening in your scene
+     * @see http://doc.babylonjs.com/features/playground_debuglayer
+     */
     export class DebugLayer {
-        private _scene: Scene;
+        /**
+         * Define the url to get the inspector script from.
+         * By default it uses the babylonjs CDN.
+         * @ignoreNaming
+         */
         public static InspectorURL = 'https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js';
+
+        private _scene: Scene;
         // The inspector instance
         private _inspector: any;
 
         private BJSINSPECTOR = typeof INSPECTOR !== 'undefined' ? INSPECTOR : undefined;
 
+        /**
+         * Observable triggered when a property is changed through the inspector.
+         */
         public onPropertyChangedObservable = new BABYLON.Observable<{ object: any, property: string, value: any, initialValue: any }>();
 
+        /**
+         * Instantiates a new debug layer.
+         * The debug layer (aka Inspector) is the go to tool in order to better understand
+         * what is happening in your scene
+         * @see http://doc.babylonjs.com/features/playground_debuglayer
+         * @param scene Defines the scene to inspect
+         */
         constructor(scene: Scene) {
             this._scene = scene;
             this._scene.onDisposeObservable.add(() => {
@@ -74,6 +95,10 @@ module BABYLON {
             } // else nothing to do as instance is already created
         }
 
+        /**
+         * Get if the inspector is visible or not.
+         * @returns true if visible otherwise, false
+         */
         public isVisible(): boolean {
             if (!this._inspector) {
                 return false;
@@ -81,6 +106,9 @@ module BABYLON {
             return true;
         }
 
+        /**
+         * Hide the inspector and close its window.
+         */
         public hide() {
             if (this._inspector) {
                 try {
@@ -112,9 +140,9 @@ module BABYLON {
         * | 9 | Physics |
         * | 10 | Camera |
         * | 11 | Audio |
-        *
+        * 
+        * @param config Define the configuration of the inspector
         */
-
         public show(config: {
             popup?: boolean,
             initialTab?: number | string,
@@ -128,7 +156,7 @@ module BABYLON {
                 colorTop?: string,
                 colorBot?: string
             }
-        } = {}) {
+        } = {}): void {
             if (typeof this.BJSINSPECTOR == 'undefined') {
                 // Load inspector and add it to the DOM
                 Tools.LoadScript(DebugLayer.InspectorURL, this._createInspector.bind(this, config));

+ 43 - 4
src/Debug/babylon.rayHelper.ts

@@ -1,6 +1,14 @@
 module BABYLON {
+    /**
+     * As raycast might be hard to debug, the RayHelper can help rendering the different rays
+     * in order to better appreciate the issue one might have.
+     * @see http://doc.babylonjs.com/babylon101/raycasts#debugging
+     */
     export class RayHelper {
 
+        /**
+         * Defines the ray we are currently tryin to visualize.
+         */
         public ray: Nullable<Ray>;
 
         private _renderPoints: Vector3[];
@@ -13,6 +21,13 @@ module BABYLON {
         private _meshSpaceDirection: Vector3;
         private _meshSpaceOrigin: Vector3;
 
+        /**
+         * Helper function to create a colored helper in a scene in one line.
+         * @param ray Defines the ray we are currently tryin to visualize
+         * @param scene Defines the scene the ray is used in
+         * @param color Defines the color we want to see the ray in
+         * @returns The newly created ray helper.
+         */
         public static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper {
             var helper = new RayHelper(ray);
 
@@ -21,10 +36,22 @@ module BABYLON {
             return helper;
         }
 
+        /**
+         * Instantiate a new ray helper.
+         * As raycast might be hard to debug, the RayHelper can help rendering the different rays
+         * in order to better appreciate the issue one might have.
+         * @see http://doc.babylonjs.com/babylon101/raycasts#debugging
+         * @param ray Defines the ray we are currently tryin to visualize
+         */
         constructor(ray: Ray) {
             this.ray = ray;
         }
 
+        /**
+         * Shows the ray we are willing to debug.
+         * @param scene Defines the scene the ray needs to be rendered in
+         * @param color Defines the color the ray needs to be rendered in
+         */
         public show(scene: Scene, color?: Color3): void {
 
             if (!this._renderFunction && this.ray) {
@@ -47,6 +74,9 @@ module BABYLON {
 
         }
 
+        /**
+         * Hides the ray we are debugging.
+         */
         public hide(): void {
 
             if (this._renderFunction && this._scene) {
@@ -82,6 +112,13 @@ module BABYLON {
 
         }
 
+        /**
+         * Attach a ray helper to a mesh so that we can easily see its orientation for instance or information like its normals.
+         * @param mesh Defines the mesh we want the helper attached to
+         * @param meshSpaceDirection Defines the direction of the Ray in mesh space (local space of the mesh node)
+         * @param meshSpaceOrigin Defines the origin of the Ray in mesh space (local space of the mesh node)
+         * @param length Defines the length of the ray
+         */
         public attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void {
 
             this._attachedToMesh = mesh;
@@ -127,9 +164,11 @@ module BABYLON {
             }
 
             this._updateToMesh();
-
         }
 
+        /**
+         * Detach the ray helper from the mesh it has previously been attached to.
+         */
         public detachFromMesh(): void {
 
             if (this._attachedToMesh) {
@@ -157,16 +196,16 @@ module BABYLON {
 
             this._attachedToMesh.getDirectionToRef(this._meshSpaceDirection, ray.direction);
             Vector3.TransformCoordinatesToRef(this._meshSpaceOrigin, this._attachedToMesh.getWorldMatrix(), ray.origin);
-
         }
 
+        /**
+         * Dispose the helper and release its associated resources.
+         */
         public dispose(): void {
 
             this.hide();
             this.detachFromMesh();
             this.ray = null;
-
         }
-
     }
 }

+ 1 - 1
src/Engine/babylon.engine.ts

@@ -4117,7 +4117,7 @@
             var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
             var fromData = url.substr(0, 5) === "data:";
             var fromBlob = url.substr(0, 5) === "blob:";
-            var isBase64 = fromData && url.indexOf("base64") !== -1;
+            var isBase64 = fromData && url.indexOf(";base64,") !== -1;
 
             let texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_URL);
 

+ 50 - 16
src/Events/babylon.keyboardEvents.ts

@@ -1,20 +1,37 @@
 module BABYLON {
-    
+    /**
+     * Gather the list of keyboard event types as constants.
+     */
     export class KeyboardEventTypes {
-        static _KEYDOWN = 0x01;
-        static _KEYUP = 0x02;
-
-        public static get KEYDOWN(): number {
-            return KeyboardEventTypes._KEYDOWN;
-        }
-
-        public static get KEYUP(): number {
-            return KeyboardEventTypes._KEYUP;
-        }
+        /**
+         * The keydown event is fired when a key becomes active (pressed).
+         */
+        public static readonly KEYDOWN = 0x01;
+        /**
+         * The keyup event is fired when a key has been released.
+         */
+        public static readonly KEYUP = 0x02;
     }
 
+    /**
+     * This class is used to store keyboard related info for the onKeyboardObservable event.
+     */
     export class KeyboardInfo {
-        constructor(public type: number, public event: KeyboardEvent) {
+        /**
+         * Instantiates a new keyboard info.
+         * This class is used to store keyboard related info for the onKeyboardObservable event.
+         * @param type Defines the type of event (BABYLON.KeyboardEventTypes)
+         * @param event Defines the related dom event
+         */
+        constructor(
+            /**
+             * Defines the type of event (BABYLON.KeyboardEventTypes)
+             */
+            public type: number,
+            /**
+             * Defines the related dom event
+             */
+            public event: KeyboardEvent) {
         }
     }
 
@@ -23,11 +40,28 @@ module BABYLON {
      * Set the skipOnKeyboardObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onKeyboardObservable
      */
     export class KeyboardInfoPre extends KeyboardInfo {
-        constructor(type: number, event: KeyboardEvent) {
+        /**
+         * Defines whether the engine should skip the next onKeyboardObservable associated to this pre.
+         */
+        public skipOnPointerObservable: boolean;
+
+        /**
+         * Instantiates a new keyboard pre info.
+         * This class is used to store keyboard related info for the onPreKeyboardObservable event.
+         * @param type Defines the type of event (BABYLON.KeyboardEventTypes)
+         * @param event Defines the related dom event
+         */
+        constructor(
+            /**
+             * Defines the type of event (BABYLON.KeyboardEventTypes)
+             */
+            public type: number,
+            /**
+             * Defines the related dom event
+             */
+            public event: KeyboardEvent) {
             super(type, event);
             this.skipOnPointerObservable = false;
         }
-
-        public skipOnPointerObservable: boolean;
-    }   
+    }
 }

+ 78 - 40
src/Events/babylon.pointerEvents.ts

@@ -1,44 +1,56 @@
 module BABYLON {
+    /**
+     * Gather the list of pointer event types as constants.
+     */
     export class PointerEventTypes {
-        static _POINTERDOWN = 0x01;
-        static _POINTERUP = 0x02;
-        static _POINTERMOVE = 0x04;
-        static _POINTERWHEEL = 0x08;
-        static _POINTERPICK = 0x10;
-        static _POINTERTAP = 0x20;
-        static _POINTERDOUBLETAP = 0x40;
-
-        public static get POINTERDOWN(): number {
-            return PointerEventTypes._POINTERDOWN;
-        }
-
-        public static get POINTERUP(): number {
-            return PointerEventTypes._POINTERUP;
-        }
-
-        public static get POINTERMOVE(): number {
-            return PointerEventTypes._POINTERMOVE;
-        }
-
-        public static get POINTERWHEEL(): number {
-            return PointerEventTypes._POINTERWHEEL;
-        }
-
-        public static get POINTERPICK(): number {
-            return PointerEventTypes._POINTERPICK;
-        }
-
-        public static get POINTERTAP(): number {
-            return PointerEventTypes._POINTERTAP;
-        }
-
-        public static get POINTERDOUBLETAP(): number {
-            return PointerEventTypes._POINTERDOUBLETAP;
-        }
+        /**
+         * The pointerdown event is fired when a pointer becomes active. For mouse, it is fired when the device transitions from no buttons depressed to at least one button depressed. For touch, it is fired when physical contact is made with the digitizer. For pen, it is fired when the stylus makes physical contact with the digitizer.
+         */
+        public static readonly POINTERDOWN = 0x01;
+        /**
+         * The pointerup event is fired when a pointer is no longer active.
+         */
+        public static readonly POINTERUP = 0x02;
+        /**
+         * The pointermove event is fired when a pointer changes coordinates.
+         */
+        public static readonly POINTERMOVE = 0x04;
+        /**
+         * The pointerwheel event is fired when a mouse wheel has been rotated.
+         */
+        public static readonly POINTERWHEEL = 0x08;
+        /**
+         * The pointerpick event is fired when a mesh or sprite has been picked by the pointer.
+         */
+        public static readonly POINTERPICK = 0x10;
+        /**
+         * The pointertap event is fired when a the object has been touched and released without drag.
+         */
+        public static readonly POINTERTAP = 0x20;
+        /**
+         * The pointertap event is fired when a the object has been touched and released twice without drag.
+         */
+        public static readonly POINTERDOUBLETAP = 0x40;
     }
 
+    /**
+     * Base class of pointer info types.
+     */
     export class PointerInfoBase {
-        constructor(public type: number, public event: PointerEvent | MouseWheelEvent) {
+        /**
+         * Instantiates the base class of pointers info.
+         * @param type Defines the type of event (BABYLON.PointerEventTypes)
+         * @param event Defines the related dom event
+         */
+        constructor(
+            /**
+             * Defines the type of event (BABYLON.PointerEventTypes)
+             */
+            public type: number, 
+            /**
+             * Defines the related dom event
+             */
+            public event: PointerEvent | MouseWheelEvent) {
         }
     }
 
@@ -51,14 +63,29 @@ module BABYLON {
          * Ray from a pointer if availible (eg. 6dof controller)
          */
         public ray:Nullable<Ray> = null;
+
+        /**
+         * Defines the local position of the pointer on the canvas.
+         */
+        public localPosition: Vector2;
+
+        /**
+         * Defines whether the engine should skip the next OnPointerObservable associated to this pre.
+         */
+        public skipOnPointerObservable: boolean;
+
+        /**
+         * Instantiates a PointerInfoPre to store pointer related info to the onPrePointerObservable event.
+         * @param type Defines the type of event (BABYLON.PointerEventTypes)
+         * @param event Defines the related dom event
+         * @param localX Defines the local x coordinates of the pointer when the event occured
+         * @param localY Defines the local y coordinates of the pointer when the event occured
+         */
         constructor(type: number, event: PointerEvent | MouseWheelEvent, localX: number, localY: number) {
             super(type, event);
             this.skipOnPointerObservable = false;
             this.localPosition = new Vector2(localX, localY);
         }
-
-        public localPosition: Vector2;
-        public skipOnPointerObservable: boolean;
     }
 
     /**
@@ -66,7 +93,18 @@ module BABYLON {
      * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
      */
     export class PointerInfo extends PointerInfoBase {
-        constructor(type: number, event: PointerEvent | MouseWheelEvent, public pickInfo: Nullable<PickingInfo>) {
+        /**
+         * Instantiates a PointerInfo to store pointer related info to the onPointerObservable event.
+         * @param type Defines the type of event (BABYLON.PointerEventTypes)
+         * @param event Defines the related dom event
+         * @param pickInfo Defines the picking info associated to the info (if any)\
+         */
+        constructor(type: number, 
+            event: PointerEvent | MouseWheelEvent, 
+            /**
+             * Defines the picking info associated to the info (if any)\
+             */
+            public pickInfo: Nullable<PickingInfo>) {
             super(type, event);
         }
     }    

+ 16 - 2
src/Instrumentation/babylon.engineInstrumentation.ts

@@ -1,6 +1,7 @@
 module BABYLON {
     /**
      * This class can be used to get instrumentation data from a Babylon engine
+     * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#engineinstrumentation
      */
     export class EngineInstrumentation implements IDisposable {
         private _captureGPUFrameTime = false;
@@ -8,7 +9,7 @@ module BABYLON {
         private _gpuFrameTime = new PerfCounter();
 
         private _captureShaderCompilationTime = false;
-        private _shaderCompilationTime = new PerfCounter();        
+        private _shaderCompilationTime = new PerfCounter();
 
         // Observers
         private _onBeginFrameObserver: Nullable<Observer<Engine>> = null;
@@ -109,9 +110,22 @@ module BABYLON {
             }
         }
 
-        public constructor(public engine: Engine) {
+        /**
+         * Instantiates a new engine instrumentation.
+         * This class can be used to get instrumentation data from a Babylon engine
+         * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#engineinstrumentation
+         * @param engine Defines the engine to instrument
+         */
+        public constructor(
+            /**
+             * Define the instrumented engine.
+             */
+            public engine: Engine) {
         }
 
+        /**
+         * Dispose and release associated resources.
+         */
         public dispose() {
             this.engine.onBeginFrameObservable.remove(this._onBeginFrameObserver);
             this._onBeginFrameObserver = null;

+ 15 - 1
src/Instrumentation/babylon.sceneInstrumentation.ts

@@ -1,6 +1,7 @@
 module BABYLON {
     /**
      * This class can be used to get instrumentation data from a Babylon engine
+     * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
      */
     export class SceneInstrumentation implements IDisposable {
         private _captureActiveMeshesEvaluationTime = false;
@@ -459,7 +460,17 @@ module BABYLON {
             return this.scene.getEngine()._textureCollisions;
         }
 
-        public constructor(public scene: Scene) {
+        /**
+         * Instantiates a new scene instrumentation.
+         * This class can be used to get instrumentation data from a Babylon engine
+         * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
+         * @param scene Defines the scene to instrument
+         */
+        public constructor(
+            /**
+             * Defines the scene to instrument
+             */
+            public scene: Scene) {
             // Before render
             this._onBeforeAnimationsObserver = scene.onBeforeAnimationsObservable.add(() => {
                 if (this._captureActiveMeshesEvaluationTime) {
@@ -512,6 +523,9 @@ module BABYLON {
             });
         }
 
+        /**
+         * Dispose and release associated resources.
+         */
         public dispose() {
             this.scene.onAfterRenderObservable.remove(this._onAfterRenderObserver);
             this._onAfterRenderObserver = null;

+ 1 - 1
src/Instrumentation/babylon.timeToken.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     /**
      * @hidden
-     **/    
+     **/
     export class _TimeToken {
         public _startTimeQuery: Nullable<WebGLQuery>;
         public _endTimeQuery: Nullable<WebGLQuery>;

+ 66 - 5
src/Layer/babylon.layer.ts

@@ -1,12 +1,51 @@
 module BABYLON {
+
+    /**
+     * This represents a full screen 2d layer.
+     * This can be usefull to display a picture in the  background of your scene for instance.
+     * @see https://www.babylonjs-playground.com/#08A2BS#1
+     */
     export class Layer {
+        /**
+         * Define the texture the layer should display.
+         */
         public texture: Nullable<Texture>;
+
+        /**
+         * Is the layer in background or foreground.
+         */
         public isBackground: boolean;
+
+        /**
+         * Define the color of the layer (instead of texture).
+         */
         public color: Color4;
+
+        /**
+         * Define the scale of the layer in order to zoom in out of the texture.
+         */
         public scale = new Vector2(1, 1);
+
+        /**
+         * Define an offset for the layer in order to shift the texture.
+         */
         public offset = new Vector2(0, 0);
+        
+        /**
+         * Define the alpha blending mode used in the layer in case the texture or color has an alpha.
+         */
         public alphaBlendingMode = Engine.ALPHA_COMBINE;
+
+        /**
+         * Define if the layer should alpha test or alpha blend with the rest of the scene.
+         * Alpha test will not mix with the background color in case of transparency.
+         * It will either use the texture color or the background depending on the alpha value of the current pixel.
+         */
         public alphaTest: boolean;
+
+        /**
+         * Define a mask to restrict the layer to only some of the scene cameras.
+         */
         public layerMask: number = 0x0FFFFFFF;
         
         private _scene: Scene;
@@ -15,15 +54,16 @@
         private _effect: Effect;
         private _alphaTestEffect: Effect;
 
-
-        // Events
-
         /**
-        * An event triggered when the layer is disposed.
-        */
+         * An event triggered when the layer is disposed.
+         */
         public onDisposeObservable = new Observable<Layer>();
 
         private _onDisposeObserver: Nullable<Observer<Layer>>;
+        /**
+         * Back compatibility with callback before the onDisposeObservable existed.
+         * The set callback will be triggered when the layer has been disposed.
+         */
         public set onDispose(callback: () => void) {
             if (this._onDisposeObserver) {
                 this.onDisposeObservable.remove(this._onDisposeObserver);
@@ -37,6 +77,10 @@
         public onBeforeRenderObservable = new Observable<Layer>();
 
         private _onBeforeRenderObserver: Nullable<Observer<Layer>>;
+        /**
+         * Back compatibility with callback before the onBeforeRenderObservable existed.
+         * The set callback will be triggered just before rendering the layer.
+         */
         public set onBeforeRender(callback: () => void) {
             if (this._onBeforeRenderObserver) {
                 this.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
@@ -57,6 +101,17 @@
             this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback);
         }
 
+        /**
+         * Instantiates a new layer.
+         * This represents a full screen 2d layer.
+         * This can be usefull to display a picture in the  background of your scene for instance.
+         * @see https://www.babylonjs-playground.com/#08A2BS#1
+         * @param name Define the name of the layer in the scene
+         * @param imgUrl Define the url of the texture to display in the layer
+         * @param scene Define the scene the layer belongs to
+         * @param isBackground Defines whether the layer is displayed in front or behind the scene
+         * @param color Defines a color for the layer
+         */
         constructor(public name: string, imgUrl: Nullable<string>, scene: Nullable<Scene>, isBackground?: boolean, color?: Color4) {
             this.texture = imgUrl ? new Texture(imgUrl, scene, true) : null;
             this.isBackground = isBackground === undefined ? true : isBackground;
@@ -123,6 +178,9 @@
             this._createIndexBuffer();
         }
 
+        /**
+         * Renders the layer in the scene.
+         */
         public render(): void {
             var currentEffect = this.alphaTest ? this._alphaTestEffect : this._effect;
 
@@ -165,6 +223,9 @@
             this.onAfterRenderObservable.notifyObservers(this);
         }
 
+        /**
+         * Disposes and releases the associated ressources.
+         */
         public dispose(): void {
             var vertexBuffer = this._vertexBuffers[VertexBuffer.PositionKind];
             if (vertexBuffer) {

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

@@ -185,6 +185,7 @@
             this._scene = scene || Engine.LastCreatedScene;
             if (this._scene) {
                 this._scene.textures.push(this);
+                this._scene.onNewTextureAddedObservable.notifyObservers(this);
             }
             this._uid = null;
         }
@@ -410,6 +411,7 @@
             if (index >= 0) {
                 this._scene.textures.splice(index, 1);
             }
+            this._scene.onTextureRemovedObservable.notifyObservers(this);
 
             if (this._texture === undefined) {
                 return;

+ 6 - 2
src/Materials/babylon.material.ts

@@ -466,8 +466,10 @@
         /**
          * Gets a boolean indicating that current material needs to register RTT
          */
-        public hasRenderTargetTextures = false;
-
+        public get hasRenderTargetTextures(): boolean {
+          return false;
+        }
+        
         /**
          * Specifies if the material should be serialized
          */
@@ -787,6 +789,7 @@
 
             if (!doNotAdd) {
                 this._scene.materials.push(this);
+                this._scene.onNewMaterialAddedObservable.notifyObservers(this);
             }
         }
 
@@ -1267,6 +1270,7 @@
             if (index >= 0) {
                 this._scene.materials.splice(index, 1);
             }
+            this._scene.onMaterialRemovedObservable.notifyObservers(this);
 
             // Remove from meshes
             for (index = 0; index < this._scene.meshes.length; index++) {

+ 3 - 1
src/PostProcess/RenderPipeline/Pipelines/babylon.standardRenderingPipeline.ts

@@ -475,7 +475,9 @@
                 this.originalPostProcess = this._basePostProcess;
             }
 
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRPassPostProcess", () => { return this.originalPostProcess; }, true));
+            if (this._bloomEnabled || this._vlsEnabled || this._lensFlareEnabled || this._depthOfFieldEnabled || this._motionBlurEnabled) {
+                this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRPassPostProcess", () => { return this.originalPostProcess; }, true));
+            }
 
             this._currentDepthOfFieldSource = this.originalPostProcess;
 

+ 31 - 1
src/Rendering/babylon.boundingBoxRenderer.ts

@@ -67,6 +67,10 @@
         configurable: true
     });
 
+    /**
+     * Component responsible of rendering the bounding box of the meshes in a scene.
+     * This is usually used through the mesh.showBoundingBox or the scene.forceShowBoundingBoxes properties
+     */
     export class BoundingBoxRenderer implements ISceneComponent {
         /**
          * The component name helpfull to identify the component in the list of scene components.
@@ -78,15 +82,31 @@
          */
         public scene: Scene;
 
+        /**
+         * Color of the bounding box lines placed in front of an object
+         */
         public frontColor = new Color3(1, 1, 1);
+        /**
+         * Color of the bounding box lines placed behind an object
+         */
         public backColor = new Color3(0.1, 0.1, 0.1);
+        /**
+         * Defines if the renderer should show the back lines or not
+         */
         public showBackLines = true;
-        public renderList = new SmartArray<BoundingBox>(32);        
+        /**
+         * @hidden
+         */
+        public renderList = new SmartArray<BoundingBox>(32);
 
         private _colorShader: ShaderMaterial;
         private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
         private _indexBuffer: WebGLBuffer;
 
+        /**
+         * Instantiates a new bounding box renderer in a scene.
+         * @param scene the scene the  renderer renders in
+         */
         constructor(scene: Scene) {
             this.scene = scene;
             scene._addComponent(this);
@@ -158,6 +178,9 @@
             this._createIndexBuffer();
         }
 
+        /**
+         * @hidden
+         */
         public reset(): void {
             this.renderList.reset();
         }
@@ -222,6 +245,10 @@
             engine.setDepthWrite(true);
         }
 
+        /**
+         * In case of occlusion queries, we can render the occlusion bounding box through this method
+         * @param mesh Define the mesh to render the occlusion bounding box for
+         */
         public renderOcclusionBoundingBox(mesh: AbstractMesh): void {
 
             this._prepareRessources();
@@ -259,6 +286,9 @@
             engine.setColorWrite(true);
         }
 
+        /**
+         * Dispose and release the resources attached to this renderer.
+         */
         public dispose(): void {
             if (!this._colorShader) {
                 return;

+ 9 - 0
src/Rendering/babylon.edgesRenderer.ts

@@ -98,8 +98,17 @@
      * This class is used to generate edges of the mesh that could then easily be rendered in a scene.
      */
     export class EdgesRenderer implements IEdgesRenderer {
+
+        /**
+         * Define the size of the edges with an orthographic camera
+         */
         public edgesWidthScalerForOrthographic = 1000.0;
+
+        /**
+         * Define the size of the edges with a perspective camera
+         */
         public edgesWidthScalerForPerspective = 50.0;
+
         protected _source: AbstractMesh;
         protected _linesPositions = new Array<number>();
         protected _linesNormals = new Array<number>();

+ 6 - 0
src/Rendering/babylon.renderingGroup.ts

@@ -1,4 +1,10 @@
 module BABYLON {
+    /**
+     * This represents the object necessary to create a rendering group.
+     * This is exclusively used and created by the rendering manager.
+     * To modify the behavior, you use the available helpers in your scene or meshes.
+     * @hidden
+     */
     export class RenderingGroup {
         private _scene: Scene;
         private _opaqueSubMeshes = new SmartArray<SubMesh>(256);

+ 32 - 2
src/Rendering/babylon.renderingManager.ts

@@ -19,6 +19,11 @@
         stencil: boolean;
     }
 
+    /**
+     * This is the manager responsible of all the rendering for meshes sprites and particles.
+     * It is enable to manage the different groups as well as the different necessary sort functions.
+     * This should not be used directly aside of the few static configurations
+     */
     export class RenderingManager {
         /**
          * The max id used for rendering groups (not included)
@@ -50,6 +55,10 @@
         private _customTransparentSortCompareFn: { [id: number]: Nullable<(a: SubMesh, b: SubMesh) => number> } = {};
         private _renderingGroupInfo: Nullable<RenderingGroupInfo> = new RenderingGroupInfo();
 
+        /**
+         * Instantiates a new rendering group for a particular scene
+         * @param scene Defines the scene the groups belongs to
+         */
         constructor(scene: Scene) {
             this._scene = scene;
 
@@ -67,6 +76,10 @@
             this._depthStencilBufferAlreadyCleaned = true;
         }
 
+        /**
+         * Renders the entire managed groups. This is used by the scene or the different rennder targets.
+         * @hidden
+         */
         public render(customRenderFunction: Nullable<(opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>) => void>,
             activeMeshes: Nullable<AbstractMesh[]>, renderParticles: boolean, renderSprites: boolean): void {
 
@@ -121,6 +134,10 @@
             }
         }
 
+        /**
+         * Resets the different information of the group to prepare a new frame
+         * @hidden
+         */
         public reset(): void {
             for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
                 var renderingGroup = this._renderingGroups[index];
@@ -130,6 +147,10 @@
             }
         }
 
+        /**
+         * Dispose and release the group and its associated resources.
+         * @hidden
+         */
         public dispose(): void {
             this.freeRenderingGroups();
             this._renderingGroups.length = 0;
@@ -158,6 +179,10 @@
             }
         }
 
+        /**
+         * Add a sprite manager to the rendering manager in order to render it this frame.
+         * @param spriteManager Define the sprite manager to render
+         */
         public dispatchSprites(spriteManager: ISpriteManager) {
             var renderingGroupId = spriteManager.renderingGroupId || 0;
 
@@ -166,6 +191,10 @@
             this._renderingGroups[renderingGroupId].dispatchSprites(spriteManager);
         }
 
+        /**
+         * Add a particle system to the rendering manager in order to render it this frame.
+         * @param particleSystem Define the particle system to render
+         */
         public dispatchParticles(particleSystem: IParticleSystem) {
             var renderingGroupId = particleSystem.renderingGroupId || 0;
 
@@ -175,9 +204,10 @@
         }
 
         /**
+         * Add a submesh to the manager in order to render it this frame
          * @param subMesh The submesh to dispatch
-         * @param [mesh] Optional reference to the submeshes's mesh. Provide if you have an exiting reference to improve performance.
-         * @param [material] Optional reference to the submeshes's material. Provide if you have an exiting reference to improve performance.
+         * @param mesh Optional reference to the submeshes's mesh. Provide if you have an exiting reference to improve performance.
+         * @param material Optional reference to the submeshes's material. Provide if you have an exiting reference to improve performance.
          */
         public dispatch(subMesh: SubMesh, mesh?: AbstractMesh, material?: Nullable<Material>): void {
             if (mesh === undefined) {

+ 9 - 4
src/Tools/babylon.tools.ts

@@ -571,6 +571,11 @@
             }
         }
 
+        /**
+         * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
+         * @param url define the url we are trying 
+         * @param element define the dom element where to configure the cors policy
+         */
         public static SetCorsBehavior(url: string | string[], element: { crossOrigin: string | null }): void {
             if (url && url.indexOf("data:") === 0) {
                 return;
@@ -2002,13 +2007,13 @@
         /**
          * Create and run an async loop.
          * @param iterations the number of iterations.
-         * @param _fn the function to run each iteration
-         * @param _successCallback the callback that will be called upon succesful execution
+         * @param fn the function to run each iteration
+         * @param successCallback the callback that will be called upon succesful execution
          * @param offset starting offset.
          * @returns the created async loop object
          */
-        public static Run(iterations: number, _fn: (asyncLoop: AsyncLoop) => void, _successCallback: () => void, offset: number = 0): AsyncLoop {
-            var loop = new AsyncLoop(iterations, _fn, _successCallback, offset);
+        public static Run(iterations: number, fn: (asyncLoop: AsyncLoop) => void, successCallback: () => void, offset: number = 0): AsyncLoop {
+            var loop = new AsyncLoop(iterations, fn, successCallback, offset);
 
             loop.executeNext();
 

+ 3 - 2
src/babylon.node.ts

@@ -247,9 +247,10 @@
          * Attach a behavior to the node
          * @see http://doc.babylonjs.com/features/behaviour
          * @param behavior defines the behavior to attach
+         * @param attachImmediately defines that the behavior must be attached even if the scene is still loading
          * @returns the current Node
          */
-        public addBehavior(behavior: Behavior<Node>): Node {
+        public addBehavior(behavior: Behavior<Node>, attachImmediately = false): Node {
             var index = this._behaviors.indexOf(behavior);
 
             if (index !== -1) {
@@ -257,7 +258,7 @@
             }
 
             behavior.init();
-            if (this._scene.isLoading) {
+            if (this._scene.isLoading && !attachImmediately) {
                 // We defer the attach when the scene will be loaded
                 this._scene.onDataLoadedObservable.addOnce(() => {
                     behavior.attach(this);

+ 48 - 1
src/babylon.scene.ts

@@ -1,4 +1,4 @@
-module BABYLON {
+module BABYLON {
     /**
      * Define an interface for all classes that will hold resources
      */
@@ -439,6 +439,26 @@
         * An event triggered when a mesh is removed
         */
         public onMeshRemovedObservable = new Observable<AbstractMesh>();
+        
+        /**
+        * An event triggered when a material is created
+        */
+        public onNewMaterialAddedObservable = new Observable<Material>();
+
+        /**
+        * An event triggered when a material is removed
+        */
+        public onMaterialRemovedObservable = new Observable<Material>();
+        
+        /**
+        * An event triggered when a texture is created
+        */
+        public onNewTextureAddedObservable = new Observable<BaseTexture>();
+
+        /**
+        * An event triggered when a texture is removed
+        */
+        public onTextureRemovedObservable = new Observable<BaseTexture>();
 
         /**
         * An event triggered when render targets are about to be rendered
@@ -3108,6 +3128,8 @@
             if (index !== -1) {
                 this.materials.splice(index, 1);
             }
+            this.onMaterialRemovedObservable.notifyObservers(toRemove);
+            
             return index;
         }
 
@@ -3134,6 +3156,8 @@
             if (index !== -1) {
                 this.textures.splice(index, 1);
             }
+            this.onTextureRemovedObservable.notifyObservers(toRemove);
+            
             return index;
         }
 
@@ -3220,6 +3244,7 @@
          */
         public addMaterial(newMaterial: Material): void {
             this.materials.push(newMaterial);
+            this.onNewMaterialAddedObservable.notifyObservers(newMaterial);
         }
 
         /**
@@ -3252,6 +3277,7 @@
          */
         public addTexture(newTexture: BaseTexture): void {
             this.textures.push(newTexture);
+            this.onNewTextureAddedObservable.notifyObservers(newTexture);
         }
 
         /**
@@ -4656,6 +4682,27 @@
             this.onBeforeRenderingGroupObservable.clear();
             this.onAfterRenderingGroupObservable.clear();
             this.onMeshImportedObservable.clear();
+            this.onBeforeCameraRenderObservable.clear();
+            this.onAfterCameraRenderObservable.clear();
+            this.onReadyObservable.clear();
+            this.onNewCameraAddedObservable.clear();
+            this.onCameraRemovedObservable.clear();
+            this.onNewLightAddedObservable.clear();
+            this.onLightRemovedObservable.clear();
+            this.onNewGeometryAddedObservable.clear();
+            this.onGeometryRemovedObservable.clear();
+            this.onNewTransformNodeAddedObservable.clear();
+            this.onTransformNodeRemovedObservable.clear();
+            this.onNewMeshAddedObservable.clear();
+            this.onMeshRemovedObservable.clear();
+            this.onNewMaterialAddedObservable.clear();
+            this.onMaterialRemovedObservable.clear();
+            this.onNewTextureAddedObservable.clear();
+            this.onTextureRemovedObservable.clear();
+            this.onPrePointerObservable.clear();
+            this.onPointerObservable.clear();
+            this.onPreKeyboardObservable.clear();
+            this.onKeyboardObservable.clear();
 
             this.detachControl();