瀏覽代碼

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 7 年之前
父節點
當前提交
f6038c4233
共有 100 個文件被更改,包括 31526 次插入29311 次删除
  1. 2 0
      .gitignore
  2. 10627 10433
      Playground/babylon.d.txt
  3. 1 1
      Playground/debug.html
  4. 1 1
      Playground/frame.html
  5. 1 1
      Playground/full.html
  6. 1 1
      Playground/index-local.html
  7. 1 1
      Playground/index.html
  8. 1 1
      Playground/indexStable.html
  9. 1 1
      Playground/zipContent/index.html
  10. 11 9
      Tools/Gulp/config.json
  11. 5 1
      Tools/Gulp/gulp-addModuleExports.js
  12. 8 1
      Tools/Gulp/gulpfile.js
  13. 1 0
      Viewer/dist/_redirects
  14. 15 18
      Viewer/src/configuration/loader.ts
  15. 0 26
      Viewer/src/helper.ts
  16. 47 24
      Viewer/src/templateManager.ts
  17. 2 2
      Viewer/src/viewer/defaultViewer.ts
  18. 41 7
      Viewer/src/viewer/viewer.ts
  19. 10329 10139
      dist/preview release/babylon.d.ts
  20. 54 54
      dist/preview release/babylon.js
  21. 788 432
      dist/preview release/babylon.max.js
  22. 54 54
      dist/preview release/babylon.worker.js
  23. 3949 3759
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  24. 55 55
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  25. 716 428
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  26. 718 430
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  27. 790 434
      dist/preview release/es6.js
  28. 6 2
      dist/preview release/gui/babylon.gui.d.ts
  29. 24 22
      dist/preview release/gui/babylon.gui.js
  30. 3 3
      dist/preview release/gui/babylon.gui.min.js
  31. 6 2
      dist/preview release/gui/babylon.gui.module.d.ts
  32. 1 1
      dist/preview release/gui/package.json
  33. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  34. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  35. 1 1
      dist/preview release/inspector/package.json
  36. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  37. 6 1
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  38. 39 9
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  39. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  40. 6 1
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  41. 39 9
      dist/preview release/loaders/babylon.glTFFileLoader.js
  42. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  43. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  44. 39 9
      dist/preview release/loaders/babylonjs.loaders.js
  45. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  46. 6 1
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  47. 1 1
      dist/preview release/loaders/package.json
  48. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  49. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  50. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  51. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  52. 1 1
      dist/preview release/materialsLibrary/package.json
  53. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  54. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  55. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  56. 1 1
      dist/preview release/postProcessesLibrary/package.json
  57. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  58. 62 24
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  59. 281 362
      dist/preview release/serializers/babylon.glTF2Serializer.js
  60. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  61. 281 362
      dist/preview release/serializers/babylonjs.serializers.js
  62. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  63. 62 24
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  64. 1 1
      dist/preview release/serializers/package.json
  65. 2 93
      dist/preview release/typedocValidationBaseline.json
  66. 8 24
      dist/preview release/viewer/babylon.viewer.d.ts
  67. 68 67
      dist/preview release/viewer/babylon.viewer.js
  68. 926 517
      dist/preview release/viewer/babylon.viewer.max.js
  69. 4 484
      dist/preview release/viewer/babylon.viewer.module.d.ts
  70. 3 1
      dist/preview release/viewer/package.json
  71. 25 12
      dist/preview release/viewer/readme.md
  72. 9 3
      dist/preview release/what's new.md
  73. 19 19
      gui/src/advancedDynamicTexture.ts
  74. 6 6
      gui/src/controls/control.ts
  75. 26 5
      loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts
  76. 6 0
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  77. 5 1
      loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts
  78. 3 3
      localDev/index.html
  79. 2 2
      package.json
  80. 1 1
      sandbox/index-local.html
  81. 3 4
      sandbox/index.html
  82. 353 412
      serializers/src/glTF/2.0/babylon.glTFExporter.ts
  83. 383 297
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  84. 6 6
      src/Engine/babylon.engine.ts
  85. 4 0
      src/Engine/babylon.nullEngine.ts
  86. 3 1
      src/Helpers/babylon.environmentHelper.ts
  87. 5 1
      src/Materials/Textures/babylon.cubeTexture.ts
  88. 0 6
      src/Math/babylon.math.ts
  89. 163 70
      src/Mesh/Compression/babylon.dracoCompression.ts
  90. 168 0
      src/Particles/babylon.IParticleSystem.ts
  91. 113 15
      src/Particles/babylon.gpuParticleSystem.ts
  92. 7 62
      src/Particles/babylon.particleSystem.ts
  93. 4 1
      src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts
  94. 2 6
      src/PostProcess/babylon.circleOfConfusionPostProcess.ts
  95. 3 4
      src/PostProcess/babylon.depthOfFieldEffect.ts
  96. 36 6
      src/Rendering/babylon.depthRenderer.ts
  97. 23 1
      src/Shaders/default.fragment.fx
  98. 14 1
      src/Shaders/default.vertex.fx
  99. 8 0
      src/Shaders/gpuRenderParticles.fragment.fx
  100. 0 0
      src/Shaders/gpuRenderParticles.vertex.fx

+ 2 - 0
.gitignore

@@ -174,3 +174,5 @@ dist/preview release/package/
 # viewer dist files
 # viewer dist files
 /Viewer/dist/viewer.js
 /Viewer/dist/viewer.js
 /Viewer/dist/viewer.min.js
 /Viewer/dist/viewer.min.js
+dist/preview release/viewer/babylon.d.ts
+Viewer/dist/viewer.max.js

File diff suppressed because it is too large
+ 10627 - 10433
Playground/babylon.d.txt


+ 1 - 1
Playground/debug.html

@@ -37,7 +37,7 @@
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <!-- Babylon.js -->
     <!-- Babylon.js -->
     <script src="https://preview.babylonjs.com/cannon.js"></script>
     <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+    <script src="https://preview.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/babylon.max.js"></script>
     <script src="https://preview.babylonjs.com/babylon.max.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>

+ 1 - 1
Playground/frame.html

@@ -26,7 +26,7 @@
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
     <!-- Babylon.js -->
     <!-- Babylon.js -->
     <script src="https://preview.babylonjs.com/cannon.js"></script>
     <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+    <script src="https://preview.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/babylon.js"></script>
     <script src="https://preview.babylonjs.com/babylon.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>

+ 1 - 1
Playground/full.html

@@ -26,7 +26,7 @@
         <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
         <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
         <!-- Babylon.js -->
         <!-- Babylon.js -->
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/cannon.js"></script>
-        <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+        <script src="https://preview.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
         <script src="https://preview.babylonjs.com/Oimo.js"></script>
         <script src="https://preview.babylonjs.com/Oimo.js"></script>
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>

+ 1 - 1
Playground/index-local.html

@@ -17,7 +17,7 @@
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <!-- Babylon.js -->
     <!-- Babylon.js -->
     <script src="../dist/preview%20release/cannon.js"></script>
     <script src="../dist/preview%20release/cannon.js"></script>
-    <script src="../dist/preview%20release/draco_decoder.js"></script>
+    <script src="../dist/preview%20release/draco_decoder.js" type="text/x-draco-decoder"></script>
     <script src="../dist/preview%20release/Oimo.js"></script>
     <script src="../dist/preview%20release/Oimo.js"></script>
     <script src="../tools/DevLoader/BabylonLoader.js"></script>
     <script src="../tools/DevLoader/BabylonLoader.js"></script>
 
 

+ 1 - 1
Playground/index.html

@@ -37,7 +37,7 @@
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <!-- Babylon.js -->
     <!-- Babylon.js -->
     <script src="https://preview.babylonjs.com/cannon.js"></script>
     <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+    <script src="https://preview.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/babylon.js"></script>
     <script src="https://preview.babylonjs.com/babylon.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>

+ 1 - 1
Playground/indexStable.html

@@ -37,7 +37,7 @@
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <!-- Babylon.js -->
     <!-- Babylon.js -->
     <script src="https://cdn.babylonjs.com/cannon.js"></script>
     <script src="https://cdn.babylonjs.com/cannon.js"></script>
-    <script src="https://cdn.babylonjs.com/draco_decoder.js"></script>
+    <script src="https://cdn.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
     <script src="https://cdn.babylonjs.com/Oimo.js"></script>
     <script src="https://cdn.babylonjs.com/Oimo.js"></script>
     <script src="https://cdn.babylonjs.com/babylon.js"></script>
     <script src="https://cdn.babylonjs.com/babylon.js"></script>
     <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
     <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>

+ 1 - 1
Playground/zipContent/index.html

@@ -9,7 +9,7 @@
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/cannon.js"></script>
-        <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+        <script src="https://preview.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
         <script src="https://preview.babylonjs.com/oimo.js"></script>
         <script src="https://preview.babylonjs.com/oimo.js"></script>
         
         
         <style>
         <style>

+ 11 - 9
Tools/Gulp/config.json

@@ -186,6 +186,7 @@
                 "../../src/Tools/babylon.smartArray.js",
                 "../../src/Tools/babylon.smartArray.js",
                 "../../src/Tools/babylon.tools.js",
                 "../../src/Tools/babylon.tools.js",
                 "../../src/Tools/babylon.promise.js",
                 "../../src/Tools/babylon.promise.js",
+                "../../src/Tools/babylon.workerPool.js",
                 "../../src/States/babylon.alphaCullingState.js",
                 "../../src/States/babylon.alphaCullingState.js",
                 "../../src/States/babylon.depthCullingState.js",
                 "../../src/States/babylon.depthCullingState.js",
                 "../../src/States/babylon.stencilState.js",
                 "../../src/States/babylon.stencilState.js",
@@ -274,10 +275,10 @@
             "files": [
             "files": [
                 "../../src/Particles/babylon.particle.js",
                 "../../src/Particles/babylon.particle.js",
                 "../../src/Particles/babylon.particleSystem.js",
                 "../../src/Particles/babylon.particleSystem.js",
+                "../../src/Particles/EmitterTypes/babylon.IParticleEmitterType.js",
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
-                "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js",
-                "../../src/Particles/EmitterTypes/babylon.IParticleEmitterType.js"
+                "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [
                 "core"
                 "core"
@@ -289,7 +290,7 @@
         },
         },
         "gpuParticles": {
         "gpuParticles": {
             "files": [
             "files": [
-                "../../src/Particles/babylon.gpuParticleSystem.js"          
+                "../../src/Particles/babylon.gpuParticleSystem.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [
                 "core",
                 "core",
@@ -430,8 +431,7 @@
                 "additionalMeshes"
                 "additionalMeshes"
             ]
             ]
         },
         },
-        "meshCompression" :
-        {
+        "meshCompression": {
             "files": [
             "files": [
                 "../../src/Mesh/Compression/babylon.dracoCompression.js"
                 "../../src/Mesh/Compression/babylon.dracoCompression.js"
             ]
             ]
@@ -1676,7 +1676,8 @@
                 "output": "babylon.viewer.js",
                 "output": "babylon.viewer.js",
                 "webpack": "../../Viewer/webpack.gulp.config.js",
                 "webpack": "../../Viewer/webpack.gulp.config.js",
                 "bundle": "true",
                 "bundle": "true",
-                "moduleDeclaration": "BabylonViewer"
+                "moduleDeclaration": "BabylonViewer",
+                "babylonIncluded": true
             }
             }
         ],
         ],
         "build": {
         "build": {
@@ -1685,12 +1686,13 @@
                 {
                 {
                     "destination": [
                     "destination": [
                         {
                         {
-                            "filename": "viewer.min.js",
+                            "filename": "viewer.js",
                             "outputDirectory": "/../../Viewer/dist/"
                             "outputDirectory": "/../../Viewer/dist/"
                         },
                         },
                         {
                         {
                             "filename": "babylon.viewer.js",
                             "filename": "babylon.viewer.js",
-                            "outputDirectory": "/viewer/"
+                            "outputDirectory": "/viewer/",
+                            "addBabylonDeclaration": true
                         }
                         }
                     ],
                     ],
                     "minified": true
                     "minified": true
@@ -1698,7 +1700,7 @@
                 {
                 {
                     "destination": [
                     "destination": [
                         {
                         {
-                            "filename": "viewer.js",
+                            "filename": "viewer.max.js",
                             "outputDirectory": "/../../Viewer/dist/"
                             "outputDirectory": "/../../Viewer/dist/"
                         },
                         },
                         {
                         {

+ 5 - 1
Tools/Gulp/gulp-addModuleExports.js

@@ -5,7 +5,7 @@ var through = require('through2');
  * The parameters for this function has grown during development.
  * The parameters for this function has grown during development.
  * Eventually, this function will need to be reorganized. 
  * Eventually, this function will need to be reorganized. 
  */
  */
-module.exports = function (varName, subModule, extendsRoot, externalUsingBabylon) {
+module.exports = function (varName, subModule, extendsRoot, externalUsingBabylon, noBabylonInit) {
     return through.obj(function (file, enc, cb) {
     return through.obj(function (file, enc, cb) {
 
 
         var optionalRequire = `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
         var optionalRequire = `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
@@ -75,6 +75,10 @@ globalObject["${base}"] = f;` : '';
             return;
             return;
         }
         }
 
 
+        if (noBabylonInit) {
+            optionalRequire = '';
+        }
+
         try {
         try {
             if (externalUsingBabylon) {
             if (externalUsingBabylon) {
                 //file.contents = new Buffer(optionalRequire.concat(String(file.contents)));
                 //file.contents = new Buffer(optionalRequire.concat(String(file.contents)));

+ 8 - 1
Tools/Gulp/gulpfile.js

@@ -434,7 +434,7 @@ var buildExternalLibrary = function (library, settings, watch) {
             let wpBuild = webpack(require(library.webpack));
             let wpBuild = webpack(require(library.webpack));
             if (settings.build.outputs) {
             if (settings.build.outputs) {
                 let build = wpBuild
                 let build = wpBuild
-                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
+                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true, library.babylonIncluded));
 
 
                 let unminifiedOutpus = [];
                 let unminifiedOutpus = [];
                 let minifiedOutputs = [];
                 let minifiedOutputs = [];
@@ -455,6 +455,12 @@ var buildExternalLibrary = function (library, settings, watch) {
                     build = build
                     build = build
                         .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
                         .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
                         .pipe(gulp.dest(outputDirectory));
                         .pipe(gulp.dest(outputDirectory));
+
+                    if (library.babylonIncluded && dest.addBabylonDeclaration) {
+                        // include the babylon declaration
+                        sequence.unshift(gulp.src(config.build.outputDirectory + '/' + config.build.declarationFilename)
+                            .pipe(gulp.dest(outputDirectory)))
+                    }
                 }
                 }
 
 
                 unminifiedOutpus.forEach(dest => {
                 unminifiedOutpus.forEach(dest => {
@@ -472,6 +478,7 @@ var buildExternalLibrary = function (library, settings, watch) {
                 });
                 });
 
 
                 sequence.push(build);
                 sequence.push(build);
+
             } else {
             } else {
                 sequence.push(
                 sequence.push(
                     wpBuild
                     wpBuild

+ 1 - 0
Viewer/dist/_redirects

@@ -0,0 +1 @@
+/viewer.min.js /viewer.js

+ 15 - 18
Viewer/src/configuration/loader.ts

@@ -3,13 +3,17 @@ import { ViewerConfiguration } from './configuration';
 import { getConfigurationType } from './types';
 import { getConfigurationType } from './types';
 
 
 import * as deepmerge from '../../assets/deepmerge.min.js';
 import * as deepmerge from '../../assets/deepmerge.min.js';
+import { Tools, IFileRequest } from 'babylonjs';
 
 
 export class ConfigurationLoader {
 export class ConfigurationLoader {
 
 
     private configurationCache: { [url: string]: any };
     private configurationCache: { [url: string]: any };
 
 
+    private loadRequests: Array<IFileRequest>;
+
     constructor() {
     constructor() {
         this.configurationCache = {};
         this.configurationCache = {};
+        this.loadRequests = [];
     }
     }
 
 
     public loadConfiguration(initConfig: ViewerConfiguration = {}, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration> {
     public loadConfiguration(initConfig: ViewerConfiguration = {}, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration> {
@@ -65,33 +69,26 @@ export class ConfigurationLoader {
         }
         }
     }
     }
 
 
+    public dispose() {
+        this.loadRequests.forEach(request => {
+            request.abort();
+        });
+    }
+
     private loadFile(url: string): Promise<any> {
     private loadFile(url: string): Promise<any> {
         let cacheReference = this.configurationCache;
         let cacheReference = this.configurationCache;
         if (cacheReference[url]) {
         if (cacheReference[url]) {
             return Promise.resolve(cacheReference[url]);
             return Promise.resolve(cacheReference[url]);
         }
         }
 
 
-        return new Promise(function (resolve, reject) {
-            var xhr = new XMLHttpRequest();
-            xhr.open('GET', url);
-            xhr.send();
-            xhr.onreadystatechange = function () {
-                var DONE = 4;
-                var OK = 200;
-                if (xhr.readyState === DONE) {
-                    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.
-                    }
-                }
-            }
+        return new Promise((resolve, reject) => {
+            let fileRequest = Tools.LoadFile(url, resolve, undefined, undefined, false, (request, error: any) => {
+                reject(error);
+            });
+            this.loadRequests.push(fileRequest);
         });
         });
     }
     }
 
 
-
 }
 }
 
 
 export let configurationLoader = new ConfigurationLoader();
 export let configurationLoader = new ConfigurationLoader();

+ 0 - 26
Viewer/src/helper.ts

@@ -5,32 +5,6 @@ export function isUrl(urlToCheck: string): boolean {
     return false;
     return false;
 }
 }
 
 
-export function loadFile(url: string): Promise<any> {
-    /*let cacheReference = this.configurationCache;
-    if (cacheReference[url]) {
-        return Promise.resolve(cacheReference[url]);
-    }*/
-
-    return new Promise(function (resolve, reject) {
-        var xhr = new XMLHttpRequest();
-        xhr.open('GET', url);
-        xhr.send();
-        xhr.onreadystatechange = function () {
-            var DONE = 4;
-            var OK = 200;
-            if (xhr.readyState === DONE) {
-                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.
-            }
-        }
-    });
-}
-
 export function kebabToCamel(s) {
 export function kebabToCamel(s) {
     return s.replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
     return s.replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
 }
 }

+ 47 - 24
Viewer/src/templateManager.ts

@@ -1,6 +1,6 @@
 
 
-import { Observable } from 'babylonjs';
-import { isUrl, loadFile, camelToKebab, kebabToCamel } from './helper';
+import { Observable, IFileRequest, Tools } from 'babylonjs';
+import { isUrl, camelToKebab, kebabToCamel } from './helper';
 
 
 export interface ITemplateConfiguration {
 export interface ITemplateConfiguration {
     location?: string; // #template-id OR http://example.com/loading.html
     location?: string; // #template-id OR http://example.com/loading.html
@@ -212,6 +212,8 @@ export class Template {
     private fragment: DocumentFragment;
     private fragment: DocumentFragment;
     private htmlTemplate: string;
     private htmlTemplate: string;
 
 
+    private loadRequests: Array<IFileRequest>;
+
     constructor(public name: string, private _configuration: ITemplateConfiguration) {
     constructor(public name: string, private _configuration: ITemplateConfiguration) {
         this.onInit = new Observable<Template>();
         this.onInit = new Observable<Template>();
         this.onLoaded = new Observable<Template>();
         this.onLoaded = new Observable<Template>();
@@ -219,6 +221,8 @@ export class Template {
         this.onStateChange = new Observable<Template>();
         this.onStateChange = new Observable<Template>();
         this.onEventTriggered = new Observable<EventCallback>();
         this.onEventTriggered = new Observable<EventCallback>();
 
 
+        this.loadRequests = [];
+
         this.isLoaded = false;
         this.isLoaded = false;
         this.isShown = false;
         this.isShown = false;
         /*
         /*
@@ -228,7 +232,7 @@ export class Template {
         */
         */
         this.onInit.notifyObservers(this);
         this.onInit.notifyObservers(this);
 
 
-        let htmlContentPromise = getTemplateAsHtml(_configuration);
+        let htmlContentPromise = this.getTemplateAsHtml(_configuration);
 
 
         this.initPromise = htmlContentPromise.then(htmlTemplate => {
         this.initPromise = htmlContentPromise.then(htmlTemplate => {
             if (htmlTemplate) {
             if (htmlTemplate) {
@@ -299,8 +303,12 @@ export class Template {
         });
         });
     }
     }
 
 
+    private isShowing: boolean;
+    private isHiding: boolean;
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (this.isHiding) return Promise.resolve(this);
         return Promise.resolve().then(() => {
         return Promise.resolve().then(() => {
+            this.isShowing = true;
             if (visibilityFunction) {
             if (visibilityFunction) {
                 return visibilityFunction(this);
                 return visibilityFunction(this);
             } else {
             } else {
@@ -310,13 +318,16 @@ export class Template {
             }
             }
         }).then(() => {
         }).then(() => {
             this.isShown = true;
             this.isShown = true;
+            this.isShowing = false;
             this.onStateChange.notifyObservers(this);
             this.onStateChange.notifyObservers(this);
             return this;
             return this;
         });
         });
     }
     }
 
 
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (this.isShowing) return Promise.resolve(this);
         return Promise.resolve().then(() => {
         return Promise.resolve().then(() => {
+            this.isHiding = true;
             if (visibilityFunction) {
             if (visibilityFunction) {
                 return visibilityFunction(this);
                 return visibilityFunction(this);
             } else {
             } else {
@@ -326,6 +337,7 @@ export class Template {
             }
             }
         }).then(() => {
         }).then(() => {
             this.isShown = false;
             this.isShown = false;
+            this.isHiding = false;
             this.onStateChange.notifyObservers(this);
             this.onStateChange.notifyObservers(this);
             return this;
             return this;
         });
         });
@@ -340,6 +352,38 @@ export class Template {
         this.isLoaded = false;
         this.isLoaded = false;
         // remove from parent
         // remove from parent
         this.parent.removeChild(this.fragment);
         this.parent.removeChild(this.fragment);
+
+        this.loadRequests.forEach(request => {
+            request.abort();
+        });
+    }
+
+    private getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
+        if (!templateConfig) {
+            return Promise.reject('No templateConfig provided');
+        } else if (templateConfig.html) {
+            return Promise.resolve(templateConfig.html);
+        } else {
+            let location = getTemplateLocation(templateConfig);
+            if (isUrl(location)) {
+                return new Promise((resolve, reject) => {
+                    let fileRequest = Tools.LoadFile(location, (data: string) => {
+                        resolve(data);
+                    }, undefined, undefined, false, (request, error: any) => {
+                        reject(error);
+                    });
+                    this.loadRequests.push(fileRequest);
+                });
+            } else {
+                location = location.replace('#', '');
+                let element = document.getElementById(location);
+                if (element) {
+                    return Promise.resolve(element.innerHTML);
+                } else {
+                    return Promise.reject('Template ID not found');
+                }
+            }
+        }
     }
     }
 
 
     private registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
     private registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
@@ -389,27 +433,6 @@ export class Template {
     }
     }
 }
 }
 
 
-export function getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
-    if (!templateConfig) {
-        return Promise.reject('No templateConfig provided');
-    } else if (templateConfig.html) {
-        return Promise.resolve(templateConfig.html);
-    } else {
-        let location = getTemplateLocation(templateConfig);
-        if (isUrl(location)) {
-            return loadFile(location);
-        } else {
-            location = location.replace('#', '');
-            let element = document.getElementById(location);
-            if (element) {
-                return Promise.resolve(element.innerHTML);
-            } else {
-                return Promise.reject('Template ID not found');
-            }
-        }
-    }
-}
-
 export function getTemplateLocation(templateConfig): string {
 export function getTemplateLocation(templateConfig): string {
     if (!templateConfig || typeof templateConfig === 'string') {
     if (!templateConfig || typeof templateConfig === 'string') {
         return templateConfig;
         return templateConfig;

+ 2 - 2
Viewer/src/viewer/defaultViewer.ts

@@ -103,8 +103,8 @@ export class DefaultViewer extends AbstractViewer {
         this.containerElement.style.display = 'flex';
         this.containerElement.style.display = 'flex';
     }
     }
 
 
-    protected configureModel(modelConfiguration: Partial<IModelConfiguration>) {
-        super.configureModel(modelConfiguration);
+    protected configureModel(modelConfiguration: Partial<IModelConfiguration>, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        super.configureModel(modelConfiguration, focusMeshes);
 
 
         let navbar = this.templateManager.getTemplate('navBar');
         let navbar = this.templateManager.getTemplate('navBar');
         if (!navbar) return;
         if (!navbar) return;

+ 41 - 7
Viewer/src/viewer/viewer.ts

@@ -421,7 +421,9 @@ export abstract class AbstractViewer {
             }
             }
         };
         };
 
 
-        const sceneExtends = this.scene.getWorldExtends();
+        const sceneExtends = this.scene.getWorldExtends((mesh) => {
+            return !this.environmentHelper || (mesh !== this.environmentHelper.ground && mesh !== this.environmentHelper.rootMesh && mesh !== this.environmentHelper.skybox);
+        });
         const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         const sceneDiagonalLenght = sceneDiagonal.length();
         const sceneDiagonalLenght = sceneDiagonal.length();
         if (isFinite(sceneDiagonalLenght))
         if (isFinite(sceneDiagonalLenght))
@@ -744,13 +746,36 @@ export abstract class AbstractViewer {
         return Promise.resolve(this.scene);
         return Promise.resolve(this.scene);
     }
     }
 
 
+    private isLoading: boolean;
+    private nextLoading: Function;
+
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
         // no model was provided? Do nothing!
         // no model was provided? Do nothing!
-        if (!model.url) {
+        let modelUrl = (typeof model === 'string') ? model : model.url;
+        if (!modelUrl) {
             return Promise.resolve(this.scene);
             return Promise.resolve(this.scene);
         }
         }
-        this.configuration.model = model;
-        let modelUrl = (typeof model === 'string') ? model : model.url;
+        if (this.isLoading) {
+            //another model is being model. Wait for it to finish, trigger the load afterwards
+            this.nextLoading = () => {
+                delete this.nextLoading;
+                this.loadModel(model, clearScene);
+            }
+            return Promise.resolve(this.scene);
+        }
+        this.isLoading = true;
+        if ((typeof model === 'string')) {
+            if (this.configuration.model && typeof this.configuration.model === 'object') {
+                this.configuration.model.url = model;
+            }
+        } else {
+            if (this.configuration.model) {
+                deepmerge(this.configuration.model, model)
+            } else {
+                this.configuration.model = model;
+            }
+        }
+
         let parts = modelUrl.split('/');
         let parts = modelUrl.split('/');
         let filename = parts.pop();
         let filename = parts.pop();
         let base = parts.join('/') + '/';
         let base = parts.join('/') + '/';
@@ -761,13 +786,18 @@ export abstract class AbstractViewer {
 
 
             if (clearScene) {
             if (clearScene) {
                 scene.meshes.forEach(mesh => {
                 scene.meshes.forEach(mesh => {
-                    mesh.dispose();
+                    if (Tags.MatchesQuery(mesh, "viewerMesh")) {
+                        mesh.dispose();
+                    }
                 });
                 });
             }
             }
             return scene!;
             return scene!;
         }).then(() => {
         }).then(() => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
                 this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
                 this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
+                    meshes.forEach(mesh => {
+                        Tags.AddTagsTo(mesh, "viewerMesh");
+                    });
                     resolve(meshes);
                     resolve(meshes);
                 }, (progressEvent) => {
                 }, (progressEvent) => {
                     this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
                     this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
@@ -783,7 +813,7 @@ export abstract class AbstractViewer {
             return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
             return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
                 .then(() => {
                 .then(() => {
                     // update the models' configuration
                     // update the models' configuration
-                    this.configureModel(model, meshes);
+                    this.configureModel(this.configuration.model || model, meshes);
                     this.configureLights(this.configuration.lights);
                     this.configureLights(this.configuration.lights);
 
 
                     if (this.configuration.camera) {
                     if (this.configuration.camera) {
@@ -791,12 +821,16 @@ export abstract class AbstractViewer {
                     }
                     }
                     return this.initEnvironment(meshes);
                     return this.initEnvironment(meshes);
                 }).then(() => {
                 }).then(() => {
+                    this.isLoading = false;
+                    if (this.nextLoading) {
+                        return this.nextLoading();
+                    }
                     return this.scene;
                     return this.scene;
                 });
                 });
         });
         });
     }
     }
 
 
-    protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
+    protected initEnvironment(focusMeshes: Array<AbstractMesh> = this.scene.meshes): Promise<Scene> {
         this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
         this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
 
 
         return Promise.resolve(this.scene);
         return Promise.resolve(this.scene);

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


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


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


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


File diff suppressed because it is too large
+ 3949 - 3759
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


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


File diff suppressed because it is too large
+ 716 - 428
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


File diff suppressed because it is too large
+ 718 - 430
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


File diff suppressed because it is too large
+ 790 - 434
dist/preview release/es6.js


+ 6 - 2
dist/preview release/gui/babylon.gui.d.ts

@@ -16,8 +16,12 @@ declare module BABYLON.GUI {
         private _background;
         private _background;
         _rootContainer: Container;
         _rootContainer: Container;
         _lastPickedControl: Control;
         _lastPickedControl: Control;
-        _lastControlOver: Nullable<Control>;
-        _lastControlDown: Nullable<Control>;
+        _lastControlOver: {
+            [pointerId: number]: Control;
+        };
+        _lastControlDown: {
+            [pointerId: number]: Control;
+        };
         _capturingControl: {
         _capturingControl: {
             [pointerId: number]: Control;
             [pointerId: number]: Control;
         };
         };

+ 24 - 22
dist/preview release/gui/babylon.gui.js

@@ -33,6 +33,8 @@ var BABYLON;
                 var _this = _super.call(this, name, { width: width, height: height }, scene, generateMipMaps, samplingMode, BABYLON.Engine.TEXTUREFORMAT_RGBA) || this;
                 var _this = _super.call(this, name, { width: width, height: height }, scene, generateMipMaps, samplingMode, BABYLON.Engine.TEXTUREFORMAT_RGBA) || this;
                 _this._isDirty = false;
                 _this._isDirty = false;
                 _this._rootContainer = new GUI.Container("root");
                 _this._rootContainer = new GUI.Container("root");
+                _this._lastControlOver = {};
+                _this._lastControlDown = {};
                 _this._capturingControl = {};
                 _this._capturingControl = {};
                 _this._linkedControls = new Array();
                 _this._linkedControls = new Array();
                 _this._isFullscreen = false;
                 _this._isFullscreen = false;
@@ -358,10 +360,10 @@ var BABYLON;
                 }
                 }
                 if (!this._rootContainer._processPicking(x, y, type, pointerId, buttonIndex)) {
                 if (!this._rootContainer._processPicking(x, y, type, pointerId, buttonIndex)) {
                     if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
-                        if (this._lastControlOver) {
-                            this._lastControlOver._onPointerOut(this._lastControlOver);
+                        if (this._lastControlOver[pointerId]) {
+                            this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
                         }
                         }
-                        this._lastControlOver = null;
+                        delete this._lastControlOver[pointerId];
                     }
                     }
                 }
                 }
                 this._manageFocus();
                 this._manageFocus();
@@ -417,17 +419,17 @@ var BABYLON;
                         }
                         }
                     }
                     }
                     else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
                     else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
-                        if (_this._lastControlDown) {
-                            _this._lastControlDown.forcePointerUp(pointerId);
+                        if (_this._lastControlDown[pointerId]) {
+                            _this._lastControlDown[pointerId].forcePointerUp(pointerId);
                         }
                         }
-                        _this._lastControlDown = null;
+                        delete _this._lastControlDown[pointerId];
                         _this.focusedControl = null;
                         _this.focusedControl = null;
                     }
                     }
                     else if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     else if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
-                        if (_this._lastControlOver) {
-                            _this._lastControlOver._onPointerOut(_this._lastControlOver);
+                        if (_this._lastControlOver[pointerId]) {
+                            _this._lastControlOver[pointerId]._onPointerOut(_this._lastControlOver[pointerId]);
                         }
                         }
-                        _this._lastControlOver = null;
+                        delete _this._lastControlOver[pointerId];
                     }
                     }
                 });
                 });
                 mesh.enablePointerMoveEvents = supportPointerMove;
                 mesh.enablePointerMoveEvents = supportPointerMove;
@@ -456,15 +458,15 @@ var BABYLON;
             };
             };
             AdvancedDynamicTexture.prototype._attachToOnPointerOut = function (scene) {
             AdvancedDynamicTexture.prototype._attachToOnPointerOut = function (scene) {
                 var _this = this;
                 var _this = this;
-                this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(function () {
-                    if (_this._lastControlOver) {
-                        _this._lastControlOver._onPointerOut(_this._lastControlOver);
+                this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(function (pointerEvent) {
+                    if (_this._lastControlOver[pointerEvent.pointerId]) {
+                        _this._lastControlOver[pointerEvent.pointerId]._onPointerOut(_this._lastControlOver[pointerEvent.pointerId]);
                     }
                     }
-                    _this._lastControlOver = null;
-                    if (_this._lastControlDown) {
-                        _this._lastControlDown.forcePointerUp();
+                    delete _this._lastControlOver[pointerEvent.pointerId];
+                    if (_this._lastControlDown[pointerEvent.pointerId]) {
+                        _this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                     }
                     }
-                    _this._lastControlDown = null;
+                    delete _this._lastControlDown[pointerEvent.pointerId];
                 });
                 });
             };
             };
             // Statics
             // Statics
@@ -1726,27 +1728,27 @@ var BABYLON;
                 this._dummyVector2.copyFromFloats(x, y);
                 this._dummyVector2.copyFromFloats(x, y);
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     this._onPointerMove(this, this._dummyVector2);
                     this._onPointerMove(this, this._dummyVector2);
-                    var previousControlOver = this._host._lastControlOver;
+                    var previousControlOver = this._host._lastControlOver[pointerId];
                     if (previousControlOver && previousControlOver !== this) {
                     if (previousControlOver && previousControlOver !== this) {
                         previousControlOver._onPointerOut(this);
                         previousControlOver._onPointerOut(this);
                     }
                     }
                     if (previousControlOver !== this) {
                     if (previousControlOver !== this) {
                         this._onPointerEnter(this);
                         this._onPointerEnter(this);
                     }
                     }
-                    this._host._lastControlOver = this;
+                    this._host._lastControlOver[pointerId] = this;
                     return true;
                     return true;
                 }
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
                 if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
                     this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex);
                     this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex);
-                    this._host._lastControlDown = this;
+                    this._host._lastControlDown[pointerId] = this;
                     this._host._lastPickedControl = this;
                     this._host._lastPickedControl = this;
                     return true;
                     return true;
                 }
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERUP) {
                 if (type === BABYLON.PointerEventTypes.POINTERUP) {
-                    if (this._host._lastControlDown) {
-                        this._host._lastControlDown._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
+                    if (this._host._lastControlDown[pointerId]) {
+                        this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
                     }
                     }
-                    this._host._lastControlDown = null;
+                    delete this._host._lastControlDown[pointerId];
                     return true;
                     return true;
                 }
                 }
                 return false;
                 return false;

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


+ 6 - 2
dist/preview release/gui/babylon.gui.module.d.ts

@@ -22,8 +22,12 @@ declare module BABYLON.GUI {
         private _background;
         private _background;
         _rootContainer: Container;
         _rootContainer: Container;
         _lastPickedControl: Control;
         _lastPickedControl: Control;
-        _lastControlOver: Nullable<Control>;
-        _lastControlDown: Nullable<Control>;
+        _lastControlOver: {
+            [pointerId: number]: Control;
+        };
+        _lastControlDown: {
+            [pointerId: number]: Control;
+        };
         _capturingControl: {
         _capturingControl: {
             [pointerId: number]: Control;
             [pointerId: number]: Control;
         };
         };

+ 1 - 1
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-gui",
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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


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


+ 1 - 1
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-inspector",
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
     "description": "The Babylon.js inspector.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


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

@@ -304,6 +304,7 @@ declare module BABYLON.GLTF2 {
         private _loadExtensions();
         private _loadExtensions();
         private _loadData(data);
         private _loadData(data);
         private _setupData();
         private _setupData();
+        private _checkExtensions();
         private _createRootNode();
         private _createRootNode();
         private _loadNodesAsync(nodes);
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
@@ -359,11 +360,12 @@ declare module BABYLON.GLTF2 {
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension, IDisposable {
         enabled: boolean;
         enabled: boolean;
         readonly abstract name: string;
         readonly abstract name: string;
         protected _loader: GLTFLoader;
         protected _loader: GLTFLoader;
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
+        dispose(): void;
         /** Override this method to modify the default behavior for loading scenes. */
         /** Override this method to modify the default behavior for loading scenes. */
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading nodes. */
         /** Override this method to modify the default behavior for loading nodes. */
@@ -415,6 +417,9 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
+        private _dracoCompression;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
     }
 }
 }

+ 39 - 9
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -571,6 +571,7 @@ var BABYLON;
                     _this._progressCallback = onProgress;
                     _this._progressCallback = onProgress;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._loadData(data);
                     _this._loadData(data);
+                    _this._checkExtensions();
                     var promises = new Array();
                     var promises = new Array();
                     if (nodes) {
                     if (nodes) {
                         promises.push(_this._loadNodesAsync(nodes));
                         promises.push(_this._loadNodesAsync(nodes));
@@ -667,6 +668,17 @@ var BABYLON;
                     }
                     }
                 }
                 }
             };
             };
+            GLTFLoader.prototype._checkExtensions = function () {
+                if (this._gltf.extensionsRequired) {
+                    for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
+                        var name_2 = _a[_i];
+                        var extension = this._extensions[name_2];
+                        if (!extension || !extension.enabled) {
+                            throw new Error("Require extension " + name_2 + " is not available");
+                        }
+                    }
+                }
+            };
             GLTFLoader.prototype._createRootNode = function () {
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -1800,6 +1812,9 @@ var BABYLON;
                 delete this._gltf;
                 delete this._gltf;
                 delete this._babylonScene;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
                 this._completePromises.length = 0;
+                for (var name_3 in this._extensions) {
+                    this._extensions[name_3].dispose();
+                }
                 this._extensions = {};
                 this._extensions = {};
                 delete this._rootBabylonMesh;
                 delete this._rootBabylonMesh;
                 delete this._progressCallback;
                 delete this._progressCallback;
@@ -1809,8 +1824,8 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_2 = _a[_i];
-                    var extension = this._extensions[name_2];
+                    var name_4 = _a[_i];
+                    var extension = this._extensions[name_4];
                     if (extension.enabled) {
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         var promise = actionAsync(extension);
                         if (promise) {
                         if (promise) {
@@ -1841,6 +1856,9 @@ var BABYLON;
                 this.enabled = true;
                 this.enabled = true;
                 this._loader = loader;
                 this._loader = loader;
             }
             }
+            GLTFLoaderExtension.prototype.dispose = function () {
+                delete this._loader;
+            };
             // #region Overridable Methods
             // #region Overridable Methods
             /** Override this method to modify the default behavior for loading scenes. */
             /** Override this method to modify the default behavior for loading scenes. */
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
@@ -2068,15 +2086,26 @@ var BABYLON;
     (function (GLTF2) {
     (function (GLTF2) {
         var Extensions;
         var Extensions;
         (function (Extensions) {
         (function (Extensions) {
-            // https://github.com/KhronosGroup/glTF/pull/874
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
             var NAME = "KHR_draco_mesh_compression";
             var NAME = "KHR_draco_mesh_compression";
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
                 __extends(KHR_draco_mesh_compression, _super);
                 __extends(KHR_draco_mesh_compression, _super);
-                function KHR_draco_mesh_compression() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function KHR_draco_mesh_compression(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
                     _this.name = NAME;
+                    _this._dracoCompression = null;
+                    // Disable extension if decoder is not available.
+                    if (!BABYLON.DracoCompression.DecoderUrl) {
+                        _this.enabled = false;
+                    }
                     return _this;
                     return _this;
                 }
                 }
+                KHR_draco_mesh_compression.prototype.dispose = function () {
+                    if (this._dracoCompression) {
+                        this._dracoCompression.dispose();
+                    }
+                    _super.prototype.dispose.call(this);
+                };
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                     var _this = this;
                     var _this = this;
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
@@ -2113,7 +2142,10 @@ var BABYLON;
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                             try {
                             try {
-                                return BABYLON.DracoCompression.Decode(data, attributes);
+                                if (!_this._dracoCompression) {
+                                    _this._dracoCompression = new BABYLON.DracoCompression();
+                                }
+                                return _this._dracoCompression.decodeMeshAsync(data, attributes);
                             }
                             }
                             catch (e) {
                             catch (e) {
                                 throw new Error(context + ": " + e.message);
                                 throw new Error(context + ": " + e.message);
@@ -2124,9 +2156,7 @@ var BABYLON;
                 return KHR_draco_mesh_compression;
                 return KHR_draco_mesh_compression;
             }(GLTF2.GLTFLoaderExtension));
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
-            if (BABYLON.DracoCompression.IsSupported) {
-                GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
-            }
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -859,6 +859,7 @@ declare module BABYLON.GLTF2 {
         private _loadExtensions();
         private _loadExtensions();
         private _loadData(data);
         private _loadData(data);
         private _setupData();
         private _setupData();
+        private _checkExtensions();
         private _createRootNode();
         private _createRootNode();
         private _loadNodesAsync(nodes);
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
@@ -914,11 +915,12 @@ declare module BABYLON.GLTF2 {
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension, IDisposable {
         enabled: boolean;
         enabled: boolean;
         readonly abstract name: string;
         readonly abstract name: string;
         protected _loader: GLTFLoader;
         protected _loader: GLTFLoader;
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
+        dispose(): void;
         /** Override this method to modify the default behavior for loading scenes. */
         /** Override this method to modify the default behavior for loading scenes. */
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading nodes. */
         /** Override this method to modify the default behavior for loading nodes. */
@@ -970,6 +972,9 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
+        private _dracoCompression;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
     }
 }
 }

+ 39 - 9
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2747,6 +2747,7 @@ var BABYLON;
                     _this._progressCallback = onProgress;
                     _this._progressCallback = onProgress;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._loadData(data);
                     _this._loadData(data);
+                    _this._checkExtensions();
                     var promises = new Array();
                     var promises = new Array();
                     if (nodes) {
                     if (nodes) {
                         promises.push(_this._loadNodesAsync(nodes));
                         promises.push(_this._loadNodesAsync(nodes));
@@ -2843,6 +2844,17 @@ var BABYLON;
                     }
                     }
                 }
                 }
             };
             };
+            GLTFLoader.prototype._checkExtensions = function () {
+                if (this._gltf.extensionsRequired) {
+                    for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
+                        var name_2 = _a[_i];
+                        var extension = this._extensions[name_2];
+                        if (!extension || !extension.enabled) {
+                            throw new Error("Require extension " + name_2 + " is not available");
+                        }
+                    }
+                }
+            };
             GLTFLoader.prototype._createRootNode = function () {
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -3976,6 +3988,9 @@ var BABYLON;
                 delete this._gltf;
                 delete this._gltf;
                 delete this._babylonScene;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
                 this._completePromises.length = 0;
+                for (var name_3 in this._extensions) {
+                    this._extensions[name_3].dispose();
+                }
                 this._extensions = {};
                 this._extensions = {};
                 delete this._rootBabylonMesh;
                 delete this._rootBabylonMesh;
                 delete this._progressCallback;
                 delete this._progressCallback;
@@ -3985,8 +4000,8 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_2 = _a[_i];
-                    var extension = this._extensions[name_2];
+                    var name_4 = _a[_i];
+                    var extension = this._extensions[name_4];
                     if (extension.enabled) {
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         var promise = actionAsync(extension);
                         if (promise) {
                         if (promise) {
@@ -4017,6 +4032,9 @@ var BABYLON;
                 this.enabled = true;
                 this.enabled = true;
                 this._loader = loader;
                 this._loader = loader;
             }
             }
+            GLTFLoaderExtension.prototype.dispose = function () {
+                delete this._loader;
+            };
             // #region Overridable Methods
             // #region Overridable Methods
             /** Override this method to modify the default behavior for loading scenes. */
             /** Override this method to modify the default behavior for loading scenes. */
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
@@ -4244,15 +4262,26 @@ var BABYLON;
     (function (GLTF2) {
     (function (GLTF2) {
         var Extensions;
         var Extensions;
         (function (Extensions) {
         (function (Extensions) {
-            // https://github.com/KhronosGroup/glTF/pull/874
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
             var NAME = "KHR_draco_mesh_compression";
             var NAME = "KHR_draco_mesh_compression";
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
                 __extends(KHR_draco_mesh_compression, _super);
                 __extends(KHR_draco_mesh_compression, _super);
-                function KHR_draco_mesh_compression() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function KHR_draco_mesh_compression(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
                     _this.name = NAME;
+                    _this._dracoCompression = null;
+                    // Disable extension if decoder is not available.
+                    if (!BABYLON.DracoCompression.DecoderUrl) {
+                        _this.enabled = false;
+                    }
                     return _this;
                     return _this;
                 }
                 }
+                KHR_draco_mesh_compression.prototype.dispose = function () {
+                    if (this._dracoCompression) {
+                        this._dracoCompression.dispose();
+                    }
+                    _super.prototype.dispose.call(this);
+                };
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                     var _this = this;
                     var _this = this;
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
@@ -4289,7 +4318,10 @@ var BABYLON;
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                             try {
                             try {
-                                return BABYLON.DracoCompression.Decode(data, attributes);
+                                if (!_this._dracoCompression) {
+                                    _this._dracoCompression = new BABYLON.DracoCompression();
+                                }
+                                return _this._dracoCompression.decodeMeshAsync(data, attributes);
                             }
                             }
                             catch (e) {
                             catch (e) {
                                 throw new Error(context + ": " + e.message);
                                 throw new Error(context + ": " + e.message);
@@ -4300,9 +4332,7 @@ var BABYLON;
                 return KHR_draco_mesh_compression;
                 return KHR_draco_mesh_compression;
             }(GLTF2.GLTFLoaderExtension));
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
-            if (BABYLON.DracoCompression.IsSupported) {
-                GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
-            }
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 39 - 9
dist/preview release/loaders/babylonjs.loaders.js

@@ -3715,6 +3715,7 @@ var BABYLON;
                     _this._progressCallback = onProgress;
                     _this._progressCallback = onProgress;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._loadData(data);
                     _this._loadData(data);
+                    _this._checkExtensions();
                     var promises = new Array();
                     var promises = new Array();
                     if (nodes) {
                     if (nodes) {
                         promises.push(_this._loadNodesAsync(nodes));
                         promises.push(_this._loadNodesAsync(nodes));
@@ -3811,6 +3812,17 @@ var BABYLON;
                     }
                     }
                 }
                 }
             };
             };
+            GLTFLoader.prototype._checkExtensions = function () {
+                if (this._gltf.extensionsRequired) {
+                    for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
+                        var name_2 = _a[_i];
+                        var extension = this._extensions[name_2];
+                        if (!extension || !extension.enabled) {
+                            throw new Error("Require extension " + name_2 + " is not available");
+                        }
+                    }
+                }
+            };
             GLTFLoader.prototype._createRootNode = function () {
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -4944,6 +4956,9 @@ var BABYLON;
                 delete this._gltf;
                 delete this._gltf;
                 delete this._babylonScene;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
                 this._completePromises.length = 0;
+                for (var name_3 in this._extensions) {
+                    this._extensions[name_3].dispose();
+                }
                 this._extensions = {};
                 this._extensions = {};
                 delete this._rootBabylonMesh;
                 delete this._rootBabylonMesh;
                 delete this._progressCallback;
                 delete this._progressCallback;
@@ -4953,8 +4968,8 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_2 = _a[_i];
-                    var extension = this._extensions[name_2];
+                    var name_4 = _a[_i];
+                    var extension = this._extensions[name_4];
                     if (extension.enabled) {
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         var promise = actionAsync(extension);
                         if (promise) {
                         if (promise) {
@@ -4985,6 +5000,9 @@ var BABYLON;
                 this.enabled = true;
                 this.enabled = true;
                 this._loader = loader;
                 this._loader = loader;
             }
             }
+            GLTFLoaderExtension.prototype.dispose = function () {
+                delete this._loader;
+            };
             // #region Overridable Methods
             // #region Overridable Methods
             /** Override this method to modify the default behavior for loading scenes. */
             /** Override this method to modify the default behavior for loading scenes. */
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
@@ -5194,15 +5212,26 @@ var BABYLON;
     (function (GLTF2) {
     (function (GLTF2) {
         var Extensions;
         var Extensions;
         (function (Extensions) {
         (function (Extensions) {
-            // https://github.com/KhronosGroup/glTF/pull/874
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
             var NAME = "KHR_draco_mesh_compression";
             var NAME = "KHR_draco_mesh_compression";
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
                 __extends(KHR_draco_mesh_compression, _super);
                 __extends(KHR_draco_mesh_compression, _super);
-                function KHR_draco_mesh_compression() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function KHR_draco_mesh_compression(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
                     _this.name = NAME;
+                    _this._dracoCompression = null;
+                    // Disable extension if decoder is not available.
+                    if (!BABYLON.DracoCompression.DecoderUrl) {
+                        _this.enabled = false;
+                    }
                     return _this;
                     return _this;
                 }
                 }
+                KHR_draco_mesh_compression.prototype.dispose = function () {
+                    if (this._dracoCompression) {
+                        this._dracoCompression.dispose();
+                    }
+                    _super.prototype.dispose.call(this);
+                };
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                     var _this = this;
                     var _this = this;
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
@@ -5239,7 +5268,10 @@ var BABYLON;
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                             try {
                             try {
-                                return BABYLON.DracoCompression.Decode(data, attributes);
+                                if (!_this._dracoCompression) {
+                                    _this._dracoCompression = new BABYLON.DracoCompression();
+                                }
+                                return _this._dracoCompression.decodeMeshAsync(data, attributes);
                             }
                             }
                             catch (e) {
                             catch (e) {
                                 throw new Error(context + ": " + e.message);
                                 throw new Error(context + ": " + e.message);
@@ -5250,9 +5282,7 @@ var BABYLON;
                 return KHR_draco_mesh_compression;
                 return KHR_draco_mesh_compression;
             }(GLTF2.GLTFLoaderExtension));
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
-            if (BABYLON.DracoCompression.IsSupported) {
-                GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
-            }
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -960,6 +960,7 @@ declare module BABYLON.GLTF2 {
         private _loadExtensions();
         private _loadExtensions();
         private _loadData(data);
         private _loadData(data);
         private _setupData();
         private _setupData();
+        private _checkExtensions();
         private _createRootNode();
         private _createRootNode();
         private _loadNodesAsync(nodes);
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
@@ -1015,11 +1016,12 @@ declare module BABYLON.GLTF2 {
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension, IDisposable {
         enabled: boolean;
         enabled: boolean;
         readonly abstract name: string;
         readonly abstract name: string;
         protected _loader: GLTFLoader;
         protected _loader: GLTFLoader;
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
+        dispose(): void;
         /** Override this method to modify the default behavior for loading scenes. */
         /** Override this method to modify the default behavior for loading scenes. */
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading nodes. */
         /** Override this method to modify the default behavior for loading nodes. */
@@ -1071,6 +1073,9 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
+        private _dracoCompression;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
     }
 }
 }

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-materials",
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-post-process",
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-procedural-textures",
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 62 - 24
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -100,6 +100,18 @@ declare module BABYLON.GLTF2 {
          */
          */
         private imageData;
         private imageData;
         /**
         /**
+         * Stores a map of the unique id of a node to its index in the node array.
+         */
+        private nodeMap;
+        /**
+         * Stores the binary buffer used to store geometry data.
+         */
+        private binaryBuffer;
+        /**
+         * Specifies if the Babylon scene should be converted to right-handed on export.
+         */
+        private convertToRightHandedSystem;
+        /**
          * Creates a glTF Exporter instance, which can accept optional exporter options.
          * Creates a glTF Exporter instance, which can accept optional exporter options.
          * @param babylonScene - Babylon scene object
          * @param babylonScene - Babylon scene object
          * @param options - Options to modify the behavior of the exporter.
          * @param options - Options to modify the behavior of the exporter.
@@ -117,26 +129,42 @@ declare module BABYLON.GLTF2 {
         private createBufferView(bufferIndex, byteOffset, byteLength, byteStride?, name?);
         private createBufferView(bufferIndex, byteOffset, byteLength, byteStride?, name?);
         /**
         /**
          * Creates an accessor based on the supplied arguments
          * Creates an accessor based on the supplied arguments
-         * @param bufferviewIndex
-         * @param name
-         * @param type
-         * @param componentType
-         * @param count
-         * @param min
-         * @param max
+         * @param bufferviewIndex - The index of the bufferview referenced by this accessor.
+         * @param name - The name of the accessor.
+         * @param type - The type of the accessor.
+         * @param componentType - The datatype of components in the attribute.
+         * @param count - The number of attributes referenced by this accessor.
+         * @param byteOffset - The offset relative to the start of the bufferView in bytes.
+         * @param min - Minimum value of each component in this attribute.
+         * @param max - Maximum value of each component in this attribute.
          * @returns - accessor for glTF
          * @returns - accessor for glTF
          */
          */
-        private createAccessor(bufferviewIndex, name, type, componentType, count, byteOffset?, min?, max?);
+        private createAccessor(bufferviewIndex, name, type, componentType, count, byteOffset, min, max);
         /**
         /**
-         * Calculates the minimum and maximum values of an array of floats, based on stride
-         * @param buff - Data to check for min and max values.
-         * @param vertexStart - Start offset to calculate min and max values.
+         * Calculates the minimum and maximum values of an array of position floats.
+         * @param positions - Positions array of a mesh.
+         * @param vertexStart - Starting vertex offset to calculate min and max values.
          * @param vertexCount - Number of vertices to check for min and max values.
          * @param vertexCount - Number of vertices to check for min and max values.
-         * @param stride - Offset between consecutive attributes.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @returns - min number array and max number array.
          * @returns - min number array and max number array.
          */
          */
-        private calculateMinMax(buff, vertexStart, vertexCount, stride, useRightHandedSystem);
+        private calculateMinMaxPositions(positions, vertexStart, vertexCount);
+        /**
+         * Converts a vector3 array to right-handed.
+         * @param vector - vector3 Array to convert to right-handed.
+         * @returns - right-handed Vector3 array.
+         */
+        private static GetRightHandedVector3(vector);
+        /**
+         * Converts a vector4 array to right-handed.
+         * @param vector - vector4 Array to convert to right-handed.
+         * @returns - right-handed vector4 array.
+         */
+        private static GetRightHandedVector4(vector);
+        /**
+         * Converts a quaternion to right-handed.
+         * @param quaternion - Source quaternion to convert to right-handed.
+         */
+        private static GetRightHandedQuaternion(quaternion);
         /**
         /**
          * Writes mesh attribute data to a data buffer.
          * Writes mesh attribute data to a data buffer.
          * Returns the bytelength of the data.
          * Returns the bytelength of the data.
@@ -145,10 +173,9 @@ declare module BABYLON.GLTF2 {
          * @param strideSize - Represents the offset between consecutive attributes
          * @param strideSize - Represents the offset between consecutive attributes
          * @param byteOffset - The offset to start counting bytes from.
          * @param byteOffset - The offset to start counting bytes from.
          * @param dataBuffer - The buffer to write the binary data to.
          * @param dataBuffer - The buffer to write the binary data to.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @returns - Byte length of the attribute data.
          * @returns - Byte length of the attribute data.
          */
          */
-        private writeAttributeData(vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer, useRightHandedSystem);
+        private writeAttributeData(vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer);
         /**
         /**
          * Generates glTF json data
          * Generates glTF json data
          * @param shouldUseGlb - Indicates whether the json should be written for a glb file.
          * @param shouldUseGlb - Indicates whether the json should be written for a glb file.
@@ -185,38 +212,49 @@ declare module BABYLON.GLTF2 {
          * Sets the TRS for each node
          * Sets the TRS for each node
          * @param node - glTF Node for storing the transformation data.
          * @param node - glTF Node for storing the transformation data.
          * @param babylonMesh - Babylon mesh used as the source for the transformation data.
          * @param babylonMesh - Babylon mesh used as the source for the transformation data.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          */
          */
-        private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
+        private setNodeTransformation(node, babylonMesh);
         /**
         /**
          * Creates a bufferview based on the vertices type for the Babylon mesh
          * Creates a bufferview based on the vertices type for the Babylon mesh
          * @param kind - Indicates the type of vertices data.
          * @param kind - Indicates the type of vertices data.
          * @param babylonMesh - The Babylon mesh to get the vertices data from.
          * @param babylonMesh - The Babylon mesh to get the vertices data from.
          * @param byteOffset - The offset from the buffer to start indexing from.
          * @param byteOffset - The offset from the buffer to start indexing from.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @param dataBuffer - The buffer to write the bufferview data to.
          * @param dataBuffer - The buffer to write the bufferview data to.
          * @returns bytelength of the bufferview data.
          * @returns bytelength of the bufferview data.
          */
          */
-        private createBufferViewKind(kind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
+        private createBufferViewKind(kind, babylonMesh, byteOffset, dataBuffer);
         /**
         /**
          * Sets data for the primitive attributes of each submesh
          * Sets data for the primitive attributes of each submesh
          * @param mesh - glTF Mesh object to store the primitive attribute information.
          * @param mesh - glTF Mesh object to store the primitive attribute information.
          * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
          * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
          * @param byteOffset - The offset in bytes of the buffer data.
          * @param byteOffset - The offset in bytes of the buffer data.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @param dataBuffer - Buffer to write the attribute data to.
          * @param dataBuffer - Buffer to write the attribute data to.
          * @returns - 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);
+        private setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
         /**
         /**
          * Creates a glTF scene based on the array of meshes.
          * Creates a glTF scene based on the array of meshes.
          * Returns the the total byte offset.
          * Returns the the total byte offset.
          * @param babylonScene - Babylon scene to get the mesh data from.
          * @param babylonScene - Babylon scene to get the mesh data from.
          * @param byteOffset - Offset to start from in bytes.
          * @param byteOffset - Offset to start from in bytes.
-         * @param dataBuffer - Buffer to write geometry data to.
          * @returns bytelength + byteoffset
          * @returns bytelength + byteoffset
          */
          */
-        private createScene(babylonScene, byteOffset, dataBuffer);
+        private createScene(babylonScene, byteOffset);
+        /**
+         * Creates a mapping of Node unique id to node index
+         * @param scene - Babylon Scene.
+         * @param byteOffset - The initial byte offset.
+         * @returns - Node mapping of unique id to index.
+         */
+        private createNodeMap(scene, byteOffset);
+        /**
+         * Creates a glTF node from a Babylon mesh.
+         * @param babylonMesh - Source Babylon mesh.
+         * @param byteOffset - The initial byte offset.
+         * @param dataBuffer - Buffer for storing geometry data.
+         * @returns - Object containing an INode and byteoffset.
+         */
+        private createNode(babylonMesh, byteOffset, dataBuffer);
     }
     }
 }
 }
 
 

+ 281 - 362
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -80,12 +80,10 @@ var BABYLON;
                 this.materials = new Array();
                 this.materials = new Array();
                 this.textures = new Array();
                 this.textures = new Array();
                 this.imageData = {};
                 this.imageData = {};
-                if (options !== undefined) {
+                this.convertToRightHandedSystem = !this.babylonScene.useRightHandedSystem;
+                if (options) {
                     this.options = options;
                     this.options = options;
                 }
                 }
-                var totalByteLength = 0;
-                totalByteLength = this.createScene(this.babylonScene, totalByteLength, null);
-                this.totalByteLength = totalByteLength;
             }
             }
             /**
             /**
              * Creates a buffer view based on teh supplied arguments
              * Creates a buffer view based on teh supplied arguments
@@ -98,7 +96,7 @@ var BABYLON;
              */
              */
             _Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength, byteStride, name) {
             _Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength, byteStride, name) {
                 var bufferview = { buffer: bufferIndex, byteLength: byteLength };
                 var bufferview = { buffer: bufferIndex, byteLength: byteLength };
-                if (byteOffset > 0) {
+                if (byteOffset) {
                     bufferview.byteOffset = byteOffset;
                     bufferview.byteOffset = byteOffset;
                 }
                 }
                 if (name) {
                 if (name) {
@@ -111,13 +109,14 @@ var BABYLON;
             };
             };
             /**
             /**
              * Creates an accessor based on the supplied arguments
              * Creates an accessor based on the supplied arguments
-             * @param bufferviewIndex
-             * @param name
-             * @param type
-             * @param componentType
-             * @param count
-             * @param min
-             * @param max
+             * @param bufferviewIndex - The index of the bufferview referenced by this accessor.
+             * @param name - The name of the accessor.
+             * @param type - The type of the accessor.
+             * @param componentType - The datatype of components in the attribute.
+             * @param count - The number of attributes referenced by this accessor.
+             * @param byteOffset - The offset relative to the start of the bufferView in bytes.
+             * @param min - Minimum value of each component in this attribute.
+             * @param max - Maximum value of each component in this attribute.
              * @returns - accessor for glTF
              * @returns - accessor for glTF
              */
              */
             _Exporter.prototype.createAccessor = function (bufferviewIndex, name, type, componentType, count, byteOffset, min, max) {
             _Exporter.prototype.createAccessor = function (bufferviewIndex, name, type, componentType, count, byteOffset, min, max) {
@@ -134,40 +133,60 @@ var BABYLON;
                 return accessor;
                 return accessor;
             };
             };
             /**
             /**
-             * Calculates the minimum and maximum values of an array of floats, based on stride
-             * @param buff - Data to check for min and max values.
-             * @param vertexStart - Start offset to calculate min and max values.
+             * Calculates the minimum and maximum values of an array of position floats.
+             * @param positions - Positions array of a mesh.
+             * @param vertexStart - Starting vertex offset to calculate min and max values.
              * @param vertexCount - Number of vertices to check for min and max values.
              * @param vertexCount - Number of vertices to check for min and max values.
-             * @param stride - Offset between consecutive attributes.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @returns - min number array and max number array.
              * @returns - min number array and max number array.
              */
              */
-            _Exporter.prototype.calculateMinMax = function (buff, vertexStart, vertexCount, stride, useRightHandedSystem) {
+            _Exporter.prototype.calculateMinMaxPositions = function (positions, vertexStart, vertexCount) {
                 var min = [Infinity, Infinity, Infinity];
                 var min = [Infinity, Infinity, Infinity];
                 var max = [-Infinity, -Infinity, -Infinity];
                 var max = [-Infinity, -Infinity, -Infinity];
+                var positionStrideSize = 3;
                 var end = vertexStart + vertexCount;
                 var end = vertexStart + vertexCount;
-                if (vertexCount > 0) {
+                if (vertexCount) {
                     for (var i = vertexStart; i < end; ++i) {
                     for (var i = vertexStart; i < end; ++i) {
-                        var index = stride * i;
-                        var scale = 1;
-                        for (var j = 0; j < stride; ++j) {
-                            if (j === (stride - 1) && !useRightHandedSystem) {
-                                scale = -1;
-                            }
-                            var num = scale * buff[index];
+                        var indexOffset = positionStrideSize * i;
+                        var position = BABYLON.Vector3.FromArray(positions, indexOffset);
+                        var vector = this.convertToRightHandedSystem ? _Exporter.GetRightHandedVector3(position).asArray() : position.asArray();
+                        for (var j = 0; j < positionStrideSize; ++j) {
+                            var num = vector[j];
                             if (num < min[j]) {
                             if (num < min[j]) {
                                 min[j] = num;
                                 min[j] = num;
                             }
                             }
                             if (num > max[j]) {
                             if (num > max[j]) {
                                 max[j] = num;
                                 max[j] = num;
                             }
                             }
-                            ++index;
+                            ++indexOffset;
                         }
                         }
                     }
                     }
                 }
                 }
                 return { min: min, max: max };
                 return { min: min, max: max };
             };
             };
             /**
             /**
+             * Converts a vector3 array to right-handed.
+             * @param vector - vector3 Array to convert to right-handed.
+             * @returns - right-handed Vector3 array.
+             */
+            _Exporter.GetRightHandedVector3 = function (vector) {
+                return new BABYLON.Vector3(vector.x, vector.y, -vector.z);
+            };
+            /**
+             * Converts a vector4 array to right-handed.
+             * @param vector - vector4 Array to convert to right-handed.
+             * @returns - right-handed vector4 array.
+             */
+            _Exporter.GetRightHandedVector4 = function (vector) {
+                return new BABYLON.Vector4(vector.x, vector.y, -vector.z, -vector.w);
+            };
+            /**
+             * Converts a quaternion to right-handed.
+             * @param quaternion - Source quaternion to convert to right-handed.
+             */
+            _Exporter.GetRightHandedQuaternion = function (quaternion) {
+                return new BABYLON.Quaternion(-quaternion.x, -quaternion.y, quaternion.z, quaternion.w);
+            };
+            /**
              * Writes mesh attribute data to a data buffer.
              * Writes mesh attribute data to a data buffer.
              * Returns the bytelength of the data.
              * Returns the bytelength of the data.
              * @param vertexBufferKind - Indicates what kind of vertex data is being passed in.
              * @param vertexBufferKind - Indicates what kind of vertex data is being passed in.
@@ -175,112 +194,35 @@ var BABYLON;
              * @param strideSize - Represents the offset between consecutive attributes
              * @param strideSize - Represents the offset between consecutive attributes
              * @param byteOffset - The offset to start counting bytes from.
              * @param byteOffset - The offset to start counting bytes from.
              * @param dataBuffer - The buffer to write the binary data to.
              * @param dataBuffer - The buffer to write the binary data to.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @returns - Byte length of the attribute data.
              * @returns - Byte length of the attribute data.
              */
              */
-            _Exporter.prototype.writeAttributeData = function (vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer, useRightHandedSystem) {
+            _Exporter.prototype.writeAttributeData = function (vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer) {
                 var byteOff = byteOffset;
                 var byteOff = byteOffset;
-                var start = 0;
                 var end = meshAttributeArray.length / strideSize;
                 var end = meshAttributeArray.length / strideSize;
                 var byteLength = 0;
                 var byteLength = 0;
-                switch (vertexBufferKind) {
-                    case BABYLON.VertexBuffer.PositionKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            if (useRightHandedSystem) {
-                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            }
-                            else {
-                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
-                            }
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
-                    }
-                    case BABYLON.VertexBuffer.NormalKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            if (useRightHandedSystem) {
-                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            }
-                            else {
-                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
-                            }
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
-                    }
-                    case BABYLON.VertexBuffer.TangentKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            if (useRightHandedSystem) {
-                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            }
-                            else {
-                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
-                            }
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                for (var k = 0; k < end; ++k) {
+                    var index = k * strideSize;
+                    var vector = [];
+                    if (vertexBufferKind === BABYLON.VertexBuffer.PositionKind || vertexBufferKind === BABYLON.VertexBuffer.NormalKind) {
+                        var vertexData = BABYLON.Vector3.FromArray(meshAttributeArray, index);
+                        vector = this.convertToRightHandedSystem ? _Exporter.GetRightHandedVector3(vertexData).asArray() : vertexData.asArray();
                     }
                     }
-                    case BABYLON.VertexBuffer.ColorKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                    else if (vertexBufferKind === BABYLON.VertexBuffer.TangentKind || vertexBufferKind === BABYLON.VertexBuffer.ColorKind) {
+                        var vertexData = BABYLON.Vector4.FromArray(meshAttributeArray, index);
+                        vector = (this.convertToRightHandedSystem && !(vertexBufferKind === BABYLON.VertexBuffer.ColorKind)) ? _Exporter.GetRightHandedVector4(vertexData).asArray() : vertexData.asArray();
                     }
                     }
-                    case BABYLON.VertexBuffer.UVKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                    else if (vertexBufferKind === BABYLON.VertexBuffer.UVKind || vertexBufferKind === BABYLON.VertexBuffer.UV2Kind) {
+                        vector = [meshAttributeArray[index], meshAttributeArray[index + 1]];
                     }
                     }
-                    case BABYLON.VertexBuffer.UV2Kind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                    else {
+                        BABYLON.Tools.Warn("Unsupported Vertex Buffer Type: " + vertexBufferKind);
                     }
                     }
-                    default: {
-                        throw new Error("Unsupported vertex buffer type: " + vertexBufferKind);
+                    for (var i = 0; i < vector.length; ++i) {
+                        dataBuffer.setFloat32(byteOff, vector[i], true);
+                        byteOff += 4;
                     }
                     }
                 }
                 }
+                byteLength = meshAttributeArray.length * 4;
                 return byteLength;
                 return byteLength;
             };
             };
             /**
             /**
@@ -295,32 +237,32 @@ var BABYLON;
                 var glTF = {
                 var glTF = {
                     asset: this.asset
                     asset: this.asset
                 };
                 };
-                if (buffer.byteLength > 0) {
+                if (buffer.byteLength) {
                     glTF.buffers = [buffer];
                     glTF.buffers = [buffer];
                 }
                 }
-                if (this.nodes && this.nodes.length !== 0) {
+                if (this.nodes && this.nodes.length) {
                     glTF.nodes = this.nodes;
                     glTF.nodes = this.nodes;
                 }
                 }
-                if (this.meshes && this.meshes.length !== 0) {
+                if (this.meshes && this.meshes.length) {
                     glTF.meshes = this.meshes;
                     glTF.meshes = this.meshes;
                 }
                 }
-                if (this.scenes && this.scenes.length !== 0) {
+                if (this.scenes && this.scenes.length) {
                     glTF.scenes = this.scenes;
                     glTF.scenes = this.scenes;
                     glTF.scene = 0;
                     glTF.scene = 0;
                 }
                 }
-                if (this.bufferViews && this.bufferViews.length !== 0) {
+                if (this.bufferViews && this.bufferViews.length) {
                     glTF.bufferViews = this.bufferViews;
                     glTF.bufferViews = this.bufferViews;
                 }
                 }
-                if (this.accessors && this.accessors.length !== 0) {
+                if (this.accessors && this.accessors.length) {
                     glTF.accessors = this.accessors;
                     glTF.accessors = this.accessors;
                 }
                 }
-                if (this.materials && this.materials.length !== 0) {
+                if (this.materials && this.materials.length) {
                     glTF.materials = this.materials;
                     glTF.materials = this.materials;
                 }
                 }
-                if (this.textures && this.textures.length !== 0) {
+                if (this.textures && this.textures.length) {
                     glTF.textures = this.textures;
                     glTF.textures = this.textures;
                 }
                 }
-                if (this.images && this.images.length !== 0) {
+                if (this.images && this.images.length) {
                     if (!shouldUseGlb) {
                     if (!shouldUseGlb) {
                         glTF.images = this.images;
                         glTF.images = this.images;
                     }
                     }
@@ -331,7 +273,7 @@ var BABYLON;
                         var byteOffset = this.totalByteLength;
                         var byteOffset = this.totalByteLength;
                         for (var i = 0; i < imageLength; ++i) {
                         for (var i = 0; i < imageLength; ++i) {
                             var image = this.images[i];
                             var image = this.images[i];
-                            if (image.uri !== undefined) {
+                            if (image.uri) {
                                 var imageData = this.imageData[image.uri];
                                 var imageData = this.imageData[image.uri];
                                 var imageName = image.uri.split('.')[0] + " image";
                                 var imageName = image.uri.split('.')[0] + " image";
                                 var bufferView = this.createBufferView(0, byteOffset, imageData.data.length, undefined, imageName);
                                 var bufferView = this.createBufferView(0, byteOffset, imageData.data.length, undefined, imageName);
@@ -359,15 +301,15 @@ var BABYLON;
              * @returns - GLTFData with glTF file data.
              * @returns - GLTFData with glTF file data.
              */
              */
             _Exporter.prototype._generateGLTF = function (glTFPrefix) {
             _Exporter.prototype._generateGLTF = function (glTFPrefix) {
-                var jsonText = this.generateJSON(false, glTFPrefix, true);
                 var binaryBuffer = this.generateBinary();
                 var binaryBuffer = this.generateBinary();
+                var jsonText = this.generateJSON(false, glTFPrefix, true);
                 var bin = new Blob([binaryBuffer], { type: 'application/octet-stream' });
                 var bin = new Blob([binaryBuffer], { type: 'application/octet-stream' });
                 var glTFFileName = glTFPrefix + '.gltf';
                 var glTFFileName = glTFPrefix + '.gltf';
                 var glTFBinFile = glTFPrefix + '.bin';
                 var glTFBinFile = glTFPrefix + '.bin';
                 var container = new BABYLON._GLTFData();
                 var container = new BABYLON._GLTFData();
                 container.glTFFiles[glTFFileName] = jsonText;
                 container.glTFFiles[glTFFileName] = jsonText;
                 container.glTFFiles[glTFBinFile] = bin;
                 container.glTFFiles[glTFBinFile] = bin;
-                if (this.imageData !== null) {
+                if (this.imageData) {
                     for (var image in this.imageData) {
                     for (var image in this.imageData) {
                         container.glTFFiles[image] = new Blob([this.imageData[image].data], { type: this.imageData[image].mimeType });
                         container.glTFFiles[image] = new Blob([this.imageData[image].data], { type: this.imageData[image].mimeType });
                     }
                     }
@@ -380,10 +322,8 @@ var BABYLON;
              */
              */
             _Exporter.prototype.generateBinary = function () {
             _Exporter.prototype.generateBinary = function () {
                 var byteOffset = 0;
                 var byteOffset = 0;
-                var binaryBuffer = new ArrayBuffer(this.totalByteLength);
-                var dataBuffer = new DataView(binaryBuffer);
-                byteOffset = this.createScene(this.babylonScene, byteOffset, dataBuffer);
-                return binaryBuffer;
+                byteOffset = this.createScene(this.babylonScene, byteOffset);
+                return this.binaryBuffer;
             };
             };
             /**
             /**
              * Pads the number to a multiple of 4
              * Pads the number to a multiple of 4
@@ -402,8 +342,8 @@ var BABYLON;
              * @returns - object with glb filename as key and data as value
              * @returns - object with glb filename as key and data as value
              */
              */
             _Exporter.prototype._generateGLB = function (glTFPrefix) {
             _Exporter.prototype._generateGLB = function (glTFPrefix) {
-                var jsonText = this.generateJSON(true);
                 var binaryBuffer = this.generateBinary();
                 var binaryBuffer = this.generateBinary();
+                var jsonText = this.generateJSON(true);
                 var glbFileName = glTFPrefix + '.glb';
                 var glbFileName = glTFPrefix + '.glb';
                 var headerLength = 12;
                 var headerLength = 12;
                 var chunkLengthPrefix = 8;
                 var chunkLengthPrefix = 8;
@@ -469,36 +409,20 @@ var BABYLON;
              * Sets the TRS for each node
              * Sets the TRS for each node
              * @param node - glTF Node for storing the transformation data.
              * @param node - glTF Node for storing the transformation data.
              * @param babylonMesh - Babylon mesh used as the source for the transformation data.
              * @param babylonMesh - Babylon mesh used as the source for the transformation data.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              */
              */
-            _Exporter.prototype.setNodeTransformation = function (node, babylonMesh, useRightHandedSystem) {
+            _Exporter.prototype.setNodeTransformation = function (node, babylonMesh) {
                 if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
                 if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
-                    if (useRightHandedSystem) {
-                        node.translation = babylonMesh.position.asArray();
-                    }
-                    else {
-                        node.translation = [babylonMesh.position.x, babylonMesh.position.y, -babylonMesh.position.z];
-                    }
+                    node.translation = this.convertToRightHandedSystem ? _Exporter.GetRightHandedVector3(babylonMesh.position).asArray() : babylonMesh.position.asArray();
                 }
                 }
                 if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
                 if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
-                    if (useRightHandedSystem) {
-                        node.scale = babylonMesh.scaling.asArray();
-                    }
-                    else {
-                        node.scale = [babylonMesh.scaling.x, babylonMesh.scaling.y, -babylonMesh.scaling.z];
-                    }
+                    node.scale = babylonMesh.scaling.asArray();
                 }
                 }
                 var rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(babylonMesh.rotation.y, babylonMesh.rotation.x, babylonMesh.rotation.z);
                 var rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(babylonMesh.rotation.y, babylonMesh.rotation.x, babylonMesh.rotation.z);
                 if (babylonMesh.rotationQuaternion) {
                 if (babylonMesh.rotationQuaternion) {
                     rotationQuaternion = rotationQuaternion.multiply(babylonMesh.rotationQuaternion);
                     rotationQuaternion = rotationQuaternion.multiply(babylonMesh.rotationQuaternion);
                 }
                 }
                 if (!(rotationQuaternion.x === 0 && rotationQuaternion.y === 0 && rotationQuaternion.z === 0 && rotationQuaternion.w === 1)) {
                 if (!(rotationQuaternion.x === 0 && rotationQuaternion.y === 0 && rotationQuaternion.z === 0 && rotationQuaternion.w === 1)) {
-                    if (useRightHandedSystem) {
-                        node.rotation = rotationQuaternion.asArray();
-                    }
-                    else {
-                        node.rotation = [-rotationQuaternion.x, -rotationQuaternion.y, rotationQuaternion.z, rotationQuaternion.w];
-                    }
+                    node.rotation = this.convertToRightHandedSystem ? _Exporter.GetRightHandedQuaternion(rotationQuaternion).asArray() : rotationQuaternion.asArray();
                 }
                 }
             };
             };
             /**
             /**
@@ -506,11 +430,10 @@ var BABYLON;
              * @param kind - Indicates the type of vertices data.
              * @param kind - Indicates the type of vertices data.
              * @param babylonMesh - The Babylon mesh to get the vertices data from.
              * @param babylonMesh - The Babylon mesh to get the vertices data from.
              * @param byteOffset - The offset from the buffer to start indexing from.
              * @param byteOffset - The offset from the buffer to start indexing from.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @param dataBuffer - The buffer to write the bufferview data to.
              * @param dataBuffer - The buffer to write the bufferview data to.
              * @returns bytelength of the bufferview data.
              * @returns bytelength of the bufferview data.
              */
              */
-            _Exporter.prototype.createBufferViewKind = function (kind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer) {
+            _Exporter.prototype.createBufferViewKind = function (kind, babylonMesh, byteOffset, dataBuffer) {
                 var bufferMesh = null;
                 var bufferMesh = null;
                 var byteLength = 0;
                 var byteLength = 0;
                 if (babylonMesh instanceof BABYLON.Mesh) {
                 if (babylonMesh instanceof BABYLON.Mesh) {
@@ -519,62 +442,29 @@ var BABYLON;
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                     bufferMesh = babylonMesh.sourceMesh;
                     bufferMesh = babylonMesh.sourceMesh;
                 }
                 }
-                if (bufferMesh !== null) {
+                if (bufferMesh) {
                     var vertexBuffer = null;
                     var vertexBuffer = null;
                     var vertexBufferOffset = null;
                     var vertexBufferOffset = null;
                     var vertexData = null;
                     var vertexData = null;
                     var vertexStrideSize = null;
                     var vertexStrideSize = null;
-                    if (bufferMesh.getVerticesDataKinds().indexOf(kind) > -1) {
+                    if (bufferMesh.isVerticesDataPresent(kind)) {
                         vertexBuffer = bufferMesh.getVertexBuffer(kind);
                         vertexBuffer = bufferMesh.getVertexBuffer(kind);
-                        vertexBufferOffset = vertexBuffer.getOffset();
-                        vertexData = vertexBuffer.getData();
-                        vertexStrideSize = vertexBuffer.getStrideSize();
-                        if (dataBuffer && vertexData) {
-                            byteLength = this.writeAttributeData(kind, vertexData, vertexStrideSize, vertexBufferOffset, byteOffset, dataBuffer, useRightHandedSystem);
-                            byteOffset += byteLength;
-                        }
-                        else {
-                            var bufferViewName = null;
-                            switch (kind) {
-                                case BABYLON.VertexBuffer.PositionKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Position - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.NormalKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Normal - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.TangentKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Tangent - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.ColorKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Color - " + bufferMesh.name;
-                                    break;
+                        if (vertexBuffer) {
+                            vertexBufferOffset = vertexBuffer.getOffset();
+                            vertexData = vertexBuffer.getData();
+                            if (vertexData) {
+                                vertexStrideSize = vertexBuffer.getStrideSize();
+                                if (dataBuffer && vertexData) {
+                                    byteLength = this.writeAttributeData(kind, vertexData, vertexStrideSize, vertexBufferOffset, byteOffset, dataBuffer);
+                                    byteOffset += byteLength;
                                 }
                                 }
-                                case BABYLON.VertexBuffer.UVKind: {
+                                else {
                                     byteLength = vertexData.length * 4;
                                     byteLength = vertexData.length * 4;
-                                    bufferViewName = "TexCoord 0 - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.UV2Kind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "TexCoord 1 - " + bufferMesh.name;
-                                    break;
-                                }
-                                default: {
-                                    BABYLON.Tools.Warn("Unsupported VertexBuffer kind: " + kind);
+                                    var bufferView = this.createBufferView(0, byteOffset, byteLength, vertexStrideSize * 4, kind + " - " + bufferMesh.name);
+                                    byteOffset += byteLength;
+                                    this.bufferViews.push(bufferView);
                                 }
                                 }
                             }
                             }
-                            if (bufferViewName !== null) {
-                                var bufferView = this.createBufferView(0, byteOffset, byteLength, vertexStrideSize * 4, bufferViewName);
-                                byteOffset += byteLength;
-                                this.bufferViews.push(bufferView);
-                            }
                         }
                         }
                     }
                     }
                 }
                 }
@@ -585,11 +475,10 @@ var BABYLON;
              * @param mesh - glTF Mesh object to store the primitive attribute information.
              * @param mesh - glTF Mesh object to store the primitive attribute information.
              * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
              * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
              * @param byteOffset - The offset in bytes of the buffer data.
              * @param byteOffset - The offset in bytes of the buffer data.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @param dataBuffer - Buffer to write the attribute data to.
              * @param dataBuffer - Buffer to write the attribute data to.
              * @returns - bytelength of the primitive attributes plus the passed in byteOffset.
              * @returns - bytelength of the primitive attributes plus the passed in byteOffset.
              */
              */
-            _Exporter.prototype.setPrimitiveAttributes = function (mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer) {
+            _Exporter.prototype.setPrimitiveAttributes = function (mesh, babylonMesh, byteOffset, dataBuffer) {
                 var bufferMesh = null;
                 var bufferMesh = null;
                 if (babylonMesh instanceof BABYLON.Mesh) {
                 if (babylonMesh instanceof BABYLON.Mesh) {
                     bufferMesh = babylonMesh;
                     bufferMesh = babylonMesh;
@@ -597,147 +486,134 @@ var BABYLON;
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                     bufferMesh = babylonMesh.sourceMesh;
                     bufferMesh = babylonMesh.sourceMesh;
                 }
                 }
-                var positionBufferViewIndex = null;
-                var normalBufferViewIndex = null;
-                var colorBufferViewIndex = null;
-                var tangentBufferViewIndex = null;
-                var texCoord0BufferViewIndex = null;
-                var texCoord1BufferViewIndex = null;
+                var attributeData = [
+                    { kind: BABYLON.VertexBuffer.PositionKind, accessorType: "VEC3" /* VEC3 */ },
+                    { kind: BABYLON.VertexBuffer.NormalKind, accessorType: "VEC3" /* VEC3 */ },
+                    { kind: BABYLON.VertexBuffer.ColorKind, accessorType: "VEC4" /* VEC4 */ },
+                    { kind: BABYLON.VertexBuffer.TangentKind, accessorType: "VEC4" /* VEC4 */ },
+                    { kind: BABYLON.VertexBuffer.UVKind, accessorType: "VEC2" /* VEC2 */ },
+                    { kind: BABYLON.VertexBuffer.UV2Kind, accessorType: "VEC2" /* VEC2 */ },
+                ];
                 var indexBufferViewIndex = null;
                 var indexBufferViewIndex = null;
-                if (bufferMesh !== null) {
+                if (bufferMesh) {
                     // For each BabylonMesh, create bufferviews for each 'kind'
                     // For each BabylonMesh, create bufferviews for each 'kind'
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.PositionKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        positionBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.NormalKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        normalBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.ColorKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        colorBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.TangentKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        colorBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.UVKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        texCoord0BufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.UV2Kind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        texCoord1BufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.getTotalIndices() > 0) {
-                        var indices = bufferMesh.getIndices();
-                        if (dataBuffer) {
-                            var end = indices.length;
-                            var byteOff = byteOffset;
-                            for (var k = 0; k < end; ++k) {
-                                dataBuffer.setUint32(byteOff, indices[k], true);
-                                byteOff += 4;
-                            }
-                            byteOffset = byteOff;
-                        }
-                        else {
-                            var byteLength = indices.length * 4;
-                            var bufferView = this.createBufferView(0, byteOffset, byteLength, undefined, "Indices - " + bufferMesh.name);
-                            byteOffset += byteLength;
-                            this.bufferViews.push(bufferView);
-                            indexBufferViewIndex = this.bufferViews.length - 1;
+                    for (var _i = 0, attributeData_1 = attributeData; _i < attributeData_1.length; _i++) {
+                        var attribute = attributeData_1[_i];
+                        var attributeKind = attribute.kind;
+                        if (bufferMesh.isVerticesDataPresent(attributeKind)) {
+                            byteOffset += this.createBufferViewKind(attributeKind, babylonMesh, byteOffset, dataBuffer);
+                            attribute.bufferViewIndex = this.bufferViews.length - 1;
                         }
                         }
                     }
                     }
-                }
-                // go through all mesh primitives (submeshes)
-                for (var j = 0; j < babylonMesh.subMeshes.length; ++j) {
-                    var submesh = babylonMesh.subMeshes[j];
-                    var meshPrimitive = { attributes: {} };
-                    if (bufferMesh !== null) {
-                        // Create a bufferview storing all the positions
-                        if (!dataBuffer) {
-                            // Loop through each attribute of the submesh (mesh primitive)
-                            if (positionBufferViewIndex !== null) {
-                                var positionVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.PositionKind);
-                                var positions = positionVertexBuffer.getData();
-                                var positionStrideSize = positionVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var result = this.calculateMinMax(positions, 0, positions.length / positionStrideSize, positionStrideSize, useRightHandedSystem);
-                                var accessor = this.createAccessor(positionBufferViewIndex, "Position", "VEC3" /* VEC3 */, 5126 /* FLOAT */, positions.length / positionStrideSize, 0, result.min, result.max);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.POSITION = this.accessors.length - 1;
-                            }
-                            if (normalBufferViewIndex !== null) {
-                                var normalVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.NormalKind);
-                                var normals = normalVertexBuffer.getData();
-                                var normalStrideSize = normalVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var accessor = this.createAccessor(normalBufferViewIndex, "Normal", "VEC3" /* VEC3 */, 5126 /* FLOAT */, normals.length / normalStrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.NORMAL = this.accessors.length - 1;
-                            }
-                            if (tangentBufferViewIndex !== null) {
-                                var tangentVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.TangentKind);
-                                var tangents = tangentVertexBuffer.getData();
-                                var tangentStrideSize = tangentVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var accessor = this.createAccessor(tangentBufferViewIndex, "Tangent", "VEC4" /* VEC4 */, 5126 /* FLOAT */, tangents.length / tangentStrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.TANGENT = this.accessors.length - 1;
-                            }
-                            if (colorBufferViewIndex !== null) {
-                                var colorVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.ColorKind);
-                                var colors = colorVertexBuffer.getData();
-                                var colorStrideSize = colorVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var accessor = this.createAccessor(colorBufferViewIndex, "Color", "VEC4" /* VEC4 */, 5126 /* FLOAT */, colors.length / colorStrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.COLOR_0 = this.accessors.length - 1;
-                            }
-                            if (texCoord0BufferViewIndex !== null) {
-                                // Create accessor
-                                var texCoord0VertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.UVKind);
-                                var texCoord0s = texCoord0VertexBuffer.getData();
-                                var texCoord0StrideSize = texCoord0VertexBuffer.getStrideSize();
-                                var accessor = this.createAccessor(texCoord0BufferViewIndex, "Texture Coords 0", "VEC2" /* VEC2 */, 5126 /* FLOAT */, texCoord0s.length / texCoord0StrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.TEXCOORD_0 = this.accessors.length - 1;
-                            }
-                            if (texCoord1BufferViewIndex !== null) {
-                                // Create accessor
-                                var texCoord1VertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.UV2Kind);
-                                var texCoord1s = texCoord1VertexBuffer.getData();
-                                var texCoord1StrideSize = texCoord1VertexBuffer.getStrideSize();
-                                var accessor = this.createAccessor(texCoord1BufferViewIndex, "Texture Coords 1", "VEC2" /* VEC2 */, 5126 /* FLOAT */, texCoord1s.length / texCoord1StrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.TEXCOORD_1 = this.accessors.length - 1;
+                    if (bufferMesh.getTotalIndices()) {
+                        var indices = bufferMesh.getIndices();
+                        if (indices) {
+                            if (dataBuffer) {
+                                var end = indices.length;
+                                var byteOff = byteOffset;
+                                for (var k = 0; k < end; ++k) {
+                                    dataBuffer.setUint32(byteOff, indices[k], true);
+                                    byteOff += 4;
+                                }
+                                byteOffset = byteOff;
                             }
                             }
-                            if (indexBufferViewIndex) {
-                                // Create accessor
-                                var accessor = this.createAccessor(indexBufferViewIndex, "Indices", "SCALAR" /* SCALAR */, 5125 /* UNSIGNED_INT */, submesh.indexCount, submesh.indexStart * 4);
-                                this.accessors.push(accessor);
-                                meshPrimitive.indices = this.accessors.length - 1;
+                            else {
+                                var byteLength = indices.length * 4;
+                                var bufferView = this.createBufferView(0, byteOffset, byteLength, undefined, "Indices - " + bufferMesh.name);
+                                byteOffset += byteLength;
+                                this.bufferViews.push(bufferView);
+                                indexBufferViewIndex = this.bufferViews.length - 1;
                             }
                             }
                         }
                         }
-                        if (bufferMesh.material) {
-                            if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
-                                var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
-                                meshPrimitive.material = materialIndex;
+                    }
+                    if (babylonMesh.subMeshes) {
+                        // go through all mesh primitives (submeshes)
+                        for (var _a = 0, _b = babylonMesh.subMeshes; _a < _b.length; _a++) {
+                            var submesh = _b[_a];
+                            var meshPrimitive = { attributes: {} };
+                            // Create a bufferview storing all the positions
+                            if (!dataBuffer) {
+                                for (var _c = 0, attributeData_2 = attributeData; _c < attributeData_2.length; _c++) {
+                                    var attribute = attributeData_2[_c];
+                                    var attributeKind = attribute.kind;
+                                    if (bufferMesh.isVerticesDataPresent(attributeKind)) {
+                                        var vertexBuffer = bufferMesh.getVertexBuffer(attributeKind);
+                                        if (vertexBuffer) {
+                                            var bufferData = vertexBuffer.getData();
+                                            if (bufferData) {
+                                                var strideSize = vertexBuffer.getStrideSize();
+                                                var minMax = void 0;
+                                                var min = null;
+                                                var max = null;
+                                                var bufferViewIndex = attribute.bufferViewIndex;
+                                                if (bufferViewIndex != undefined) {
+                                                    if (attributeKind == BABYLON.VertexBuffer.PositionKind) {
+                                                        minMax = this.calculateMinMaxPositions(bufferData, 0, bufferData.length / strideSize);
+                                                        min = minMax.min;
+                                                        max = minMax.max;
+                                                    }
+                                                    var accessor = this.createAccessor(bufferViewIndex, attributeKind + " - " + babylonMesh.name, attribute.accessorType, 5126 /* FLOAT */, bufferData.length / strideSize, 0, min, max);
+                                                    this.accessors.push(accessor);
+                                                    switch (attributeKind) {
+                                                        case BABYLON.VertexBuffer.PositionKind: {
+                                                            meshPrimitive.attributes.POSITION = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.NormalKind: {
+                                                            meshPrimitive.attributes.NORMAL = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.ColorKind: {
+                                                            meshPrimitive.attributes.COLOR_0 = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.TangentKind: {
+                                                            meshPrimitive.attributes.TANGENT = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.UVKind: {
+                                                            meshPrimitive.attributes.TEXCOORD_0 = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.UV2Kind: {
+                                                            meshPrimitive.attributes.TEXCOORD_1 = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        default: {
+                                                            BABYLON.Tools.Warn("Unsupported Vertex Buffer Type: " + attributeKind);
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                if (indexBufferViewIndex) {
+                                    // Create accessor
+                                    var accessor = this.createAccessor(indexBufferViewIndex, "indices - " + babylonMesh.name, "SCALAR" /* SCALAR */, 5125 /* UNSIGNED_INT */, submesh.indexCount, submesh.indexStart * 4, null, null);
+                                    this.accessors.push(accessor);
+                                    meshPrimitive.indices = this.accessors.length - 1;
+                                }
                             }
                             }
-                            else if (bufferMesh.material instanceof BABYLON.MultiMaterial) {
-                                var babylonMultiMaterial = bufferMesh.material;
-                                var material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
-                                if (material !== null) {
-                                    var materialIndex = babylonMesh.getScene().materials.indexOf(material);
+                            if (bufferMesh.material) {
+                                if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                                    var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
                                     meshPrimitive.material = materialIndex;
                                     meshPrimitive.material = materialIndex;
                                 }
                                 }
+                                else if (bufferMesh.material instanceof BABYLON.MultiMaterial) {
+                                    var babylonMultiMaterial = bufferMesh.material;
+                                    var material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
+                                    if (material) {
+                                        var materialIndex = babylonMesh.getScene().materials.indexOf(material);
+                                        meshPrimitive.material = materialIndex;
+                                    }
+                                }
+                                else {
+                                    BABYLON.Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
+                                }
                             }
                             }
-                            else {
-                                BABYLON.Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
-                            }
+                            mesh.primitives.push(meshPrimitive);
                         }
                         }
-                        mesh.primitives.push(meshPrimitive);
                     }
                     }
                 }
                 }
                 return byteOffset;
                 return byteOffset;
@@ -747,47 +623,90 @@ var BABYLON;
              * Returns the the total byte offset.
              * Returns the the total byte offset.
              * @param babylonScene - Babylon scene to get the mesh data from.
              * @param babylonScene - Babylon scene to get the mesh data from.
              * @param byteOffset - Offset to start from in bytes.
              * @param byteOffset - Offset to start from in bytes.
-             * @param dataBuffer - Buffer to write geometry data to.
              * @returns bytelength + byteoffset
              * @returns bytelength + byteoffset
              */
              */
-            _Exporter.prototype.createScene = function (babylonScene, byteOffset, dataBuffer) {
-                if (babylonScene.meshes.length > 0) {
+            _Exporter.prototype.createScene = function (babylonScene, byteOffset) {
+                if (babylonScene.meshes.length) {
                     var babylonMeshes = babylonScene.meshes;
                     var babylonMeshes = babylonScene.meshes;
                     var scene = { nodes: new Array() };
                     var scene = { nodes: new Array() };
-                    if (dataBuffer == null) {
-                        GLTF2._GLTFMaterial.ConvertMaterialsToGLTF(babylonScene.materials, "image/jpeg" /* JPEG */, this.images, this.textures, this.materials, this.imageData, true);
-                    }
+                    GLTF2._GLTFMaterial.ConvertMaterialsToGLTF(babylonScene.materials, "image/jpeg" /* JPEG */, this.images, this.textures, this.materials, this.imageData, true);
+                    var result = this.createNodeMap(babylonScene, byteOffset);
+                    this.nodeMap = result.nodeMap;
+                    this.totalByteLength = result.byteOffset;
+                    this.binaryBuffer = new ArrayBuffer(this.totalByteLength);
+                    var dataBuffer = new DataView(this.binaryBuffer);
                     for (var i = 0; i < babylonMeshes.length; ++i) {
                     for (var i = 0; i < babylonMeshes.length; ++i) {
                         if (this.options &&
                         if (this.options &&
-                            this.options.shouldExportMesh !== undefined &&
+                            this.options.shouldExportMesh != undefined &&
                             !this.options.shouldExportMesh(babylonMeshes[i])) {
                             !this.options.shouldExportMesh(babylonMeshes[i])) {
                             continue;
                             continue;
                         }
                         }
                         else {
                         else {
-                            // create node to hold translation/rotation/scale and the mesh
-                            var node = { mesh: -1 };
                             var babylonMesh = babylonMeshes[i];
                             var babylonMesh = babylonMeshes[i];
-                            var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
-                            // Set transformation
-                            this.setNodeTransformation(node, babylonMesh, useRightHandedSystem);
-                            // create mesh
-                            var mesh = { primitives: new Array() };
-                            mesh.primitives = [];
-                            byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                            // go through all mesh primitives (submeshes)
-                            this.meshes.push(mesh);
-                            node.mesh = this.meshes.length - 1;
-                            if (babylonMesh.name) {
-                                node.name = babylonMesh.name;
+                            // Build Hierarchy with the node map.
+                            var glTFNodeIndex = this.nodeMap[babylonMesh.uniqueId];
+                            var glTFNode = this.nodes[glTFNodeIndex];
+                            if (!babylonMesh.parent) {
+                                scene.nodes.push(glTFNodeIndex);
                             }
                             }
-                            this.nodes.push(node);
-                            scene.nodes.push(this.nodes.length - 1);
+                            var directDescendents = babylonMesh.getDescendants(true);
+                            if (!glTFNode.children && directDescendents && directDescendents.length) {
+                                glTFNode.children = [];
+                                for (var _i = 0, directDescendents_1 = directDescendents; _i < directDescendents_1.length; _i++) {
+                                    var descendent = directDescendents_1[_i];
+                                    glTFNode.children.push(this.nodeMap[descendent.uniqueId]);
+                                }
+                            }
+                            var mesh = { primitives: new Array() };
+                            byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
                         }
                         }
                     }
                     }
                     this.scenes.push(scene);
                     this.scenes.push(scene);
                 }
                 }
                 return byteOffset;
                 return byteOffset;
             };
             };
+            /**
+             * Creates a mapping of Node unique id to node index
+             * @param scene - Babylon Scene.
+             * @param byteOffset - The initial byte offset.
+             * @returns - Node mapping of unique id to index.
+             */
+            _Exporter.prototype.createNodeMap = function (scene, byteOffset) {
+                var nodeMap = {};
+                for (var _i = 0, _a = scene.meshes; _i < _a.length; _i++) {
+                    var babylonMesh = _a[_i];
+                    var result = this.createNode(babylonMesh, byteOffset, null);
+                    this.nodes.push(result.node);
+                    nodeMap[babylonMesh.uniqueId] = this.nodes.length - 1;
+                    byteOffset = result.byteOffset;
+                }
+                return { nodeMap: nodeMap, byteOffset: byteOffset };
+            };
+            /**
+             * Creates a glTF node from a Babylon mesh.
+             * @param babylonMesh - Source Babylon mesh.
+             * @param byteOffset - The initial byte offset.
+             * @param dataBuffer - Buffer for storing geometry data.
+             * @returns - Object containing an INode and byteoffset.
+             */
+            _Exporter.prototype.createNode = function (babylonMesh, byteOffset, dataBuffer) {
+                // create node to hold translation/rotation/scale and the mesh
+                var node = {};
+                if (babylonMesh.name) {
+                    node.name = babylonMesh.name;
+                }
+                // Set transformation
+                this.setNodeTransformation(node, babylonMesh);
+                // create mesh
+                var mesh = { primitives: new Array() };
+                mesh.primitives = [];
+                byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
+                if (mesh.primitives.length) {
+                    this.meshes.push(mesh);
+                    node.mesh = this.meshes.length - 1;
+                }
+                return { node: node, byteOffset: byteOffset };
+            };
             return _Exporter;
             return _Exporter;
         }());
         }());
         GLTF2._Exporter = _Exporter;
         GLTF2._Exporter = _Exporter;

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 281 - 362
dist/preview release/serializers/babylonjs.serializers.js

@@ -224,12 +224,10 @@ var BABYLON;
                 this.materials = new Array();
                 this.materials = new Array();
                 this.textures = new Array();
                 this.textures = new Array();
                 this.imageData = {};
                 this.imageData = {};
-                if (options !== undefined) {
+                this.convertToRightHandedSystem = !this.babylonScene.useRightHandedSystem;
+                if (options) {
                     this.options = options;
                     this.options = options;
                 }
                 }
-                var totalByteLength = 0;
-                totalByteLength = this.createScene(this.babylonScene, totalByteLength, null);
-                this.totalByteLength = totalByteLength;
             }
             }
             /**
             /**
              * Creates a buffer view based on teh supplied arguments
              * Creates a buffer view based on teh supplied arguments
@@ -242,7 +240,7 @@ var BABYLON;
              */
              */
             _Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength, byteStride, name) {
             _Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength, byteStride, name) {
                 var bufferview = { buffer: bufferIndex, byteLength: byteLength };
                 var bufferview = { buffer: bufferIndex, byteLength: byteLength };
-                if (byteOffset > 0) {
+                if (byteOffset) {
                     bufferview.byteOffset = byteOffset;
                     bufferview.byteOffset = byteOffset;
                 }
                 }
                 if (name) {
                 if (name) {
@@ -255,13 +253,14 @@ var BABYLON;
             };
             };
             /**
             /**
              * Creates an accessor based on the supplied arguments
              * Creates an accessor based on the supplied arguments
-             * @param bufferviewIndex
-             * @param name
-             * @param type
-             * @param componentType
-             * @param count
-             * @param min
-             * @param max
+             * @param bufferviewIndex - The index of the bufferview referenced by this accessor.
+             * @param name - The name of the accessor.
+             * @param type - The type of the accessor.
+             * @param componentType - The datatype of components in the attribute.
+             * @param count - The number of attributes referenced by this accessor.
+             * @param byteOffset - The offset relative to the start of the bufferView in bytes.
+             * @param min - Minimum value of each component in this attribute.
+             * @param max - Maximum value of each component in this attribute.
              * @returns - accessor for glTF
              * @returns - accessor for glTF
              */
              */
             _Exporter.prototype.createAccessor = function (bufferviewIndex, name, type, componentType, count, byteOffset, min, max) {
             _Exporter.prototype.createAccessor = function (bufferviewIndex, name, type, componentType, count, byteOffset, min, max) {
@@ -278,40 +277,60 @@ var BABYLON;
                 return accessor;
                 return accessor;
             };
             };
             /**
             /**
-             * Calculates the minimum and maximum values of an array of floats, based on stride
-             * @param buff - Data to check for min and max values.
-             * @param vertexStart - Start offset to calculate min and max values.
+             * Calculates the minimum and maximum values of an array of position floats.
+             * @param positions - Positions array of a mesh.
+             * @param vertexStart - Starting vertex offset to calculate min and max values.
              * @param vertexCount - Number of vertices to check for min and max values.
              * @param vertexCount - Number of vertices to check for min and max values.
-             * @param stride - Offset between consecutive attributes.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @returns - min number array and max number array.
              * @returns - min number array and max number array.
              */
              */
-            _Exporter.prototype.calculateMinMax = function (buff, vertexStart, vertexCount, stride, useRightHandedSystem) {
+            _Exporter.prototype.calculateMinMaxPositions = function (positions, vertexStart, vertexCount) {
                 var min = [Infinity, Infinity, Infinity];
                 var min = [Infinity, Infinity, Infinity];
                 var max = [-Infinity, -Infinity, -Infinity];
                 var max = [-Infinity, -Infinity, -Infinity];
+                var positionStrideSize = 3;
                 var end = vertexStart + vertexCount;
                 var end = vertexStart + vertexCount;
-                if (vertexCount > 0) {
+                if (vertexCount) {
                     for (var i = vertexStart; i < end; ++i) {
                     for (var i = vertexStart; i < end; ++i) {
-                        var index = stride * i;
-                        var scale = 1;
-                        for (var j = 0; j < stride; ++j) {
-                            if (j === (stride - 1) && !useRightHandedSystem) {
-                                scale = -1;
-                            }
-                            var num = scale * buff[index];
+                        var indexOffset = positionStrideSize * i;
+                        var position = BABYLON.Vector3.FromArray(positions, indexOffset);
+                        var vector = this.convertToRightHandedSystem ? _Exporter.GetRightHandedVector3(position).asArray() : position.asArray();
+                        for (var j = 0; j < positionStrideSize; ++j) {
+                            var num = vector[j];
                             if (num < min[j]) {
                             if (num < min[j]) {
                                 min[j] = num;
                                 min[j] = num;
                             }
                             }
                             if (num > max[j]) {
                             if (num > max[j]) {
                                 max[j] = num;
                                 max[j] = num;
                             }
                             }
-                            ++index;
+                            ++indexOffset;
                         }
                         }
                     }
                     }
                 }
                 }
                 return { min: min, max: max };
                 return { min: min, max: max };
             };
             };
             /**
             /**
+             * Converts a vector3 array to right-handed.
+             * @param vector - vector3 Array to convert to right-handed.
+             * @returns - right-handed Vector3 array.
+             */
+            _Exporter.GetRightHandedVector3 = function (vector) {
+                return new BABYLON.Vector3(vector.x, vector.y, -vector.z);
+            };
+            /**
+             * Converts a vector4 array to right-handed.
+             * @param vector - vector4 Array to convert to right-handed.
+             * @returns - right-handed vector4 array.
+             */
+            _Exporter.GetRightHandedVector4 = function (vector) {
+                return new BABYLON.Vector4(vector.x, vector.y, -vector.z, -vector.w);
+            };
+            /**
+             * Converts a quaternion to right-handed.
+             * @param quaternion - Source quaternion to convert to right-handed.
+             */
+            _Exporter.GetRightHandedQuaternion = function (quaternion) {
+                return new BABYLON.Quaternion(-quaternion.x, -quaternion.y, quaternion.z, quaternion.w);
+            };
+            /**
              * Writes mesh attribute data to a data buffer.
              * Writes mesh attribute data to a data buffer.
              * Returns the bytelength of the data.
              * Returns the bytelength of the data.
              * @param vertexBufferKind - Indicates what kind of vertex data is being passed in.
              * @param vertexBufferKind - Indicates what kind of vertex data is being passed in.
@@ -319,112 +338,35 @@ var BABYLON;
              * @param strideSize - Represents the offset between consecutive attributes
              * @param strideSize - Represents the offset between consecutive attributes
              * @param byteOffset - The offset to start counting bytes from.
              * @param byteOffset - The offset to start counting bytes from.
              * @param dataBuffer - The buffer to write the binary data to.
              * @param dataBuffer - The buffer to write the binary data to.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @returns - Byte length of the attribute data.
              * @returns - Byte length of the attribute data.
              */
              */
-            _Exporter.prototype.writeAttributeData = function (vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer, useRightHandedSystem) {
+            _Exporter.prototype.writeAttributeData = function (vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer) {
                 var byteOff = byteOffset;
                 var byteOff = byteOffset;
-                var start = 0;
                 var end = meshAttributeArray.length / strideSize;
                 var end = meshAttributeArray.length / strideSize;
                 var byteLength = 0;
                 var byteLength = 0;
-                switch (vertexBufferKind) {
-                    case BABYLON.VertexBuffer.PositionKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            if (useRightHandedSystem) {
-                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            }
-                            else {
-                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
-                            }
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
-                    }
-                    case BABYLON.VertexBuffer.NormalKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            if (useRightHandedSystem) {
-                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            }
-                            else {
-                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
-                            }
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
-                    }
-                    case BABYLON.VertexBuffer.TangentKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            if (useRightHandedSystem) {
-                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            }
-                            else {
-                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
-                            }
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                for (var k = 0; k < end; ++k) {
+                    var index = k * strideSize;
+                    var vector = [];
+                    if (vertexBufferKind === BABYLON.VertexBuffer.PositionKind || vertexBufferKind === BABYLON.VertexBuffer.NormalKind) {
+                        var vertexData = BABYLON.Vector3.FromArray(meshAttributeArray, index);
+                        vector = this.convertToRightHandedSystem ? _Exporter.GetRightHandedVector3(vertexData).asArray() : vertexData.asArray();
                     }
                     }
-                    case BABYLON.VertexBuffer.ColorKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                    else if (vertexBufferKind === BABYLON.VertexBuffer.TangentKind || vertexBufferKind === BABYLON.VertexBuffer.ColorKind) {
+                        var vertexData = BABYLON.Vector4.FromArray(meshAttributeArray, index);
+                        vector = (this.convertToRightHandedSystem && !(vertexBufferKind === BABYLON.VertexBuffer.ColorKind)) ? _Exporter.GetRightHandedVector4(vertexData).asArray() : vertexData.asArray();
                     }
                     }
-                    case BABYLON.VertexBuffer.UVKind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                    else if (vertexBufferKind === BABYLON.VertexBuffer.UVKind || vertexBufferKind === BABYLON.VertexBuffer.UV2Kind) {
+                        vector = [meshAttributeArray[index], meshAttributeArray[index + 1]];
                     }
                     }
-                    case BABYLON.VertexBuffer.UV2Kind: {
-                        for (var k = start; k < end; ++k) {
-                            var index = k * strideSize;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
-                            byteOff += 4;
-                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
-                            byteOff += 4;
-                        }
-                        byteLength = meshAttributeArray.length * 4;
-                        break;
+                    else {
+                        BABYLON.Tools.Warn("Unsupported Vertex Buffer Type: " + vertexBufferKind);
                     }
                     }
-                    default: {
-                        throw new Error("Unsupported vertex buffer type: " + vertexBufferKind);
+                    for (var i = 0; i < vector.length; ++i) {
+                        dataBuffer.setFloat32(byteOff, vector[i], true);
+                        byteOff += 4;
                     }
                     }
                 }
                 }
+                byteLength = meshAttributeArray.length * 4;
                 return byteLength;
                 return byteLength;
             };
             };
             /**
             /**
@@ -439,32 +381,32 @@ var BABYLON;
                 var glTF = {
                 var glTF = {
                     asset: this.asset
                     asset: this.asset
                 };
                 };
-                if (buffer.byteLength > 0) {
+                if (buffer.byteLength) {
                     glTF.buffers = [buffer];
                     glTF.buffers = [buffer];
                 }
                 }
-                if (this.nodes && this.nodes.length !== 0) {
+                if (this.nodes && this.nodes.length) {
                     glTF.nodes = this.nodes;
                     glTF.nodes = this.nodes;
                 }
                 }
-                if (this.meshes && this.meshes.length !== 0) {
+                if (this.meshes && this.meshes.length) {
                     glTF.meshes = this.meshes;
                     glTF.meshes = this.meshes;
                 }
                 }
-                if (this.scenes && this.scenes.length !== 0) {
+                if (this.scenes && this.scenes.length) {
                     glTF.scenes = this.scenes;
                     glTF.scenes = this.scenes;
                     glTF.scene = 0;
                     glTF.scene = 0;
                 }
                 }
-                if (this.bufferViews && this.bufferViews.length !== 0) {
+                if (this.bufferViews && this.bufferViews.length) {
                     glTF.bufferViews = this.bufferViews;
                     glTF.bufferViews = this.bufferViews;
                 }
                 }
-                if (this.accessors && this.accessors.length !== 0) {
+                if (this.accessors && this.accessors.length) {
                     glTF.accessors = this.accessors;
                     glTF.accessors = this.accessors;
                 }
                 }
-                if (this.materials && this.materials.length !== 0) {
+                if (this.materials && this.materials.length) {
                     glTF.materials = this.materials;
                     glTF.materials = this.materials;
                 }
                 }
-                if (this.textures && this.textures.length !== 0) {
+                if (this.textures && this.textures.length) {
                     glTF.textures = this.textures;
                     glTF.textures = this.textures;
                 }
                 }
-                if (this.images && this.images.length !== 0) {
+                if (this.images && this.images.length) {
                     if (!shouldUseGlb) {
                     if (!shouldUseGlb) {
                         glTF.images = this.images;
                         glTF.images = this.images;
                     }
                     }
@@ -475,7 +417,7 @@ var BABYLON;
                         var byteOffset = this.totalByteLength;
                         var byteOffset = this.totalByteLength;
                         for (var i = 0; i < imageLength; ++i) {
                         for (var i = 0; i < imageLength; ++i) {
                             var image = this.images[i];
                             var image = this.images[i];
-                            if (image.uri !== undefined) {
+                            if (image.uri) {
                                 var imageData = this.imageData[image.uri];
                                 var imageData = this.imageData[image.uri];
                                 var imageName = image.uri.split('.')[0] + " image";
                                 var imageName = image.uri.split('.')[0] + " image";
                                 var bufferView = this.createBufferView(0, byteOffset, imageData.data.length, undefined, imageName);
                                 var bufferView = this.createBufferView(0, byteOffset, imageData.data.length, undefined, imageName);
@@ -503,15 +445,15 @@ var BABYLON;
              * @returns - GLTFData with glTF file data.
              * @returns - GLTFData with glTF file data.
              */
              */
             _Exporter.prototype._generateGLTF = function (glTFPrefix) {
             _Exporter.prototype._generateGLTF = function (glTFPrefix) {
-                var jsonText = this.generateJSON(false, glTFPrefix, true);
                 var binaryBuffer = this.generateBinary();
                 var binaryBuffer = this.generateBinary();
+                var jsonText = this.generateJSON(false, glTFPrefix, true);
                 var bin = new Blob([binaryBuffer], { type: 'application/octet-stream' });
                 var bin = new Blob([binaryBuffer], { type: 'application/octet-stream' });
                 var glTFFileName = glTFPrefix + '.gltf';
                 var glTFFileName = glTFPrefix + '.gltf';
                 var glTFBinFile = glTFPrefix + '.bin';
                 var glTFBinFile = glTFPrefix + '.bin';
                 var container = new BABYLON._GLTFData();
                 var container = new BABYLON._GLTFData();
                 container.glTFFiles[glTFFileName] = jsonText;
                 container.glTFFiles[glTFFileName] = jsonText;
                 container.glTFFiles[glTFBinFile] = bin;
                 container.glTFFiles[glTFBinFile] = bin;
-                if (this.imageData !== null) {
+                if (this.imageData) {
                     for (var image in this.imageData) {
                     for (var image in this.imageData) {
                         container.glTFFiles[image] = new Blob([this.imageData[image].data], { type: this.imageData[image].mimeType });
                         container.glTFFiles[image] = new Blob([this.imageData[image].data], { type: this.imageData[image].mimeType });
                     }
                     }
@@ -524,10 +466,8 @@ var BABYLON;
              */
              */
             _Exporter.prototype.generateBinary = function () {
             _Exporter.prototype.generateBinary = function () {
                 var byteOffset = 0;
                 var byteOffset = 0;
-                var binaryBuffer = new ArrayBuffer(this.totalByteLength);
-                var dataBuffer = new DataView(binaryBuffer);
-                byteOffset = this.createScene(this.babylonScene, byteOffset, dataBuffer);
-                return binaryBuffer;
+                byteOffset = this.createScene(this.babylonScene, byteOffset);
+                return this.binaryBuffer;
             };
             };
             /**
             /**
              * Pads the number to a multiple of 4
              * Pads the number to a multiple of 4
@@ -546,8 +486,8 @@ var BABYLON;
              * @returns - object with glb filename as key and data as value
              * @returns - object with glb filename as key and data as value
              */
              */
             _Exporter.prototype._generateGLB = function (glTFPrefix) {
             _Exporter.prototype._generateGLB = function (glTFPrefix) {
-                var jsonText = this.generateJSON(true);
                 var binaryBuffer = this.generateBinary();
                 var binaryBuffer = this.generateBinary();
+                var jsonText = this.generateJSON(true);
                 var glbFileName = glTFPrefix + '.glb';
                 var glbFileName = glTFPrefix + '.glb';
                 var headerLength = 12;
                 var headerLength = 12;
                 var chunkLengthPrefix = 8;
                 var chunkLengthPrefix = 8;
@@ -613,36 +553,20 @@ var BABYLON;
              * Sets the TRS for each node
              * Sets the TRS for each node
              * @param node - glTF Node for storing the transformation data.
              * @param node - glTF Node for storing the transformation data.
              * @param babylonMesh - Babylon mesh used as the source for the transformation data.
              * @param babylonMesh - Babylon mesh used as the source for the transformation data.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              */
              */
-            _Exporter.prototype.setNodeTransformation = function (node, babylonMesh, useRightHandedSystem) {
+            _Exporter.prototype.setNodeTransformation = function (node, babylonMesh) {
                 if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
                 if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
-                    if (useRightHandedSystem) {
-                        node.translation = babylonMesh.position.asArray();
-                    }
-                    else {
-                        node.translation = [babylonMesh.position.x, babylonMesh.position.y, -babylonMesh.position.z];
-                    }
+                    node.translation = this.convertToRightHandedSystem ? _Exporter.GetRightHandedVector3(babylonMesh.position).asArray() : babylonMesh.position.asArray();
                 }
                 }
                 if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
                 if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
-                    if (useRightHandedSystem) {
-                        node.scale = babylonMesh.scaling.asArray();
-                    }
-                    else {
-                        node.scale = [babylonMesh.scaling.x, babylonMesh.scaling.y, -babylonMesh.scaling.z];
-                    }
+                    node.scale = babylonMesh.scaling.asArray();
                 }
                 }
                 var rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(babylonMesh.rotation.y, babylonMesh.rotation.x, babylonMesh.rotation.z);
                 var rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(babylonMesh.rotation.y, babylonMesh.rotation.x, babylonMesh.rotation.z);
                 if (babylonMesh.rotationQuaternion) {
                 if (babylonMesh.rotationQuaternion) {
                     rotationQuaternion = rotationQuaternion.multiply(babylonMesh.rotationQuaternion);
                     rotationQuaternion = rotationQuaternion.multiply(babylonMesh.rotationQuaternion);
                 }
                 }
                 if (!(rotationQuaternion.x === 0 && rotationQuaternion.y === 0 && rotationQuaternion.z === 0 && rotationQuaternion.w === 1)) {
                 if (!(rotationQuaternion.x === 0 && rotationQuaternion.y === 0 && rotationQuaternion.z === 0 && rotationQuaternion.w === 1)) {
-                    if (useRightHandedSystem) {
-                        node.rotation = rotationQuaternion.asArray();
-                    }
-                    else {
-                        node.rotation = [-rotationQuaternion.x, -rotationQuaternion.y, rotationQuaternion.z, rotationQuaternion.w];
-                    }
+                    node.rotation = this.convertToRightHandedSystem ? _Exporter.GetRightHandedQuaternion(rotationQuaternion).asArray() : rotationQuaternion.asArray();
                 }
                 }
             };
             };
             /**
             /**
@@ -650,11 +574,10 @@ var BABYLON;
              * @param kind - Indicates the type of vertices data.
              * @param kind - Indicates the type of vertices data.
              * @param babylonMesh - The Babylon mesh to get the vertices data from.
              * @param babylonMesh - The Babylon mesh to get the vertices data from.
              * @param byteOffset - The offset from the buffer to start indexing from.
              * @param byteOffset - The offset from the buffer to start indexing from.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @param dataBuffer - The buffer to write the bufferview data to.
              * @param dataBuffer - The buffer to write the bufferview data to.
              * @returns bytelength of the bufferview data.
              * @returns bytelength of the bufferview data.
              */
              */
-            _Exporter.prototype.createBufferViewKind = function (kind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer) {
+            _Exporter.prototype.createBufferViewKind = function (kind, babylonMesh, byteOffset, dataBuffer) {
                 var bufferMesh = null;
                 var bufferMesh = null;
                 var byteLength = 0;
                 var byteLength = 0;
                 if (babylonMesh instanceof BABYLON.Mesh) {
                 if (babylonMesh instanceof BABYLON.Mesh) {
@@ -663,62 +586,29 @@ var BABYLON;
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                     bufferMesh = babylonMesh.sourceMesh;
                     bufferMesh = babylonMesh.sourceMesh;
                 }
                 }
-                if (bufferMesh !== null) {
+                if (bufferMesh) {
                     var vertexBuffer = null;
                     var vertexBuffer = null;
                     var vertexBufferOffset = null;
                     var vertexBufferOffset = null;
                     var vertexData = null;
                     var vertexData = null;
                     var vertexStrideSize = null;
                     var vertexStrideSize = null;
-                    if (bufferMesh.getVerticesDataKinds().indexOf(kind) > -1) {
+                    if (bufferMesh.isVerticesDataPresent(kind)) {
                         vertexBuffer = bufferMesh.getVertexBuffer(kind);
                         vertexBuffer = bufferMesh.getVertexBuffer(kind);
-                        vertexBufferOffset = vertexBuffer.getOffset();
-                        vertexData = vertexBuffer.getData();
-                        vertexStrideSize = vertexBuffer.getStrideSize();
-                        if (dataBuffer && vertexData) {
-                            byteLength = this.writeAttributeData(kind, vertexData, vertexStrideSize, vertexBufferOffset, byteOffset, dataBuffer, useRightHandedSystem);
-                            byteOffset += byteLength;
-                        }
-                        else {
-                            var bufferViewName = null;
-                            switch (kind) {
-                                case BABYLON.VertexBuffer.PositionKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Position - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.NormalKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Normal - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.TangentKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Tangent - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.ColorKind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "Color - " + bufferMesh.name;
-                                    break;
+                        if (vertexBuffer) {
+                            vertexBufferOffset = vertexBuffer.getOffset();
+                            vertexData = vertexBuffer.getData();
+                            if (vertexData) {
+                                vertexStrideSize = vertexBuffer.getStrideSize();
+                                if (dataBuffer && vertexData) {
+                                    byteLength = this.writeAttributeData(kind, vertexData, vertexStrideSize, vertexBufferOffset, byteOffset, dataBuffer);
+                                    byteOffset += byteLength;
                                 }
                                 }
-                                case BABYLON.VertexBuffer.UVKind: {
+                                else {
                                     byteLength = vertexData.length * 4;
                                     byteLength = vertexData.length * 4;
-                                    bufferViewName = "TexCoord 0 - " + bufferMesh.name;
-                                    break;
-                                }
-                                case BABYLON.VertexBuffer.UV2Kind: {
-                                    byteLength = vertexData.length * 4;
-                                    bufferViewName = "TexCoord 1 - " + bufferMesh.name;
-                                    break;
-                                }
-                                default: {
-                                    BABYLON.Tools.Warn("Unsupported VertexBuffer kind: " + kind);
+                                    var bufferView = this.createBufferView(0, byteOffset, byteLength, vertexStrideSize * 4, kind + " - " + bufferMesh.name);
+                                    byteOffset += byteLength;
+                                    this.bufferViews.push(bufferView);
                                 }
                                 }
                             }
                             }
-                            if (bufferViewName !== null) {
-                                var bufferView = this.createBufferView(0, byteOffset, byteLength, vertexStrideSize * 4, bufferViewName);
-                                byteOffset += byteLength;
-                                this.bufferViews.push(bufferView);
-                            }
                         }
                         }
                     }
                     }
                 }
                 }
@@ -729,11 +619,10 @@ var BABYLON;
              * @param mesh - glTF Mesh object to store the primitive attribute information.
              * @param mesh - glTF Mesh object to store the primitive attribute information.
              * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
              * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
              * @param byteOffset - The offset in bytes of the buffer data.
              * @param byteOffset - The offset in bytes of the buffer data.
-             * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
              * @param dataBuffer - Buffer to write the attribute data to.
              * @param dataBuffer - Buffer to write the attribute data to.
              * @returns - bytelength of the primitive attributes plus the passed in byteOffset.
              * @returns - bytelength of the primitive attributes plus the passed in byteOffset.
              */
              */
-            _Exporter.prototype.setPrimitiveAttributes = function (mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer) {
+            _Exporter.prototype.setPrimitiveAttributes = function (mesh, babylonMesh, byteOffset, dataBuffer) {
                 var bufferMesh = null;
                 var bufferMesh = null;
                 if (babylonMesh instanceof BABYLON.Mesh) {
                 if (babylonMesh instanceof BABYLON.Mesh) {
                     bufferMesh = babylonMesh;
                     bufferMesh = babylonMesh;
@@ -741,147 +630,134 @@ var BABYLON;
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                 else if (babylonMesh instanceof BABYLON.InstancedMesh) {
                     bufferMesh = babylonMesh.sourceMesh;
                     bufferMesh = babylonMesh.sourceMesh;
                 }
                 }
-                var positionBufferViewIndex = null;
-                var normalBufferViewIndex = null;
-                var colorBufferViewIndex = null;
-                var tangentBufferViewIndex = null;
-                var texCoord0BufferViewIndex = null;
-                var texCoord1BufferViewIndex = null;
+                var attributeData = [
+                    { kind: BABYLON.VertexBuffer.PositionKind, accessorType: "VEC3" /* VEC3 */ },
+                    { kind: BABYLON.VertexBuffer.NormalKind, accessorType: "VEC3" /* VEC3 */ },
+                    { kind: BABYLON.VertexBuffer.ColorKind, accessorType: "VEC4" /* VEC4 */ },
+                    { kind: BABYLON.VertexBuffer.TangentKind, accessorType: "VEC4" /* VEC4 */ },
+                    { kind: BABYLON.VertexBuffer.UVKind, accessorType: "VEC2" /* VEC2 */ },
+                    { kind: BABYLON.VertexBuffer.UV2Kind, accessorType: "VEC2" /* VEC2 */ },
+                ];
                 var indexBufferViewIndex = null;
                 var indexBufferViewIndex = null;
-                if (bufferMesh !== null) {
+                if (bufferMesh) {
                     // For each BabylonMesh, create bufferviews for each 'kind'
                     // For each BabylonMesh, create bufferviews for each 'kind'
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.PositionKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        positionBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.NormalKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        normalBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.ColorKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        colorBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.TangentKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        colorBufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.UVKind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        texCoord0BufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                        byteOffset += this.createBufferViewKind(BABYLON.VertexBuffer.UV2Kind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                        texCoord1BufferViewIndex = this.bufferViews.length - 1;
-                    }
-                    if (bufferMesh.getTotalIndices() > 0) {
-                        var indices = bufferMesh.getIndices();
-                        if (dataBuffer) {
-                            var end = indices.length;
-                            var byteOff = byteOffset;
-                            for (var k = 0; k < end; ++k) {
-                                dataBuffer.setUint32(byteOff, indices[k], true);
-                                byteOff += 4;
-                            }
-                            byteOffset = byteOff;
-                        }
-                        else {
-                            var byteLength = indices.length * 4;
-                            var bufferView = this.createBufferView(0, byteOffset, byteLength, undefined, "Indices - " + bufferMesh.name);
-                            byteOffset += byteLength;
-                            this.bufferViews.push(bufferView);
-                            indexBufferViewIndex = this.bufferViews.length - 1;
+                    for (var _i = 0, attributeData_1 = attributeData; _i < attributeData_1.length; _i++) {
+                        var attribute = attributeData_1[_i];
+                        var attributeKind = attribute.kind;
+                        if (bufferMesh.isVerticesDataPresent(attributeKind)) {
+                            byteOffset += this.createBufferViewKind(attributeKind, babylonMesh, byteOffset, dataBuffer);
+                            attribute.bufferViewIndex = this.bufferViews.length - 1;
                         }
                         }
                     }
                     }
-                }
-                // go through all mesh primitives (submeshes)
-                for (var j = 0; j < babylonMesh.subMeshes.length; ++j) {
-                    var submesh = babylonMesh.subMeshes[j];
-                    var meshPrimitive = { attributes: {} };
-                    if (bufferMesh !== null) {
-                        // Create a bufferview storing all the positions
-                        if (!dataBuffer) {
-                            // Loop through each attribute of the submesh (mesh primitive)
-                            if (positionBufferViewIndex !== null) {
-                                var positionVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.PositionKind);
-                                var positions = positionVertexBuffer.getData();
-                                var positionStrideSize = positionVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var result = this.calculateMinMax(positions, 0, positions.length / positionStrideSize, positionStrideSize, useRightHandedSystem);
-                                var accessor = this.createAccessor(positionBufferViewIndex, "Position", "VEC3" /* VEC3 */, 5126 /* FLOAT */, positions.length / positionStrideSize, 0, result.min, result.max);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.POSITION = this.accessors.length - 1;
-                            }
-                            if (normalBufferViewIndex !== null) {
-                                var normalVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.NormalKind);
-                                var normals = normalVertexBuffer.getData();
-                                var normalStrideSize = normalVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var accessor = this.createAccessor(normalBufferViewIndex, "Normal", "VEC3" /* VEC3 */, 5126 /* FLOAT */, normals.length / normalStrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.NORMAL = this.accessors.length - 1;
-                            }
-                            if (tangentBufferViewIndex !== null) {
-                                var tangentVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.TangentKind);
-                                var tangents = tangentVertexBuffer.getData();
-                                var tangentStrideSize = tangentVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var accessor = this.createAccessor(tangentBufferViewIndex, "Tangent", "VEC4" /* VEC4 */, 5126 /* FLOAT */, tangents.length / tangentStrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.TANGENT = this.accessors.length - 1;
-                            }
-                            if (colorBufferViewIndex !== null) {
-                                var colorVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.ColorKind);
-                                var colors = colorVertexBuffer.getData();
-                                var colorStrideSize = colorVertexBuffer.getStrideSize();
-                                // Create accessor
-                                var accessor = this.createAccessor(colorBufferViewIndex, "Color", "VEC4" /* VEC4 */, 5126 /* FLOAT */, colors.length / colorStrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.COLOR_0 = this.accessors.length - 1;
-                            }
-                            if (texCoord0BufferViewIndex !== null) {
-                                // Create accessor
-                                var texCoord0VertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.UVKind);
-                                var texCoord0s = texCoord0VertexBuffer.getData();
-                                var texCoord0StrideSize = texCoord0VertexBuffer.getStrideSize();
-                                var accessor = this.createAccessor(texCoord0BufferViewIndex, "Texture Coords 0", "VEC2" /* VEC2 */, 5126 /* FLOAT */, texCoord0s.length / texCoord0StrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.TEXCOORD_0 = this.accessors.length - 1;
-                            }
-                            if (texCoord1BufferViewIndex !== null) {
-                                // Create accessor
-                                var texCoord1VertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.UV2Kind);
-                                var texCoord1s = texCoord1VertexBuffer.getData();
-                                var texCoord1StrideSize = texCoord1VertexBuffer.getStrideSize();
-                                var accessor = this.createAccessor(texCoord1BufferViewIndex, "Texture Coords 1", "VEC2" /* VEC2 */, 5126 /* FLOAT */, texCoord1s.length / texCoord1StrideSize);
-                                this.accessors.push(accessor);
-                                meshPrimitive.attributes.TEXCOORD_1 = this.accessors.length - 1;
+                    if (bufferMesh.getTotalIndices()) {
+                        var indices = bufferMesh.getIndices();
+                        if (indices) {
+                            if (dataBuffer) {
+                                var end = indices.length;
+                                var byteOff = byteOffset;
+                                for (var k = 0; k < end; ++k) {
+                                    dataBuffer.setUint32(byteOff, indices[k], true);
+                                    byteOff += 4;
+                                }
+                                byteOffset = byteOff;
                             }
                             }
-                            if (indexBufferViewIndex) {
-                                // Create accessor
-                                var accessor = this.createAccessor(indexBufferViewIndex, "Indices", "SCALAR" /* SCALAR */, 5125 /* UNSIGNED_INT */, submesh.indexCount, submesh.indexStart * 4);
-                                this.accessors.push(accessor);
-                                meshPrimitive.indices = this.accessors.length - 1;
+                            else {
+                                var byteLength = indices.length * 4;
+                                var bufferView = this.createBufferView(0, byteOffset, byteLength, undefined, "Indices - " + bufferMesh.name);
+                                byteOffset += byteLength;
+                                this.bufferViews.push(bufferView);
+                                indexBufferViewIndex = this.bufferViews.length - 1;
                             }
                             }
                         }
                         }
-                        if (bufferMesh.material) {
-                            if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
-                                var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
-                                meshPrimitive.material = materialIndex;
+                    }
+                    if (babylonMesh.subMeshes) {
+                        // go through all mesh primitives (submeshes)
+                        for (var _a = 0, _b = babylonMesh.subMeshes; _a < _b.length; _a++) {
+                            var submesh = _b[_a];
+                            var meshPrimitive = { attributes: {} };
+                            // Create a bufferview storing all the positions
+                            if (!dataBuffer) {
+                                for (var _c = 0, attributeData_2 = attributeData; _c < attributeData_2.length; _c++) {
+                                    var attribute = attributeData_2[_c];
+                                    var attributeKind = attribute.kind;
+                                    if (bufferMesh.isVerticesDataPresent(attributeKind)) {
+                                        var vertexBuffer = bufferMesh.getVertexBuffer(attributeKind);
+                                        if (vertexBuffer) {
+                                            var bufferData = vertexBuffer.getData();
+                                            if (bufferData) {
+                                                var strideSize = vertexBuffer.getStrideSize();
+                                                var minMax = void 0;
+                                                var min = null;
+                                                var max = null;
+                                                var bufferViewIndex = attribute.bufferViewIndex;
+                                                if (bufferViewIndex != undefined) {
+                                                    if (attributeKind == BABYLON.VertexBuffer.PositionKind) {
+                                                        minMax = this.calculateMinMaxPositions(bufferData, 0, bufferData.length / strideSize);
+                                                        min = minMax.min;
+                                                        max = minMax.max;
+                                                    }
+                                                    var accessor = this.createAccessor(bufferViewIndex, attributeKind + " - " + babylonMesh.name, attribute.accessorType, 5126 /* FLOAT */, bufferData.length / strideSize, 0, min, max);
+                                                    this.accessors.push(accessor);
+                                                    switch (attributeKind) {
+                                                        case BABYLON.VertexBuffer.PositionKind: {
+                                                            meshPrimitive.attributes.POSITION = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.NormalKind: {
+                                                            meshPrimitive.attributes.NORMAL = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.ColorKind: {
+                                                            meshPrimitive.attributes.COLOR_0 = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.TangentKind: {
+                                                            meshPrimitive.attributes.TANGENT = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.UVKind: {
+                                                            meshPrimitive.attributes.TEXCOORD_0 = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        case BABYLON.VertexBuffer.UV2Kind: {
+                                                            meshPrimitive.attributes.TEXCOORD_1 = this.accessors.length - 1;
+                                                            break;
+                                                        }
+                                                        default: {
+                                                            BABYLON.Tools.Warn("Unsupported Vertex Buffer Type: " + attributeKind);
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                if (indexBufferViewIndex) {
+                                    // Create accessor
+                                    var accessor = this.createAccessor(indexBufferViewIndex, "indices - " + babylonMesh.name, "SCALAR" /* SCALAR */, 5125 /* UNSIGNED_INT */, submesh.indexCount, submesh.indexStart * 4, null, null);
+                                    this.accessors.push(accessor);
+                                    meshPrimitive.indices = this.accessors.length - 1;
+                                }
                             }
                             }
-                            else if (bufferMesh.material instanceof BABYLON.MultiMaterial) {
-                                var babylonMultiMaterial = bufferMesh.material;
-                                var material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
-                                if (material !== null) {
-                                    var materialIndex = babylonMesh.getScene().materials.indexOf(material);
+                            if (bufferMesh.material) {
+                                if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                                    var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
                                     meshPrimitive.material = materialIndex;
                                     meshPrimitive.material = materialIndex;
                                 }
                                 }
+                                else if (bufferMesh.material instanceof BABYLON.MultiMaterial) {
+                                    var babylonMultiMaterial = bufferMesh.material;
+                                    var material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
+                                    if (material) {
+                                        var materialIndex = babylonMesh.getScene().materials.indexOf(material);
+                                        meshPrimitive.material = materialIndex;
+                                    }
+                                }
+                                else {
+                                    BABYLON.Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
+                                }
                             }
                             }
-                            else {
-                                BABYLON.Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
-                            }
+                            mesh.primitives.push(meshPrimitive);
                         }
                         }
-                        mesh.primitives.push(meshPrimitive);
                     }
                     }
                 }
                 }
                 return byteOffset;
                 return byteOffset;
@@ -891,47 +767,90 @@ var BABYLON;
              * Returns the the total byte offset.
              * Returns the the total byte offset.
              * @param babylonScene - Babylon scene to get the mesh data from.
              * @param babylonScene - Babylon scene to get the mesh data from.
              * @param byteOffset - Offset to start from in bytes.
              * @param byteOffset - Offset to start from in bytes.
-             * @param dataBuffer - Buffer to write geometry data to.
              * @returns bytelength + byteoffset
              * @returns bytelength + byteoffset
              */
              */
-            _Exporter.prototype.createScene = function (babylonScene, byteOffset, dataBuffer) {
-                if (babylonScene.meshes.length > 0) {
+            _Exporter.prototype.createScene = function (babylonScene, byteOffset) {
+                if (babylonScene.meshes.length) {
                     var babylonMeshes = babylonScene.meshes;
                     var babylonMeshes = babylonScene.meshes;
                     var scene = { nodes: new Array() };
                     var scene = { nodes: new Array() };
-                    if (dataBuffer == null) {
-                        GLTF2._GLTFMaterial.ConvertMaterialsToGLTF(babylonScene.materials, "image/jpeg" /* JPEG */, this.images, this.textures, this.materials, this.imageData, true);
-                    }
+                    GLTF2._GLTFMaterial.ConvertMaterialsToGLTF(babylonScene.materials, "image/jpeg" /* JPEG */, this.images, this.textures, this.materials, this.imageData, true);
+                    var result = this.createNodeMap(babylonScene, byteOffset);
+                    this.nodeMap = result.nodeMap;
+                    this.totalByteLength = result.byteOffset;
+                    this.binaryBuffer = new ArrayBuffer(this.totalByteLength);
+                    var dataBuffer = new DataView(this.binaryBuffer);
                     for (var i = 0; i < babylonMeshes.length; ++i) {
                     for (var i = 0; i < babylonMeshes.length; ++i) {
                         if (this.options &&
                         if (this.options &&
-                            this.options.shouldExportMesh !== undefined &&
+                            this.options.shouldExportMesh != undefined &&
                             !this.options.shouldExportMesh(babylonMeshes[i])) {
                             !this.options.shouldExportMesh(babylonMeshes[i])) {
                             continue;
                             continue;
                         }
                         }
                         else {
                         else {
-                            // create node to hold translation/rotation/scale and the mesh
-                            var node = { mesh: -1 };
                             var babylonMesh = babylonMeshes[i];
                             var babylonMesh = babylonMeshes[i];
-                            var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
-                            // Set transformation
-                            this.setNodeTransformation(node, babylonMesh, useRightHandedSystem);
-                            // create mesh
-                            var mesh = { primitives: new Array() };
-                            mesh.primitives = [];
-                            byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                            // go through all mesh primitives (submeshes)
-                            this.meshes.push(mesh);
-                            node.mesh = this.meshes.length - 1;
-                            if (babylonMesh.name) {
-                                node.name = babylonMesh.name;
+                            // Build Hierarchy with the node map.
+                            var glTFNodeIndex = this.nodeMap[babylonMesh.uniqueId];
+                            var glTFNode = this.nodes[glTFNodeIndex];
+                            if (!babylonMesh.parent) {
+                                scene.nodes.push(glTFNodeIndex);
                             }
                             }
-                            this.nodes.push(node);
-                            scene.nodes.push(this.nodes.length - 1);
+                            var directDescendents = babylonMesh.getDescendants(true);
+                            if (!glTFNode.children && directDescendents && directDescendents.length) {
+                                glTFNode.children = [];
+                                for (var _i = 0, directDescendents_1 = directDescendents; _i < directDescendents_1.length; _i++) {
+                                    var descendent = directDescendents_1[_i];
+                                    glTFNode.children.push(this.nodeMap[descendent.uniqueId]);
+                                }
+                            }
+                            var mesh = { primitives: new Array() };
+                            byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
                         }
                         }
                     }
                     }
                     this.scenes.push(scene);
                     this.scenes.push(scene);
                 }
                 }
                 return byteOffset;
                 return byteOffset;
             };
             };
+            /**
+             * Creates a mapping of Node unique id to node index
+             * @param scene - Babylon Scene.
+             * @param byteOffset - The initial byte offset.
+             * @returns - Node mapping of unique id to index.
+             */
+            _Exporter.prototype.createNodeMap = function (scene, byteOffset) {
+                var nodeMap = {};
+                for (var _i = 0, _a = scene.meshes; _i < _a.length; _i++) {
+                    var babylonMesh = _a[_i];
+                    var result = this.createNode(babylonMesh, byteOffset, null);
+                    this.nodes.push(result.node);
+                    nodeMap[babylonMesh.uniqueId] = this.nodes.length - 1;
+                    byteOffset = result.byteOffset;
+                }
+                return { nodeMap: nodeMap, byteOffset: byteOffset };
+            };
+            /**
+             * Creates a glTF node from a Babylon mesh.
+             * @param babylonMesh - Source Babylon mesh.
+             * @param byteOffset - The initial byte offset.
+             * @param dataBuffer - Buffer for storing geometry data.
+             * @returns - Object containing an INode and byteoffset.
+             */
+            _Exporter.prototype.createNode = function (babylonMesh, byteOffset, dataBuffer) {
+                // create node to hold translation/rotation/scale and the mesh
+                var node = {};
+                if (babylonMesh.name) {
+                    node.name = babylonMesh.name;
+                }
+                // Set transformation
+                this.setNodeTransformation(node, babylonMesh);
+                // create mesh
+                var mesh = { primitives: new Array() };
+                mesh.primitives = [];
+                byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
+                if (mesh.primitives.length) {
+                    this.meshes.push(mesh);
+                    node.mesh = this.meshes.length - 1;
+                }
+                return { node: node, byteOffset: byteOffset };
+            };
             return _Exporter;
             return _Exporter;
         }());
         }());
         GLTF2._Exporter = _Exporter;
         GLTF2._Exporter = _Exporter;

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 62 - 24
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -363,6 +363,18 @@ declare module BABYLON.GLTF2 {
          */
          */
         private imageData;
         private imageData;
         /**
         /**
+         * Stores a map of the unique id of a node to its index in the node array.
+         */
+        private nodeMap;
+        /**
+         * Stores the binary buffer used to store geometry data.
+         */
+        private binaryBuffer;
+        /**
+         * Specifies if the Babylon scene should be converted to right-handed on export.
+         */
+        private convertToRightHandedSystem;
+        /**
          * Creates a glTF Exporter instance, which can accept optional exporter options.
          * Creates a glTF Exporter instance, which can accept optional exporter options.
          * @param babylonScene - Babylon scene object
          * @param babylonScene - Babylon scene object
          * @param options - Options to modify the behavior of the exporter.
          * @param options - Options to modify the behavior of the exporter.
@@ -380,26 +392,42 @@ declare module BABYLON.GLTF2 {
         private createBufferView(bufferIndex, byteOffset, byteLength, byteStride?, name?);
         private createBufferView(bufferIndex, byteOffset, byteLength, byteStride?, name?);
         /**
         /**
          * Creates an accessor based on the supplied arguments
          * Creates an accessor based on the supplied arguments
-         * @param bufferviewIndex
-         * @param name
-         * @param type
-         * @param componentType
-         * @param count
-         * @param min
-         * @param max
+         * @param bufferviewIndex - The index of the bufferview referenced by this accessor.
+         * @param name - The name of the accessor.
+         * @param type - The type of the accessor.
+         * @param componentType - The datatype of components in the attribute.
+         * @param count - The number of attributes referenced by this accessor.
+         * @param byteOffset - The offset relative to the start of the bufferView in bytes.
+         * @param min - Minimum value of each component in this attribute.
+         * @param max - Maximum value of each component in this attribute.
          * @returns - accessor for glTF
          * @returns - accessor for glTF
          */
          */
-        private createAccessor(bufferviewIndex, name, type, componentType, count, byteOffset?, min?, max?);
+        private createAccessor(bufferviewIndex, name, type, componentType, count, byteOffset, min, max);
         /**
         /**
-         * Calculates the minimum and maximum values of an array of floats, based on stride
-         * @param buff - Data to check for min and max values.
-         * @param vertexStart - Start offset to calculate min and max values.
+         * Calculates the minimum and maximum values of an array of position floats.
+         * @param positions - Positions array of a mesh.
+         * @param vertexStart - Starting vertex offset to calculate min and max values.
          * @param vertexCount - Number of vertices to check for min and max values.
          * @param vertexCount - Number of vertices to check for min and max values.
-         * @param stride - Offset between consecutive attributes.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @returns - min number array and max number array.
          * @returns - min number array and max number array.
          */
          */
-        private calculateMinMax(buff, vertexStart, vertexCount, stride, useRightHandedSystem);
+        private calculateMinMaxPositions(positions, vertexStart, vertexCount);
+        /**
+         * Converts a vector3 array to right-handed.
+         * @param vector - vector3 Array to convert to right-handed.
+         * @returns - right-handed Vector3 array.
+         */
+        private static GetRightHandedVector3(vector);
+        /**
+         * Converts a vector4 array to right-handed.
+         * @param vector - vector4 Array to convert to right-handed.
+         * @returns - right-handed vector4 array.
+         */
+        private static GetRightHandedVector4(vector);
+        /**
+         * Converts a quaternion to right-handed.
+         * @param quaternion - Source quaternion to convert to right-handed.
+         */
+        private static GetRightHandedQuaternion(quaternion);
         /**
         /**
          * Writes mesh attribute data to a data buffer.
          * Writes mesh attribute data to a data buffer.
          * Returns the bytelength of the data.
          * Returns the bytelength of the data.
@@ -408,10 +436,9 @@ declare module BABYLON.GLTF2 {
          * @param strideSize - Represents the offset between consecutive attributes
          * @param strideSize - Represents the offset between consecutive attributes
          * @param byteOffset - The offset to start counting bytes from.
          * @param byteOffset - The offset to start counting bytes from.
          * @param dataBuffer - The buffer to write the binary data to.
          * @param dataBuffer - The buffer to write the binary data to.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @returns - Byte length of the attribute data.
          * @returns - Byte length of the attribute data.
          */
          */
-        private writeAttributeData(vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer, useRightHandedSystem);
+        private writeAttributeData(vertexBufferKind, meshAttributeArray, strideSize, vertexBufferOffset, byteOffset, dataBuffer);
         /**
         /**
          * Generates glTF json data
          * Generates glTF json data
          * @param shouldUseGlb - Indicates whether the json should be written for a glb file.
          * @param shouldUseGlb - Indicates whether the json should be written for a glb file.
@@ -448,38 +475,49 @@ declare module BABYLON.GLTF2 {
          * Sets the TRS for each node
          * Sets the TRS for each node
          * @param node - glTF Node for storing the transformation data.
          * @param node - glTF Node for storing the transformation data.
          * @param babylonMesh - Babylon mesh used as the source for the transformation data.
          * @param babylonMesh - Babylon mesh used as the source for the transformation data.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          */
          */
-        private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
+        private setNodeTransformation(node, babylonMesh);
         /**
         /**
          * Creates a bufferview based on the vertices type for the Babylon mesh
          * Creates a bufferview based on the vertices type for the Babylon mesh
          * @param kind - Indicates the type of vertices data.
          * @param kind - Indicates the type of vertices data.
          * @param babylonMesh - The Babylon mesh to get the vertices data from.
          * @param babylonMesh - The Babylon mesh to get the vertices data from.
          * @param byteOffset - The offset from the buffer to start indexing from.
          * @param byteOffset - The offset from the buffer to start indexing from.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @param dataBuffer - The buffer to write the bufferview data to.
          * @param dataBuffer - The buffer to write the bufferview data to.
          * @returns bytelength of the bufferview data.
          * @returns bytelength of the bufferview data.
          */
          */
-        private createBufferViewKind(kind, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
+        private createBufferViewKind(kind, babylonMesh, byteOffset, dataBuffer);
         /**
         /**
          * Sets data for the primitive attributes of each submesh
          * Sets data for the primitive attributes of each submesh
          * @param mesh - glTF Mesh object to store the primitive attribute information.
          * @param mesh - glTF Mesh object to store the primitive attribute information.
          * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
          * @param babylonMesh - Babylon mesh to get the primitive attribute data from.
          * @param byteOffset - The offset in bytes of the buffer data.
          * @param byteOffset - The offset in bytes of the buffer data.
-         * @param useRightHandedSystem - Indicates whether the data should be modified for a right or left handed coordinate system.
          * @param dataBuffer - Buffer to write the attribute data to.
          * @param dataBuffer - Buffer to write the attribute data to.
          * @returns - 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);
+        private setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
         /**
         /**
          * Creates a glTF scene based on the array of meshes.
          * Creates a glTF scene based on the array of meshes.
          * Returns the the total byte offset.
          * Returns the the total byte offset.
          * @param babylonScene - Babylon scene to get the mesh data from.
          * @param babylonScene - Babylon scene to get the mesh data from.
          * @param byteOffset - Offset to start from in bytes.
          * @param byteOffset - Offset to start from in bytes.
-         * @param dataBuffer - Buffer to write geometry data to.
          * @returns bytelength + byteoffset
          * @returns bytelength + byteoffset
          */
          */
-        private createScene(babylonScene, byteOffset, dataBuffer);
+        private createScene(babylonScene, byteOffset);
+        /**
+         * Creates a mapping of Node unique id to node index
+         * @param scene - Babylon Scene.
+         * @param byteOffset - The initial byte offset.
+         * @returns - Node mapping of unique id to index.
+         */
+        private createNodeMap(scene, byteOffset);
+        /**
+         * Creates a glTF node from a Babylon mesh.
+         * @param babylonMesh - Source Babylon mesh.
+         * @param byteOffset - The initial byte offset.
+         * @param dataBuffer - Buffer for storing geometry data.
+         * @returns - Object containing an INode and byteoffset.
+         */
+        private createNode(babylonMesh, byteOffset, dataBuffer);
     }
     }
 }
 }
 
 

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-serializers",
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1,7 +1,7 @@
 {
 {
-  "errors": 7253,
+  "errors": 7238,
   "babylon.typedoc.json": {
   "babylon.typedoc.json": {
-    "errors": 7253,
+    "errors": 7238,
     "AnimationKeyInterpolation": {
     "AnimationKeyInterpolation": {
       "Enumeration": {
       "Enumeration": {
         "Comments": {
         "Comments": {
@@ -8873,61 +8873,6 @@
         }
         }
       }
       }
     },
     },
-    "DepthRenderer": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Constructor": {
-        "new DepthRenderer": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "type": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
-      "Method": {
-        "dispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getDepthMap": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "isReady": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "subMesh": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "useInstances": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      }
-    },
     "DisplayPassPostProcess": {
     "DisplayPassPostProcess": {
       "Class": {
       "Class": {
         "Comments": {
         "Comments": {
@@ -27690,11 +27635,6 @@
             "MissingText": true
             "MissingText": true
           }
           }
         },
         },
-        "disableDepthRenderer": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "disableGeometryBufferRenderer": {
         "disableGeometryBufferRenderer": {
           "Comments": {
           "Comments": {
             "MissingText": true
             "MissingText": true
@@ -27715,11 +27655,6 @@
             "MissingText": true
             "MissingText": true
           }
           }
         },
         },
-        "enableDepthRenderer": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "enableGeometryBufferRenderer": {
         "enableGeometryBufferRenderer": {
           "Comments": {
           "Comments": {
             "MissingText": true
             "MissingText": true
@@ -28271,11 +28206,6 @@
             "MissingText": true
             "MissingText": true
           }
           }
         },
         },
-        "getWorldExtends": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "incrementRenderId": {
         "incrementRenderId": {
           "Comments": {
           "Comments": {
             "MissingText": true
             "MissingText": true
@@ -28609,37 +28539,16 @@
         "simulatePointerDown": {
         "simulatePointerDown": {
           "Comments": {
           "Comments": {
             "MissingReturn": true
             "MissingReturn": true
-          },
-          "Parameter": {
-            "pickResult": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
           }
           }
         },
         },
         "simulatePointerMove": {
         "simulatePointerMove": {
           "Comments": {
           "Comments": {
             "MissingReturn": true
             "MissingReturn": true
-          },
-          "Parameter": {
-            "pickResult": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
           }
           }
         },
         },
         "simulatePointerUp": {
         "simulatePointerUp": {
           "Comments": {
           "Comments": {
             "MissingReturn": true
             "MissingReturn": true
-          },
-          "Parameter": {
-            "pickResult": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
           }
           }
         },
         },
         "sortLightsByPriority": {
         "sortLightsByPriority": {

+ 8 - 24
dist/preview release/viewer/babylon.viewer.d.ts

@@ -1,5 +1,3 @@
-/// <reference path="../babylon.d.ts"/>
-
 declare module BabylonViewer {
 declare module BabylonViewer {
 
 
     export let disableInit: boolean;
     export let disableInit: boolean;
@@ -56,7 +54,7 @@ declare module BabylonViewer {
         selector: string;
         selector: string;
         payload?: any;
         payload?: any;
     }
     }
-    class TemplateManager {
+    interface TemplateManager {
         containerElement: HTMLElement;
         containerElement: HTMLElement;
         onInit: BABYLON.Observable<Template>;
         onInit: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
@@ -64,20 +62,16 @@ declare module BabylonViewer {
         onAllLoaded: BABYLON.Observable<TemplateManager>;
         onAllLoaded: BABYLON.Observable<TemplateManager>;
         onEventTriggered: BABYLON.Observable<EventCallback>;
         onEventTriggered: BABYLON.Observable<EventCallback>;
         eventManager: EventManager;
         eventManager: EventManager;
-        private templates;
         constructor(containerElement: HTMLElement);
         constructor(containerElement: HTMLElement);
         initTemplate(templates: {
         initTemplate(templates: {
             [key: string]: ITemplateConfiguration;
             [key: string]: ITemplateConfiguration;
         }): void;
         }): void;
-        private buildHTMLTree(templates);
         getCanvas(): HTMLCanvasElement | null;
         getCanvas(): HTMLCanvasElement | null;
         getTemplate(name: string): Template | undefined;
         getTemplate(name: string): Template | undefined;
-        private checkLoadedState();
     }
     }
 
 
-    class Template {
+    interface Template {
         name: string;
         name: string;
-        private _configuration;
         onInit: BABYLON.Observable<Template>;
         onInit: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
         onAppended: BABYLON.Observable<Template>;
         onAppended: BABYLON.Observable<Template>;
@@ -87,7 +81,6 @@ declare module BabylonViewer {
         isShown: boolean;
         isShown: boolean;
         parent: HTMLElement;
         parent: HTMLElement;
         initPromise: Promise<Template>;
         initPromise: Promise<Template>;
-        private fragment;
         constructor(name: string, _configuration: ITemplateConfiguration);
         constructor(name: string, _configuration: ITemplateConfiguration);
         readonly configuration: ITemplateConfiguration;
         readonly configuration: ITemplateConfiguration;
         getChildElements(): Array<string>;
         getChildElements(): Array<string>;
@@ -95,11 +88,9 @@ declare module BabylonViewer {
         show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         dispose(): void;
         dispose(): void;
-        private registerEvents();
     }
     }
 
 
-    class ViewerManager {
-        private viewers;
+    interface ViewerManager {
         onViewerAdded: (viewer: AbstractViewer) => void;
         onViewerAdded: (viewer: AbstractViewer) => void;
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
         constructor();
         constructor();
@@ -107,7 +98,6 @@ declare module BabylonViewer {
         getViewerById(id: string): AbstractViewer;
         getViewerById(id: string): AbstractViewer;
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
-        private _onViewerAdded(viewer);
     }
     }
     export let viewerManager: ViewerManager;
     export let viewerManager: ViewerManager;
 
 
@@ -119,37 +109,31 @@ declare module BabylonViewer {
 
 
     export function InitTags(selector?: string): void;
     export function InitTags(selector?: string): void;
 
 
-    class EventManager {
-        private templateManager;
-        private callbacksContainer;
+    interface EventManager {
         constructor(templateManager: TemplateManager);
         constructor(templateManager: TemplateManager);
         registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
         registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
         unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
         unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-        private eventTriggered(data);
     }
     }
 
 
-    class PromiseObservable<T> extends BABYLON.Observable<T> {
+    interface PromiseObservable<T> extends BABYLON.Observable<T> {
         notifyWithPromise(eventData: T, mask?: number, target?: any, currentTarget?: any): Promise<any>;
         notifyWithPromise(eventData: T, mask?: number, target?: any, currentTarget?: any): Promise<any>;
     }
     }
 
 
     export interface IMapper {
     export interface IMapper {
         map(rawSource: any): ViewerConfiguration;
         map(rawSource: any): ViewerConfiguration;
     }
     }
-    class MapperManager {
-        private mappers;
-        static DefaultMapper: string;
+    interface MapperManager {
+        DefaultMapper: string;
         constructor();
         constructor();
         getMapper(type: string): IMapper;
         getMapper(type: string): IMapper;
         registerMapper(type: string, mapper: IMapper): void;
         registerMapper(type: string, mapper: IMapper): void;
     }
     }
     export let mapperManager: MapperManager;
     export let mapperManager: MapperManager;
 
 
-    class ConfigurationLoader {
-        private configurationCache;
+    interface ConfigurationLoader {
         constructor();
         constructor();
         loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
         loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
         getConfigurationType(type: string): void;
         getConfigurationType(type: string): void;
-        private loadFile(url);
     }
     }
     export let configurationLoader: ConfigurationLoader;
     export let configurationLoader: ConfigurationLoader;
 
 

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


File diff suppressed because it is too large
+ 926 - 517
dist/preview release/viewer/babylon.viewer.max.js


+ 4 - 484
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -1,486 +1,6 @@
-/// <reference types="babylonjs"/>
+/// <reference path="./babylon.d.ts"/>
+/// <reference path="./babylon.viewer.d.ts"/>
 
 
-declare module BabylonViewer {
-
-    export let disableInit: boolean;
-
-    export interface ITemplateConfiguration {
-        location?: string;
-        html?: string;
-        id?: string;
-        params?: {
-            [key: string]: string | number | boolean | object;
-        };
-        events?: {
-            pointerdown?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerup?: boolean | {
-                [id: string]: boolean;
-            };
-            pointermove?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerover?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerout?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerenter?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerleave?: boolean | {
-                [id: string]: boolean;
-            };
-            pointercancel?: boolean | {
-                [id: string]: boolean;
-            };
-            click?: boolean | {
-                [id: string]: boolean;
-            };
-            dragstart?: boolean | {
-                [id: string]: boolean;
-            };
-            drop?: boolean | {
-                [id: string]: boolean;
-            };
-            [key: string]: boolean | {
-                [id: string]: boolean;
-            } | undefined;
-        };
-    }
-    export interface EventCallback {
-        event: Event;
-        template: Template;
-        selector: string;
-        payload?: any;
-    }
-    class TemplateManager {
-        containerElement: HTMLElement;
-        onInit: BABYLON.Observable<Template>;
-        onLoaded: BABYLON.Observable<Template>;
-        onStateChange: BABYLON.Observable<Template>;
-        onAllLoaded: BABYLON.Observable<TemplateManager>;
-        onEventTriggered: BABYLON.Observable<EventCallback>;
-        eventManager: EventManager;
-        private templates;
-        constructor(containerElement: HTMLElement);
-        initTemplate(templates: {
-            [key: string]: ITemplateConfiguration;
-        }): void;
-        private buildHTMLTree(templates);
-        getCanvas(): HTMLCanvasElement | null;
-        getTemplate(name: string): Template | undefined;
-        private checkLoadedState();
-    }
-
-    class Template {
-        name: string;
-        private _configuration;
-        onInit: BABYLON.Observable<Template>;
-        onLoaded: BABYLON.Observable<Template>;
-        onAppended: BABYLON.Observable<Template>;
-        onStateChange: BABYLON.Observable<Template>;
-        onEventTriggered: BABYLON.Observable<EventCallback>;
-        isLoaded: boolean;
-        isShown: boolean;
-        parent: HTMLElement;
-        initPromise: Promise<Template>;
-        private fragment;
-        constructor(name: string, _configuration: ITemplateConfiguration);
-        readonly configuration: ITemplateConfiguration;
-        getChildElements(): Array<string>;
-        appendTo(parent: HTMLElement): void;
-        show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
-        hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
-        dispose(): void;
-        private registerEvents();
-    }
-
-    class ViewerManager {
-        private viewers;
-        onViewerAdded: (viewer: AbstractViewer) => void;
-        onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
-        constructor();
-        addViewer(viewer: AbstractViewer): void;
-        getViewerById(id: string): AbstractViewer;
-        getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
-        getViewerPromiseById(id: string): Promise<AbstractViewer>;
-        private _onViewerAdded(viewer);
-    }
-    export let viewerManager: ViewerManager;
-
-    export const enum CameraBehavior {
-        AUTOROTATION = 0,
-        BOUNCING = 1,
-        FRAMING = 2,
-    }
-
-    export function InitTags(selector?: string): void;
-
-    class EventManager {
-        private templateManager;
-        private callbacksContainer;
-        constructor(templateManager: TemplateManager);
-        registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-        unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-        private eventTriggered(data);
-    }
-
-    class PromiseObservable<T> extends BABYLON.Observable<T> {
-        notifyWithPromise(eventData: T, mask?: number, target?: any, currentTarget?: any): Promise<any>;
-    }
-
-    export interface IMapper {
-        map(rawSource: any): ViewerConfiguration;
-    }
-    class MapperManager {
-        private mappers;
-        static DefaultMapper: string;
-        constructor();
-        getMapper(type: string): IMapper;
-        registerMapper(type: string, mapper: IMapper): void;
-    }
-    export let mapperManager: MapperManager;
-
-    class ConfigurationLoader {
-        private configurationCache;
-        constructor();
-        loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
-        getConfigurationType(type: string): void;
-        private loadFile(url);
-    }
-    export let configurationLoader: ConfigurationLoader;
-
-
-    /////> configuration
-    export interface ViewerConfiguration {
-
-        // configuration version
-        version?: string;
-        extends?: string; // is this configuration extending an existing configuration?
-
-        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;
-            payload?: any;
-            mapper?: string; // json (default), html, yaml, xml, etc'. if not provided, file extension will be used.
-        };
-
-        // names of functions in the window context.
-        observers?: IObserversConfiguration;
-
-        canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
-
-        model?: IModelConfiguration | string;
-
-        scene?: ISceneConfiguration;
-        optimizer?: ISceneOptimizerConfiguration | boolean;
-        // at the moment, support only a single camera.
-        camera?: ICameraConfiguration,
-        skybox?: boolean | ISkyboxConfiguration;
-
-        ground?: boolean | IGroundConfiguration;
-        lights?: { [name: string]: boolean | ILightConfiguration },
-        // engine configuration. optional!
-        engine?: {
-            antialiasing?: boolean;
-            disableResize?: boolean;
-            engineOptions?: { [key: string]: any };
-            adaptiveQuality?: boolean;
-        },
-        //templateStructure?: ITemplateStructure,
-        templates?: {
-            main: ITemplateConfiguration,
-            [key: string]: ITemplateConfiguration
-        };
-
-        customShaders?: {
-            shaders?: {
-                [key: string]: string;
-            };
-            includes?: {
-                [key: string]: string;
-            }
-        }
-
-        // features that are being tested.
-        // those features' syntax will change and move out! 
-        // Don't use in production (or be ready to make the changes :) )
-        lab?: {
-            flashlight?: boolean | {
-                exponent?: number;
-                angle?: number;
-                intensity?: number;
-                diffuse?: { r: number, g: number, b: number };
-                specular?: { r: number, g: number, b: number };
-            }
-            hideLoadingDelay?: number;
-        }
-    }
-
-    export interface IModelConfiguration {
-        url?: string;
-        loader?: string; // obj, gltf?
-        position?: { x: number, y: number, z: number };
-        rotation?: { x: number, y: number, z: number, w?: number };
-        scaling?: { x: number, y: number, z: number };
-        parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
-
-        castShadow?: boolean;
-        normalize?: boolean | {
-            center?: boolean;
-            unitSize?: boolean;
-            parentIndex?: number;
-        }; // shoud the model be scaled to unit-size
-
-        title?: string;
-        subtitle?: string;
-        thumbnail?: string; // URL or data-url
-
-        // [propName: string]: any; // further configuration, like title and creator
-    }
-
-    export interface ISkyboxConfiguration {
-        cubeTexture?: {
-            noMipMap?: boolean;
-            gammaSpace?: boolean;
-            url?: string | Array<string>;
-        };
-        color?: { r: number, g: number, b: number };
-        pbr?: boolean; // deprecated
-        scale?: number;
-        blur?: number; // deprecated
-        material?: {
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
-            [propName: string]: any;
-        };
-        infiniteDIstance?: boolean;
-
-    }
-
-    export interface IGroundConfiguration {
-        size?: number;
-        receiveShadows?: boolean;
-        shadowLevel?: number;
-        shadowOnly?: boolean; // deprecated
-        mirror?: boolean | {
-            sizeRatio?: number;
-            blurKernel?: number;
-            amount?: number;
-            fresnelWeight?: number;
-            fallOffDistance?: number;
-            textureType?: number;
-        };
-        texture?: string;
-        color?: { r: number, g: number, b: number };
-        opacity?: number;
-        material?: { // deprecated!
-            [propName: string]: any;
-        };
-    }
-
-    export interface ISceneConfiguration {
-        debug?: boolean;
-        autoRotate?: boolean; // deprecated
-        rotationSpeed?: number; // deprecated
-        defaultCamera?: boolean; // deprecated
-        defaultLight?: boolean; // deprecated
-        clearColor?: { r: number, g: number, b: number, a: number };
-        imageProcessingConfiguration?: IImageProcessingConfiguration;
-        environmentTexture?: string;
-    }
-
-    export interface ISceneOptimizerConfiguration {
-        targetFrameRate?: number;
-        trackerDuration?: number;
-        autoGeneratePriorities?: boolean;
-        improvementMode?: boolean;
-        degradation?: string; // low, moderate, high
-        types?: {
-            texture?: ISceneOptimizerParameters;
-            hardwareScaling?: ISceneOptimizerParameters;
-            shadow?: ISceneOptimizerParameters;
-            postProcess?: ISceneOptimizerParameters;
-            lensFlare?: ISceneOptimizerParameters;
-            particles?: ISceneOptimizerParameters;
-            renderTarget?: ISceneOptimizerParameters;
-            mergeMeshes?: ISceneOptimizerParameters;
-        }
-    }
-
-    export interface IObserversConfiguration {
-        onEngineInit?: string;
-        onSceneInit?: string;
-        onModelLoaded?: string;
-    }
-
-    export interface ICameraConfiguration {
-        position?: { x: number, y: number, z: number };
-        rotation?: { x: number, y: number, z: number, w: number };
-        fov?: number;
-        fovMode?: number;
-        minZ?: number;
-        maxZ?: number;
-        inertia?: number;
-        behaviors?: {
-            [name: string]: number | {
-                type: number;
-                [propName: string]: any;
-            };
-        };
-
-        [propName: string]: any;
-    }
-
-    export interface ILightConfiguration {
-        type: number;
-        name?: string;
-        disabled?: boolean;
-        position?: { x: number, y: number, z: number };
-        target?: { x: number, y: number, z: number };
-        direction?: { x: number, y: number, z: number };
-        diffuse?: { r: number, g: number, b: number };
-        specular?: { r: number, g: number, b: number };
-        intensity?: number;
-        intensityMode?: number;
-        radius?: number;
-        shadownEnabled?: boolean; // only on specific lights!
-        shadowConfig?: {
-            useBlurExponentialShadowMap?: boolean;
-            useKernelBlur?: boolean;
-            blurKernel?: number;
-            blurScale?: number;
-            minZ?: number;
-            maxZ?: number;
-            frustumSize?: number;
-            angleScale?: number;
-            [propName: string]: any;
-        }
-        [propName: string]: any;
-
-        // no behaviors for light at the moment, but allowing configuration for future reference.
-        behaviors?: {
-            [name: string]: number | {
-                type: number;
-                [propName: string]: any;
-            };
-        };
-    }
-
-    export interface ISceneOptimizerParameters {
-        priority?: number;
-        maximumSize?: number;
-        step?: number;
-    }
-
-    export interface IImageProcessingConfiguration {
-        colorGradingEnabled?: boolean;
-        colorCurvesEnabled?: boolean;
-        colorCurves?: {
-            globalHue?: number;
-            globalDensity?: number;
-            globalSaturation?: number;
-            globalExposure?: number;
-            highlightsHue?: number;
-            highlightsDensity?: number;
-            highlightsSaturation?: number;
-            highlightsExposure?: number;
-            midtonesHue?: number;
-            midtonesDensity?: number;
-            midtonesSaturation?: number;
-            midtonesExposure?: number;
-            shadowsHue?: number;
-            shadowsDensity?: number;
-            shadowsSaturation?: number;
-            shadowsExposure?: number;
-        };
-        colorGradingWithGreenDepth?: boolean;
-        colorGradingBGR?: boolean;
-        exposure?: number;
-        toneMappingEnabled?: boolean;
-        contrast?: number;
-        vignetteEnabled?: boolean;
-        vignetteStretch?: number;
-        vignetteCentreX?: number;
-        vignetteCentreY?: number;
-        vignetteWeight?: number;
-        vignetteColor?: { r: number, g: number, b: number, a?: number };
-        vignetteCameraFov?: number;
-        vignetteBlendMode?: number;
-        vignetteM?: boolean;
-        applyByPostProcess?: boolean;
-
-    }
-    /////>configuration
-
-    /////<viewer
-    export abstract class AbstractViewer {
-        containerElement: HTMLElement;
-        templateManager: TemplateManager;
-        camera: BABYLON.ArcRotateCamera;
-        engine: BABYLON.Engine;
-        scene: BABYLON.Scene;
-        baseId: string;
-        canvas: HTMLCanvasElement;
-        protected configuration: ViewerConfiguration;
-        environmentHelper: BABYLON.EnvironmentHelper;
-        protected defaultHighpTextureType: number;
-        protected shadowGeneratorBias: number;
-        protected defaultPipelineTextureType: number;
-        protected maxShadows: number;
-        onSceneInitObservable: BABYLON.Observable<BABYLON.Scene>;
-        onEngineInitObservable: BABYLON.Observable<BABYLON.Engine>;
-        onModelLoadedObservable: BABYLON.Observable<BABYLON.AbstractMesh[]>;
-        onModelLoadProgressObservable: BABYLON.Observable<BABYLON.SceneLoaderProgressEvent>;
-        onModelLoadErrorObservable: BABYLON.Observable<{ message: string; exception: any }>;
-        onLoaderInitObservable: BABYLON.Observable<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>;
-        onInitDoneObservable: BABYLON.Observable<AbstractViewer>;
-        constructor(containerElement: HTMLElement, initialConfiguration?: ViewerConfiguration);
-        getBaseId(): string;
-        protected abstract prepareContainerElement(): any;
-        protected onTemplatesLoaded(): Promise<AbstractViewer>;
-        protected initEngine(): Promise<BABYLON.Engine>;
-        protected initScene(): Promise<BABYLON.Scene>;
-        dispose(): void;
-        loadModel(model?: any, clearScene?: boolean): Promise<BABYLON.Scene>;
-        lastUsedLoader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
-        sceneOptimizer: BABYLON.SceneOptimizer;
-        protected registeredOnBeforerenderFunctions: Array<() => void>;
-        isCanvasInDOM(): boolean;
-        protected resize: () => void;
-        protected render: () => void;
-        updateConfiguration(newConfiguration: Partial<ViewerConfiguration>): void;
-        protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): void;
-        protected configureScene(sceneConfig: ISceneConfiguration, optimizerConfig?: ISceneOptimizerConfiguration): void;
-        protected configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean): void;
-        protected configureObservers(observersConfiguration: IObserversConfiguration): void;
-        protected configureCamera(cameraConfig: ICameraConfiguration, focusMeshes: Array<BABYLON.AbstractMesh>): void;
-        protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean }, focusMeshes: Array<BABYLON.AbstractMesh>): void;
-        protected configureModel(modelConfiguration: Partial<IModelConfiguration>, focusMeshes: Array<BABYLON.AbstractMesh>): void;
-        dispose(): void;
-        protected initEnvironment(focusMeshes: Array<BABYLON.AbstractMesh>): Promise<BABYLON.Scene>;
-        protected injectCustomShaders(): void;
-        protected extendClassWithConfig(object: any, config: any): void;
-        protected handleHardwareLimitations(): void;
-
-
-    }
-
-    export class DefaultViewer extends AbstractViewer {
-        containerElement: HTMLElement;
-        camera: BABYLON.ArcRotateCamera;
-        constructor(containerElement: HTMLElement, initialConfiguration?: ViewerConfiguration);
-        initScene(): Promise<BABYLON.Scene>;
-        protected onTemplatesLoaded(): Promise<AbstractViewer>;
-        protected prepareContainerElement(): void;
-        loadModel(model?: any): Promise<BABYLON.Scene>;
-        initEnvironment(focusMeshes?: Array<BABYLON.AbstractMesh>): Promise<BABYLON.Scene>;
-        showOverlayScreen(subScreen: string): Promise<Template>;
-        hideOverlayScreen(): Promise<Template>;
-        showLoadingScreen(): Promise<Template>;
-        hideLoadingScreen(): Promise<Template>;
-    }
+declare module "babylonjs-viewer" {
+    export = BabylonViewer;
 }
 }

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-viewer",
     "name": "babylonjs-viewer",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -12,7 +12,9 @@
     "main": "babylon.viewer.js",
     "main": "babylon.viewer.js",
     "files": [
     "files": [
         "babylon.viewer.js",
         "babylon.viewer.js",
+        "babylon.viewer.d.ts",
         "babylon.viewer.module.d.ts",
         "babylon.viewer.module.d.ts",
+        "babylon.d.ts",
         "readme.md",
         "readme.md",
         "package.json"
         "package.json"
     ],
     ],

+ 25 - 12
dist/preview release/viewer/readme.md

@@ -1,5 +1,4 @@
-Babylon.js Viewer
-=====================
+# Babylon.js Viewer
 
 
 Babylon's viewer is a wrapper around Babylon, that automatically initializes the needed components in order to display a loaded model. It is easy to use, and require no coding at all.
 Babylon's viewer is a wrapper around Babylon, that automatically initializes the needed components in order to display a loaded model. It is easy to use, and require no coding at all.
 
 
@@ -9,13 +8,13 @@ for basic and advanced usage instructions please read the doc at https://doc.bab
 
 
 The source code can be found at https://github.com/BabylonJS/Babylon.js/tree/master/Viewer
 The source code can be found at https://github.com/BabylonJS/Babylon.js/tree/master/Viewer
 
 
-# Basic usage
+## Basic usage
 
 
-to create a simple viewer add the following code to your HTML>
+to create a simple viewer add the following code to your HTML:
 
 
 ```HTML
 ```HTML
 <babylon model="https://playground.babylonjs.com/scenes/Rabbit.babylon"></babylon>
 <babylon model="https://playground.babylonjs.com/scenes/Rabbit.babylon"></babylon>
-<script src="https://viewer.babylonjs.com/viewer.min.js"></script>
+<script src="https://viewer.babylonjs.com/viewer.js"></script>
 ```
 ```
 
 
 Make sure to size the babylon HTML tag. For example:
 Make sure to size the babylon HTML tag. For example:
@@ -29,28 +28,42 @@ babylon {
 }
 }
 ```
 ```
 
 
-# Installation instructions
+## Installation instructions
 
 
-## CDN
+### CDN
 
 
-Compiled js files (minified) are offered on our public CDN here:
+Compiled js files are offered on our public CDN here:
 
 
-* https://viewer.babylonjs.com/serializers/viewer.min.js
+* https://viewer.babylonjs.com/viewer.js (minified)
+* https://viewer.babylonjs.com/viewer.max.js
 
 
-## NPM
+### Using NPM
 
 
 To install using npm :
 To install using npm :
 
 
-```
+```javascript
 npm install --save babylonjs-viewer
 npm install --save babylonjs-viewer
 ```
 ```
 
 
 Afterwards it can be imported to the project using:
 Afterwards it can be imported to the project using:
 
 
-```
+```javascript
 import from 'babylonjs-viewer';
 import from 'babylonjs-viewer';
 ```
 ```
 
 
 This will enable the BabylonViewer namespace.
 This will enable the BabylonViewer namespace.
 
 
 Using webpack to package your project will use the minified js file.
 Using webpack to package your project will use the minified js file.
+
+## TypeScript
+
+If you use the npm package, starting 3.2.0-alpha8 the babylon viewer has a module declaration file that also includes the BABYLON namespace.
+
+Using TypeScript and NPM you could do the following:
+
+```javascript
+import from 'babylonjs-viewer';
+
+// both namespaces are now available
+console.log(BabylonViewer, BABYLON)
+```

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

@@ -13,6 +13,8 @@
 - Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode) ([deltakosh](https://github.com/deltakosh))
 - Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode) ([deltakosh](https://github.com/deltakosh))
 - Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos ([DavidHGillen](https://github.com/DavidHGillen))
 - Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos ([DavidHGillen](https://github.com/DavidHGillen))
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
+- New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) Class and loading methods ([trevordev](https://github.com/trevordev))
+- Added depth of field effect to the default pipeline ([trevordev](https://github.com/trevordev))
 
 
 ## Updates
 ## Updates
 
 
@@ -41,7 +43,6 @@
    ([carloslanderas](https://github.com/carloslanderas))
    ([carloslanderas](https://github.com/carloslanderas))
 - (Viewer) initScene and initEngine can now be extended. onProgress during model loading is implemented as observable. ([RaananW](https://github.com/RaananW))
 - (Viewer) initScene and initEngine can now be extended. onProgress during model loading is implemented as observable. ([RaananW](https://github.com/RaananW))
 - glTF loader now supports the KHR_lights extension ([MiiBond](https://github.com/MiiBond))
 - glTF loader now supports the KHR_lights extension ([MiiBond](https://github.com/MiiBond))
-- Added depth of field effect to the default pipeline ([trevordev](https://github.com/trevordev))
 - The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
 - The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
 - Added base64 helper functions to `Tools` ([bghgary](https://github.com/bghgary))
 - Added base64 helper functions to `Tools` ([bghgary](https://github.com/bghgary))
 - Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))
 - Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))
@@ -52,7 +53,6 @@
 - SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
 - SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
 - SPS particle parenting feature ([jbousquie](https://github.com/jbousquie))
 - SPS particle parenting feature ([jbousquie](https://github.com/jbousquie))
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
-- AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
 - KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
 - KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
 - (Viewer) It is now possible to update parts of the configuration without rcreating the objects. Extra configuration can be loaded sync (if provided) ([RaananW](https://github.com/RaananW))
 - (Viewer) It is now possible to update parts of the configuration without rcreating the objects. Extra configuration can be loaded sync (if provided) ([RaananW](https://github.com/RaananW))
 - (Gulp) extra/external declarations can be prepended to final declarations during build. ([RaananW](https://github.com/RaananW))
 - (Gulp) extra/external declarations can be prepended to final declarations during build. ([RaananW](https://github.com/RaananW))
@@ -71,8 +71,12 @@
 - Add isThumbClamped option on GUI slider control ([JeanPhilippeKernel](https://github.com/JeanPhilippeKernel))
 - Add isThumbClamped option on GUI slider control ([JeanPhilippeKernel](https://github.com/JeanPhilippeKernel))
 - Add floating point texture support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
 - Add floating point texture support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
 - Support for mutli-touch when interacting with multiple gui elements simultaneously ([trevordev](https://github.com/trevordev))
 - Support for mutli-touch when interacting with multiple gui elements simultaneously ([trevordev](https://github.com/trevordev))
-- (Viewer) Declaration file published. ([RaananW](https://github.com/RaananW))
+- (Viewer) Declaration file published, ready for npm. ([RaananW](https://github.com/RaananW))
 - Added Draco mesh compression support to glTF 2.0 loader. ([bghgary](https://github.com/bghgary))
 - Added Draco mesh compression support to glTF 2.0 loader. ([bghgary](https://github.com/bghgary))
+- Support multiple simultaneous webVR controller gui interactions in WebVRExperienceHelper ([trevordev](https://github.com/trevordev))
+- (Viewer) XHR requests not use Tools.LoadFile and are disposed correctly - [#3671](https://github.com/BabylonJS/Babylon.js/issues/3671) ([RaananW](https://github.com/RaananW))
+- Added `Tools.WorkerPool` class for web worker management. ([bghgary](https://github.com/bghgary))
+- Support depth maps for multiple active cameras for post processes like depth of field ([trevordev](https://github.com/trevordev))
 
 
 ## Bug fixes
 ## Bug fixes
 
 
@@ -82,9 +86,11 @@
 - SPS internal temporary vector3 instead of Tmp.Vector3 to avoid possible concurrent uses ([jbousquie](https://github.com/jbousquie))
 - SPS internal temporary vector3 instead of Tmp.Vector3 to avoid possible concurrent uses ([jbousquie](https://github.com/jbousquie))
 - Fixed a bug when calling load on an empty assets manager - [#3739](https://github.com/BabylonJS/Babylon.js/issues/3739). ([RaananW](https://github.com/RaananW))
 - Fixed a bug when calling load on an empty assets manager - [#3739](https://github.com/BabylonJS/Babylon.js/issues/3739). ([RaananW](https://github.com/RaananW))
 - Enabling teleportation in the vr helper class caused a redundant post process to be added ([trevordev](https://github.com/trevordev))
 - Enabling teleportation in the vr helper class caused a redundant post process to be added ([trevordev](https://github.com/trevordev))
+- (Viewer) Fixed a bug where loading another mesh positioned it incorrectly ([RaananW](https://github.com/RaananW))
 
 
 ## Breaking changes
 ## Breaking changes
 
 
 - Removed the unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
 - Removed the unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
 - VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
 - VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
 - glTF 2.0 loader will now create a mesh for each primitive instead of merging the primitives together into one mesh. ([bghgary](https://github.com/bghgary)]
 - glTF 2.0 loader will now create a mesh for each primitive instead of merging the primitives together into one mesh. ([bghgary](https://github.com/bghgary)]
+- Engine's onCanvasPointerOutObservable will now return a PointerEvent instead of the Engine. ([trevordev](https://github.com/trevordev))

+ 19 - 19
gui/src/advancedDynamicTexture.ts

@@ -14,12 +14,12 @@ module BABYLON.GUI {
         private _preKeyboardObserver: Nullable<Observer<KeyboardInfoPre>>;
         private _preKeyboardObserver: Nullable<Observer<KeyboardInfoPre>>;
         private _pointerMoveObserver: Nullable<Observer<PointerInfoPre>>;
         private _pointerMoveObserver: Nullable<Observer<PointerInfoPre>>;
         private _pointerObserver: Nullable<Observer<PointerInfo>>;
         private _pointerObserver: Nullable<Observer<PointerInfo>>;
-        private _canvasPointerOutObserver: Nullable<Observer<Engine>>;
+        private _canvasPointerOutObserver: Nullable<Observer<PointerEvent>>;
         private _background: string;
         private _background: string;
         public _rootContainer = new Container("root");
         public _rootContainer = new Container("root");
         public _lastPickedControl: Control;
         public _lastPickedControl: Control;
-        public _lastControlOver: Nullable<Control>;
-        public _lastControlDown: Nullable<Control>;
+        public _lastControlOver: {[pointerId:number]:Control} = {};
+        public _lastControlDown: {[pointerId:number]:Control} = {};
         public _capturingControl: {[pointerId:number]:Control} = {};
         public _capturingControl: {[pointerId:number]:Control} = {};
         public _shouldBlockPointer: boolean;
         public _shouldBlockPointer: boolean;
         public _layerToDispose: Nullable<Layer>;
         public _layerToDispose: Nullable<Layer>;
@@ -393,11 +393,11 @@ module BABYLON.GUI {
             if (!this._rootContainer._processPicking(x, y, type, pointerId, buttonIndex)) {
             if (!this._rootContainer._processPicking(x, y, type, pointerId, buttonIndex)) {
 
 
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
-                    if (this._lastControlOver) {
-                        this._lastControlOver._onPointerOut(this._lastControlOver);
+                    if (this._lastControlOver[pointerId]) {
+                        this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
                     }
                     }
 
 
-                    this._lastControlOver = null;
+                    delete this._lastControlOver[pointerId];
                 }
                 }
             }
             }
 
 
@@ -461,17 +461,17 @@ module BABYLON.GUI {
                         this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, pointerId, pi.event.button);
                         this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, pointerId, pi.event.button);
                     }
                     }
                 } else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
                 } else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
-                    if (this._lastControlDown) {
-                        this._lastControlDown.forcePointerUp(pointerId);
+                    if (this._lastControlDown[pointerId]) {
+                        this._lastControlDown[pointerId].forcePointerUp(pointerId);
                     }
                     }
-                    this._lastControlDown = null;
+                    delete this._lastControlDown[pointerId];
 
 
                     this.focusedControl = null;
                     this.focusedControl = null;
                 } else if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
                 } else if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
-                    if (this._lastControlOver) {
-                        this._lastControlOver._onPointerOut(this._lastControlOver);
+                    if (this._lastControlOver[pointerId]) {
+                        this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
                     }
                     }
-                    this._lastControlOver = null;
+                    delete this._lastControlOver[pointerId];
                 }
                 }
             });
             });
 
 
@@ -505,16 +505,16 @@ module BABYLON.GUI {
         }
         }
 
 
         private _attachToOnPointerOut(scene: Scene): void {
         private _attachToOnPointerOut(scene: Scene): void {
-            this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(() => {
-                if (this._lastControlOver) {
-                    this._lastControlOver._onPointerOut(this._lastControlOver);
+            this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add((pointerEvent) => {
+                if (this._lastControlOver[pointerEvent.pointerId]) {
+                    this._lastControlOver[pointerEvent.pointerId]._onPointerOut(this._lastControlOver[pointerEvent.pointerId]);
                 }
                 }
-                this._lastControlOver = null;
+                delete this._lastControlOver[pointerEvent.pointerId];
 
 
-                if (this._lastControlDown) {
-                    this._lastControlDown.forcePointerUp();
+                if (this._lastControlDown[pointerEvent.pointerId]) {
+                    this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                 }
                 }
-                this._lastControlDown = null;
+                delete this._lastControlDown[pointerEvent.pointerId];
             });
             });
         }
         }
 
 

+ 6 - 6
gui/src/controls/control.ts

@@ -943,7 +943,7 @@ module BABYLON.GUI {
             if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
             if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                 this._onPointerMove(this, this._dummyVector2);
                 this._onPointerMove(this, this._dummyVector2);
 
 
-                var previousControlOver = this._host._lastControlOver;
+                var previousControlOver = this._host._lastControlOver[pointerId];
                 if (previousControlOver && previousControlOver !== this) {
                 if (previousControlOver && previousControlOver !== this) {
                     previousControlOver._onPointerOut(this);
                     previousControlOver._onPointerOut(this);
                 }
                 }
@@ -952,22 +952,22 @@ module BABYLON.GUI {
                     this._onPointerEnter(this);
                     this._onPointerEnter(this);
                 }
                 }
 
 
-                this._host._lastControlOver = this;
+                this._host._lastControlOver[pointerId] = this;
                 return true;
                 return true;
             }
             }
 
 
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
                 this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex);
                 this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex);
-                this._host._lastControlDown = this;
+                this._host._lastControlDown[pointerId] = this;
                 this._host._lastPickedControl = this;
                 this._host._lastPickedControl = this;
                 return true;
                 return true;
             }
             }
 
 
             if (type === BABYLON.PointerEventTypes.POINTERUP) {
             if (type === BABYLON.PointerEventTypes.POINTERUP) {
-                if (this._host._lastControlDown) {
-                    this._host._lastControlDown._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
+                if (this._host._lastControlDown[pointerId]) {
+                    this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
                 }
                 }
-                this._host._lastControlDown = null;
+                delete this._host._lastControlDown[pointerId];
                 return true;
                 return true;
             }
             }
 
 

+ 26 - 5
loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts

@@ -1,7 +1,7 @@
 /// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
 
 
 module BABYLON.GLTF2.Extensions {
 module BABYLON.GLTF2.Extensions {
-    // https://github.com/KhronosGroup/glTF/pull/874
+    // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
 
 
     const NAME = "KHR_draco_mesh_compression";
     const NAME = "KHR_draco_mesh_compression";
 
 
@@ -13,6 +13,25 @@ module BABYLON.GLTF2.Extensions {
     export class KHR_draco_mesh_compression extends GLTFLoaderExtension {
     export class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         public readonly name = NAME;
         public readonly name = NAME;
 
 
+        private _dracoCompression: Nullable<DracoCompression> = null;
+
+        constructor(loader: GLTFLoader) {
+            super(loader);
+
+            // Disable extension if decoder is not available.
+            if (!DracoCompression.DecoderUrl) {
+                this.enabled = false;
+            }
+        }
+
+        public dispose(): void {
+            if (this._dracoCompression) {
+                this._dracoCompression.dispose();
+            }
+
+            super.dispose();
+        }
+
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>> {
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>> {
             return this._loadExtensionAsync<IKHRDracoMeshCompression, VertexData>(context, primitive, (extensionContext, extension) => {
             return this._loadExtensionAsync<IKHRDracoMeshCompression, VertexData>(context, primitive, (extensionContext, extension) => {
                 if (primitive.mode != undefined) {
                 if (primitive.mode != undefined) {
@@ -54,7 +73,11 @@ module BABYLON.GLTF2.Extensions {
                 var bufferView = GLTFLoader._GetProperty(extensionContext, this._loader._gltf.bufferViews, extension.bufferView);
                 var bufferView = GLTFLoader._GetProperty(extensionContext, this._loader._gltf.bufferViews, extension.bufferView);
                 return this._loader._loadBufferViewAsync(`#/bufferViews/${bufferView._index}`, bufferView).then(data => {
                 return this._loader._loadBufferViewAsync(`#/bufferViews/${bufferView._index}`, bufferView).then(data => {
                     try {
                     try {
-                        return DracoCompression.Decode(data, attributes);
+                        if (!this._dracoCompression) {
+                            this._dracoCompression = new DracoCompression();
+                        }
+
+                        return this._dracoCompression.decodeMeshAsync(data, attributes);
                     }
                     }
                     catch (e) {
                     catch (e) {
                         throw new Error(`${context}: ${e.message}`);
                         throw new Error(`${context}: ${e.message}`);
@@ -64,7 +87,5 @@ module BABYLON.GLTF2.Extensions {
         }
         }
     }
     }
 
 
-    if (DracoCompression.IsSupported) {
-        GLTFLoader._Register(NAME, loader => new KHR_draco_mesh_compression(loader));
-    }
+    GLTFLoader._Register(NAME, loader => new KHR_draco_mesh_compression(loader));
 }
 }

+ 6 - 0
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -1568,7 +1568,13 @@ module BABYLON.GLTF2 {
             delete this._gltf;
             delete this._gltf;
             delete this._babylonScene;
             delete this._babylonScene;
             this._completePromises.length = 0;
             this._completePromises.length = 0;
+
+            for (const name in this._extensions) {
+                this._extensions[name].dispose();
+            }
+
             this._extensions = {};
             this._extensions = {};
+
             delete this._rootBabylonMesh;
             delete this._rootBabylonMesh;
             delete this._progressCallback;
             delete this._progressCallback;
 
 

+ 5 - 1
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -1,7 +1,7 @@
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 
 
 module BABYLON.GLTF2 {
 module BABYLON.GLTF2 {
-    export abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+    export abstract class GLTFLoaderExtension implements IGLTFLoaderExtension, IDisposable {
         public enabled = true;
         public enabled = true;
         public abstract readonly name: string;
         public abstract readonly name: string;
 
 
@@ -11,6 +11,10 @@ module BABYLON.GLTF2 {
             this._loader = loader;
             this._loader = loader;
         }
         }
 
 
+        public dispose(): void {
+            delete this._loader;
+        }
+
         // #region Overridable Methods
         // #region Overridable Methods
 
 
         /** Override this method to modify the default behavior for loading scenes. */
         /** Override this method to modify the default behavior for loading scenes. */

+ 3 - 3
localDev/index.html

@@ -5,10 +5,10 @@
     <title>Local Development</title>
     <title>Local Development</title>
 
 
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+    <script src="../dist/preview%20release/cannon.js"></script>
+    <script src="../dist/preview%20release/draco_decoder.js" type="text/x-draco-decoder"></script>
+    <script src="../dist/preview%20release/Oimo.js"></script>
     <script src="../Tools/DevLoader/BabylonLoader.js"></script>
     <script src="../Tools/DevLoader/BabylonLoader.js"></script>
     <script src="src/webgl-debug.js"></script>
     <script src="src/webgl-debug.js"></script>
 
 

+ 2 - 2
package.json

@@ -9,7 +9,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -41,4 +41,4 @@
     },
     },
     "readme": "Babylon.js is a 3D engine based on webgl and javascript",
     "readme": "Babylon.js is a 3D engine based on webgl and javascript",
     "readmeFilename": "README.md"
     "readmeFilename": "README.md"
-}
+}

+ 1 - 1
sandbox/index-local.html

@@ -4,7 +4,7 @@
     <title>BabylonJS - Sandbox</title>
     <title>BabylonJS - Sandbox</title>
     <link href="index.css" rel="stylesheet" />
     <link href="index.css" rel="stylesheet" />
     <script src="../dist/preview%20release/cannon.js"></script>
     <script src="../dist/preview%20release/cannon.js"></script>
-    <script src="../dist/preview%20release/draco_decoder.js"></script>
+    <script src="../dist/preview%20release/draco_decoder.js" type="text/x-draco-decoder"></script>
     <script src="../dist/preview%20release/Oimo.js"></script>
     <script src="../dist/preview%20release/Oimo.js"></script>
     <script src="../Tools/DevLoader/BabylonLoader.js"></script>
     <script src="../Tools/DevLoader/BabylonLoader.js"></script>
 </head>
 </head>

+ 3 - 4
sandbox/index.html

@@ -27,14 +27,13 @@
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
 
 
     <script src="https://preview.babylonjs.com/cannon.js"></script>
     <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+    <script src="https://preview.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
     <script src="https://preview.babylonjs.com/babylon.js"></script>
     <script src="https://preview.babylonjs.com/babylon.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
 
 
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
+    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
 </head>
 </head>
 
 
 <body>
 <body>

File diff suppressed because it is too large
+ 353 - 412
serializers/src/glTF/2.0/babylon.glTFExporter.ts


File diff suppressed because it is too large
+ 383 - 297
src/Cameras/VR/babylon.vrExperienceHelper.ts


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

@@ -613,7 +613,7 @@
         /**
         /**
          * Observable event triggered each time the canvas receives pointerout event
          * Observable event triggered each time the canvas receives pointerout event
          */
          */
-        public onCanvasPointerOutObservable = new Observable<Engine>();
+        public onCanvasPointerOutObservable = new Observable<PointerEvent>();
 
 
         /**
         /**
          * Observable event triggered before each texture is initialized
          * Observable event triggered before each texture is initialized
@@ -694,7 +694,7 @@
         // Focus
         // Focus
         private _onFocus: () => void;
         private _onFocus: () => void;
         private _onBlur: () => void;
         private _onBlur: () => void;
-        private _onCanvasPointerOut: () => void;
+        private _onCanvasPointerOut: (event: PointerEvent) => void;
         private _onCanvasBlur: () => void;
         private _onCanvasBlur: () => void;
         private _onCanvasFocus: () => void;
         private _onCanvasFocus: () => void;
 
 
@@ -996,8 +996,8 @@
                     this._windowIsBackground = false;
                     this._windowIsBackground = false;
                 };
                 };
 
 
-                this._onCanvasPointerOut = () => {
-                    this.onCanvasPointerOutObservable.notifyObservers(this);
+                this._onCanvasPointerOut = (ev) => {
+                    this.onCanvasPointerOutObservable.notifyObservers(ev);
                 };
                 };
 
 
                 window.addEventListener("blur", this._onBlur);
                 window.addEventListener("blur", this._onBlur);
@@ -4268,7 +4268,7 @@
                 }, undefined, undefined, true, onerror);
                 }, undefined, undefined, true, onerror);
             } else if (isDDS) {
             } else if (isDDS) {
                 if (files && files.length === 6) {
                 if (files && files.length === 6) {
-                    this._cascadeLoadFiles(rootUrl,
+                    this._cascadeLoadFiles(
                         scene,
                         scene,
                         imgs => {
                         imgs => {
                             var info: DDSInfo | undefined;
                             var info: DDSInfo | undefined;
@@ -5883,7 +5883,7 @@
             this._loadFile(url, onload, undefined, undefined, true, onerror);
             this._loadFile(url, onload, undefined, undefined, true, onerror);
         }
         }
 
 
-        private _cascadeLoadFiles(rootUrl: string, scene: Nullable<Scene>, onfinish: (images: (string | ArrayBuffer)[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null): void {
+        private _cascadeLoadFiles(scene: Nullable<Scene>, onfinish: (images: (string | ArrayBuffer)[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null): void {
             var loadedFiles: (string | ArrayBuffer)[] = [];
             var loadedFiles: (string | ArrayBuffer)[] = [];
             (<any>loadedFiles)._internalCount = 0;
             (<any>loadedFiles)._internalCount = 0;
 
 

+ 4 - 0
src/Engine/babylon.nullEngine.ts

@@ -25,6 +25,10 @@
             return this._options.lockstepMaxSteps;
             return this._options.lockstepMaxSteps;
         }
         }
 
 
+        public getHardwareScalingLevel(): number {
+            return 1.0;
+        }
+
         public constructor(options: NullEngineOptions = new NullEngineOptions()) {
         public constructor(options: NullEngineOptions = new NullEngineOptions()) {
             super(null);
             super(null);
 
 

+ 3 - 1
src/Helpers/babylon.environmentHelper.ts

@@ -476,7 +476,9 @@ module BABYLON {
                 return { groundSize, skyboxSize, rootPosition };
                 return { groundSize, skyboxSize, rootPosition };
             }
             }
 
 
-            const sceneExtends = this._scene.getWorldExtends();
+            const sceneExtends = this._scene.getWorldExtends((mesh) => {
+                return (mesh !== this._ground && mesh !== this._rootMesh && mesh !== this._skybox);
+            });
             const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
             const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
 
 
             if (this._options.sizeAuto) {
             if (this._options.sizeAuto) {

+ 5 - 1
src/Materials/Textures/babylon.cubeTexture.ts

@@ -39,7 +39,11 @@
         private _prefiltered: boolean;
         private _prefiltered: boolean;
 
 
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
-            return new CubeTexture("", scene, null, noMipmap, files);
+            let rootUrlKey = "";
+            
+            files.forEach(url => rootUrlKey += url);
+
+            return new CubeTexture(rootUrlKey, scene, null, noMipmap, files);
         }
         }
 
 
         public static CreateFromPrefilteredData(url: string, scene: Scene, forcedExtension: any = null) {
         public static CreateFromPrefilteredData(url: string, scene: Scene, forcedExtension: any = null) {

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

@@ -334,7 +334,6 @@
          */
          */
         public static FromHexString(hex: string): Color3 {
         public static FromHexString(hex: string): Color3 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 7) {
             if (hex.substring(0, 1) !== "#" || hex.length !== 7) {
-                //Tools.Warn("Color3.FromHexString must be called with a string like #FFFFFF");
                 return new Color3(0, 0, 0);
                 return new Color3(0, 0, 0);
             }
             }
 
 
@@ -746,7 +745,6 @@
          */
          */
         public static FromHexString(hex: string): Color4 {
         public static FromHexString(hex: string): Color4 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 9) {
             if (hex.substring(0, 1) !== "#" || hex.length !== 9) {
-                //Tools.Warn("Color4.FromHexString must be called with a string like #FFFFFFFF");
                 return new Color4(0.0, 0.0, 0.0, 0.0);
                 return new Color4(0.0, 0.0, 0.0, 0.0);
             }
             }
 
 
@@ -5290,7 +5288,6 @@
          */
          */
         public addLineTo(x: number, y: number): Path2 {
         public addLineTo(x: number, y: number): Path2 {
             if (this.closed) {
             if (this.closed) {
-                //Tools.Error("cannot add lines to closed paths");
                 return this;
                 return this;
             }
             }
             var newPoint = new Vector2(x, y);
             var newPoint = new Vector2(x, y);
@@ -5306,7 +5303,6 @@
          */
          */
         public addArcTo(midX: number, midY: number, endX: number, endY: number, numberOfSegments = 36): Path2 {
         public addArcTo(midX: number, midY: number, endX: number, endY: number, numberOfSegments = 36): Path2 {
             if (this.closed) {
             if (this.closed) {
-                //Tools.Error("cannot add arcs to closed paths");
                 return this;
                 return this;
             }
             }
             var startPoint = this._points[this._points.length - 1];
             var startPoint = this._points[this._points.length - 1];
@@ -5361,7 +5357,6 @@
          */
          */
         public getPointAtLengthPosition(normalizedLengthPosition: number): Vector2 {
         public getPointAtLengthPosition(normalizedLengthPosition: number): Vector2 {
             if (normalizedLengthPosition < 0 || normalizedLengthPosition > 1) {
             if (normalizedLengthPosition < 0 || normalizedLengthPosition > 1) {
-                //Tools.Error("normalized length position should be between 0 and 1.");
                 return Vector2.Zero();
                 return Vector2.Zero();
             }
             }
 
 
@@ -5388,7 +5383,6 @@
                 previousOffset = nextOffset;
                 previousOffset = nextOffset;
             }
             }
 
 
-            //Tools.Error("internal error");
             return Vector2.Zero();
             return Vector2.Zero();
         }
         }
 
 

+ 163 - 70
src/Mesh/Compression/babylon.dracoCompression.ts

@@ -6,101 +6,194 @@ module BABYLON {
     /**
     /**
      * Draco compression (https://google.github.io/draco/)
      * Draco compression (https://google.github.io/draco/)
      */
      */
-    export class DracoCompression {
+    export class DracoCompression implements IDisposable {
+        private _workerPool: WorkerPool;
+
+        /**
+         * Gets the url to the draco decoder if available.
+         */
+        public static DecoderUrl: Nullable<string> = DracoCompression._GetDefaultDecoderUrl();
+
         /**
         /**
-         * Returns whether Draco compression is supported.
+         * Constructor
+         * @param numWorkers The number of workers for async operations
          */
          */
-        public static get IsSupported(): boolean {
-            return !!window.DracoDecoderModule;
+        constructor(numWorkers = (navigator.hardwareConcurrency || 4)) {
+            const workers = new Array<Worker>(numWorkers);
+            for (let i = 0; i < workers.length; i++) {
+                const worker = new Worker(DracoCompression._WorkerBlobUrl);
+                worker.postMessage({ id: "initDecoder", url: DracoCompression.DecoderUrl });
+                workers[i] = worker;
+            }
+
+            this._workerPool = new WorkerPool(workers);
         }
         }
 
 
         /**
         /**
-         * Decodes Draco compressed data to vertex data.
+         * Stop all async operations and release resources.
+         */
+        public dispose(): void {
+            this._workerPool.dispose();
+            delete this._workerPool;
+        }
+
+        /**
+         * Decode Draco compressed mesh data to vertex data.
          * @param data The array buffer view for the Draco compression data
          * @param data The array buffer view for the Draco compression data
          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns The decoded vertex data
+         * @returns A promise that resolves with the decoded vertex data
          */
          */
-        public static Decode(data: ArrayBufferView, attributes: { [kind: string]: number }): VertexData {
-            const dracoModule = new DracoDecoderModule();
-            const buffer = new dracoModule.DecoderBuffer();
-            buffer.Init(data, data.byteLength);
-
-            const decoder = new dracoModule.Decoder();
-            let geometry: any;
-            let status: any;
-
-            const vertexData = new VertexData();
-
-            try {
-                const type = decoder.GetEncodedGeometryType(buffer);
-                switch (type) {
-                    case dracoModule.TRIANGULAR_MESH:
-                        geometry = new dracoModule.Mesh();
-                        status = decoder.DecodeBufferToMesh(buffer, geometry);
-                        break;
-                    case dracoModule.POINT_CLOUD:
-                        geometry = new dracoModule.PointCloud();
-                        status = decoder.DecodeBufferToPointCloud(buffer, geometry);
-                        break;
-                    default:
-                        throw new Error(`Invalid geometry type ${type}`);
-                }
+        public decodeMeshAsync(data: ArrayBufferView, attributes: { [kind: string]: number }): Promise<VertexData> {
+            return new Promise((resolve, reject) => {
+                this._workerPool.push((worker, onComplete) => {
+                    const vertexData = new VertexData();
 
 
-                if (!status.ok() || !geometry.ptr) {
-                    throw new Error(status.error_msg());
-                }
+                    const onError = (error: ErrorEvent) => {
+                        worker.removeEventListener("error", onError);
+                        worker.removeEventListener("message", onMessage);
+                        reject(error);
+                        onComplete();
+                    };
 
 
-                const numPoints = geometry.num_points();
-
-                if (type === dracoModule.TRIANGULAR_MESH) {
-                    const numFaces = geometry.num_faces();
-                    const faceIndices = new dracoModule.DracoInt32Array();
-                    try {
-                        vertexData.indices = new Uint32Array(numFaces * 3);
-                        for (let i = 0; i < numFaces; i++) {
-                            decoder.GetFaceFromMesh(geometry, i, faceIndices);
-                            const offset = i * 3;
-                            vertexData.indices[offset + 0] = faceIndices.GetValue(0);
-                            vertexData.indices[offset + 1] = faceIndices.GetValue(1);
-                            vertexData.indices[offset + 2] = faceIndices.GetValue(2);
+                    const onMessage = (message: MessageEvent) => {
+                        if (message.data === "done") {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            resolve(vertexData);
+                            onComplete();
                         }
                         }
+                        else if (message.data.id === "indices") {
+                            vertexData.indices = message.data.value;
+                        }
+                        else {
+                            vertexData.set(message.data.value, message.data.id);
+                        }
+                    };
+
+                    worker.addEventListener("error", onError);
+                    worker.addEventListener("message", onMessage);
+
+                    const dataCopy = new Uint8Array(data.byteLength);
+                    dataCopy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
+
+                    worker.postMessage({ id: "decodeMesh", data: dataCopy, attributes: attributes }, [dataCopy.buffer]);
+                });
+            });
+        }
+
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker(): void {
+            // self is actually a DedicatedWorkerGlobalScope
+            const _self = self as any as {
+                onmessage: (event: MessageEvent) => void;
+                postMessage: (message: any, transfer?: any[]) => void;
+                close: () => void;
+            };
+
+            const decodeMesh = (data: ArrayBufferView, attributes: { [kind: string]: number }): void => {
+                const dracoModule = new DracoDecoderModule();
+                const buffer = new dracoModule.DecoderBuffer();
+                buffer.Init(data, data.byteLength);
+
+                const decoder = new dracoModule.Decoder();
+                let geometry: any;
+                let status: any;
+
+                try {
+                    const type = decoder.GetEncodedGeometryType(buffer);
+                    switch (type) {
+                        case dracoModule.TRIANGULAR_MESH:
+                            geometry = new dracoModule.Mesh();
+                            status = decoder.DecodeBufferToMesh(buffer, geometry);
+                            break;
+                        case dracoModule.POINT_CLOUD:
+                            geometry = new dracoModule.PointCloud();
+                            status = decoder.DecodeBufferToPointCloud(buffer, geometry);
+                            break;
+                        default:
+                            throw new Error(`Invalid geometry type ${type}`);
                     }
                     }
-                    finally {
-                        dracoModule.destroy(faceIndices);
+
+                    if (!status.ok() || !geometry.ptr) {
+                        throw new Error(status.error_msg());
                     }
                     }
-                }
 
 
-                for (const kind in attributes) {
-                    const uniqueId = attributes[kind];
-                    const attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
-                    const dracoData = new dracoModule.DracoFloat32Array();
-                    try {
-                        if (attribute.num_components() !== VertexBuffer.DeduceStride(kind)) {
-                            throw new Error(`Unsupported number of components for ${kind}`);
+                    const numPoints = geometry.num_points();
+
+                    if (type === dracoModule.TRIANGULAR_MESH) {
+                        const numFaces = geometry.num_faces();
+                        const faceIndices = new dracoModule.DracoInt32Array();
+                        try {
+                            const indices = new Uint32Array(numFaces * 3);
+                            for (let i = 0; i < numFaces; i++) {
+                                decoder.GetFaceFromMesh(geometry, i, faceIndices);
+                                const offset = i * 3;
+                                indices[offset + 0] = faceIndices.GetValue(0);
+                                indices[offset + 1] = faceIndices.GetValue(1);
+                                indices[offset + 2] = faceIndices.GetValue(2);
+                            }
+                            _self.postMessage({ id: "indices", value: indices }, [indices.buffer]);
+                        }
+                        finally {
+                            dracoModule.destroy(faceIndices);
                         }
                         }
+                    }
 
 
-                        decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
-                        const babylonData = new Float32Array(numPoints * attribute.num_components());
-                        for (let i = 0; i < babylonData.length; i++) {
-                            babylonData[i] = dracoData.GetValue(i);
+                    for (const kind in attributes) {
+                        const uniqueId = attributes[kind];
+                        const attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
+                        const dracoData = new dracoModule.DracoFloat32Array();
+                        try {
+                            decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
+                            const babylonData = new Float32Array(numPoints * attribute.num_components());
+                            for (let i = 0; i < babylonData.length; i++) {
+                                babylonData[i] = dracoData.GetValue(i);
+                            }
+                            _self.postMessage({ id: kind, value: babylonData }, [babylonData.buffer]);
+                        }
+                        finally {
+                            dracoModule.destroy(dracoData);
                         }
                         }
-                        vertexData.set(babylonData, kind);
                     }
                     }
-                    finally {
-                        dracoModule.destroy(dracoData);
+                }
+                finally {
+                    if (geometry) {
+                        dracoModule.destroy(geometry);
                     }
                     }
+
+                    dracoModule.destroy(decoder);
+                    dracoModule.destroy(buffer);
                 }
                 }
+
+                _self.postMessage("done");
             }
             }
-            finally {
-                if (geometry) {
-                    dracoModule.destroy(geometry);
+
+            _self.onmessage = event => {
+                switch (event.data.id) {
+                    case "initDecoder": {
+                        importScripts(event.data.url);
+                        break;
+                    }
+                    case "decodeMesh": {
+                        decodeMesh(event.data.data, event.data.attributes);
+                        break;
+                    }
                 }
                 }
+            };
+        }
 
 
-                dracoModule.destroy(decoder);
-                dracoModule.destroy(buffer);
+        private static _WorkerBlobUrl = URL.createObjectURL(new Blob([`(${DracoCompression._Worker.toString()})()`], { type: "application/javascript" }));
+
+        private static _GetDefaultDecoderUrl(): Nullable<string> {
+            for (let i = 0; i < document.scripts.length; i++) {
+                if (document.scripts[i].type === "text/x-draco-decoder") {
+                    return document.scripts[i].src;
+                }
             }
             }
 
 
-            return vertexData;
+            return null;
         }
         }
     }
     }
 }
 }

+ 168 - 0
src/Particles/babylon.IParticleSystem.ts

@@ -0,0 +1,168 @@
+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;
+
+         /**
+         * The overall motion speed (0.01 is default update speed, faster updates = faster animation)
+         */
+        updateSpeed: number;        
+
+        /**
+         * The amount of time the particle system is running (depends of the overall update speed).
+         */
+        targetStopDuration: number;        
+
+        /**
+         * The texture used to render each particle. (this can be a spritesheet)
+         */
+        particleTexture: Nullable<Texture>;   
+        
+        /**
+         * Blend mode use to render the particle, it can be either ParticleSystem.BLENDMODE_ONEONE or ParticleSystem.BLENDMODE_STANDARD.
+         */
+        blendMode: number;   
+        
+        /**
+         * Minimum life time of emitting particles.
+         */
+        minLifeTime: number;
+        /**
+         * Maximum life time of emitting particles.
+         */
+        maxLifeTime: number;    
+
+        /**
+         * Minimum Size of emitting particles.
+         */
+        minSize: number;
+        /**
+         * Maximum Size of emitting particles.
+         */
+        maxSize: number;        
+        
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
+        color1: Color4;
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
+        color2: Color4;  
+        
+        /**
+         * Color the particle will have at the end of its lifetime.
+         */
+        colorDead: Color4;
+        
+        /**
+         * The maximum number of particles to emit per frame until we reach the activeParticleCount value
+         */
+        emitRate: number; 
+        
+        /**
+         * You can use gravity if you want to give an orientation to your particles.
+         */
+        gravity: Vector3;    
+
+        /**
+         * Minimum power of emitting particles.
+         */
+        minEmitPower: number;
+        /**
+         * Maximum power of emitting particles.
+         */
+        maxEmitPower: number;        
+
+        /**
+         * The particle emitter type defines the emitter used by the particle system.
+         * It can be for example box, sphere, or cone...
+         */
+        particleEmitterType: Nullable<IParticleEmitterType>;        
+
+        /**
+         * Gets the maximum number of particles active at the same time.
+         * @returns The max number of active particles.
+         */
+        getCapacity(): number;
+
+        /**
+         * Gets Wether the system has been started.
+         * @returns True if it has been started, otherwise false.
+         */
+        isStarted(): boolean;
+
+        /**
+         * 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;
+
+        /**
+         * Starts the particle system and begins to emit.
+         */
+        start(): void;
+
+        /**
+         * Stops the particle system.
+         */
+        stop(): void;
+
+        /**
+         * Remove all active particles
+         */
+        reset(): void;
+    }
+}

+ 113 - 15
src/Particles/babylon.gpuParticleSystem.ts

@@ -2,7 +2,7 @@
     /**
     /**
      * This represents a GPU particle system in Babylon
      * This represents a GPU particle system in Babylon
      * This is the fastest particle system in Babylon as it uses the GPU to update the individual particle data
      * This is the fastest particle system in Babylon as it uses the GPU to update the individual particle data
-     * @see https://www.babylonjs-playground.com/#PU4WYI
+     * @see https://www.babylonjs-playground.com/#PU4WYI#4
      */
      */
     export class GPUParticleSystem implements IDisposable, IParticleSystem, IAnimatable {
     export class GPUParticleSystem implements IDisposable, IParticleSystem, IAnimatable {
         /**
         /**
@@ -39,8 +39,8 @@
         private _buffer0: Buffer;
         private _buffer0: Buffer;
         private _buffer1: Buffer;
         private _buffer1: Buffer;
         private _spriteBuffer: Buffer;
         private _spriteBuffer: Buffer;
-        private _updateVAO = new Array<WebGLVertexArrayObject>();
-        private _renderVAO = new Array<WebGLVertexArrayObject>()
+        private _updateVAO: Array<WebGLVertexArrayObject>;
+        private _renderVAO: Array<WebGLVertexArrayObject>;
 
 
         private _targetIndex = 0;
         private _targetIndex = 0;
         private _sourceBuffer: Buffer;
         private _sourceBuffer: Buffer;
@@ -158,7 +158,79 @@
          * The particle emitter type defines the emitter used by the particle system.
          * The particle emitter type defines the emitter used by the particle system.
          * It can be for example box, sphere, or cone...
          * It can be for example box, sphere, or cone...
          */
          */
-        public particleEmitterType: Nullable<IParticleEmitterType>;        
+        public particleEmitterType: Nullable<IParticleEmitterType>;    
+
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get direction1(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction1) {
+                return (<BoxParticleEmitter>this.particleEmitterType).direction1;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set direction1(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction1) {
+                (<BoxParticleEmitter>this.particleEmitterType).direction1 = value;
+            }
+        }        
+        
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get direction2(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction2) {
+                return (<BoxParticleEmitter>this.particleEmitterType).direction2;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set direction2(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction2) {
+                (<BoxParticleEmitter>this.particleEmitterType).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.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get minEmitBox(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).minEmitBox) {
+                return (<BoxParticleEmitter>this.particleEmitterType).minEmitBox;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set minEmitBox(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).minEmitBox) {
+                (<BoxParticleEmitter>this.particleEmitterType).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.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get maxEmitBox(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).maxEmitBox) {
+                return (<BoxParticleEmitter>this.particleEmitterType).maxEmitBox;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set maxEmitBox(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).maxEmitBox) {
+                (<BoxParticleEmitter>this.particleEmitterType).maxEmitBox = value;
+            }
+        }        
 
 
         /**
         /**
          * Gets the maximum number of particles active at the same time.
          * Gets the maximum number of particles active at the same time.
@@ -263,10 +335,6 @@
                 transformFeedbackVaryings: ["outPosition", "outAge", "outLife", "outSeed", "outSize", "outColor", "outDirection"]
                 transformFeedbackVaryings: ["outPosition", "outAge", "outLife", "outSeed", "outSize", "outColor", "outDirection"]
             };
             };
 
 
-            this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._scene.getEngine());   
-
-            this._renderEffect = new Effect("gpuRenderParticles", ["position", "age", "life", "size", "color", "offset", "uv"], ["view", "projection", "colorDead"], ["textureSampler"], this._scene.getEngine());
-
             // Random data
             // Random data
             var maxTextureSize = Math.min(this._engine.getCaps().maxTextureSize, fullOptions.randomTextureSize);
             var maxTextureSize = Math.min(this._engine.getCaps().maxTextureSize, fullOptions.randomTextureSize);
             var d = [];
             var d = [];
@@ -281,6 +349,7 @@
             this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
             this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
 
 
             this._randomTextureSize = maxTextureSize;
             this._randomTextureSize = maxTextureSize;
+            this.particleEmitterType = new BoxParticleEmitter();
         }
         }
 
 
         private _createUpdateVAO(source: Buffer): WebGLVertexArrayObject {            
         private _createUpdateVAO(source: Buffer): WebGLVertexArrayObject {            
@@ -363,10 +432,12 @@
             this._spriteBuffer = new Buffer(engine, spriteData, false, 4);                                      
             this._spriteBuffer = new Buffer(engine, spriteData, false, 4);                                      
 
 
             // Update VAO
             // Update VAO
+            this._updateVAO = [];
             this._updateVAO.push(this._createUpdateVAO(this._buffer0));
             this._updateVAO.push(this._createUpdateVAO(this._buffer0));
             this._updateVAO.push(this._createUpdateVAO(this._buffer1));
             this._updateVAO.push(this._createUpdateVAO(this._buffer1));
 
 
             // Render VAO
             // Render VAO
+            this._renderVAO = [];
             this._renderVAO.push(this._createRenderVAO(this._buffer1, this._spriteBuffer));
             this._renderVAO.push(this._createRenderVAO(this._buffer1, this._spriteBuffer));
             this._renderVAO.push(this._createRenderVAO(this._buffer0, this._spriteBuffer));
             this._renderVAO.push(this._createRenderVAO(this._buffer0, this._spriteBuffer));
 
 
@@ -377,14 +448,32 @@
         }
         }
 
 
         /** @ignore */
         /** @ignore */
-        public _recreateUpdateEffect(defines: string) {
-            if (this._updateEffectOptions.defines === defines) {
+        public _recreateUpdateEffect() {
+            let defines = this.particleEmitterType ? this.particleEmitterType.getEffectDefines() : "";
+            if (this._updateEffect && this._updateEffectOptions.defines === defines) {
                 return;
                 return;
             }
             }
             this._updateEffectOptions.defines = defines;
             this._updateEffectOptions.defines = defines;
             this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._scene.getEngine());   
             this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._scene.getEngine());   
         }
         }
 
 
+        /** @ignore */
+        public _recreateRenderEffect() {
+            let defines = "";
+            if (this._scene.clipPlane) {
+                defines = "\n#define CLIPPLANE";
+            }
+
+            if (this._renderEffect && this._renderEffect.defines === defines) {
+                return;
+            }
+
+            this._renderEffect = new Effect("gpuRenderParticles", 
+                                            ["position", "age", "life", "size", "color", "offset", "uv"], 
+                                            ["view", "projection", "colorDead", "invView", "vClipPlane"], 
+                                            ["textureSampler"], this._scene.getEngine(), defines);
+        }        
+
         /**
         /**
          * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
          * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
          */
          */
@@ -409,9 +498,8 @@
                 return 0;
                 return 0;
             }
             }
 
 
-            if (this.particleEmitterType) {
-                this._recreateUpdateEffect(this.particleEmitterType.getEffectDefines());
-            }
+            this._recreateUpdateEffect();
+            this._recreateRenderEffect();
 
 
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
                 return 0;
                 return 0;
@@ -426,7 +514,7 @@
             // Get everything ready to render
             // Get everything ready to render
             this. _initialize();
             this. _initialize();
 
 
-            this._currentActiveCount = Math.min(this._activeCount, this._currentActiveCount + this.emitRate);
+            this._currentActiveCount = Math.min(this._activeCount, this._currentActiveCount + (this.emitRate * this._timeDelta) | 0);
             
             
             // Enable update effect
             // Enable update effect
 
 
@@ -472,11 +560,21 @@
 
 
             // Enable render effect
             // Enable render effect
             this._engine.enableEffect(this._renderEffect);
             this._engine.enableEffect(this._renderEffect);
-            this._renderEffect.setMatrix("view", this._scene.getViewMatrix());
+            let viewMatrix = this._scene.getViewMatrix();
+            this._renderEffect.setMatrix("view", viewMatrix);
             this._renderEffect.setMatrix("projection", this._scene.getProjectionMatrix());
             this._renderEffect.setMatrix("projection", this._scene.getProjectionMatrix());
             this._renderEffect.setTexture("textureSampler", this.particleTexture);
             this._renderEffect.setTexture("textureSampler", this.particleTexture);
             this._renderEffect.setDirectColor4("colorDead", this.colorDead);
             this._renderEffect.setDirectColor4("colorDead", this.colorDead);
 
 
+
+            if (this._scene.clipPlane) {
+                var clipPlane = this._scene.clipPlane;
+                var invView = viewMatrix.clone();
+                invView.invert();
+                this._renderEffect.setMatrix("invView", invView);
+                this._renderEffect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+            }            
+
             // Draw order
             // Draw order
             if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
             if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
                 this._engine.setAlphaMode(Engine.ALPHA_ONEONE);
                 this._engine.setAlphaMode(Engine.ALPHA_ONEONE);

+ 7 - 62
src/Particles/babylon.particleSystem.ts

@@ -1,67 +1,5 @@
 module BABYLON {
 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.
      * 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 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.
      * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function.
@@ -395,6 +333,13 @@
         private _isAnimationSheetEnabled: boolean;
         private _isAnimationSheetEnabled: boolean;
 
 
         /**
         /**
+         * Gets the current list of active particles
+         */
+        public get particles(): Particle[] {
+            return this._particles;
+        }
+
+        /**
          * Returns the string "ParticleSystem"
          * Returns the string "ParticleSystem"
          * @returns a string containing the class name
          * @returns a string containing the class name
          */
          */

+ 4 - 1
src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts

@@ -286,7 +286,10 @@
             this._reset();
             this._reset();
 
 
             if(this.depthOfFieldEnabled){
             if(this.depthOfFieldEnabled){
-                this.depthOfField = new DepthOfFieldEffect(this._scene, this._depthOfFieldBlurLevel, this._defaultPipelineTextureType);
+                // Enable and get current depth map
+                var depthTexture = this._scene.enableDepthRenderer(this._cameras[0]).getDepthMap();
+
+                this.depthOfField = new DepthOfFieldEffect(this._scene, depthTexture, this._depthOfFieldBlurLevel, this._defaultPipelineTextureType);
                 this.addEffect(this.depthOfField);
                 this.addEffect(this.depthOfField);
             }
             }
 
 

+ 2 - 6
src/PostProcess/babylon.circleOfConfusionPostProcess.ts

@@ -23,7 +23,6 @@ module BABYLON {
         /**
         /**
          * Creates a new instance of @see CircleOfConfusionPostProcess
          * Creates a new instance of @see CircleOfConfusionPostProcess
          * @param name The name of the effect.
          * @param name The name of the effect.
-         * @param scene The scene the effect belongs to.
          * @param depthTexture The depth texture of the scene to compute the circle of confusion.
          * @param depthTexture The depth texture of the scene to compute the circle of confusion.
          * @param options The required width/height ratio to downsize to before computing the render pass.
          * @param options The required width/height ratio to downsize to before computing the render pass.
          * @param camera The camera to apply the render pass to.
          * @param camera The camera to apply the render pass to.
@@ -32,7 +31,7 @@ module BABYLON {
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
          * @param textureType Type of textures used when performing the post process. (default: 0)
          */
          */
-        constructor(name: string, scene: Scene, depthTexture: RenderTargetTexture, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+        constructor(name: string, depthTexture: RenderTargetTexture, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
             super(name, "circleOfConfusion", ["cameraMinMaxZ", "focusDistance", "cocPrecalculation"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType);
             super(name, "circleOfConfusion", ["cameraMinMaxZ", "focusDistance", "cocPrecalculation"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType);
             this.onApplyObservable.add((effect: Effect) => {
             this.onApplyObservable.add((effect: Effect) => {
                 effect.setTexture("depthSampler", depthTexture);
                 effect.setTexture("depthSampler", depthTexture);
@@ -43,10 +42,7 @@ module BABYLON {
                 
                 
                 effect.setFloat('focusDistance', this.focusDistance);
                 effect.setFloat('focusDistance', this.focusDistance);
                 effect.setFloat('cocPrecalculation', cocPrecalculation);
                 effect.setFloat('cocPrecalculation', cocPrecalculation);
-                
-                if(scene.activeCamera){
-                    effect.setFloat2('cameraMinMaxZ', scene.activeCamera.minZ, scene.activeCamera.maxZ);
-                }
+                effect.setFloat2('cameraMinMaxZ', depthTexture.activeCamera!.minZ, depthTexture.activeCamera!.maxZ);
             })
             })
         }
         }
     }
     }

+ 3 - 4
src/PostProcess/babylon.depthOfFieldEffect.ts

@@ -66,14 +66,13 @@ module BABYLON {
         /**
         /**
          * Creates a new instance of @see DepthOfFieldEffect
          * Creates a new instance of @see DepthOfFieldEffect
          * @param scene The scene the effect belongs to.
          * @param scene The scene the effect belongs to.
+         * @param depthTexture The depth texture of the scene to compute the circle of confusion.
          * @param pipelineTextureType The type of texture to be used when performing the post processing.
          * @param pipelineTextureType The type of texture to be used when performing the post processing.
          */
          */
-        constructor(scene: Scene, blurLevel: DepthOfFieldEffectBlurLevel = DepthOfFieldEffectBlurLevel.Low, pipelineTextureType = 0) {
+        constructor(scene: Scene, depthTexture: RenderTargetTexture, blurLevel: DepthOfFieldEffectBlurLevel = DepthOfFieldEffectBlurLevel.Low, pipelineTextureType = 0) {
             super(scene.getEngine(), "depth of field", ()=>{
             super(scene.getEngine(), "depth of field", ()=>{
-                // Enable and get current depth map
-                var depthMap = scene.enableDepthRenderer().getDepthMap();
                 // Circle of confusion value for each pixel is used to determine how much to blur that pixel
                 // Circle of confusion value for each pixel is used to determine how much to blur that pixel
-                this._circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", scene, depthMap, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+                this._circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", depthTexture, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
                 // Capture circle of confusion texture
                 // Capture circle of confusion texture
                 this._depthOfFieldPass = new PassPostProcess("depthOfFieldPass", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
                 this._depthOfFieldPass = new PassPostProcess("depthOfFieldPass", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
                 this._depthOfFieldPass.autoClear = false;
                 this._depthOfFieldPass.autoClear = false;

+ 36 - 6
src/Rendering/babylon.depthRenderer.ts

@@ -1,13 +1,25 @@
 module BABYLON {
 module BABYLON {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
     export class DepthRenderer {
     export class DepthRenderer {
         private _scene: Scene;
         private _scene: Scene;
         private _depthMap: RenderTargetTexture;
         private _depthMap: RenderTargetTexture;
         private _effect: Effect;
         private _effect: Effect;
 
 
         private _cachedDefines: string;
         private _cachedDefines: string;
-
-        constructor(scene: Scene, type: number = Engine.TEXTURETYPE_FLOAT) {
+        private _camera:Nullable<Camera>;
+
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         */
+        constructor(scene: Scene, type: number = Engine.TEXTURETYPE_FLOAT, camera:Nullable<Camera> = null) {
             this._scene = scene;
             this._scene = scene;
+            this._camera = camera;
             var engine = scene.getEngine();
             var engine = scene.getEngine();
 
 
             // Render target
             // Render target
@@ -17,6 +29,11 @@
             this._depthMap.refreshRate = 1;
             this._depthMap.refreshRate = 1;
             this._depthMap.renderParticles = false;
             this._depthMap.renderParticles = false;
             this._depthMap.renderList = null;
             this._depthMap.renderList = null;
+
+            // Camera to get depth map from to support multiple concurrent cameras
+            this._depthMap.activeCamera = this._camera;
+            this._depthMap.ignoreCameraViewport = true;
+            this._depthMap.useCameraPostProcesses = false;
             
             
             // set default depth value to 1.0 (far away)
             // set default depth value to 1.0 (far away)
             this._depthMap.onClearObservable.add((engine: Engine) => {
             this._depthMap.onClearObservable.add((engine: Engine) => {
@@ -45,14 +62,15 @@
                 }
                 }
 
 
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
-
-                if (this.isReady(subMesh, hardwareInstancedRendering) && scene.activeCamera) {
+                
+                var camera = this._camera || scene.activeCamera;
+                if (this.isReady(subMesh, hardwareInstancedRendering) && camera) {
                     engine.enableEffect(this._effect);
                     engine.enableEffect(this._effect);
                     mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
                     mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
 
 
                     this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
                     this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
 
-                    this._effect.setFloat2("depthValues", scene.activeCamera.minZ, scene.activeCamera.minZ + scene.activeCamera.maxZ);
+                    this._effect.setFloat2("depthValues", camera.minZ, camera.minZ + camera.maxZ);
 
 
                     // Alpha test
                     // Alpha test
                     if (material && material.needAlphaTesting()) {
                     if (material && material.needAlphaTesting()) {
@@ -96,6 +114,12 @@
             };
             };
         }
         }
 
 
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
             var material: any = subMesh.getMaterial();
             var material: any = subMesh.getMaterial();
             if (material.disableDepthWrite) {
             if (material.disableDepthWrite) {
@@ -157,11 +181,17 @@
             return this._effect.isReady();
             return this._effect.isReady();
         }
         }
 
 
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
         public getDepthMap(): RenderTargetTexture {
         public getDepthMap(): RenderTargetTexture {
             return this._depthMap;
             return this._depthMap;
         }
         }
 
 
-        // Methods
+        /**
+         * Disposes of the depth renderer.
+         */
         public dispose(): void {
         public dispose(): void {
             this._depthMap.dispose();
             this._depthMap.dispose();
         }
         }

+ 23 - 1
src/Shaders/default.fragment.fx

@@ -4,6 +4,8 @@
 #extension GL_OES_standard_derivatives : enable
 #extension GL_OES_standard_derivatives : enable
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEGIN
+
 #ifdef LOGARITHMICDEPTH
 #ifdef LOGARITHMICDEPTH
 #extension GL_EXT_frag_depth : enable
 #extension GL_EXT_frag_depth : enable
 #endif
 #endif
@@ -152,14 +154,23 @@ varying vec3 vDirectionW;
 #include<logDepthDeclaration>
 #include<logDepthDeclaration>
 #include<fogFragmentDeclaration>
 #include<fogFragmentDeclaration>
 
 
+#define CUSTOM_FRAGMENT_DEFINITIONS
+
 void main(void) {
 void main(void) {
+
+#define CUSTOM_FRAGMENT_MAIN_BEGIN
+
 #include<clipPlaneFragment>
 #include<clipPlaneFragment>
 
 
+
+
 	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
 	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
 
 
 	// Base color
 	// Base color
 	vec4 baseColor = vec4(1., 1., 1., 1.);
 	vec4 baseColor = vec4(1., 1., 1., 1.);
 	vec3 diffuseColor = vDiffuseColor.rgb;
 	vec3 diffuseColor = vDiffuseColor.rgb;
+	
+	
 
 
 	// Alpha
 	// Alpha
 	float alpha = vDiffuseColor.a;
 	float alpha = vDiffuseColor.a;
@@ -188,16 +199,22 @@ void main(void) {
 	#ifdef ALPHAFROMDIFFUSE
 	#ifdef ALPHAFROMDIFFUSE
 		alpha *= baseColor.a;
 		alpha *= baseColor.a;
 	#endif
 	#endif
+	
+	#define CUSTOM_FRAGMENT_UPDATE_ALPHA
 
 
 	baseColor.rgb *= vDiffuseInfos.y;
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 #endif
 
 
+
+
 #include<depthPrePass>
 #include<depthPrePass>
 
 
 #ifdef VERTEXCOLOR
 #ifdef VERTEXCOLOR
 	baseColor.rgb *= vColor.rgb;
 	baseColor.rgb *= vColor.rgb;
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE
+
 	// Ambient color
 	// Ambient color
 	vec3 baseAmbientColor = vec3(1., 1., 1.);
 	vec3 baseAmbientColor = vec3(1., 1., 1.);
 
 
@@ -205,6 +222,8 @@ void main(void) {
 	baseAmbientColor = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb * vAmbientInfos.y;
 	baseAmbientColor = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb * vAmbientInfos.y;
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEFORE_LIGHTS
+
 	// Specular map
 	// Specular map
 #ifdef SPECULARTERM
 #ifdef SPECULARTERM
 	float glossiness = vSpecularColor.a;
 	float glossiness = vSpecularColor.a;
@@ -398,6 +417,8 @@ void main(void) {
     #endif
     #endif
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEFORE_FOG
+
 #include<logDepthFragment>
 #include<logDepthFragment>
 #include<fogFragment>
 #include<fogFragment>
 
 
@@ -417,5 +438,6 @@ void main(void) {
 	color.rgb *= color.a;
 	color.rgb *= color.a;
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 	gl_FragColor = color;
 	gl_FragColor = color;
-}
+}

+ 14 - 1
src/Shaders/default.vertex.fx

@@ -1,5 +1,8 @@
 #include<__decl__defaultVertex>
 #include<__decl__defaultVertex>
 // Attributes
 // Attributes
+
+#define CUSTOM_VERTEX_BEGIN
+
 attribute vec3 position;
 attribute vec3 position;
 #ifdef NORMAL
 #ifdef NORMAL
 attribute vec3 normal;
 attribute vec3 normal;
@@ -89,8 +92,12 @@ varying vec3 vDirectionW;
 #endif
 #endif
 
 
 #include<logDepthDeclaration>
 #include<logDepthDeclaration>
+#define CUSTOM_VERTEX_DEFINITIONS
 
 
 void main(void) {
 void main(void) {
+	
+	#define CUSTOM_VERTEX_MAIN_BEGIN
+	
 	vec3 positionUpdated = position;
 	vec3 positionUpdated = position;
 #ifdef NORMAL	
 #ifdef NORMAL	
 	vec3 normalUpdated = normal;
 	vec3 normalUpdated = normal;
@@ -105,6 +112,10 @@ void main(void) {
 	vPositionUVW = positionUpdated;
 	vPositionUVW = positionUpdated;
 #endif 
 #endif 
 
 
+#define CUSTOM_VERTEX_UPDATE_POSITION
+
+#define CUSTOM_VERTEX_UPDATE_NORMAL
+
 #include<instancesVertex>
 #include<instancesVertex>
 #include<bonesVertex>
 #include<bonesVertex>
 
 
@@ -233,4 +244,6 @@ void main(void) {
 #include<pointCloudVertex>
 #include<pointCloudVertex>
 #include<logDepthVertex>
 #include<logDepthVertex>
 
 
-}
+#define CUSTOM_VERTEX_MAIN_END
+
+}

+ 8 - 0
src/Shaders/gpuRenderParticles.fragment.fx

@@ -7,6 +7,14 @@ in vec4 vColor;
 
 
 out vec4 outFragColor;
 out vec4 outFragColor;
 
 
+#ifdef CLIPPLANE
+in float fClipDistance;
+#endif
+
 void main() {
 void main() {
+#ifdef CLIPPLANE
+	if (fClipDistance > 0.0)
+		discard;
+#endif  
   outFragColor = texture(textureSampler, vUV) * vColor;
   outFragColor = texture(textureSampler, vUV) * vColor;
 }
 }

+ 0 - 0
src/Shaders/gpuRenderParticles.vertex.fx


Some files were not shown because too many files changed in this diff