فهرست منبع

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

David 7 سال پیش
والد
کامیت
e82ece3b89
100فایلهای تغییر یافته به همراه84407 افزوده شده و 54761 حذف شده
  1. 15 1
      .travis.yml
  2. 9 1
      .vscode/settings.json
  3. 6403 4014
      Playground/babylon.d.txt
  4. 5 2
      Tools/Gulp/config.json
  5. 15 1
      Tools/Gulp/gulp-validateTypedoc.js
  6. 58 14
      Tools/Gulp/gulpfile.js
  7. 40 17
      Tools/Publisher/index.js
  8. 3 0
      Tools/Publisher/package.json
  9. 4 3
      Viewer/dist/basicExample.html
  10. 5 0
      Viewer/dist/config.json
  11. 18444 15388
      Viewer/dist/viewer.js
  12. 1 1
      Viewer/dist/viewer.min.js
  13. 10 10
      Viewer/package.json
  14. 5 15
      Viewer/src/configuration/configuration.ts
  15. 28 17
      Viewer/src/configuration/loader.ts
  16. 1 2
      Viewer/src/configuration/mappers.ts
  17. 7 1
      Viewer/src/configuration/types/default.ts
  18. 2 1
      Viewer/src/configuration/types/index.ts
  19. 40 0
      Viewer/src/eventManager.ts
  20. 60 23
      Viewer/src/templateManager.ts
  21. 42 59
      Viewer/src/viewer/defaultViewer.ts
  22. 47 10
      Viewer/src/viewer/viewer.ts
  23. 1 1
      Viewer/src/viewer/viewerManager.ts
  24. 251 0
      dist/babylon.glTFInterface.d.ts
  25. 13030 10735
      dist/preview release/babylon.d.ts
  26. 49 49
      dist/preview release/babylon.js
  27. 2555 469
      dist/preview release/babylon.max.js
  28. 19088 0
      dist/preview release/babylon.module.d.ts
  29. 50 50
      dist/preview release/babylon.worker.js
  30. 6332 4042
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  31. 51 51
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  32. 2501 470
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  33. 2503 472
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  34. 2557 471
      dist/preview release/es6.js
  35. 70 1
      dist/preview release/gui/babylon.gui.d.ts
  36. 74 1
      dist/preview release/gui/babylon.gui.js
  37. 2 2
      dist/preview release/gui/babylon.gui.min.js
  38. 70 1
      dist/preview release/gui/babylon.gui.module.d.ts
  39. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  40. 0 3
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  41. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  42. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  43. 0 3
      dist/preview release/loaders/babylon.glTFFileLoader.js
  44. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  45. 0 3
      dist/preview release/loaders/babylonjs.loaders.js
  46. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  47. 2 2
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  48. 1 3
      dist/preview release/loaders/package.json
  49. 1 3
      dist/preview release/materialsLibrary/package.json
  50. 1 3
      dist/preview release/postProcessesLibrary/package.json
  51. 1 3
      dist/preview release/proceduralTexturesLibrary/package.json
  52. 173 42
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  53. 997 559
      dist/preview release/serializers/babylon.glTF2Serializer.js
  54. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  55. 997 559
      dist/preview release/serializers/babylonjs.serializers.js
  56. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  57. 173 42
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  58. 1 3
      dist/preview release/serializers/package.json
  59. 4033 16203
      dist/preview release/typedocValidationBaseline.json
  60. 63 63
      dist/preview release/viewer/babylon.viewer.js
  61. 8 1
      dist/preview release/what's new.md
  62. 11 0
      gui/src/advancedDynamicTexture.ts
  63. 65 3
      gui/src/controls/textBlock.ts
  64. 2 5
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  65. 1 1
      loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts
  66. 1 1
      package.json
  67. 25 10
      serializers/src/glTF/2.0/babylon.glTFData.ts
  68. 516 224
      serializers/src/glTF/2.0/babylon.glTFExporter.ts
  69. 198 0
      serializers/src/glTF/2.0/babylon.glTFMaterial.ts
  70. 45 21
      serializers/src/glTF/2.0/babylon.glTFSerializer.ts
  71. 19 0
      src/Actions/babylon.actionManager.ts
  72. 5 1
      src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.ts
  73. 98 5
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  74. 204 26
      src/Cameras/VR/babylon.webVRCamera.ts
  75. 11 9
      src/Cameras/babylon.camera.ts
  76. 14 1
      src/Cameras/babylon.cameraInputsManager.ts
  77. 25 2
      src/Cameras/babylon.deviceOrientationCamera.ts
  78. 9 1
      src/Cameras/babylon.freeCamera.ts
  79. 15 1
      src/Collisions/babylon.collisionCoordinator.ts
  80. 39 20
      src/Engine/babylon.engine.ts
  81. 8 2
      src/Layer/babylon.highlightlayer.ts
  82. 156 2
      src/Materials/Textures/babylon.internalTexture.ts
  83. 29 0
      src/Materials/Textures/babylon.internalTextureTracker.ts
  84. 212 93
      src/Materials/Textures/babylon.videoTexture.ts
  85. 49 0
      src/Math/babylon.math.ts
  86. 2 0
      src/Mesh/babylon.abstractMesh.ts
  87. 601 35
      src/Mesh/babylon.geometry.ts
  88. 11 3
      src/Mesh/babylon.mesh.ts
  89. 1 0
      src/Mesh/babylon.vertexBuffer.ts
  90. 51 6
      src/Particles/babylon.boxParticleEmitter.ts
  91. 77 10
      src/Particles/babylon.coneParticleEmitter.ts
  92. 72 7
      src/Particles/babylon.gpuParticleSystem.ts
  93. 18 0
      src/Particles/babylon.iParticleEmitterType.ts
  94. 56 1
      src/Particles/babylon.particle.ts
  95. 375 80
      src/Particles/babylon.particleSystem.ts
  96. 216 112
      src/Particles/babylon.solidParticle.ts
  97. 208 170
      src/Particles/babylon.solidParticleSystem.ts
  98. 73 9
      src/Particles/babylon.sphereParticleEmitter.ts
  99. 1 1
      src/Rendering/babylon.boundingBoxRenderer.ts
  100. 0 0
      src/Rendering/babylon.geometryBufferRenderer.ts

+ 15 - 1
.travis.yml

@@ -3,6 +3,13 @@ dist: trusty
 language: node_js
 node_js:
 - '6'
+cache:
+  directories:
+    - Tools/Gulp/node_modules
+    - Playground/node_modules
+    - tests/unit/node_modules
+git:
+  depth: 3
 before_script:
 - travis_retry npm install -g gulp
 - cd ./Tools/Gulp
@@ -10,7 +17,14 @@ before_script:
 - "export DISPLAY=:99.0"
 - "sh -e /etc/init.d/xvfb start"
 - sleep 3 # give xvfb some time to start
-script: gulp
+script: 
+- gulp tests-whatsnew
+- set -e
+- gulp typescript-all
+- gulp typedoc-all
+- gulp tests-unit
+- travis_retry gulp tests-validation-virtualscreen
+- travis_retry gulp tests-validation-browserstack
 notifications:
   slack:
     secure: TBYDAN8Dlkx3dM+Q5ClAZem7agAhQ1oB/fGT665qn7D+j2YfWChvlfXegvXL4LPDmQgbI0UfazcjWId5a0EwmmPkRb+kMJItPiMt5jiIp2WKoZQ+qob6H9tBCRJbbpWM430wiPeKfBfbcZP/XSlpVMWhgU5ogAFDSUKjvHT7IuE=

+ 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": { 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 6403 - 4014
Playground/babylon.d.txt


+ 5 - 2
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": [
@@ -178,6 +178,7 @@
                 "../../src/Tools/babylon.observable.js",
                 "../../src/Tools/babylon.smartArray.js",
                 "../../src/Tools/babylon.tools.js",
+                "../../src/Tools/babylon.promise.js",
                 "../../src/States/babylon.alphaCullingState.js",
                 "../../src/States/babylon.depthCullingState.js",
                 "../../src/States/babylon.stencilState.js",
@@ -196,6 +197,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",
@@ -1469,7 +1471,8 @@
                 "files": [
                     "../../serializers/src/glTF/2.0/babylon.glTFSerializer.ts",
                     "../../serializers/src/glTF/2.0/babylon.glTFExporter.ts",
-                    "../../serializers/src/glTF/2.0/babylon.glTFData.ts"
+                    "../../serializers/src/glTF/2.0/babylon.glTFData.ts",
+                    "../../serializers/src/glTF/2.0/babylon.glTFMaterial.ts"
                 ],
                 "output": "babylon.glTF2Serializer.js"
             }

+ 15 - 1
Tools/Gulp/gulp-validateTypedoc.js

@@ -238,7 +238,15 @@ Validate.prototype.getContents = function () {
  * Validate a TypeDoc JSON file
  */
 Validate.prototype.validateTypedoc = function (json) {
-    var namespaces = json.children[0].children;
+    for (var i = 0; i < json.children.length; i++) {
+        var namespaces = json.children[i].children;
+        this.validateTypedocNamespaces(namespaces);
+    }
+}
+/**
+ * Validate namespaces attach to a declaration file from a TypeDoc JSON file
+ */
+Validate.prototype.validateTypedocNamespaces = function (namespaces) {
     var namespace = null;
 
     var containerNode;
@@ -437,6 +445,12 @@ Validate.prototype.validateComment = function(node) {
         return true;
     }
 
+    // Return true for overwrited properties
+    if (node.overwrites) {
+        return true;
+    }
+    
+
     if (node.comment) {
 
         if (node.comment.text || node.comment.shortText) {

+ 58 - 14
Tools/Gulp/gulpfile.js

@@ -27,13 +27,14 @@ var sass = require("gulp-sass");
 var webpack = require("webpack-stream");
 var typedoc = require("gulp-typedoc");
 var validateTypedoc = require("./gulp-validateTypedoc");
+var request = require('request');
+var fs = require("fs");
+var karmaServer = require('karma').Server;
 
 var config = require("./config.json");
 
 var del = require("del");
 
-var karmaServer = require('karma').Server;
-
 var debug = require("gulp-debug");
 var includeShadersStream;
 var shadersStream;
@@ -252,14 +253,11 @@ gulp.task("typescript-compile", function () {
 
     //If this gulp task is running on travis, file the build!
     if (process.env.TRAVIS) {
-        var error = false;
-        tsResult.on("error", function () {
-            error = true;
-        }).on("end", function () {
-            if (error) {
+        tsResult.once("error", function () {
+            tsResult.once("finish", function () {
                 console.log("Typescript compile failed");
                 process.exit(1);
-            }
+            });
         });
     }
 
@@ -593,14 +591,11 @@ gulp.task("modules-compile", function () {
 
     // If this gulp task is running on travis
     if (process.env.TRAVIS) {
-        var error = false;
-        tsResult.on("error", function () {
-            error = true;
-        }).on("end", function () {
-            if (error) {
+        tsResult.once("error", function () {
+            tsResult.once("finish", function () {
                 console.log("Typescript compile failed");
                 process.exit(1);
-            }
+            });
         });
     }
 
@@ -906,6 +901,13 @@ gulp.task("tests-unit-transpile", function (done) {
 
     var tsResult = gulp.src("../../tests/unit/**/*.ts", { base: "../../" })
         .pipe(tsProject());
+    
+    tsResult.once("error", function () {
+        tsResult.once("finish", function () {
+            console.log("Typescript compile failed");
+            process.exit(1);
+        });
+    });
  
     return tsResult.js.pipe(gulp.dest("../../"));
 });
@@ -938,3 +940,45 @@ gulp.task("tests-unit", ["tests-unit-transpile"], function (done) {
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
 });
+
+gulp.task("tests-whatsnew", function(done) {
+    // Only checks on Travis
+    if (!process.env.TRAVIS) {
+        done();
+        return;
+    }
+
+    // Only checks on Pull Requests
+    if (process.env.TRAVIS_PULL_REQUEST == "false") {
+        done();
+        return;
+    }
+
+    // Do not check deploy
+    if (process.env.TRAVIS_BRANCH == "preview") {
+        done();
+        return;
+    }
+
+    // Compare what's new with the current one in the preview release folder.
+    const https = require("https");
+    const url = "https://rawgit.com/BabylonJS/Babylon.js/master/dist/preview%20release/what's%20new.md";
+    https.get(url, res => {
+        res.setEncoding("utf8");
+        let oldData = "";
+        res.on("data", data => {
+            oldData += data;
+        });
+        res.on("end", () => {
+            fs.readFile("../../dist/preview release/what's new.md", "utf-8", function(err, newData) {
+                if (err || oldData != newData) {
+                    done();
+                    return;
+                }
+                
+                console.error("What's new file did not change.");
+                process.exit(1);
+            });
+        });
+    });
+});

+ 40 - 17
Tools/Publisher/index.js

@@ -46,6 +46,39 @@ let packages = [
     }
 ];
 
+function updateEngineVersion(newVersion) {
+    console.log("updating version in babylon.engine.ts");
+    let engineContent = fs.readFileSync("../../src/Engine/babylon.engine.ts").toString();
+    let replaced = engineContent.replace(/(public static get Version\(\): string {\s*return ")(.*)(";\s*})/g, "$1" + newVersion + "$3");
+    fs.writeFileSync("../../src/Engine/babylon.engine.ts", replaced);
+}
+
+function runGulp() {
+    // run gulp typescript-all
+    let exec = shelljs.exec("gulp typescript-all --gulpfile ../Gulp/gulpfile.js");
+    if (exec.code) {
+        console.log("error during compilation, aborting");
+        process.exit(1);
+    }
+}
+
+function processPackages() {
+    packages.forEach((package) => {
+        if (package.name === "core") {
+            processCore(package, version);
+        } else {
+            let packageJson = require(package.path + 'package.json');
+            packageJson.version = version;
+            if (packageJson.peerDependencies) packageJson.peerDependencies.babylonjs = minimumDependency;
+            fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));
+            console.log('Publishing ' + package.name + " from " + package.path);
+            //publish the respected package
+            shelljs.exec('npm publish \"' + package.path + "\"");
+        }
+
+    });
+}
+
 //check if logged in
 console.log("Using npm user:");
 let loginCheck = shelljs.exec('npm whoami');
@@ -55,21 +88,11 @@ if (loginCheck.code === 0) {
 
     prompt.get(['version'], function (err, result) {
         let version = result.version;
-        packages.forEach((package) => {
-            if (package.name === "core") {
-                processCore(package, version);
-            } else {
-                let packageJson = require(package.path + 'package.json');
-                packageJson.version = version;
-                if (packageJson.peerDependencies) packageJson.peerDependencies.babylonjs = minimumDependency;
-                fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));
-                console.log('Publishing ' + package.name + " from " + package.path);
-                //publish the respected package
-                shelljs.exec('npm publish \"' + package.path + "\"");
-            }
-
-        });
-        console.log("done, please don't forget to commit the changes")
+        updateEngineVersion(version);
+        runGulp();
+        processPackages();
+
+        console.log("done, please tag git with " + version);
     });
 } else {
     console.log('not logged in.');
@@ -143,7 +166,7 @@ function processCore(package, version) {
     });
     console.log("updating package.json");
     packageJson.files = packageFiles;
-    packageJson.main = "babylon.max.js";
+    packageJson.main = "babylon.js";
     packageJson.typings = "babylon.d.ts";
 
     fs.writeFileSync(basePath + '/package/' + 'package.json', JSON.stringify(packageJson, null, 4));
@@ -163,7 +186,7 @@ function processCore(package, version) {
             return file;
         }
     });
-    packageJson.main = "dist/preview release/babylon.max.js";
+    packageJson.main = "dist/preview release/babylon.js";
     packageJson.typings = "dist/preview release/babylon.d.ts";
 
     fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));

+ 3 - 0
Tools/Publisher/package.json

@@ -12,5 +12,8 @@
     "fs-extra": "^5.0.0",
     "prompt": "^1.0.0",
     "shelljs": "^0.7.8"
+  },
+  "devDependencies": {
+    "gulp": "^3.9.1"
   }
 }

+ 4 - 3
Viewer/dist/basicExample.html

@@ -17,8 +17,9 @@
     </head>
 
     <body>
-        <babylon model.title="Damaged Helmet" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
-            model.url="https://www.babylonjs.com/Assets/DamagedHelmet/glTF/DamagedHelmet.gltf" camera.behaviors.auto-rotate="0" templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
+        <babylon configuration="config.json" model.title="Damaged Helmet" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
+            model.url="https://www.babylonjs.com/Assets/DamagedHelmet/glTF/DamagedHelmet.gltf" camera.behaviors.auto-rotate="0"
+            templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
         <script src="viewer.js"></script>
         <script>
             // The following lines are redundant. 
@@ -31,4 +32,4 @@
         </script>
     </body>
 
-</html>
+</html>

+ 5 - 0
Viewer/dist/config.json

@@ -0,0 +1,5 @@
+{
+    "scene": {
+        "debug": false
+    }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 18444 - 15388
Viewer/dist/viewer.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 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"
     }
-}
+}

+ 5 - 15
Viewer/src/configuration/configuration.ts

@@ -9,24 +9,11 @@ export interface ViewerConfiguration {
     pageUrl?: string; // will be used for sharing and other fun stuff. This is the page showing the model (not the model's url!)
 
     configuration?: string | {
-        url: string;
+        url?: string;
+        payload?: any;
         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;
@@ -137,6 +124,9 @@ export interface ViewerConfiguration {
     // engine configuration. optional!
     engine?: {
         antialiasing?: boolean;
+        disableResize?: boolean;
+        engineOptions?: { [key: string]: any };
+        adaptiveQuality?: boolean;
     },
     //templateStructure?: ITemplateStructure,
     templates?: {

+ 28 - 17
Viewer/src/configuration/loader.ts

@@ -6,7 +6,11 @@ import * as deepmerge from '../../assets/deepmerge.min.js';
 
 export class ConfigurationLoader {
 
-    private configurationCache: { (url: string): any };
+    private configurationCache: { [url: string]: any };
+
+    constructor() {
+        this.configurationCache = {};
+    }
 
     public loadConfiguration(initConfig: ViewerConfiguration = {}): Promise<ViewerConfiguration> {
 
@@ -19,20 +23,27 @@ export class ConfigurationLoader {
         if (loadedConfig.configuration) {
 
             let mapperType = "json";
-            let url = loadedConfig.configuration;
-
-            // if configuration is an object
-            if (loadedConfig.configuration.url) {
-                url = loadedConfig.configuration.url;
-                mapperType = loadedConfig.configuration.mapper;
-                if (!mapperType) {
-                    // load mapper type from filename / url
-                    mapperType = loadedConfig.configuration.url.split('.').pop();
+            return Promise.resolve().then(() => {
+                if (typeof loadedConfig.configuration === "string" || loadedConfig.configuration.url) {
+                    // a file to load
+                    let url = loadedConfig.configuration;
+
+                    // if configuration is an object
+                    if (loadedConfig.configuration.url) {
+                        url = loadedConfig.configuration.url;
+                        mapperType = loadedConfig.configuration.mapper;
+                        if (!mapperType) {
+                            // load mapper type from filename / url
+                            mapperType = loadedConfig.configuration.url.split('.').pop();
+                        }
+                    }
+                    return this.loadFile(url);
+                } else {
+                    mapperType = loadedConfig.configuration.mapper || mapperType;
+                    return loadedConfig.configuration.payload || {};
                 }
-            }
-
-            let mapper = mapperManager.getMapper(mapperType);
-            return this.loadFile(url).then((data: any) => {
+            }).then((data: any) => {
+                let mapper = mapperManager.getMapper(mapperType);
                 let parsed = mapper.map(data);
                 return deepmerge(loadedConfig, parsed);
             });
@@ -62,10 +73,10 @@ export class ConfigurationLoader {
                     if (xhr.status === OK) {
                         cacheReference[url] = xhr.responseText;
                         resolve(xhr.responseText); // 'This is the returned text.'
+                    } else {
+                        console.log('Error: ' + xhr.status, url);
+                        reject('Error: ' + xhr.status); // An error occurred during the request.
                     }
-                } else {
-                    console.log('Error: ' + xhr.status, url);
-                    reject('Error: ' + xhr.status); // An error occurred during the request.
                 }
             }
         });

+ 1 - 2
Viewer/src/configuration/mappers.ts

@@ -117,5 +117,4 @@ export class MapperManager {
 
 }
 
-export let mapperManager = new MapperManager();
-export default mapperManager;
+export let mapperManager = new MapperManager();

+ 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: {

+ 2 - 1
Viewer/src/configuration/types/index.ts

@@ -1,7 +1,8 @@
 import { minimalConfiguration } from './minimal';
 import { defaultConfiguration } from './default';
+import { ViewerConfiguration } from '../configuration';
 
-let getConfigurationType = function (type: string) {
+let getConfigurationType = function (type: string): ViewerConfiguration {
     switch (type) {
         case 'default':
             return defaultConfiguration;

+ 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);
+        });
+    }
+}

+ 60 - 23
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 }) {
@@ -83,8 +89,13 @@ export class TemplateManager {
         }
 
         //build the html tree
-        this.buildHTMLTree(templates).then(htmlTree => {
-            internalInit(htmlTree, 'main');
+        return this.buildHTMLTree(templates).then(htmlTree => {
+            if (this.templates['main']) {
+                internalInit(htmlTree, 'main');
+            } else {
+                this.checkLoadedState();
+            }
+            return;
         });
     }
 
@@ -101,6 +112,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;
         });
@@ -115,8 +128,9 @@ export class TemplateManager {
                     buildTree(parentObject[element], element);
                 });
             }
-
-            buildTree(templateStructure, "main");
+            if (this.templates['main']) {
+                buildTree(templateStructure, "main");
+            }
             return templateStructure;
         });
     }
@@ -131,7 +145,7 @@ export class TemplateManager {
     }
 
     private checkLoadedState() {
-        let done = Object.keys(this.templates).every((key) => {
+        let done = Object.keys(this.templates).length === 0 || Object.keys(this.templates).every((key) => {
             return this.templates[key].isLoaded && !!this.templates[key].parent;
         });
 
@@ -144,6 +158,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 +184,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 +204,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 +221,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 +266,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 +323,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;

+ 47 - 10
Viewer/src/viewer/viewer.ts

@@ -20,6 +20,8 @@ export abstract class AbstractViewer {
     public onEngineInitObservable: PromiseObservable<Engine>;
     public onModelLoadedObservable: PromiseObservable<AbstractMesh[]>;
 
+    private canvas: HTMLCanvasElement;
+
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
         // if exists, use the container id. otherwise, generate a random string.
         if (containerElement.id) {
@@ -62,6 +64,10 @@ export abstract class AbstractViewer {
             this.templateManager.initTemplate(templateConfiguration);
             // when done, execute onTemplatesLoaded()
             this.templateManager.onAllLoaded.add(() => {
+                let canvas = this.templateManager.getCanvas();
+                if (canvas) {
+                    this.canvas = canvas;
+                }
                 this.onTemplatesLoaded();
             });
         });
@@ -72,6 +78,31 @@ export abstract class AbstractViewer {
         return this.baseId;
     }
 
+    public isCanvasInDOM(): boolean {
+        return !!this.canvas && !!this.canvas.parentElement;
+    }
+
+    protected resize = (): void => {
+        // Only resize if Canvas is in the DOM
+        if (!this.isCanvasInDOM()) {
+            return;
+        }
+
+        if (this.canvas.clientWidth <= 0 || this.canvas.clientHeight <= 0) {
+            return;
+        }
+
+        this.engine.resize();
+    }
+
+    protected render = (): void => {
+        this.scene && this.scene.render();
+    }
+
+    public dispose() {
+        window.removeEventListener('resize', this.resize);
+    }
+
     protected abstract prepareContainerElement();
 
     /**
@@ -84,7 +115,11 @@ export abstract class AbstractViewer {
      */
     protected onTemplatesLoaded(): Promise<AbstractViewer> {
         return this.initEngine().then(() => {
-            return this.loadModel();
+            if (this.configuration.model) {
+                return this.loadModel();
+            } else {
+                return this.scene;
+            }
         }).then(() => {
             return this;
         });
@@ -104,21 +139,22 @@ export abstract class AbstractViewer {
         }
         let config = this.configuration.engine || {};
         // TDO enable further configuration
-        this.engine = new Engine(canvasElement, !!config.antialiasing);
+        this.engine = new Engine(canvasElement, !!config.antialiasing, config.engineOptions);
 
         // Disable manifest checking
         Database.IDBStorageEnabled = false;
 
-        window.addEventListener('resize', () => {
-            this.engine.resize();
-        });
+        if (!config.disableResize) {
+            window.addEventListener('resize', this.resize);
+        }
 
-        this.engine.runRenderLoop(() => {
-            this.scene && this.scene.render();
-        });
 
-        var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
-        this.engine.setHardwareScalingLevel(scale);
+        this.engine.runRenderLoop(this.render);
+
+        if (this.configuration.engine && this.configuration.engine.adaptiveQuality) {
+            var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
+            this.engine.setHardwareScalingLevel(scale);
+        }
 
         return this.onEngineInitObservable.notifyWithPromise(this.engine).then(() => {
             return this.engine;
@@ -145,6 +181,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();

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

@@ -3,7 +3,7 @@
 import { Observable } from 'babylonjs';
 import { AbstractViewer } from './viewer';
 
-class ViewerManager {
+export class ViewerManager {
 
     private viewers: { [key: string]: AbstractViewer };
 

+ 251 - 0
dist/babylon.glTFInterface.d.ts

@@ -0,0 +1,251 @@
+declare module BABYLON.GLTF2 {
+    /**
+     * Specifies if the attribute is a scalar, vector, or matrix.
+     */
+    const enum AccessorType {
+        SCALAR = "SCALAR",
+        VEC2 = "VEC2",
+        VEC3 = "VEC3",
+        VEC4 = "VEC4",
+        MAT2 = "MAT2",
+        MAT3 = "MAT3",
+        MAT4 = "MAT4",
+    }
+    const enum MaterialAlphaMode {
+        OPAQUE = "OPAQUE",
+        MASK = "MASK",
+        BLEND = "BLEND",
+    }
+    const enum AnimationChannelTargetPath {
+        TRANSLATION = "translation",
+        ROTATION = "rotation",
+        SCALE = "scale",
+        WEIGHTS = "weights",
+    }
+    const enum CameraType {
+        PERSPECTIVE = "perspective",
+        ORTHOGRAPHIC = "orthographic",
+    }
+    const enum AccessorComponentType {
+        BYTE = 5120,
+        UNSIGNED_BYTE = 5121,
+        SHORT = 5122,
+        UNSIGNED_SHORT = 5123,
+        UNSIGNED_INT = 5125,
+        FLOAT = 5126,
+    }
+    const enum AnimationInterpolation {
+        LINEAR = "LINEAR",
+        STEP = "STEP",
+        CUBICSPLINE = "CUBICSPLINE",
+    }
+    const enum MeshPrimitiveMode {
+        POINTS = 0,
+        LINES = 1,
+        LINE_LOOP = 2,
+        LINE_STRIP = 3,
+        TRIANGLES = 4,
+        TRIANGLE_STRIP = 5,
+        TRIANGLE_FAN = 6,
+    }
+    const enum ImageMimeType {
+        JPEG = "image/jpeg",
+        PNG = "image/png",
+    }
+    const enum TextureMagFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+    }
+    const enum TextureMinFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+        NEAREST_MIPMAP_NEAREST = 9984,
+        LINEAR_MIPMAP_NEAREST = 9985,
+        NEAREST_MIPMAP_LINEAR = 9986,
+        LINEAR_MIPMAP_LINEAR = 9987,
+    }
+    const enum TextureWrapMode {
+        CLAMP_TO_EDGE = 33071,
+        MIRRORED_REPEAT = 33648,
+        REPEAT = 10497,
+    }
+    interface IProperty {
+        extensions?: {
+            [key: string]: any;
+        };
+        extras?: any;
+    }
+    interface IChildRootProperty extends IProperty {
+        name?: string;
+    }
+    interface IAccessorSparseIndices extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+    }
+    interface IAccessorSparseValues extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+    }
+    interface IAccessorSparse extends IProperty {
+        count: number;
+        indices: IAccessorSparseIndices;
+        values: IAccessorSparseValues;
+    }
+    interface IAccessor extends IChildRootProperty {
+        bufferView?: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+        normalized?: boolean;
+        count: number;
+        type: AccessorType;
+        max?: number[];
+        min?: number[];
+        sparse?: IAccessorSparse;
+    }
+    interface IAnimationChannel extends IProperty {
+        sampler: number;
+        target: IAnimationChannelTarget;
+    }
+    interface IAnimationChannelTarget extends IProperty {
+        node: number;
+        path: AnimationChannelTargetPath;
+    }
+    interface IAnimationSampler extends IProperty {
+        input: number;
+        interpolation?: AnimationInterpolation;
+        output: number;
+    }
+    interface IAnimation extends IChildRootProperty {
+        channels: IAnimationChannel[];
+        samplers: IAnimationSampler[];
+    }
+    interface IAsset extends IChildRootProperty {
+        copyright?: string;
+        generator?: string;
+        version: string;
+        minVersion?: string;
+    }
+    interface IBuffer extends IChildRootProperty {
+        uri?: string;
+        byteLength: number;
+    }
+    interface IBufferView extends IChildRootProperty {
+        buffer: number;
+        byteOffset?: number;
+        byteLength: number;
+        byteStride?: number;
+    }
+    interface ICameraOrthographic extends IProperty {
+        xmag: number;
+        ymag: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICameraPerspective extends IProperty {
+        aspectRatio: number;
+        yfov: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICamera extends IChildRootProperty {
+        orthographic?: ICameraOrthographic;
+        perspective?: ICameraPerspective;
+        type: CameraType;
+    }
+    interface IImage extends IChildRootProperty {
+        uri?: string;
+        mimeType?: ImageMimeType;
+        bufferView?: number;
+    }
+    interface IMaterialNormalTextureInfo extends ITextureInfo {
+        scale?: number;
+    }
+    interface IMaterialOcclusionTextureInfo extends ITextureInfo {
+        strength?: number;
+    }
+    interface IMaterialPbrMetallicRoughness {
+        baseColorFactor?: number[];
+        baseColorTexture?: ITextureInfo;
+        metallicFactor?: number;
+        roughnessFactor?: number;
+        metallicRoughnessTexture?: ITextureInfo;
+    }
+    interface IMaterial extends IChildRootProperty {
+        pbrMetallicRoughness?: IMaterialPbrMetallicRoughness;
+        normalTexture?: IMaterialNormalTextureInfo;
+        occlusionTexture?: IMaterialOcclusionTextureInfo;
+        emissiveTexture?: ITextureInfo;
+        emissiveFactor?: number[];
+        alphaMode?: MaterialAlphaMode;
+        alphaCutoff?: number;
+        doubleSided?: boolean;
+    }
+    interface IMeshPrimitive extends IProperty {
+        attributes: {
+            [name: string]: number;
+        };
+        indices?: number;
+        material?: number;
+        mode?: MeshPrimitiveMode;
+        targets?: {
+            [name: string]: number;
+        }[];
+    }
+    interface IMesh extends IChildRootProperty {
+        primitives: IMeshPrimitive[];
+        weights?: number[];
+    }
+    interface INode extends IChildRootProperty {
+        camera?: number;
+        children?: number[];
+        skin?: number;
+        matrix?: number[];
+        mesh?: number;
+        rotation?: number[];
+        scale?: number[];
+        translation?: number[];
+        weights?: number[];
+    }
+    interface ISampler extends IChildRootProperty {
+        magFilter?: TextureMagFilter;
+        minFilter?: TextureMinFilter;
+        wrapS?: TextureWrapMode;
+        wrapT?: TextureWrapMode;
+    }
+    interface IScene extends IChildRootProperty {
+        nodes: number[];
+    }
+    interface ISkin extends IChildRootProperty {
+        inverseBindMatrices?: number;
+        skeleton?: number;
+        joints: number[];
+    }
+    interface ITexture extends IChildRootProperty {
+        sampler?: number;
+        source: number;
+    }
+    interface ITextureInfo {
+        index: number;
+        texCoord?: number;
+    }
+    interface IGLTF extends IProperty {
+        accessors?: IAccessor[];
+        animations?: IAnimation[];
+        asset: IAsset;
+        buffers?: IBuffer[];
+        bufferViews?: IBufferView[];
+        cameras?: ICamera[];
+        extensionsUsed?: string[];
+        extensionsRequired?: string[];
+        images?: IImage[];
+        materials?: IMaterial[];
+        meshes?: IMesh[];
+        nodes?: INode[];
+        samplers?: ISampler[];
+        scene?: number;
+        scenes?: IScene[];
+        skins?: ISkin[];
+        textures?: ITexture[];
+    }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 13030 - 10735
dist/preview release/babylon.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 49 - 49
dist/preview release/babylon.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2555 - 469
dist/preview release/babylon.max.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 19088 - 0
dist/preview release/babylon.module.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 50 - 50
dist/preview release/babylon.worker.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 6332 - 4042
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 51 - 51
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2501 - 470
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2503 - 472
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2557 - 471
dist/preview release/es6.js


+ 70 - 1
dist/preview release/gui/babylon.gui.d.ts

@@ -56,6 +56,17 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+         * @param name name for the Texture
+         * @param foreground render in foreground (default is true)
+         * @param scene scene to be rendered in
+         * @param sampling method for scaling to fit screen
+         * @returns AdvancedDynamicTexture
+         */
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>, sampling?: number): AdvancedDynamicTexture;
     }
 }
@@ -509,6 +520,9 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
+        /**
+         * Defines the name of the control
+         */
         name: string | undefined;
         private _text;
         private _textWrapping;
@@ -522,15 +536,70 @@ declare module BABYLON.GUI {
         * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        onLinesReadyObservable: Observable<TextBlock>;
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        readonly lines: any[];
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
         resizeToFit: boolean;
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         textWrapping: boolean;
+        /**
+         * Gets or sets text to display
+         */
+        /**
+         * Gets or sets text to display
+         */
         text: string;
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         textHorizontalAlignment: number;
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
         textVerticalAlignment: number;
+        /**
+         * Gets or sets line spacing value
+         */
+        /**
+         * Gets or sets line spacing value
+         */
         lineSpacing: string | number;
-        constructor(name?: string | undefined, text?: string);
+        /**
+         * Creates a new TextBlock object
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
+        /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;

+ 74 - 1
dist/preview release/gui/babylon.gui.js

@@ -476,6 +476,17 @@ var BABYLON;
                 result.attachToMesh(mesh, supportPointerMove);
                 return result;
             };
+            /**
+             * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+             * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+             * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+             * layerMask is set through advancedTexture.layer.layerMask
+             * @param name name for the Texture
+             * @param foreground render in foreground (default is true)
+             * @param scene scene to be rendered in
+             * @param sampling method for scaling to fit screen
+             * @returns AdvancedDynamicTexture
+             */
             AdvancedDynamicTexture.CreateFullscreenUI = function (name, foreground, scene, sampling) {
                 if (foreground === void 0) { foreground = true; }
                 if (scene === void 0) { scene = null; }
@@ -3174,7 +3185,16 @@ var BABYLON;
     (function (GUI) {
         var TextBlock = /** @class */ (function (_super) {
             __extends(TextBlock, _super);
-            function TextBlock(name, text) {
+            /**
+             * Creates a new TextBlock object
+             * @param name defines the name of the control
+             * @param text defines the text to display (emptry string by default)
+             */
+            function TextBlock(
+                /**
+                 * Defines the name of the control
+                 */
+                name, text) {
                 if (text === void 0) { text = ""; }
                 var _this = _super.call(this, name) || this;
                 _this.name = name;
@@ -3189,13 +3209,34 @@ var BABYLON;
                 * @type {BABYLON.Observable}
                 */
                 _this.onTextChangedObservable = new BABYLON.Observable();
+                /**
+                * An event triggered after the text was broken up into lines
+                * @type {BABYLON.Observable}
+                */
+                _this.onLinesReadyObservable = new BABYLON.Observable();
                 _this.text = text;
                 return _this;
             }
+            Object.defineProperty(TextBlock.prototype, "lines", {
+                /**
+                 * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+                 */
+                get: function () {
+                    return this._lines;
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(TextBlock.prototype, "resizeToFit", {
+                /**
+                 * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+                 */
                 get: function () {
                     return this._resizeToFit;
                 },
+                /**
+                 * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+                 */
                 set: function (value) {
                     this._resizeToFit = value;
                     if (this._resizeToFit) {
@@ -3207,9 +3248,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textWrapping", {
+                /**
+                 * Gets or sets a boolean indicating if text must be wrapped
+                 */
                 get: function () {
                     return this._textWrapping;
                 },
+                /**
+                 * Gets or sets a boolean indicating if text must be wrapped
+                 */
                 set: function (value) {
                     if (this._textWrapping === value) {
                         return;
@@ -3221,9 +3268,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "text", {
+                /**
+                 * Gets or sets text to display
+                 */
                 get: function () {
                     return this._text;
                 },
+                /**
+                 * Gets or sets text to display
+                 */
                 set: function (value) {
                     if (this._text === value) {
                         return;
@@ -3236,9 +3289,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textHorizontalAlignment", {
+                /**
+                 * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+                 */
                 get: function () {
                     return this._textHorizontalAlignment;
                 },
+                /**
+                 * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+                 */
                 set: function (value) {
                     if (this._textHorizontalAlignment === value) {
                         return;
@@ -3250,9 +3309,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textVerticalAlignment", {
+                /**
+                 * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+                 */
                 get: function () {
                     return this._textVerticalAlignment;
                 },
+                /**
+                 * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+                 */
                 set: function (value) {
                     if (this._textVerticalAlignment === value) {
                         return;
@@ -3264,9 +3329,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "lineSpacing", {
+                /**
+                 * Gets or sets line spacing value
+                 */
                 get: function () {
                     return this._lineSpacing.toString(this._host);
                 },
+                /**
+                 * Gets or sets line spacing value
+                 */
                 set: function (value) {
                     if (this._lineSpacing.fromString(value)) {
                         this._markAsDirty();
@@ -3300,6 +3371,7 @@ var BABYLON;
                 }
                 context.fillText(text, this._currentMeasure.left + x, y);
             };
+            /** @ignore */
             TextBlock.prototype._draw = function (parentMeasure, context) {
                 context.save();
                 this._applyStates(context);
@@ -3324,6 +3396,7 @@ var BABYLON;
                         this._lines.push(this._parseLine(_line, context));
                     }
                 }
+                this.onLinesReadyObservable.notifyObservers(this);
             };
             TextBlock.prototype._parseLine = function (line, context) {
                 if (line === void 0) { line = ''; }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


+ 70 - 1
dist/preview release/gui/babylon.gui.module.d.ts

@@ -62,6 +62,17 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+         * @param name name for the Texture
+         * @param foreground render in foreground (default is true)
+         * @param scene scene to be rendered in
+         * @param sampling method for scaling to fit screen
+         * @returns AdvancedDynamicTexture
+         */
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>, sampling?: number): AdvancedDynamicTexture;
     }
 }
@@ -515,6 +526,9 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
+        /**
+         * Defines the name of the control
+         */
         name: string | undefined;
         private _text;
         private _textWrapping;
@@ -528,15 +542,70 @@ declare module BABYLON.GUI {
         * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        onLinesReadyObservable: Observable<TextBlock>;
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        readonly lines: any[];
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
         resizeToFit: boolean;
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         textWrapping: boolean;
+        /**
+         * Gets or sets text to display
+         */
+        /**
+         * Gets or sets text to display
+         */
         text: string;
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         textHorizontalAlignment: number;
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
         textVerticalAlignment: number;
+        /**
+         * Gets or sets line spacing value
+         */
+        /**
+         * Gets or sets line spacing value
+         */
         lineSpacing: string | number;
-        constructor(name?: string | undefined, text?: string);
+        /**
+         * Creates a new TextBlock object
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
+        /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;

+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -362,7 +362,7 @@ declare module BABYLON.GLTF2 {
         index: number;
         texCoord?: number;
     }
-    interface IGLTF extends IGLTFProperty {
+    interface _IGLTF extends IGLTFProperty {
         accessors?: IGLTFAccessor[];
         animations?: IGLTFAnimation[];
         asset: IGLTFAsset;
@@ -386,7 +386,7 @@ declare module BABYLON.GLTF2 {
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: IGLTF;
+        _gltf: _IGLTF;
         _babylonScene: Scene;
         private _disposed;
         private _rootUrl;

+ 0 - 3
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -1891,9 +1891,6 @@ var BABYLON;
                     });
                 });
                 this._requests.push(request);
-                request.onCompleteObservable.add(function () {
-                    _this._requests.splice(_this._requests.indexOf(request), 1);
-                });
             };
             GLTFLoader.prototype._tryCatchOnError = function (handler) {
                 if (this._disposed) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -919,7 +919,7 @@ declare module BABYLON.GLTF2 {
         index: number;
         texCoord?: number;
     }
-    interface IGLTF extends IGLTFProperty {
+    interface _IGLTF extends IGLTFProperty {
         accessors?: IGLTFAccessor[];
         animations?: IGLTFAnimation[];
         asset: IGLTFAsset;
@@ -943,7 +943,7 @@ declare module BABYLON.GLTF2 {
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: IGLTF;
+        _gltf: _IGLTF;
         _babylonScene: Scene;
         private _disposed;
         private _rootUrl;

+ 0 - 3
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -4057,9 +4057,6 @@ var BABYLON;
                     });
                 });
                 this._requests.push(request);
-                request.onCompleteObservable.add(function () {
-                    _this._requests.splice(_this._requests.indexOf(request), 1);
-                });
             };
             GLTFLoader.prototype._tryCatchOnError = function (handler) {
                 if (this._disposed) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 0 - 3
dist/preview release/loaders/babylonjs.loaders.js

@@ -5031,9 +5031,6 @@ var BABYLON;
                     });
                 });
                 this._requests.push(request);
-                request.onCompleteObservable.add(function () {
-                    _this._requests.splice(_this._requests.indexOf(request), 1);
-                });
             };
             GLTFLoader.prototype._tryCatchOnError = function (handler) {
                 if (this._disposed) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1020,7 +1020,7 @@ declare module BABYLON.GLTF2 {
         index: number;
         texCoord?: number;
     }
-    interface IGLTF extends IGLTFProperty {
+    interface _IGLTF extends IGLTFProperty {
         accessors?: IGLTFAccessor[];
         animations?: IGLTFAnimation[];
         asset: IGLTFAsset;
@@ -1044,7 +1044,7 @@ declare module BABYLON.GLTF2 {
 
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: IGLTF;
+        _gltf: _IGLTF;
         _babylonScene: Scene;
         private _disposed;
         private _rootUrl;

+ 1 - 3
dist/preview release/loaders/package.json

@@ -31,7 +31,5 @@
     },
     "engines": {
         "node": "*"
-    },
-    "_id": "babylonjs-loaders@3.1.0-alpha1",
-    "_from": "babylonjs-loaders@"
+    }
 }

+ 1 - 3
dist/preview release/materialsLibrary/package.json

@@ -31,7 +31,5 @@
     },
     "engines": {
         "node": "*"
-    },
-    "_id": "babylonjs-materials@3.1.0-alpha1",
-    "_from": "babylonjs-materials@"
+    }
 }

+ 1 - 3
dist/preview release/postProcessesLibrary/package.json

@@ -31,7 +31,5 @@
     },
     "engines": {
         "node": "*"
-    },
-    "_id": "babylonjs-post-process@3.1.0-alpha1",
-    "_from": "babylonjs-post-process@"
+    }
 }

+ 1 - 3
dist/preview release/proceduralTexturesLibrary/package.json

@@ -31,7 +31,5 @@
     },
     "engines": {
         "node": "*"
-    },
-    "_id": "babylonjs-procedural-textures@3.1.0-alpha1",
-    "_from": "babylonjs-procedural-textures@"
+    }
 }

+ 173 - 42
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -1,47 +1,118 @@
 
 declare module BABYLON {
+    /**
+     * Holds a collection of exporter options and parameters
+     */
+    interface IExporterOptions {
+        /**
+         * Function which indicates whether a babylon mesh should be exported or not.
+         * @param mesh - source Babylon mesh. It is used to check whether it should be
+         * exported to glTF or not.
+         * @returns boolean, which indicates whether the mesh should be exported (true) or not (false)
+         */
+        shouldExportMesh?(mesh: AbstractMesh): boolean;
+    }
+    /**
+     * Class for generating glTF data from a Babylon scene.
+     */
     class GLTF2Export {
         /**
-         * Exports the geometry of a Mesh array in .gltf file format.
-         * If glb is set to true, exports as .glb.
-         * @param meshes
-         * @param materials
-         *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .gltf, .glb and associates textures
+         * Exports the geometry of the scene to .gltf file format.
+         * @param scene - Babylon scene with scene hierarchy information.
+         * @param filePrefix - File prefix to use when generating the glTF file.
+         * @param options - Exporter options.
+         * @returns - Returns an object with a .gltf file and associates texture names
          * as keys and their data and paths as values.
          */
-        static GLTF(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLTF(scene: Scene, filePrefix: string, options?: IExporterOptions): _GLTFData;
         /**
-         *
-         * @param meshes
-         * @param filename
-         *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .glb filename as key and data as value
+         * Exports the geometry of the scene to .glb file format.
+         * @param scene - Babylon scene with scene hierarchy information.
+         * @param filePrefix - File prefix to use when generating glb file.
+         * @param options - Exporter options.
+         * @returns - Returns an object with a .glb filename as key and data as value
          */
-        static GLB(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLB(scene: Scene, filePrefix: string, options?: IExporterOptions): _GLTFData;
     }
 }
 
-declare module BABYLON {
-    class _GLTF2Exporter {
+
+/**
+ * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally.
+ * @ignore - capitalization of GLTF2 module.
+ */
+declare module BABYLON.GLTF2 {
+    /**
+     * Converts Babylon Scene into glTF 2.0.
+     */
+    class _Exporter {
+        /**
+         * Stores all generated buffer views, which represents views into the main glTF buffer data.
+         */
         private bufferViews;
+        /**
+         * Stores all the generated accessors, which is used for accessing the data within the buffer views in glTF.
+         */
         private accessors;
+        /**
+         * Stores all the generated nodes, which contains transform and/or mesh information per node.
+         */
         private nodes;
+        /**
+         * Stores the glTF asset information, which represents the glTF version and this file generator.
+         */
         private asset;
+        /**
+         * Stores all the generated glTF scenes, which stores multiple node hierarchies.
+         */
         private scenes;
+        /**
+         * Stores all the generated mesh information, each containing a set of primitives to render in glTF.
+         */
         private meshes;
+        /**
+         * Stores all the generated material information, which represents the appearance of each primitive.
+         */
+        private materials;
+        /**
+         * Stores all the generated texture information, which is referenced by glTF materials.
+         */
+        private textures;
+        /**
+         * Stores all the generated image information, which is referenced by glTF textures.
+         */
+        private images;
+        /**
+         * Stores the total amount of bytes stored in the glTF buffer.
+         */
         private totalByteLength;
+        /**
+         * Stores a reference to the Babylon scene containing the source geometry and material information.
+         */
         private babylonScene;
-        constructor(babylonScene: BABYLON.Scene);
+        /**
+         * Stores the exporter options, which are optionally passed in from the glTF serializer.
+         */
+        private options?;
+        /**
+         * Stores a map of the image data, where the key is the file name and the value
+         * is the image data.
+         */
+        private imageData;
+        /**
+         * Creates a glTF Exporter instance, which can accept optional exporter options.
+         * @param babylonScene - Babylon scene object
+         * @param options - Options to modify the behavior of the exporter.
+         */
+        constructor(babylonScene: Scene, options?: IExporterOptions);
         /**
          * Creates a buffer view based on teh supplied arguments
-         * @param bufferIndex
-         * @param byteOffset
-         * @param byteLength
-         *
-         * @returns {_IGLTFBufferView}
+         * @param {number} bufferIndex - index value of the specified buffer
+         * @param {number} byteOffset - byte offset value
+         * @param {number} byteLength - byte length of the bufferView
+         * @returns - bufferView for glTF
          */
-        private createBufferView(bufferIndex, byteOffset, byteLength);
+        private createBufferView(bufferIndex, byteOffset, byteLength, name?);
         /**
          * Creates an accessor based on the supplied arguments
          * @param bufferviewIndex
@@ -51,8 +122,7 @@ declare module BABYLON {
          * @param count
          * @param min
          * @param max
-         *
-         * @returns {_IGLTFAccessor}
+         * @returns - accessor for glTF
          */
         private createAccessor(bufferviewIndex, name, type, componentType, count, min?, max?);
         /**
@@ -62,8 +132,7 @@ declare module BABYLON {
          * @param vertexCount
          * @param arrayOffset
          * @param stride
-         *
-         * @returns {min: number[], max: number[]} min number array and max number array
+         * @returns - min number array and max number array
          */
         private calculateMinMax(buff, vertexStart, vertexCount, arrayOffset, stride);
         /**
@@ -76,8 +145,7 @@ declare module BABYLON {
          * @param byteOffset
          * @param dataBuffer
          * @param useRightHandedSystem
-         *
-         * @returns {number} byte length
+         * @returns - byte length
          */
         private writeAttributeData(vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem);
         /**
@@ -85,32 +153,34 @@ declare module BABYLON {
          * @param glb
          * @param glTFPrefix
          * @param prettyPrint
-         *
-         * @returns {string} json data as string
+         * @returns - json data as string
          */
         private generateJSON(glb, glTFPrefix?, prettyPrint?);
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix
-         *
-         * @returns {[x: string]: string | Blob} object with glTF json tex filename
+         * @returns - object with glTF json tex filename
          * and binary file name as keys and their data as values
          */
         _generateGLTF(glTFPrefix: string): _GLTFData;
         /**
          * Creates a binary buffer for glTF
-         *
-         * @returns {ArrayBuffer}
+         * @returns - array buffer for binary data
          */
         private generateBinary();
         /**
+         * Pads the number to a power of 4
+         * @param num - number to pad
+         * @returns - padded number
+         */
+        private _getPadding(num);
+        /**
          * Generates a glb file from the json and binary data.
          * Returns an object with the glb file name as the key and data as the value.
          * @param jsonText
          * @param binaryBuffer
          * @param glTFPrefix
-         *
-         * @returns {[glbFileName: string]: Blob} object with glb filename as key and data as value
+         * @returns - object with glb filename as key and data as value
          */
         _generateGLB(glTFPrefix: string): _GLTFData;
         /**
@@ -121,14 +191,19 @@ declare module BABYLON {
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
+         *
+         * @param babylonTexture
+         * @return - glTF texture, or null if the texture format is not supported
+         */
+        private exportTexture(babylonTexture, mimeType?);
+        /**
          * Sets data for the primitive attributes of each submesh
          * @param mesh
          * @param babylonMesh
          * @param byteOffset
          * @param useRightHandedSystem
          * @param dataBuffer
-         *
-         * @returns {number} bytelength of the primitive attributes plus the passed in byteOffset
+         * @returns - bytelength of the primitive attributes plus the passed in byteOffset
          */
         private setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer?);
         /**
@@ -138,25 +213,81 @@ declare module BABYLON {
          * @param byteOffset
          * @param buffer
          * @param dataBuffer
-         *
-         * @returns {number} bytelength + byteoffset
+         * @returns bytelength + byteoffset
          */
         private createScene(babylonScene, byteOffset, dataBuffer?);
     }
 }
 
+
 declare module BABYLON {
     /**
      * Class for holding and downloading glTF file data
      */
     class _GLTFData {
-        _glTFFiles: {
+        /**
+         * Object which contains the file name as the key and its data as the value.
+         */
+        glTFFiles: {
             [fileName: string]: string | Blob;
         };
+        /**
+         * Initializes the glTF file object.
+         */
         constructor();
         /**
-         * Downloads glTF data.
+         * Downloads the glTF data as files based on their names and data.
          */
         downloadFiles(): void;
     }
 }
+
+
+declare module BABYLON.GLTF2 {
+    /**
+     * Utility methods for working with glTF material conversion properties.  This class should only be used internally.
+     */
+    class _GLTFMaterial {
+        /**
+         * Represents the dielectric specular values for R, G and B.
+         */
+        private static readonly dielectricSpecular;
+        /**
+         * Epsilon value, used as a small tolerance value for a numeric value.
+         */
+        private static readonly epsilon;
+        /**
+         * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
+         * @param babylonStandardMaterial
+         * @returns - glTF Metallic Roughness Material representation
+         */
+        static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
+        /**
+         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
+         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
+         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
+         * @returns - Babylon metallic roughness values
+         */
+        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness);
+        /**
+         * Returns the perceived brightness value based on the provided color
+         * @param color - color used in calculating the perceived brightness
+         * @returns - perceived brightness value
+         */
+        private static PerceivedBrightness(color);
+        /**
+         * Computes the metallic factor
+         * @param diffuse - diffused value
+         * @param specular - specular value
+         * @param oneMinusSpecularStrength - one minus the specular strength
+         * @returns - metallic value
+         */
+        static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number;
+        /**
+         * Gets the glTF alpha mode from the Babylon Material
+         * @param babylonMaterial - Babylon Material
+         * @returns - The Babylon alpha mode value
+         */
+        static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
+    }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 997 - 559
dist/preview release/serializers/babylon.glTF2Serializer.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 997 - 559
dist/preview release/serializers/babylonjs.serializers.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 173 - 42
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -14,48 +14,119 @@ declare module BABYLON {
 
 
 declare module BABYLON {
+    /**
+     * Holds a collection of exporter options and parameters
+     */
+    interface IExporterOptions {
+        /**
+         * Function which indicates whether a babylon mesh should be exported or not.
+         * @param mesh - source Babylon mesh. It is used to check whether it should be
+         * exported to glTF or not.
+         * @returns boolean, which indicates whether the mesh should be exported (true) or not (false)
+         */
+        shouldExportMesh?(mesh: AbstractMesh): boolean;
+    }
+    /**
+     * Class for generating glTF data from a Babylon scene.
+     */
     class GLTF2Export {
         /**
-         * Exports the geometry of a Mesh array in .gltf file format.
-         * If glb is set to true, exports as .glb.
-         * @param meshes
-         * @param materials
-         *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .gltf, .glb and associates textures
+         * Exports the geometry of the scene to .gltf file format.
+         * @param scene - Babylon scene with scene hierarchy information.
+         * @param filePrefix - File prefix to use when generating the glTF file.
+         * @param options - Exporter options.
+         * @returns - Returns an object with a .gltf file and associates texture names
          * as keys and their data and paths as values.
          */
-        static GLTF(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLTF(scene: Scene, filePrefix: string, options?: IExporterOptions): _GLTFData;
         /**
-         *
-         * @param meshes
-         * @param filename
-         *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .glb filename as key and data as value
+         * Exports the geometry of the scene to .glb file format.
+         * @param scene - Babylon scene with scene hierarchy information.
+         * @param filePrefix - File prefix to use when generating glb file.
+         * @param options - Exporter options.
+         * @returns - Returns an object with a .glb filename as key and data as value
          */
-        static GLB(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLB(scene: Scene, filePrefix: string, options?: IExporterOptions): _GLTFData;
     }
 }
 
-declare module BABYLON {
-    class _GLTF2Exporter {
+
+/**
+ * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally.
+ * @ignore - capitalization of GLTF2 module.
+ */
+declare module BABYLON.GLTF2 {
+    /**
+     * Converts Babylon Scene into glTF 2.0.
+     */
+    class _Exporter {
+        /**
+         * Stores all generated buffer views, which represents views into the main glTF buffer data.
+         */
         private bufferViews;
+        /**
+         * Stores all the generated accessors, which is used for accessing the data within the buffer views in glTF.
+         */
         private accessors;
+        /**
+         * Stores all the generated nodes, which contains transform and/or mesh information per node.
+         */
         private nodes;
+        /**
+         * Stores the glTF asset information, which represents the glTF version and this file generator.
+         */
         private asset;
+        /**
+         * Stores all the generated glTF scenes, which stores multiple node hierarchies.
+         */
         private scenes;
+        /**
+         * Stores all the generated mesh information, each containing a set of primitives to render in glTF.
+         */
         private meshes;
+        /**
+         * Stores all the generated material information, which represents the appearance of each primitive.
+         */
+        private materials;
+        /**
+         * Stores all the generated texture information, which is referenced by glTF materials.
+         */
+        private textures;
+        /**
+         * Stores all the generated image information, which is referenced by glTF textures.
+         */
+        private images;
+        /**
+         * Stores the total amount of bytes stored in the glTF buffer.
+         */
         private totalByteLength;
+        /**
+         * Stores a reference to the Babylon scene containing the source geometry and material information.
+         */
         private babylonScene;
-        constructor(babylonScene: BABYLON.Scene);
+        /**
+         * Stores the exporter options, which are optionally passed in from the glTF serializer.
+         */
+        private options?;
+        /**
+         * Stores a map of the image data, where the key is the file name and the value
+         * is the image data.
+         */
+        private imageData;
+        /**
+         * Creates a glTF Exporter instance, which can accept optional exporter options.
+         * @param babylonScene - Babylon scene object
+         * @param options - Options to modify the behavior of the exporter.
+         */
+        constructor(babylonScene: Scene, options?: IExporterOptions);
         /**
          * Creates a buffer view based on teh supplied arguments
-         * @param bufferIndex
-         * @param byteOffset
-         * @param byteLength
-         *
-         * @returns {_IGLTFBufferView}
+         * @param {number} bufferIndex - index value of the specified buffer
+         * @param {number} byteOffset - byte offset value
+         * @param {number} byteLength - byte length of the bufferView
+         * @returns - bufferView for glTF
          */
-        private createBufferView(bufferIndex, byteOffset, byteLength);
+        private createBufferView(bufferIndex, byteOffset, byteLength, name?);
         /**
          * Creates an accessor based on the supplied arguments
          * @param bufferviewIndex
@@ -65,8 +136,7 @@ declare module BABYLON {
          * @param count
          * @param min
          * @param max
-         *
-         * @returns {_IGLTFAccessor}
+         * @returns - accessor for glTF
          */
         private createAccessor(bufferviewIndex, name, type, componentType, count, min?, max?);
         /**
@@ -76,8 +146,7 @@ declare module BABYLON {
          * @param vertexCount
          * @param arrayOffset
          * @param stride
-         *
-         * @returns {min: number[], max: number[]} min number array and max number array
+         * @returns - min number array and max number array
          */
         private calculateMinMax(buff, vertexStart, vertexCount, arrayOffset, stride);
         /**
@@ -90,8 +159,7 @@ declare module BABYLON {
          * @param byteOffset
          * @param dataBuffer
          * @param useRightHandedSystem
-         *
-         * @returns {number} byte length
+         * @returns - byte length
          */
         private writeAttributeData(vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem);
         /**
@@ -99,32 +167,34 @@ declare module BABYLON {
          * @param glb
          * @param glTFPrefix
          * @param prettyPrint
-         *
-         * @returns {string} json data as string
+         * @returns - json data as string
          */
         private generateJSON(glb, glTFPrefix?, prettyPrint?);
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix
-         *
-         * @returns {[x: string]: string | Blob} object with glTF json tex filename
+         * @returns - object with glTF json tex filename
          * and binary file name as keys and their data as values
          */
         _generateGLTF(glTFPrefix: string): _GLTFData;
         /**
          * Creates a binary buffer for glTF
-         *
-         * @returns {ArrayBuffer}
+         * @returns - array buffer for binary data
          */
         private generateBinary();
         /**
+         * Pads the number to a power of 4
+         * @param num - number to pad
+         * @returns - padded number
+         */
+        private _getPadding(num);
+        /**
          * Generates a glb file from the json and binary data.
          * Returns an object with the glb file name as the key and data as the value.
          * @param jsonText
          * @param binaryBuffer
          * @param glTFPrefix
-         *
-         * @returns {[glbFileName: string]: Blob} object with glb filename as key and data as value
+         * @returns - object with glb filename as key and data as value
          */
         _generateGLB(glTFPrefix: string): _GLTFData;
         /**
@@ -135,14 +205,19 @@ declare module BABYLON {
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
+         *
+         * @param babylonTexture
+         * @return - glTF texture, or null if the texture format is not supported
+         */
+        private exportTexture(babylonTexture, mimeType?);
+        /**
          * Sets data for the primitive attributes of each submesh
          * @param mesh
          * @param babylonMesh
          * @param byteOffset
          * @param useRightHandedSystem
          * @param dataBuffer
-         *
-         * @returns {number} bytelength of the primitive attributes plus the passed in byteOffset
+         * @returns - bytelength of the primitive attributes plus the passed in byteOffset
          */
         private setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer?);
         /**
@@ -152,25 +227,81 @@ declare module BABYLON {
          * @param byteOffset
          * @param buffer
          * @param dataBuffer
-         *
-         * @returns {number} bytelength + byteoffset
+         * @returns bytelength + byteoffset
          */
         private createScene(babylonScene, byteOffset, dataBuffer?);
     }
 }
 
+
 declare module BABYLON {
     /**
      * Class for holding and downloading glTF file data
      */
     class _GLTFData {
-        _glTFFiles: {
+        /**
+         * Object which contains the file name as the key and its data as the value.
+         */
+        glTFFiles: {
             [fileName: string]: string | Blob;
         };
+        /**
+         * Initializes the glTF file object.
+         */
         constructor();
         /**
-         * Downloads glTF data.
+         * Downloads the glTF data as files based on their names and data.
          */
         downloadFiles(): void;
     }
 }
+
+
+declare module BABYLON.GLTF2 {
+    /**
+     * Utility methods for working with glTF material conversion properties.  This class should only be used internally.
+     */
+    class _GLTFMaterial {
+        /**
+         * Represents the dielectric specular values for R, G and B.
+         */
+        private static readonly dielectricSpecular;
+        /**
+         * Epsilon value, used as a small tolerance value for a numeric value.
+         */
+        private static readonly epsilon;
+        /**
+         * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
+         * @param babylonStandardMaterial
+         * @returns - glTF Metallic Roughness Material representation
+         */
+        static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
+        /**
+         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
+         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
+         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
+         * @returns - Babylon metallic roughness values
+         */
+        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness);
+        /**
+         * Returns the perceived brightness value based on the provided color
+         * @param color - color used in calculating the perceived brightness
+         * @returns - perceived brightness value
+         */
+        private static PerceivedBrightness(color);
+        /**
+         * Computes the metallic factor
+         * @param diffuse - diffused value
+         * @param specular - specular value
+         * @param oneMinusSpecularStrength - one minus the specular strength
+         * @returns - metallic value
+         */
+        static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number;
+        /**
+         * Gets the glTF alpha mode from the Babylon Material
+         * @param babylonMaterial - Babylon Material
+         * @returns - The Babylon alpha mode value
+         */
+        static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
+    }
+}

+ 1 - 3
dist/preview release/serializers/package.json

@@ -31,7 +31,5 @@
     },
     "engines": {
         "node": "*"
-    },
-    "_id": "babylonjs-serializers@3.1.0-alpha1",
-    "_from": "babylonjs-serializers@"
+    }
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 4033 - 16203
dist/preview release/typedocValidationBaseline.json


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 63 - 63
dist/preview release/viewer/babylon.viewer.js


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

@@ -1,10 +1,15 @@
 # 3.2.0
 
 ## Major updates
+- Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
 - Introduced texture binding atlas. This optimization allows the engine to reuse texture bindings instead of rebinding textures when they are not on constant sampler indexes ([deltakosh](https://github.com/deltakosh))
 - New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
+- `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
+- New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 
 ## Updates
+- Tons of functions and classes received the code comments they deserved (All the community)
+- Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adapatability ([deltakosh](https://github.com/deltakosh))
 - Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
 - New watcher configuration for VSCode. Now the task only compiles changed files ([sebavan](https://github.com/sebavan))
@@ -18,7 +23,9 @@
    ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
    ([carloslanderas](https://github.com/carloslanderas))
-- `AssetsManager` will now clear its `tasks` lsit from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))
+- `AssetsManager` will now clear its `tasks` list from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))
+- Added documentation to WebVRCamera and VRExperienceHelper ([trevordev](https://github.com/trevordev))
+- Introduced `isStroke` on `HighlightLayerOptions` which makes the highlight solid ([PixelsCommander](https://github.com/pixelscommander))
 
 ## Bug fixes
 

+ 11 - 0
gui/src/advancedDynamicTexture.ts

@@ -529,6 +529,17 @@ module BABYLON.GUI {
             return result;
         }
 
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+		 * @param name name for the Texture
+		 * @param foreground render in foreground (default is true)
+		 * @param scene scene to be rendered in
+		 * @param sampling method for scaling to fit screen
+		 * @returns AdvancedDynamicTexture
+         */
         public static CreateFullscreenUI(name: string, foreground: boolean = true, scene: Nullable<Scene> = null, sampling = Texture.BILINEAR_SAMPLINGMODE): AdvancedDynamicTexture {
             var result = new AdvancedDynamicTexture(name, 0, 0, scene, false, sampling);
 

+ 65 - 3
gui/src/controls/textBlock.ts

@@ -16,11 +16,30 @@ module BABYLON.GUI {
         */
         public onTextChangedObservable = new Observable<TextBlock>();
 
-        get resizeToFit(): boolean {
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        public onLinesReadyObservable = new Observable<TextBlock>();
+
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        public get lines(): any[] {
+            return this._lines;
+        }
+        
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        public get resizeToFit(): boolean {
             return this._resizeToFit;
         }
 
-        set resizeToFit(value: boolean) {
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */        
+        public set resizeToFit(value: boolean) {
             this._resizeToFit = value;
 
             if (this._resizeToFit) {
@@ -29,10 +48,16 @@ module BABYLON.GUI {
             }
         }
 
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         public get textWrapping(): boolean {
             return this._textWrapping;
         }
 
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */        
         public set textWrapping(value: boolean) {
             if (this._textWrapping === value) {
                 return;
@@ -41,10 +66,16 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
+        /**
+         * Gets or sets text to display
+         */
         public get text(): string {
             return this._text;
         }
 
+        /**
+         * Gets or sets text to display
+         */
         public set text(value: string) {
             if (this._text === value) {
                 return;
@@ -55,10 +86,16 @@ module BABYLON.GUI {
             this.onTextChangedObservable.notifyObservers(this);
         }
 
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         public get textHorizontalAlignment(): number {
             return this._textHorizontalAlignment;
         }
 
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */        
         public set textHorizontalAlignment(value: number) {
             if (this._textHorizontalAlignment === value) {
                 return;
@@ -68,10 +105,16 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */        
         public get textVerticalAlignment(): number {
             return this._textVerticalAlignment;
         }
 
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */           
         public set textVerticalAlignment(value: number) {
             if (this._textVerticalAlignment === value) {
                 return;
@@ -81,17 +124,33 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
+        /**
+         * Gets or sets line spacing value
+         */
         public set lineSpacing(value: string | number) {
             if (this._lineSpacing.fromString(value)) {
                 this._markAsDirty();
             }
         }
 
+        /**
+         * Gets or sets line spacing value
+         */        
         public get lineSpacing(): string | number {
             return this._lineSpacing.toString(this._host);
         }
 
-        constructor(public name?: string, text: string = "") {
+        /**
+         * Creates a new TextBlock object
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            public name?: string, 
+            text: string = "") {
             super(name);
 
             this.text = text;
@@ -126,6 +185,7 @@ module BABYLON.GUI {
             context.fillText(text, this._currentMeasure.left + x, y);
         }
 
+        /** @ignore */
         public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             context.save();
 
@@ -151,6 +211,8 @@ module BABYLON.GUI {
                     this._lines.push(this._parseLine(_line, context));
                 }
             }
+
+            this.onLinesReadyObservable.notifyObservers(this);
         }
 
         protected _parseLine(line: string = '', context: CanvasRenderingContext2D): object {

+ 2 - 5
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -40,7 +40,7 @@ module BABYLON.GLTF2 {
     }
 
     export class GLTFLoader implements IGLTFLoader {
-        public _gltf: IGLTF;
+        public _gltf: _IGLTF;
         public _babylonScene: Scene;
 
         private _disposed = false;
@@ -182,7 +182,7 @@ module BABYLON.GLTF2 {
         }
 
         private _loadData(data: IGLTFLoaderData): void {
-            this._gltf = <IGLTF>data.json;
+            this._gltf = <_IGLTF>data.json;
 
             // Assign the index of each object for convinience.
             GLTFLoader._AssignIndices(this._gltf.accessors);
@@ -1620,9 +1620,6 @@ module BABYLON.GLTF2 {
             }) as IGLTFLoaderFileRequest;
 
             this._requests.push(request);
-            request.onCompleteObservable.add(() => {
-                this._requests.splice(this._requests.indexOf(request), 1);
-            });
         }
 
         public _tryCatchOnError(handler: () => void): void {

+ 1 - 1
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -284,7 +284,7 @@ module BABYLON.GLTF2 {
         texCoord?: number;
     }
 
-    export interface IGLTF extends IGLTFProperty {
+    export interface _IGLTF extends IGLTFProperty {
         accessors?: IGLTFAccessor[];
         animations?: IGLTFAnimation[];
         asset: IGLTFAsset;

+ 1 - 1
package.json

@@ -14,7 +14,7 @@
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
-    "main": "dist/preview release/babylon.max.js",
+    "main": "dist/preview release/babylon.js",
     "files": [
         "package.json",
         "dist/preview release/babylon.d.ts",

+ 25 - 10
serializers/src/glTF/2.0/babylon.glTFData.ts

@@ -1,33 +1,42 @@
+/// <reference path="../../../../dist/babylon.glTFInterface.d.ts"/>
+
 module BABYLON {
     /**
      * Class for holding and downloading glTF file data
      */
     export class _GLTFData {
-        _glTFFiles: { [fileName: string]: string | Blob };
+        /**
+         * Object which contains the file name as the key and its data as the value.
+         */
+        glTFFiles: { [fileName: string]: string | Blob };
 
+        /**
+         * Initializes the glTF file object.
+         */
         public constructor() {
-            this._glTFFiles = {};
+            this.glTFFiles = {};
         }
+
         /**
-         * Downloads glTF data.
+         * Downloads the glTF data as files based on their names and data.
          */
         public downloadFiles(): void {
             /**
-            * Checks for a matching suffix at the end of a string (for ES5 and lower)
-            * @param str 
-            * @param suffix 
-            * 
-            * @returns {boolean} indicating whether the suffix matches or not
+            * Checks for a matching suffix at the end of a string (for ES5 and lower).
+            * @param str - Source string.
+            * @param suffix - Suffix to search for in the source string.
+            * @returns - Boolean indicating whether the suffix was found (true) or not (false).
             */
             function endsWith(str: string, suffix: string): boolean {
                 return str.indexOf(suffix, str.length - suffix.length) !== -1;
             }
-            for (let key in this._glTFFiles) {
+
+            for (let key in this.glTFFiles) {
                 let link = document.createElement('a');
                 document.body.appendChild(link);
                 link.setAttribute("type", "hidden");
                 link.download = key;
-                let blob = this._glTFFiles[key];
+                let blob = this.glTFFiles[key];
                 let mimeType;
 
                 if (endsWith(key, ".glb")) {
@@ -39,6 +48,12 @@ module BABYLON {
                 else if (endsWith(key, ".gltf")) {
                     mimeType = { type: "model/gltf+json" };
                 }
+                else if (endsWith(key, ".jpeg" || ".jpg")) {
+                    mimeType = {type: GLTF2.ImageMimeType.JPEG};
+                }
+                else if (endsWith(key, ".png")) {
+                    mimeType = {type: GLTF2.ImageMimeType.PNG};
+                }
 
                 link.href = window.URL.createObjectURL(new Blob([blob], mimeType));
                 link.click();

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 516 - 224
serializers/src/glTF/2.0/babylon.glTFExporter.ts


+ 198 - 0
serializers/src/glTF/2.0/babylon.glTFMaterial.ts

@@ -0,0 +1,198 @@
+/// <reference path="../../../../dist/babylon.glTFInterface.d.ts"/>
+
+module BABYLON.GLTF2 {
+    /**
+     * Represents the components used for representing a physically-based specular glossiness material
+     */
+    interface IBabylonPbrSpecularGlossiness {
+        /**
+         * The diffuse color of the model, whose color values should be 
+         * normalized from 0 to 1.  
+         */
+        diffuse: Color3;
+        /**
+         * Represents the transparency of the material, from a range of 0 to 1.
+         */
+        opacity: number;
+        /**
+         * Represents how specular the material is, from a range of 0 to 1.
+         */
+        specular: Color3;
+        /**
+         * Represents how glossy the material is, from a range of 0 to 1.
+         */
+        glossiness: number;
+    }
+
+    /**
+     * Represents the components used for representing a physically-based metallic roughness material.
+     */
+    interface _IBabylonPbrMetallicRoughness {
+        /**
+         * The albedo color of the material, whose color components should be normalized from 0 to 1.
+         */
+        baseColor: Color3;
+        /**
+         * Represents the transparency of the material, from a range of 0 (transparent) to 1 (opaque).
+         */
+        opacity: number;
+        /**
+         * Represents the "metalness" of a material, from a range of 0 (dielectric) to 1 (metal).
+         */
+        metallic: number;
+        /**
+         * Represents the "roughness" of a material, from a range of 0 (completely smooth) to 1 (completely rough).
+         */
+        roughness: number;
+    }
+
+    /**
+     * Utility methods for working with glTF material conversion properties.  This class should only be used internally.
+     */
+    export class _GLTFMaterial {
+        /**
+         * Represents the dielectric specular values for R, G and B.
+         */
+        private static readonly dielectricSpecular = new Color3(0.04, 0.04, 0.04);
+        /**
+         * Epsilon value, used as a small tolerance value for a numeric value.
+         */
+        private static readonly epsilon = 1e-6;
+
+        /**
+         * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
+         * @param babylonStandardMaterial 
+         * @returns - glTF Metallic Roughness Material representation
+         */
+        public static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness {
+            const babylonSpecularGlossiness: IBabylonPbrSpecularGlossiness = {
+                diffuse: babylonStandardMaterial.diffuseColor,
+                opacity: babylonStandardMaterial.alpha,
+                specular: babylonStandardMaterial.specularColor || Color3.Black(),
+                glossiness: babylonStandardMaterial.specularPower / 256
+            };
+            if (babylonStandardMaterial.specularTexture) {
+
+            }
+            const babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
+
+            const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {
+                baseColorFactor: [
+                    babylonMetallicRoughness.baseColor.r,
+                    babylonMetallicRoughness.baseColor.g,
+                    babylonMetallicRoughness.baseColor.b,
+                    babylonMetallicRoughness.opacity
+                ],
+                metallicFactor: babylonMetallicRoughness.metallic,
+                roughnessFactor: babylonMetallicRoughness.roughness
+            };
+
+            return glTFPbrMetallicRoughness;
+        }
+
+        /**
+         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
+         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
+         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
+         * @returns - Babylon metallic roughness values
+         */
+        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness: IBabylonPbrSpecularGlossiness): _IBabylonPbrMetallicRoughness {
+            const diffuse = babylonSpecularGlossiness.diffuse;
+            const opacity = babylonSpecularGlossiness.opacity;
+            const specular = babylonSpecularGlossiness.specular;
+            const glossiness = babylonSpecularGlossiness.glossiness;
+            
+            const oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
+            const diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
+            const specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
+            const metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
+            const diffuseScaleFactor = oneMinusSpecularStrength/(1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
+            const baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
+            const baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1/ Math.max(metallic, this.epsilon));
+            const lerpColor = Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
+            let baseColor = new Color3();
+            lerpColor.clampToRef(0, 1, baseColor);
+
+            const babylonMetallicRoughness: _IBabylonPbrMetallicRoughness = {
+                baseColor: baseColor,
+                opacity: opacity,
+                metallic: metallic,
+                roughness: 1.0 - glossiness
+            };
+
+            return babylonMetallicRoughness;
+        }
+
+        /**
+         * Returns the perceived brightness value based on the provided color
+         * @param color - color used in calculating the perceived brightness
+         * @returns - perceived brightness value
+         */
+        private static PerceivedBrightness(color: Color3): number {
+            return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
+        }
+
+        /**
+         * Computes the metallic factor
+         * @param diffuse - diffused value
+         * @param specular - specular value
+         * @param oneMinusSpecularStrength - one minus the specular strength
+         * @returns - metallic value
+         */
+        public static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number {
+            if (specular < this.dielectricSpecular.r) {
+                return 0;
+            }
+
+            const a = this.dielectricSpecular.r;
+            const b = diffuse * oneMinusSpecularStrength /(1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
+            const c = this.dielectricSpecular.r - specular;
+            const D = b * b - 4.0 * a * c;
+            return BABYLON.Scalar.Clamp((-b + Math.sqrt(D))/(2.0 * a));
+        }
+        
+        /**
+         * Gets the glTF alpha mode from the Babylon Material
+         * @param babylonMaterial - Babylon Material
+         * @returns - The Babylon alpha mode value
+         */
+        public static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode {
+            if (babylonMaterial instanceof StandardMaterial) {
+                const babylonStandardMaterial = babylonMaterial as StandardMaterial;
+                if ((babylonStandardMaterial.alpha != 1.0) || 
+                    (babylonStandardMaterial.diffuseTexture != null && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
+                    (babylonStandardMaterial.opacityTexture != null)) {
+                    return  MaterialAlphaMode.BLEND;
+                }
+                else {
+                    return MaterialAlphaMode.OPAQUE;
+                }
+            }
+            else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
+                const babylonPBRMetallicRoughness = babylonMaterial as PBRMetallicRoughnessMaterial;
+
+                switch(babylonPBRMetallicRoughness.transparencyMode) {
+                    case PBRMaterial.PBRMATERIAL_OPAQUE: {
+                        return MaterialAlphaMode.OPAQUE;
+                    }
+                    case PBRMaterial.PBRMATERIAL_ALPHABLEND: {
+                        return MaterialAlphaMode.BLEND;
+                    }
+                    case PBRMaterial.PBRMATERIAL_ALPHATEST: {
+                        return MaterialAlphaMode.MASK;
+                    }
+                    case PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
+                        console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                        return MaterialAlphaMode.BLEND;
+                    }
+                    default: {
+                        throw new Error("Unsupported alpha mode " + babylonPBRMetallicRoughness.transparencyMode);
+                    }
+                }
+            }
+            else {
+                throw new Error("Unsupported Babylon material type");
+            }   
+        }
+    }
+}

+ 45 - 21
serializers/src/glTF/2.0/babylon.glTFSerializer.ts

@@ -1,34 +1,58 @@
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON {
+    /**
+     * Holds a collection of exporter options and parameters
+     */
+    export interface IExporterOptions {
+        /**
+         * Function which indicates whether a babylon mesh should be exported or not.
+         * @param mesh - source Babylon mesh. It is used to check whether it should be 
+         * exported to glTF or not.
+         * @returns boolean, which indicates whether the mesh should be exported (true) or not (false)
+         */
+        shouldExportMesh?(mesh: AbstractMesh): boolean;
+    };
+
+    /**
+     * Class for generating glTF data from a Babylon scene.
+     */
     export class GLTF2Export {
         /**
-         * Exports the geometry of a Mesh array in .gltf file format.
-         * If glb is set to true, exports as .glb.
-         * @param meshes 
-         * @param materials 
-         * 
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .gltf, .glb and associates textures
+         * Exports the geometry of the scene to .gltf file format.
+         * @param scene - Babylon scene with scene hierarchy information.
+         * @param filePrefix - File prefix to use when generating the glTF file.
+         * @param options - Exporter options.
+         * @returns - Returns an object with a .gltf file and associates texture names
          * as keys and their data and paths as values.
          */
-        public static GLTF(scene: BABYLON.Scene, filename: string): _GLTFData {
-            let glTFPrefix = filename.replace(/\.[^/.]+$/, "");
-            let gltfGenerator = new _GLTF2Exporter(scene);
-
-            return gltfGenerator._generateGLTF(glTFPrefix);
+        public static GLTF(scene: Scene, filePrefix: string, options?: IExporterOptions): _GLTFData {
+            const glTFPrefix = filePrefix.replace(/\.[^/.]+$/, "");
+            const gltfGenerator = new GLTF2._Exporter(scene, options);
+            if (scene.isReady) {
+                return gltfGenerator._generateGLTF(glTFPrefix);
+            }
+            else {
+                throw new Error("glTF Serializer: Scene is not ready!");
+            } 
         }
+
         /**
-         * 
-         * @param meshes 
-         * @param filename 
-         * 
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .glb filename as key and data as value
+         * Exports the geometry of the scene to .glb file format.
+         * @param scene - Babylon scene with scene hierarchy information.
+         * @param filePrefix - File prefix to use when generating glb file.
+         * @param options - Exporter options.
+         * @returns - Returns an object with a .glb filename as key and data as value
          */
-        public static GLB(scene: BABYLON.Scene, filename: string): _GLTFData {
-            let glTFPrefix = filename.replace(/\.[^/.]+$/, "");        
-            let gltfGenerator = new _GLTF2Exporter(scene);
-
-            return gltfGenerator._generateGLB(glTFPrefix);
+        public static GLB(scene: Scene, filePrefix: string, options?: IExporterOptions): _GLTFData {
+            const glTFPrefix = filePrefix.replace(/\.[^/.]+$/, "");        
+            const gltfGenerator = new GLTF2._Exporter(scene, options);
+            if (scene.isReady) {
+                return gltfGenerator._generateGLB(glTFPrefix);
+            }
+            else {
+                throw new Error("glTF Serializer: Scene is not ready!");
+            }  
         }
     }
 }

+ 19 - 0
src/Actions/babylon.actionManager.ts

@@ -319,6 +319,25 @@
         }
 
         /**
+         * Unregisters an action to this action manager
+         * @param action The action to be unregistered
+         * @return whether the action has been unregistered
+         */
+        public unregisterAction(action: Action): Boolean {
+            var index = this.actions.indexOf(action);
+            if (index !== -1) {
+                this.actions.splice(index, 1);
+                ActionManager.Triggers[action.trigger] -= 1;
+                if (ActionManager.Triggers[action.trigger] === 0) {
+                    delete ActionManager.Triggers[action.trigger]
+                }
+                delete action._actionManager;
+                return true;
+            }
+            return false;
+        }
+
+        /**
          * Process a specific trigger
          * @param {number} trigger - the trigger to process
          * @param evt {BABYLON.ActionEvent} the event details to be processed

+ 5 - 1
src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.ts

@@ -1,4 +1,8 @@
 module BABYLON {
+    /**
+     * Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
+     * Screen rotation is taken into account.
+     */
     export class FreeCameraDeviceOrientationInput implements ICameraInput<FreeCamera> {
         private _camera: FreeCamera;
 
@@ -74,4 +78,4 @@ module BABYLON {
     }
 
     (<any>CameraInputTypes)["FreeCameraDeviceOrientationInput"] = FreeCameraDeviceOrientationInput;
-}
+}

+ 98 - 5
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -1,14 +1,36 @@
 module BABYLON {
+    /**
+     * Options to modify the vr teleportation behavior.
+     */
     export interface VRTeleportationOptions {
-        floorMeshName?: string; // If you'd like to provide a mesh acting as the floor
+        /**
+         * The name of the mesh which should be used as the teleportation floor. (default: null)
+         */
+        floorMeshName?: string;
+        /**
+         * A list of meshes to be used as the teleportation floor. (default: empty)
+         */
         floorMeshes?: Mesh[];
     }
 
+    /**
+     * Options to modify the vr experience helper's behavior.
+     */
     export interface VRExperienceHelperOptions extends WebVROptions {
-        createDeviceOrientationCamera?: boolean; // Create a DeviceOrientationCamera to be used as your out of vr camera.
-        createFallbackVRDeviceOrientationFreeCamera?: boolean; // Create a VRDeviceOrientationFreeCamera to be used for VR when no external HMD is found
+        /**
+         * Create a DeviceOrientationCamera to be used as your out of vr camera.
+         */
+        createDeviceOrientationCamera?: boolean;
+        /**
+         * Create a VRDeviceOrientationFreeCamera to be used for VR when no external HMD is found.
+         */
+        createFallbackVRDeviceOrientationFreeCamera?: boolean;
     }
 
+    /**
+     * Helps to quickly add VR support to an existing scene.
+     * See http://doc.babylonjs.com/how_to/webvr_helper
+     */
     export class VRExperienceHelper {
         private _scene: Scene;
         private _position: Vector3;
@@ -166,10 +188,16 @@ module BABYLON {
 
         private _dpadPressed = true;
 
+        /**
+         * The mesh used to display where the user is going to teleport.
+         */
         public get teleportationTarget(): Mesh {
             return this._teleportationTarget;
         }
 
+        /**
+         * Sets the mesh to be used to display where the user is going to teleport.
+         */
         public set teleportationTarget(value: Mesh) {
             if (value) {
                 value.name = "teleportationTarget";
@@ -178,10 +206,16 @@ module BABYLON {
             }
         }
 
+        /**
+         * If the ray of the gaze should be displayed.
+         */
         public get displayGaze(): boolean {
             return this._displayGaze;
         }
 
+        /**
+         * Sets if the ray of the gaze should be displayed.
+         */
         public set displayGaze(value: boolean) {
             this._displayGaze = value;
             if (!value) {
@@ -189,10 +223,16 @@ module BABYLON {
             }
         }
 
+        /**
+         * If the ray of the LaserPointer should be displayed.
+         */
         public get displayLaserPointer(): boolean {
             return this._displayLaserPointer;
         }
 
+        /**
+         * Sets if the ray of the LaserPointer should be displayed.
+         */
         public set displayLaserPointer(value: boolean) {
             this._displayLaserPointer = value;
             if (!value) {
@@ -213,11 +253,16 @@ module BABYLON {
             }
         }
 
+        /**
+         * The deviceOrientationCamera used as the camera when not in VR.
+         */
         public get deviceOrientationCamera(): Nullable<DeviceOrientationCamera> {
             return this._deviceOrientationCamera;
         }
 
-        // Based on the current WebVR support, returns the current VR camera used
+        /**
+         * Based on the current WebVR support, returns the current VR camera used.
+         */
         public get currentVRCamera(): Nullable<Camera> {
             if (this._webVRready) {
                 return this._webVRCamera;
@@ -227,15 +272,27 @@ module BABYLON {
             }
         }
 
+        /**
+         * The webVRCamera which is used when in VR.
+         */
         public get webVRCamera(): WebVRFreeCamera {
             return this._webVRCamera;
         }
 
+        /**
+         * The deviceOrientationCamera that is used as a fallback when vr device is not connected.
+         */
         public get vrDeviceOrientationCamera(): Nullable<VRDeviceOrientationFreeCamera> {
             return this._vrDeviceOrientationCamera;
         }
 
-        constructor(scene: Scene, public webVROptions: VRExperienceHelperOptions = {}) {
+        /**
+         * Instantiates a VRExperienceHelper.
+         * Helps to quickly add VR support to an existing scene.
+         * @param scene The scene the VRExperienceHelper belongs to.
+         * @param webVROptions Options to modify the vr experience helper's behavior.
+         */
+        constructor(scene: Scene, /** Options to modify the vr experience helper's behavior. */public webVROptions: VRExperienceHelperOptions = {}) {
             this._scene = scene;
             this._canvas = scene.getEngine().getRenderingCanvas();
 
@@ -581,10 +638,16 @@ module BABYLON {
             }
         }
 
+        /**
+         * The position of the vr experience helper.
+         */
         public get position(): Vector3 {
             return this._position;
         }
 
+        /**
+         * Sets the position of the vr experience helper.
+         */
         public set position(value: Vector3) {
             this._position = value;
 
@@ -593,6 +656,9 @@ module BABYLON {
             }
         }
 
+        /**
+         * Enables controllers and user interactions suck as selecting and object or clicking on an object.
+         */
         public enableInteractions() {
             if (!this._interactionsEnabled) {
                 this._interactionsRequested = true;
@@ -644,6 +710,10 @@ module BABYLON {
             return false;
         }
 
+        /**
+         * Adds a floor mesh to be used for teleportation.
+         * @param floorMesh the mesh to be used for teleportation.
+         */
         public addFloorMesh(floorMesh: Mesh): void {
             if (!this._floorMeshesCollection) {
                 return;
@@ -656,6 +726,10 @@ module BABYLON {
             this._floorMeshesCollection.push(floorMesh);
         }
 
+        /**
+         * Removes a floor mesh from being used for teleportation.
+         * @param floorMesh the mesh to be removed.
+         */
         public removeFloorMesh(floorMesh: Mesh): void {
             if (!this._floorMeshesCollection) {
                 return
@@ -667,6 +741,10 @@ module BABYLON {
             }
         }
 
+        /**
+         * Enables interactions and teleportation using the VR controllers and gaze.
+         * @param vrTeleportationOptions options to modify teleportation behavior.
+         */
         public enableTeleportation(vrTeleportationOptions: VRTeleportationOptions = {}) {
             if (!this._teleportationInitialized) {
                 this._teleportationRequested = true;
@@ -1463,6 +1541,10 @@ module BABYLON {
             }
         }
 
+        /**
+         * Sets the color of the laser ray from the vr controllers.
+         * @param color new color for the ray.
+         */
         public changeLaserColor(color: Color3) {
             if (this._leftLaserPointer && this._leftLaserPointer.material) {
                 (<StandardMaterial>this._leftLaserPointer.material).emissiveColor = color;
@@ -1472,12 +1554,19 @@ module BABYLON {
             }
         }
 
+        /**
+         * Sets the color of the ray from the vr headsets gaze.
+         * @param color new color for the ray.
+         */
         public changeGazeColor(color: Color3) {
             if (this._gazeTracker.material) {
                 (<StandardMaterial>this._gazeTracker.material).emissiveColor = color;
             }
         }
 
+        /**
+         * Exits VR and disposes of the vr experience helper
+         */
         public dispose() {
             if (this.isInVRMode) {
                 this.exitVR();
@@ -1535,6 +1624,10 @@ module BABYLON {
             this._scene.unregisterBeforeRender(this.beforeRender);
         }
 
+        /**
+         * Gets the name of the VRExperienceHelper class
+         * @returns "VRExperienceHelper"
+         */
         public getClassName(): string {
             return "VRExperienceHelper";
         }

+ 204 - 26
src/Cameras/VR/babylon.webVRCamera.ts

@@ -4,45 +4,135 @@ declare var VRFrameData: any;
 
 module BABYLON {
     /**
-     * This is a copy of VRPose.
+     * This is a copy of VRPose. See https://developer.mozilla.org/en-US/docs/Web/API/VRPose
      * IMPORTANT!! The data is right-hand data.
      * @export
      * @interface DevicePose
      */
     export interface DevicePose {
+        /**
+         * The position of the device, values in array are [x,y,z].
+         */
         readonly position?: Float32Array;
+        /**
+         * The linearVelocity of the device, values in array are [x,y,z].
+         */
         readonly linearVelocity?: Float32Array;
+        /**
+         * The linearAcceleration of the device, values in array are [x,y,z].
+         */
         readonly linearAcceleration?: Float32Array;
 
+        /**
+         * The orientation of the device in a quaternion array, values in array are [x,y,z,w].
+         */
         readonly orientation?: Float32Array;
+        /**
+         * The angularVelocity of the device, values in array are [x,y,z].
+         */
         readonly angularVelocity?: Float32Array;
+        /**
+         * The angularAcceleration of the device, values in array are [x,y,z].
+         */
         readonly angularAcceleration?: Float32Array;
     }
 
+     /**
+     * Interface representing a pose controlled object in Babylon.
+     * A pose controlled object has both regular pose values as well as pose values 
+     * from an external device such as a VR head mounted display
+     */
     export interface PoseControlled {
+        /**
+         * The position of the object in babylon space.
+         */
         position: Vector3;
+        /**
+         * The rotation quaternion of the object in babylon space.
+         */
         rotationQuaternion: Quaternion;
+        /**
+         * The position of the device in babylon space.
+         */
         devicePosition?: Vector3;
+        /**
+         * The rotation quaternion of the device in babylon space.
+         */
         deviceRotationQuaternion: Quaternion;
+        /**
+         * The raw pose coming from the device.
+         */
         rawPose: Nullable<DevicePose>;
+        /**
+         * The scale of the device to be used when translating from device space to babylon space.
+         */
         deviceScaleFactor: number;
+        /**
+         * Updates the poseControlled values based on the input device pose.
+         * @param poseData the pose data to update the object with
+         */
         updateFromDevice(poseData: DevicePose): void;
     }
 
+    /**
+     * Set of options to customize the webVRCamera
+     */
     export interface WebVROptions {
-        trackPosition?: boolean; //for the sake of your users - set it to true.
+        /**
+         * Sets if the webVR camera should be tracked to the vrDevice. (default: true)
+         */
+        trackPosition?: boolean;
+        /**
+         * Sets the scale of the vrDevice in babylon space. (default: 1)
+         */
         positionScale?: number;
-        displayName?: string; //if there are more than one VRDisplays.
-        controllerMeshes?: boolean; // should the native controller meshes be initialized
-        defaultLightingOnControllers?: boolean; // creating a default HemiLight only on controllers
-        useCustomVRButton?: boolean; // if you don't want to use the default VR button of the helper
-        customVRButton?: HTMLButtonElement; //if you'd like to provide your own button to the VRHelper
-        rayLength?: number; // to change the length of the ray for gaze/controllers.
-        defaultHeight?: number; // to change the default offset from the ground to account for user's height
+        /**
+         * If there are more than one VRDisplays, this will choose the display matching this name. (default: pick first vrDisplay)
+         */
+        displayName?: string;
+        /**
+         * Should the native controller meshes be initialized. (default: true)
+         */
+        controllerMeshes?: boolean;
+        /**
+         * Creating a default HemiLight only on controllers. (default: true)
+         */
+        defaultLightingOnControllers?: boolean;
+        /**
+         * If you don't want to use the default VR button of the helper. (default: false)
+         */
+        useCustomVRButton?: boolean;
+
+        /**
+         * If you'd like to provide your own button to the VRHelper. (default: standard babylon vr button)
+         */
+        customVRButton?: HTMLButtonElement;
+
+        /**
+         * To change the length of the ray for gaze/controllers. (default: 100)
+         */
+        rayLength?: number;
+
+        /**
+         * To change the default offset from the ground to account for user's height. (default: 1.7)
+         */
+        defaultHeight?: number;
+
     }
 
+    /**
+     * This represents a WebVR camera.
+     * The WebVR camera is Babylon's simple interface to interaction with Windows Mixed Reality, HTC Vive and Oculus Rift.
+     * @example http://doc.babylonjs.com/how_to/webvr_camera
+     */
     export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
+        /**
+         * The vrDisplay tied to the camera. See https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay
+         */
         public _vrDevice: any = null;
+        /**
+         * The rawPose of the vrDevice.
+         */
         public rawPose: Nullable<DevicePose> = null;
         private _onVREnabled: (success: boolean) => void;
         private _specsVersion: string = "1.1";
@@ -58,24 +148,51 @@ module BABYLON {
 
         private _standingMatrix: Nullable<Matrix> = null;
 
-        // Represents device position and rotation in babylon space
+        /**
+         * Represents device position in babylon space.
+         */
         public devicePosition = Vector3.Zero();
+        /**
+         * Represents device rotation in babylon space.
+         */
         public deviceRotationQuaternion = Quaternion.Identity();
 
+        /**
+         * The scale of the device to be used when translating from device space to babylon space.
+         */
         public deviceScaleFactor: number = 1;
 
         private _deviceToWorld = Matrix.Identity();
         private _worldToDevice = Matrix.Identity();
 
+        /**
+         * References to the webVR controllers for the vrDevice.
+         */
         public controllers: Array<WebVRController> = [];
+        /**
+         * Emits an event when a controller is attached.
+         */
         public onControllersAttachedObservable = new Observable<Array<WebVRController>>();
+        /**
+         * Emits an event when a controller's mesh has been loaded;
+         */
         public onControllerMeshLoadedObservable = new Observable<WebVRController>();
-
-        public rigParenting: boolean = true; // should the rig cameras be used as parent instead of this camera.
+        /**
+         * If the rig cameras be used as parent instead of this camera.
+         */
+        public rigParenting: boolean = true;
 
         private _lightOnControllers: HemisphericLight;
 
-        private _defaultHeight = 0;
+        private _defaultHeight?: number = undefined;
+
+        /**
+         * Instantiates a WebVRFreeCamera.
+         * @param name The name of the WebVRFreeCamera
+         * @param position The starting anchor position for the camera
+         * @param scene The scene the camera belongs to
+         * @param webVROptions a set of customizable options for the webVRCamera
+         */
         constructor(name: string, position: Vector3, scene: Scene, private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
             this._cache.position = Vector3.Zero();
@@ -164,18 +281,26 @@ module BABYLON {
             });
         }
 
-        public deviceDistanceToRoomGround = () => {
-            if (this._standingMatrix) {
+        /**
+         * Gets the device distance from the ground.
+         * @returns the distance from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
+         */
+        public deviceDistanceToRoomGround(): number {
+            if (this._standingMatrix && this._defaultHeight === undefined) {
                 // Add standing matrix offset to get real offset from ground in room
                 this._standingMatrix.getTranslationToRef(this._workingVector);
                 return this._deviceRoomPosition.y + this._workingVector.y
-            } else {
-                return this._defaultHeight;
             }
+            //If VRDisplay does not inform stage parameters and no default height is set we fallback to zero.
+            return this._defaultHeight || 0;            
         }
 
-        public useStandingMatrix = (callback = (bool: boolean) => { }) => {
-            // Use standing matrix if availible
+        /**
+         * Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
+         * @param callback will be called when the standing matrix is set. Callback parameter is if the standing matrix is supported.
+         */
+        public useStandingMatrix(callback = (bool: boolean) => { }) {
+            // Use standing matrix if available
             if (!navigator || !navigator.getVRDisplays) {
                 callback(false);
             } else {
@@ -192,17 +317,25 @@ module BABYLON {
                                 }
                             });
                         }
-                        callback(true)
+                        callback(true);
                     }
-                })
+                });
             }
         }
 
+        /**
+         * Disposes the camera
+         */
         public dispose(): void {
             this.getEngine().onVRRequestPresentComplete.removeCallback(this._onVREnabled);
             super.dispose();
         }
 
+        /**
+         * Gets a vrController by name.
+         * @param name The name of the controller to retreive
+         * @returns the controller matching the name specified or null if not found
+         */
         public getControllerByName(name: string): Nullable<WebVRController> {
             for (var gp of this.controllers) {
                 if (gp.hand === name) {
@@ -214,6 +347,9 @@ module BABYLON {
         }
 
         private _leftController: Nullable<WebVRController>;
+        /**
+         * The controller corrisponding to the users left hand.
+         */
         public get leftController(): Nullable<WebVRController> {
             if (!this._leftController) {
                 this._leftController = this.getControllerByName("left");
@@ -223,6 +359,9 @@ module BABYLON {
         };
 
         private _rightController: Nullable<WebVRController>;
+        /**
+         * The controller corrisponding to the users right hand.
+         */
         public get rightController(): Nullable<WebVRController> {
             if (!this._rightController) {
                 this._rightController = this.getControllerByName("right");
@@ -232,7 +371,11 @@ module BABYLON {
         };
 
 
-
+        /**
+         * Casts a ray forward from the vrCamera's gaze.
+         * @param length Length of the ray (default: 100)
+         * @returns the ray corrisponding to the gaze
+         */
         public getForwardRay(length = 100): Ray {
             if (this.leftCamera) {
                 // Use left eye to avoid computation to compute center on every call
@@ -243,6 +386,9 @@ module BABYLON {
             }
         }
 
+        /**
+         * Updates the camera based on device's frame data
+         */
         public _checkInputs(): void {
             if (this._vrDevice && this._vrDevice.isPresenting) {
                 this._vrDevice.getFrameData(this._frameData);
@@ -253,6 +399,10 @@ module BABYLON {
             super._checkInputs();
         }
 
+        /**
+         * Updates the poseControlled values based on the input device pose.
+         * @param poseData Pose coming from the device
+         */
         updateFromDevice(poseData: DevicePose) {
             if (poseData && poseData.orientation) {
                 this.rawPose = poseData;
@@ -277,10 +427,8 @@ module BABYLON {
          * within a user-interaction callback. Example:
          * <pre> scene.onPointerDown = function() { camera.attachControl(canvas); }</pre>
          * 
-         * @param {HTMLElement} element 
-         * @param {boolean} [noPreventDefault] 
-         * 
-         * @memberOf WebVRFreeCamera
+         * @param element html element to attach the vrDevice to
+         * @param noPreventDefault prevent the default html element operation when attaching the vrDevice
          */
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
             super.attachControl(element, noPreventDefault);
@@ -293,6 +441,11 @@ module BABYLON {
             }
         }
 
+        /**
+         * Detaches the camera from the html element and disables VR
+         * 
+         * @param element html element to detach from
+         */
         public detachControl(element: HTMLElement): void {
             this.getScene().gamepadManager.onGamepadConnectedObservable.remove(this._onGamepadConnectedObserver);
             this.getScene().gamepadManager.onGamepadDisconnectedObservable.remove(this._onGamepadDisconnectedObserver);
@@ -302,16 +455,26 @@ module BABYLON {
             this.getEngine().disableVR();
         }
 
+        /**
+         * @returns the name of this class
+         */
         public getClassName(): string {
             return "WebVRFreeCamera";
         }
 
+        /**
+         * Calls resetPose on the vrDisplay
+         * See: https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay/resetPose
+         */
         public resetToCurrentRotation() {
             //uses the vrDisplay's "resetPose()".
             //pitch and roll won't be affected.
             this._vrDevice.resetPose();
         }
 
+        /**
+         * Updates the rig cameras (left and right eye)
+         */
         public _updateRigCameras() {
             var camLeft = <TargetCamera>this._rigCameras[0];
             var camRight = <TargetCamera>this._rigCameras[1];
@@ -328,6 +491,10 @@ module BABYLON {
 
         private updateCacheCalled: boolean;
 
+        /**
+         * Updates the cached values of the camera
+         * @param ignoreParentClass ignores updating the parent class's cache (default: false)
+         */
         public _updateCache(ignoreParentClass?: boolean): void {
             if (!this.rotationQuaternion.equals(this._cache.rotationQuaternion) || !this.position.equals(this._cache.position)) {
                 // Update to ensure devicePosition is up to date with most recent _deviceRoomPosition
@@ -367,6 +534,9 @@ module BABYLON {
             this.updateCacheCalled = false;
         }
 
+        /**
+         * Updates the current device position and rotation in the babylon world
+         */
         public update() {
             // Get current device position in babylon world
             Vector3.TransformCoordinatesToRef(this._deviceRoomPosition, this._deviceToWorld, this.devicePosition);
@@ -378,6 +548,11 @@ module BABYLON {
 
             super.update();
         }
+
+        /**
+         * Gets the view matrix of this camera (Always set to identity as left and right eye cameras contain the actual view matrix)
+         * @returns an identity matrix
+         */
         public _getViewMatrix(): Matrix {
             return Matrix.Identity();
         }
@@ -447,6 +622,9 @@ module BABYLON {
         private _onGamepadConnectedObserver: Nullable<Observer<Gamepad>>;
         private _onGamepadDisconnectedObserver: Nullable<Observer<Gamepad>>;
 
+        /**
+         * Initializes the controllers and their meshes
+         */
         public initControllers() {
             this.controllers = [];
 

+ 11 - 9
src/Cameras/babylon.camera.ts

@@ -34,7 +34,7 @@
             return Camera._FOVMODE_VERTICAL_FIXED;
         }
 
-		/**
+        /**
          * This setting aligns the left and right bounds of the viewport to the left and right bounds of the camera frustum.
          *
          */
@@ -78,6 +78,10 @@
         @serializeAsVector3()
         public position: Vector3;
 
+        /**
+         * The vector the camera should consider as up.
+         * (default is Vector3(0, 1, 0) aka Vector3.Up())
+         */
         @serializeAsVector3()
         public upVector = Vector3.Up();
 
@@ -94,8 +98,7 @@
         public orthoTop: Nullable<number> = null;
 
         /**
-         * default : 0.8
-         * FOV is set in Radians.
+         * FOV is set in Radians. (default is 0.8)
          */
         @serialize()
         public fov = 0.8;
@@ -116,16 +119,15 @@
         public viewport = new Viewport(0, 0, 1.0, 1.0);
 
         /**
-        * Restricts the camera to viewing objects with the same layerMask.
-        * A camera with a layerMask of 1 will render meshes with no layerMask and meshes with a layerMask of 1.
-        */
+         * Restricts the camera to viewing objects with the same layerMask.
+         * A camera with a layerMask of 1 will render mesh.layerMask & camera.layerMask!== 0
+         */
         @serialize()
         public layerMask: number = 0x0FFFFFFF;
 
         /**
-        * default : FOVMODE_VERTICAL_FIXED
-        * fovMode sets the camera frustum bounds to the viewport bounds.
-        */
+         * fovMode sets the camera frustum bounds to the viewport bounds. (default is FOVMODE_VERTICAL_FIXED)
+         */
         @serialize()
         public fovMode: number = Camera.FOVMODE_VERTICAL_FIXED;
 

+ 14 - 1
src/Cameras/babylon.cameraInputsManager.ts

@@ -28,6 +28,12 @@ module BABYLON {
             this.checkInputs = () => { };
         }
 
+        /**
+         * Add an input method to a camera.
+         * builtin inputs example: camera.inputs.addGamepad();
+         * custom inputs example: camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
+         * @param input camera input method
+         */
         public add(input: ICameraInput<TCamera>) {
             var type = input.getSimpleName();
             if (this.attached[type]) {
@@ -49,7 +55,11 @@ module BABYLON {
                 input.attachControl(this.attachedElement);
             }
         }
-
+        /**
+         * Remove a specific input method from a camera
+         * example: camera.inputs.remove(camera.inputs.attached.mouse);
+         * @param inputToRemove camera input method
+         */
         public remove(inputToRemove: ICameraInput<TCamera>) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
@@ -129,6 +139,9 @@ module BABYLON {
             }
         }
 
+        /**
+         * Remove all attached input methods from a camera
+         */
         public clear() {
             if (this.attachedElement) {
                 this.detachElement(this.attachedElement, true);

+ 25 - 2
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 start 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,12 @@ 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;
 
@@ -45,4 +68,4 @@ module BABYLON {
             this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
         }
     }
-}
+}

+ 9 - 1
src/Cameras/babylon.freeCamera.ts

@@ -15,6 +15,10 @@
         public inputs: FreeCameraInputsManager;
 
         //-- begin properties for backward compatibility for inputs
+        /**
+         * Gets the input sensibility for a mouse input. (default is 2000.0)
+         * Higher values reduce sensitivity.
+         */
         public get angularSensibility(): number {
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
             if (mouse)
@@ -23,6 +27,10 @@
             return 0;
         }
 
+        /**
+         * Sets the input sensibility for a mouse input. (default is 2000.0)
+         * Higher values reduce sensitivity.
+         */
         public set angularSensibility(value: number) {
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
             if (mouse)
@@ -212,4 +220,4 @@
             return "FreeCamera";
         }
     }
-} 
+}

+ 15 - 1
src/Collisions/babylon.collisionCoordinator.ts

@@ -44,12 +44,26 @@ module BABYLON {
         boxMaximum: Array<number>;
     }
 
+    /**
+     * Interface describing the value associated with a geometry
+     */
     export interface SerializedGeometry {
+        /**
+         * Defines the unique ID of the geometry
+         */
         id: string;
+        /**
+         * Defines the array containing the positions
+         */
         positions: Float32Array;
+        /**
+         * Defines the array containing the indices
+         */        
         indices: Uint32Array;
+        /**
+         * Defines the array containing the normals
+         */        
         normals: Float32Array;
-        //uvs?: Float32Array;
     }
 
     export interface BabylonMessage {

+ 39 - 20
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>;
@@ -824,6 +825,10 @@
          * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
         constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio: boolean = false) {
+
+            // Register promises
+            PromisePolyfill.Apply();
+
             let canvas: Nullable<HTMLCanvasElement> = null;
             Engine.Instances.push(this);
 
@@ -1091,6 +1096,8 @@
                 this._currentBufferPointers[i] = new BufferPointer();
             }
 
+            this._linkTrackers(this._firstBoundInternalTextureTracker, this._lastBoundInternalTextureTracker);
+
             // Load WebVR Devices
             if (options.autoEnableWebVR) {
                 this.initWebVR();
@@ -4740,14 +4747,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.disableTextureBindingOptimization || 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 +4784,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 +4792,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 +4846,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;
@@ -5269,7 +5288,7 @@
             var index = Engine.Instances.indexOf(this);
 
             if (index >= 0) {
-                delete Engine.Instances[index];
+                Engine.Instances.splice(index, 1);
             }
 
             this._workingCanvas = null;
@@ -5730,7 +5749,7 @@
             let request = Tools.LoadFile(url, onSuccess, onProgress, database, useArrayBuffer, onError);
             this._activeRequests.push(request);
             request.onCompleteObservable.add(request => {
-                delete this._activeRequests[this._activeRequests.indexOf(request)];
+                this._activeRequests.splice(this._activeRequests.indexOf(request), 1);
             });
             return request;
         }

+ 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;
+    }
+}

+ 212 - 93
src/Materials/Textures/babylon.videoTexture.ts

@@ -1,44 +1,127 @@
 module BABYLON {
+    /**
+     * Settings for finer control over video usage
+     */
+    export interface VideoTextureSettings {
+        /**
+         * Applies `autoplay` to video, if specified
+         */
+        autoPlay?: boolean;
+
+        /**
+         * Applies `loop` to video, if specified
+         */
+        loop?: boolean;
+
+        /**
+         * Automatically updates internal texture from video at every frame in the render loop
+         */
+        autoUpdateTexture: boolean;
+    }
+
     export class VideoTexture extends Texture {
-        public video: HTMLVideoElement;
+        /**
+         * Tells whether textures will be updated automatically or user is required to call `updateTexture` manually
+         */
+        public readonly autoUpdateTexture: boolean;
 
-        private _autoLaunch = true;
-        private _lastUpdate: number;
-        private _generateMipMaps: boolean
-        private _setTextureReady: () => void;
+        /**
+         * The video instance used by the texture internally
+         */
+        public readonly video: HTMLVideoElement;
+
+        private _generateMipMaps: boolean;
         private _engine: Engine;
 
         /**
          * Creates a video texture.
-         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
-         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
+         * Sample : https://doc.babylonjs.com/how_to/video_texture
+         * @param {string | null} name optional name, will detect from video source, if not defined
+         * @param {(string | string[] | HTMLVideoElement)} src can be used to provide an url, array of urls or an already setup HTML video element.
          * @param {BABYLON.Scene} scene is obviously the current scene.
          * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
          * @param {boolean} invertY is false by default but can be used to invert video on Y axis
          * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
+         * @param {VideoTextureSettings} [settings] allows finer control over video usage
          */
-        constructor(name: string, urlsOrVideo: string[] | HTMLVideoElement, scene: Scene, generateMipMaps = false, invertY = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+        constructor(
+            name: Nullable<string>,
+            src: string | string[] | HTMLVideoElement,
+            scene: Nullable<Scene>,
+            generateMipMaps = false,
+            invertY = false,
+            samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE,
+            settings: VideoTextureSettings = {
+                autoPlay: true,
+                loop: true,
+                autoUpdateTexture: true,
+            }
+        ) {
             super(null, scene, !generateMipMaps, invertY);
 
-            var urls: Nullable<string[]> = null;
-            this.name = name;
+            this._engine = this.getScene()!.getEngine();
+            this._generateMipMaps = generateMipMaps;
+            this._samplingMode = samplingMode;
+            this.autoUpdateTexture = settings.autoUpdateTexture;
 
-            if (urlsOrVideo instanceof HTMLVideoElement) {
-                this.video = <any>urlsOrVideo;
-            } else {
-                urls = urlsOrVideo;
+            this.name = name || this._getName(src);
+            this.video = this._getVideo(src);
 
-                this.video = document.createElement("video");
-                this.video.autoplay = false;
-                this.video.loop = true;
-                Tools.SetCorsBehavior(urls, this.video);
+            if (settings.autoPlay !== undefined) {
+                this.video.autoplay = settings.autoPlay;
+            }
+            if (settings.loop !== undefined) {
+                this.video.loop = settings.loop;
             }
 
-            this._engine = (<Scene>this.getScene()).getEngine();
-            this._generateMipMaps = generateMipMaps;
-            this._samplingMode = samplingMode;
+            this.video.addEventListener("canplay", this._createInternalTexture);
+            this.video.addEventListener("paused", this._updateInternalTexture);
+            this.video.addEventListener("seeked", this._updateInternalTexture);
+            this.video.addEventListener("emptied", this.reset);
+
+            if (this.video.readyState >= this.video.HAVE_CURRENT_DATA) {
+                this._createInternalTexture();
+            }
+        }
+
+        private _getName(src: string | string[] | HTMLVideoElement): string {
+            if (src instanceof HTMLVideoElement) {
+                return src.currentSrc;
+            }
+    
+            if (typeof src === "object") {
+                return src.toString();
+            }
+    
+            return src;
+        };
+    
+        private _getVideo(src: string | string[] | HTMLVideoElement): HTMLVideoElement {
+            if (src instanceof HTMLVideoElement) {
+                return src;
+            }
+            const video: HTMLVideoElement = document.createElement("video");
+            if (typeof src === "string") {
+                video.src = src;
+            } else {
+                src.forEach(url => {
+                    const source = document.createElement("source");
+                    source.src = url;
+                    video.appendChild(source);
+                });
+            }
+            return video;
+        };
+
+        private _createInternalTexture = (): void => {
+            if (this._texture != null) {
+                return;
+            }
 
-            if (!this._engine.needPOTTextures || (Tools.IsExponentOfTwo(this.video.videoWidth) && Tools.IsExponentOfTwo(this.video.videoHeight))) {
+            if (
+                !this._engine.needPOTTextures ||
+                (Tools.IsExponentOfTwo(this.video.videoWidth) && Tools.IsExponentOfTwo(this.video.videoHeight))
+            ) {
                 this.wrapU = Texture.WRAP_ADDRESSMODE;
                 this.wrapV = Texture.WRAP_ADDRESSMODE;
             } else {
@@ -47,110 +130,146 @@
                 this._generateMipMaps = false;
             }
 
-            if (urls) {
-                this.video.addEventListener("canplay", () => {
-                    if (this._texture === undefined){ 
-                      this._createTexture();
-                    }
-                });
-                urls.forEach(url => {
-                    var source = document.createElement("source");
-                    source.src = url;
-                    this.video.appendChild(source);
-                });
-            } else {
-                this._createTexture();
-            }
-
-            this._lastUpdate = Tools.Now;
-        }
+            this._texture = this._engine.createDynamicTexture(
+                this.video.videoWidth,
+                this.video.videoHeight,
+                this._generateMipMaps,
+                this._samplingMode
+            );
+            this._texture.width;
 
-        private __setTextureReady(): void {
-            if (this._texture) {
-                this._texture.isReady = true;
-            }
-        }
+            this._updateInternalTexture();
 
-        private _createTexture(): void {
-            this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
+            this._texture.isReady = true;
+        };
 
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
+        private reset = (): void => {
+            if (this._texture == null) {
+                return;
             }
-            this._setTextureReady = this.__setTextureReady.bind(this);
-            this.video.addEventListener("playing", this._setTextureReady);
-        }
-
+            this._texture.dispose();
+            this._texture = null;
+        };
 
+        /**
+         * Internal method to initiate `update`.
+         */
         public _rebuild(): void {
             this.update();
         }
 
-        public update(): boolean {
-            var now = Tools.Now;
+        /**
+         * Update Texture in the `auto` mode. Does not do anything if `settings.autoUpdateTexture` is false.
+         */
+        public update(): void {
+            if (!this.autoUpdateTexture) {
+                // Expecting user to call `updateTexture` manually
+                return;
+            }
 
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-                return false;
+            this.updateTexture(true);
+        }
+
+        /**
+         * Update Texture in `manual` mode. Does not do anything if not visible or paused.
+         * @param isVisible Visibility state, detected by user using `scene.getActiveMeshes()` or othervise.
+         */
+        public updateTexture(isVisible: boolean): void {
+            if (!isVisible) {
+                return;
+            }
+            if (this.video.paused) {
+                return;
+            }
+            this._updateInternalTexture();
+        }
+
+        protected _updateInternalTexture = (e?: Event): void => {
+            if (this._texture == null || !this._texture.isReady) {
+                return;
+            }
+            if (this.video.readyState < this.video.HAVE_CURRENT_DATA) {
+                return;
             }
 
-            this._lastUpdate = now;
             this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
+        };
+
+        /**
+         * Change video content. Changing video instance or setting multiple urls (as in constructor) is not supported.
+         * @param url New url.
+         */
+        public updateURL(url: string): void {
+            this.video.src = url;
         }
 
         public dispose(): void {
             super.dispose();
-            this.video.removeEventListener("playing", this._setTextureReady);
+            this.video.removeEventListener("canplay", this._createInternalTexture);
+            this.video.removeEventListener("paused", this._updateInternalTexture);
+            this.video.removeEventListener("seeked", this._updateInternalTexture);
+            this.video.removeEventListener("emptied", this.reset);
         }
 
-        public static CreateFromWebCam(scene: Scene, onReady: (videoTexture: VideoTexture) => void, constraints: {
-            minWidth: number,
-            maxWidth: number,
-            minHeight: number,
-            maxHeight: number,
-            deviceId: string
-        }): void {
+        public static CreateFromWebCam(
+            scene: Scene,
+            onReady: (videoTexture: VideoTexture) => void,
+            constraints: {
+                minWidth: number;
+                maxWidth: number;
+                minHeight: number;
+                maxHeight: number;
+                deviceId: string;
+            }
+        ): void {
             var video = document.createElement("video");
             var constraintsDeviceId;
             if (constraints && constraints.deviceId) {
                 constraintsDeviceId = {
-                    exact: constraints.deviceId
-                }
+                    exact: constraints.deviceId,
+                };
             }
 
-            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+            navigator.getUserMedia =
+                navigator.getUserMedia ||
+                navigator.webkitGetUserMedia ||
+                navigator.mozGetUserMedia ||
+                navigator.msGetUserMedia;
             window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
 
             if (navigator.getUserMedia) {
-                navigator.getUserMedia({
-                    video: {
-                        deviceId: constraintsDeviceId,
-                        width: {
-                            min: (constraints && constraints.minWidth) || 256,
-                            max: (constraints && constraints.maxWidth) || 640
+                navigator.getUserMedia(
+                    {
+                        video: {
+                            deviceId: constraintsDeviceId,
+                            width: {
+                                min: (constraints && constraints.minWidth) || 256,
+                                max: (constraints && constraints.maxWidth) || 640,
+                            },
+                            height: {
+                                min: (constraints && constraints.minHeight) || 256,
+                                max: (constraints && constraints.maxHeight) || 480,
+                            },
                         },
-                        height: {
-                            min: (constraints && constraints.minHeight) || 256,
-                            max: (constraints && constraints.maxHeight) || 480
+                    },
+                    (stream: any) => {
+                        if (video.mozSrcObject !== undefined) {
+                            // hack for Firefox < 19
+                            video.mozSrcObject = stream;
+                        } else {
+                            video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
                         }
-                    }
-                }, (stream: any) => {
 
-                    if (video.mozSrcObject !== undefined) { // hack for Firefox < 19
-                        video.mozSrcObject = stream;
-                    } else {
-                        video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
-                    }
-
-                    video.play();
+                        video.play();
 
-                    if (onReady) {
-                        onReady(new VideoTexture("video", video, scene, true, true));
+                        if (onReady) {
+                            onReady(new VideoTexture("video", video, scene, true, true));
+                        }
+                    },
+                    function(e: MediaStreamError) {
+                        Tools.Error(e.name);
                     }
-                }, function (e: MediaStreamError) {
-                    Tools.Error(e.name);
-                });
+                );
             }
         }
     }

+ 49 - 0
src/Math/babylon.math.ts

@@ -126,6 +126,21 @@
         }
 
         /**
+         * Clamps the rgb values by the min and max values and stores the result into "result".
+         * Returns the unmodified current Color3.
+         * @param min - minimum clamping value.  Defaults to 0
+         * @param max - maximum clamping value.  Defaults to 1
+         * @param result - color to store the result into.
+         * @returns - the original Color3
+         */
+        public clampToRef(min: number = 0, max: number = 1, result: Color3): Color3 {
+            result.r = BABYLON.Scalar.Clamp(this.r, min, max);
+            result.g = BABYLON.Scalar.Clamp(this.g, min, max);
+            result.b = BABYLON.Scalar.Clamp(this.b, min, max);
+            return this;
+        }
+
+        /**
          * Returns a new Color3 set with the added values of the current Color3 and of the passed one.  
          */
         public add(otherColor: Color3): Color3 {
@@ -389,6 +404,22 @@
         }
 
         /**
+         * Clamps the rgb values by the min and max values and stores the result into "result".
+         * Returns the unmodified current Color4.
+         * @param min - minimum clamping value.  Defaults to 0
+         * @param max - maximum clamping value.  Defaults to 1
+         * @param result - color to store the result into.
+         * @returns - the original Color4
+         */
+        public clampToRef(min: number = 0, max: number = 1, result: Color4): Color4 {
+            result.r = BABYLON.Scalar.Clamp(this.r, min, max);
+            result.g = BABYLON.Scalar.Clamp(this.g, min, max);
+            result.b = BABYLON.Scalar.Clamp(this.b, min, max);
+            result.a = BABYLON.Scalar.Clamp(this.a, min, max);
+            return this;
+        }
+
+        /**
           * Multipy an RGBA Color4 value by another and return a new Color4 object
           * @param color The Color4 (RGBA) value to multiply by
           * @returns A new Color4.
@@ -1460,6 +1491,24 @@
         }
 
         /**
+         * Get angle between two vectors.
+         * @param vector0 angle between vector0 and vector1
+         * @param vector1 angle between vector0 and vector1
+         * @param normal direction of the normal.
+         * @return the angle between vector0 and vector1.
+         */
+        public static GetAngleBetweenVectors(vector0: Vector3, vector1: Vector3, normal: Vector3):number {
+            var v0:Vector3 = vector0.clone().normalize();
+            var v1:Vector3 = vector1.clone().normalize();
+            var dot:number = Vector3.Dot(v0, v1);
+            var n = Vector3.Cross(v0, v1);
+            if (Vector3.Dot(n, normal) > 0) {
+                return Math.acos(dot);
+            }
+            return -Math.acos(dot);
+        }
+
+        /**
          * Returns a new Vector3 set from the index "offset" of the passed array.
          */
         public static FromArray(array: ArrayLike<number>, offset?: number): Vector3 {

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

@@ -539,6 +539,8 @@
                 return;
             }
             this._lightSources.splice(index, 1);
+
+            this._markSubMeshesAsLightDirty();
         }
 
         private _markSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 601 - 35
src/Mesh/babylon.geometry.ts


+ 11 - 3
src/Mesh/babylon.mesh.ts

@@ -297,6 +297,14 @@
             return this._LODLevels.length > 0;
         }
 
+        /**
+         * Gets the list of {BABYLON.MeshLODLevel} associated with the current mesh
+         * @returns an array of {BABYLON.MeshLODLevel} 
+         */
+        public getLODLevels(): MeshLODLevel[] {
+            return this._LODLevels;
+        }
+
         private _sortLODLevels(): void {
             this._LODLevels.sort((a, b) => {
                 if (a.distance < b.distance) {
@@ -767,7 +775,7 @@
             var data = this.getVerticesData(VertexBuffer.PositionKind);
 
             if (data && applySkeleton && this.skeleton) {
-                data = data.slice();
+                data = Tools.Slice(data);
 
                 var matricesIndicesData = this.getVerticesData(VertexBuffer.MatricesIndicesKind);
                 var matricesWeightsData = this.getVerticesData(VertexBuffer.MatricesWeightsKind);
@@ -2492,14 +2500,14 @@
                     mesh._delayInfo.push(VertexBuffer.MatricesWeightsKind);
                 }
 
-                mesh._delayLoadingFunction = Geometry.ImportGeometry;
+                mesh._delayLoadingFunction = Geometry._ImportGeometry;
 
                 if (SceneLoader.ForceFullSceneLoadingForIncremental) {
                     mesh._checkDelayState();
                 }
 
             } else {
-                Geometry.ImportGeometry(parsedMesh, mesh);
+                Geometry._ImportGeometry(parsedMesh, mesh);
             }
 
             // Material

+ 1 - 0
src/Mesh/babylon.vertexBuffer.ts

@@ -145,6 +145,7 @@
 
         /**
          * Updates the underlying WebGLBuffer according to the passed numeric array or Float32Array.  
+         * This function will create a new buffer if the current one is not updatable
          * Returns the updated WebGLBuffer.  
          */
         public update(data: FloatArray): void {

+ 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 friendly name 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);
         }
     }

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

@@ -131,7 +131,7 @@
             this._scene.resetCachedMaterial();
             this._colorShader.bind(worldMatrix);
 
-            engine.drawElementsType(Material.TriangleFillMode, 0, 24);
+            engine.drawElementsType(Material.LineListDrawMode, 0, 24);
 
             this._colorShader.unbind();
             engine.setDepthFunctionToLessOrEqual();

+ 0 - 0
src/Rendering/babylon.geometryBufferRenderer.ts


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است