Selaa lähdekoodia

Merge pull request #3565 from BabylonJS/master

Nightly
David Catuhe 7 vuotta sitten
vanhempi
commit
42f70eb047
57 muutettua tiedostoa jossa 34413 lisäystä ja 25579 poistoa
  1. 9 1
      .vscode/settings.json
  2. 1858 702
      Playground/babylon.d.txt
  3. 2 1
      Tools/Gulp/config.json
  4. 18438 15383
      Viewer/dist/viewer.js
  5. 1 1
      Viewer/dist/viewer.min.js
  6. 10 10
      Viewer/package.json
  7. 0 14
      Viewer/src/configuration/configuration.ts
  8. 7 1
      Viewer/src/configuration/types/default.ts
  9. 40 0
      Viewer/src/eventManager.ts
  10. 49 18
      Viewer/src/templateManager.ts
  11. 42 59
      Viewer/src/viewer/defaultViewer.ts
  12. 1 0
      Viewer/src/viewer/viewer.ts
  13. 1846 721
      dist/preview release/babylon.d.ts
  14. 51 51
      dist/preview release/babylon.js
  15. 1170 292
      dist/preview release/babylon.max.js
  16. 52 52
      dist/preview release/babylon.worker.js
  17. 5720 4595
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  18. 55 55
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  19. 1116 290
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  20. 1118 292
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  21. 1172 294
      dist/preview release/es6.js
  22. 3 3
      dist/preview release/gui/babylon.gui.min.js
  23. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  24. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  25. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  26. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  27. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  28. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  29. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  30. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  31. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  32. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  33. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  34. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  35. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  36. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  37. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  38. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  39. 2 2212
      dist/preview release/typedocValidationBaseline.json
  40. 63 63
      dist/preview release/viewer/babylon.viewer.js
  41. 23 1
      src/Cameras/babylon.deviceOrientationCamera.ts
  42. 33 18
      src/Engine/babylon.engine.ts
  43. 8 2
      src/Layer/babylon.highlightlayer.ts
  44. 156 2
      src/Materials/Textures/babylon.internalTexture.ts
  45. 29 0
      src/Materials/Textures/babylon.internalTextureTracker.ts
  46. 51 6
      src/Particles/babylon.boxParticleEmitter.ts
  47. 77 10
      src/Particles/babylon.coneParticleEmitter.ts
  48. 72 7
      src/Particles/babylon.gpuParticleSystem.ts
  49. 18 0
      src/Particles/babylon.iParticleEmitterType.ts
  50. 56 1
      src/Particles/babylon.particle.ts
  51. 375 80
      src/Particles/babylon.particleSystem.ts
  52. 216 112
      src/Particles/babylon.solidParticle.ts
  53. 208 170
      src/Particles/babylon.solidParticleSystem.ts
  54. 73 9
      src/Particles/babylon.sphereParticleEmitter.ts
  55. 6 0
      src/Shaders/glowMapMerge.fragment.fx
  56. 158 22
      src/Tools/babylon.sceneOptimizer.ts
  57. BIN
      tests/validation/ReferenceImages/Flat2009.png

+ 9 - 1
.vscode/settings.json

@@ -11,7 +11,15 @@
         "**/node_modules": true,
         "**/temp": true,
         "**/.temp": true,
-        "**/*.d.ts": true,
+        "src/**/*.d.ts": true,
+        "gui/**/*.d.ts": true,
+        "inspector/**/*.d.ts": true,
+        "loaders/**/*.d.ts": true,
+        "materialsLibrary/**/*.d.ts": true,
+        "postProcessesLibrary/**/*.d.ts": true,
+        "proceduralTexturesLibrary/**/*.d.ts": true,
+        "serielazers/**/*.d.ts": true,
+        "viewer/**/*.d.ts": true,
         "**/*.js.map": true,
         "**/*.js.fx": true,
         "**/*.js": { 

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1858 - 702
Playground/babylon.d.txt


+ 2 - 1
Tools/Gulp/config.json

@@ -16,7 +16,7 @@
         "srcOutputDirectory": "../../src/",
         "currentConfig": "all",
         "typedocJSON": "../../.temp/babylon.typedoc.json",
-        "typedocValidationBaseline": "../../dist/preview release/typedocValidationBaseline.json" 
+        "typedocValidationBaseline": "../../dist/preview release/typedocValidationBaseline.json"
     },
     "buildConfigurations": {
         "all": [
@@ -195,6 +195,7 @@
                 "../../src/babylon.assetContainer.js",
                 "../../src/Mesh/babylon.buffer.js",
                 "../../src/Mesh/babylon.vertexBuffer.js",
+                "../../src/Materials/Textures/babylon.internalTextureTracker.js",
                 "../../src/Materials/Textures/babylon.internalTexture.js",
                 "../../src/Materials/Textures/babylon.baseTexture.js",
                 "../../src/Materials/Textures/babylon.texture.js",

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 18438 - 15383
Viewer/dist/viewer.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
Viewer/dist/viewer.min.js


+ 10 - 10
Viewer/package.json

@@ -23,21 +23,21 @@
     },
     "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
     "devDependencies": {
-        "@types/node": "^8.0.53",
-        "base64-image-loader": "^1.2.0",
-        "html-loader": "^0.5.1",
+        "@types/node": "^8.5.8",
+        "base64-image-loader": "^1.2.1",
+        "html-loader": "^0.5.4",
         "json-loader": "^0.5.7",
         "ts-loader": "^2.3.7",
         "typescript": "^2.6.2",
-        "uglifyjs-webpack-plugin": "^1.1.1",
-        "webpack": "^3.8.1",
-        "webpack-dev-server": "^2.9.5"
+        "uglifyjs-webpack-plugin": "^1.1.6",
+        "webpack": "^3.10.0",
+        "webpack-dev-server": "^2.11.0"
     },
     "dependencies": {
-        "babylonjs": "^3.1.0-beta6",
-        "babylonjs-loaders": "^3.1.0-beta6",
+        "babylonjs": "^3.2.0-alpha4",
+        "babylonjs-loaders": "^3.2.0-alpha4",
         "deepmerge": "^2.0.1",
-        "es6-promise": "^4.1.1",
+        "es6-promise": "^4.2.2",
         "handlebars": "^4.0.11"
     }
-}
+}

+ 0 - 14
Viewer/src/configuration/configuration.ts

@@ -13,20 +13,6 @@ export interface ViewerConfiguration {
         mapper?: string; // json (default), html, yaml, xml, etc'. if not provided, file extension will be used.
     };
 
-    // Deprecated
-    /*// native (!!!) javascript events. Mainly used in the JSON-format.
-    // those events will be triggered by the container element (the <babylon> tag);
-    events?: {
-        load: boolean | string;
-        init: boolean | string;
-        meshselected: boolean | string;
-        pointerdown: boolean | string;
-        pointerup: boolean | string;
-        pointermove: boolean | string;
-        // load: 'onViewerLoaded' // will trigger the event prefix-onViewerLoaded instead of prefix-onLoad (and ONLY this event).
-    } | boolean; //events: true - fire all events*/
-    //eventPrefix?: string;
-
     // names of functions in the window context.
     observers?: {
         onEngineInit?: string;

+ 7 - 1
Viewer/src/configuration/types/default.ts

@@ -17,6 +17,11 @@ export let defaultConfiguration: ViewerConfiguration = {
         },
         viewer: {
             html: require("../../../assets/templates/default/defaultViewer.html"),
+            events: {
+                pointerout: true,
+                pointerdown: true,
+                pointerup: true
+            }
         },
         navBar: {
             html: require("../../../assets/templates/default/navbar.html"),
@@ -34,7 +39,8 @@ export let defaultConfiguration: ViewerConfiguration = {
                 visibilityTimeout: 2000
             },
             events: {
-                pointerdown: { 'fullscreen-button': true/*, '#help-button': true*/ }
+                pointerdown: { 'fullscreen-button': true/*, '#help-button': true*/ },
+                pointerover: true
             }
         },
         overlay: {

+ 40 - 0
Viewer/src/eventManager.ts

@@ -0,0 +1,40 @@
+import { EventCallback, TemplateManager } from "./templateManager";
+
+
+export class EventManager {
+
+    private callbacksContainer: { [key: string]: Array<{ eventType?: string, selector?: string, callback: (eventData: EventCallback) => void }> }
+
+    constructor(private templateManager: TemplateManager) {
+        this.callbacksContainer = {};
+        this.templateManager.onEventTriggered.add(eventData => {
+            this.eventTriggered(eventData);
+        })
+    }
+
+    public registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string) {
+        if (!this.callbacksContainer[templateName]) {
+            this.callbacksContainer[templateName] = [];
+        }
+        this.callbacksContainer[templateName].push({
+            eventType: eventType,
+            callback: callback
+        });
+    }
+
+    public unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string) {
+        let callbackDefs = this.callbacksContainer[templateName] || [];
+        this.callbacksContainer[templateName] = callbackDefs.filter(callbackDef => (!callbackDef.eventType || callbackDef.eventType === eventType) && (!callbackDef.selector || callbackDef.selector === selector));
+    }
+
+    private eventTriggered(data: EventCallback) {
+        let templateName = data.template.name;
+        let eventType = data.event.type;
+        let selector = data.selector;
+
+        let callbackDefs = this.callbacksContainer[templateName] || [];
+        callbackDefs.filter(callbackDef => (!callbackDef.eventType || callbackDef.eventType === eventType) && (!callbackDef.selector || callbackDef.selector === selector)).forEach(callbackDef => {
+            callbackDef.callback(data);
+        });
+    }
+}

+ 49 - 18
Viewer/src/templateManager.ts

@@ -40,6 +40,9 @@ export class TemplateManager {
     public onLoaded: Observable<Template>;
     public onStateChange: Observable<Template>;
     public onAllLoaded: Observable<TemplateManager>;
+    public onEventTriggered: Observable<EventCallback>;
+
+    public eventManager: EventManager;
 
     private templates: { [name: string]: Template };
 
@@ -50,6 +53,9 @@ export class TemplateManager {
         this.onLoaded = new Observable<Template>();
         this.onStateChange = new Observable<Template>();
         this.onAllLoaded = new Observable<TemplateManager>();
+        this.onEventTriggered = new Observable<EventCallback>();
+
+        this.eventManager = new EventManager(this);
     }
 
     public initTemplate(templates: { [key: string]: ITemplateConfiguration }) {
@@ -101,6 +107,8 @@ export class TemplateManager {
     private buildHTMLTree(templates: { [key: string]: ITemplateConfiguration }): Promise<object> {
         let promises = Object.keys(templates).map(name => {
             let template = new Template(name, templates[name]);
+            // make sure the global onEventTriggered is called as well
+            template.onEventTriggered.add(eventData => this.onEventTriggered.notifyObservers(eventData));
             this.templates[name] = template;
             return template.initPromise;
         });
@@ -144,6 +152,8 @@ export class TemplateManager {
 
 
 import * as Handlebars from '../assets/handlebars.min.js';
+import { PromiseObservable } from './util/promiseObservable';
+import { EventManager } from './eventManager';
 // register a new helper. modified https://stackoverflow.com/questions/9838925/is-there-any-method-to-iterate-a-map-with-handlebars-js
 Handlebars.registerHelper('eachInMap', function (map, block) {
     var out = '';
@@ -168,6 +178,11 @@ export class Template {
     public onEventTriggered: Observable<EventCallback>;
 
     public isLoaded: boolean;
+    /**
+     * This is meant to be used to track the show and hide functions.
+     * This is NOT (!!) a flag to check if the element is actually visible to the user.
+     */
+    public isShown: boolean;
 
     public parent: HTMLElement;
 
@@ -183,6 +198,7 @@ export class Template {
         this.onEventTriggered = new Observable<EventCallback>();
 
         this.isLoaded = false;
+        this.isShown = false;
         /*
         if (configuration.id) {
             this.parent.id = configuration.id;
@@ -199,6 +215,7 @@ export class Template {
                 let rawHtml = compiledTemplate(config);
                 this.fragment = document.createRange().createContextualFragment(rawHtml);
                 this.isLoaded = true;
+                this.isShown = true;
                 this.onLoaded.notifyObservers(this);
             }
             return this;
@@ -243,30 +260,44 @@ export class Template {
     }
 
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
-        if (visibilityFunction) {
-            return visibilityFunction(this).then(() => {
-                this.onStateChange.notifyObservers(this);
+        return Promise.resolve().then(() => {
+            if (visibilityFunction) {
+                return visibilityFunction(this);
+            } else {
+                // flex? box? should this be configurable easier than the visibilityFunction?
+                this.parent.style.display = 'flex';
                 return this;
-            });
-        } else {
-            // flex? box? should this be configurable easier than the visibilityFunction?
-            this.parent.style.display = 'flex';
+            }
+        }).then(() => {
+            this.isShown = true;
             this.onStateChange.notifyObservers(this);
-            return Promise.resolve(this);
-        }
+            return this;
+        });
     }
 
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
-        if (visibilityFunction) {
-            return visibilityFunction(this).then(() => {
-                this.onStateChange.notifyObservers(this);
+        return Promise.resolve().then(() => {
+            if (visibilityFunction) {
+                return visibilityFunction(this);
+            } else {
+                // flex? box? should this be configurable easier than the visibilityFunction?
+                this.parent.style.display = 'hide';
                 return this;
-            });
-        } else {
-            this.parent.style.display = 'none';
+            }
+        }).then(() => {
+            this.isShown = false;
             this.onStateChange.notifyObservers(this);
-            return Promise.resolve(this);
-        }
+            return this;
+        });
+    }
+
+    public dispose() {
+        this.onAppended.clear();
+        this.onEventTriggered.clear();
+        this.onInit.clear();
+        this.onLoaded.clear();
+        this.onStateChange.clear();
+        this.isLoaded = false;
     }
 
     // TODO - Should events be removed as well? when are templates disposed?
@@ -286,7 +317,7 @@ export class Template {
                         // strict null checl is working incorrectly, must override:
                         let event = this._configuration.events[eventName] || {};
                         selectorsArray.filter(selector => event[selector]).forEach(selector => {
-                            if (selector.indexOf('#') !== 0) {
+                            if (selector && selector.indexOf('#') !== 0) {
                                 selector = '#' + selector;
                             }
                             let htmlElement = <HTMLElement>this.parent.querySelector(selector);

+ 42 - 59
Viewer/src/viewer/defaultViewer.ts

@@ -1,7 +1,7 @@
 
 
 import { ViewerConfiguration } from './../configuration/configuration';
-import { Template } from './../templateManager';
+import { Template, EventCallback } from './../templateManager';
 import { AbstractViewer } from './viewer';
 import { MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMaterial, Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
 import { CameraBehavior } from '../interfaces';
@@ -27,9 +27,22 @@ export class DefaultViewer extends AbstractViewer {
         this.showLoadingScreen();
 
         // navbar
-        let viewerElement = this.templateManager.getTemplate('viewer');
+        this.initNavbar();
+
+        // close overlay button
+        let closeButton = document.getElementById('close-button');
+        if (closeButton) {
+            closeButton.addEventListener('pointerdown', () => {
+                this.hideOverlayScreen();
+            })
+        }
+
+        return super.onTemplatesLoaded();
+    }
+
+    private initNavbar() {
         let navbar = this.templateManager.getTemplate('navBar');
-        if (viewerElement && navbar) {
+        if (navbar) {
             let navbarHeight = navbar.parent.clientHeight + 'px';
 
             let navbarShown: boolean = true;
@@ -61,64 +74,30 @@ export class DefaultViewer extends AbstractViewer {
                 }
             }
 
-
-
-            viewerElement.parent.addEventListener('pointerout', triggerNavbar.bind(this, false));
-            viewerElement.parent.addEventListener('pointerdown', triggerNavbar.bind(this, true));
-            viewerElement.parent.addEventListener('pointerup', triggerNavbar.bind(this, false));
-            navbar.parent.addEventListener('pointerover', triggerNavbar.bind(this, true))
-            // triggerNavbar(false);
-
-            // events registration
-            this.registerNavbarButtons();
-        }
-
-        // close overlay button
-        let closeButton = document.getElementById('close-button');
-        if (closeButton) {
-            closeButton.addEventListener('pointerdown', () => {
-                this.hideOverlayScreen();
-            })
-        }
-
-        return super.onTemplatesLoaded();
-    }
-
-    private registerNavbarButtons() {
-        let isFullscreen = false;
-
-        let navbar = this.templateManager.getTemplate('navBar');
-        let viewerTemplate = this.templateManager.getTemplate('viewer');
-        if (!navbar || !viewerTemplate) return;
-
-        let viewerElement = viewerTemplate.parent;
-
-
-        navbar.onEventTriggered.add((data) => {
-            switch (data.event.type) {
-                case 'pointerdown':
-                    let event: PointerEvent = <PointerEvent>data.event;
-                    if (event.button === 0) {
-                        switch (data.selector) {
-                            case '#fullscreen-button':
-                                if (!isFullscreen) {
-                                    let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
-                                    requestFullScreen.call(viewerElement);
-                                } else {
-                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || (<any>document).mozCancelFullScreen
-                                    exitFullscreen.call(document);
-                                }
-
-                                isFullscreen = !isFullscreen;
-                                break;
-                            case '#help-button':
-                                this.showOverlayScreen('help');
-                                break;
-                        }
+            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, false), 'pointerout');
+            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, true), 'pointerdown');
+            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, false), 'pointerup');
+            this.templateManager.eventManager.registerCallback('navBar', triggerNavbar.bind(this, true), 'pointerover');
+
+            // other events
+            let viewerTemplate = this.templateManager.getTemplate('viewer');
+            let viewerElement = viewerTemplate && viewerTemplate.parent;
+            // full screen
+            let triggerFullscren = (eventData: EventCallback) => {
+                if (viewerElement) {
+                    let fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement || (<any>document).mozFullScreenElement || (<any>document).msFullscreenElement;
+                    if (!fullscreenElement) {
+                        let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
+                        requestFullScreen.call(viewerElement);
+                    } else {
+                        let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || (<any>document).mozCancelFullScreen
+                        exitFullscreen.call(document);
                     }
-                    break;
+                }
             }
-        });
+
+            this.templateManager.eventManager.registerCallback('navBar', triggerFullscren, 'pointerdown', '#fullscreen-button');
+        }
     }
 
     protected prepareContainerElement() {
@@ -228,6 +207,10 @@ export class DefaultViewer extends AbstractViewer {
             ground.rotation.x = Math.PI / 2; // Face up by default.
             ground.receiveShadows = groundConfig.receiveShadows || false;
 
+            // position the ground correctly
+            let groundPosition = focusMeshes[0].getHierarchyBoundingVectors().min.y;
+            ground.position.y = groundPosition;
+
             // default values
             backgroundMaterial.alpha = 0.9;
             backgroundMaterial.alphaMode = Engine.ALPHA_PREMULTIPLIED_PORTERDUFF;

+ 1 - 0
Viewer/src/viewer/viewer.ts

@@ -145,6 +145,7 @@ export abstract class AbstractViewer {
     }
 
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
+        this.configuration.model = model;
         let modelUrl = (typeof model === 'string') ? model : model.url;
         let parts = modelUrl.split('/');
         let filename = parts.pop();

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1846 - 721
dist/preview release/babylon.d.ts


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 51 - 51
dist/preview release/babylon.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1170 - 292
dist/preview release/babylon.max.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 52 - 52
dist/preview release/babylon.worker.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 5720 - 4595
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 55 - 55
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1116 - 290
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1118 - 292
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1172 - 294
dist/preview release/es6.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2212
dist/preview release/typedocValidationBaseline.json


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 63 - 63
dist/preview release/viewer/babylon.viewer.js


+ 23 - 1
src/Cameras/babylon.deviceOrientationCamera.ts

@@ -1,20 +1,38 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
+    /**
+     * This is a camera specifically designed to react to device orientation events such as a modern mobile device 
+     * being tilted forward or back and left or right.
+     */
     export class DeviceOrientationCamera extends FreeCamera {
 
         private _initialQuaternion: Quaternion;
         private _quaternionCache: Quaternion;
 
+        /**
+         * Creates a new device orientation camera. @see DeviceOrientationCamera
+         * @param name The name of the camera
+         * @param position The starts position camera
+         * @param scene The scene the camera belongs to
+         */
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
             this._quaternionCache = new Quaternion();
             this.inputs.addDeviceOrientation();
         }
 
+        /**
+         * Gets the current instance class name ("DeviceOrientationCamera").
+         * This helps avoiding instanceof at run time.
+         * @returns the class name
+         */
         public getClassName(): string {
             return "DeviceOrientationCamera";
         }
 
+        /**
+         * Checks and applies the current values of the inputs to the camera. (Internal use only)
+         */
         public _checkInputs(): void {
             super._checkInputs();
             this._quaternionCache.copyFrom(this.rotationQuaternion);
@@ -23,7 +41,11 @@ module BABYLON {
             }
         }
 
-        public resetToCurrentRotation(axis: Axis = Axis.Y) {
+        /**
+         * Reset the camera to its default orientation on the specified axis only.
+         * @param axis The axis to reset
+         */
+        public resetToCurrentRotation(axis: Axis = Axis.Y): void {
             //can only work if this camera has a rotation quaternion already.
             if (!this.rotationQuaternion) return;
 

+ 33 - 18
src/Engine/babylon.engine.ts

@@ -539,7 +539,7 @@
         }
 
         public static get Version(): string {
-            return "3.2.0-alpha4";
+            return "3.2.0-alpha5";
         }
 
         // Updatable statics so stick with vars here
@@ -733,7 +733,6 @@
         protected _activeChannel = 0;
         private _currentTextureChannel = -1;
         protected _boundTexturesCache: { [key: string]: Nullable<InternalTexture> } = {};
-        protected _boundTexturesStack = new Array<InternalTexture>();
         protected _currentEffect: Nullable<Effect>;
         protected _currentProgram: Nullable<WebGLProgram>;
         private _compiledEffects: { [key: string]: Effect } = {}
@@ -751,6 +750,8 @@
         private _currentInstanceLocations = new Array<number>();
         private _currentInstanceBuffers = new Array<WebGLBuffer>();
         private _textureUnits: Int32Array;
+        private _firstBoundInternalTextureTracker = new DummyInternalTextureTracker();
+        private _lastBoundInternalTextureTracker = new DummyInternalTextureTracker();
 
         private _workingCanvas: Nullable<HTMLCanvasElement>;
         private _workingContext: Nullable<CanvasRenderingContext2D>;
@@ -1091,6 +1092,8 @@
                 this._currentBufferPointers[i] = new BufferPointer();
             }
 
+            this._linkTrackers(this._firstBoundInternalTextureTracker, this._lastBoundInternalTextureTracker);
+
             // Load WebVR Devices
             if (options.autoEnableWebVR) {
                 this.initWebVR();
@@ -4740,14 +4743,19 @@
         }
 
         private _moveBoundTextureOnTop(internalTexture: InternalTexture): void {
-            let index = this._boundTexturesStack.indexOf(internalTexture);
-
-            if (index > -1 && index !== this._boundTexturesStack.length - 1) {
-                this._boundTexturesStack.splice(index, 1);
-                this._boundTexturesStack.push(internalTexture);
+            if (this._lastBoundInternalTextureTracker.previous === internalTexture) {
+                return;
             }
-        }
 
+            // Remove
+            this._linkTrackers(internalTexture.previous, internalTexture.next);
+
+            // Bind last to it
+            this._linkTrackers(this._lastBoundInternalTextureTracker.previous, internalTexture);
+
+            // Bind to dummy
+            this._linkTrackers(internalTexture, this._lastBoundInternalTextureTracker);
+        }
 
         private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>): number {
             if (!internalTexture) {
@@ -4772,7 +4780,7 @@
 
                         // We need to recycle the oldest bound texture, sorry.
                         this._textureCollisions.addCount(1, false);
-                        return this._removeDesignatedSlot(this._boundTexturesStack[0]);
+                        return this._removeDesignatedSlot(<InternalTexture>this._firstBoundInternalTextureTracker.next);
                     }
                 }
             }
@@ -4780,20 +4788,25 @@
             return channel;
         }
 
+        private _linkTrackers(previous: Nullable<IInternalTextureTracker>, next: Nullable<IInternalTextureTracker>) {
+            previous!.next = next;
+            next!.previous = previous;
+        }
 
         private _removeDesignatedSlot(internalTexture: InternalTexture): number {
             let currentSlot = internalTexture._designatedSlot;
+            if (currentSlot === -1) {
+                return -1;
+            }
 
             internalTexture._designatedSlot = -1;
-            let index = this._boundTexturesStack.indexOf(internalTexture);
 
-            if (index > -1) {
-                this._boundTexturesStack.splice(index, 1);
-                if (currentSlot > -1) {
-                    this._boundTexturesCache[currentSlot] = null;
-                    this._nextFreeTextureSlots.push(currentSlot);
-                }
-            }
+            // Remove from bound list
+            this._linkTrackers(internalTexture.previous, internalTexture.next);
+
+            // Free the slot
+            this._boundTexturesCache[currentSlot] = null;
+            this._nextFreeTextureSlots.push(currentSlot);
 
             return currentSlot;
         }
@@ -4829,7 +4842,9 @@
                         if (slotIndex > -1) {
                             this._nextFreeTextureSlots.splice(slotIndex, 1);
                         }
-                        this._boundTexturesStack.push(texture);
+
+                        this._linkTrackers(this._lastBoundInternalTextureTracker.previous, texture);
+                        this._linkTrackers(texture, this._lastBoundInternalTextureTracker);
                     }
 
                     texture._designatedSlot = this._activeChannel;

+ 8 - 2
src/Layer/babylon.highlightlayer.ts

@@ -6,7 +6,7 @@
     class GlowBlurPostProcess extends PostProcess {
         constructor(name: string, public direction: Vector2, public kernel: number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean) {
             super(name, "glowBlurPostProcess", ["screenSize", "direction", "blurWidth"], null, options, camera, samplingMode, engine, reusable);
-
+            
             this.onApplyObservable.add((effect: Effect) => {
                 effect.setFloat2("screenSize", this.width, this.height);
                 effect.setVector2("direction", this.direction);
@@ -56,6 +56,11 @@
          * The camera attached to the layer.
          */
         camera: Nullable<Camera>;
+
+        /**
+         * Should we display highlight as a solid stroke?
+         */
+        isStroke?: boolean;
     }
 
     /**
@@ -289,7 +294,8 @@
             this._glowMapMergeEffect = engine.createEffect("glowMapMerge",
                 [VertexBuffer.PositionKind],
                 ["offset"],
-                ["textureSampler"], "");
+                ["textureSampler"],
+                this._options.isStroke ? "#define STROKE \n" : undefined);
 
             // Render target
             this.setMainTextureSize();

+ 156 - 2
src/Materials/Textures/babylon.internalTexture.ts

@@ -1,80 +1,219 @@
 module BABYLON {
-    export class InternalTexture {
-
+    /**
+     * Class used to store data associated with WebGL texture data for the engine
+     * This class should not be used directly
+     */
+    export class InternalTexture implements IInternalTextureTracker {
+
+        /**
+         * The source of the texture data is unknown
+         */
         public static DATASOURCE_UNKNOWN = 0;
+        /**
+         * Texture data comes from an URL
+         */
         public static DATASOURCE_URL = 1;
+        /**
+         * Texture data is only used for temporary storage
+         */
         public static DATASOURCE_TEMP = 2;
+        /**
+         * Texture data comes from raw data (ArrayBuffer)
+         */
         public static DATASOURCE_RAW = 3;
+        /**
+         * Texture content is dynamic (video or dynamic texture)
+         */
         public static DATASOURCE_DYNAMIC = 4;
+        /**
+         * Texture content is generated by rendering to it
+         */
         public static DATASOURCE_RENDERTARGET = 5;
+        /**
+         * Texture content is part of a multi render target process
+         */
         public static DATASOURCE_MULTIRENDERTARGET = 6;
+        /**
+         * Texture data comes from a cube data file
+         */
         public static DATASOURCE_CUBE = 7;
+        /**
+         * Texture data comes from a raw cube data
+         */
         public static DATASOURCE_CUBERAW = 8;
+        /**
+         * Texture data come from a prefiltered cube data file
+         */
         public static DATASOURCE_CUBEPREFILTERED = 9;
+        /**
+         * Texture content is raw 3D data
+         */
         public static DATASOURCE_RAW3D = 10;
 
+        /**
+         * Defines if the texture is ready
+         */
         public isReady: boolean;
+        /**
+         * Defines if the texture is a cube texture
+         */
         public isCube: boolean;
+        /**
+         * Defines if the texture contains 3D data
+         */
         public is3D: boolean;
+        /**
+         * Gets the URL used to load this texture
+         */
         public url: string;
+        /**
+         * Gets the sampling mode of the texture
+         */
         public samplingMode: number;
+        /**
+         * Gets a boolean indicating if the texture needs mipmaps generation
+         */
         public generateMipMaps: boolean;
+        /**
+         * Gets the number of samples used by the texture (WebGL2+ only)
+         */
         public samples: number;
+        /**
+         * Gets the type of the texture
+         */
         public type: number;
+        /**
+         * Gets the format of the texture 
+         */
         public format: number;
+        /**
+         * Observable called when the texture is loaded
+         */
         public onLoadedObservable = new Observable<InternalTexture>();
+        /**
+         * Gets the width of the texture
+         */
         public width: number;
+        /**
+         * Gets the height of the texture
+         */
         public height: number;
+        /**
+         * Gets the depth of the texture
+         */
         public depth: number;
+        /**
+         * Gets the initial width of the texture (It could be rescaled if the current system does not support non power of two textures)
+         */
         public baseWidth: number;
+        /**
+         * Gets the initial height of the texture (It could be rescaled if the current system does not support non power of two textures)
+         */
         public baseHeight: number;
+        /**
+         * Gets the initial depth of the texture (It could be rescaled if the current system does not support non power of two textures)
+         */
         public baseDepth: number;
+        /**
+         * Gets a boolean indicating if the texture is inverted on Y axis
+         */
         public invertY: boolean;
 
+        /**
+         * Gets or set the previous tracker in the list
+         */
+        public previous: Nullable<IInternalTextureTracker> = null
+        /**
+         * Gets or set the next tracker in the list
+         */
+        public next: Nullable<IInternalTextureTracker> = null
+
         // Private
+        /** @ignore */
         public _initialSlot = -1;
+        /** @ignore */
         public _designatedSlot = -1;
+        /** @ignore */
         public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
+        /** @ignore */
         public _buffer: Nullable<ArrayBuffer | HTMLImageElement>;
+        /** @ignore */
         public _bufferView: Nullable<ArrayBufferView>;
+        /** @ignore */
         public _bufferViewArray: Nullable<ArrayBufferView[]>;
+        /** @ignore */
         public _size: number;
+        /** @ignore */
         public _extension: string;
+        /** @ignore */
         public _files: Nullable<string[]>;
+        /** @ignore */
         public _workingCanvas: HTMLCanvasElement;
+        /** @ignore */
         public _workingContext: CanvasRenderingContext2D;
+        /** @ignore */
         public _framebuffer: Nullable<WebGLFramebuffer>;
+        /** @ignore */
         public _depthStencilBuffer: Nullable<WebGLRenderbuffer>;
+        /** @ignore */
         public _MSAAFramebuffer: Nullable<WebGLFramebuffer>;
+        /** @ignore */
         public _MSAARenderBuffer: Nullable<WebGLRenderbuffer>;
+        /** @ignore */
         public _attachments: Nullable<number[]>;
+        /** @ignore */
         public _cachedCoordinatesMode: Nullable<number>;
+        /** @ignore */
         public _cachedWrapU: Nullable<number>;
+        /** @ignore */
         public _cachedWrapV: Nullable<number>;
+        /** @ignore */
         public _cachedWrapR: Nullable<number>;
+        /** @ignore */
         public _cachedAnisotropicFilteringLevel: Nullable<number>;
+        /** @ignore */
         public _isDisabled: boolean;
+        /** @ignore */
         public _compression: Nullable<string>;
+        /** @ignore */
         public _generateStencilBuffer: boolean;
+        /** @ignore */
         public _generateDepthBuffer: boolean;
+        /** @ignore */
         public _sphericalPolynomial: Nullable<SphericalPolynomial>;
+        /** @ignore */
         public _lodGenerationScale: number;
+        /** @ignore */
         public _lodGenerationOffset: number;
+
         // The following three fields helps sharing generated fixed LODs for texture filtering
         // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
         // They are at the level of the gl texture to benefit from the cache.
+        /** @ignore */
         public _lodTextureHigh: BaseTexture;
+        /** @ignore */
         public _lodTextureMid: BaseTexture;
+        /** @ignore */
         public _lodTextureLow: BaseTexture;
 
+        /** @ignore */
         public _webGLTexture: Nullable<WebGLTexture>;
+        /** @ignore */
         public _references: number = 1;
         private _engine: Engine;
 
+        /**
+         * Gets the data source type of the texture (can be one of the BABYLON.InternalTexture.DATASOURCE_XXXX)
+         */
         public get dataSource(): number {
             return this._dataSource;
         }
 
+        /**
+         * Creates a new InternalTexture
+         * @param engine defines the engine to use
+         * @param dataSource defines the type of data that will be used
+         */
         constructor(engine: Engine, dataSource: number) {
             this._engine = engine;
             this._dataSource = dataSource;
@@ -82,10 +221,19 @@ module BABYLON {
             this._webGLTexture = engine._createTexture();
         }
 
+        /**
+         * Increments the number of references (ie. the number of {BABYLON.Texture} that point to it)
+         */
         public incrementReferences(): void {
             this._references++;
         }
 
+        /**
+         * Change the size of the texture (not the size of the content)
+         * @param width defines the new width
+         * @param height defines the new height
+         * @param depth defines the new depth (1 by default)
+         */
         public updateSize(width: int, height: int, depth: int = 1): void {
             this.width = width;
             this.height = height;
@@ -98,6 +246,7 @@ module BABYLON {
             this._size = width * height * depth;
         }
 
+        /** @ignore */
         public _rebuild(): void {
             var proxy: InternalTexture;
             this.isReady = false;
@@ -228,6 +377,9 @@ module BABYLON {
             }
         }
 
+        /**
+         * Dispose the current allocated resources
+         */
         public dispose(): void {
             if (!this._webGLTexture) {
                 return;
@@ -237,6 +389,8 @@ module BABYLON {
             if (this._references === 0) {
                 this._engine._releaseTexture(this);
                 this._webGLTexture = null;
+                this.previous = null;
+                this.next = null;
             }
         }
     }

+ 29 - 0
src/Materials/Textures/babylon.internalTextureTracker.ts

@@ -0,0 +1,29 @@
+module BABYLON {
+    /**
+     * Internal interface used to track {BABYLON.InternalTexture} already bound to the GL context
+     */
+    export interface IInternalTextureTracker {
+        /**
+         * Gets or set the previous tracker in the list
+         */
+        previous: Nullable<IInternalTextureTracker>;
+        /**
+         * Gets or set the next tracker in the list
+         */
+        next: Nullable<IInternalTextureTracker>;
+    }
+
+    /**
+     * Internal class used by the engine to get list of {BABYLON.InternalTexture} already bound to the GL context
+     */
+    export class DummyInternalTextureTracker {
+        /**
+         * Gets or set the previous tracker in the list
+         */
+        public previous: Nullable<IInternalTextureTracker> = null;
+        /**
+         * Gets or set the next tracker in the list
+         */
+        public next: Nullable<IInternalTextureTracker> = null;
+    }
+}

+ 51 - 6
src/Particles/babylon.boxParticleEmitter.ts

@@ -1,52 +1,97 @@
 module BABYLON {
+    /**
+     * Particle emitter emitting particles from the inside of a box.
+     * It emits the particles randomly between 2 given directions. 
+     */
     export class BoxParticleEmitter implements IParticleEmitterType {
 
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public get direction1(): Vector3 {
             return this._particleSystem.direction1;
         }
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public set direction1(value: Vector3) {
             this._particleSystem.direction1 = value;
         }
 
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public get direction2(): Vector3 {
             return this._particleSystem.direction2;
         }
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public set direction2(value: Vector3) {
             this._particleSystem.direction2 = value;
         }
 
+        /**
+         * Minimum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public get minEmitBox(): Vector3 {
             return this._particleSystem.minEmitBox;
         }
+        /**
+         * Minimum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public set minEmitBox(value: Vector3) {
             this._particleSystem.minEmitBox = value;
         }
 
+        /**
+         * Maximum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public get maxEmitBox(): Vector3 {
             return this._particleSystem.maxEmitBox;
         }
+        /**
+         * Maximum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public set maxEmitBox(value: Vector3) {
             this._particleSystem.maxEmitBox = value;
         }
         
         // to be updated like the rest of emitters when breaking changes.
         // all property should be come public variables and passed through constructor.
+        /**
+         * Creates a new instance of @see BoxParticleEmitter
+         * @param _particleSystem the particle system associated with the emitter
+         */
         constructor(private _particleSystem: ParticleSystem) {
 
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
-            var randX = ParticleSystem.randomNumber(this.direction1.x, this.direction2.x);
-            var randY = ParticleSystem.randomNumber(this.direction1.y, this.direction2.y);
-            var randZ = ParticleSystem.randomNumber(this.direction1.z, this.direction2.z);
+            var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
+            var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
+            var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
 
             Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
         }
 
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
-            var randX = ParticleSystem.randomNumber(this.minEmitBox.x, this.maxEmitBox.x);
-            var randY = ParticleSystem.randomNumber(this.minEmitBox.y, this.maxEmitBox.y);
-            var randZ = ParticleSystem.randomNumber(this.minEmitBox.z, this.maxEmitBox.z);
+            var randX = Scalar.RandomRange(this.minEmitBox.x, this.maxEmitBox.x);
+            var randY = Scalar.RandomRange(this.minEmitBox.y, this.maxEmitBox.y);
+            var randZ = Scalar.RandomRange(this.minEmitBox.z, this.maxEmitBox.z);
 
             Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }

+ 77 - 10
src/Particles/babylon.coneParticleEmitter.ts

@@ -1,29 +1,96 @@
 module BABYLON {
+    /**
+     * Particle emitter emitting particles from the inside of a cone.
+     * It emits the particles alongside the cone volume from the base to the particle. 
+     * The emission direction might be randomized.
+     */
     export class ConeParticleEmitter implements IParticleEmitterType {
-        constructor(public radius: number, public angle: number) {
+        private _radius: number;
+        private _height: number;
+
+        /**
+         * Gets the radius of the emission cone.
+         */
+        public get radius(): number {
+            return this._radius;
+        }
+
+        /**
+         * Sets the radius of the emission cone.
+         */
+        public set radius(value: number) {
+            this._radius = value;
+            if (this.angle !== 0) {
+                this._height = value / Math.tan(this.angle / 2);
+            }
+            else {
+                this._height = 1;
+            }
+        }
+
+        /**
+         * Creates a new instance of @see ConeParticleEmitter
+         * @param radius the radius of the emission cone
+         * @param angles the cone base angle
+         * @param directionRandomizer defines how much to randomize the particle direction [0-1]
+         */
+        constructor(radius: number, 
+            /**
+             * The radius of the emission cone.
+             */
+            public angle: number, 
+            /**
+             * The cone base angle.
+             */
+            public directionRandomizer = 0) {
+            this.radius = radius;
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
             if (this.angle === 0) {
                 Vector3.TransformNormalFromFloatsToRef(0, emitPower, 0, worldMatrix, directionToUpdate);
             }
             else {
-                var phi = ParticleSystem.randomNumber(0, 2 * Math.PI);
-                var theta = ParticleSystem.randomNumber(0, this.angle);
-                var randX = Math.cos(phi) * Math.sin(theta);
-                var randY = Math.cos(theta);
-                var randZ = Math.sin(phi) * Math.sin(theta);
-                Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+                // measure the direction Vector from the emitter to the particle.
+                var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
+                var randX = Scalar.RandomRange(0, this.directionRandomizer);
+                var randY = Scalar.RandomRange(0, this.directionRandomizer);
+                var randZ = Scalar.RandomRange(0, this.directionRandomizer);
+                direction.x += randX;
+                direction.y += randY;
+                direction.z += randZ;
+                direction.normalize();
+
+                Vector3.TransformNormalFromFloatsToRef(direction.x * emitPower, direction.y * emitPower, direction.z * emitPower, worldMatrix, directionToUpdate);
             }
         }
 
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
-            var s = ParticleSystem.randomNumber(0, Math.PI * 2);
-            var radius = ParticleSystem.randomNumber(0, this.radius);
+            var s = Scalar.RandomRange(0, Math.PI * 2);
+            var h = Scalar.RandomRange(0, 1);
+            // Better distribution in a cone at normal angles.
+            h = 1 - h * h;
+            var radius = Scalar.RandomRange(0, this._radius);
+            radius = radius * h / this._height;
+
             var randX = radius * Math.sin(s);
             var randZ = radius * Math.cos(s);
+            var randY = h;
 
-            Vector3.TransformCoordinatesFromFloatsToRef(randX, 0, randZ, worldMatrix, positionToUpdate);
+            Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }
     }
 }

+ 72 - 7
src/Particles/babylon.gpuParticleSystem.ts

@@ -1,10 +1,34 @@
 module BABYLON {
+    /**
+     * This represents a GPU particle system in Babylon.
+     * This os the fastest particle system in Babylon as it uses the GPU to update the individual particle data.
+     */
     export class GPUParticleSystem implements IDisposable, IParticleSystem {
-        // Members
+        /**
+         * The id of the Particle system.
+         */
         public id: string;
-        public emitter: Nullable<AbstractMesh | Vector3> = null;       
-        public renderingGroupId = 0;        
+
+        /**
+         * The friendluname of the Particle system.
+         */
+        public name: string;
+
+        /**
+         * The emitter represents the Mesh or position we are attaching the particle system to.
+         */
+        public emitter: Nullable<AbstractMesh | Vector3> = null;
+
+        /**
+         * The rendering group used by the Particle system to chose when to render.
+         */
+        public renderingGroupId = 0;
+
+        /**
+         * The layer mask we are rendering the particles through.
+         */
         public layerMask: number = 0x0FFFFFFF; // TODO
+
         private _capacity: number;
         private _renderEffect: Effect;
         private _updateEffect: Effect;
@@ -29,24 +53,41 @@
 
         /**
         * An event triggered when the system is disposed.
-        * @type {BABYLON.Observable}
         */
         public onDisposeObservable = new Observable<GPUParticleSystem>();
 
+        /**
+         * Gets Wether the system has been started.
+         * @returns True if it has been started, otherwise false.
+         */
         public isStarted(): boolean {
             return this._started;
-        }     
+        }
 
+        /**
+         * Starts the particle system and begins to emit.
+         */
         public start(): void {
             this._started = true;
         }
 
+        /**
+         * Stops the particle system.
+         */
         public stop(): void {
             this._started = false;
-        }        
+        }
 
-        constructor(public name: string, capacity: number, scene: Scene) {
+        /**
+         * Instantiates a GPU particle system.
+         * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
+         * @param name The name of the particle system
+         * @param capacity The max number of particles alive at the same time
+         * @param scene The scene the particle system belongs to
+         */
+        constructor(name: string, capacity: number, scene: Scene) {
             this.id = name;
+            this.name = name;
             this._scene = scene || Engine.LastCreatedScene;
             this._capacity = capacity;
             this._engine = this._scene.getEngine();
@@ -72,6 +113,9 @@
             this._updateEffect = new Effect("gpuUpdateParticles", updateEffectOptions, this._scene.getEngine());   
         }
 
+        /**
+         * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
+         */
         public animate(): void {
             // Do nothing
         }
@@ -126,6 +170,10 @@
             this._targetBuffer = this._renderBuffer;
         }
 
+        /**
+         * Renders the particle system in its current state.
+         * @returns the current number of particles.
+         */
         public render(): number {
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
                 return 0;
@@ -178,10 +226,16 @@
             return 0;
         }
 
+        /**
+         * Rebuilds the particle system
+         */
         public rebuild(): void {
             
         }
 
+        /**
+         * Disposes the particle system and free the associated resources.
+         */
         public dispose(): void {
             var index = this._scene.particleSystems.indexOf(this);
             if (index > -1) {
@@ -196,10 +250,21 @@
         }
 
         //TODO: Clone / Parse / serialize
+
+        /**
+         * Clones the particle system.
+         * @param name The name of the cloned object
+         * @param newEmitter The new emitter to use
+         * @returns the cloned particle system
+         */
         public clone(name: string, newEmitter: any): Nullable<GPUParticleSystem> {
             return null;
         }
 
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */
         public serialize(): any {
         }
     }

+ 18 - 0
src/Particles/babylon.iParticleEmitterType.ts

@@ -1,6 +1,24 @@
 module BABYLON {
+    /**
+     * Particle emitter represents a volume emitting particles.
+     * This is the responsibility of the implementation to define the volume shape like cone/sphere/box.
+     */
     export interface IParticleEmitterType {
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void;
+
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void;
     }
 }

+ 56 - 1
src/Particles/babylon.particle.ts

@@ -1,19 +1,66 @@
 module BABYLON {
 
+    /**
+     * A particle represents one of the element emitted by a particle system.
+     * This is mainly define by its coordinates, direction, velocity and age.
+     */
     export class Particle {
+        /**
+         * The world position of the particle in the scene.
+         */
         public position = Vector3.Zero();
+
+        /**
+         * The world direction of the particle in the scene.
+         */
         public direction = Vector3.Zero();
+
+        /**
+         * The color of the particle.
+         */
         public color = new Color4(0, 0, 0, 0);
+
+        /**
+         * The color change of the particle per step.
+         */
         public colorStep = new Color4(0, 0, 0, 0);
+
+        /**
+         * Defines how long will the life of the particle be.
+         */
         public lifeTime = 1.0;
+
+        /**
+         * The current age of the particle.
+         */
         public age = 0;
+
+        /**
+         * The current size of the particle.
+         */
         public size = 0;
+
+        /**
+         * The current angle of the particle.
+         */
         public angle = 0;
+
+        /**
+         * Defines how fast is the angle changing.
+         */
         public angularSpeed = 0;
 
-        private _currentFrameCounter = 0;
+        /**
+         * Defines the cell index used by the particle to be rendered from a sprite.
+         */
         public cellIndex: number = 0;
 
+        private _currentFrameCounter = 0;
+
+        /**
+         * Creates a new instance of @see Particle
+         * @param particleSystem the particle system the particle belongs to
+         */
         constructor(private particleSystem: ParticleSystem) {
             if (!this.particleSystem.isAnimationSheetEnabled) {
                 return;
@@ -29,6 +76,10 @@
             }
         }
 
+        /**
+         * Defines how the sprite cell index is updated for the particle. This is 
+         * defined as a callback.
+         */
         public updateCellIndex: (scaledUpdateSpeed: number) => void;
 
         private updateCellIndexWithSpeedCalculated(scaledUpdateSpeed: number): void {
@@ -63,6 +114,10 @@
             }
         }
 
+        /**
+         * Copy the properties of particle to another one.
+         * @param other the particle to copy the information to.
+         */
         public copyTo(other: Particle) {
             other.position.copyFrom(this.position);
             other.direction.copyFrom(this.direction);

+ 375 - 80
src/Particles/babylon.particleSystem.ts

@@ -1,94 +1,321 @@
 module BABYLON {
+    /**
+     * Interface representing a particle system in Babylon.
+     * This groups the common functionalities that needs to be implemented in order to create a particle system.
+     * A particle system represents a way to manage particles (@see Particle) from their emission to their animation and rendering.
+     */
     export interface IParticleSystem {
+        /**
+         * The id of the Particle system.
+         */
         id: string;
+        /**
+         * The name of the Particle system.
+         */
         name: string;
+        /**
+         * The emitter represents the Mesh or position we are attaching the particle system to.
+         */
         emitter: Nullable<AbstractMesh | Vector3>;
+        /**
+         * The rendering group used by the Particle system to chose when to render.
+         */
         renderingGroupId: number;
+        /**
+         * The layer mask we are rendering the particles through.
+         */
         layerMask: number;
+        /**
+         * Gets if the particle system has been started.
+         * @return true if the system has been started, otherwise false.
+         */
         isStarted(): boolean;
+        /**
+         * Animates the particle system for this frame.
+         */
         animate(): void;
+        /**
+         * Renders the particle system in its current state.
+         * @returns the current number of particles.
+         */
         render(): number;
+        /**
+         * Dispose the particle system and frees its associated resources.
+         */
         dispose(): void;
+        /**
+         * Clones the particle system.
+         * @param name The name of the cloned object
+         * @param newEmitter The new emitter to use
+         * @returns the cloned particle system
+         */
         clone(name: string, newEmitter: any): Nullable<IParticleSystem>;
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */
         serialize(): any;
-
+        /**
+         * Rebuild the particle system
+         */
         rebuild(): void
     }
 
+    /**
+     * This represents a particle system in Babylon.
+     * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
+     * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function.
+     * @example https://doc.babylonjs.com/babylon101/particles
+     */
     export class ParticleSystem implements IDisposable, IAnimatable, IParticleSystem {
-        // Statics
+        /**
+         * Source color is added to the destination color without alpha affecting the result.
+         */
         public static BLENDMODE_ONEONE = 0;
+        /**
+         * Blend current color and particle color using particle’s alpha.
+         */
         public static BLENDMODE_STANDARD = 1;
 
-        // Members
+        /**
+         * List of animations used by the particle system.
+         */
         public animations: Animation[] = [];
 
+        /**
+         * The id of the Particle system.
+         */
         public id: string;
+
+        /**
+         * The friendly name of the Particle system.
+         */
+        public name: string;
+
+        /**
+         * The rendering group used by the Particle system to chose when to render.
+         */
         public renderingGroupId = 0;
+
+        /**
+         * The emitter represents the Mesh or position we are attaching the particle system to.
+         */
         public emitter: Nullable<AbstractMesh | Vector3> = null;
+
+        /**
+         * The density of particles, the rate of particle flow
+         */
         public emitRate = 10;
+
+        /**
+         * If you want to launch only a few particles at once, that can be done, as well.
+         */
         public manualEmitCount = -1;
+
+        /**
+         * The overall motion speed (0.01 is default update speed, faster updates = faster animation)
+         */
         public updateSpeed = 0.01;
+
+        /**
+         * The amount of time the particle system is running (depends of the overall speed above).
+         */
         public targetStopDuration = 0;
+
+        /**
+         * Specifies whether the particle system will be disposed once it reaches the end of the animation.
+         */
         public disposeOnStop = false;
 
+        /**
+         * Minimum power of emitting particles.
+         */
         public minEmitPower = 1;
+        /**
+         * Maximum power of emitting particles.
+         */
         public maxEmitPower = 1;
 
+        /**
+         * Minimum life time of emitting particles.
+         */
         public minLifeTime = 1;
+        /**
+         * Maximum life time of emitting particles.
+         */
         public maxLifeTime = 1;
 
+        /**
+         * Minimum Size of emitting particles.
+         */
         public minSize = 1;
+        /**
+         * Maximum Size of emitting particles.
+         */
         public maxSize = 1;
+
+        /**
+         * Minimum angular speed of emitting particles (Z-axis rotation for each particle).
+         */
         public minAngularSpeed = 0;
+        /**
+         * Maximum angular speed of emitting particles (Z-axis rotation for each particle).
+         */
         public maxAngularSpeed = 0;
 
+        /**
+         * The texture used to render each particle. (this can be a spritesheet)
+         */
         public particleTexture: Nullable<Texture>;
 
+        /**
+         * The layer mask we are rendering the particles through.
+         */
         public layerMask: number = 0x0FFFFFFF;
 
+        /**
+         * This can help using your own shader to render the particle system.
+         * The according effect will be created 
+         */
         public customShader: any = null;
-        public preventAutoStart: boolean = false;
-
-        private _epsilon: number;
-
 
         /**
-        * An event triggered when the system is disposed.
-        * @type {BABYLON.Observable}
-        */
-        public onDisposeObservable = new Observable<ParticleSystem>();
-
-        private _onDisposeObserver: Nullable<Observer<ParticleSystem>>;
-        public set onDispose(callback: () => void) {
-            if (this._onDisposeObserver) {
-                this.onDisposeObservable.remove(this._onDisposeObserver);
-            }
-            this._onDisposeObserver = this.onDisposeObservable.add(callback);
-        }
+         * By default particle system starts as soon as they are created. This prevents the 
+         * automatic start to happen and let you decide when to start emitting particles.
+         */
+        public preventAutoStart: boolean = false;
 
+        /**
+         * This function can be defined to provide custom update for active particles.
+         * This function will be called instead of regular update (age, position, color, etc.).
+         * Do not forget that this function will be called on every frame so try to keep it simple and fast :)
+         */
         public updateFunction: (particles: Particle[]) => void;
+
+        /**
+         * Callback triggered when the particle animation is ending.
+         */
         public onAnimationEnd: Nullable<() => void> = null;
 
+        /**
+         * Blend mode use to render the particle, it can be either ParticleSystem.BLENDMODE_ONEONE or ParticleSystem.BLENDMODE_STANDARD.
+         */
         public blendMode = ParticleSystem.BLENDMODE_ONEONE;
 
+        /**
+         * Forces the particle to write their depth information to the depth buffer. This can help preventing other draw calls
+         * to override the particles.
+         */
         public forceDepthWrite = false;
 
+        /**
+         * You can use gravity if you want to give an orientation to your particles.
+         */
         public gravity = Vector3.Zero();
+
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public direction1 = new Vector3(0, 1.0, 0);
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public direction2 = new Vector3(0, 1.0, 0);
+
+        /**
+         * Minimum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public minEmitBox = new Vector3(-0.5, -0.5, -0.5);
+        /**
+         * Maximum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public maxEmitBox = new Vector3(0.5, 0.5, 0.5);
+
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
         public color1 = new Color4(1.0, 1.0, 1.0, 1.0);
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
         public color2 = new Color4(1.0, 1.0, 1.0, 1.0);
+        /**
+         * Color the particle will have at the end of its lifetime.
+         */
         public colorDead = new Color4(0, 0, 0, 1.0);
+
+        /**
+         * An optional mask to filter some colors out of the texture, or filter a part of the alpha channel.
+         */
         public textureMask = new Color4(1.0, 1.0, 1.0, 1.0);
+
+        /**
+         * The particle emitter type defines the emitter used by the particle system.
+         * It can be for example box, sphere, or cone...
+         */
         public particleEmitterType: IParticleEmitterType;
+
+        /**
+         * This function can be defined to specify initial direction for every new particle.
+         * It by default use the emitterType defined function.
+         */
         public startDirectionFunction: (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle) => void;
+        /**
+         * This function can be defined to specify initial position for every new particle.
+         * It by default use the emitterType defined function.
+         */
         public startPositionFunction: (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle) => void;
 
-        private particles = new Array<Particle>();
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled), defines if the sprite animation should loop between startSpriteCellID and endSpriteCellID or not.
+         */
+        public spriteCellLoop = true;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled) and spriteCellLoop defines the speed of the sprite loop.
+         */
+        public spriteCellChangeSpeed = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled) and spriteCellLoop defines the first sprite cell to display.
+         */
+        public startSpriteCellID = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled) and spriteCellLoop defines the last sprite cell to display.
+         */
+        public endSpriteCellID = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled), defines the sprite cell width to use.
+         */
+        public spriteCellWidth = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled), defines the sprite cell height to use.
+         */
+        public spriteCellHeight = 0;
+
+        /**
+        * An event triggered when the system is disposed.
+        */
+        public onDisposeObservable = new Observable<ParticleSystem>();
 
+        private _onDisposeObserver: Nullable<Observer<ParticleSystem>>;
+        /**
+         * Sets a callback that will be triggered when the system is disposed.
+         */
+        public set onDispose(callback: () => void) {
+            if (this._onDisposeObserver) {
+                this.onDisposeObservable.remove(this._onDisposeObserver);
+            }
+            this._onDisposeObserver = this.onDisposeObservable.add(callback);
+        }
+
+        /**
+         * Gets wether an animation sprite sheet is enabled or not on the particle system.
+         */
+        public get isAnimationSheetEnabled(): Boolean {
+            return this._isAnimationSheetEnabled;
+        }
+
+        private _particles = new Array<Particle>();
+        private _epsilon: number;
         private _capacity: number;
         private _scene: Scene;
         private _stockParticles = new Array<Particle>();
@@ -100,40 +327,38 @@
         private _effect: Effect;
         private _customEffect: Nullable<Effect>;
         private _cachedDefines: string;
-
         private _scaledColorStep = new Color4(0, 0, 0, 0);
         private _colorDiff = new Color4(0, 0, 0, 0);
         private _scaledDirection = Vector3.Zero();
         private _scaledGravity = Vector3.Zero();
         private _currentRenderId = -1;
-
         private _alive: boolean;
         private _started = false;
         private _stopped = false;
         private _actualFrame = 0;
         private _scaledUpdateSpeed: number;
-
-        // sheet animation
-        public startSpriteCellID = 0;
-        public endSpriteCellID = 0;
-        public spriteCellLoop = true;
-        public spriteCellChangeSpeed = 0;
-
-        public spriteCellWidth = 0;
-        public spriteCellHeight = 0;
         private _vertexBufferSize = 11;
+        private _isAnimationSheetEnabled: boolean;
 
-        public get isAnimationSheetEnabled(): Boolean {
-            return this._isAnimationSheetEnabled;
-        }
-        // end of sheet animation
-
-        constructor(public name: string, capacity: number, scene: Scene, customEffect: Nullable<Effect> = null, private _isAnimationSheetEnabled: boolean = false, epsilon: number = 0.01) {
+        /**
+         * Instantiates a particle system.
+         * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
+         * @param name The name of the particle system
+         * @param capacity The max number of particles alive at the same time
+         * @param scene The scene the particle system belongs to
+         * @param customEffect a custom effect used to change the way particles are rendered by default
+         * @param isAnimationSheetEnabled Must be true if using a spritesheet to animate the particles texture
+         * @param epsilon Offset used to render the particles
+         */
+        constructor(name: string, capacity: number, scene: Scene, customEffect: Nullable<Effect> = null, isAnimationSheetEnabled: boolean = false, epsilon: number = 0.01) {
             this.id = name;
+            this.name = name;
+
             this._capacity = capacity;
 
             this._epsilon = epsilon;
-            if (_isAnimationSheetEnabled) {
+            this._isAnimationSheetEnabled = isAnimationSheetEnabled;
+            if (isAnimationSheetEnabled) {
                 this._vertexBufferSize = 12;
             }
 
@@ -214,8 +439,13 @@
             this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
         }
 
+        /**
+         * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
+         * Its lifetime will start back at 0.
+         * @param particle The particle to recycle
+         */
         public recycleParticle(particle: Particle): void {
-            var lastParticle = <Particle>this.particles.pop();
+            var lastParticle = <Particle>this._particles.pop();
 
             if (lastParticle !== particle) {
                 lastParticle.copyTo(particle);
@@ -223,30 +453,49 @@
             }
         }
 
+        /**
+         * Gets the maximum number of particles active at the same time.
+         * @returns The max number of active particles.
+         */
         public getCapacity(): number {
             return this._capacity;
         }
 
+        /**
+         * Gets Wether there are still active particles in the system.
+         * @returns True if it is alive, otherwise false.
+         */
         public isAlive(): boolean {
             return this._alive;
         }
 
+        /**
+         * Gets Wether the system has been started.
+         * @returns True if it has been started, otherwise false.
+         */
         public isStarted(): boolean {
             return this._started;
         }
 
+        /**
+         * Starts the particle system and begins to emit.
+         */
         public start(): void {
             this._started = true;
             this._stopped = false;
             this._actualFrame = 0;
         }
 
+        /**
+         * Stops the particle system.
+         */
         public stop(): void {
             this._stopped = true;
         }
 
-        // animation sheet
-
+        /**
+         * @ignore (for internal use only)
+         */
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {
             var offset = index * this._vertexBufferSize;
             this._vertexData[offset] = particle.position.x;
@@ -262,8 +511,10 @@
             this._vertexData[offset + 10] = offsetY;
         }
 
+        /**
+         * @ignore (for internal use only)
+         */
         public _appendParticleVertexWithAnimation(index: number, particle: Particle, offsetX: number, offsetY: number): void {
-
             if (offsetX === 0)
                 offsetX = this._epsilon;
             else if (offsetX === 1)
@@ -291,9 +542,9 @@
 
         private _update(newParticles: number): void {
             // Update current
-            this._alive = this.particles.length > 0;
+            this._alive = this._particles.length > 0;
 
-            this.updateFunction(this.particles);
+            this.updateFunction(this._particles);
 
             // Add new ones
             var worldMatrix;
@@ -308,7 +559,7 @@
 
             var particle: Particle;
             for (var index = 0; index < newParticles; index++) {
-                if (this.particles.length === this._capacity) {
+                if (this._particles.length === this._capacity) {
                     break;
                 }
 
@@ -320,30 +571,30 @@
                     particle = new Particle(this);
                 }
 
-                this.particles.push(particle);
+                this._particles.push(particle);
 
-                var emitPower = ParticleSystem.randomNumber(this.minEmitPower, this.maxEmitPower);
+                var emitPower = Scalar.RandomRange(this.minEmitPower, this.maxEmitPower);
 
-                if (this.startDirectionFunction) {
-                    this.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                if (this.startPositionFunction) {
+                    this.startPositionFunction(worldMatrix, particle.position, particle);
                 }
                 else {
-                    this.particleEmitterType.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                    this.particleEmitterType.startPositionFunction(worldMatrix, particle.position, particle);
                 }
 
-                if (this.startPositionFunction) {
-                    this.startPositionFunction(worldMatrix, particle.position, particle);
+                if (this.startDirectionFunction) {
+                    this.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
                 }
                 else {
-                    this.particleEmitterType.startPositionFunction(worldMatrix, particle.position, particle);
+                    this.particleEmitterType.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
                 }
 
-                particle.lifeTime = ParticleSystem.randomNumber(this.minLifeTime, this.maxLifeTime);
+                particle.lifeTime = Scalar.RandomRange(this.minLifeTime, this.maxLifeTime);
 
-                particle.size = ParticleSystem.randomNumber(this.minSize, this.maxSize);
-                particle.angularSpeed = ParticleSystem.randomNumber(this.minAngularSpeed, this.maxAngularSpeed);
+                particle.size = Scalar.RandomRange(this.minSize, this.maxSize);
+                particle.angularSpeed = Scalar.RandomRange(this.minAngularSpeed, this.maxAngularSpeed);
 
-                var step = ParticleSystem.randomNumber(0, 1.0);
+                var step = Scalar.RandomRange(0, 1.0);
 
                 Color4.LerpToRef(this.color1, this.color2, step, particle.color);
 
@@ -394,6 +645,9 @@
             return this._effect;
         }
 
+        /**
+         * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
+         */
         public animate(): void {
             if (!this._started)
                 return;
@@ -457,17 +711,17 @@
 
             // Animation sheet
             if (this._isAnimationSheetEnabled) {
-                this.appendParticleVertexes = this.appenedParticleVertexesWithSheet;
+                this._appendParticleVertexes = this._appenedParticleVertexesWithSheet;
             }
             else {
-                this.appendParticleVertexes = this.appenedParticleVertexesNoSheet;
+                this._appendParticleVertexes = this._appenedParticleVertexesNoSheet;
             }
 
             // Update VBO
             var offset = 0;
-            for (var index = 0; index < this.particles.length; index++) {
-                var particle = this.particles[index];
-                this.appendParticleVertexes(offset, particle);
+            for (var index = 0; index < this._particles.length; index++) {
+                var particle = this._particles[index];
+                this._appendParticleVertexes(offset, particle);
                 offset += 4;
             }
 
@@ -476,22 +730,25 @@
             }
         }
 
-        public appendParticleVertexes: Nullable<(offset: number, particle: Particle) => void> = null;
+        private _appendParticleVertexes: Nullable<(offset: number, particle: Particle) => void> = null;
 
-        private appenedParticleVertexesWithSheet(offset: number, particle: Particle) {
+        private _appenedParticleVertexesWithSheet(offset: number, particle: Particle) {
             this._appendParticleVertexWithAnimation(offset++, particle, 0, 0);
             this._appendParticleVertexWithAnimation(offset++, particle, 1, 0);
             this._appendParticleVertexWithAnimation(offset++, particle, 1, 1);
             this._appendParticleVertexWithAnimation(offset++, particle, 0, 1);
         }
 
-        private appenedParticleVertexesNoSheet(offset: number, particle: Particle) {
+        private _appenedParticleVertexesNoSheet(offset: number, particle: Particle) {
             this._appendParticleVertex(offset++, particle, 0, 0);
             this._appendParticleVertex(offset++, particle, 1, 0);
             this._appendParticleVertex(offset++, particle, 1, 1);
             this._appendParticleVertex(offset++, particle, 0, 1);
         }
 
+        /**
+         * Rebuilds the particle system.
+         */
         public rebuild(): void {
             this._createIndexBuffer();
 
@@ -500,11 +757,15 @@
             }
         }
 
+        /**
+         * Renders the particle system in its current state.
+         * @returns the current number of particles.
+         */
         public render(): number {
             var effect = this._getEffect();
 
             // Check
-            if (!this.emitter || !effect.isReady() || !this.particleTexture || !this.particleTexture.isReady() || !this.particles.length)
+            if (!this.emitter || !effect.isReady() || !this.particleTexture || !this.particleTexture.isReady() || !this._particles.length)
                 return 0;
 
             var engine = this._scene.getEngine();
@@ -547,12 +808,15 @@
                 engine.setDepthWrite(true);
             }
 
-            engine.drawElementsType(Material.TriangleFillMode, 0, this.particles.length * 6);
+            engine.drawElementsType(Material.TriangleFillMode, 0, this._particles.length * 6);
             engine.setAlphaMode(Engine.ALPHA_DISABLE);
 
-            return this.particles.length;
+            return this._particles.length;
         }
 
+        /**
+         * Disposes the particle system and free the associated resources.
+         */
         public dispose(): void {
             if (this._vertexBuffer) {
                 this._vertexBuffer.dispose();
@@ -580,18 +844,36 @@
             this.onDisposeObservable.clear();
         }
 
+        /**
+         * Creates a Sphere Emitter for the particle system. (emits along the sphere radius)
+         * @param radius The radius of the sphere to emit from
+         * @returns the emitter
+         */
         public createSphereEmitter(radius = 1): SphereParticleEmitter {
             var particleEmitter = new SphereParticleEmitter(radius);
             this.particleEmitterType = particleEmitter;
             return particleEmitter;
         }
 
+        /**
+         * Creates a Directed Sphere Emitter for the particle system. (emits between direction1 and direction2)
+         * @param radius The radius of the sphere to emit from
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @returns the emitter
+         */
         public createDirectedSphereEmitter(radius = 1, direction1 = new Vector3(0, 1.0, 0), direction2 = new Vector3(0, 1.0, 0)): SphereDirectedParticleEmitter {
             var particleEmitter = new SphereDirectedParticleEmitter(radius, direction1, direction2)
             this.particleEmitterType = particleEmitter;
             return particleEmitter;
         }
 
+        /**
+         * Creates a Cone Emitter for the particle system. (emits from the cone to the particle position)
+         * @param radius The radius of the cone to emit from
+         * @param angle The base angle of the cone
+         * @returns the emitter
+         */
         public createConeEmitter(radius = 1, angle = Math.PI / 4): ConeParticleEmitter {
             var particleEmitter = new ConeParticleEmitter(radius, angle);
             this.particleEmitterType = particleEmitter;
@@ -599,6 +881,14 @@
         }
 
         // this method needs to be changed when breaking changes will be allowed to match the sphere and cone methods and properties direction1,2 and minEmitBox,maxEmitBox to be removed from the system.
+        /**
+         * Creates a Box Emitter for the particle system. (emits between direction1 and direction2 from withing the box defined by minEmitBox and maxEmitBox)
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
+         * @param minEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @param maxEmitBox  Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @returns the emitter
+         */
         public createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3): BoxParticleEmitter {
             var particleEmitter = new BoxParticleEmitter(this);
             this.direction1 = direction1;
@@ -609,18 +899,12 @@
             return particleEmitter;
         }
 
-        public static randomNumber(min: number, max: number): number {
-            if (min === max) {
-                return (min);
-            }
-
-            var random = Math.random();
-
-            return ((random * (max - min)) + min);
-        }
-
-
-        // Clone
+        /**
+         * Clones the particle system.
+         * @param name The name of the cloned object
+         * @param newEmitter The new emitter to use
+         * @returns the cloned particle system
+         */
         public clone(name: string, newEmitter: any): ParticleSystem {
             var custom: Nullable<Effect> = null;
             var program: any = null;
@@ -650,6 +934,10 @@
             return result;
         }
 
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */
         public serialize(): any {
             var serializationObject: any = {};
 
@@ -711,6 +999,13 @@
             return serializationObject;
         }
 
+        /**
+         * Parses a JSON object to create a particle system.
+         * @param parsedParticleSystem The JSON object to parse
+         * @param scene The scene to create the particle system in
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the Parsed particle system
+         */
         public static Parse(parsedParticleSystem: any, scene: Scene, rootUrl: string): ParticleSystem {
             var name = parsedParticleSystem.name;
             var custom: Nullable<Effect> = null;

+ 216 - 112
src/Particles/babylon.solidParticle.ts

@@ -1,119 +1,223 @@
 module BABYLON {
-    
-        export class SolidParticle {
-            public idx: number = 0;                                             // particle global index
-            public color: Nullable<Color4> = new Color4(1.0, 1.0, 1.0, 1.0);    // color
-            public position: Vector3 = Vector3.Zero();                                   // position
-            public rotation: Vector3 = Vector3.Zero();                                   // rotation
-            public rotationQuaternion: Nullable<Quaternion>;                    // quaternion, will overwrite rotation
-            public scaling: Vector3 = Vector3.One();                                     // scaling
-            public uvs: Vector4 = new Vector4(0.0, 0.0, 1.0, 1.0);                       // uvs
-            public velocity: Vector3 = Vector3.Zero();                                   // velocity
-            public pivot: Vector3 = Vector3.Zero();                                      // pivot point in the particle local space
-            public alive: boolean = true;                                                // alive
-            public isVisible: boolean = true;                                            // visibility
-            public _pos: number = 0;                                            // index of this particle in the global "positions" array
-            public _ind: number = 0;                                            // index of this particle in the global "indices" array
-            public _model: ModelShape;                                          // model shape reference
-            public shapeId: number = 0;                                         // model shape id
-            public idxInShape: number = 0;                                      // index of the particle in its shape id
-            public _modelBoundingInfo: BoundingInfo;                            // reference to the shape model BoundingInfo object
-            public _boundingInfo: BoundingInfo;                                 // particle BoundingInfo
-            public _sps: SolidParticleSystem;                                   // reference to the SPS what the particle belongs to
-            public _stillInvisible: boolean = false;                            // still set as invisible in order to skip useless computations
-    
-            /**
-             * Creates a Solid Particle object.
-             * Don't create particles manually, use instead the Solid Particle System internal tools like _addParticle()
-             * `particleIndex` (integer) is the particle index in the Solid Particle System pool. It's also the particle identifier.  
-             * `positionIndex` (integer) is the starting index of the particle vertices in the SPS "positions" array.
-             * `indiceIndex` (integer) is the starting index of the particle indices in the SPS "indices" array.
-             * `model` (ModelShape) is a reference to the model shape on what the particle is designed.  
-             * `shapeId` (integer) is the model shape identifier in the SPS.
-             * `idxInShape` (integer) is the index of the particle in the current model (ex: the 10th box of addShape(box, 30))
-             * `modelBoundingInfo` is the reference to the model BoundingInfo used for intersection computations.
-             */
-            constructor(particleIndex: number, positionIndex: number, indiceIndex: number, model: Nullable<ModelShape>, shapeId: number, idxInShape: number, sps: SolidParticleSystem, modelBoundingInfo: Nullable<BoundingInfo> = null) {
-                this.idx = particleIndex;
-                this._pos = positionIndex;
-                this._ind = indiceIndex;
-                this._model = <ModelShape>model;
-                this.shapeId = shapeId;
-                this.idxInShape = idxInShape;
-                this._sps = sps;
-                if (modelBoundingInfo) {
-                    this._modelBoundingInfo = modelBoundingInfo;
-                    this._boundingInfo = new BoundingInfo(modelBoundingInfo.minimum, modelBoundingInfo.maximum);
-                }
-            }
-    
-            /**
-             * legacy support, changed scale to scaling
-             */
-            public get scale(): Vector3 {
-                return this.scaling;
-            }
-    
-            public set scale(scale: Vector3) {
-                this.scaling = scale;
-            }
-    
-            /**
-             * legacy support, changed quaternion to rotationQuaternion
-             */ 
-            public get quaternion(): Nullable<Quaternion> {
-                return this.rotationQuaternion;
-            }
-    
-            public set quaternion(q: Nullable<Quaternion>) {
-                this.rotationQuaternion = q;
-            }
-    
-            /**
-             * Returns a boolean. True if the particle intersects another particle or another mesh, else false.
-             * The intersection is computed on the particle bounding sphere and Axis Aligned Bounding Box (AABB)
-             * `target` is the object (solid particle or mesh) what the intersection is computed against.
-             */
-            public intersectsMesh(target: Mesh | SolidParticle): boolean {
-                if (!this._boundingInfo || !target._boundingInfo) {
-                    return false;
-                }
-                if (this._sps._bSphereOnly) {
-                    return BoundingSphere.Intersects(this._boundingInfo.boundingSphere, target._boundingInfo.boundingSphere);
-                }
-                return this._boundingInfo.intersects(target._boundingInfo, false);
+    /**
+     * Represents one particle of a solid particle system.
+     * @see SolidParticleSystem
+     */
+    export class SolidParticle {
+        /**
+         * particle global index
+         */
+        public idx: number = 0;
+        /**
+         * The color of the particle
+         */
+        public color: Nullable<Color4> = new Color4(1.0, 1.0, 1.0, 1.0);
+        /**
+         * The world space position of the particle.
+         */
+        public position: Vector3 = Vector3.Zero();
+        /**
+         * The world space rotation of the particle. (Not use if rotationQuaternion is set)
+         */
+        public rotation: Vector3 = Vector3.Zero();
+        /**
+         * The world space rotation quaternion of the particle.
+         */
+        public rotationQuaternion: Nullable<Quaternion>;
+        /**
+         * The scaling of the particle.
+         */
+        public scaling: Vector3 = Vector3.One();
+        /**
+         * The uvs of the particle.
+         */
+        public uvs: Vector4 = new Vector4(0.0, 0.0, 1.0, 1.0);
+        /**
+         * The current speed of the particle.
+         */
+        public velocity: Vector3 = Vector3.Zero();
+        /**
+         * The pivot point in the particle local space.
+         */
+        public pivot: Vector3 = Vector3.Zero();
+        /**
+         * Is the particle active or not ?
+         */
+        public alive: boolean = true;
+        /**
+         * Is the particle visible or not ?
+         */
+        public isVisible: boolean = true;
+        /**
+         * Index of this particle in the global "positions" array (Internal use)
+         */
+        public _pos: number = 0;
+        /**
+         * Index of this particle in the global "indices" array (Internal use)
+         */
+        public _ind: number = 0;
+        /**
+         * ModelShape of this particle (Internal use)
+         */
+        public _model: ModelShape;
+        /**
+         * ModelShape id of this particle
+         */
+        public shapeId: number = 0;
+        /**
+         * Index of the particle in its shape id (Internal use)
+         */
+        public idxInShape: number = 0;
+        /**
+         * Reference to the shape model BoundingInfo object (Internal use)
+         */
+        public _modelBoundingInfo: BoundingInfo;
+        /**
+         * Particle BoundingInfo object (Internal use)
+         */
+        public _boundingInfo: BoundingInfo;
+        /**
+         * Reference to the SPS what the particle belongs to (Internal use)
+         */
+        public _sps: SolidParticleSystem;
+        /**
+         * Still set as invisible in order to skip useless computations (Internal use)
+         */
+        public _stillInvisible: boolean = false;
+
+        /**
+         * Creates a Solid Particle object.
+         * Don't create particles manually, use instead the Solid Particle System internal tools like _addParticle()
+         * @param particleIndex (integer) is the particle index in the Solid Particle System pool. It's also the particle identifier.  
+         * @param positionIndex (integer) is the starting index of the particle vertices in the SPS "positions" array.
+         * @param indiceIndex (integer) is the starting index of the particle indices in the SPS "indices" array.
+         * @param model (ModelShape) is a reference to the model shape on what the particle is designed.  
+         * @param shapeId (integer) is the model shape identifier in the SPS.
+         * @param idxInShape (integer) is the index of the particle in the current model (ex: the 10th box of addShape(box, 30))
+         * @param modelBoundingInfo is the reference to the model BoundingInfo used for intersection computations.
+         */
+        constructor(particleIndex: number, positionIndex: number, indiceIndex: number, model: Nullable<ModelShape>, shapeId: number, idxInShape: number, sps: SolidParticleSystem, modelBoundingInfo: Nullable<BoundingInfo> = null) {
+            this.idx = particleIndex;
+            this._pos = positionIndex;
+            this._ind = indiceIndex;
+            this._model = <ModelShape>model;
+            this.shapeId = shapeId;
+            this.idxInShape = idxInShape;
+            this._sps = sps;
+            if (modelBoundingInfo) {
+                this._modelBoundingInfo = modelBoundingInfo;
+                this._boundingInfo = new BoundingInfo(modelBoundingInfo.minimum, modelBoundingInfo.maximum);
             }
         }
-    
-        export class ModelShape {
-            public shapeID: number;
-            public _shape: Vector3[];                   // flat array of model positions
-            public _shapeUV: number[];                  // flat array of model UVs
-            public _indicesLength: number = 0;          // length of the shape in the model indices array
-            public _positionFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>;
-            public _vertexFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>;
-    
-            /**
-             * Creates a ModelShape object. This is an internal simplified reference to a mesh used as for a model to replicate particles from by the SPS.
-             * SPS internal tool, don't use it manually.  
-             */
-            constructor(id: number, shape: Vector3[], indicesLength: number, shapeUV: number[], 
-                            posFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>, vtxFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>) {
-                this.shapeID = id;
-                this._shape = shape;
-                this._indicesLength = indicesLength;
-                this._shapeUV = shapeUV;
-                this._positionFunction = posFunction;
-                this._vertexFunction = vtxFunction;
+
+        /**
+         * Legacy support, changed scale to scaling
+         */
+        public get scale(): Vector3 {
+            return this.scaling;
+        }
+
+        /**
+         * Legacy support, changed scale to scaling
+         */
+        public set scale(scale: Vector3) {
+            this.scaling = scale;
+        }
+
+        /**
+         * Legacy support, changed quaternion to rotationQuaternion
+         */
+        public get quaternion(): Nullable<Quaternion> {
+            return this.rotationQuaternion;
+        }
+
+        /**
+         * Legacy support, changed quaternion to rotationQuaternion
+         */
+        public set quaternion(q: Nullable<Quaternion>) {
+            this.rotationQuaternion = q;
+        }
+
+        /**
+         * Returns a boolean. True if the particle intersects another particle or another mesh, else false.
+         * The intersection is computed on the particle bounding sphere and Axis Aligned Bounding Box (AABB)
+         * @param target is the object (solid particle or mesh) what the intersection is computed against.
+         * @returns true if it intersects
+         */
+        public intersectsMesh(target: Mesh | SolidParticle): boolean {
+            if (!this._boundingInfo || !target._boundingInfo) {
+                return false;
             }
+            if (this._sps._bSphereOnly) {
+                return BoundingSphere.Intersects(this._boundingInfo.boundingSphere, target._boundingInfo.boundingSphere);
+            }
+            return this._boundingInfo.intersects(target._boundingInfo, false);
         }
-    
-        export class DepthSortedParticle {
-            public ind: number = 0;                      // index of the particle in the "indices" array
-            public indicesLength: number = 0;            // length of the particle shape in the "indices" array
-            public sqDistance: number = 0.0;             // squared distance from the particle to the camera
+    }
+
+    /**
+     * Represents the shape of the model used by one particle of a solid particle system.
+     * SPS internal tool, don't use it manually.
+     * @see SolidParticleSystem
+     */
+    export class ModelShape {
+        /**
+         * The shape id.
+         */
+        public shapeID: number;
+        /**
+         * flat array of model positions (internal use)
+         */
+        public _shape: Vector3[];
+        /**
+         * flat array of model UVs (internal use)
+         */
+        public _shapeUV: number[];
+        /**
+         * length of the shape in the model indices array (internal use)
+         */
+        public _indicesLength: number = 0;
+        /**
+         * Custom position function (internal use)
+         */
+        public _positionFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>;
+        /**
+         * Custom vertex function (internal use)
+         */
+        public _vertexFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>;
+
+        /**
+         * Creates a ModelShape object. This is an internal simplified reference to a mesh used as for a model to replicate particles from by the SPS.
+         * SPS internal tool, don't use it manually.
+         * @ignore
+         */
+        constructor(id: number, shape: Vector3[], indicesLength: number, shapeUV: number[], 
+                        posFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>, vtxFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>) {
+            this.shapeID = id;
+            this._shape = shape;
+            this._indicesLength = indicesLength;
+            this._shapeUV = shapeUV;
+            this._positionFunction = posFunction;
+            this._vertexFunction = vtxFunction;
         }
     }
-    
-    
-    
+
+    /**
+     * Represents a Depth Sorted Particle in the solid particle system.
+     * @see SolidParticleSystem
+     */
+    export class DepthSortedParticle {
+        /**
+         * Index of the particle in the "indices" array
+         */
+        public ind: number = 0;
+        /**
+         * Length of the particle shape in the "indices" array
+         */
+        public indicesLength: number = 0;
+        /**
+         * Squared distance from the particle to the camera
+         */
+        public sqDistance: number = 0.0;
+    }
+}

+ 208 - 170
src/Particles/babylon.solidParticleSystem.ts

@@ -1,60 +1,72 @@
 module BABYLON {
-    
         /**
-        * Full documentation here : http://doc.babylonjs.com/overviews/Solid_Particle_System
-        */
+         * The SPS is a single updatable mesh. The solid particles are simply separate parts or faces fo this big mesh.
+         *As it is just a mesh, the SPS has all the same properties than any other BJS mesh : not more, not less. It can be scaled, rotated, translated, enlighted, textured, moved, etc.
+
+         * The SPS is also a particle system. It provides some methods to manage the particles.
+         * However it is behavior agnostic. This means it has no emitter, no particle physics, no particle recycler. You have to implement your own behavior.
+         * 
+         * Full documentation here : http://doc.babylonjs.com/overviews/Solid_Particle_System
+         */
         export class SolidParticleSystem implements IDisposable {
-            // public members
             /**
-            *  The SPS array of Solid Particle objects. Just access each particle as with any classic array.
-            *  Example : var p = SPS.particles[i];
-            */
+             *  The SPS array of Solid Particle objects. Just access each particle as with any classic array.
+             *  Example : var p = SPS.particles[i];
+             */
             public particles: SolidParticle[] = new Array<SolidParticle>();
             /**
-            * The SPS total number of particles. Read only. Use SPS.counter instead if you need to set your own value.
-            */
+             * The SPS total number of particles. Read only. Use SPS.counter instead if you need to set your own value.
+             */
             public nbParticles: number = 0;
             /**
-            * If the particles must ever face the camera (default false). Useful for planar particles.
-            */
+             * If the particles must ever face the camera (default false). Useful for planar particles.
+             */
             public billboard: boolean = false;
             /**
              * Recompute normals when adding a shape
              */
             public recomputeNormals: boolean = true;
             /**
-            * This a counter ofr your own usage. It's not set by any SPS functions.
-            */
+             * This a counter ofr your own usage. It's not set by any SPS functions.
+             */
             public counter: number = 0;
             /**
-            * The SPS name. This name is also given to the underlying mesh.
-            */
+             * The SPS name. This name is also given to the underlying mesh.
+             */
             public name: string;
             /**
-            * The SPS mesh. It's a standard BJS Mesh, so all the methods from the Mesh class are avalaible.
-            */
+             * The SPS mesh. It's a standard BJS Mesh, so all the methods from the Mesh class are avalaible.
+             */
             public mesh: Mesh;
             /**
-            * This empty object is intended to store some SPS specific or temporary values in order to lower the Garbage Collector activity.
-            * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#garbage-collector-concerns
-            */
+             * This empty object is intended to store some SPS specific or temporary values in order to lower the Garbage Collector activity.
+             * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#garbage-collector-concerns
+             */
             public vars: any = {};
             /**
-            * This array is populated when the SPS is set as 'pickable'.  
-            * Each key of this array is a `faceId` value that you can get from a pickResult object.  
-            * Each element of this array is an object `{idx: int, faceId: int}`.  
-            * `idx` is the picked particle index in the `SPS.particles` array  
-            * `faceId` is the picked face index counted within this particle.  
-            * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#pickable-particles  
-            */
+             * This array is populated when the SPS is set as 'pickable'.  
+             * Each key of this array is a `faceId` value that you can get from a pickResult object.  
+             * Each element of this array is an object `{idx: int, faceId: int}`.  
+             * `idx` is the picked particle index in the `SPS.particles` array  
+             * `faceId` is the picked face index counted within this particle.  
+             * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#pickable-particles  
+             */
             public pickedParticles: { idx: number; faceId: number }[];
             /**
-            * This array is populated when `enableDepthSort` is set to true.  
-            * Each element of this array is an instance of the class DepthSortedParticle.  
-            */
+             * This array is populated when `enableDepthSort` is set to true.  
+             * Each element of this array is an instance of the class DepthSortedParticle.  
+             */
             public depthSortedParticles: DepthSortedParticle[];
-    
-            // private members
+
+            /**
+             * If the particle intersection must be computed only with the bounding sphere (no bounding box computation, so faster). (Internal use only)
+             */
+            public _bSphereOnly: boolean = false;
+            /**
+             * A number to multiply the boundind sphere radius by in order to reduce it for instance. (Internal use only)
+             */
+            public _bSphereRadiusFactor: number = 1.0;
+
             private _scene: Scene;
             private _positions: number[] = new Array<number>();
             private _indices: number[] = new Array<number>();
@@ -121,22 +133,19 @@
                     return (p2.sqDistance - p1.sqDistance);
                 };
             private _needs32Bits: boolean = false;
-            public _bSphereOnly: boolean = false;
-            public _bSphereRadiusFactor: number = 1.0;
-    
-    
+
             /**
-            * Creates a SPS (Solid Particle System) object.
-            * `name` (String) is the SPS name, this will be the underlying mesh name.  
-            * `scene` (Scene) is the scene in which the SPS is added.  
-            * `updatable` (optional boolean, default true) : if the SPS must be updatable or immutable.  
-            * `isPickable` (optional boolean, default false) : if the solid particles must be pickable.  
-            * `enableDepthSort` (optional boolean, default false) : if the solid particles must be sorted in the geometry according to their distance to the camera.  
-            * `particleIntersection` (optional boolean, default false) : if the solid particle intersections must be computed.    
-            * `boundingSphereOnly` (optional boolean, default false) : if the particle intersection must be computed only with the bounding sphere (no bounding box computation, so faster).  
-            * `bSphereRadiusFactor` (optional float, default 1.0) : a number to multiply the boundind sphere radius by in order to reduce it for instance. 
-            *  Example : bSphereRadiusFactor = 1.0 / Math.sqrt(3.0) => the bounding sphere exactly matches a spherical mesh.  
-            */
+             * Creates a SPS (Solid Particle System) object.
+             * @param name (String) is the SPS name, this will be the underlying mesh name.  
+             * @param scene (Scene) is the scene in which the SPS is added.  
+             * @param updatable (optional boolean, default true) : if the SPS must be updatable or immutable.  
+             * @param isPickable (optional boolean, default false) : if the solid particles must be pickable.  
+             * @param enableDepthSort (optional boolean, default false) : if the solid particles must be sorted in the geometry according to their distance to the camera.  
+             * @param particleIntersection (optional boolean, default false) : if the solid particle intersections must be computed.    
+             * @param boundingSphereOnly (optional boolean, default false) : if the particle intersection must be computed only with the bounding sphere (no bounding box computation, so faster).
+             * @param bSphereRadiusFactor (optional float, default 1.0) : a number to multiply the boundind sphere radius by in order to reduce it for instance. 
+             * @example bSphereRadiusFactor = 1.0 / Math.sqrt(3.0) => the bounding sphere exactly matches a spherical mesh.  
+             */
             constructor(name: string, scene: Scene, options?: { updatable?: boolean; isPickable?: boolean; enableDepthSort?: boolean; particleIntersection?: boolean; boundingSphereOnly?: boolean; bSphereRadiusFactor?: number }) {
                 this.name = name;
                 this._scene = scene || Engine.LastCreatedScene;
@@ -158,11 +167,12 @@
                     this.depthSortedParticles = [];
                 }
             }
-    
+
             /**
-            * Builds the SPS underlying mesh. Returns a standard Mesh.
-            * If no model shape was added to the SPS, the returned mesh is just a single triangular plane.
-            */
+             * Builds the SPS underlying mesh. Returns a standard Mesh.
+             * If no model shape was added to the SPS, the returned mesh is just a single triangular plane.
+             * @returns the created mesh
+             */
             public buildMesh(): Mesh {
                 if (this.nbParticles === 0) {
                     var triangle = MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
@@ -214,14 +224,15 @@
             }
     
             /**
-            * Digests the mesh and generates as many solid particles in the system as wanted. Returns the SPS.  
-            * These particles will have the same geometry than the mesh parts and will be positioned at the same localisation than the mesh original places.
-            * Thus the particles generated from `digest()` have their property `position` set yet.  
-            * `mesh` ( Mesh ) is the mesh to be digested  
-            * `facetNb` (optional integer, default 1) is the number of mesh facets per particle, this parameter is overriden by the parameter `number` if any
-            * `delta` (optional integer, default 0) is the random extra number of facets per particle , each particle will have between `facetNb` and `facetNb + delta` facets
-            * `number` (optional positive integer) is the wanted number of particles : each particle is built with `mesh_total_facets / number` facets
-            */
+             * Digests the mesh and generates as many solid particles in the system as wanted. Returns the SPS.  
+             * These particles will have the same geometry than the mesh parts and will be positioned at the same localisation than the mesh original places.
+             * Thus the particles generated from `digest()` have their property `position` set yet.  
+             * @param mesh ( Mesh ) is the mesh to be digested  
+             * @param options {facetNb} (optional integer, default 1) is the number of mesh facets per particle, this parameter is overriden by the parameter `number` if any
+             * {delta} (optional integer, default 0) is the random extra number of facets per particle , each particle will have between `facetNb` and `facetNb + delta` facets
+             * {number} (optional positive integer) is the wanted number of particles : each particle is built with `mesh_total_facets / number` facets
+             * @returns the current SPS
+             */
             public digest(mesh: Mesh, options?: { facetNb?: number; number?: number; delta?: number }): SolidParticleSystem {
                 var size: number = (options && options.facetNb) || 1;
                 var number: number = (options && options.number) || 0;
@@ -487,13 +498,14 @@
             }
     
             /**
-            * Adds some particles to the SPS from the model shape. Returns the shape id.   
-            * Please read the doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#create-an-immutable-sps
-            * `mesh` is any Mesh object that will be used as a model for the solid particles.
-            * `nb` (positive integer) the number of particles to be created from this model
-            * `positionFunction` is an optional javascript function to called for each particle on SPS creation. 
-            * `vertexFunction` is an optional javascript function to called for each vertex of each particle on SPS creation
-            */
+             * Adds some particles to the SPS from the model shape. Returns the shape id.   
+             * Please read the doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#create-an-immutable-sps
+             * @param mesh is any Mesh object that will be used as a model for the solid particles.
+             * @param nb (positive integer) the number of particles to be created from this model
+             * @param options {positionFunction} is an optional javascript function to called for each particle on SPS creation.
+             * {vertexFunction} is an optional javascript function to called for each vertex of each particle on SPS creation
+             * @returns the number of shapes in the system
+             */
             public addShape(mesh: Mesh, nb: number, options?: { positionFunction?: any; vertexFunction?: any }): number {
                 var meshPos = <FloatArray>mesh.getVerticesData(VertexBuffer.PositionKind);
                 var meshInd = <IndicesArray>mesh.getIndices();
@@ -594,11 +606,11 @@
                 particle.scaling.y = 1.0;
                 particle.scaling.z = 1.0;
             }
-    
+
             /**
-            * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.  
-            * Returns the SPS.  
-            */
+             * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.  
+             * @returns the SPS.
+             */
             public rebuildMesh(): SolidParticleSystem {
                 for (var p = 0; p < this.particles.length; p++) {
                     this._rebuildParticle(this.particles[p]);
@@ -606,17 +618,16 @@
                 this.mesh.updateVerticesData(VertexBuffer.PositionKind, this._positions32, false, false);
                 return this;
             }
-    
-    
+
             /**
-            *  Sets all the particles : this method actually really updates the mesh according to the particle positions, rotations, colors, textures, etc.
-            *  This method calls `updateParticle()` for each particle of the SPS.
-            *  For an animated SPS, it is usually called within the render loop.
-            * @param start The particle index in the particle array where to start to compute the particle property values _(default 0)_
-            * @param end The particle index in the particle array where to stop to compute the particle property values _(default nbParticle - 1)_
-            * @param update If the mesh must be finally updated on this call after all the particle computations _(default true)_   
-            * Returns the SPS.  
-            */
+             *  Sets all the particles : this method actually really updates the mesh according to the particle positions, rotations, colors, textures, etc.
+             *  This method calls `updateParticle()` for each particle of the SPS.
+             *  For an animated SPS, it is usually called within the render loop.
+             * @param start The particle index in the particle array where to start to compute the particle property values _(default 0)_
+             * @param end The particle index in the particle array where to stop to compute the particle property values _(default nbParticle - 1)_
+             * @param update If the mesh must be finally updated on this call after all the particle computations _(default true)_   
+             * @returns the SPS.
+             */
             public setParticles(start: number = 0, end: number = this.nbParticles - 1, update: boolean = true): SolidParticleSystem {
                 if (!this._updatable) {
                     return this;
@@ -970,8 +981,7 @@
             }
     
             /**
-            * Disposes the SPS.  
-            * Returns nothing.  
+            * Disposes the SPS.
             */
             public dispose(): void {
                 this.mesh.dispose();
@@ -990,12 +1000,12 @@
                 (<any>this._colors32) = null;
                 (<any>this.pickedParticles) = null;
             }
-    
+
             /**
-            * Visibilty helper : Recomputes the visible size according to the mesh bounding box
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility   
-            * Returns the SPS.  
-            */
+             * Visibilty helper : Recomputes the visible size according to the mesh bounding box
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility   
+             * @returns the SPS.
+             */
             public refreshVisibleSize(): SolidParticleSystem {
                 if (!this._isVisibilityBoxLocked) {
                     this.mesh.refreshBoundingInfo();
@@ -1004,35 +1014,37 @@
             }
     
             /** 
-            * Visibility helper : Sets the size of a visibility box, this sets the underlying mesh bounding box.
-            * @param size the size (float) of the visibility box
-            * note : this doesn't lock the SPS mesh bounding box.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
-            */
+             * Visibility helper : Sets the size of a visibility box, this sets the underlying mesh bounding box.
+             * @param size the size (float) of the visibility box
+             * note : this doesn't lock the SPS mesh bounding box.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public setVisibilityBox(size: number): void {
                 var vis = size / 2;
                 this.mesh._boundingInfo = new BoundingInfo(new Vector3(-vis, -vis, -vis), new Vector3(vis, vis, vis));
             }
-    
-    
-            // getter and setter
+
+            /**
+             * Gets whether the SPS as always visible or not
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public get isAlwaysVisible(): boolean {
                 return this._alwaysVisible;
             }
     
             /**
-            * Sets the SPS as always visible or not
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
-            */
+             * Sets the SPS as always visible or not
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public set isAlwaysVisible(val: boolean) {
                 this._alwaysVisible = val;
                 this.mesh.alwaysSelectAsActiveMesh = val;
             }
-    
+
             /**
-            * Sets the SPS visibility box as locked or not. This enables/disables the underlying mesh bounding box updates.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
-            */
+             * Sets the SPS visibility box as locked or not. This enables/disables the underlying mesh bounding box updates.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public set isVisibilityBoxLocked(val: boolean) {
                 this._isVisibilityBoxLocked = val;
 
@@ -1040,145 +1052,171 @@
 
                 boundingInfo.isLocked = val;
             }
-    
+
+            /**
+             * Gets if the SPS visibility box as locked or not. This enables/disables the underlying mesh bounding box updates.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public get isVisibilityBoxLocked(): boolean {
                 return this._isVisibilityBoxLocked;
             }
-    
-            // Optimizer setters
+
             /**
-            * Tells to `setParticles()` to compute the particle rotations or not.
-            * Default value : true. The SPS is faster when it's set to false.
-            * Note : the particle rotations aren't stored values, so setting `computeParticleRotation` to false will prevents the particle to rotate.
-            */
+             * Tells to `setParticles()` to compute the particle rotations or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle rotations aren't stored values, so setting `computeParticleRotation` to false will prevents the particle to rotate.
+             */
             public set computeParticleRotation(val: boolean) {
                 this._computeParticleRotation = val;
             }
             /**
-            * Tells to `setParticles()` to compute the particle colors or not.
-            * Default value : true. The SPS is faster when it's set to false.
-            * Note : the particle colors are stored values, so setting `computeParticleColor` to false will keep yet the last colors set.
-            */
+             * Tells to `setParticles()` to compute the particle colors or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle colors are stored values, so setting `computeParticleColor` to false will keep yet the last colors set.
+             */
             public set computeParticleColor(val: boolean) {
                 this._computeParticleColor = val;
             }
-            /**
-            * Tells to `setParticles()` to compute the particle textures or not.
-            * Default value : true. The SPS is faster when it's set to false.
-            * Note : the particle textures are stored values, so setting `computeParticleTexture` to false will keep yet the last colors set.
-            */
+            
             public set computeParticleTexture(val: boolean) {
                 this._computeParticleTexture = val;
             }
             /**
-            * Tells to `setParticles()` to call the vertex function for each vertex of each particle, or not.
-            * Default value : false. The SPS is faster when it's set to false.
-            * Note : the particle custom vertex positions aren't stored values.
-            */
+             * Tells to `setParticles()` to call the vertex function for each vertex of each particle, or not.
+             * Default value : false. The SPS is faster when it's set to false.
+             * Note : the particle custom vertex positions aren't stored values.
+             */
             public set computeParticleVertex(val: boolean) {
                 this._computeParticleVertex = val;
             }
             /**
-            * Tells to `setParticles()` to compute or not the mesh bounding box when computing the particle positions.
-            */
+             * Tells to `setParticles()` to compute or not the mesh bounding box when computing the particle positions.
+             */
             public set computeBoundingBox(val: boolean) {
                 this._computeBoundingBox = val;
             }
             /**
-            * Tells to `setParticles()` to sort or not the distance between each particle and the camera.  
-            * Skipped when `enableDepthSort` is set to `false` (default) at construction time.
-            * Default : `true`  
-            */
+             * Tells to `setParticles()` to sort or not the distance between each particle and the camera.  
+             * Skipped when `enableDepthSort` is set to `false` (default) at construction time.
+             * Default : `true`  
+             */
             public set depthSortParticles(val: boolean) {
                 this._depthSortParticles = val;
             }
-            // getters
+
+            /**
+             * Gets if `setParticles()` computes the particle rotations or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle rotations aren't stored values, so setting `computeParticleRotation` to false will prevents the particle to rotate.
+             */
             public get computeParticleRotation(): boolean {
                 return this._computeParticleRotation;
             }
-    
+            /**
+             * Gets if `setParticles()` computes the particle colors or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle colors are stored values, so setting `computeParticleColor` to false will keep yet the last colors set.
+             */
             public get computeParticleColor(): boolean {
                 return this._computeParticleColor;
             }
-    
+            /**
+             * Gets if `setParticles()` computes the particle textures or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle textures are stored values, so setting `computeParticleTexture` to false will keep yet the last colors set.
+             */
             public get computeParticleTexture(): boolean {
                 return this._computeParticleTexture;
             }
-    
+            /**
+             * Gets if `setParticles()` calls the vertex function for each vertex of each particle, or not.
+             * Default value : false. The SPS is faster when it's set to false.
+             * Note : the particle custom vertex positions aren't stored values.
+             */
             public get computeParticleVertex(): boolean {
                 return this._computeParticleVertex;
             }
-    
+            /**
+             * Gets if `setParticles()` computes or not the mesh bounding box when computing the particle positions.
+             */
             public get computeBoundingBox(): boolean {
                 return this._computeBoundingBox;
             }
-    
+            /**
+             * Gets if `setParticles()` sorts or not the distance between each particle and the camera.  
+             * Skipped when `enableDepthSort` is set to `false` (default) at construction time.
+             * Default : `true`  
+             */
             public get depthSortParticles(): boolean {
                 return this._depthSortParticles;
             }
     
             // =======================================================================
             // Particle behavior logic
-            // these following methods may be overwritten by the user to fit his needs
-    
+            // these following methods may be overwritten by the user to fit his needs    
     
             /**
-            * This function does nothing. It may be overwritten to set all the particle first values.
-            * The SPS doesn't call this function, you may have to call it by your own.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
-            */
+             * This function does nothing. It may be overwritten to set all the particle first values.
+             * The SPS doesn't call this function, you may have to call it by your own.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
+             */
             public initParticles(): void {
             }
     
             /**
-            * This function does nothing. It may be overwritten to recycle a particle.
-            * The SPS doesn't call this function, you may have to call it by your own.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
-            */
+             * This function does nothing. It may be overwritten to recycle a particle.
+             * The SPS doesn't call this function, you may have to call it by your own.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
+             * @param particle The particle to recycle
+             * @returns the recycled particle
+             */
             public recycleParticle(particle: SolidParticle): SolidParticle {
                 return particle;
             }
     
             /**
-            * Updates a particle : this function should  be overwritten by the user.
-            * It is called on each particle by `setParticles()`. This is the place to code each particle behavior.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
-            * ex : just set a particle position or velocity and recycle conditions
-            */
+             * Updates a particle : this function should  be overwritten by the user.
+             * It is called on each particle by `setParticles()`. This is the place to code each particle behavior.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
+             * @example : just set a particle position or velocity and recycle conditions
+             * @param particle The particle to update
+             * @returns the updated particle
+             */
             public updateParticle(particle: SolidParticle): SolidParticle {
                 return particle;
             }
     
             /**
-            * Updates a vertex of a particle : it can be overwritten by the user.
-            * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
-            * @param particle the current particle
-            * @param vertex the current index of the current particle
-            * @param pt the index of the current vertex in the particle shape
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#update-each-particle-shape
-            * ex : just set a vertex particle position
-            */
+             * Updates a vertex of a particle : it can be overwritten by the user.
+             * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
+             * @param particle the current particle
+             * @param vertex the current index of the current particle
+             * @param pt the index of the current vertex in the particle shape
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#update-each-particle-shape
+             * @example : just set a vertex particle position
+             * @returns the updated vertex
+             */
             public updateParticleVertex(particle: SolidParticle, vertex: Vector3, pt: number): Vector3 {
                 return vertex;
             }
     
             /**
-            * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
-            * This does nothing and may be overwritten by the user.
-            * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param update the boolean update value actually passed to setParticles()
-            */
+             * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
+             * This does nothing and may be overwritten by the user.
+             * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param update the boolean update value actually passed to setParticles()
+             */
             public beforeUpdateParticles(start?: number, stop?: number, update?: boolean): void {
             }
             /**
-            * This will be called  by `setParticles()` after all the other treatments and just before the actual mesh update.
-            * This will be passed three parameters.
-            * This does nothing and may be overwritten by the user.
-            * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param update the boolean update value actually passed to setParticles()
-            */
+             * This will be called  by `setParticles()` after all the other treatments and just before the actual mesh update.
+             * This will be passed three parameters.
+             * This does nothing and may be overwritten by the user.
+             * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param update the boolean update value actually passed to setParticles()
+             */
             public afterUpdateParticles(start?: number, stop?: number, update?: boolean): void {
             }
         }

+ 73 - 9
src/Particles/babylon.sphereParticleEmitter.ts

@@ -1,18 +1,56 @@
 module BABYLON {
+    /**
+     * Particle emitter emitting particles from the inside of a sphere.
+     * It emits the particles alongside the sphere radius. The emission direction might be randomized.
+     */
     export class SphereParticleEmitter implements IParticleEmitterType {
-        constructor(public radius: number) {
+
+        /**
+         * Creates a new instance of @see SphereParticleEmitter
+         * @param radius the radius of the emission sphere
+         * @param directionRandomizer defines how much to randomize the particle direction [0-1]
+         */
+        constructor(
+            /**
+             * The radius of the emission sphere.
+             */
+            public radius: number, 
+            /**
+             * How much to randomize the particle direction [0-1].
+             */
+            public directionRandomizer = 0) {
 
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
-            // measure the direction Vector from the emitter to the particle.
-            var direction = particle.position.subtract(worldMatrix.getTranslation());
+            var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
+            var randX = Scalar.RandomRange(0, this.directionRandomizer);
+            var randY = Scalar.RandomRange(0, this.directionRandomizer);
+            var randZ = Scalar.RandomRange(0, this.directionRandomizer);
+            direction.x += randX;
+            direction.y += randY;
+            direction.z += randZ;
+            direction.normalize();
+
             Vector3.TransformNormalFromFloatsToRef(direction.x * emitPower, direction.y * emitPower, direction.z * emitPower, worldMatrix, directionToUpdate);
         }
 
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
-            var phi = ParticleSystem.randomNumber(0, 2 * Math.PI);
-            var theta = ParticleSystem.randomNumber(0, Math.PI);
+            var phi = Scalar.RandomRange(0, 2 * Math.PI);
+            var theta = Scalar.RandomRange(0, Math.PI);
             var randX = this.radius * Math.cos(phi) * Math.sin(theta);
             var randY = this.radius * Math.cos(theta);
             var randZ = this.radius * Math.sin(phi) * Math.sin(theta);
@@ -20,15 +58,41 @@ module BABYLON {
         }
     }
 
+    /**
+     * Particle emitter emitting particles from the inside of a sphere.
+     * It emits the particles randomly between two vectors.
+     */
     export class SphereDirectedParticleEmitter extends SphereParticleEmitter {
-        constructor(radius: number, public direction1: Vector3, public direction2: Vector3) {
+
+        /**
+         * Creates a new instance of @see SphereDirectedParticleEmitter
+         * @param radius the radius of the emission sphere
+         * @param direction1 the min limit of the emission direction
+         * @param direction2 the max limit of the emission direction
+         */
+        constructor(radius: number, 
+            /**
+             * The min limit of the emission direction.
+             */
+            public direction1: Vector3, 
+            /**
+             * The max limit of the emission direction.
+             */
+            public direction2: Vector3) {
             super(radius);
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
-            var randX = ParticleSystem.randomNumber(this.direction1.x, this.direction2.x);
-            var randY = ParticleSystem.randomNumber(this.direction1.y, this.direction2.y);
-            var randZ = ParticleSystem.randomNumber(this.direction1.z, this.direction2.z);
+            var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
+            var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
+            var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
             Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
         }
     }

+ 6 - 0
src/Shaders/glowMapMerge.fragment.fx

@@ -10,5 +10,11 @@ void main(void) {
 
 	baseColor.a = abs(offset - baseColor.a);
 
+	#ifdef STROKE
+        float alpha = smoothstep(.0, .1, baseColor.a);
+        baseColor.a = alpha;
+        baseColor.rgb = baseColor.rgb * alpha;
+    #endif
+
 	gl_FragColor = baseColor;
 }

+ 158 - 22
src/Tools/babylon.sceneOptimizer.ts

@@ -6,6 +6,7 @@
     export class SceneOptimization {
         /**
          * Gets a string describing the action executed by the current optimization
+         * @returns description string
          */
         public getDescription(): string {
             return "";
@@ -14,7 +15,7 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
-         * @returnstrue if everything that can be done was applied
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
             return true;
@@ -25,7 +26,11 @@
          * @param priority defines the priority of this optimization (0 by default which means first in the list)
          * @param desc defines the description associated with the optimization
          */
-        constructor(public priority: number = 0) {
+        constructor(
+            /**
+             * Defines the priority of this optimization (0 by default which means first in the list)
+             */
+            public priority: number = 0) {
         }
     }
 
@@ -36,6 +41,7 @@
     export class TextureOptimization extends SceneOptimization {
         /**
          * Gets a string describing the action executed by the current optimization
+         * @returns description string
          */
         public getDescription(): string {
             return "Reducing render target texture size to " + this.maximumSize;
@@ -47,13 +53,26 @@
          * @param maximumSize defines the maximum sized allowed for textures (1024 is the default value). If a texture is bigger, it will be scaled down using a factor defined by the step parameter
          * @param step defines the factor (0.5 by default) used to scale down textures bigger than maximum sized allowed.
          */
-        constructor(public priority: number = 0, public maximumSize: number = 1024, public step = 0.5) {
+        constructor(
+            /**
+             * Defines the priority of this optimization (0 by default which means first in the list)
+             */
+            public priority: number = 0,
+            /**
+             * Defines the maximum sized allowed for textures (1024 is the default value). If a texture is bigger, it will be scaled down using a factor defined by the step parameter
+             */
+            public maximumSize: number = 1024,
+            /**
+             * Defines the factor (0.5 by default) used to scale down textures bigger than maximum sized allowed.
+             */
+            public step = 0.5) {
             super(priority);
         }
 
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
 
@@ -88,6 +107,7 @@
 
         /**
          * Gets a string describing the action executed by the current optimization
+         * @return description string
          */
         public getDescription(): string {
             return "Setting hardware scaling level to " + this._currentScale;
@@ -95,17 +115,30 @@
 
         /**
          * Creates the HardwareScalingOptimization object
-         * @param priority priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param maximumScale 
-         * @param step 
-         */
-        constructor(public priority: number = 0, public maximumScale: number = 2, public step: number = 0.25) {
+         * @param priority defines the priority of this optimization (0 by default which means first in the list)
+         * @param maximumScale defines the maximum scale to use (2 by default)
+         * @param step defines the step to use between two passes (0.5 by default)
+         */
+        constructor(
+            /**
+             * Defines the priority of this optimization (0 by default which means first in the list)
+             */
+            public priority: number = 0,
+            /**
+             * Defines the maximum scale to use (2 by default)
+             */
+            public maximumScale: number = 2,
+            /**
+             * Defines the step to use between two passes (0.5 by default)
+             */
+            public step: number = 0.25) {
             super(priority);
         }
 
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
             if (this._currentScale === -1) {
@@ -130,17 +163,36 @@
     export class ShadowsOptimization extends SceneOptimization {
         /**
          * Gets a string describing the action executed by the current optimization
+         * @return description string
          */
         public getDescription(): string {
-            return "Turning shadows off";
+            return "Turning shadows on/off";
+        }
+
+        /**
+         * Creates the ShadowsOptimization object
+         * @param priority defines the priority of this optimization (0 by default which means first in the list)
+         * @param target defines the value to set the scene.shadowsEnabled property to (false by default)
+         */
+        constructor(
+            /**
+             * Defines the priority of this optimization (0 by default which means first in the list)
+             */
+            public priority: number = 0,
+            /**
+             * Defines the value to set the scene.shadowsEnabled property to (false by default)
+             */
+            public target = false) {
+            super(priority);
         }
 
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
-            scene.shadowsEnabled = false;
+            scene.shadowsEnabled = this.target;
             return true;
         };
     }
@@ -152,17 +204,36 @@
     export class PostProcessesOptimization extends SceneOptimization {
         /**
          * Gets a string describing the action executed by the current optimization
+         * @return description string
          */
         public getDescription(): string {
-            return "Turning post-processes off";
+            return "Turning post-processes on/off";
+        }
+
+        /**
+         * Creates the PostProcessesOptimization object
+         * @param priority defines the priority of this optimization (0 by default which means first in the list)
+         * @param target defines the value to set the scene.postProcessesEnabled property to (false by default)
+         */
+        constructor(
+            /**
+             * Defines the priority of this optimization (0 by default which means first in the list)
+             */
+            public priority: number = 0,
+            /**
+             * Defines the value to set the scene.postProcessesEnabled property to (false by default)
+             */
+            public target = false) {
+            super(priority);
         }
 
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
-            scene.postProcessesEnabled = false;
+            scene.postProcessesEnabled = this.target;
             return true;
         };
     }
@@ -174,17 +245,36 @@
     export class LensFlaresOptimization extends SceneOptimization {
         /**
          * Gets a string describing the action executed by the current optimization
+         * @return description string
          */
         public getDescription(): string {
-            return "Turning lens flares off";
+            return "Turning lens flares on/off";
+        }
+
+        /**
+         * Creates the LensFlaresOptimization object
+         * @param priority defines the priority of this optimization (0 by default which means first in the list)
+         * @param target defines the value to set the scene.lensFlaresEnabled property to (false by default)
+         */
+        constructor(
+            /**
+             * Defines the priority of this optimization (0 by default which means first in the list)
+             */
+            public priority: number = 0,
+            /**
+             * Defines the value to set the scene.lensFlaresEnabled property to (false by default)
+             */
+            public target = false) {
+            super(priority);
         }
 
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
-            scene.lensFlaresEnabled = false;
+            scene.lensFlaresEnabled = this.target;
             return true;
         };
     }
@@ -196,8 +286,6 @@
     export class CustomOptimization extends SceneOptimization {
         /**
          * Callback called to apply the custom optimization.
-         * @param scene defines the scene to apply the optimization to
-         * @returns a boolean defining if all the optimization was applied or if more options are available (for the next turn)
          */
         public onApply: (scene: Scene) => boolean;
 
@@ -208,6 +296,7 @@
 
         /**
          * Gets a string describing the action executed by the current optimization
+         * @returns description string
          */
         public getDescription(): string {
             if (this.onGetDescription) {
@@ -220,6 +309,7 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
             if (this.onApply) {
@@ -236,17 +326,36 @@
     export class ParticlesOptimization extends SceneOptimization {
         /**
          * Gets a string describing the action executed by the current optimization
+         * @return description string
          */
         public getDescription(): string {
-            return "Turning particles off";
+            return "Turning particles on/off";
+        }
+
+        /**
+         * Creates the ParticlesOptimization object
+         * @param priority defines the priority of this optimization (0 by default which means first in the list)
+         * @param target defines the value to set the scene.particlesEnabled property to (false by default)
+         */
+        constructor(
+            /**
+             * Defines the priority of this optimization (0 by default which means first in the list)
+             */
+            public priority: number = 0,
+            /**
+             * Defines the value to set the scene.particlesEnabled property to (false by default)
+             */
+            public target = false) {
+            super(priority);
         }
 
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
-            scene.particlesEnabled = false;
+            scene.particlesEnabled = this.target;
             return true;
         };
     }
@@ -258,6 +367,7 @@
     export class RenderTargetsOptimization extends SceneOptimization {
         /**
          * Gets a string describing the action executed by the current optimization
+         * @return description string
          */
         public getDescription(): string {
             return "Turning render targets off";
@@ -266,6 +376,7 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene): boolean {
             scene.renderTargetsEnabled = false;
@@ -279,7 +390,7 @@
      * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
      */
     export class MergeMeshesOptimization extends SceneOptimization {
-        static _UpdateSelectionTree = false;
+        private static _UpdateSelectionTree = false;
 
         /**
          * Gets or sets a boolean which defines if optimization octree has to be updated
@@ -297,6 +408,7 @@
 
         /**
          * Gets a string describing the action executed by the current optimization
+         * @return description string
          */
         public getDescription(): string {
             return "Merging similar meshes together";
@@ -331,6 +443,8 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param updateSelectionTree defines that the selection octree has to be updated (false by default)
+         * @returns true if everything that can be done was applied
          */
         public apply(scene: Scene, updateSelectionTree?: boolean): boolean {
 
@@ -408,12 +522,21 @@
          * @param targetFrameRate defines the target frame rate to reach (60 by default)
          * @param trackerDuration defines the interval between two checkes (2000ms by default)
          */
-        constructor(public targetFrameRate: number = 60, public trackerDuration: number = 2000) {
+        constructor(
+            /**
+             * Defines the target frame rate to reach (60 by default)
+             */
+            public targetFrameRate: number = 60,
+            /**
+             * Defines the interval between two checkes (2000ms by default)
+             */
+            public trackerDuration: number = 2000) {
         }
 
         /**
          * Add a new optimization
          * @param optimization defines the SceneOptimization to add to the list of active optimizations
+         * @returns the current SceneOptimizerOptions
          */
         public addOptimization(optimization: SceneOptimization): SceneOptimizerOptions {
             this.optimizations.push(optimization);
@@ -425,6 +548,7 @@
          * @param onApply defines the callback called to apply the custom optimization.
          * @param onGetDescription defines the callback called to get the description attached with the optimization.
          * @param priority defines the priority of this optimization (0 by default which means first in the list)
+         * @returns the current SceneOptimizerOptions
          */
         public addCustomOptimization(onApply: (scene: Scene) => boolean, onGetDescription: () => string, priority: number = 0): SceneOptimizerOptions {
             let optimization = new CustomOptimization(priority);
@@ -540,6 +664,7 @@
         private _trackerDuration = 2000;
         private _currentFrameRate = 0;
         private _sceneDisposeObserver: Nullable<Observer<Scene>>;
+        private _improvementMode = false;
 
         /**
          * Defines an observable called when the optimizer reaches the target frame rate
@@ -608,8 +733,9 @@
          * @param scene defines the scene to work on
          * @param options defines the options to use with the SceneOptimizer
          * @param autoGeneratePriorities defines if priorities must be generated and not read from SceneOptimization property (true by default)
+         * @param improvementMode defines if the scene optimizer must run the maximum optimization while staying over a target frame instead of trying to reach the target framerate (false by default)
          */
-        public constructor(scene: Scene, options?: SceneOptimizerOptions, autoGeneratePriorities = true) {
+        public constructor(scene: Scene, options?: SceneOptimizerOptions, autoGeneratePriorities = true, improvementMode = false) {
             if (!options) {
                 this._options = new SceneOptimizerOptions();
             } else {
@@ -631,6 +757,7 @@
                 }
             }
 
+            this._improvementMode = improvementMode;
             this._scene = scene || Engine.LastCreatedScene;
             this._sceneDisposeObserver = this._scene.onDisposeObservable.add(() => {
                 this._sceneDisposeObserver = null;
@@ -645,10 +772,17 @@
             this._isRunning = false;
         }
 
+        /**
+         * Reset the optimizer to initial step (current priority level = 0)
+         */
         public reset() {
             this._currentPriorityLevel = 0;
         }
 
+        /**
+         * Start the optimizer. By default it will try to reach a specific framerate 
+         * but if the optimizer is set with improvementMode === true then it will run all optimiatiation while frame rate is above the target frame rate
+         */
         public start() {
             if (this._isRunning) {
                 return;
@@ -674,7 +808,8 @@
 
             this._currentFrameRate = Math.round(scene.getEngine().getFps());
 
-            if (this._currentFrameRate >= this._targetFrameRate) {
+            if (this._improvementMode && this._currentFrameRate <= this._targetFrameRate ||
+                !this._improvementMode && this._currentFrameRate >= this._targetFrameRate) {
                 this._isRunning = false;
                 this.onSuccessObservable.notifyObservers(this);
                 return;
@@ -733,6 +868,7 @@
          * @param options defines the options to use with the SceneOptimizer
          * @param onSuccess defines a callback to call on success
          * @param onFailure defines a callback to call on failure
+         * @returns the new SceneOptimizer object
          */
         public static OptimizeAsync(scene: Scene, options?: SceneOptimizerOptions, onSuccess?: () => void, onFailure?: () => void): SceneOptimizer {
             let optimizer = new SceneOptimizer(scene, options || SceneOptimizerOptions.ModerateDegradationAllowed(), false);

BIN
tests/validation/ReferenceImages/Flat2009.png