Przeglądaj źródła

Merge pull request #5127 from sebavan/master

Doc
sebavan 7 lat temu
rodzic
commit
d9011dd5dd

+ 180 - 25
src/Animations/babylon.easing.ts

@@ -1,42 +1,72 @@
 module BABYLON {
 module BABYLON {
 
 
+    /**
+     * This represents the main contract an easing function should follow.
+     * Easing functions are used throughout the animation system.
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export interface IEasingFunction {
     export interface IEasingFunction {
+        /**
+         * Given an input gradient between 0 and 1, this returns the corrseponding value
+         * of the easing function. 
+         * The link below provides some of the most common examples of easing functions.
+         * @see https://easings.net/
+         * @param gradient Defines the value between 0 and 1 we want the easing value for
+         * @returns the corresponding value on the curve defined by the easing function
+         */
         ease(gradient: number): number;
         ease(gradient: number): number;
     }
     }
 
 
+    /**
+     * Base class used for every default easing function.
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class EasingFunction implements IEasingFunction {
     export class EasingFunction implements IEasingFunction {
-        //Statics
-        private static _EASINGMODE_EASEIN = 0;
-        private static _EASINGMODE_EASEOUT = 1;
-        private static _EASINGMODE_EASEINOUT = 2;
+        /**
+         * Interpolation follows the mathematical formula associated with the easing function.
+         */
+        public static readonly EASINGMODE_EASEIN = 0;
 
 
-        public static get EASINGMODE_EASEIN(): number {
-            return EasingFunction._EASINGMODE_EASEIN;
-        }
-
-        public static get EASINGMODE_EASEOUT(): number {
-            return EasingFunction._EASINGMODE_EASEOUT;
-        }
+        /**
+         * Interpolation follows 100% interpolation minus the output of the formula associated with the easing function.
+         */
+        public static readonly EASINGMODE_EASEOUT = 1;
 
 
-        public static get EASINGMODE_EASEINOUT(): number {
-            return EasingFunction._EASINGMODE_EASEINOUT;
-        }
+        /**
+         * Interpolation uses EaseIn for the first half of the animation and EaseOut for the second half.
+         */
+        public static readonly EASINGMODE_EASEINOUT = 2;
 
 
-        // Properties
         private _easingMode = EasingFunction.EASINGMODE_EASEIN;
         private _easingMode = EasingFunction.EASINGMODE_EASEIN;
 
 
+        /**
+         * Sets the easing mode of the current function.
+         * @param easingMode Defines the willing mode (EASINGMODE_EASEIN, EASINGMODE_EASEOUT or EASINGMODE_EASEINOUT)
+         */
         public setEasingMode(easingMode: number) {
         public setEasingMode(easingMode: number) {
             var n = Math.min(Math.max(easingMode, 0), 2);
             var n = Math.min(Math.max(easingMode, 0), 2);
             this._easingMode = n;
             this._easingMode = n;
         }
         }
+        /**
+         * Gets the current easing mode.
+         */
         public getEasingMode(): number {
         public getEasingMode(): number {
             return this._easingMode;
             return this._easingMode;
         }
         }
 
 
+        /**
+         * @hidden
+         */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             throw new Error('You must implement this method');
             throw new Error('You must implement this method');
         }
         }
 
 
+        /**
+         * Given an input gradient between 0 and 1, this returns the corrseponding value
+         * of the easing function.
+         * @param gradient Defines the value between 0 and 1 we want the easing value for
+         * @returns the corresponding value on the curve defined by the easing function
+         */
         public ease(gradient: number): number {
         public ease(gradient: number): number {
             switch (this._easingMode) {
             switch (this._easingMode) {
                 case EasingFunction.EASINGMODE_EASEIN:
                 case EasingFunction.EASINGMODE_EASEIN:
@@ -51,32 +81,66 @@
 
 
             return (this.easeInCore(gradient * 2) * 0.5);
             return (this.easeInCore(gradient * 2) * 0.5);
         }
         }
-
     }
     }
 
 
+    /**
+     * Easing function with a circle shape (see link below).
+     * @see https://easings.net/#easeInCirc
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class CircleEase extends EasingFunction implements IEasingFunction {
     export class CircleEase extends EasingFunction implements IEasingFunction {
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             gradient = Math.max(0, Math.min(1, gradient));
             gradient = Math.max(0, Math.min(1, gradient));
             return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
             return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a ease back shape (see link below).
+     * @see https://easings.net/#easeInBack
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class BackEase extends EasingFunction implements IEasingFunction {
     export class BackEase extends EasingFunction implements IEasingFunction {
-        constructor(public amplitude: number = 1) {
+        /**
+         * Instantiates a back ease easing
+         * @see https://easings.net/#easeInBack
+         * @param amplitude Defines the amplitude of the function
+         */
+        constructor(
+            /** Defines the amplitude of the function */
+            public amplitude: number = 1) {
             super();
             super();
         }
         }
 
 
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             var num = Math.max(0, this.amplitude);
             var num = Math.max(0, this.amplitude);
             return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
             return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a bouncing shape (see link below).
+     * @see https://easings.net/#easeInBounce
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class BounceEase extends EasingFunction implements IEasingFunction {
     export class BounceEase extends EasingFunction implements IEasingFunction {
-        constructor(public bounces: number= 3, public bounciness: number= 2) {
+        /**
+         * Instantiates a bounce easing
+         * @see https://easings.net/#easeInBounce
+         * @param bounces Defines the number of bounces
+         * @param bounciness Defines the amplitude of the bounce
+         */
+        constructor(
+            /** Defines the number of bounces */
+            public bounces: number= 3, 
+            /** Defines the amplitude of the bounce */
+            public bounciness: number= 2) {
             super();
             super();
         }
         }
 
 
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             var y = Math.max(0.0, this.bounces);
             var y = Math.max(0.0, this.bounces);
             var bounciness = this.bounciness;
             var bounciness = this.bounciness;
@@ -99,17 +163,39 @@
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a power of 3 shape (see link below).
+     * @see https://easings.net/#easeInCubic
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class CubicEase extends EasingFunction implements IEasingFunction {
     export class CubicEase extends EasingFunction implements IEasingFunction {
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             return (gradient * gradient * gradient);
             return (gradient * gradient * gradient);
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with an elastic shape (see link below).
+     * @see https://easings.net/#easeInElastic
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class ElasticEase extends EasingFunction implements IEasingFunction {
     export class ElasticEase extends EasingFunction implements IEasingFunction {
-        constructor(public oscillations: number= 3, public springiness: number= 3) {
+        /**
+         * Instantiates an elastic easing function
+         * @see https://easings.net/#easeInElastic
+         * @param oscillations Defines the number of oscillations
+         * @param springiness Defines the amplitude of the oscillations
+         */
+        constructor(
+            /** Defines the number of oscillations*/
+            public oscillations: number= 3,
+            /** Defines the amplitude of the oscillations*/
+            public springiness: number= 3) {
             super();
             super();
         }
         }
 
 
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             var num2;
             var num2;
             var num3 = Math.max(0.0, this.oscillations);
             var num3 = Math.max(0.0, this.oscillations);
@@ -124,11 +210,24 @@
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with an exponential shape (see link below).
+     * @see https://easings.net/#easeInExpo
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class ExponentialEase extends EasingFunction implements IEasingFunction {
     export class ExponentialEase extends EasingFunction implements IEasingFunction {
-        constructor(public exponent: number= 2) {
+        /**
+         * Instantiates an exponential easing function
+         * @see https://easings.net/#easeInExpo
+         * @param exponent Defines the exponent of the function
+         */
+        constructor(
+            /** Defines the exponent of the function */
+            public exponent: number= 2) {
             super();
             super();
         }
         }
 
 
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             if (this.exponent <= 0) {
             if (this.exponent <= 0) {
                 return gradient;
                 return gradient;
@@ -138,49 +237,105 @@
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a power shape (see link below).
+     * @see https://easings.net/#easeInQuad
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class PowerEase  extends EasingFunction implements IEasingFunction {
     export class PowerEase  extends EasingFunction implements IEasingFunction {
-        constructor(public power: number= 2) {
+        /**
+         * Instantiates an power base easing function
+         * @see https://easings.net/#easeInQuad
+         * @param power Defines the power of the function
+         */
+        constructor(
+            /** Defines the power of the function */
+            public power: number= 2) {
             super();
             super();
         }
         }
 
 
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             var y = Math.max(0.0, this.power);
             var y = Math.max(0.0, this.power);
             return Math.pow(gradient, y);
             return Math.pow(gradient, y);
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a power of 2 shape (see link below).
+     * @see https://easings.net/#easeInQuad
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class QuadraticEase extends EasingFunction implements IEasingFunction {
     export class QuadraticEase extends EasingFunction implements IEasingFunction {
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             return (gradient * gradient);
             return (gradient * gradient);
-
-           
-
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a power of 4 shape (see link below).
+     * @see https://easings.net/#easeInQuart
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class QuarticEase extends EasingFunction implements IEasingFunction {
     export class QuarticEase extends EasingFunction implements IEasingFunction {
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             return (gradient * gradient * gradient * gradient);
             return (gradient * gradient * gradient * gradient);
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a power of 5 shape (see link below).
+     * @see https://easings.net/#easeInQuint
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class QuinticEase extends EasingFunction implements IEasingFunction {
     export class QuinticEase extends EasingFunction implements IEasingFunction {
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             return (gradient * gradient * gradient * gradient * gradient);
             return (gradient * gradient * gradient * gradient * gradient);
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a sin shape (see link below).
+     * @see https://easings.net/#easeInSine
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class SineEase  extends EasingFunction implements IEasingFunction {
     export class SineEase  extends EasingFunction implements IEasingFunction {
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
             return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
         }
         }
     }
     }
 
 
+    /**
+     * Easing function with a bezier shape (see link below).
+     * @see http://cubic-bezier.com/#.17,.67,.83,.67
+     * @see http://doc.babylonjs.com/babylon101/animations#easing-functions
+     */
     export class BezierCurveEase extends EasingFunction implements IEasingFunction {
     export class BezierCurveEase extends EasingFunction implements IEasingFunction {
-        constructor(public x1: number= 0, public y1: number= 0, public x2: number= 1, public y2: number= 1) {
+        /**
+         * Instantiates a bezier function
+         * @see http://cubic-bezier.com/#.17,.67,.83,.67
+         * @param x1 Defines the x component of the start tangent in the bezier curve
+         * @param y1 Defines the y component of the start tangent in the bezier curve
+         * @param x2 Defines the x component of the end tangent in the bezier curve
+         * @param y2 Defines the y component of the end tangent in the bezier curve
+         */
+        constructor(
+            /** Defines the x component of the start tangent in the bezier curve */
+            public x1: number= 0,
+            /** Defines the y component of the start tangent in the bezier curve */
+            public y1: number= 0,
+            /** Defines the x component of the end tangent in the bezier curve */
+            public x2: number= 1,
+            /** Defines the y component of the end tangent in the bezier curve */
+            public y2: number= 1) {
             super();
             super();
         }
         }
 
 
+        /** @hidden */
         public easeInCore(gradient: number): number {
         public easeInCore(gradient: number): number {
             return BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
             return BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
         }
         }

+ 67 - 8
src/Audio/babylon.audioEngine.ts

@@ -39,20 +39,53 @@
     // Sets the default audio engine to Babylon JS.
     // Sets the default audio engine to Babylon JS.
     Engine.AudioEngineFactory = () => { return new AudioEngine(); };
     Engine.AudioEngineFactory = () => { return new AudioEngine(); };
 
 
+    /**
+     * This represents the default audio engine used in babylon.
+     * It is responsible to play, synchronize and analyse sounds throughout the  application.
+     * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
+     */
     export class AudioEngine implements IAudioEngine{
     export class AudioEngine implements IAudioEngine{
-        private _audioContext: Nullable<AudioContext> = null;
-        private _audioContextInitialized = false;
+        /**
+         * Gets whether the current host supports Web Audio and thus could create AudioContexts.
+         */
         public canUseWebAudio: boolean = false;
         public canUseWebAudio: boolean = false;
+
+        /**
+         * The master gain node defines the global audio volume of your audio engine.
+         */
         public masterGain: GainNode;
         public masterGain: GainNode;
 
 
-        private _connectedAnalyser: Nullable<Analyser>;
+        /**
+         * Defines if Babylon should emit a warning if WebAudio is not supported.
+         * @ignoreNaming
+         */
         public WarnedWebAudioUnsupported: boolean = false;
         public WarnedWebAudioUnsupported: boolean = false;
-        public unlocked: boolean = false;
-        public onAudioUnlocked: () => any;
 
 
+        /**
+         * Gets whether or not mp3 are supported by your browser.
+         */
         public isMP3supported: boolean = false;
         public isMP3supported: boolean = false;
+
+        /**
+         * Gets whether or not ogg are supported by your browser.
+         */
         public isOGGsupported: boolean = false;
         public isOGGsupported: boolean = false;
 
 
+        /**
+         * Gets whether audio has been unlocked on the device.
+         * Some Browsers have strong restrictions about Audio and won t autoplay unless
+         * a user interaction has happened.
+         */
+        public unlocked: boolean = false;
+
+        /**
+         * Event raised when audio has been unlocked on the browser.
+         */
+        public onAudioUnlocked: () => any;
+
+        /**
+         * Gets the current AudioContext if available.
+         */
         public get audioContext(): Nullable<AudioContext> {
         public get audioContext(): Nullable<AudioContext> {
             if (!this._audioContextInitialized) {
             if (!this._audioContextInitialized) {
                 this._initializeAudioContext();
                 this._initializeAudioContext();
@@ -60,6 +93,16 @@
             return this._audioContext;
             return this._audioContext;
         }
         }
 
 
+        private _audioContext: Nullable<AudioContext> = null;
+        private _audioContextInitialized = false;
+        private _connectedAnalyser: Nullable<Analyser>;
+        
+        /**
+         * Instantiates a new audio engine.
+         * 
+         * There should be only one per page as some browsers restrict the number
+         * of audio contexts you can create.
+         */
         constructor() {
         constructor() {
             if (typeof window.AudioContext !== 'undefined' || typeof window.webkitAudioContext !== 'undefined') {
             if (typeof window.AudioContext !== 'undefined' || typeof window.webkitAudioContext !== 'undefined') {
                 window.AudioContext = window.AudioContext || window.webkitAudioContext;
                 window.AudioContext = window.AudioContext || window.webkitAudioContext;
@@ -136,7 +179,10 @@
             }
             }
         }
         }
 
 
-        public dispose() {
+        /**
+         * Destroy and release the resources associated with the audio ccontext.
+         */
+        public dispose(): void {
             if (this.canUseWebAudio && this._audioContextInitialized) {
             if (this.canUseWebAudio && this._audioContextInitialized) {
                 if (this._connectedAnalyser && this._audioContext) {
                 if (this._connectedAnalyser && this._audioContext) {
                     this._connectedAnalyser.stopDebugCanvas();
                     this._connectedAnalyser.stopDebugCanvas();
@@ -150,6 +196,10 @@
             this.WarnedWebAudioUnsupported = false;
             this.WarnedWebAudioUnsupported = false;
         }
         }
 
 
+        /**
+         * Gets the global volume sets on the master gain.
+         * @returns the global volume if set or -1 otherwise
+         */
         public getGlobalVolume(): number {
         public getGlobalVolume(): number {
             if (this.canUseWebAudio && this._audioContextInitialized) {
             if (this.canUseWebAudio && this._audioContextInitialized) {
                 return this.masterGain.gain.value;
                 return this.masterGain.gain.value;
@@ -159,13 +209,22 @@
             }
             }
         }
         }
 
 
-        public setGlobalVolume(newVolume: number) {
+        /**
+         * Sets the global volume of your experience (sets on the master gain).
+         */
+        public setGlobalVolume(newVolume: number): void {
             if (this.canUseWebAudio && this._audioContextInitialized) {
             if (this.canUseWebAudio && this._audioContextInitialized) {
                 this.masterGain.gain.value = newVolume;
                 this.masterGain.gain.value = newVolume;
             }
             }
         }
         }
 
 
-        public connectToAnalyser(analyser: Analyser) {
+        /**
+         * Connect the audio engine 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) {
             if (this._connectedAnalyser) {
                 this._connectedAnalyser.stopDebugCanvas();
                 this._connectedAnalyser.stopDebugCanvas();
             }
             }

+ 146 - 129
src/Behaviors/Cameras/babylon.autoRotationBehavior.ts

@@ -1,76 +1,83 @@
 module BABYLON {
 module BABYLON {
+    /**
+     * The autoRotation behavior (BABYLON.AutoRotationBehavior) is designed to create a smooth rotation of an ArcRotateCamera when there is no user interaction.
+     * @see http://doc.babylonjs.com/how_to/camera_behaviors#autorotation-behavior
+     */
     export class AutoRotationBehavior implements Behavior<ArcRotateCamera> {
     export class AutoRotationBehavior implements Behavior<ArcRotateCamera> {
+        /**
+         * Gets the name of the behavior.
+         */
         public get name(): string {
         public get name(): string {
             return "AutoRotation";
             return "AutoRotation";
         }
         }
 
 
         private _zoomStopsAnimation = false;
         private _zoomStopsAnimation = false;
-		private _idleRotationSpeed = 0.05;
-		private _idleRotationWaitTime = 2000;
+        private _idleRotationSpeed = 0.05;
+        private _idleRotationWaitTime = 2000;
         private _idleRotationSpinupTime = 2000;  
         private _idleRotationSpinupTime = 2000;  
        
        
-		/**
-		* Sets the flag that indicates if user zooming should stop animation.
-		*/
-		public set zoomStopsAnimation(flag: boolean) {
-			this._zoomStopsAnimation = flag;
-		}
-
-		/**
-		* Gets the flag that indicates if user zooming should stop animation.
-		*/
-		public get zoomStopsAnimation(): boolean {
-			return this._zoomStopsAnimation;
+        /**
+        * Sets the flag that indicates if user zooming should stop animation.
+        */
+        public set zoomStopsAnimation(flag: boolean) {
+            this._zoomStopsAnimation = flag;
+        }
+
+        /**
+        * Gets the flag that indicates if user zooming should stop animation.
+        */
+        public get zoomStopsAnimation(): boolean {
+            return this._zoomStopsAnimation;
         }       
         }       
         
         
-		/**
-		* Sets the default speed at which the camera rotates around the model.
-		*/
-		public set idleRotationSpeed(speed: number) {
-			this._idleRotationSpeed = speed;
-		}
-
-		/**
-		* Gets the default speed at which the camera rotates around the model.
-		*/
-		public get idleRotationSpeed() {
-			return this._idleRotationSpeed;
-		}
-
-		/**
-		* Sets the time (in milliseconds) to wait after user interaction before the camera starts rotating.
-		*/
-		public set idleRotationWaitTime(time: number) {
-			this._idleRotationWaitTime = time;
-		}
-
-		/**
-		* Gets the time (milliseconds) to wait after user interaction before the camera starts rotating.
-		*/
-		public get idleRotationWaitTime() {
-			return this._idleRotationWaitTime;
-		}
-
-		/**
-		* Sets the time (milliseconds) to take to spin up to the full idle rotation speed.
-		*/
-		public set idleRotationSpinupTime(time: number) {
-			this._idleRotationSpinupTime = time;
-		}
-
-		/**
-		* Gets the time (milliseconds) to take to spin up to the full idle rotation speed.
-		*/
-		public get idleRotationSpinupTime() {
-			return this._idleRotationSpinupTime;
-		}
-
-		/**
-		 * Gets a value indicating if the camera is currently rotating because of this behavior
-		 */
-		public get rotationInProgress(): boolean {
-			return Math.abs(this._cameraRotationSpeed) > 0;
-		}
+        /**
+        * Sets the default speed at which the camera rotates around the model.
+        */
+        public set idleRotationSpeed(speed: number) {
+            this._idleRotationSpeed = speed;
+        }
+
+        /**
+        * Gets the default speed at which the camera rotates around the model.
+        */
+        public get idleRotationSpeed() {
+            return this._idleRotationSpeed;
+        }
+
+        /**
+        * Sets the time (in milliseconds) to wait after user interaction before the camera starts rotating.
+        */
+        public set idleRotationWaitTime(time: number) {
+            this._idleRotationWaitTime = time;
+        }
+
+        /**
+        * Gets the time (milliseconds) to wait after user interaction before the camera starts rotating.
+        */
+        public get idleRotationWaitTime() {
+            return this._idleRotationWaitTime;
+        }
+
+        /**
+        * Sets the time (milliseconds) to take to spin up to the full idle rotation speed.
+        */
+        public set idleRotationSpinupTime(time: number) {
+            this._idleRotationSpinupTime = time;
+        }
+
+        /**
+        * Gets the time (milliseconds) to take to spin up to the full idle rotation speed.
+        */
+        public get idleRotationSpinupTime() {
+            return this._idleRotationSpinupTime;
+        }
+
+        /**
+         * Gets a value indicating if the camera is currently rotating because of this behavior
+         */
+        public get rotationInProgress(): boolean {
+            return Math.abs(this._cameraRotationSpeed) > 0;
+        }
         
         
         // Default behavior functions
         // Default behavior functions
         private _onPrePointerObservableObserver: Nullable<Observer<PointerInfoPre>>;
         private _onPrePointerObservableObserver: Nullable<Observer<PointerInfoPre>>;
@@ -78,13 +85,20 @@ module BABYLON {
         private _attachedCamera: Nullable<ArcRotateCamera>;
         private _attachedCamera: Nullable<ArcRotateCamera>;
         private _isPointerDown = false;
         private _isPointerDown = false;
         private _lastFrameTime: Nullable<number> = null;
         private _lastFrameTime: Nullable<number> = null;
-		private _lastInteractionTime = -Infinity;
-		private _cameraRotationSpeed: number = 0;
-
-		public init(): void {
-			// Do notihng
-		}
+        private _lastInteractionTime = -Infinity;
+        private _cameraRotationSpeed: number = 0;
+
+        /**
+         * Initializes the behavior.
+         */
+        public init(): void {
+            // Do notihng
+        }
 
 
+        /**
+         * Attaches the behavior to its arc rotate camera.
+         * @param camera Defines the camera to attach the behavior to
+         */
         public attach(camera: ArcRotateCamera): void {
         public attach(camera: ArcRotateCamera): void {
             this._attachedCamera = camera;
             this._attachedCamera = camera;
             let scene = this._attachedCamera.getScene();
             let scene = this._attachedCamera.getScene();
@@ -112,78 +126,81 @@ module BABYLON {
                 this._applyUserInteraction();
                 this._applyUserInteraction();
     
     
                 let timeToRotation = now - this._lastInteractionTime - this._idleRotationWaitTime;
                 let timeToRotation = now - this._lastInteractionTime - this._idleRotationWaitTime;
-				let scale = Math.max(Math.min(timeToRotation / (this._idleRotationSpinupTime), 1), 0);
+                let scale = Math.max(Math.min(timeToRotation / (this._idleRotationSpinupTime), 1), 0);
                 this._cameraRotationSpeed = this._idleRotationSpeed * scale;
                 this._cameraRotationSpeed = this._idleRotationSpeed * scale;
     
     
-				// Step camera rotation by rotation speed
-				if (this._attachedCamera) {
-					this._attachedCamera.alpha -= this._cameraRotationSpeed * (dt / 1000);
-				}
+                // Step camera rotation by rotation speed
+                if (this._attachedCamera) {
+                    this._attachedCamera.alpha -= this._cameraRotationSpeed * (dt / 1000);
+                }
             });
             });
         }
         }
-             
+
+        /**
+         * Detaches the behavior from its current arc rotate camera.
+         */
         public detach(): void {
         public detach(): void {
-			if (!this._attachedCamera) {
-				return;
-			}
+            if (!this._attachedCamera) {
+                return;
+            }
             let scene = this._attachedCamera.getScene();
             let scene = this._attachedCamera.getScene();
-			
-			if (this._onPrePointerObservableObserver) {
-				scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver);
-			}
-			
-			this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
-			this._attachedCamera = null;
-		}
-
-		/**
-		 * Returns true if user is scrolling. 
-		 * @return true if user is scrolling.
-		 */
-		private _userIsZooming(): boolean {
-			if (!this._attachedCamera) {
-				return false;
-			}			
-			return this._attachedCamera.inertialRadiusOffset !== 0;
-		}   		
-		
-		private _lastFrameRadius = 0;
-		private _shouldAnimationStopForInteraction(): boolean {
-			if (!this._attachedCamera) {
-				return false;
-			}	
-
-			var zoomHasHitLimit = false;
-			if (this._lastFrameRadius === this._attachedCamera.radius && this._attachedCamera.inertialRadiusOffset !== 0) {
-				zoomHasHitLimit = true;
-			}
-
-			// Update the record of previous radius - works as an approx. indicator of hitting radius limits
-			this._lastFrameRadius = this._attachedCamera.radius;
-			return this._zoomStopsAnimation ? zoomHasHitLimit : this._userIsZooming();
-		}   		
-
-		/**
-		 *  Applies any current user interaction to the camera. Takes into account maximum alpha rotation.
-		 */          
+            
+            if (this._onPrePointerObservableObserver) {
+                scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver);
+            }
+            
+            this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
+            this._attachedCamera = null;
+        }
+
+        /**
+         * Returns true if user is scrolling. 
+         * @return true if user is scrolling.
+         */
+        private _userIsZooming(): boolean {
+            if (!this._attachedCamera) {
+                return false;
+            }			
+            return this._attachedCamera.inertialRadiusOffset !== 0;
+        }   		
+        
+        private _lastFrameRadius = 0;
+        private _shouldAnimationStopForInteraction(): boolean {
+            if (!this._attachedCamera) {
+                return false;
+            }	
+
+            var zoomHasHitLimit = false;
+            if (this._lastFrameRadius === this._attachedCamera.radius && this._attachedCamera.inertialRadiusOffset !== 0) {
+                zoomHasHitLimit = true;
+            }
+
+            // Update the record of previous radius - works as an approx. indicator of hitting radius limits
+            this._lastFrameRadius = this._attachedCamera.radius;
+            return this._zoomStopsAnimation ? zoomHasHitLimit : this._userIsZooming();
+        }   		
+
+        /**
+         *  Applies any current user interaction to the camera. Takes into account maximum alpha rotation.
+         */          
         private _applyUserInteraction(): void {
         private _applyUserInteraction(): void {
-			if (this._userIsMoving() && !this._shouldAnimationStopForInteraction()) {
+            if (this._userIsMoving() && !this._shouldAnimationStopForInteraction()) {
                 this._lastInteractionTime = Tools.Now;
                 this._lastInteractionTime = Tools.Now;
-			}
+            }
         }                
         }                
    
    
         // Tools
         // Tools
         private _userIsMoving(): boolean {
         private _userIsMoving(): boolean {
-			if (!this._attachedCamera) {
-				return false;
-			}	
-			
-			return this._attachedCamera.inertialAlphaOffset !== 0 ||
-				this._attachedCamera.inertialBetaOffset !== 0 ||
-				this._attachedCamera.inertialRadiusOffset !== 0 ||
-				this._attachedCamera.inertialPanningX !== 0 ||
-				this._attachedCamera.inertialPanningY !== 0 ||
-				this._isPointerDown;
-		}
+            if (!this._attachedCamera) {
+                return false;
+            }	
+            
+            return this._attachedCamera.inertialAlphaOffset !== 0 ||
+                this._attachedCamera.inertialBetaOffset !== 0 ||
+                this._attachedCamera.inertialRadiusOffset !== 0 ||
+                this._attachedCamera.inertialPanningX !== 0 ||
+                this._attachedCamera.inertialPanningY !== 0 ||
+                this._isPointerDown;
+        }
     }
     }
 }
 }

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

@@ -1944,20 +1944,32 @@
     }
     }
 
 
     /**
     /**
-    * An implementation of a loop for asynchronous functions.
-    */
+     * An implementation of a loop for asynchronous functions.
+     */
     export class AsyncLoop {
     export class AsyncLoop {
+        /**
+         * Defines the current index of the loop.
+         */
         public index: number;
         public index: number;
+
         private _done: boolean;
         private _done: boolean;
 
 
         /**
         /**
-         * Constroctor.
+         * Constructor.
          * @param iterations the number of iterations.
          * @param iterations the number of iterations.
          * @param _fn the function to run each iteration
          * @param _fn the function to run each iteration
          * @param _successCallback the callback that will be called upon succesful execution
          * @param _successCallback the callback that will be called upon succesful execution
          * @param offset starting offset.
          * @param offset starting offset.
          */
          */
-        constructor(public iterations: number, private _fn: (asyncLoop: AsyncLoop) => void, private _successCallback: () => void, offset: number = 0) {
+        constructor(
+            /**
+             * Defines the number of iterations for the loop
+             */
+            public iterations: number, 
+            private _fn: (asyncLoop: AsyncLoop) => void, 
+            private _successCallback: () => void, 
+            offset: number = 0) {
+
             this.index = offset - 1;
             this.index = offset - 1;
             this._done = false;
             this._done = false;
         }
         }
@@ -1985,7 +1997,12 @@
         }
         }
 
 
         /**
         /**
-         * Helper function
+         * 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 offset starting offset.
+         * @returns the created async loop object
          */
          */
         public static Run(iterations: number, _fn: (asyncLoop: AsyncLoop) => void, _successCallback: () => void, offset: number = 0): AsyncLoop {
         public static Run(iterations: number, _fn: (asyncLoop: AsyncLoop) => void, _successCallback: () => void, offset: number = 0): AsyncLoop {
             var loop = new AsyncLoop(iterations, _fn, _successCallback, offset);
             var loop = new AsyncLoop(iterations, _fn, _successCallback, offset);
@@ -1995,7 +2012,6 @@
             return loop;
             return loop;
         }
         }
 
 
-
         /**
         /**
          * A for-loop that will run a given number of iterations synchronous and the rest async.
          * A for-loop that will run a given number of iterations synchronous and the rest async.
          * @param iterations total number of iterations
          * @param iterations total number of iterations
@@ -2004,10 +2020,10 @@
          * @param callback a success call back that will be called when iterating stops.
          * @param callback a success call back that will be called when iterating stops.
          * @param breakFunction a break condition (optional)
          * @param breakFunction a break condition (optional)
          * @param timeout timeout settings for the setTimeout function. default - 0.
          * @param timeout timeout settings for the setTimeout function. default - 0.
-         * @constructor
+         * @returns the created async loop object
          */
          */
-        public static SyncAsyncForLoop(iterations: number, syncedIterations: number, fn: (iteration: number) => void, callback: () => void, breakFunction?: () => boolean, timeout: number = 0) {
-            AsyncLoop.Run(Math.ceil(iterations / syncedIterations), (loop: AsyncLoop) => {
+        public static SyncAsyncForLoop(iterations: number, syncedIterations: number, fn: (iteration: number) => void, callback: () => void, breakFunction?: () => boolean, timeout: number = 0): AsyncLoop {
+            return AsyncLoop.Run(Math.ceil(iterations / syncedIterations), (loop: AsyncLoop) => {
                 if (breakFunction && breakFunction()) loop.breakLoop();
                 if (breakFunction && breakFunction()) loop.breakLoop();
                 else {
                 else {
                     setTimeout(() => {
                     setTimeout(() => {