Browse Source

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 7 years ago
parent
commit
1fd30a5719
100 changed files with 207223 additions and 46044 deletions
  1. 16 0
      .github/ISSUE_TEMPLATE.md
  2. 5 0
      .gitignore
  3. 1 1
      .vscode/launch.json
  4. 13 6
      .vscode/tasks.json
  5. 11444 8878
      Playground/babylon.d.txt
  6. 1 0
      Playground/debug.html
  7. 1 0
      Playground/frame.html
  8. 1 0
      Playground/full.html
  9. 3 2
      Playground/index-local.html
  10. 1 0
      Playground/index.html
  11. 1 0
      Playground/indexStable.html
  12. 4 0
      Playground/scenes/BoomBox/BoomBox.gltf
  13. BIN
      Playground/scenes/Buggy/glTF-Draco/0.bin
  14. 16995 0
      Playground/scenes/Buggy/glTF-Draco/Buggy.gltf
  15. 15818 0
      Playground/scenes/Buggy/glTF/Buggy.gltf
  16. BIN
      Playground/scenes/Buggy/glTF/Buggy0.bin
  17. 1 1
      Playground/scripts/instanced bones.js
  18. 1 0
      Playground/zipContent/index.html
  19. 42 10
      Tools/Gulp/config.json
  20. 37 13
      Tools/Gulp/gulpfile.js
  21. 1 1
      Tools/Gulp/package.json
  22. 0 69
      Viewer/dist/viewer.js
  23. 0 69
      Viewer/dist/viewer.min.js
  24. 8 2
      Viewer/src/configuration/configuration.ts
  25. 5 2
      Viewer/src/configuration/loader.ts
  26. 2 0
      Viewer/src/configuration/types/index.ts
  27. 134 33
      Viewer/src/viewer/viewer.ts
  28. 2 2
      dist/babylon.glTF2Interface.d.ts
  29. 21 0
      dist/preview release/Oimo.license
  30. 17564 15039
      dist/preview release/babylon.d.ts
  31. 55 53
      dist/preview release/babylon.js
  32. 4828 1356
      dist/preview release/babylon.max.js
  33. 56 54
      dist/preview release/babylon.worker.js
  34. 22 0
      dist/preview release/cannon.license
  35. 4254 1729
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  36. 57 56
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  37. 5635 2855
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  38. 5637 2857
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  39. 201 0
      dist/preview release/draco.license
  40. 31 0
      dist/preview release/draco_decoder.js
  41. 4830 1358
      dist/preview release/es6.js
  42. 57 20
      dist/preview release/gui/babylon.gui.d.ts
  43. 178 54
      dist/preview release/gui/babylon.gui.js
  44. 3 3
      dist/preview release/gui/babylon.gui.min.js
  45. 57 20
      dist/preview release/gui/babylon.gui.module.d.ts
  46. 1 1
      dist/preview release/gui/package.json
  47. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  48. 5 2
      dist/preview release/inspector/babylon.inspector.css
  49. 13 2
      dist/preview release/inspector/babylon.inspector.js
  50. 4 4
      dist/preview release/inspector/babylon.inspector.min.js
  51. 1 1
      dist/preview release/inspector/package.json
  52. 57 23
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  53. 107 81
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  54. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  55. 252 385
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  56. 1283 1518
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  57. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  58. 244 379
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  59. 1323 1548
      dist/preview release/loaders/babylon.glTFFileLoader.js
  60. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  61. 1 1
      dist/preview release/loaders/babylon.objFileLoader.d.ts
  62. 4 7
      dist/preview release/loaders/babylon.objFileLoader.js
  63. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  64. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.d.ts
  65. 4 7
      dist/preview release/loaders/babylon.stlFileLoader.js
  66. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.min.js
  67. 1322 1562
      dist/preview release/loaders/babylonjs.loaders.js
  68. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  69. 246 381
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  70. 1 1
      dist/preview release/loaders/package.json
  71. 1 0
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  72. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.min.js
  73. 1 0
      dist/preview release/materialsLibrary/babylonjs.materials.js
  74. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  75. 1 1
      dist/preview release/materialsLibrary/package.json
  76. 1 1
      dist/preview release/postProcessesLibrary/package.json
  77. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  78. 65 22
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  79. 297 248
      dist/preview release/serializers/babylon.glTF2Serializer.js
  80. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  81. 297 248
      dist/preview release/serializers/babylonjs.serializers.js
  82. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  83. 314 22
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  84. 1 1
      dist/preview release/serializers/package.json
  85. 1398 4908
      dist/preview release/typedocValidationBaseline.json
  86. 486 0
      dist/preview release/viewer/babylon.viewer.d.ts
  87. 68 67
      dist/preview release/viewer/babylon.viewer.js
  88. 110728 0
      dist/preview release/viewer/babylon.viewer.max.js
  89. 486 0
      dist/preview release/viewer/babylon.viewer.module.d.ts
  90. 3 1
      dist/preview release/viewer/package.json
  91. 40 7
      dist/preview release/what's new.md
  92. 16 9
      gui/src/advancedDynamicTexture.ts
  93. 6 6
      gui/src/controls/button.ts
  94. 2 2
      gui/src/controls/checkbox.ts
  95. 6 6
      gui/src/controls/colorpicker.ts
  96. 4 3
      gui/src/controls/container.ts
  97. 40 13
      gui/src/controls/control.ts
  98. 4 4
      gui/src/controls/inputText.ts
  99. 45 7
      gui/src/controls/line.ts
  100. 0 0
      gui/src/controls/radioButton.ts

+ 16 - 0
.github/ISSUE_TEMPLATE.md

@@ -0,0 +1,16 @@
+Before creating an issue, please make sure to provide the following template (based on why you create the issue):
+(Please do not use Github issues for questions - We have a really active forum to help answering questions (http://www.html5gamedevs.com/forum/16-babylonjs/))
+
+# Bugs
+
+- Bug repro on [playground](https://playground.babylonjs.com):
+- Expected result:
+- Current result:
+
+# Feature request
+
+- Link to [forum](http://www.html5gamedevs.com/forum/16-babylonjs/) discussion about the feature:
+- Feature description
+- Additional links that could help implementing the feature:
+
+

+ 5 - 0
.gitignore

@@ -24,6 +24,7 @@ postProcessLibrary/src/**/*.js
 inspector/src/**/*.js
 inspector/src/**/*.js
 serializers/src/**/*.js
 serializers/src/**/*.js
 gui/src/**/*.js
 gui/src/**/*.js
+viewer/src/**/*.js
 tests/unit/**/*.js
 tests/unit/**/*.js
 !tests/unit/karma.conf.js
 !tests/unit/karma.conf.js
 
 
@@ -169,3 +170,7 @@ localDev/src/*
 /localDev/src/index.js
 /localDev/src/index.js
 package-lock.json
 package-lock.json
 dist/preview release/package/
 dist/preview release/package/
+
+# viewer dist files
+/Viewer/dist/viewer.js
+/Viewer/dist/viewer.min.js

+ 1 - 1
.vscode/launch.json

@@ -1,5 +1,5 @@
 {
 {
-    "version": "0.1.0",
+    "version": "2.0.0",
     "configurations": [
     "configurations": [
         {
         {
             "name": "Launch Viewer (Chrome)",
             "name": "Launch Viewer (Chrome)",

+ 13 - 6
.vscode/tasks.json

@@ -1,19 +1,26 @@
 {
 {
     // See https://go.microsoft.com/fwlink/?LinkId=733558
     // See https://go.microsoft.com/fwlink/?LinkId=733558
     // for the documentation about the tasks.json format
     // for the documentation about the tasks.json format
-    "version": "0.1.0",
+    "version": "2.0.0",
     "command": "gulp",
     "command": "gulp",
-    "isShellCommand": true,
     "args": [],
     "args": [],
-    "showOutput": "always",
+    "type": "shell",
     "options": {
     "options": {
         "cwd": "${workspaceRoot}/Tools/Gulp"
         "cwd": "${workspaceRoot}/Tools/Gulp"
     },
     },
+    "presentation": {
+        "echo": true,
+        "reveal": "always",
+        "focus": false,
+        "panel": "shared"
+    },
     "tasks": [
     "tasks": [
         { 
         { 
-            "taskName": "run",
-            // Hijack Test Command for easy shortcut
-            "isTestCommand": true,
+            "label": "run",
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            },
             "isBackground": true,
             "isBackground": true,
             "problemMatcher": {
             "problemMatcher": {
                 "owner": "typescript",
                 "owner": "typescript",

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


+ 1 - 0
Playground/debug.html

@@ -37,6 +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/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 - 0
Playground/frame.html

@@ -26,6 +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/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 - 0
Playground/full.html

@@ -26,6 +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/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>

+ 3 - 2
Playground/index-local.html

@@ -16,8 +16,9 @@
     <!--Monaco-->
     <!--Monaco-->
     <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/Oimo.js"></script>
+    <script src="../dist/preview%20release/cannon.js"></script>
+    <script src="../dist/preview%20release/draco_decoder.js"></script>
+    <script src="../dist/preview%20release/Oimo.js"></script>
     <script src="../tools/DevLoader/BabylonLoader.js"></script>
     <script src="../tools/DevLoader/BabylonLoader.js"></script>
 
 
     <link href="css/index.css" rel="stylesheet" />
     <link href="css/index.css" rel="stylesheet" />

+ 1 - 0
Playground/index.html

@@ -37,6 +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/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 - 0
Playground/indexStable.html

@@ -37,6 +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/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>

+ 4 - 0
Playground/scenes/BoomBox/BoomBox.gltf

@@ -158,15 +158,19 @@
   ],
   ],
   "textures": [
   "textures": [
     {
     {
+      "name": "baseColor",
       "source": 0
       "source": 0
     },
     },
     {
     {
+      "name": "occlusionRoughnessMetallic",
       "source": 1
       "source": 1
     },
     },
     {
     {
+      "name": "normal",
       "source": 2
       "source": 2
     },
     },
     {
     {
+      "name": "emissive",
       "source": 3
       "source": 3
     }
     }
   ]
   ]

BIN
Playground/scenes/Buggy/glTF-Draco/0.bin


File diff suppressed because it is too large
+ 16995 - 0
Playground/scenes/Buggy/glTF-Draco/Buggy.gltf


File diff suppressed because it is too large
+ 15818 - 0
Playground/scenes/Buggy/glTF/Buggy.gltf


BIN
Playground/scenes/Buggy/glTF/Buggy0.bin


+ 1 - 1
Playground/scripts/instanced bones.js

@@ -21,7 +21,7 @@ var createScene = function () {
 
 
     // Shadows
     // Shadows
     var shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
     var shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
-    shadowGenerator.useBlurVarianceShadowMap = true;
+    shadowGenerator.useBlurExponentialShadowMap = true;
 
 
     // Dude
     // Dude
     BABYLON.SceneLoader.ImportMesh("him", "scenes/Dude/", "Dude.babylon", scene, function (newMeshes2, particleSystems2, skeletons2) {
     BABYLON.SceneLoader.ImportMesh("him", "scenes/Dude/", "Dude.babylon", scene, function (newMeshes2, particleSystems2, skeletons2) {

+ 1 - 0
Playground/zipContent/index.html

@@ -9,6 +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/oimo.js"></script>
         <script src="https://preview.babylonjs.com/oimo.js"></script>
         
         
         <style>
         <style>

+ 42 - 10
Tools/Gulp/config.json

@@ -37,6 +37,7 @@
             "solidParticles",
             "solidParticles",
             "additionalMeshes",
             "additionalMeshes",
             "meshBuilder",
             "meshBuilder",
+            "meshCompression",
             "audio",
             "audio",
             "additionalTextures",
             "additionalTextures",
             "shadows",
             "shadows",
@@ -86,7 +87,8 @@
             "nullEngine",
             "nullEngine",
             "instrumentation",
             "instrumentation",
             "backgroundMaterial",
             "backgroundMaterial",
-            "environmentHelper"
+            "environmentHelper",
+            "videoDome"
         ],
         ],
         "minimal": [
         "minimal": [
             "freeCamera",
             "freeCamera",
@@ -114,6 +116,7 @@
             "solidParticles",
             "solidParticles",
             "additionalMeshes",
             "additionalMeshes",
             "meshBuilder",
             "meshBuilder",
+            "meshCompression",
             "audio",
             "audio",
             "additionalTextures",
             "additionalTextures",
             "shadows",
             "shadows",
@@ -178,6 +181,7 @@
                 "../../src/babylon.mixins.js",
                 "../../src/babylon.mixins.js",
                 "../../src/Engine/babylon.webgl2.js",
                 "../../src/Engine/babylon.webgl2.js",
                 "../../src/Tools/babylon.decorators.js",
                 "../../src/Tools/babylon.decorators.js",
+                "../../src/Tools/babylon.deferred.js",
                 "../../src/Tools/babylon.observable.js",
                 "../../src/Tools/babylon.observable.js",
                 "../../src/Tools/babylon.smartArray.js",
                 "../../src/Tools/babylon.smartArray.js",
                 "../../src/Tools/babylon.tools.js",
                 "../../src/Tools/babylon.tools.js",
@@ -270,10 +274,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/babylon.boxParticleEmitter.js",
-                "../../src/Particles/babylon.coneParticleEmitter.js",
-                "../../src/Particles/babylon.sphereParticleEmitter.js",
-                "../../src/Particles/babylon.iParticleEmitterType.js"
+                "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.IParticleEmitterType.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [
                 "core"
                 "core"
@@ -285,10 +289,11 @@
         },
         },
         "gpuParticles": {
         "gpuParticles": {
             "files": [
             "files": [
-                "../../src/Particles/babylon.gpuParticleSystem.js"
+                "../../src/Particles/babylon.gpuParticleSystem.js"          
             ],
             ],
             "dependUpon": [
             "dependUpon": [
-                "core"
+                "core",
+                "particles"
             ],
             ],
             "shaders": [
             "shaders": [
                 "gpuRenderParticles.vertex",
                 "gpuRenderParticles.vertex",
@@ -425,6 +430,12 @@
                 "additionalMeshes"
                 "additionalMeshes"
             ]
             ]
         },
         },
+        "meshCompression" :
+        {
+            "files": [
+                "../../src/Mesh/Compression/babylon.dracoCompression.js"
+            ]
+        },
         "shaderMaterial": {
         "shaderMaterial": {
             "files": [
             "files": [
                 "../../src/Materials/babylon.shaderMaterial.js"
                 "../../src/Materials/babylon.shaderMaterial.js"
@@ -1041,7 +1052,9 @@
             "files": [
             "files": [
                 "../../src/Rendering/babylon.outlineRenderer.js",
                 "../../src/Rendering/babylon.outlineRenderer.js",
                 "../../src/Rendering/babylon.edgesRenderer.js",
                 "../../src/Rendering/babylon.edgesRenderer.js",
-                "../../src/Layer/babylon.highlightlayer.js"
+                "../../src/Layer/babylon.effectLayer.js",
+                "../../src/Layer/babylon.highlightLayer.js",
+                "../../src/Layer/babylon.glowLayer.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [
                 "shaderMaterial"
                 "shaderMaterial"
@@ -1120,6 +1133,16 @@
                 "backgroundMaterial",
                 "backgroundMaterial",
                 "additionalTextures"
                 "additionalTextures"
             ]
             ]
+        },
+        "videoDome": {
+            "files": [
+                "../../src/Helpers/babylon.videoDome.js"
+            ],
+            "dependUpon": [
+                "core",
+                "meshBuilder",
+                "additionalTextures"
+            ]
         }
         }
     },
     },
     "typescript": [
     "typescript": [
@@ -1460,11 +1483,12 @@
             {
             {
                 "files": [
                 "files": [
                     "../../loaders/src/glTF/babylon.glTFFileLoader.ts",
                     "../../loaders/src/glTF/babylon.glTFFileLoader.ts",
+                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtilities.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
-                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
+                    "../../loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_lights.ts"
                     "../../loaders/src/glTF/2.0/Extensions/KHR_lights.ts"
                 ],
                 ],
@@ -1480,11 +1504,12 @@
                     "../../loaders/src/glTF/1.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFBinaryExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFBinaryExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFMaterialsCommonExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFMaterialsCommonExtension.ts",
+                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtilities.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
-                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
+                    "../../loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts",
                     "../../loaders/src/glTF/2.0/Extensions/KHR_lights.ts"
                     "../../loaders/src/glTF/2.0/Extensions/KHR_lights.ts"
                 ],
                 ],
@@ -1524,6 +1549,9 @@
             "distOutputDirectory": "/serializers/",
             "distOutputDirectory": "/serializers/",
             "buildAsModule": true,
             "buildAsModule": true,
             "moduleName": "babylonjs-serializers",
             "moduleName": "babylonjs-serializers",
+            "extraDeclarations": [
+                "../../dist/babylon.glTF2Interface.d.ts"
+            ],
             "outputFilename": "babylonjs.serializers",
             "outputFilename": "babylonjs.serializers",
             "moduleDeclaration": "BJSSerializers",
             "moduleDeclaration": "BJSSerializers",
             "extendsRoot": true
             "extendsRoot": true
@@ -1672,6 +1700,10 @@
                         {
                         {
                             "filename": "viewer.js",
                             "filename": "viewer.js",
                             "outputDirectory": "/../../Viewer/dist/"
                             "outputDirectory": "/../../Viewer/dist/"
+                        },
+                        {
+                            "filename": "babylon.viewer.max.js",
+                            "outputDirectory": "/viewer/"
                         }
                         }
                     ]
                     ]
                 }
                 }

+ 37 - 13
Tools/Gulp/gulpfile.js

@@ -325,7 +325,9 @@ var buildExternalLibraries = function (settings) {
             let dtsFiles = files.map(function (filename) {
             let dtsFiles = files.map(function (filename) {
                 return filename.replace(".js", ".d.ts");
                 return filename.replace(".js", ".d.ts");
             });
             });
-
+            if (settings.build.extraDeclarations) {
+                settings.build.extraDeclarations.forEach(file => { dtsFiles.unshift(file) })
+            }
             let dtsTask = gulp.src(dtsFiles)
             let dtsTask = gulp.src(dtsFiles)
                 .pipe(concat(settings.build.outputFilename + ".module.d.ts"))
                 .pipe(concat(settings.build.outputFilename + ".module.d.ts"))
                 .pipe(replace(referenceSearchRegex, ""))
                 .pipe(replace(referenceSearchRegex, ""))
@@ -405,6 +407,8 @@ var buildExternalLibrary = function (library, settings, watch) {
             .pipe(gulp.dest(outputDirectory));
             .pipe(gulp.dest(outputDirectory));
         /*}*/
         /*}*/
 
 
+
+
         var dts = tsProcess.dts
         var dts = tsProcess.dts
             .pipe(concat(library.output))
             .pipe(concat(library.output))
             .pipe(replace(referenceSearchRegex, ""))
             .pipe(replace(referenceSearchRegex, ""))
@@ -432,22 +436,42 @@ var buildExternalLibrary = function (library, settings, watch) {
                 let build = wpBuild
                 let build = wpBuild
                     .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
                     .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
 
 
+                let unminifiedOutpus = [];
+                let minifiedOutputs = [];
                 settings.build.outputs.forEach(out => {
                 settings.build.outputs.forEach(out => {
-                    let outBuild = build;
                     if (out.minified) {
                     if (out.minified) {
-                        outBuild = build
-                            .pipe(uglify())
-                            .pipe(optimisejs())
+                        out.destination.forEach(dest => {
+                            minifiedOutputs.push(dest);
+                        });
+                    } else {
+                        out.destination.forEach(dest => {
+                            unminifiedOutpus.push(dest);
+                        });
                     }
                     }
+                });
+
+                function processDestination(dest) {
+                    var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
+                    build = build
+                        .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
+                        .pipe(gulp.dest(outputDirectory));
+                }
+
+                unminifiedOutpus.forEach(dest => {
+                    processDestination(dest);
+                });
+
+                if (minifiedOutputs.length) {
+                    build = build
+                        .pipe(uglify())
+                        .pipe(optimisejs())
+                }
+
+                minifiedOutputs.forEach(dest => {
+                    processDestination(dest);
+                });
 
 
-                    out.destination.forEach(dest => {
-                        var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
-                        let destBuild = outBuild
-                            .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                            .pipe(gulp.dest(outputDirectory));
-                        sequence.push(destBuild);
-                    });
-                })
+                sequence.push(build);
             } else {
             } else {
                 sequence.push(
                 sequence.push(
                     wpBuild
                     wpBuild

+ 1 - 1
Tools/Gulp/package.json

@@ -57,7 +57,7 @@
         "through2": "~0.6.5",
         "through2": "~0.6.5",
         "ts-loader": "^2.3.7",
         "ts-loader": "^2.3.7",
         "typedoc": "^0.9.0",
         "typedoc": "^0.9.0",
-        "typescript": "^2.6.2",
+        "typescript": "~2.6.2",
         "webpack-stream": "^4.0.0"
         "webpack-stream": "^4.0.0"
     },
     },
     "scripts": {
     "scripts": {

File diff suppressed because it is too large
+ 0 - 69
Viewer/dist/viewer.js


File diff suppressed because it is too large
+ 0 - 69
Viewer/dist/viewer.min.js


+ 8 - 2
Viewer/src/configuration/configuration.ts

@@ -67,7 +67,7 @@ export interface ViewerConfiguration {
 }
 }
 
 
 export interface IModelConfiguration {
 export interface IModelConfiguration {
-    url: string;
+    url?: string;
     loader?: string; // obj, gltf?
     loader?: string; // obj, gltf?
     position?: { x: number, y: number, z: number };
     position?: { x: number, y: number, z: number };
     rotation?: { x: number, y: number, z: number, w?: number };
     rotation?: { x: number, y: number, z: number, w?: number };
@@ -75,8 +75,13 @@ export interface IModelConfiguration {
     parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
     parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
 
 
     castShadow?: boolean;
     castShadow?: boolean;
+    normalize?: boolean | {
+        center?: boolean;
+        unitSize?: boolean;
+        parentIndex?: number;
+    }; // shoud the model be scaled to unit-size
 
 
-    title: string;
+    title?: string;
     subtitle?: string;
     subtitle?: string;
     thumbnail?: string; // URL or data-url
     thumbnail?: string; // URL or data-url
 
 
@@ -95,6 +100,7 @@ export interface ISkyboxConfiguration {
     blur?: number; // deprecated
     blur?: number; // deprecated
     material?: {
     material?: {
         imageProcessingConfiguration?: IImageProcessingConfiguration;
         imageProcessingConfiguration?: IImageProcessingConfiguration;
+        [propName: string]: any;
     };
     };
     infiniteDIstance?: boolean;
     infiniteDIstance?: boolean;
 
 

+ 5 - 2
Viewer/src/configuration/loader.ts

@@ -12,7 +12,7 @@ export class ConfigurationLoader {
         this.configurationCache = {};
         this.configurationCache = {};
     }
     }
 
 
-    public loadConfiguration(initConfig: ViewerConfiguration = {}): Promise<ViewerConfiguration> {
+    public loadConfiguration(initConfig: ViewerConfiguration = {}, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration> {
 
 
         let loadedConfig: ViewerConfiguration = deepmerge({}, initConfig);
         let loadedConfig: ViewerConfiguration = deepmerge({}, initConfig);
 
 
@@ -55,9 +55,12 @@ export class ConfigurationLoader {
             }).then((data: any) => {
             }).then((data: any) => {
                 let mapper = mapperManager.getMapper(mapperType);
                 let mapper = mapperManager.getMapper(mapperType);
                 let parsed = mapper.map(data);
                 let parsed = mapper.map(data);
-                return deepmerge(loadedConfig, parsed);
+                let merged = deepmerge(loadedConfig, parsed);
+                if (callback) callback(merged);
+                return merged;
             });
             });
         } else {
         } else {
+            if (callback) callback(loadedConfig);
             return Promise.resolve(loadedConfig);
             return Promise.resolve(loadedConfig);
         }
         }
     }
     }

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

@@ -8,6 +8,8 @@ let getConfigurationType = function (type: string): ViewerConfiguration {
             return defaultConfiguration;
             return defaultConfiguration;
         case 'minimal':
         case 'minimal':
             return minimalConfiguration;
             return minimalConfiguration;
+        case 'none':
+            return {};
         default:
         default:
             return defaultConfiguration;
             return defaultConfiguration;
     }
     }

+ 134 - 33
Viewer/src/viewer/viewer.ts

@@ -26,12 +26,17 @@ export abstract class AbstractViewer {
     public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
     public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
 
 
     protected configuration: ViewerConfiguration;
     protected configuration: ViewerConfiguration;
-    protected environmentHelper: EnvironmentHelper;
+    public environmentHelper: EnvironmentHelper;
 
 
     protected defaultHighpTextureType: number;
     protected defaultHighpTextureType: number;
     protected shadowGeneratorBias: number;
     protected shadowGeneratorBias: number;
     protected defaultPipelineTextureType: number;
     protected defaultPipelineTextureType: number;
     protected maxShadows: number;
     protected maxShadows: number;
+    private _hdrSupport: boolean;
+
+    public get isHdrSupported() {
+        return this._hdrSupport;
+    }
 
 
 
 
     // observables
     // observables
@@ -43,7 +48,7 @@ export abstract class AbstractViewer {
     public onLoaderInitObservable: Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
     public onLoaderInitObservable: Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
     public onInitDoneObservable: Observable<AbstractViewer>;
     public onInitDoneObservable: Observable<AbstractViewer>;
 
 
-    protected canvas: HTMLCanvasElement;
+    public canvas: HTMLCanvasElement;
 
 
     protected registeredOnBeforerenderFunctions: Array<() => void>;
     protected registeredOnBeforerenderFunctions: Array<() => void>;
 
 
@@ -74,8 +79,8 @@ export abstract class AbstractViewer {
         this.prepareContainerElement();
         this.prepareContainerElement();
 
 
         // extend the configuration
         // extend the configuration
-        configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
-            this.configuration = configuration;
+        configurationLoader.loadConfiguration(initialConfiguration, (configuration) => {
+            this.configuration = deepmerge(this.configuration || {}, configuration);
             if (this.configuration.observers) {
             if (this.configuration.observers) {
                 this.configureObservers(this.configuration.observers);
                 this.configureObservers(this.configuration.observers);
             }
             }
@@ -131,6 +136,9 @@ export abstract class AbstractViewer {
      * @param newConfiguration 
      * @param newConfiguration 
      */
      */
     public updateConfiguration(newConfiguration: Partial<ViewerConfiguration> = this.configuration) {
     public updateConfiguration(newConfiguration: Partial<ViewerConfiguration> = this.configuration) {
+        // update this.configuration with the new data
+        this.configuration = deepmerge(this.configuration || {}, newConfiguration);
+
         // update scene configuration
         // update scene configuration
         if (newConfiguration.scene) {
         if (newConfiguration.scene) {
             this.configureScene(newConfiguration.scene);
             this.configureScene(newConfiguration.scene);
@@ -160,14 +168,17 @@ export abstract class AbstractViewer {
             this.configureEnvironment(newConfiguration.skybox, newConfiguration.ground);
             this.configureEnvironment(newConfiguration.skybox, newConfiguration.ground);
         }
         }
 
 
-        // update this.configuration with the new data
-        this.configuration = deepmerge(this.configuration || {}, newConfiguration);
+        // camera
+        if (newConfiguration.camera) {
+            this.configureCamera(newConfiguration.camera);
+        }
     }
     }
 
 
     protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean) {
     protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean) {
         if (!skyboxConifguration && !groundConfiguration) {
         if (!skyboxConifguration && !groundConfiguration) {
             if (this.environmentHelper) {
             if (this.environmentHelper) {
                 this.environmentHelper.dispose();
                 this.environmentHelper.dispose();
+                delete this.environmentHelper;
             };
             };
             return Promise.resolve(this.scene);
             return Promise.resolve(this.scene);
         }
         }
@@ -187,7 +198,7 @@ export abstract class AbstractViewer {
             }
             }
 
 
             options.enableGroundShadow = groundConfig === true || groundConfig.receiveShadows;
             options.enableGroundShadow = groundConfig === true || groundConfig.receiveShadows;
-            if (groundConfig.shadowLevel) {
+            if (groundConfig.shadowLevel !== undefined) {
                 options.groundShadowLevel = groundConfig.shadowLevel;
                 options.groundShadowLevel = groundConfig.shadowLevel;
             }
             }
             options.enableGroundMirror = !!groundConfig.mirror;
             options.enableGroundMirror = !!groundConfig.mirror;
@@ -198,22 +209,26 @@ export abstract class AbstractViewer {
                 options.groundColor = new Color3(groundConfig.color.r, groundConfig.color.g, groundConfig.color.b)
                 options.groundColor = new Color3(groundConfig.color.r, groundConfig.color.g, groundConfig.color.b)
             }
             }
 
 
+            if (groundConfig.opacity !== undefined) {
+                options.groundOpacity = groundConfig.opacity;
+            }
+
             if (groundConfig.mirror) {
             if (groundConfig.mirror) {
                 options.enableGroundMirror = true;
                 options.enableGroundMirror = true;
                 // to prevent undefines
                 // to prevent undefines
                 if (typeof groundConfig.mirror === "object") {
                 if (typeof groundConfig.mirror === "object") {
-                    if (groundConfig.mirror.amount)
+                    if (groundConfig.mirror.amount !== undefined)
                         options.groundMirrorAmount = groundConfig.mirror.amount;
                         options.groundMirrorAmount = groundConfig.mirror.amount;
-                    if (groundConfig.mirror.sizeRatio)
+                    if (groundConfig.mirror.sizeRatio !== undefined)
                         options.groundMirrorSizeRatio = groundConfig.mirror.sizeRatio;
                         options.groundMirrorSizeRatio = groundConfig.mirror.sizeRatio;
-                    if (groundConfig.mirror.blurKernel)
+                    if (groundConfig.mirror.blurKernel !== undefined)
                         options.groundMirrorBlurKernel = groundConfig.mirror.blurKernel;
                         options.groundMirrorBlurKernel = groundConfig.mirror.blurKernel;
-                    if (groundConfig.mirror.fresnelWeight)
+                    if (groundConfig.mirror.fresnelWeight !== undefined)
                         options.groundMirrorFresnelWeight = groundConfig.mirror.fresnelWeight;
                         options.groundMirrorFresnelWeight = groundConfig.mirror.fresnelWeight;
-                    if (groundConfig.mirror.fallOffDistance)
+                    if (groundConfig.mirror.fallOffDistance !== undefined)
                         options.groundMirrorFallOffDistance = groundConfig.mirror.fallOffDistance;
                         options.groundMirrorFallOffDistance = groundConfig.mirror.fallOffDistance;
-                    if (this.defaultHighpTextureType !== undefined)
-                        options.groundMirrorTextureType = this.defaultHighpTextureType;
+                    if (this.defaultPipelineTextureType !== undefined)
+                        options.groundMirrorTextureType = this.defaultPipelineTextureType;
                 }
                 }
             }
             }
 
 
@@ -247,6 +262,8 @@ export abstract class AbstractViewer {
             }
             }
         }
         }
 
 
+        options.setupImageProcessing = false; // TMP
+
         if (!this.environmentHelper) {
         if (!this.environmentHelper) {
             this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
             this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
         } else {
         } else {
@@ -393,6 +410,8 @@ export abstract class AbstractViewer {
             this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
             this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
         }
         }
 
 
+        this.extendClassWithConfig(this.camera, cameraConfig);
+
         this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
         this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
         this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
         this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
 
 
@@ -405,7 +424,8 @@ export abstract class AbstractViewer {
         const sceneExtends = this.scene.getWorldExtends();
         const sceneExtends = this.scene.getWorldExtends();
         const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         const sceneDiagonalLenght = sceneDiagonal.length();
         const sceneDiagonalLenght = sceneDiagonal.length();
-        this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
+        if (isFinite(sceneDiagonalLenght))
+            this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
     }
     }
 
 
     protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
     protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
@@ -413,6 +433,15 @@ export abstract class AbstractViewer {
         if (!Object.keys(lightsConfiguration).length) return;
         if (!Object.keys(lightsConfiguration).length) return;
 
 
         let lightsAvailable: Array<string> = this.scene.lights.map(light => light.name);
         let lightsAvailable: Array<string> = this.scene.lights.map(light => light.name);
+        // compare to the global (!) configuration object and dispose unneeded:
+        let lightsToConfigure = Object.keys(this.configuration.lights || []);
+        if (Object.keys(lightsToConfigure).length !== lightsAvailable.length) {
+            lightsAvailable.forEach(lName => {
+                if (lightsToConfigure.indexOf(lName) === -1) {
+                    this.scene.getLightByName(lName)!.dispose()
+                }
+            });
+        }
 
 
         Object.keys(lightsConfiguration).forEach((name, idx) => {
         Object.keys(lightsConfiguration).forEach((name, idx) => {
             let lightConfig: ILightConfiguration = { type: 0 };
             let lightConfig: ILightConfiguration = { type: 0 };
@@ -422,7 +451,7 @@ export abstract class AbstractViewer {
 
 
             lightConfig.name = name;
             lightConfig.name = name;
 
 
-            let light;
+            let light: Light;
             // light is not already available
             // light is not already available
             if (lightsAvailable.indexOf(name) === -1) {
             if (lightsAvailable.indexOf(name) === -1) {
                 let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
                 let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
@@ -430,8 +459,14 @@ export abstract class AbstractViewer {
                 light = constructor();
                 light = constructor();
             } else {
             } else {
                 // available? get it from the scene
                 // available? get it from the scene
-                light = this.scene.getLightByName(name);
+                light = <Light>this.scene.getLightByName(name);
                 lightsAvailable = lightsAvailable.filter(ln => ln !== name);
                 lightsAvailable = lightsAvailable.filter(ln => ln !== name);
+                if (lightConfig.type !== undefined && light.getTypeID() !== lightConfig.type) {
+                    light.dispose();
+                    let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
+                    if (!constructor) return;
+                    light = constructor();
+                }
             }
             }
 
 
             // if config set the light to false, dispose it.
             // if config set the light to false, dispose it.
@@ -441,18 +476,28 @@ export abstract class AbstractViewer {
             }
             }
 
 
             //enabled
             //enabled
-            if (light.isEnabled() !== !lightConfig.disabled) {
-                light.setEnabled(!lightConfig.disabled);
-            }
+            var enabled = lightConfig.enabled !== undefined ? lightConfig.enabled : !lightConfig.disabled;
+            light.setEnabled(enabled);
+
 
 
             this.extendClassWithConfig(light, lightConfig);
             this.extendClassWithConfig(light, lightConfig);
 
 
             //position. Some lights don't support shadows
             //position. Some lights don't support shadows
             if (light instanceof ShadowLight) {
             if (light instanceof ShadowLight) {
+                if (lightConfig.target) {
+                    if (light.setDirectionToTarget) {
+                        let target = Vector3.Zero().copyFrom(lightConfig.target as Vector3);
+                        light.setDirectionToTarget(target);
+                    }
+                } else if (lightConfig.direction) {
+                    let direction = Vector3.Zero().copyFrom(lightConfig.direction as Vector3);
+                    light.direction = direction;
+                }
                 let shadowGenerator = light.getShadowGenerator();
                 let shadowGenerator = light.getShadowGenerator();
                 if (lightConfig.shadowEnabled && this.maxShadows) {
                 if (lightConfig.shadowEnabled && this.maxShadows) {
                     if (!shadowGenerator) {
                     if (!shadowGenerator) {
                         shadowGenerator = new ShadowGenerator(512, light);
                         shadowGenerator = new ShadowGenerator(512, light);
+                        // TODO blur kernel definition
                     }
                     }
                     this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
                     this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
                     // add the focues meshes to the shadow list
                     // add the focues meshes to the shadow list
@@ -461,7 +506,7 @@ export abstract class AbstractViewer {
                     let renderList = shadownMap.renderList;
                     let renderList = shadownMap.renderList;
                     for (var index = 0; index < focusMeshes.length; index++) {
                     for (var index = 0; index < focusMeshes.length; index++) {
                         if (Tags.MatchesQuery(focusMeshes[index], 'castShadow')) {
                         if (Tags.MatchesQuery(focusMeshes[index], 'castShadow')) {
-                            // renderList && renderList.push(focusMeshes[index]);
+                            renderList && renderList.push(focusMeshes[index]);
                         }
                         }
                     }
                     }
                 } else if (shadowGenerator) {
                 } else if (shadowGenerator) {
@@ -473,7 +518,7 @@ export abstract class AbstractViewer {
         // remove the unneeded lights
         // remove the unneeded lights
         /*lightsAvailable.forEach(name => {
         /*lightsAvailable.forEach(name => {
             let light = this.scene.getLightByName(name);
             let light = this.scene.getLightByName(name);
-            if (light) {
+            if (light && !Tags.MatchesQuery(light, "fixed")) {
                 light.dispose();
                 light.dispose();
             }
             }
         });*/
         });*/
@@ -529,13 +574,60 @@ export abstract class AbstractViewer {
                 Tags.AddTagsTo(mesh, 'castShadow');
                 Tags.AddTagsTo(mesh, 'castShadow');
             });
             });
         }
         }
+
+        if (modelConfiguration.normalize) {
+            let center = false;
+            let unitSize = false;
+            let parentIndex;
+            if (modelConfiguration.normalize === true) {
+                center = true;
+                unitSize = true;
+                parentIndex = 0;
+            } else {
+                center = !!modelConfiguration.normalize.center;
+                unitSize = !!modelConfiguration.normalize.unitSize;
+                parentIndex = modelConfiguration.normalize.parentIndex;
+            }
+
+            let meshesToNormalize: Array<AbstractMesh> = [];
+            if (parentIndex !== undefined) {
+                meshesToNormalize.push(focusMeshes[parentIndex]);
+            } else {
+                meshesToNormalize = meshesWithNoParent;
+            }
+
+            if (unitSize) {
+                meshesToNormalize.forEach(mesh => {
+                    console.log(mesh.scaling.x)
+                    mesh.normalizeToUnitCube(true);
+                    mesh.computeWorldMatrix(true);
+                    console.log(mesh.scaling.x)
+                });
+            }
+            if (center) {
+                meshesToNormalize.forEach(mesh => {
+                    const boundingInfo = mesh.getHierarchyBoundingVectors(true);
+                    const sizeVec = boundingInfo.max.subtract(boundingInfo.min);
+                    const halfSizeVec = sizeVec.scale(0.5);
+                    const center = boundingInfo.min.add(halfSizeVec);
+                    mesh.position = center.scale(-1);
+
+                    // Set on ground.
+                    mesh.position.y += halfSizeVec.y;
+
+                    // Recompute Info.
+                    mesh.computeWorldMatrix(true);
+                });
+            }
+        }
     }
     }
 
 
     public dispose() {
     public dispose() {
         window.removeEventListener('resize', this.resize);
         window.removeEventListener('resize', this.resize);
-
-        this.sceneOptimizer.stop();
-        this.sceneOptimizer.dispose();
+        if (this.sceneOptimizer) {
+            this.sceneOptimizer.stop();
+            this.sceneOptimizer.dispose();
+        }
 
 
         if (this.scene.activeCamera) {
         if (this.scene.activeCamera) {
             this.scene.activeCamera.detachControl(this.canvas);
             this.scene.activeCamera.detachControl(this.canvas);
@@ -653,6 +745,10 @@ export abstract class AbstractViewer {
     }
     }
 
 
     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!
+        if (!model.url) {
+            return Promise.resolve(this.scene);
+        }
         this.configuration.model = model;
         this.configuration.model = model;
         let modelUrl = (typeof model === 'string') ? model : model.url;
         let modelUrl = (typeof model === 'string') ? model : model.url;
         let parts = modelUrl.split('/');
         let parts = modelUrl.split('/');
@@ -727,7 +823,7 @@ export abstract class AbstractViewer {
         let linearHalfFloatTargets = caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering;
         let linearHalfFloatTargets = caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering;
         let linearFloatTargets = caps.textureFloatRender && caps.textureFloatLinearFiltering;
         let linearFloatTargets = caps.textureFloatRender && caps.textureFloatLinearFiltering;
 
 
-        let supportsHDR: boolean = !!(linearFloatTargets || linearHalfFloatTargets);
+        this._hdrSupport = !!(linearFloatTargets || linearHalfFloatTargets);
 
 
         if (linearHalfFloatTargets) {
         if (linearHalfFloatTargets) {
             this.defaultHighpTextureType = Engine.TEXTURETYPE_HALF_FLOAT;
             this.defaultHighpTextureType = Engine.TEXTURETYPE_HALF_FLOAT;
@@ -740,7 +836,7 @@ export abstract class AbstractViewer {
             this.shadowGeneratorBias = 0.001;
             this.shadowGeneratorBias = 0.001;
         }
         }
 
 
-        this.defaultPipelineTextureType = supportsHDR ? this.defaultHighpTextureType : Engine.TEXTURETYPE_UNSIGNED_INT;
+        this.defaultPipelineTextureType = this._hdrSupport ? this.defaultHighpTextureType : Engine.TEXTURETYPE_UNSIGNED_INT;
     }
     }
 
 
     /**
     /**
@@ -770,12 +866,14 @@ export abstract class AbstractViewer {
         if (!config) return;
         if (!config) return;
         Object.keys(config).forEach(key => {
         Object.keys(config).forEach(key => {
             if (key in object && typeof object[key] !== 'function') {
             if (key in object && typeof object[key] !== 'function') {
-                if (typeof object[key] === 'function') return;
+                // if (typeof object[key] === 'function') return;
                 // if it is an object, iterate internally until reaching basic types
                 // if it is an object, iterate internally until reaching basic types
                 if (typeof object[key] === 'object') {
                 if (typeof object[key] === 'object') {
                     this.extendClassWithConfig(object[key], config[key]);
                     this.extendClassWithConfig(object[key], config[key]);
                 } else {
                 } else {
-                    object[key] = config[key];
+                    if (config[key] !== undefined) {
+                        object[key] = config[key];
+                    }
                 }
                 }
             }
             }
         });
         });
@@ -794,13 +892,16 @@ export abstract class AbstractViewer {
         // constructing behavior
         // constructing behavior
         switch (type) {
         switch (type) {
             case CameraBehavior.AUTOROTATION:
             case CameraBehavior.AUTOROTATION:
-                behavior = new AutoRotationBehavior();
+                this.camera.useAutoRotationBehavior = true;
+                behavior = this.camera.autoRotationBehavior;
                 break;
                 break;
             case CameraBehavior.BOUNCING:
             case CameraBehavior.BOUNCING:
-                behavior = new BouncingBehavior();
+                this.camera.useBouncingBehavior = true;
+                behavior = this.camera.bouncingBehavior;
                 break;
                 break;
             case CameraBehavior.FRAMING:
             case CameraBehavior.FRAMING:
-                behavior = new FramingBehavior();
+                this.camera.useFramingBehavior = true;
+                behavior = this.camera.framingBehavior;
                 break;
                 break;
             default:
             default:
                 behavior = null;
                 behavior = null;
@@ -811,7 +912,7 @@ export abstract class AbstractViewer {
             if (typeof behaviorConfig === "object") {
             if (typeof behaviorConfig === "object") {
                 this.extendClassWithConfig(behavior, behaviorConfig);
                 this.extendClassWithConfig(behavior, behaviorConfig);
             }
             }
-            this.camera.addBehavior(behavior);
+            //this.camera.addBehavior(behavior);
         }
         }
 
 
         // post attach configuration. Some functionalities require the attached camera.
         // post attach configuration. Some functionalities require the attached camera.

+ 2 - 2
dist/babylon.glTF2Interface.d.ts

@@ -22,7 +22,7 @@ declare module BABYLON.GLTF2 {
         SCALE = "scale",
         SCALE = "scale",
         WEIGHTS = "weights",
         WEIGHTS = "weights",
     }
     }
-    const enum AnimationInterpolation {
+    const enum AnimationSamplerInterpolation {
         LINEAR = "LINEAR",
         LINEAR = "LINEAR",
         STEP = "STEP",
         STEP = "STEP",
         CUBICSPLINE = "CUBICSPLINE",
         CUBICSPLINE = "CUBICSPLINE",
@@ -110,7 +110,7 @@ declare module BABYLON.GLTF2 {
     }
     }
     interface IAnimationSampler extends IProperty {
     interface IAnimationSampler extends IProperty {
         input: number;
         input: number;
-        interpolation?: AnimationInterpolation;
+        interpolation?: AnimationSamplerInterpolation;
         output: number;
         output: number;
     }
     }
     interface IAnimation extends IChildRootProperty {
     interface IAnimation extends IChildRootProperty {

+ 21 - 0
dist/preview release/Oimo.license

@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright © 2010-2017 three.js authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

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


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


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


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


+ 22 - 0
dist/preview release/cannon.license

@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2015 cannon.js Authors
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */

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


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


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


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


+ 201 - 0
dist/preview release/draco.license

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

File diff suppressed because it is too large
+ 31 - 0
dist/preview release/draco_decoder.js


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


+ 57 - 20
dist/preview release/gui/babylon.gui.d.ts

@@ -18,7 +18,9 @@ declare module BABYLON.GUI {
         _lastPickedControl: Control;
         _lastPickedControl: Control;
         _lastControlOver: Nullable<Control>;
         _lastControlOver: Nullable<Control>;
         _lastControlDown: Nullable<Control>;
         _lastControlDown: Nullable<Control>;
-        _capturingControl: Nullable<Control>;
+        _capturingControl: {
+            [pointerId: number]: Control;
+        };
         _shouldBlockPointer: boolean;
         _shouldBlockPointer: boolean;
         _layerToDispose: Nullable<Layer>;
         _layerToDispose: Nullable<Layer>;
         _linkedControls: Control[];
         _linkedControls: Control[];
@@ -49,7 +51,7 @@ declare module BABYLON.GUI {
         _getGlobalViewport(scene: Scene): Viewport;
         _getGlobalViewport(scene: Scene): Viewport;
         private _checkUpdate(camera);
         private _checkUpdate(camera);
         private _render();
         private _render();
-        private _doPicking(x, y, type, buttonIndex);
+        private _doPicking(x, y, type, pointerId, buttonIndex);
         attach(): void;
         attach(): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         moveFocusToControl(control: IFocusableControl): void;
         moveFocusToControl(control: IFocusableControl): void;
@@ -163,6 +165,7 @@ declare module BABYLON.GUI {
         protected _horizontalAlignment: number;
         protected _horizontalAlignment: number;
         protected _verticalAlignment: number;
         protected _verticalAlignment: number;
         private _isDirty;
         private _isDirty;
+        _tempParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         private _paddingLeft;
         private _paddingLeft;
         private _paddingRight;
         private _paddingRight;
@@ -188,6 +191,7 @@ declare module BABYLON.GUI {
         private _downCount;
         private _downCount;
         private _enterCount;
         private _enterCount;
         private _doNotRender;
         private _doNotRender;
+        private _downPointerIds;
         isHitTestVisible: boolean;
         isHitTestVisible: boolean;
         isPointerBlocker: boolean;
         isPointerBlocker: boolean;
         isFocusInvisible: boolean;
         isFocusInvisible: boolean;
@@ -247,6 +251,8 @@ declare module BABYLON.GUI {
         readonly heightInPixels: number;
         readonly heightInPixels: number;
         fontFamily: string;
         fontFamily: string;
         fontStyle: string;
         fontStyle: string;
+        /** @ignore */
+        readonly _isFontSizeInPercentage: boolean;
         readonly fontSizeInPixels: number;
         readonly fontSizeInPixels: number;
         fontSize: string | number;
         fontSize: string | number;
         color: string;
         color: string;
@@ -274,6 +280,8 @@ declare module BABYLON.GUI {
         readonly centerY: number;
         readonly centerY: number;
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
+        /** @ignore */
+        _resetFontCache(): void;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
@@ -294,14 +302,14 @@ declare module BABYLON.GUI {
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         contains(x: number, y: number): boolean;
         contains(x: number, y: number): boolean;
-        _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
+        _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerEnter(target: Control): boolean;
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerOut(target: Control): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
-        forcePointerUp(): void;
-        _processObservables(type: number, x: number, y: number, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        forcePointerUp(pointerId?: Nullable<number>): void;
+        _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number): boolean;
         private _prepareFont();
         private _prepareFont();
         dispose(): void;
         dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
@@ -352,7 +360,7 @@ declare module BABYLON.GUI {
         protected _localDraw(context: CanvasRenderingContext2D): void;
         protected _localDraw(context: CanvasRenderingContext2D): void;
         _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
+        _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         dispose(): void;
         dispose(): void;
@@ -436,7 +444,19 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _moveToProjectedPosition(projectedPosition: Vector3): void;
+        /**
+         * Move one end of the line given 3D cartesian coordinates.
+         * @param position Targeted world position
+         * @param scene Scene
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        moveToVector3(position: Vector3, scene: Scene, end?: boolean): void;
+        /**
+         * Move one end of the line to a position in screen absolute space.
+         * @param projectedPosition Position in screen absolute space (X, Y)
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        _moveToProjectedPosition(projectedPosition: Vector3, end?: boolean): void;
     }
     }
 }
 }
 
 
@@ -470,9 +490,9 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
         private _pointerIsDown;
         private _updateValueFromPointer(x, y);
         private _updateValueFromPointer(x, y);
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
     }
     }
 }
 }
 
 
@@ -492,7 +512,7 @@ declare module BABYLON.GUI {
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
     }
     }
 }
 }
 
 
@@ -513,7 +533,7 @@ declare module BABYLON.GUI {
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
     }
     }
 }
 }
 
 
@@ -531,6 +551,8 @@ declare module BABYLON.GUI {
         private _lines;
         private _lines;
         private _resizeToFit;
         private _resizeToFit;
         private _lineSpacing;
         private _lineSpacing;
+        private _outlineWidth;
+        private _outlineColor;
         /**
         /**
         * An event triggered after the text is changed
         * An event triggered after the text is changed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
@@ -588,6 +610,20 @@ declare module BABYLON.GUI {
          */
          */
         lineSpacing: string | number;
         lineSpacing: string | number;
         /**
         /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        outlineWidth: number;
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        outlineColor: string;
+        /**
          * Creates a new TextBlock object
          * Creates a new TextBlock object
          * @param name defines the name of the control
          * @param name defines the name of the control
          * @param text defines the text to display (emptry string by default)
          * @param text defines the text to display (emptry string by default)
@@ -601,6 +637,7 @@ declare module BABYLON.GUI {
         private _drawText(text, textWidth, y, context);
         private _drawText(text, textWidth, y, context);
         /** @ignore */
         /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
@@ -665,11 +702,11 @@ declare module BABYLON.GUI {
         pointerUpAnimation: () => void;
         pointerUpAnimation: () => void;
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
-        _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
+        _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         _onPointerEnter(target: Control): boolean;
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerOut(target: Control): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
@@ -710,9 +747,9 @@ declare module BABYLON.GUI {
         private _updateValueFromPointer(x, y);
         private _updateValueFromPointer(x, y);
         private _isPointOnSquare(coordinates);
         private _isPointOnSquare(coordinates);
         private _isPointOnWheel(coordinates);
         private _isPointOnWheel(coordinates);
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
     }
     }
 }
 }
 
 
@@ -759,8 +796,8 @@ declare module BABYLON.GUI {
         processKey(keyCode: number, key?: string): void;
         processKey(keyCode: number, key?: string): void;
         processKeyboard(evt: KeyboardEvent): void;
         processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
         dispose(): void;
         dispose(): void;
     }
     }
 }
 }

+ 178 - 54
dist/preview release/gui/babylon.gui.js

@@ -33,6 +33,7 @@ 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._capturingControl = {};
                 _this._linkedControls = new Array();
                 _this._linkedControls = new Array();
                 _this._isFullscreen = false;
                 _this._isFullscreen = false;
                 _this._fullscreenViewport = new BABYLON.Viewport(0, 0, 1, 1);
                 _this._fullscreenViewport = new BABYLON.Viewport(0, 0, 1, 1);
@@ -203,6 +204,11 @@ var BABYLON;
             };
             };
             AdvancedDynamicTexture.prototype.markAsDirty = function () {
             AdvancedDynamicTexture.prototype.markAsDirty = function () {
                 this._isDirty = true;
                 this._isDirty = true;
+                this.executeOnAllControls(function (control) {
+                    if (control._isFontSizeInPercentage) {
+                        control._resetFontCache();
+                    }
+                });
             };
             };
             AdvancedDynamicTexture.prototype.addControl = function (control) {
             AdvancedDynamicTexture.prototype.addControl = function (control) {
                 this._rootContainer.addControl(control);
                 this._rootContainer.addControl(control);
@@ -335,7 +341,7 @@ var BABYLON;
                 var measure = new GUI.Measure(0, 0, renderWidth, renderHeight);
                 var measure = new GUI.Measure(0, 0, renderWidth, renderHeight);
                 this._rootContainer._draw(measure, context);
                 this._rootContainer._draw(measure, context);
             };
             };
-            AdvancedDynamicTexture.prototype._doPicking = function (x, y, type, buttonIndex) {
+            AdvancedDynamicTexture.prototype._doPicking = function (x, y, type, pointerId, buttonIndex) {
                 var scene = this.getScene();
                 var scene = this.getScene();
                 if (!scene) {
                 if (!scene) {
                     return;
                     return;
@@ -346,11 +352,11 @@ var BABYLON;
                     x = x * ((textureSize.width / this._renderScale) / engine.getRenderWidth());
                     x = x * ((textureSize.width / this._renderScale) / engine.getRenderWidth());
                     y = y * ((textureSize.height / this._renderScale) / engine.getRenderHeight());
                     y = y * ((textureSize.height / this._renderScale) / engine.getRenderHeight());
                 }
                 }
-                if (this._capturingControl) {
-                    this._capturingControl._processObservables(type, x, y, buttonIndex);
+                if (this._capturingControl[pointerId]) {
+                    this._capturingControl[pointerId]._processObservables(type, x, y, pointerId, buttonIndex);
                     return;
                     return;
                 }
                 }
-                if (!this._rootContainer._processPicking(x, y, type, buttonIndex)) {
+                if (!this._rootContainer._processPicking(x, y, type, pointerId, buttonIndex)) {
                     if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                         if (this._lastControlOver) {
                         if (this._lastControlOver) {
                             this._lastControlOver._onPointerOut(this._lastControlOver);
                             this._lastControlOver._onPointerOut(this._lastControlOver);
@@ -384,7 +390,7 @@ var BABYLON;
                     var x = (scene.pointerX / engine.getHardwareScalingLevel() - viewport.x * engine.getRenderWidth()) / viewport.width;
                     var x = (scene.pointerX / engine.getHardwareScalingLevel() - viewport.x * engine.getRenderWidth()) / viewport.width;
                     var y = (scene.pointerY / engine.getHardwareScalingLevel() - viewport.y * engine.getRenderHeight()) / viewport.height;
                     var y = (scene.pointerY / engine.getHardwareScalingLevel() - viewport.y * engine.getRenderHeight()) / viewport.height;
                     _this._shouldBlockPointer = false;
                     _this._shouldBlockPointer = false;
-                    _this._doPicking(x, y, pi.type, pi.event.button);
+                    _this._doPicking(x, y, pi.type, pi.event.pointerId || 0, pi.event.button);
                     pi.skipOnPointerObservable = _this._shouldBlockPointer;
                     pi.skipOnPointerObservable = _this._shouldBlockPointer;
                 });
                 });
                 this._attachToOnPointerOut(scene);
                 this._attachToOnPointerOut(scene);
@@ -402,16 +408,17 @@ var BABYLON;
                         && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
                         && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
                         return;
                         return;
                     }
                     }
+                    var pointerId = pi.event.pointerId || 0;
                     if (pi.pickInfo && pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
                     if (pi.pickInfo && pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
                         var uv = pi.pickInfo.getTextureCoordinates();
                         var uv = pi.pickInfo.getTextureCoordinates();
                         if (uv) {
                         if (uv) {
                             var size = _this.getSize();
                             var size = _this.getSize();
-                            _this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, 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) {
                         if (_this._lastControlDown) {
-                            _this._lastControlDown.forcePointerUp();
+                            _this._lastControlDown.forcePointerUp(pointerId);
                         }
                         }
                         _this._lastControlDown = null;
                         _this._lastControlDown = null;
                         _this.focusedControl = null;
                         _this.focusedControl = null;
@@ -826,6 +833,7 @@ var BABYLON;
                 this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
                 this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
                 this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
                 this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
                 this._isDirty = true;
                 this._isDirty = true;
+                this._tempParentMeasure = GUI.Measure.Empty();
                 this._cachedParentMeasure = GUI.Measure.Empty();
                 this._cachedParentMeasure = GUI.Measure.Empty();
                 this._paddingLeft = new GUI.ValueAndUnit(0);
                 this._paddingLeft = new GUI.ValueAndUnit(0);
                 this._paddingRight = new GUI.ValueAndUnit(0);
                 this._paddingRight = new GUI.ValueAndUnit(0);
@@ -848,6 +856,7 @@ var BABYLON;
                 this._downCount = 0;
                 this._downCount = 0;
                 this._enterCount = 0;
                 this._enterCount = 0;
                 this._doNotRender = false;
                 this._doNotRender = false;
+                this._downPointerIds = {};
                 this.isHitTestVisible = true;
                 this.isHitTestVisible = true;
                 this.isPointerBlocker = false;
                 this.isPointerBlocker = false;
                 this.isFocusInvisible = false;
                 this.isFocusInvisible = false;
@@ -1091,9 +1100,20 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
+            Object.defineProperty(Control.prototype, "_isFontSizeInPercentage", {
+                /** @ignore */
+                get: function () {
+                    return this._fontSize.isPercentage;
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Control.prototype, "fontSizeInPixels", {
             Object.defineProperty(Control.prototype, "fontSizeInPixels", {
                 get: function () {
                 get: function () {
-                    return this._fontSize.getValueInPixel(this._host, 100);
+                    if (this._fontSize.isPixel) {
+                        return this._fontSize.getValue(this._host);
+                    }
+                    return this._fontSize.getValueInPixel(this._host, this._tempParentMeasure.height || this._cachedParentMeasure.height);
                 },
                 },
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
@@ -1348,6 +1368,10 @@ var BABYLON;
             Control.prototype._getTypeName = function () {
             Control.prototype._getTypeName = function () {
                 return "Control";
                 return "Control";
             };
             };
+            /** @ignore */
+            Control.prototype._resetFontCache = function () {
+                this._fontSet = true;
+            };
             Control.prototype.getLocalCoordinates = function (globalCoordinates) {
             Control.prototype.getLocalCoordinates = function (globalCoordinates) {
                 var result = BABYLON.Vector2.Zero();
                 var result = BABYLON.Vector2.Zero();
                 this.getLocalCoordinatesToRef(globalCoordinates, result);
                 this.getLocalCoordinatesToRef(globalCoordinates, result);
@@ -1638,14 +1662,14 @@ var BABYLON;
                 }
                 }
                 return true;
                 return true;
             };
             };
-            Control.prototype._processPicking = function (x, y, type, buttonIndex) {
+            Control.prototype._processPicking = function (x, y, type, pointerId, buttonIndex) {
                 if (!this.isHitTestVisible || !this.isVisible || this._doNotRender) {
                 if (!this.isHitTestVisible || !this.isVisible || this._doNotRender) {
                     return false;
                     return false;
                 }
                 }
                 if (!this.contains(x, y)) {
                 if (!this.contains(x, y)) {
                     return false;
                     return false;
                 }
                 }
-                this._processObservables(type, x, y, buttonIndex);
+                this._processObservables(type, x, y, pointerId, buttonIndex);
                 return true;
                 return true;
             };
             };
             Control.prototype._onPointerMove = function (target, coordinates) {
             Control.prototype._onPointerMove = function (target, coordinates) {
@@ -1669,26 +1693,36 @@ var BABYLON;
                 if (canNotify && this.parent != null)
                 if (canNotify && this.parent != null)
                     this.parent._onPointerOut(target);
                     this.parent._onPointerOut(target);
             };
             };
-            Control.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
+            Control.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
                 if (this._downCount !== 0) {
                 if (this._downCount !== 0) {
                     return false;
                     return false;
                 }
                 }
                 this._downCount++;
                 this._downCount++;
+                this._downPointerIds[pointerId] = true;
                 var canNotify = this.onPointerDownObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
                 var canNotify = this.onPointerDownObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
                 if (canNotify && this.parent != null)
                 if (canNotify && this.parent != null)
-                    this.parent._onPointerDown(target, coordinates, buttonIndex);
+                    this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex);
                 return true;
                 return true;
             };
             };
-            Control.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
+            Control.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
                 this._downCount = 0;
                 this._downCount = 0;
+                delete this._downPointerIds[pointerId];
                 var canNotify = this.onPointerUpObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
                 var canNotify = this.onPointerUpObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
                 if (canNotify && this.parent != null)
                 if (canNotify && this.parent != null)
-                    this.parent._onPointerUp(target, coordinates, buttonIndex);
+                    this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex);
             };
             };
-            Control.prototype.forcePointerUp = function () {
-                this._onPointerUp(this, BABYLON.Vector2.Zero(), 0);
+            Control.prototype.forcePointerUp = function (pointerId) {
+                if (pointerId === void 0) { pointerId = null; }
+                if (pointerId !== null) {
+                    this._onPointerUp(this, BABYLON.Vector2.Zero(), pointerId, 0);
+                }
+                else {
+                    for (var key in this._downPointerIds) {
+                        this._onPointerUp(this, BABYLON.Vector2.Zero(), +key, 0);
+                    }
+                }
             };
             };
-            Control.prototype._processObservables = function (type, x, y, buttonIndex) {
+            Control.prototype._processObservables = function (type, x, y, pointerId, buttonIndex) {
                 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);
@@ -1703,14 +1737,14 @@ var BABYLON;
                     return true;
                     return true;
                 }
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
                 if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                    this._onPointerDown(this, this._dummyVector2, buttonIndex);
+                    this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex);
                     this._host._lastControlDown = this;
                     this._host._lastControlDown = 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) {
                     if (this._host._lastControlDown) {
-                        this._host._lastControlDown._onPointerUp(this, this._dummyVector2, buttonIndex);
+                        this._host._lastControlDown._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
                     }
                     }
                     this._host._lastControlDown = null;
                     this._host._lastControlDown = null;
                     return true;
                     return true;
@@ -1721,7 +1755,7 @@ var BABYLON;
                 if (!this._font && !this._fontSet) {
                 if (!this._font && !this._fontSet) {
                     return;
                     return;
                 }
                 }
-                this._font = this._fontStyle + " " + this._fontSize.getValue(this._host) + "px " + this._fontFamily;
+                this._font = this._fontStyle + " " + this.fontSizeInPixels + "px " + this._fontFamily;
                 this._fontOffset = Control._GetFontOffset(this._font);
                 this._fontOffset = Control._GetFontOffset(this._font);
             };
             };
             Control.prototype.dispose = function () {
             Control.prototype.dispose = function () {
@@ -2009,6 +2043,7 @@ var BABYLON;
                     for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
                     for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
                         var child = _a[_i];
                         var child = _a[_i];
                         if (child.isVisible && !child.notRenderable) {
                         if (child.isVisible && !child.notRenderable) {
+                            child._tempParentMeasure.copyFrom(this._measureForChildren);
                             child._draw(this._measureForChildren, context);
                             child._draw(this._measureForChildren, context);
                             if (child.onAfterDrawObservable.hasObservers()) {
                             if (child.onAfterDrawObservable.hasObservers()) {
                                 child.onAfterDrawObservable.notifyObservers(child);
                                 child.onAfterDrawObservable.notifyObservers(child);
@@ -2021,7 +2056,7 @@ var BABYLON;
                     this.onAfterDrawObservable.notifyObservers(this);
                     this.onAfterDrawObservable.notifyObservers(this);
                 }
                 }
             };
             };
-            Container.prototype._processPicking = function (x, y, type, buttonIndex) {
+            Container.prototype._processPicking = function (x, y, type, pointerId, buttonIndex) {
                 if (!this.isVisible || this.notRenderable) {
                 if (!this.isVisible || this.notRenderable) {
                     return false;
                     return false;
                 }
                 }
@@ -2031,14 +2066,14 @@ var BABYLON;
                 // Checking backwards to pick closest first
                 // Checking backwards to pick closest first
                 for (var index = this._children.length - 1; index >= 0; index--) {
                 for (var index = this._children.length - 1; index >= 0; index--) {
                     var child = this._children[index];
                     var child = this._children[index];
-                    if (child._processPicking(x, y, type, buttonIndex)) {
+                    if (child._processPicking(x, y, type, pointerId, buttonIndex)) {
                         return true;
                         return true;
                     }
                     }
                 }
                 }
                 if (!this.isHitTestVisible) {
                 if (!this.isHitTestVisible) {
                     return false;
                     return false;
                 }
                 }
-                return this._processObservables(type, x, y, buttonIndex);
+                return this._processObservables(type, x, y, pointerId, buttonIndex);
             };
             };
             Container.prototype._clipForChildren = function (context) {
             Container.prototype._clipForChildren = function (context) {
                 // DO nothing
                 // DO nothing
@@ -2600,11 +2635,48 @@ var BABYLON;
                 this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
                 this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
                 this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
                 this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
             };
             };
-            Line.prototype._moveToProjectedPosition = function (projectedPosition) {
-                this.x1 = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
-                this.y1 = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
-                this._x1.ignoreAdaptiveScaling = true;
-                this._y1.ignoreAdaptiveScaling = true;
+            /**
+             * Move one end of the line given 3D cartesian coordinates.
+             * @param position Targeted world position
+             * @param scene Scene
+             * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+             */
+            Line.prototype.moveToVector3 = function (position, scene, end) {
+                if (end === void 0) { end = false; }
+                if (!this._host || this._root !== this._host._rootContainer) {
+                    BABYLON.Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
+                    return;
+                }
+                var globalViewport = this._host._getGlobalViewport(scene);
+                var projectedPosition = BABYLON.Vector3.Project(position, BABYLON.Matrix.Identity(), scene.getTransformMatrix(), globalViewport);
+                this._moveToProjectedPosition(projectedPosition, end);
+                if (projectedPosition.z < 0 || projectedPosition.z > 1) {
+                    this.notRenderable = true;
+                    return;
+                }
+                this.notRenderable = false;
+            };
+            /**
+             * Move one end of the line to a position in screen absolute space.
+             * @param projectedPosition Position in screen absolute space (X, Y)
+             * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+             */
+            Line.prototype._moveToProjectedPosition = function (projectedPosition, end) {
+                if (end === void 0) { end = false; }
+                var x = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
+                var y = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
+                if (end) {
+                    this.x2 = x;
+                    this.y2 = y;
+                    this._x2.ignoreAdaptiveScaling = true;
+                    this._y2.ignoreAdaptiveScaling = true;
+                }
+                else {
+                    this.x1 = x;
+                    this.y1 = y;
+                    this._x1.ignoreAdaptiveScaling = true;
+                    this._y1.ignoreAdaptiveScaling = true;
+                }
             };
             };
             return Line;
             return Line;
         }(GUI.Control));
         }(GUI.Control));
@@ -2874,13 +2946,13 @@ var BABYLON;
                 }
                 }
                 this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
                 this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
             };
             };
-            Slider.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
+            Slider.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, pointerId, buttonIndex)) {
                     return false;
                     return false;
                 }
                 }
                 this._pointerIsDown = true;
                 this._pointerIsDown = true;
                 this._updateValueFromPointer(coordinates.x, coordinates.y);
                 this._updateValueFromPointer(coordinates.x, coordinates.y);
-                this._host._capturingControl = this;
+                this._host._capturingControl[pointerId] = this;
                 return true;
                 return true;
             };
             };
             Slider.prototype._onPointerMove = function (target, coordinates) {
             Slider.prototype._onPointerMove = function (target, coordinates) {
@@ -2889,10 +2961,10 @@ var BABYLON;
                 }
                 }
                 _super.prototype._onPointerMove.call(this, target, coordinates);
                 _super.prototype._onPointerMove.call(this, target, coordinates);
             };
             };
-            Slider.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
+            Slider.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
                 this._pointerIsDown = false;
                 this._pointerIsDown = false;
-                this._host._capturingControl = null;
-                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
+                delete this._host._capturingControl[pointerId];
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
             };
             };
             return Slider;
             return Slider;
         }(GUI.Control));
         }(GUI.Control));
@@ -3014,8 +3086,8 @@ var BABYLON;
                 context.restore();
                 context.restore();
             };
             };
             // Events
             // Events
-            Checkbox.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
+            Checkbox.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, pointerId, buttonIndex)) {
                     return false;
                     return false;
                 }
                 }
                 this.isChecked = !this.isChecked;
                 this.isChecked = !this.isChecked;
@@ -3162,8 +3234,8 @@ var BABYLON;
                 context.restore();
                 context.restore();
             };
             };
             // Events
             // Events
-            RadioButton.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
+            RadioButton.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, pointerId, buttonIndex)) {
                     return false;
                     return false;
                 }
                 }
                 this.isChecked = !this.isChecked;
                 this.isChecked = !this.isChecked;
@@ -3204,6 +3276,8 @@ var BABYLON;
                 _this._textVerticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER;
                 _this._textVerticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER;
                 _this._resizeToFit = false;
                 _this._resizeToFit = false;
                 _this._lineSpacing = new GUI.ValueAndUnit(0);
                 _this._lineSpacing = new GUI.ValueAndUnit(0);
+                _this._outlineWidth = 0;
+                _this._outlineColor = "white";
                 /**
                 /**
                 * An event triggered after the text is changed
                 * An event triggered after the text is changed
                 * @type {BABYLON.Observable}
                 * @type {BABYLON.Observable}
@@ -3346,6 +3420,46 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
+            Object.defineProperty(TextBlock.prototype, "outlineWidth", {
+                /**
+                 * Gets or sets outlineWidth of the text to display
+                 */
+                get: function () {
+                    return this._outlineWidth;
+                },
+                /**
+                 * Gets or sets outlineWidth of the text to display
+                 */
+                set: function (value) {
+                    if (this._outlineWidth === value) {
+                        return;
+                    }
+                    this._outlineWidth = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(TextBlock.prototype, "outlineColor", {
+                /**
+                 * Gets or sets outlineColor of the text to display
+                 */
+                get: function () {
+                    return this._outlineColor;
+                },
+                /**
+                 * Gets or sets outlineColor of the text to display
+                 */
+                set: function (value) {
+                    if (this._outlineColor === value) {
+                        return;
+                    }
+                    this._outlineColor = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             TextBlock.prototype._getTypeName = function () {
             TextBlock.prototype._getTypeName = function () {
                 return "TextBlock";
                 return "TextBlock";
             };
             };
@@ -3369,6 +3483,9 @@ var BABYLON;
                     context.shadowOffsetX = this.shadowOffsetX;
                     context.shadowOffsetX = this.shadowOffsetX;
                     context.shadowOffsetY = this.shadowOffsetY;
                     context.shadowOffsetY = this.shadowOffsetY;
                 }
                 }
+                if (this.outlineWidth) {
+                    context.strokeText(text, this._currentMeasure.left + x, y);
+                }
                 context.fillText(text, this._currentMeasure.left + x, y);
                 context.fillText(text, this._currentMeasure.left + x, y);
             };
             };
             /** @ignore */
             /** @ignore */
@@ -3381,6 +3498,13 @@ var BABYLON;
                 }
                 }
                 context.restore();
                 context.restore();
             };
             };
+            TextBlock.prototype._applyStates = function (context) {
+                _super.prototype._applyStates.call(this, context);
+                if (this.outlineWidth) {
+                    context.lineWidth = this.outlineWidth;
+                    context.strokeStyle = this.outlineColor;
+                }
+            };
             TextBlock.prototype._additionalProcessing = function (parentMeasure, context) {
             TextBlock.prototype._additionalProcessing = function (parentMeasure, context) {
                 this._lines = [];
                 this._lines = [];
                 var _lines = this.text.split("\n");
                 var _lines = this.text.split("\n");
@@ -3818,14 +3942,14 @@ var BABYLON;
                 return "Button";
                 return "Button";
             };
             };
             // While being a container, the button behaves like a control.
             // While being a container, the button behaves like a control.
-            Button.prototype._processPicking = function (x, y, type, buttonIndex) {
+            Button.prototype._processPicking = function (x, y, type, pointerId, buttonIndex) {
                 if (!this.isHitTestVisible || !this.isVisible || this.notRenderable) {
                 if (!this.isHitTestVisible || !this.isVisible || this.notRenderable) {
                     return false;
                     return false;
                 }
                 }
                 if (!_super.prototype.contains.call(this, x, y)) {
                 if (!_super.prototype.contains.call(this, x, y)) {
                     return false;
                     return false;
                 }
                 }
-                this._processObservables(type, x, y, buttonIndex);
+                this._processObservables(type, x, y, pointerId, buttonIndex);
                 return true;
                 return true;
             };
             };
             Button.prototype._onPointerEnter = function (target) {
             Button.prototype._onPointerEnter = function (target) {
@@ -3843,8 +3967,8 @@ var BABYLON;
                 }
                 }
                 _super.prototype._onPointerOut.call(this, target);
                 _super.prototype._onPointerOut.call(this, target);
             };
             };
-            Button.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
+            Button.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, pointerId, buttonIndex)) {
                     return false;
                     return false;
                 }
                 }
                 if (this.pointerDownAnimation) {
                 if (this.pointerDownAnimation) {
@@ -3852,11 +3976,11 @@ var BABYLON;
                 }
                 }
                 return true;
                 return true;
             };
             };
-            Button.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
+            Button.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
                 if (this.pointerUpAnimation) {
                 if (this.pointerUpAnimation) {
                     this.pointerUpAnimation();
                     this.pointerUpAnimation();
                 }
                 }
-                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
             };
             };
             // Statics
             // Statics
             Button.CreateImageButton = function (name, text, imageUrl) {
             Button.CreateImageButton = function (name, text, imageUrl) {
@@ -4238,8 +4362,8 @@ var BABYLON;
                 }
                 }
                 return false;
                 return false;
             };
             };
-            ColorPicker.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
+            ColorPicker.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, pointerId, buttonIndex)) {
                     return false;
                     return false;
                 }
                 }
                 this._pointerIsDown = true;
                 this._pointerIsDown = true;
@@ -4252,7 +4376,7 @@ var BABYLON;
                     this._pointerStartedOnWheel = true;
                     this._pointerStartedOnWheel = true;
                 }
                 }
                 this._updateValueFromPointer(coordinates.x, coordinates.y);
                 this._updateValueFromPointer(coordinates.x, coordinates.y);
-                this._host._capturingControl = this;
+                this._host._capturingControl[pointerId] = this;
                 return true;
                 return true;
             };
             };
             ColorPicker.prototype._onPointerMove = function (target, coordinates) {
             ColorPicker.prototype._onPointerMove = function (target, coordinates) {
@@ -4261,10 +4385,10 @@ var BABYLON;
                 }
                 }
                 _super.prototype._onPointerMove.call(this, target, coordinates);
                 _super.prototype._onPointerMove.call(this, target, coordinates);
             };
             };
-            ColorPicker.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
+            ColorPicker.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
                 this._pointerIsDown = false;
                 this._pointerIsDown = false;
-                this._host._capturingControl = null;
-                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
+                delete this._host._capturingControl[pointerId];
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
             };
             };
             return ColorPicker;
             return ColorPicker;
         }(GUI.Control));
         }(GUI.Control));
@@ -4686,8 +4810,8 @@ var BABYLON;
                 }
                 }
                 context.restore();
                 context.restore();
             };
             };
-            InputText.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
+            InputText.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, pointerId, buttonIndex)) {
                     return false;
                     return false;
                 }
                 }
                 this._clickedCoordinate = coordinates.x;
                 this._clickedCoordinate = coordinates.x;
@@ -4700,8 +4824,8 @@ var BABYLON;
                 this._host.focusedControl = this;
                 this._host.focusedControl = this;
                 return true;
                 return true;
             };
             };
-            InputText.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
-                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
+            InputText.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
             };
             };
             InputText.prototype.dispose = function () {
             InputText.prototype.dispose = function () {
                 _super.prototype.dispose.call(this);
                 _super.prototype.dispose.call(this);

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


+ 57 - 20
dist/preview release/gui/babylon.gui.module.d.ts

@@ -24,7 +24,9 @@ declare module BABYLON.GUI {
         _lastPickedControl: Control;
         _lastPickedControl: Control;
         _lastControlOver: Nullable<Control>;
         _lastControlOver: Nullable<Control>;
         _lastControlDown: Nullable<Control>;
         _lastControlDown: Nullable<Control>;
-        _capturingControl: Nullable<Control>;
+        _capturingControl: {
+            [pointerId: number]: Control;
+        };
         _shouldBlockPointer: boolean;
         _shouldBlockPointer: boolean;
         _layerToDispose: Nullable<Layer>;
         _layerToDispose: Nullable<Layer>;
         _linkedControls: Control[];
         _linkedControls: Control[];
@@ -55,7 +57,7 @@ declare module BABYLON.GUI {
         _getGlobalViewport(scene: Scene): Viewport;
         _getGlobalViewport(scene: Scene): Viewport;
         private _checkUpdate(camera);
         private _checkUpdate(camera);
         private _render();
         private _render();
-        private _doPicking(x, y, type, buttonIndex);
+        private _doPicking(x, y, type, pointerId, buttonIndex);
         attach(): void;
         attach(): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         moveFocusToControl(control: IFocusableControl): void;
         moveFocusToControl(control: IFocusableControl): void;
@@ -169,6 +171,7 @@ declare module BABYLON.GUI {
         protected _horizontalAlignment: number;
         protected _horizontalAlignment: number;
         protected _verticalAlignment: number;
         protected _verticalAlignment: number;
         private _isDirty;
         private _isDirty;
+        _tempParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         private _paddingLeft;
         private _paddingLeft;
         private _paddingRight;
         private _paddingRight;
@@ -194,6 +197,7 @@ declare module BABYLON.GUI {
         private _downCount;
         private _downCount;
         private _enterCount;
         private _enterCount;
         private _doNotRender;
         private _doNotRender;
+        private _downPointerIds;
         isHitTestVisible: boolean;
         isHitTestVisible: boolean;
         isPointerBlocker: boolean;
         isPointerBlocker: boolean;
         isFocusInvisible: boolean;
         isFocusInvisible: boolean;
@@ -253,6 +257,8 @@ declare module BABYLON.GUI {
         readonly heightInPixels: number;
         readonly heightInPixels: number;
         fontFamily: string;
         fontFamily: string;
         fontStyle: string;
         fontStyle: string;
+        /** @ignore */
+        readonly _isFontSizeInPercentage: boolean;
         readonly fontSizeInPixels: number;
         readonly fontSizeInPixels: number;
         fontSize: string | number;
         fontSize: string | number;
         color: string;
         color: string;
@@ -280,6 +286,8 @@ declare module BABYLON.GUI {
         readonly centerY: number;
         readonly centerY: number;
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
+        /** @ignore */
+        _resetFontCache(): void;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
@@ -300,14 +308,14 @@ declare module BABYLON.GUI {
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         contains(x: number, y: number): boolean;
         contains(x: number, y: number): boolean;
-        _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
+        _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerEnter(target: Control): boolean;
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerOut(target: Control): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
-        forcePointerUp(): void;
-        _processObservables(type: number, x: number, y: number, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        forcePointerUp(pointerId?: Nullable<number>): void;
+        _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number): boolean;
         private _prepareFont();
         private _prepareFont();
         dispose(): void;
         dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
@@ -358,7 +366,7 @@ declare module BABYLON.GUI {
         protected _localDraw(context: CanvasRenderingContext2D): void;
         protected _localDraw(context: CanvasRenderingContext2D): void;
         _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         _link(root: Nullable<Container>, host: AdvancedDynamicTexture): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
+        _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         dispose(): void;
         dispose(): void;
@@ -442,7 +450,19 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _moveToProjectedPosition(projectedPosition: Vector3): void;
+        /**
+         * Move one end of the line given 3D cartesian coordinates.
+         * @param position Targeted world position
+         * @param scene Scene
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        moveToVector3(position: Vector3, scene: Scene, end?: boolean): void;
+        /**
+         * Move one end of the line to a position in screen absolute space.
+         * @param projectedPosition Position in screen absolute space (X, Y)
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        _moveToProjectedPosition(projectedPosition: Vector3, end?: boolean): void;
     }
     }
 }
 }
 
 
@@ -476,9 +496,9 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
         private _pointerIsDown;
         private _updateValueFromPointer(x, y);
         private _updateValueFromPointer(x, y);
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
     }
     }
 }
 }
 
 
@@ -498,7 +518,7 @@ declare module BABYLON.GUI {
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
     }
     }
 }
 }
 
 
@@ -519,7 +539,7 @@ declare module BABYLON.GUI {
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
     }
     }
 }
 }
 
 
@@ -537,6 +557,8 @@ declare module BABYLON.GUI {
         private _lines;
         private _lines;
         private _resizeToFit;
         private _resizeToFit;
         private _lineSpacing;
         private _lineSpacing;
+        private _outlineWidth;
+        private _outlineColor;
         /**
         /**
         * An event triggered after the text is changed
         * An event triggered after the text is changed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
@@ -594,6 +616,20 @@ declare module BABYLON.GUI {
          */
          */
         lineSpacing: string | number;
         lineSpacing: string | number;
         /**
         /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        outlineWidth: number;
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        outlineColor: string;
+        /**
          * Creates a new TextBlock object
          * Creates a new TextBlock object
          * @param name defines the name of the control
          * @param name defines the name of the control
          * @param text defines the text to display (emptry string by default)
          * @param text defines the text to display (emptry string by default)
@@ -607,6 +643,7 @@ declare module BABYLON.GUI {
         private _drawText(text, textWidth, y, context);
         private _drawText(text, textWidth, y, context);
         /** @ignore */
         /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
@@ -671,11 +708,11 @@ declare module BABYLON.GUI {
         pointerUpAnimation: () => void;
         pointerUpAnimation: () => void;
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
-        _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
+        _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         _onPointerEnter(target: Control): boolean;
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerOut(target: Control): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
@@ -716,9 +753,9 @@ declare module BABYLON.GUI {
         private _updateValueFromPointer(x, y);
         private _updateValueFromPointer(x, y);
         private _isPointOnSquare(coordinates);
         private _isPointOnSquare(coordinates);
         private _isPointOnWheel(coordinates);
         private _isPointOnWheel(coordinates);
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
     }
     }
 }
 }
 
 
@@ -765,8 +802,8 @@ declare module BABYLON.GUI {
         processKey(keyCode: number, key?: string): void;
         processKey(keyCode: number, key?: string): void;
         processKeyboard(evt: KeyboardEvent): void;
         processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
         dispose(): void;
         dispose(): void;
     }
     }
 }
 }

+ 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-alpha6",
+    "version": "3.2.0-alpha7",
     "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


+ 5 - 2
dist/preview release/inspector/babylon.inspector.css

@@ -283,6 +283,8 @@
           background-color: #242424; }
           background-color: #242424; }
         .insp-wrapper .insp-tree .line .line-content .line:hover:first-child {
         .insp-wrapper .insp-tree .line .line-content .line:hover:first-child {
           background-color: #383838; }
           background-color: #383838; }
+    .insp-wrapper .insp-tree .line_invisible {
+      display: none; }
   .insp-wrapper .insp-details {
   .insp-wrapper .insp-details {
     background-color: #242424;
     background-color: #242424;
     overflow-y: auto;
     overflow-y: auto;
@@ -303,7 +305,7 @@
         width: 35%; }
         width: 35%; }
       .insp-wrapper .insp-details .base-row .prop-value, .insp-wrapper .insp-details .row .prop-value, .insp-wrapper .insp-details .header-row .prop-value {
       .insp-wrapper .insp-details .base-row .prop-value, .insp-wrapper .insp-details .row .prop-value, .insp-wrapper .insp-details .header-row .prop-value {
         width: 59%;
         width: 59%;
-        padding-left: 10px; }
+        padding-left: 5px; }
         .insp-wrapper .insp-details .base-row .prop-value.clickable, .insp-wrapper .insp-details .row .prop-value.clickable, .insp-wrapper .insp-details .header-row .prop-value.clickable {
         .insp-wrapper .insp-details .base-row .prop-value.clickable, .insp-wrapper .insp-details .row .prop-value.clickable, .insp-wrapper .insp-details .header-row .prop-value.clickable {
           cursor: pointer; }
           cursor: pointer; }
           .insp-wrapper .insp-details .base-row .prop-value.clickable:hover, .insp-wrapper .insp-details .row .prop-value.clickable:hover, .insp-wrapper .insp-details .header-row .prop-value.clickable:hover {
           .insp-wrapper .insp-details .base-row .prop-value.clickable:hover, .insp-wrapper .insp-details .row .prop-value.clickable:hover, .insp-wrapper .insp-details .header-row .prop-value.clickable:hover {
@@ -340,7 +342,8 @@
       display: inline-block;
       display: inline-block;
       margin-left: 5px; }
       margin-left: 5px; }
     .insp-wrapper .insp-details .color-element {
     .insp-wrapper .insp-details .color-element {
-      top: 2px; }
+      width: 20px;
+      height: 15px; }
     .insp-wrapper .insp-details .texture-element {
     .insp-wrapper .insp-details .texture-element {
       color: #f29766;
       color: #f29766;
       margin-left: 10px; }
       margin-left: 10px; }

+ 13 - 2
dist/preview release/inspector/babylon.inspector.js

@@ -383,7 +383,7 @@ var INSPECTOR;
         },
         },
         'Color3': {
         'Color3': {
             type: BABYLON.Color3,
             type: BABYLON.Color3,
-            format: function (color) { return "R:" + color.r + ", G:" + color.g + ", B:" + color.b; },
+            format: function (color) { return "R:" + color.r.toPrecision(2) + ", G:" + color.g.toPrecision(2) + ", B:" + color.b.toPrecision(2); },
             slider: {
             slider: {
                 r: { min: 0, max: 1, step: 0.01 },
                 r: { min: 0, max: 1, step: 0.01 },
                 g: { min: 0, max: 1, step: 0.01 },
                 g: { min: 0, max: 1, step: 0.01 },
@@ -4568,7 +4568,18 @@ var INSPECTOR;
         };
         };
         /** Build the HTML of this item */
         /** Build the HTML of this item */
         TreeItem.prototype._build = function () {
         TreeItem.prototype._build = function () {
-            this._div.className = 'line';
+            /**
+             *  Hide the debug objects :
+             * - Axis : xline, yline, zline
+             * */
+            var adapterId = this._adapter.id();
+            if (adapterId == "xline"
+                || adapterId == "yline"
+                || adapterId == "zline") {
+                this._div.className = "line_invisible";
+            }
+            else
+                this._div.className = 'line';
             // special class for transform node ONLY
             // special class for transform node ONLY
             if (this.adapter instanceof INSPECTOR.MeshAdapter) {
             if (this.adapter instanceof INSPECTOR.MeshAdapter) {
                 var obj = this.adapter.object;
                 var obj = this.adapter.object;

File diff suppressed because it is too large
+ 4 - 4
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-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 57 - 23
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -28,19 +28,40 @@ declare module BABYLON {
         json: Object;
         json: Object;
         bin: Nullable<ArrayBufferView>;
         bin: Nullable<ArrayBufferView>;
     }
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         compileMaterials: boolean;
         useClipPlane: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -78,19 +99,19 @@ declare module BABYLON {
         /**
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         onMaterialLoaded: (Material: Material) => void;
         /**
         /**
@@ -98,15 +119,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         private _onCompleteObserver;
         onComplete: () => void;
         onComplete: () => void;
         /**
         /**
         * Raised when the loader is disposed.
         * Raised when the loader is disposed.
         */
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         private _onDisposeObserver;
         onDispose: () => void;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         private _loader;
         name: string;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
@@ -114,9 +146,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
          */
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -534,9 +570,17 @@ declare module BABYLON.GLTF1 {
         onTextureLoadedObservable: Observable<BaseTexture>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void;
+        private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        private _loadAsync(scene, data, rootUrl, onSuccess, onProgress, onError);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
         private _createNodes(gltfRuntime);
@@ -567,16 +611,6 @@ declare module BABYLON.GLTF1 {
          */
          */
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         /**
         /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        /**
         * Returns the wrap mode of the texture
         * Returns the wrap mode of the texture
         * @param mode: the mode value
         * @param mode: the mode value
         */
         */

+ 107 - 81
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -27,6 +27,12 @@ var BABYLON;
          */
          */
         GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
         GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
     })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
     })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
+    var GLTFLoaderState;
+    (function (GLTFLoaderState) {
+        GLTFLoaderState[GLTFLoaderState["Loading"] = 0] = "Loading";
+        GLTFLoaderState[GLTFLoaderState["Ready"] = 1] = "Ready";
+        GLTFLoaderState[GLTFLoaderState["Complete"] = 2] = "Complete";
+    })(GLTFLoaderState = BABYLON.GLTFLoaderState || (BABYLON.GLTFLoaderState = {}));
     var GLTFFileLoader = /** @class */ (function () {
     var GLTFFileLoader = /** @class */ (function () {
         function GLTFFileLoader() {
         function GLTFFileLoader() {
             // #region Common options
             // #region Common options
@@ -80,6 +86,11 @@ var BABYLON;
             * Raised when the loader is disposed.
             * Raised when the loader is disposed.
             */
             */
             this.onDisposeObservable = new BABYLON.Observable();
             this.onDisposeObservable = new BABYLON.Observable();
+            /**
+             * Raised after a loader extension is created.
+             * Set additional options for a loader extension in this event.
+             */
+            this.onExtensionLoadedObservable = new BABYLON.Observable();
             // #endregion
             // #endregion
             this._loader = null;
             this._loader = null;
             this.name = "gltf";
             this.name = "gltf";
@@ -148,6 +159,26 @@ var BABYLON;
             enumerable: true,
             enumerable: true,
             configurable: true
             configurable: true
         });
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onExtensionLoaded", {
+            set: function (callback) {
+                if (this._onExtensionLoadedObserver) {
+                    this.onExtensionLoadedObservable.remove(this._onExtensionLoadedObserver);
+                }
+                this._onExtensionLoadedObserver = this.onExtensionLoadedObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
+            /**
+             * The loader state or null if not active.
+             */
+            get: function () {
+                return this._loader ? this._loader.state : null;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
         /**
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
          */
@@ -156,65 +187,42 @@ var BABYLON;
                 this._loader.dispose();
                 this._loader.dispose();
                 this._loader = null;
                 this._loader = null;
             }
             }
-            this.onParsedObservable.clear();
             this.onMeshLoadedObservable.clear();
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
             this.onMaterialLoadedObservable.clear();
             this.onMaterialLoadedObservable.clear();
-            this.onCompleteObservable.clear();
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.clear();
             this.onDisposeObservable.clear();
         };
         };
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
-            try {
-                var loaderData = this._parse(data);
-                this._loader = this._getLoader(loaderData);
-                this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    BABYLON.Tools.Error(e.message);
-                }
-            }
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+            var _this = this;
+            return Promise.resolve().then(function () {
+                var loaderData = _this._parse(data);
+                _this._loader = _this._getLoader(loaderData);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress);
+            });
         };
         };
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
-            try {
-                var loaderData = this._parse(data);
-                this._loader = this._getLoader(loaderData);
-                this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    BABYLON.Tools.Error(e.message);
-                }
-            }
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+            var _this = this;
+            return Promise.resolve().then(function () {
+                var loaderData = _this._parse(data);
+                _this._loader = _this._getLoader(loaderData);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress);
+            });
         };
         };
-        GLTFFileLoader.prototype.loadAssetsAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
-            try {
-                var loaderData = this._parse(data);
-                this._loader = this._getLoader(loaderData);
-                this._loader.importMeshAsync(null, scene, loaderData, rootUrl, function (meshes, particleSystems, skeletons) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+            var _this = this;
+            return Promise.resolve().then(function () {
+                var loaderData = _this._parse(data);
+                _this._loader = _this._getLoader(loaderData);
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     var container = new BABYLON.AssetContainer(scene);
-                    Array.prototype.push.apply(container.meshes, meshes);
-                    Array.prototype.push.apply(container.particleSystems, particleSystems);
-                    Array.prototype.push.apply(container.skeletons, skeletons);
+                    Array.prototype.push.apply(container.meshes, result.meshes);
+                    Array.prototype.push.apply(container.particleSystems, result.particleSystems);
+                    Array.prototype.push.apply(container.skeletons, result.skeletons);
                     container.removeAllFromScene();
                     container.removeAllFromScene();
-                    onSuccess(container);
-                }, onProgress, onError);
-            }
-            catch (e) {
-                if (onError) {
-                    onError(e.message, e);
-                }
-                else {
-                    BABYLON.Tools.Error(e.message);
-                }
-            }
+                    return container;
+                });
+            });
         };
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
@@ -234,6 +242,7 @@ var BABYLON;
                 };
                 };
             }
             }
             this.onParsedObservable.notifyObservers(parsedData);
             this.onParsedObservable.notifyObservers(parsedData);
+            this.onParsedObservable.clear();
             return parsedData;
             return parsedData;
         };
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
@@ -270,7 +279,14 @@ var BABYLON;
             loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
             loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
-            loader.onCompleteObservable.add(function () { return _this.onCompleteObservable.notifyObservers(_this); });
+            loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
+            loader.onCompleteObservable.add(function () {
+                _this.onMeshLoadedObservable.clear();
+                _this.onTextureLoadedObservable.clear();
+                _this.onMaterialLoadedObservable.clear();
+                _this.onCompleteObservable.notifyObservers(_this);
+                _this.onCompleteObservable.clear();
+            });
             return loader;
             return loader;
         };
         };
         GLTFFileLoader._parseBinary = function (data) {
         GLTFFileLoader._parseBinary = function (data) {
@@ -1009,8 +1025,7 @@ var BABYLON;
                 return newMesh;
                 return newMesh;
             }
             }
             var subMaterials = [];
             var subMaterials = [];
-            var vertexData = new BABYLON.VertexData();
-            var geometry = new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
+            var vertexData = null;
             var verticesStarts = new Array();
             var verticesStarts = new Array();
             var verticesCounts = new Array();
             var verticesCounts = new Array();
             var indexStarts = new Array();
             var indexStarts = new Array();
@@ -1094,7 +1109,12 @@ var BABYLON;
                         tempVertexData.indices = new Int32Array(indices);
                         tempVertexData.indices = new Int32Array(indices);
                         indexCounts.push(tempVertexData.indices.length);
                         indexCounts.push(tempVertexData.indices.length);
                     }
                     }
-                    vertexData.merge(tempVertexData);
+                    if (!vertexData) {
+                        vertexData = tempVertexData;
+                    }
+                    else {
+                        vertexData.merge(tempVertexData);
+                    }
                     // Sub material
                     // Sub material
                     var material_1 = gltfRuntime.scene.getMaterialByID(primitive.material);
                     var material_1 = gltfRuntime.scene.getMaterialByID(primitive.material);
                     subMaterials.push(material_1 === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material_1);
                     subMaterials.push(material_1 === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material_1);
@@ -1118,7 +1138,7 @@ var BABYLON;
                 newMesh.material = material;
                 newMesh.material = material;
             }
             }
             // Apply geometry
             // Apply geometry
-            geometry.setAllVerticesData(vertexData, false);
+            new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
             newMesh.computeWorldMatrix(true);
             newMesh.computeWorldMatrix(true);
             // Apply submeshes
             // Apply submeshes
             newMesh.subMeshes = [];
             newMesh.subMeshes = [];
@@ -1593,8 +1613,8 @@ var BABYLON;
             };
             };
             GLTFLoaderBase.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
             GLTFLoaderBase.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
                 var buffer = gltfRuntime.buffers[id];
                 var buffer = gltfRuntime.buffers[id];
-                if (GLTF1.GLTFUtils.IsBase64(buffer.uri)) {
-                    setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(buffer.uri))); });
+                if (BABYLON.Tools.IsBase64(buffer.uri)) {
+                    setTimeout(function () { return onSuccess(new Uint8Array(BABYLON.Tools.DecodeBase64(buffer.uri))); });
                 }
                 }
                 else {
                 else {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, undefined, true, function (request) {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, undefined, true, function (request) {
@@ -1615,8 +1635,8 @@ var BABYLON;
                     return;
                     return;
                 }
                 }
                 var source = gltfRuntime.images[texture.source];
                 var source = gltfRuntime.images[texture.source];
-                if (GLTF1.GLTFUtils.IsBase64(source.uri)) {
-                    setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(source.uri))); });
+                if (BABYLON.Tools.IsBase64(source.uri)) {
+                    setTimeout(function () { return onSuccess(new Uint8Array(BABYLON.Tools.DecodeBase64(source.uri))); });
                 }
                 }
                 else {
                 else {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, undefined, undefined, true, function (request) {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, undefined, undefined, true, function (request) {
@@ -1654,7 +1674,7 @@ var BABYLON;
             };
             };
             GLTFLoaderBase.LoadShaderStringAsync = function (gltfRuntime, id, onSuccess, onError) {
             GLTFLoaderBase.LoadShaderStringAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var shader = gltfRuntime.shaders[id];
                 var shader = gltfRuntime.shaders[id];
-                if (GLTF1.GLTFUtils.IsBase64(shader.uri)) {
+                if (BABYLON.Tools.IsBase64(shader.uri)) {
                     var shaderString = atob(shader.uri.split(",")[1]);
                     var shaderString = atob(shader.uri.split(",")[1]);
                     onSuccess(shaderString);
                     onSuccess(shaderString);
                 }
                 }
@@ -1818,6 +1838,8 @@ var BABYLON;
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
+                this.onExtensionLoadedObservable = new BABYLON.Observable();
+                this.state = null;
             }
             }
             GLTFLoader.RegisterExtension = function (extension) {
             GLTFLoader.RegisterExtension = function (extension) {
                 if (GLTFLoader.Extensions[extension.name]) {
                 if (GLTFLoader.Extensions[extension.name]) {
@@ -1828,7 +1850,7 @@ var BABYLON;
             };
             };
             GLTFLoader.prototype.dispose = function () { };
             GLTFLoader.prototype.dispose = function () { };
             // #endregion
             // #endregion
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            GLTFLoader.prototype._importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1879,7 +1901,21 @@ var BABYLON;
                 }, onError);
                 }, onError);
                 return true;
                 return true;
             };
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+                var _this = this;
+                return new Promise(function (resolve, reject) {
+                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, particleSystems, skeletons) {
+                        resolve({
+                            meshes: meshes,
+                            particleSystems: particleSystems,
+                            skeletons: skeletons
+                        });
+                    }, onProgress, function (message) {
+                        reject(new Error(message));
+                    });
+                });
+            };
+            GLTFLoader.prototype._loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1903,6 +1939,16 @@ var BABYLON;
                     }, onError);
                     }, onError);
                 }, onError);
                 }, onError);
             };
             };
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+                var _this = this;
+                return new Promise(function (resolve, reject) {
+                    _this._loadAsync(scene, data, rootUrl, function () {
+                        resolve();
+                    }, onProgress, function (message) {
+                        reject(new Error(message));
+                    });
+                });
+            };
             GLTFLoader.prototype._loadShadersAsync = function (gltfRuntime, onload) {
             GLTFLoader.prototype._loadShadersAsync = function (gltfRuntime, onload) {
                 var hasShaders = false;
                 var hasShaders = false;
                 var processShader = function (sha, shader) {
                 var processShader = function (sha, shader) {
@@ -2094,26 +2140,6 @@ var BABYLON;
                 }
                 }
             };
             };
             /**
             /**
-            * If the uri is a base64 string
-            * @param uri: the uri to test
-            */
-            GLTFUtils.IsBase64 = function (uri) {
-                return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
-            };
-            /**
-            * Decode the base64 uri
-            * @param uri: the uri to decode
-            */
-            GLTFUtils.DecodeBase64 = function (uri) {
-                var decodedString = atob(uri.split(",")[1]);
-                var bufferLength = decodedString.length;
-                var bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
-                for (var i = 0; i < bufferLength; i++) {
-                    bufferView[i] = decodedString.charCodeAt(i);
-                }
-                return bufferView.buffer;
-            };
-            /**
             * Returns the wrap mode of the texture
             * Returns the wrap mode of the texture
             * @param mode: the mode value
             * @param mode: the mode value
             */
             */

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


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

@@ -28,19 +28,40 @@ declare module BABYLON {
         json: Object;
         json: Object;
         bin: Nullable<ArrayBufferView>;
         bin: Nullable<ArrayBufferView>;
     }
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         compileMaterials: boolean;
         useClipPlane: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -78,19 +99,19 @@ declare module BABYLON {
         /**
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         onMaterialLoaded: (Material: Material) => void;
         /**
         /**
@@ -98,15 +119,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         private _onCompleteObserver;
         onComplete: () => void;
         onComplete: () => void;
         /**
         /**
         * Raised when the loader is disposed.
         * Raised when the loader is disposed.
         */
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         private _onDisposeObserver;
         onDispose: () => void;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         private _loader;
         name: string;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
@@ -114,9 +146,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
          */
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -133,440 +169,271 @@ declare module BABYLON {
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    /**
-    * Enums
-    */
-    enum EComponentType {
-        BYTE = 5120,
-        UNSIGNED_BYTE = 5121,
-        SHORT = 5122,
-        UNSIGNED_SHORT = 5123,
-        UNSIGNED_INT = 5125,
-        FLOAT = 5126,
-    }
-    enum EMeshPrimitiveMode {
-        POINTS = 0,
-        LINES = 1,
-        LINE_LOOP = 2,
-        LINE_STRIP = 3,
-        TRIANGLES = 4,
-        TRIANGLE_STRIP = 5,
-        TRIANGLE_FAN = 6,
-    }
-    enum ETextureMagFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-    }
-    enum ETextureMinFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-        NEAREST_MIPMAP_NEAREST = 9984,
-        LINEAR_MIPMAP_NEAREST = 9985,
-        NEAREST_MIPMAP_LINEAR = 9986,
-        LINEAR_MIPMAP_LINEAR = 9987,
-    }
-    enum ETextureWrapMode {
-        CLAMP_TO_EDGE = 33071,
-        MIRRORED_REPEAT = 33648,
-        REPEAT = 10497,
-    }
-    /**
-    * Interfaces
-    */
-    interface IGLTFProperty {
-        extensions?: {
-            [key: string]: any;
-        };
-        extras?: any;
-    }
-    interface IGLTFChildRootProperty extends IGLTFProperty {
-        name?: string;
-    }
-    interface IGLTFAccessorSparseIndices extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-    }
-    interface IGLTFAccessorSparseValues extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-    }
-    interface IGLTFAccessorSparse extends IGLTFProperty {
-        count: number;
-        indices: IGLTFAccessorSparseIndices;
-        values: IGLTFAccessorSparseValues;
-    }
-    interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView?: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-        normalized?: boolean;
-        count: number;
-        type: string;
-        max: number[];
-        min: number[];
-        sparse?: IGLTFAccessorSparse;
-        index: number;
-    }
-    interface IGLTFAnimationChannel extends IGLTFProperty {
-        sampler: number;
-        target: IGLTFAnimationChannelTarget;
-    }
-    interface IGLTFAnimationChannelTarget extends IGLTFProperty {
-        node: number;
-        path: string;
-    }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
-    }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        babylonAnimationGroup: AnimationGroup;
-    }
-    interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
-    }
-    interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
-    }
-    interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-        index: number;
-    }
-    interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
-    }
-    interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
-    }
-    interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
-    }
-    interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-        index: number;
-    }
-    interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
-    }
-    interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
-    }
-    interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
-    }
-    interface IGLTFMaterial extends IGLTFChildRootProperty {
-        pbrMetallicRoughness?: IGLTFMaterialPbrMetallicRoughness;
-        normalTexture?: IGLTFMaterialNormalTextureInfo;
-        occlusionTexture?: IGLTFMaterialOcclusionTextureInfo;
-        emissiveTexture?: IGLTFTextureInfo;
-        emissiveFactor?: number[];
-        alphaMode?: string;
-        alphaCutoff: number;
-        doubleSided?: boolean;
-        index: number;
-        babylonMaterial: Material;
-    }
-    interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: {
-            [name: string]: number;
-        };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: {
-            [name: string]: number;
-        }[];
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
-    }
-    interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-        index: number;
-        hasVertexAlpha: boolean;
-    }
-    interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: number;
-        children?: number[];
-        skin?: number;
-        matrix?: number[];
-        mesh?: number;
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-        weights?: number[];
-        index: number;
-        parent: IGLTFNode;
-        babylonMesh: Mesh;
-        babylonAnimationTargets?: Node[];
-    }
-    interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: ETextureMagFilter;
-        minFilter?: ETextureMinFilter;
-        wrapS?: ETextureWrapMode;
-        wrapT?: ETextureWrapMode;
-        index: number;
+    interface TypedArray extends ArrayBufferView {
+        [index: number]: number;
+    }
+    interface IArrayItem {
+        _index: number;
+    }
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
+    }
+}
+
+
+
+declare module BABYLON.GLTF2 {
+    interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
+    }
+    interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
+    }
+    interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
+    }
+    interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
+    }
+    interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
+    }
+    interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
+    }
+    interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
+    }
+    interface ILoaderCamera extends ICamera, IArrayItem {
+    }
+    interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
+    }
+    interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
+    }
+    interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
+    }
+    interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
+    }
+    interface ILoaderSamplerData {
         noMipMaps: boolean;
         noMipMaps: boolean;
         samplingMode: number;
         samplingMode: number;
         wrapU: number;
         wrapU: number;
         wrapV: number;
         wrapV: number;
     }
     }
-    interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: number[];
-        index: number;
-    }
-    interface IGLTFSkin extends IGLTFChildRootProperty {
-        inverseBindMatrices?: number;
-        skeleton?: number;
-        joints: number[];
-        index: number;
-        babylonSkeleton: Skeleton;
-    }
-    interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler?: number;
-        source: number;
-        index: number;
-        url?: string;
-        dataReadyObservable?: Observable<IGLTFTexture>;
-    }
-    interface IGLTFTextureInfo {
-        index: number;
-        texCoord?: number;
-    }
-    interface _IGLTF extends IGLTFProperty {
-        accessors?: IGLTFAccessor[];
-        animations?: IGLTFAnimation[];
-        asset: IGLTFAsset;
-        buffers?: IGLTFBuffer[];
-        bufferViews?: IGLTFBufferView[];
-        cameras?: IGLTFCamera[];
-        extensionsUsed?: string[];
-        extensionsRequired?: string[];
-        images?: IGLTFImage[];
-        materials?: IGLTFMaterial[];
-        meshes?: IGLTFMesh[];
-        nodes?: IGLTFNode[];
-        samplers?: IGLTFSampler[];
-        scene?: number;
-        scenes?: IGLTFScene[];
-        skins?: IGLTFSkin[];
-        textures?: IGLTFTexture[];
+    interface ILoaderSampler extends ISampler, IArrayItem {
+        _data?: ILoaderSamplerData;
+    }
+    interface ILoaderScene extends IScene, IArrayItem {
+    }
+    interface ILoaderSkin extends ISkin, IArrayItem {
+        _babylonSkeleton: Nullable<Skeleton>;
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderTexture extends ITexture, IArrayItem {
+    }
+    interface ILoaderGLTF extends IGLTF {
+        accessors?: ILoaderAccessor[];
+        animations?: ILoaderAnimation[];
+        buffers?: ILoaderBuffer[];
+        bufferViews?: ILoaderBufferView[];
+        cameras?: ILoaderCamera[];
+        images?: ILoaderImage[];
+        materials?: ILoaderMaterial[];
+        meshes?: ILoaderMesh[];
+        nodes?: ILoaderNode[];
+        samplers?: ILoaderSampler[];
+        scenes?: ILoaderScene[];
+        skins?: ILoaderSkin[];
+        textures?: ILoaderTexture[];
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: _IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
         private _disposed;
+        private _state;
+        private _extensions;
         private _rootUrl;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback?;
         private _progressCallback?;
         private _progressCallback?;
-        private _errorCallback?;
-        private _renderReady;
         private _requests;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         compileMaterials: boolean;
         useClipPlane: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        onMaterialLoadedObservable: Observable<Material>;
-        onCompleteObservable: Observable<IGLTFLoader>;
+        readonly onDisposeObservable: Observable<IGLTFLoader>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        readonly onCompleteObservable: Observable<IGLTFLoader>;
+        readonly state: Nullable<GLTFLoaderState>;
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
-        private _onProgress();
-        _executeWhenRenderReady(func: () => void): void;
-        private _onRenderReady();
-        private _onComplete();
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
+        private _loadExtensions();
         private _loadData(data);
         private _loadData(data);
+        private _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getMeshes();
         private _getSkeletons();
         private _getSkeletons();
         private _startAnimations();
         private _startAnimations();
-        private _loadDefaultScene(nodeNames);
-        private _loadScene(context, scene, nodeNames);
-        _loadNode(context: string, node: IGLTFNode): void;
-        private _loadMesh(context, node, mesh);
-        private _loadAllVertexDataAsync(context, mesh, onSuccess);
-        /**
-         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4TextureCoordArray(context, data, accessor);
-        /**
-         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4ColorArray(context, data, accessor);
-        private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(context, node, mesh);
-        private _loadMorphTargets(context, node, mesh);
-        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
-        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
-        private _loadTransform(node);
-        private _loadSkinAsync(context, skin, onSuccess);
+        _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
+        private _loadMeshAsync(context, node, mesh);
+        private _loadPrimitiveAsync(context, node, mesh, primitive);
+        private _loadVertexDataAsync(context, primitive, babylonMesh);
+        private _createMorphTargets(context, node, mesh, primitive, babylonMesh);
+        private _loadMorphTargetsAsync(context, primitive, babylonMesh, babylonVertexData);
+        private _loadMorphTargetVertexDataAsync(context, babylonVertexData, attributes, babylonMorphTarget);
+        private static _ConvertToFloat32Array(context, accessor, data);
+        private static _ConvertVec3ToVec4(context, data);
+        private static _LoadTransform(node, babylonNode);
+        private _loadSkinAsync(context, node, mesh, skin);
+        private _loadSkinInverseBindMatricesDataAsync(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
-        private _loadBones(context, skin, inverseBindMatrixData);
-        private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
+        private _loadBones(context, skin, inverseBindMatricesData);
+        private _loadBone(node, skin, inverseBindMatricesData, babylonBones);
         private _getNodeMatrix(node);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
-        private _loadAnimations();
-        private _loadAnimation(context, animation);
-        private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
-        private _loadBufferAsync(context, buffer, onSuccess);
-        private _loadBufferViewAsync(context, bufferView, onSuccess);
-        private _loadAccessorAsync(context, accessor, onSuccess);
+        private _loadAnimationsAsync();
+        private _loadAnimationAsync(context, animation);
+        private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
+        private _loadAnimationSamplerAsync(context, sampler);
+        private _loadBufferAsync(context, buffer);
+        _loadBufferViewAsync(context: string, bufferView: ILoaderBufferView): Promise<ArrayBufferView>;
+        private _loadAccessorAsync(context, accessor);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
-        _addPendingData(data: any): void;
-        _removePendingData(data: any): void;
-        _addLoaderPendingData(data: any): void;
-        _removeLoaderPendingData(data: any): void;
-        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
         private _getDefaultMaterial();
-        private _loadMaterialMetallicRoughnessProperties(context, material);
-        _loadMaterial(context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        _createPbrMaterial(material: IGLTFMaterial): void;
-        _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
-        _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadMaterialMetallicRoughnessPropertiesAsync(context, material);
+        _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Promise<void>;
+        _createMaterial(material: ILoaderMaterial): PBRMaterial;
+        _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial): Promise<void>;
+        _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial): void;
+        _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
         private _loadSampler(context, sampler);
-        private _loadImageAsync(context, image, onSuccess);
-        _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
-        _tryCatchOnError(handler: () => void): void;
-        private static _AssignIndices(array?);
-        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(context, mode?);
+        private _loadImageAsync(context, image);
+        _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
+        private _onProgress();
+        static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
+        private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetNumComponents(context, type);
         private static _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-        private _abortRequests();
-        private _releaseResources();
+        private static _ValidateUri(uri);
+        private _compileMaterialsAsync();
+        private _compileShadowGeneratorsAsync();
+        private _clear();
+        _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    /**
-    * Utils functions for GLTF
-    */
-    class GLTFUtils {
-        /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        static ValidateUri(uri: string): boolean;
-    }
-}
-
-
-declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         enabled: boolean;
         readonly abstract name: string;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
-        static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private static _ApplyExtensions(action);
+        protected _loader: GLTFLoader;
+        constructor(loader: GLTFLoader);
+        /** Override this method to modify the default behavior for loading scenes. */
+        protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading nodes. */
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading mesh primitive vertex data. */
+        protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
+        /** Override this method to modify the default behavior for loading materials. */
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading uris. */
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Helper method called by a loader extension to load an glTF extension. */
+        protected _loadExtensionAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (context: string, extension: TProperty) => Promise<TResult>): Nullable<Promise<TResult>>;
+        /** Helper method called by the loader to allow extensions to override loading scenes. */
+        static _LoadSceneAsync(loader: GLTFLoader, context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading nodes. */
+        static _LoadNodeAsync(loader: GLTFLoader, context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading mesh primitive vertex data. */
+        static _LoadVertexDataAsync(loader: GLTFLoader, context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
+        /** Helper method called by the loader to allow extensions to override loading materials. */
+        static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading uris. */
+        static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class MSFTLOD extends GLTFLoaderExtension {
+    class MSFT_lod extends GLTFLoaderExtension {
+        readonly name: string;
+        /**
+         * Maximum number of LODs to load, starting from the lowest LOD.
+         */
+        maxLODsToLoad: number;
+        private _loadingNodeLOD;
+        private _loadNodeSignals;
+        private _loadingMaterialLOD;
+        private _loadMaterialSignals;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
         /**
         /**
-         * Specify the minimal delay between LODs in ms (default = 250)
+         * Gets an array of LOD properties from lowest to highest.
          */
          */
-        Delay: number;
+        private _getLODs<T>(context, property, array, ids);
+    }
+}
+
+
+declare module BABYLON.GLTF2.Extensions {
+    class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        private _loadNodeLOD(loader, context, nodes, index, onComplete);
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadMaterialLOD(loader, context, materials, index, assign, onComplete);
+        protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadSpecularGlossinessProperties(loader, context, material, properties);
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class KHRLights extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        private applyCommonProperties(light, lightInfo);
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
+        protected _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
     }
 }
 }

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


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


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

@@ -28,19 +28,40 @@ declare module BABYLON {
         json: Object;
         json: Object;
         bin: Nullable<ArrayBufferView>;
         bin: Nullable<ArrayBufferView>;
     }
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         compileMaterials: boolean;
         useClipPlane: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -78,19 +99,19 @@ declare module BABYLON {
         /**
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         onMaterialLoaded: (Material: Material) => void;
         /**
         /**
@@ -98,15 +119,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         private _onCompleteObserver;
         onComplete: () => void;
         onComplete: () => void;
         /**
         /**
         * Raised when the loader is disposed.
         * Raised when the loader is disposed.
         */
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         private _onDisposeObserver;
         onDispose: () => void;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         private _loader;
         name: string;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
@@ -114,9 +146,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
          */
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -534,9 +570,17 @@ declare module BABYLON.GLTF1 {
         onTextureLoadedObservable: Observable<BaseTexture>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void;
+        private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        private _loadAsync(scene, data, rootUrl, onSuccess, onProgress, onError);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
         private _createNodes(gltfRuntime);
@@ -567,16 +611,6 @@ declare module BABYLON.GLTF1 {
          */
          */
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         /**
         /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        /**
         * Returns the wrap mode of the texture
         * Returns the wrap mode of the texture
         * @param mode: the mode value
         * @param mode: the mode value
         */
         */
@@ -690,440 +724,271 @@ declare module BABYLON.GLTF1 {
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    /**
-    * Enums
-    */
-    enum EComponentType {
-        BYTE = 5120,
-        UNSIGNED_BYTE = 5121,
-        SHORT = 5122,
-        UNSIGNED_SHORT = 5123,
-        UNSIGNED_INT = 5125,
-        FLOAT = 5126,
+    interface TypedArray extends ArrayBufferView {
+        [index: number]: number;
     }
     }
-    enum EMeshPrimitiveMode {
-        POINTS = 0,
-        LINES = 1,
-        LINE_LOOP = 2,
-        LINE_STRIP = 3,
-        TRIANGLES = 4,
-        TRIANGLE_STRIP = 5,
-        TRIANGLE_FAN = 6,
-    }
-    enum ETextureMagFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-    }
-    enum ETextureMinFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-        NEAREST_MIPMAP_NEAREST = 9984,
-        LINEAR_MIPMAP_NEAREST = 9985,
-        NEAREST_MIPMAP_LINEAR = 9986,
-        LINEAR_MIPMAP_LINEAR = 9987,
-    }
-    enum ETextureWrapMode {
-        CLAMP_TO_EDGE = 33071,
-        MIRRORED_REPEAT = 33648,
-        REPEAT = 10497,
-    }
-    /**
-    * Interfaces
-    */
-    interface IGLTFProperty {
-        extensions?: {
-            [key: string]: any;
-        };
-        extras?: any;
-    }
-    interface IGLTFChildRootProperty extends IGLTFProperty {
-        name?: string;
-    }
-    interface IGLTFAccessorSparseIndices extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-    }
-    interface IGLTFAccessorSparseValues extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-    }
-    interface IGLTFAccessorSparse extends IGLTFProperty {
-        count: number;
-        indices: IGLTFAccessorSparseIndices;
-        values: IGLTFAccessorSparseValues;
-    }
-    interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView?: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-        normalized?: boolean;
-        count: number;
-        type: string;
-        max: number[];
-        min: number[];
-        sparse?: IGLTFAccessorSparse;
-        index: number;
-    }
-    interface IGLTFAnimationChannel extends IGLTFProperty {
-        sampler: number;
-        target: IGLTFAnimationChannelTarget;
-    }
-    interface IGLTFAnimationChannelTarget extends IGLTFProperty {
-        node: number;
-        path: string;
-    }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
-    }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        babylonAnimationGroup: AnimationGroup;
+    interface IArrayItem {
+        _index: number;
     }
     }
-    interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
     }
     }
-    interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
+}
+
+
+
+declare module BABYLON.GLTF2 {
+    interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
     }
     }
-    interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-        index: number;
+    interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
     }
     }
-    interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
     }
     }
-    interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
     }
     }
-    interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
+    interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
     }
     }
-    interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-        index: number;
+    interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
     }
-    interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
+    interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
     }
-    interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
+    interface ILoaderCamera extends ICamera, IArrayItem {
     }
     }
-    interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
+    interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
     }
     }
-    interface IGLTFMaterial extends IGLTFChildRootProperty {
-        pbrMetallicRoughness?: IGLTFMaterialPbrMetallicRoughness;
-        normalTexture?: IGLTFMaterialNormalTextureInfo;
-        occlusionTexture?: IGLTFMaterialOcclusionTextureInfo;
-        emissiveTexture?: IGLTFTextureInfo;
-        emissiveFactor?: number[];
-        alphaMode?: string;
-        alphaCutoff: number;
-        doubleSided?: boolean;
-        index: number;
-        babylonMaterial: Material;
+    interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
     }
     }
-    interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: {
-            [name: string]: number;
-        };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: {
-            [name: string]: number;
-        }[];
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
+    interface ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
     }
     }
-    interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-        index: number;
-        hasVertexAlpha: boolean;
+    interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
     }
     }
-    interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: number;
-        children?: number[];
-        skin?: number;
-        matrix?: number[];
-        mesh?: number;
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-        weights?: number[];
-        index: number;
-        parent: IGLTFNode;
-        babylonMesh: Mesh;
-        babylonAnimationTargets?: Node[];
+    interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
     }
     }
-    interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: ETextureMagFilter;
-        minFilter?: ETextureMinFilter;
-        wrapS?: ETextureWrapMode;
-        wrapT?: ETextureWrapMode;
-        index: number;
+    interface ILoaderSamplerData {
         noMipMaps: boolean;
         noMipMaps: boolean;
         samplingMode: number;
         samplingMode: number;
         wrapU: number;
         wrapU: number;
         wrapV: number;
         wrapV: number;
     }
     }
-    interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: number[];
-        index: number;
+    interface ILoaderSampler extends ISampler, IArrayItem {
+        _data?: ILoaderSamplerData;
     }
     }
-    interface IGLTFSkin extends IGLTFChildRootProperty {
-        inverseBindMatrices?: number;
-        skeleton?: number;
-        joints: number[];
-        index: number;
-        babylonSkeleton: Skeleton;
+    interface ILoaderScene extends IScene, IArrayItem {
     }
     }
-    interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler?: number;
-        source: number;
-        index: number;
-        url?: string;
-        dataReadyObservable?: Observable<IGLTFTexture>;
-    }
-    interface IGLTFTextureInfo {
-        index: number;
-        texCoord?: number;
-    }
-    interface _IGLTF extends IGLTFProperty {
-        accessors?: IGLTFAccessor[];
-        animations?: IGLTFAnimation[];
-        asset: IGLTFAsset;
-        buffers?: IGLTFBuffer[];
-        bufferViews?: IGLTFBufferView[];
-        cameras?: IGLTFCamera[];
-        extensionsUsed?: string[];
-        extensionsRequired?: string[];
-        images?: IGLTFImage[];
-        materials?: IGLTFMaterial[];
-        meshes?: IGLTFMesh[];
-        nodes?: IGLTFNode[];
-        samplers?: IGLTFSampler[];
-        scene?: number;
-        scenes?: IGLTFScene[];
-        skins?: IGLTFSkin[];
-        textures?: IGLTFTexture[];
+    interface ILoaderSkin extends ISkin, IArrayItem {
+        _babylonSkeleton: Nullable<Skeleton>;
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderTexture extends ITexture, IArrayItem {
+    }
+    interface ILoaderGLTF extends IGLTF {
+        accessors?: ILoaderAccessor[];
+        animations?: ILoaderAnimation[];
+        buffers?: ILoaderBuffer[];
+        bufferViews?: ILoaderBufferView[];
+        cameras?: ILoaderCamera[];
+        images?: ILoaderImage[];
+        materials?: ILoaderMaterial[];
+        meshes?: ILoaderMesh[];
+        nodes?: ILoaderNode[];
+        samplers?: ILoaderSampler[];
+        scenes?: ILoaderScene[];
+        skins?: ILoaderSkin[];
+        textures?: ILoaderTexture[];
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: _IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
         private _disposed;
+        private _state;
+        private _extensions;
         private _rootUrl;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback?;
         private _progressCallback?;
         private _progressCallback?;
-        private _errorCallback?;
-        private _renderReady;
         private _requests;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         compileMaterials: boolean;
         useClipPlane: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        onMaterialLoadedObservable: Observable<Material>;
-        onCompleteObservable: Observable<IGLTFLoader>;
+        readonly onDisposeObservable: Observable<IGLTFLoader>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        readonly onCompleteObservable: Observable<IGLTFLoader>;
+        readonly state: Nullable<GLTFLoaderState>;
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
-        private _onProgress();
-        _executeWhenRenderReady(func: () => void): void;
-        private _onRenderReady();
-        private _onComplete();
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
+        private _loadExtensions();
         private _loadData(data);
         private _loadData(data);
+        private _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getMeshes();
         private _getSkeletons();
         private _getSkeletons();
         private _startAnimations();
         private _startAnimations();
-        private _loadDefaultScene(nodeNames);
-        private _loadScene(context, scene, nodeNames);
-        _loadNode(context: string, node: IGLTFNode): void;
-        private _loadMesh(context, node, mesh);
-        private _loadAllVertexDataAsync(context, mesh, onSuccess);
-        /**
-         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4TextureCoordArray(context, data, accessor);
-        /**
-         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4ColorArray(context, data, accessor);
-        private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(context, node, mesh);
-        private _loadMorphTargets(context, node, mesh);
-        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
-        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
-        private _loadTransform(node);
-        private _loadSkinAsync(context, skin, onSuccess);
+        _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
+        private _loadMeshAsync(context, node, mesh);
+        private _loadPrimitiveAsync(context, node, mesh, primitive);
+        private _loadVertexDataAsync(context, primitive, babylonMesh);
+        private _createMorphTargets(context, node, mesh, primitive, babylonMesh);
+        private _loadMorphTargetsAsync(context, primitive, babylonMesh, babylonVertexData);
+        private _loadMorphTargetVertexDataAsync(context, babylonVertexData, attributes, babylonMorphTarget);
+        private static _ConvertToFloat32Array(context, accessor, data);
+        private static _ConvertVec3ToVec4(context, data);
+        private static _LoadTransform(node, babylonNode);
+        private _loadSkinAsync(context, node, mesh, skin);
+        private _loadSkinInverseBindMatricesDataAsync(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
-        private _loadBones(context, skin, inverseBindMatrixData);
-        private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
+        private _loadBones(context, skin, inverseBindMatricesData);
+        private _loadBone(node, skin, inverseBindMatricesData, babylonBones);
         private _getNodeMatrix(node);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
-        private _loadAnimations();
-        private _loadAnimation(context, animation);
-        private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
-        private _loadBufferAsync(context, buffer, onSuccess);
-        private _loadBufferViewAsync(context, bufferView, onSuccess);
-        private _loadAccessorAsync(context, accessor, onSuccess);
+        private _loadAnimationsAsync();
+        private _loadAnimationAsync(context, animation);
+        private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
+        private _loadAnimationSamplerAsync(context, sampler);
+        private _loadBufferAsync(context, buffer);
+        _loadBufferViewAsync(context: string, bufferView: ILoaderBufferView): Promise<ArrayBufferView>;
+        private _loadAccessorAsync(context, accessor);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
-        _addPendingData(data: any): void;
-        _removePendingData(data: any): void;
-        _addLoaderPendingData(data: any): void;
-        _removeLoaderPendingData(data: any): void;
-        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
         private _getDefaultMaterial();
-        private _loadMaterialMetallicRoughnessProperties(context, material);
-        _loadMaterial(context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        _createPbrMaterial(material: IGLTFMaterial): void;
-        _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
-        _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadMaterialMetallicRoughnessPropertiesAsync(context, material);
+        _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Promise<void>;
+        _createMaterial(material: ILoaderMaterial): PBRMaterial;
+        _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial): Promise<void>;
+        _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial): void;
+        _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
         private _loadSampler(context, sampler);
-        private _loadImageAsync(context, image, onSuccess);
-        _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
-        _tryCatchOnError(handler: () => void): void;
-        private static _AssignIndices(array?);
-        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(context, mode?);
+        private _loadImageAsync(context, image);
+        _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
+        private _onProgress();
+        static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
+        private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetNumComponents(context, type);
         private static _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-        private _abortRequests();
-        private _releaseResources();
-    }
-}
-
-
-declare module BABYLON.GLTF2 {
-    /**
-    * Utils functions for GLTF
-    */
-    class GLTFUtils {
-        /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        static ValidateUri(uri: string): boolean;
+        private static _ValidateUri(uri);
+        private _compileMaterialsAsync();
+        private _compileShadowGeneratorsAsync();
+        private _clear();
+        _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         enabled: boolean;
         readonly abstract name: string;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
-        static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private static _ApplyExtensions(action);
+        protected _loader: GLTFLoader;
+        constructor(loader: GLTFLoader);
+        /** Override this method to modify the default behavior for loading scenes. */
+        protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading nodes. */
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading mesh primitive vertex data. */
+        protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
+        /** Override this method to modify the default behavior for loading materials. */
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading uris. */
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Helper method called by a loader extension to load an glTF extension. */
+        protected _loadExtensionAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (context: string, extension: TProperty) => Promise<TResult>): Nullable<Promise<TResult>>;
+        /** Helper method called by the loader to allow extensions to override loading scenes. */
+        static _LoadSceneAsync(loader: GLTFLoader, context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading nodes. */
+        static _LoadNodeAsync(loader: GLTFLoader, context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading mesh primitive vertex data. */
+        static _LoadVertexDataAsync(loader: GLTFLoader, context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
+        /** Helper method called by the loader to allow extensions to override loading materials. */
+        static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading uris. */
+        static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class MSFTLOD extends GLTFLoaderExtension {
+    class MSFT_lod extends GLTFLoaderExtension {
+        readonly name: string;
         /**
         /**
-         * Specify the minimal delay between LODs in ms (default = 250)
+         * Maximum number of LODs to load, starting from the lowest LOD.
          */
          */
-        Delay: number;
+        maxLODsToLoad: number;
+        private _loadingNodeLOD;
+        private _loadNodeSignals;
+        private _loadingMaterialLOD;
+        private _loadMaterialSignals;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Gets an array of LOD properties from lowest to highest.
+         */
+        private _getLODs<T>(context, property, array, ids);
+    }
+}
+
+
+declare module BABYLON.GLTF2.Extensions {
+    class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        private _loadNodeLOD(loader, context, nodes, index, onComplete);
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadMaterialLOD(loader, context, materials, index, assign, onComplete);
+        protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadSpecularGlossinessProperties(loader, context, material, properties);
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class KHRLights extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        private applyCommonProperties(light, lightInfo);
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
+        protected _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
     }
 }
 }

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


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


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

@@ -58,7 +58,7 @@ declare module BABYLON {
         private _loadMTL(url, rootUrl, onSuccess);
         private _loadMTL(url, rootUrl, onSuccess);
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         /**
         /**
          * Read the OBJ file and create an Array of meshes.
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
          * Each mesh contains all information given by the OBJ and the MTL file.

+ 4 - 7
dist/preview release/loaders/babylon.objFileLoader.js

@@ -260,14 +260,11 @@ var BABYLON;
             //Get the 3D model
             //Get the 3D model
             return this.importMesh(null, scene, data, rootUrl, null, null, null);
             return this.importMesh(null, scene, data, rootUrl, null, null, null);
         };
         };
-        OBJFileLoader.prototype.loadAssets = function (scene, data, rootUrl, onError) {
+        OBJFileLoader.prototype.loadAssetContainer = function (scene, data, rootUrl, onError) {
             var container = new BABYLON.AssetContainer(scene);
             var container = new BABYLON.AssetContainer(scene);
-            var result = this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
-            if (result) {
-                container.removeAllFromScene();
-                return container;
-            }
-            return null;
+            this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
+            container.removeAllFromScene();
+            return container;
         };
         };
         /**
         /**
          * Read the OBJ file and create an Array of meshes.
          * Read the OBJ file and create an Array of meshes.

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


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

@@ -9,7 +9,7 @@ declare module BABYLON {
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         private isBinary(data);
         private isBinary(data);
         private parseBinary(mesh, data);
         private parseBinary(mesh, data);
         private parseASCII(mesh, solidData);
         private parseASCII(mesh, solidData);

+ 4 - 7
dist/preview release/loaders/babylon.stlFileLoader.js

@@ -70,14 +70,11 @@ var BABYLON;
             }
             }
             return result;
             return result;
         };
         };
-        STLFileLoader.prototype.loadAssets = function (scene, data, rootUrl, onError) {
+        STLFileLoader.prototype.loadAssetContainer = function (scene, data, rootUrl, onError) {
             var container = new BABYLON.AssetContainer(scene);
             var container = new BABYLON.AssetContainer(scene);
-            var result = this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
-            if (result) {
-                container.removeAllFromScene();
-                return container;
-            }
-            return null;
+            this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
+            container.removeAllFromScene();
+            return container;
         };
         };
         STLFileLoader.prototype.isBinary = function (data) {
         STLFileLoader.prototype.isBinary = function (data) {
             // check if file size is correct for binary stl
             // check if file size is correct for binary stl

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


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


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


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

@@ -15,7 +15,7 @@ declare module BABYLON {
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
         load(scene: Scene, data: any, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         private isBinary(data);
         private isBinary(data);
         private parseBinary(mesh, data);
         private parseBinary(mesh, data);
         private parseASCII(mesh, solidData);
         private parseASCII(mesh, solidData);
@@ -82,7 +82,7 @@ declare module BABYLON {
         private _loadMTL(url, rootUrl, onSuccess);
         private _loadMTL(url, rootUrl, onSuccess);
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
         load(scene: Scene, data: string, rootUrl: string): boolean;
-        loadAssets(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): Nullable<AssetContainer>;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         /**
         /**
          * Read the OBJ file and create an Array of meshes.
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
          * Each mesh contains all information given by the OBJ and the MTL file.
@@ -129,19 +129,40 @@ declare module BABYLON {
         json: Object;
         json: Object;
         bin: Nullable<ArrayBufferView>;
         bin: Nullable<ArrayBufferView>;
     }
     }
+    interface IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Whether this extension is enabled.
+         */
+        enabled: boolean;
+    }
+    enum GLTFLoaderState {
+        Loading = 0,
+        Ready = 1,
+        Complete = 2,
+    }
     interface IGLTFLoader extends IDisposable {
     interface IGLTFLoader extends IDisposable {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         compileMaterials: boolean;
         useClipPlane: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onCompleteObservable: Observable<IGLTFLoader>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: () => IGLTFLoader;
         static CreateGLTFLoaderV1: () => IGLTFLoader;
@@ -179,19 +200,19 @@ declare module BABYLON {
         /**
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
          */
-        onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         private _onMeshLoadedObserver;
         private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
          */
-        onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
         private _onTextureLoadedObserver;
         private _onTextureLoadedObserver;
         onTextureLoaded: (Texture: BaseTexture) => void;
         onTextureLoaded: (Texture: BaseTexture) => void;
         /**
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
          */
-        onMaterialLoadedObservable: Observable<Material>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
         private _onMaterialLoadedObserver;
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (Material: Material) => void;
         onMaterialLoaded: (Material: Material) => void;
         /**
         /**
@@ -199,15 +220,26 @@ declare module BABYLON {
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
          */
-        onCompleteObservable: Observable<GLTFFileLoader>;
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
         private _onCompleteObserver;
         private _onCompleteObserver;
         onComplete: () => void;
         onComplete: () => void;
         /**
         /**
         * Raised when the loader is disposed.
         * Raised when the loader is disposed.
         */
         */
-        onDisposeObservable: Observable<GLTFFileLoader>;
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
         private _onDisposeObserver;
         private _onDisposeObserver;
         onDispose: () => void;
         onDispose: () => void;
+        /**
+         * Raised after a loader extension is created.
+         * Set additional options for a loader extension in this event.
+         */
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        private _onExtensionLoadedObserver;
+        onExtensionLoaded: (extension: IGLTFLoaderExtension) => void;
+        /**
+         * The loader state or null if not active.
+         */
+        readonly loaderState: Nullable<GLTFLoaderState>;
         private _loader;
         private _loader;
         name: string;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
@@ -215,9 +247,13 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
          */
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAssetsAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (assets: AssetContainer) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
         canDirectLoad(data: string): boolean;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -635,9 +671,17 @@ declare module BABYLON.GLTF1 {
         onTextureLoadedObservable: Observable<BaseTexture>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
         onMaterialLoadedObservable: Observable<Material>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void;
+        private _importMeshAsync(meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        private _loadAsync(scene, data, rootUrl, onSuccess, onProgress, onError);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
         private _createNodes(gltfRuntime);
@@ -668,16 +712,6 @@ declare module BABYLON.GLTF1 {
          */
          */
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean;
         /**
         /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        /**
         * Returns the wrap mode of the texture
         * Returns the wrap mode of the texture
         * @param mode: the mode value
         * @param mode: the mode value
         */
         */
@@ -791,440 +825,271 @@ declare module BABYLON.GLTF1 {
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    /**
-    * Enums
-    */
-    enum EComponentType {
-        BYTE = 5120,
-        UNSIGNED_BYTE = 5121,
-        SHORT = 5122,
-        UNSIGNED_SHORT = 5123,
-        UNSIGNED_INT = 5125,
-        FLOAT = 5126,
+    interface TypedArray extends ArrayBufferView {
+        [index: number]: number;
     }
     }
-    enum EMeshPrimitiveMode {
-        POINTS = 0,
-        LINES = 1,
-        LINE_LOOP = 2,
-        LINE_STRIP = 3,
-        TRIANGLES = 4,
-        TRIANGLE_STRIP = 5,
-        TRIANGLE_FAN = 6,
-    }
-    enum ETextureMagFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-    }
-    enum ETextureMinFilter {
-        NEAREST = 9728,
-        LINEAR = 9729,
-        NEAREST_MIPMAP_NEAREST = 9984,
-        LINEAR_MIPMAP_NEAREST = 9985,
-        NEAREST_MIPMAP_LINEAR = 9986,
-        LINEAR_MIPMAP_LINEAR = 9987,
-    }
-    enum ETextureWrapMode {
-        CLAMP_TO_EDGE = 33071,
-        MIRRORED_REPEAT = 33648,
-        REPEAT = 10497,
-    }
-    /**
-    * Interfaces
-    */
-    interface IGLTFProperty {
-        extensions?: {
-            [key: string]: any;
-        };
-        extras?: any;
-    }
-    interface IGLTFChildRootProperty extends IGLTFProperty {
-        name?: string;
-    }
-    interface IGLTFAccessorSparseIndices extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-    }
-    interface IGLTFAccessorSparseValues extends IGLTFProperty {
-        bufferView: number;
-        byteOffset?: number;
-    }
-    interface IGLTFAccessorSparse extends IGLTFProperty {
-        count: number;
-        indices: IGLTFAccessorSparseIndices;
-        values: IGLTFAccessorSparseValues;
-    }
-    interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView?: number;
-        byteOffset?: number;
-        componentType: EComponentType;
-        normalized?: boolean;
-        count: number;
-        type: string;
-        max: number[];
-        min: number[];
-        sparse?: IGLTFAccessorSparse;
-        index: number;
-    }
-    interface IGLTFAnimationChannel extends IGLTFProperty {
-        sampler: number;
-        target: IGLTFAnimationChannelTarget;
-    }
-    interface IGLTFAnimationChannelTarget extends IGLTFProperty {
-        node: number;
-        path: string;
-    }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
-    }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        babylonAnimationGroup: AnimationGroup;
+    interface IArrayItem {
+        _index: number;
     }
     }
-    interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
     }
     }
-    interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
+}
+
+
+
+declare module BABYLON.GLTF2 {
+    interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
     }
     }
-    interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-        index: number;
+    interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
     }
     }
-    interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
     }
     }
-    interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
     }
     }
-    interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
+    interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
     }
     }
-    interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-        index: number;
+    interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
     }
-    interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
+    interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
     }
-    interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
+    interface ILoaderCamera extends ICamera, IArrayItem {
     }
     }
-    interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
+    interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
     }
     }
-    interface IGLTFMaterial extends IGLTFChildRootProperty {
-        pbrMetallicRoughness?: IGLTFMaterialPbrMetallicRoughness;
-        normalTexture?: IGLTFMaterialNormalTextureInfo;
-        occlusionTexture?: IGLTFMaterialOcclusionTextureInfo;
-        emissiveTexture?: IGLTFTextureInfo;
-        emissiveFactor?: number[];
-        alphaMode?: string;
-        alphaCutoff: number;
-        doubleSided?: boolean;
-        index: number;
-        babylonMaterial: Material;
+    interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
     }
     }
-    interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: {
-            [name: string]: number;
-        };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: {
-            [name: string]: number;
-        }[];
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
+    interface ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
     }
     }
-    interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-        index: number;
-        hasVertexAlpha: boolean;
+    interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
     }
     }
-    interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: number;
-        children?: number[];
-        skin?: number;
-        matrix?: number[];
-        mesh?: number;
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-        weights?: number[];
-        index: number;
-        parent: IGLTFNode;
-        babylonMesh: Mesh;
-        babylonAnimationTargets?: Node[];
+    interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
     }
     }
-    interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: ETextureMagFilter;
-        minFilter?: ETextureMinFilter;
-        wrapS?: ETextureWrapMode;
-        wrapT?: ETextureWrapMode;
-        index: number;
+    interface ILoaderSamplerData {
         noMipMaps: boolean;
         noMipMaps: boolean;
         samplingMode: number;
         samplingMode: number;
         wrapU: number;
         wrapU: number;
         wrapV: number;
         wrapV: number;
     }
     }
-    interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: number[];
-        index: number;
+    interface ILoaderSampler extends ISampler, IArrayItem {
+        _data?: ILoaderSamplerData;
     }
     }
-    interface IGLTFSkin extends IGLTFChildRootProperty {
-        inverseBindMatrices?: number;
-        skeleton?: number;
-        joints: number[];
-        index: number;
-        babylonSkeleton: Skeleton;
+    interface ILoaderScene extends IScene, IArrayItem {
     }
     }
-    interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler?: number;
-        source: number;
-        index: number;
-        url?: string;
-        dataReadyObservable?: Observable<IGLTFTexture>;
-    }
-    interface IGLTFTextureInfo {
-        index: number;
-        texCoord?: number;
-    }
-    interface _IGLTF extends IGLTFProperty {
-        accessors?: IGLTFAccessor[];
-        animations?: IGLTFAnimation[];
-        asset: IGLTFAsset;
-        buffers?: IGLTFBuffer[];
-        bufferViews?: IGLTFBufferView[];
-        cameras?: IGLTFCamera[];
-        extensionsUsed?: string[];
-        extensionsRequired?: string[];
-        images?: IGLTFImage[];
-        materials?: IGLTFMaterial[];
-        meshes?: IGLTFMesh[];
-        nodes?: IGLTFNode[];
-        samplers?: IGLTFSampler[];
-        scene?: number;
-        scenes?: IGLTFScene[];
-        skins?: IGLTFSkin[];
-        textures?: IGLTFTexture[];
+    interface ILoaderSkin extends ISkin, IArrayItem {
+        _babylonSkeleton: Nullable<Skeleton>;
+        _loaded?: Promise<void>;
+    }
+    interface ILoaderTexture extends ITexture, IArrayItem {
+    }
+    interface ILoaderGLTF extends IGLTF {
+        accessors?: ILoaderAccessor[];
+        animations?: ILoaderAnimation[];
+        buffers?: ILoaderBuffer[];
+        bufferViews?: ILoaderBufferView[];
+        cameras?: ILoaderCamera[];
+        images?: ILoaderImage[];
+        materials?: ILoaderMaterial[];
+        meshes?: ILoaderMesh[];
+        nodes?: ILoaderNode[];
+        samplers?: ILoaderSampler[];
+        scenes?: ILoaderScene[];
+        skins?: ILoaderSkin[];
+        textures?: ILoaderTexture[];
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
     class GLTFLoader implements IGLTFLoader {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: _IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
         private _disposed;
+        private _state;
+        private _extensions;
         private _rootUrl;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback?;
         private _progressCallback?;
         private _progressCallback?;
-        private _errorCallback?;
-        private _renderReady;
         private _requests;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         animationStartMode: GLTFLoaderAnimationStartMode;
         compileMaterials: boolean;
         compileMaterials: boolean;
         useClipPlane: boolean;
         useClipPlane: boolean;
         compileShadowGenerators: boolean;
         compileShadowGenerators: boolean;
-        onDisposeObservable: Observable<IGLTFLoader>;
-        onMeshLoadedObservable: Observable<AbstractMesh>;
-        onTextureLoadedObservable: Observable<BaseTexture>;
-        onMaterialLoadedObservable: Observable<Material>;
-        onCompleteObservable: Observable<IGLTFLoader>;
+        readonly onDisposeObservable: Observable<IGLTFLoader>;
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        readonly onCompleteObservable: Observable<IGLTFLoader>;
+        readonly state: Nullable<GLTFLoaderState>;
         dispose(): void;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
-        private _onProgress();
-        _executeWhenRenderReady(func: () => void): void;
-        private _onRenderReady();
-        private _onComplete();
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+            meshes: AbstractMesh[];
+            particleSystems: ParticleSystem[];
+            skeletons: Skeleton[];
+        }>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
+        private _loadExtensions();
         private _loadData(data);
         private _loadData(data);
+        private _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getMeshes();
         private _getSkeletons();
         private _getSkeletons();
         private _startAnimations();
         private _startAnimations();
-        private _loadDefaultScene(nodeNames);
-        private _loadScene(context, scene, nodeNames);
-        _loadNode(context: string, node: IGLTFNode): void;
-        private _loadMesh(context, node, mesh);
-        private _loadAllVertexDataAsync(context, mesh, onSuccess);
-        /**
-         * Converts a data bufferview into a Float4 Texture Coordinate Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4TextureCoordArray(context, data, accessor);
-        /**
-         * Converts a data bufferview into a Float4 Color Array, based on the accessor component type
-         * @param {ArrayBufferView} data
-         * @param {IGLTFAccessor} accessor
-         */
-        private _convertToFloat4ColorArray(context, data, accessor);
-        private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(context, node, mesh);
-        private _loadMorphTargets(context, node, mesh);
-        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
-        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
-        private _loadTransform(node);
-        private _loadSkinAsync(context, skin, onSuccess);
+        _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
+        private _loadMeshAsync(context, node, mesh);
+        private _loadPrimitiveAsync(context, node, mesh, primitive);
+        private _loadVertexDataAsync(context, primitive, babylonMesh);
+        private _createMorphTargets(context, node, mesh, primitive, babylonMesh);
+        private _loadMorphTargetsAsync(context, primitive, babylonMesh, babylonVertexData);
+        private _loadMorphTargetVertexDataAsync(context, babylonVertexData, attributes, babylonMorphTarget);
+        private static _ConvertToFloat32Array(context, accessor, data);
+        private static _ConvertVec3ToVec4(context, data);
+        private static _LoadTransform(node, babylonNode);
+        private _loadSkinAsync(context, node, mesh, skin);
+        private _loadSkinInverseBindMatricesDataAsync(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
-        private _loadBones(context, skin, inverseBindMatrixData);
-        private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
+        private _loadBones(context, skin, inverseBindMatricesData);
+        private _loadBone(node, skin, inverseBindMatricesData, babylonBones);
         private _getNodeMatrix(node);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
-        private _loadAnimations();
-        private _loadAnimation(context, animation);
-        private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
-        private _loadBufferAsync(context, buffer, onSuccess);
-        private _loadBufferViewAsync(context, bufferView, onSuccess);
-        private _loadAccessorAsync(context, accessor, onSuccess);
+        private _loadAnimationsAsync();
+        private _loadAnimationAsync(context, animation);
+        private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
+        private _loadAnimationSamplerAsync(context, sampler);
+        private _loadBufferAsync(context, buffer);
+        _loadBufferViewAsync(context: string, bufferView: ILoaderBufferView): Promise<ArrayBufferView>;
+        private _loadAccessorAsync(context, accessor);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
         private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride?);
-        _addPendingData(data: any): void;
-        _removePendingData(data: any): void;
-        _addLoaderPendingData(data: any): void;
-        _removeLoaderPendingData(data: any): void;
-        _whenAction(action: () => void, onComplete: () => void): void;
         private _getDefaultMaterial();
         private _getDefaultMaterial();
-        private _loadMaterialMetallicRoughnessProperties(context, material);
-        _loadMaterial(context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): void;
-        _createPbrMaterial(material: IGLTFMaterial): void;
-        _loadMaterialBaseProperties(context: string, material: IGLTFMaterial): void;
-        _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
-        _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex?: number): Texture;
+        private _loadMaterialMetallicRoughnessPropertiesAsync(context, material);
+        _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Promise<void>;
+        _createMaterial(material: ILoaderMaterial): PBRMaterial;
+        _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial): Promise<void>;
+        _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial): void;
+        _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void>;
         private _loadSampler(context, sampler);
         private _loadSampler(context, sampler);
-        private _loadImageAsync(context, image, onSuccess);
-        _loadUriAsync(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
-        _tryCatchOnError(handler: () => void): void;
-        private static _AssignIndices(array?);
-        static _GetProperty<T extends IGLTFProperty>(array?: ArrayLike<T>, index?: number): Nullable<T>;
-        private static _GetTextureWrapMode(context, mode?);
+        private _loadImageAsync(context, image);
+        _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView>;
+        private _onProgress();
+        static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T;
+        private static _GetTextureWrapMode(context, mode);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetTextureSamplingMode(context, magFilter?, minFilter?);
         private static _GetNumComponents(context, type);
         private static _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-        private _abortRequests();
-        private _releaseResources();
-    }
-}
-
-
-declare module BABYLON.GLTF2 {
-    /**
-    * Utils functions for GLTF
-    */
-    class GLTFUtils {
-        /**
-        * If the uri is a base64 string
-        * @param uri: the uri to test
-        */
-        static IsBase64(uri: string): boolean;
-        /**
-        * Decode the base64 uri
-        * @param uri: the uri to decode
-        */
-        static DecodeBase64(uri: string): ArrayBuffer;
-        static ValidateUri(uri: string): boolean;
+        private static _ValidateUri(uri);
+        private _compileMaterialsAsync();
+        private _compileShadowGeneratorsAsync();
+        private _clear();
+        _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         enabled: boolean;
         readonly abstract name: string;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
-        static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        static LoadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
-        static LoadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private static _ApplyExtensions(action);
+        protected _loader: GLTFLoader;
+        constructor(loader: GLTFLoader);
+        /** Override this method to modify the default behavior for loading scenes. */
+        protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading nodes. */
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading mesh primitive vertex data. */
+        protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
+        /** Override this method to modify the default behavior for loading materials. */
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading uris. */
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Helper method called by a loader extension to load an glTF extension. */
+        protected _loadExtensionAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (context: string, extension: TProperty) => Promise<TResult>): Nullable<Promise<TResult>>;
+        /** Helper method called by the loader to allow extensions to override loading scenes. */
+        static _LoadSceneAsync(loader: GLTFLoader, context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading nodes. */
+        static _LoadNodeAsync(loader: GLTFLoader, context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading mesh primitive vertex data. */
+        static _LoadVertexDataAsync(loader: GLTFLoader, context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
+        /** Helper method called by the loader to allow extensions to override loading materials. */
+        static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading uris. */
+        static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class MSFTLOD extends GLTFLoaderExtension {
+    class MSFT_lod extends GLTFLoaderExtension {
+        readonly name: string;
         /**
         /**
-         * Specify the minimal delay between LODs in ms (default = 250)
+         * Maximum number of LODs to load, starting from the lowest LOD.
          */
          */
-        Delay: number;
+        maxLODsToLoad: number;
+        private _loadingNodeLOD;
+        private _loadNodeSignals;
+        private _loadingMaterialLOD;
+        private _loadMaterialSignals;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Gets an array of LOD properties from lowest to highest.
+         */
+        private _getLODs<T>(context, property, array, ids);
+    }
+}
+
+
+declare module BABYLON.GLTF2.Extensions {
+    class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        private _loadNodeLOD(loader, context, nodes, index, onComplete);
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadMaterialLOD(loader, context, materials, index, assign, onComplete);
+        protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
-        private _loadSpecularGlossinessProperties(loader, context, material, properties);
+        protected _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
     }
 }
 }
 
 
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
-    class KHRLights extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
         readonly name: string;
-        private applyCommonProperties(light, lightInfo);
-        protected _loadScene(loader: GLTFLoader, context: string, scene: IGLTFScene): boolean;
-        protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
-        protected _loadRoot(loader: GLTFLoader, context: string, root: BABYLON.GLTF2._IGLTF): boolean;
+        protected _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
     }
 }
 }

+ 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-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 0
dist/preview release/materialsLibrary/babylon.fireMaterial.js

@@ -88,6 +88,7 @@ var BABYLON;
                     }
                     }
                 }
                 }
             }
             }
+            defines.ALPHATEST = this._opacityTexture ? true : false;
             // Misc.
             // Misc.
             if (defines._areMiscDirty) {
             if (defines._areMiscDirty) {
                 defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);
                 defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);

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


+ 1 - 0
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -2118,6 +2118,7 @@ var BABYLON;
                     }
                     }
                 }
                 }
             }
             }
+            defines.ALPHATEST = this._opacityTexture ? true : false;
             // Misc.
             // Misc.
             if (defines._areMiscDirty) {
             if (defines._areMiscDirty) {
                 defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);
                 defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);

File diff suppressed because it is too large
+ 1 - 1
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-alpha6",
+    "version": "3.2.0-alpha7",
     "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/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-alpha6",
+    "version": "3.2.0-alpha7",
     "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-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 65 - 22
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -189,13 +189,6 @@ declare module BABYLON.GLTF2 {
          */
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
         /**
-         *
-         * @param babylonTexture - Babylon texture to extract.
-         * @param mimeType - Mime Type of the babylonTexture.
-         * @return - glTF texture, or null if the texture format is not supported.
-         */
-        private exportTexture(babylonTexture, mimeType?);
-        /**
          * 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.
@@ -261,9 +254,25 @@ declare module BABYLON.GLTF2 {
          */
          */
         private static readonly dielectricSpecular;
         private static readonly dielectricSpecular;
         /**
         /**
-         * Epsilon value, used as a small tolerance value for a numeric value.
+         * Allows the maximum specular power to be defined for material calculations.
+         */
+        private static maxSpecularPower;
+        /**
+         * Gets the materials from a Babylon scene and converts them to glTF materials.
+         * @param scene
+         * @param mimeType
+         * @param images
+         * @param textures
+         * @param materials
+         * @param imageData
+         * @param hasTextureCoords
          */
          */
-        private static readonly epsilon;
+        static ConvertMaterialsToGLTF(babylonMaterials: Material[], mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
         /**
         /**
          * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
          * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
          * @param babylonStandardMaterial
          * @param babylonStandardMaterial
@@ -271,19 +280,6 @@ declare module BABYLON.GLTF2 {
          */
          */
         static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
         static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
         /**
         /**
-         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
-         * @returns - Babylon metallic roughness values
-         */
-        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness);
-        /**
-         * Returns the perceived brightness value based on the provided color
-         * @param color - color used in calculating the perceived brightness
-         * @returns - perceived brightness value
-         */
-        private static PerceivedBrightness(color);
-        /**
          * Computes the metallic factor
          * Computes the metallic factor
          * @param diffuse - diffused value
          * @param diffuse - diffused value
          * @param specular - specular value
          * @param specular - specular value
@@ -297,5 +293,52 @@ declare module BABYLON.GLTF2 {
          * @returns - The Babylon alpha mode value
          * @returns - The Babylon alpha mode value
          */
          */
         static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
         static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
+        /**
+         * Converts a Babylon Standard Material to a glTF Material.
+         * @param babylonStandardMaterial - BJS Standard Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertStandardMaterial(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+         * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertPBRMetallicRoughnessMaterial(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Extracts a texture from a Babylon texture into file data and glTF data.
+         * @param babylonTexture - Babylon texture to extract.
+         * @param mimeType - Mime Type of the babylonTexture.
+         * @param images - Array of glTF images.
+         * @param textures - Array of glTF textures.
+         * @param imageData - map of image file name and data.
+         * @return - glTF texture, or null if the texture format is not supported.
+         */
+        static ExportTexture(babylonTexture: BaseTexture, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }): Nullable<ITextureInfo>;
     }
     }
 }
 }

+ 297 - 248
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -502,84 +502,6 @@ var BABYLON;
                 }
                 }
             };
             };
             /**
             /**
-             *
-             * @param babylonTexture - Babylon texture to extract.
-             * @param mimeType - Mime Type of the babylonTexture.
-             * @return - glTF texture, or null if the texture format is not supported.
-             */
-            _Exporter.prototype.exportTexture = function (babylonTexture, mimeType) {
-                if (mimeType === void 0) { mimeType = "image/jpeg" /* JPEG */; }
-                var textureInfo = null;
-                var glTFTexture;
-                glTFTexture = {
-                    source: this.images.length
-                };
-                var textureName = babylonTexture.getInternalTexture().url;
-                if (textureName.search('/') !== -1) {
-                    var splitFilename = textureName.split('/');
-                    textureName = splitFilename[splitFilename.length - 1];
-                    var basefile = textureName.split('.')[0];
-                    var extension = textureName.split('.')[1];
-                    if (mimeType === "image/jpeg" /* JPEG */) {
-                        extension = ".jpg";
-                    }
-                    else if (mimeType === "image/png" /* PNG */) {
-                        extension = ".png";
-                    }
-                    else {
-                        throw new Error("Unsupported mime type " + mimeType);
-                    }
-                    textureName = basefile + extension;
-                }
-                var pixels = babylonTexture.readPixels();
-                var imageCanvas = document.createElement('canvas');
-                imageCanvas.id = "ImageCanvas";
-                var ctx = imageCanvas.getContext('2d');
-                var size = babylonTexture.getSize();
-                imageCanvas.width = size.width;
-                imageCanvas.height = size.height;
-                var imgData = ctx.createImageData(size.width, size.height);
-                imgData.data.set(pixels);
-                ctx.putImageData(imgData, 0, 0);
-                var base64Data = imageCanvas.toDataURL(mimeType);
-                var binStr = atob(base64Data.split(',')[1]);
-                var arr = new Uint8Array(binStr.length);
-                for (var i = 0; i < binStr.length; ++i) {
-                    arr[i] = binStr.charCodeAt(i);
-                }
-                var imageValues = { data: arr, mimeType: mimeType };
-                this.imageData[textureName] = imageValues;
-                if (mimeType === "image/jpeg" /* JPEG */) {
-                    var glTFImage = {
-                        uri: textureName
-                    };
-                    var foundIndex = -1;
-                    for (var i = 0; i < this.images.length; ++i) {
-                        if (this.images[i].uri === textureName) {
-                            foundIndex = i;
-                            break;
-                        }
-                    }
-                    if (foundIndex === -1) {
-                        this.images.push(glTFImage);
-                        glTFTexture.source = this.images.length - 1;
-                        this.textures.push({
-                            source: this.images.length - 1
-                        });
-                        textureInfo = {
-                            index: this.images.length - 1
-                        };
-                    }
-                    else {
-                        glTFTexture.source = foundIndex;
-                        textureInfo = {
-                            index: foundIndex
-                        };
-                    }
-                }
-                return textureInfo;
-            };
-            /**
              * 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.
@@ -645,7 +567,7 @@ var BABYLON;
                                     break;
                                     break;
                                 }
                                 }
                                 default: {
                                 default: {
-                                    console.warn("Unsupported VertexBuffer kind: " + kind);
+                                    BABYLON.Tools.Warn("Unsupported VertexBuffer kind: " + kind);
                                 }
                                 }
                             }
                             }
                             if (bufferViewName !== null) {
                             if (bufferViewName !== null) {
@@ -799,120 +721,20 @@ var BABYLON;
                             }
                             }
                         }
                         }
                         if (bufferMesh.material) {
                         if (bufferMesh.material) {
-                            if (bufferMesh.material instanceof BABYLON.StandardMaterial) {
-                                console.warn("Standard Material is currently not fully supported/implemented in glTF serializer");
-                                var babylonStandardMaterial = bufferMesh.material;
-                                var glTFPbrMetallicRoughness = GLTF2._GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
-                                var glTFMaterial = { name: babylonStandardMaterial.name };
-                                if (!babylonStandardMaterial.backFaceCulling) {
-                                    glTFMaterial.doubleSided = true;
-                                }
-                                if (babylonStandardMaterial.diffuseTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.diffuseTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.bumpTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.normalTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.emissiveTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
-                                    if (glTFEmissiveTexture) {
-                                        glTFMaterial.emissiveTexture = glTFEmissiveTexture;
-                                    }
-                                    glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
-                                }
-                                if (babylonStandardMaterial.ambientTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
-                                    if (glTFOcclusionTexture) {
-                                        glTFMaterial.occlusionTexture = glTFOcclusionTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
-                                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
-                                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
-                                    }
-                                    else {
-                                        console.warn("glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
+                            if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                                var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
+                                meshPrimitive.material = materialIndex;
                             }
                             }
-                            else if (bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
-                                var babylonPBRMaterial = bufferMesh.material;
-                                var glTFPbrMetallicRoughness = {};
-                                if (babylonPBRMaterial.baseColor) {
-                                    glTFPbrMetallicRoughness.baseColorFactor = [
-                                        babylonPBRMaterial.baseColor.r,
-                                        babylonPBRMaterial.baseColor.g,
-                                        babylonPBRMaterial.baseColor.b,
-                                        babylonPBRMaterial.alpha
-                                    ];
-                                }
-                                if (babylonPBRMaterial.baseTexture !== undefined) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.baseTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                                    }
-                                    glTFPbrMetallicRoughness.baseColorTexture;
-                                }
-                                if (babylonPBRMaterial.metallic !== undefined) {
-                                    glTFPbrMetallicRoughness.metallicFactor = babylonPBRMaterial.metallic;
-                                }
-                                if (babylonPBRMaterial.roughness !== undefined) {
-                                    glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMaterial.roughness;
-                                }
-                                var glTFMaterial = {
-                                    name: babylonPBRMaterial.name
-                                };
-                                if (babylonPBRMaterial.doubleSided) {
-                                    glTFMaterial.doubleSided = babylonPBRMaterial.doubleSided;
-                                }
-                                if (babylonPBRMaterial.normalTexture) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.normalTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.normalTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonPBRMaterial.occlusionTexture) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.occlusionTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.occlusionTexture = glTFTexture;
-                                        if (babylonPBRMaterial.occlusionStrength !== undefined) {
-                                            glTFMaterial.occlusionTexture.strength = babylonPBRMaterial.occlusionStrength;
-                                        }
-                                    }
-                                }
-                                if (babylonPBRMaterial.emissiveTexture) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.emissiveTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFMaterial.emissiveTexture = glTFTexture;
-                                    }
-                                }
-                                if (!babylonPBRMaterial.emissiveColor.equals(new BABYLON.Color3(0.0, 0.0, 0.0))) {
-                                    glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
+                            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);
+                                    meshPrimitive.material = materialIndex;
                                 }
                                 }
-                                if (babylonPBRMaterial.transparencyMode) {
-                                    var alphaMode = GLTF2._GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
-                                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
-                                        glTFMaterial.alphaMode = alphaMode;
-                                        if (alphaMode === "BLEND" /* BLEND */) {
-                                            glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
-                                        }
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
                             }
                             }
                             else {
                             else {
-                                console.warn("Material type is not yet implemented in glTF serializer: " + bufferMesh.material.name);
+                                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);
@@ -932,6 +754,9 @@ var BABYLON;
                 if (babylonScene.meshes.length > 0) {
                 if (babylonScene.meshes.length > 0) {
                     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);
+                    }
                     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 &&
@@ -1042,70 +867,79 @@ var BABYLON;
             function _GLTFMaterial() {
             function _GLTFMaterial() {
             }
             }
             /**
             /**
+             * Gets the materials from a Babylon scene and converts them to glTF materials.
+             * @param scene
+             * @param mimeType
+             * @param images
+             * @param textures
+             * @param materials
+             * @param imageData
+             * @param hasTextureCoords
+             */
+            _GLTFMaterial.ConvertMaterialsToGLTF = function (babylonMaterials, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                for (var i = 0; i < babylonMaterials.length; ++i) {
+                    var babylonMaterial = babylonMaterials[i];
+                    if (babylonMaterial instanceof BABYLON.StandardMaterial) {
+                        _GLTFMaterial.ConvertStandardMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                    else if (babylonMaterial instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                        _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                }
+            };
+            /**
              * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
              * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
              * @param babylonStandardMaterial
              * @param babylonStandardMaterial
              * @returns - glTF Metallic Roughness Material representation
              * @returns - glTF Metallic Roughness Material representation
              */
              */
             _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness = function (babylonStandardMaterial) {
             _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness = function (babylonStandardMaterial) {
-                var babylonSpecularGlossiness = {
-                    diffuse: babylonStandardMaterial.diffuseColor,
-                    opacity: babylonStandardMaterial.alpha,
-                    specular: babylonStandardMaterial.specularColor || BABYLON.Color3.Black(),
-                    glossiness: babylonStandardMaterial.specularPower / 256
-                };
-                if (babylonStandardMaterial.specularTexture) {
+                var P0 = new BABYLON.Vector2(0, 1);
+                var P1 = new BABYLON.Vector2(0, 0.1);
+                var P2 = new BABYLON.Vector2(0, 0.1);
+                var P3 = new BABYLON.Vector2(1300, 0.1);
+                /**
+                 * Given the control points, solve for x based on a given t for a cubic bezier curve.
+                 * @param t - a value between 0 and 1.
+                 * @param p0 - first control point.
+                 * @param p1 - second control point.
+                 * @param p2 - third control point.
+                 * @param p3 - fourth control point.
+                 * @returns - number result of cubic bezier curve at the specified t.
+                 */
+                function cubicBezierCurve(t, p0, p1, p2, p3) {
+                    return ((1 - t) * (1 - t) * (1 - t) * p0 +
+                        3 * (1 - t) * (1 - t) * t * p1 +
+                        3 * (1 - t) * t * t * p2 +
+                        t * t * t * p3);
                 }
                 }
-                var babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
+                /**
+                 * Evaluates a specified specular power value to determine the appropriate roughness value,
+                 * based on a pre-defined cubic bezier curve with specular on the abscissa axis (x-axis)
+                 * and roughness on the ordinant axis (y-axis).
+                 * @param specularPower - specular power of standard material.
+                 * @returns - Number representing the roughness value.
+                 */
+                function solveForRoughness(specularPower) {
+                    var t = Math.pow(specularPower / P3.x, 0.333333);
+                    return cubicBezierCurve(t, P0.y, P1.y, P2.y, P3.y);
+                }
+                var diffuse = babylonStandardMaterial.diffuseColor.toLinearSpace().scale(0.5);
+                var opacity = babylonStandardMaterial.alpha;
+                var specularPower = BABYLON.Scalar.Clamp(babylonStandardMaterial.specularPower, 0, this.maxSpecularPower);
+                var roughness = solveForRoughness(specularPower);
                 var glTFPbrMetallicRoughness = {
                 var glTFPbrMetallicRoughness = {
                     baseColorFactor: [
                     baseColorFactor: [
-                        babylonMetallicRoughness.baseColor.r,
-                        babylonMetallicRoughness.baseColor.g,
-                        babylonMetallicRoughness.baseColor.b,
-                        babylonMetallicRoughness.opacity
+                        diffuse.r,
+                        diffuse.g,
+                        diffuse.b,
+                        opacity
                     ],
                     ],
-                    metallicFactor: babylonMetallicRoughness.metallic,
-                    roughnessFactor: babylonMetallicRoughness.roughness
+                    metallicFactor: 0,
+                    roughnessFactor: roughness,
                 };
                 };
                 return glTFPbrMetallicRoughness;
                 return glTFPbrMetallicRoughness;
             };
             };
             /**
             /**
-             * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-             * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-             * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
-             * @returns - Babylon metallic roughness values
-             */
-            _GLTFMaterial._ConvertToMetallicRoughness = function (babylonSpecularGlossiness) {
-                var diffuse = babylonSpecularGlossiness.diffuse;
-                var opacity = babylonSpecularGlossiness.opacity;
-                var specular = babylonSpecularGlossiness.specular;
-                var glossiness = BABYLON.Scalar.Clamp(babylonSpecularGlossiness.glossiness);
-                var oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
-                var diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
-                var specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
-                var metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
-                var diffuseScaleFactor = oneMinusSpecularStrength / (1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
-                var baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
-                var baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1 / Math.max(metallic, this.epsilon));
-                var lerpColor = BABYLON.Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
-                var baseColor = new BABYLON.Color3();
-                lerpColor.clampToRef(0, 1, baseColor);
-                var babylonMetallicRoughness = {
-                    baseColor: baseColor,
-                    opacity: opacity,
-                    metallic: metallic,
-                    roughness: 1.0 - glossiness
-                };
-                return babylonMetallicRoughness;
-            };
-            /**
-             * Returns the perceived brightness value based on the provided color
-             * @param color - color used in calculating the perceived brightness
-             * @returns - perceived brightness value
-             */
-            _GLTFMaterial.PerceivedBrightness = function (color) {
-                return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
-            };
-            /**
              * Computes the metallic factor
              * Computes the metallic factor
              * @param diffuse - diffused value
              * @param diffuse - diffused value
              * @param specular - specular value
              * @param specular - specular value
@@ -1113,14 +947,15 @@ var BABYLON;
              * @returns - metallic value
              * @returns - metallic value
              */
              */
             _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
             _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
-                if (specular < this.dielectricSpecular.r) {
+                if (specular < _GLTFMaterial.dielectricSpecular.r) {
+                    _GLTFMaterial.dielectricSpecular;
                     return 0;
                     return 0;
                 }
                 }
-                var a = this.dielectricSpecular.r;
-                var b = diffuse * oneMinusSpecularStrength / (1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
-                var c = this.dielectricSpecular.r - specular;
+                var a = _GLTFMaterial.dielectricSpecular.r;
+                var b = diffuse * oneMinusSpecularStrength / (1.0 - _GLTFMaterial.dielectricSpecular.r) + specular - 2.0 * _GLTFMaterial.dielectricSpecular.r;
+                var c = _GLTFMaterial.dielectricSpecular.r - specular;
                 var D = b * b - 4.0 * a * c;
                 var D = b * b - 4.0 * a * c;
-                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a));
+                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a), 0, 1);
             };
             };
             /**
             /**
              * Gets the glTF alpha mode from the Babylon Material
              * Gets the glTF alpha mode from the Babylon Material
@@ -1152,7 +987,7 @@ var BABYLON;
                             return "MASK" /* MASK */;
                             return "MASK" /* MASK */;
                         }
                         }
                         case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
                         case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
-                            console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                            BABYLON.Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
                             return "BLEND" /* BLEND */;
                             return "BLEND" /* BLEND */;
                         }
                         }
                         default: {
                         default: {
@@ -1165,13 +1000,227 @@ var BABYLON;
                 }
                 }
             };
             };
             /**
             /**
+             * Converts a Babylon Standard Material to a glTF Material.
+             * @param babylonStandardMaterial - BJS Standard Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertStandardMaterial = function (babylonStandardMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Standard Material is currently not fully supported/implemented in glTF serializer");
+                var glTFPbrMetallicRoughness = _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
+                var glTFMaterial = { name: babylonStandardMaterial.name };
+                if (babylonStandardMaterial.backFaceCulling) {
+                    if (!babylonStandardMaterial.twoSidedLighting) {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
+                    }
+                    glTFMaterial.doubleSided = true;
+                }
+                if (hasTextureCoords) {
+                    if (babylonStandardMaterial.diffuseTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.diffuseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.bumpTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.bumpTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.emissiveTexture) {
+                        var glTFEmissiveTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFEmissiveTexture) {
+                            glTFMaterial.emissiveTexture = glTFEmissiveTexture;
+                        }
+                        glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
+                    }
+                    if (babylonStandardMaterial.ambientTexture) {
+                        var glTFOcclusionTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData);
+                        if (glTFOcclusionTexture) {
+                            glTFMaterial.occlusionTexture = glTFOcclusionTexture;
+                        }
+                    }
+                }
+                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
+                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
+                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
+                    }
+                    else {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+             * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial = function (babylonPBRMetalRoughMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                var glTFPbrMetallicRoughness = {};
+                if (babylonPBRMetalRoughMaterial.baseColor) {
+                    glTFPbrMetallicRoughness.baseColorFactor = [
+                        babylonPBRMetalRoughMaterial.baseColor.r,
+                        babylonPBRMetalRoughMaterial.baseColor.g,
+                        babylonPBRMetalRoughMaterial.baseColor.b,
+                        babylonPBRMetalRoughMaterial.alpha
+                    ];
+                }
+                if (babylonPBRMetalRoughMaterial.metallic != null) {
+                    glTFPbrMetallicRoughness.metallicFactor = babylonPBRMetalRoughMaterial.metallic;
+                }
+                if (babylonPBRMetalRoughMaterial.roughness != null) {
+                    glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMetalRoughMaterial.roughness;
+                }
+                var glTFMaterial = {
+                    name: babylonPBRMetalRoughMaterial.name
+                };
+                if (babylonPBRMetalRoughMaterial.doubleSided) {
+                    glTFMaterial.doubleSided = babylonPBRMetalRoughMaterial.doubleSided;
+                }
+                if (hasTextureCoords) {
+                    if (babylonPBRMetalRoughMaterial.baseTexture != null) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.baseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.normalTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.normalTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.occlusionTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.occlusionTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.occlusionTexture = glTFTexture;
+                            if (babylonPBRMetalRoughMaterial.occlusionStrength != null) {
+                                glTFMaterial.occlusionTexture.strength = babylonPBRMetalRoughMaterial.occlusionStrength;
+                            }
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.emissiveTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFMaterial.emissiveTexture = glTFTexture;
+                        }
+                    }
+                }
+                if (babylonPBRMetalRoughMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
+                    glTFMaterial.emissiveFactor = babylonPBRMetalRoughMaterial.emissiveColor.asArray();
+                }
+                if (babylonPBRMetalRoughMaterial.transparencyMode != null) {
+                    var alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMetalRoughMaterial);
+                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
+                        glTFMaterial.alphaMode = alphaMode;
+                        if (alphaMode === "BLEND" /* BLEND */) {
+                            glTFMaterial.alphaCutoff = babylonPBRMetalRoughMaterial.alphaCutOff;
+                        }
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Extracts a texture from a Babylon texture into file data and glTF data.
+             * @param babylonTexture - Babylon texture to extract.
+             * @param mimeType - Mime Type of the babylonTexture.
+             * @param images - Array of glTF images.
+             * @param textures - Array of glTF textures.
+             * @param imageData - map of image file name and data.
+             * @return - glTF texture, or null if the texture format is not supported.
+             */
+            _GLTFMaterial.ExportTexture = function (babylonTexture, mimeType, images, textures, imageData) {
+                var textureInfo = null;
+                var glTFTexture = {
+                    source: images.length
+                };
+                var textureName = "texture_" + (textures.length - 1).toString();
+                var textureData = babylonTexture.getInternalTexture();
+                if (textureData != null) {
+                    textureName = textureData.url;
+                }
+                textureName = BABYLON.Tools.GetFilename(textureName);
+                var baseFile = textureName.split('.')[0];
+                var extension = "";
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    extension = ".jpg";
+                }
+                else if (mimeType === "image/png" /* PNG */) {
+                    extension = ".png";
+                }
+                else {
+                    BABYLON.Tools.Error("Unsupported mime type " + mimeType);
+                }
+                textureName = baseFile + extension;
+                var pixels = babylonTexture.readPixels();
+                var imageCanvas = document.createElement('canvas');
+                imageCanvas.id = "ImageCanvas";
+                var ctx = imageCanvas.getContext('2d');
+                var size = babylonTexture.getSize();
+                imageCanvas.width = size.width;
+                imageCanvas.height = size.height;
+                var imgData = ctx.createImageData(size.width, size.height);
+                imgData.data.set(pixels);
+                ctx.putImageData(imgData, 0, 0);
+                var base64Data = imageCanvas.toDataURL(mimeType);
+                var binStr = atob(base64Data.split(',')[1]);
+                var arr = new Uint8Array(binStr.length);
+                for (var i = 0; i < binStr.length; ++i) {
+                    arr[i] = binStr.charCodeAt(i);
+                }
+                var imageValues = { data: arr, mimeType: mimeType };
+                imageData[textureName] = imageValues;
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    var glTFImage = {
+                        uri: textureName
+                    };
+                    var foundIndex = -1;
+                    for (var i = 0; i < images.length; ++i) {
+                        if (images[i].uri === textureName) {
+                            foundIndex = i;
+                            break;
+                        }
+                    }
+                    if (foundIndex === -1) {
+                        images.push(glTFImage);
+                        glTFTexture.source = images.length - 1;
+                        textures.push({
+                            source: images.length - 1
+                        });
+                        textureInfo = {
+                            index: images.length - 1
+                        };
+                    }
+                    else {
+                        glTFTexture.source = foundIndex;
+                        textureInfo = {
+                            index: foundIndex
+                        };
+                    }
+                }
+                return textureInfo;
+            };
+            /**
              * Represents the dielectric specular values for R, G and B.
              * Represents the dielectric specular values for R, G and B.
              */
              */
             _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
             _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
             /**
             /**
-             * Epsilon value, used as a small tolerance value for a numeric value.
+             * Allows the maximum specular power to be defined for material calculations.
              */
              */
-            _GLTFMaterial.epsilon = 1e-6;
+            _GLTFMaterial.maxSpecularPower = 1024;
             return _GLTFMaterial;
             return _GLTFMaterial;
         }());
         }());
         GLTF2._GLTFMaterial = _GLTFMaterial;
         GLTF2._GLTFMaterial = _GLTFMaterial;

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


+ 297 - 248
dist/preview release/serializers/babylonjs.serializers.js

@@ -646,84 +646,6 @@ var BABYLON;
                 }
                 }
             };
             };
             /**
             /**
-             *
-             * @param babylonTexture - Babylon texture to extract.
-             * @param mimeType - Mime Type of the babylonTexture.
-             * @return - glTF texture, or null if the texture format is not supported.
-             */
-            _Exporter.prototype.exportTexture = function (babylonTexture, mimeType) {
-                if (mimeType === void 0) { mimeType = "image/jpeg" /* JPEG */; }
-                var textureInfo = null;
-                var glTFTexture;
-                glTFTexture = {
-                    source: this.images.length
-                };
-                var textureName = babylonTexture.getInternalTexture().url;
-                if (textureName.search('/') !== -1) {
-                    var splitFilename = textureName.split('/');
-                    textureName = splitFilename[splitFilename.length - 1];
-                    var basefile = textureName.split('.')[0];
-                    var extension = textureName.split('.')[1];
-                    if (mimeType === "image/jpeg" /* JPEG */) {
-                        extension = ".jpg";
-                    }
-                    else if (mimeType === "image/png" /* PNG */) {
-                        extension = ".png";
-                    }
-                    else {
-                        throw new Error("Unsupported mime type " + mimeType);
-                    }
-                    textureName = basefile + extension;
-                }
-                var pixels = babylonTexture.readPixels();
-                var imageCanvas = document.createElement('canvas');
-                imageCanvas.id = "ImageCanvas";
-                var ctx = imageCanvas.getContext('2d');
-                var size = babylonTexture.getSize();
-                imageCanvas.width = size.width;
-                imageCanvas.height = size.height;
-                var imgData = ctx.createImageData(size.width, size.height);
-                imgData.data.set(pixels);
-                ctx.putImageData(imgData, 0, 0);
-                var base64Data = imageCanvas.toDataURL(mimeType);
-                var binStr = atob(base64Data.split(',')[1]);
-                var arr = new Uint8Array(binStr.length);
-                for (var i = 0; i < binStr.length; ++i) {
-                    arr[i] = binStr.charCodeAt(i);
-                }
-                var imageValues = { data: arr, mimeType: mimeType };
-                this.imageData[textureName] = imageValues;
-                if (mimeType === "image/jpeg" /* JPEG */) {
-                    var glTFImage = {
-                        uri: textureName
-                    };
-                    var foundIndex = -1;
-                    for (var i = 0; i < this.images.length; ++i) {
-                        if (this.images[i].uri === textureName) {
-                            foundIndex = i;
-                            break;
-                        }
-                    }
-                    if (foundIndex === -1) {
-                        this.images.push(glTFImage);
-                        glTFTexture.source = this.images.length - 1;
-                        this.textures.push({
-                            source: this.images.length - 1
-                        });
-                        textureInfo = {
-                            index: this.images.length - 1
-                        };
-                    }
-                    else {
-                        glTFTexture.source = foundIndex;
-                        textureInfo = {
-                            index: foundIndex
-                        };
-                    }
-                }
-                return textureInfo;
-            };
-            /**
              * 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.
@@ -789,7 +711,7 @@ var BABYLON;
                                     break;
                                     break;
                                 }
                                 }
                                 default: {
                                 default: {
-                                    console.warn("Unsupported VertexBuffer kind: " + kind);
+                                    BABYLON.Tools.Warn("Unsupported VertexBuffer kind: " + kind);
                                 }
                                 }
                             }
                             }
                             if (bufferViewName !== null) {
                             if (bufferViewName !== null) {
@@ -943,120 +865,20 @@ var BABYLON;
                             }
                             }
                         }
                         }
                         if (bufferMesh.material) {
                         if (bufferMesh.material) {
-                            if (bufferMesh.material instanceof BABYLON.StandardMaterial) {
-                                console.warn("Standard Material is currently not fully supported/implemented in glTF serializer");
-                                var babylonStandardMaterial = bufferMesh.material;
-                                var glTFPbrMetallicRoughness = GLTF2._GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
-                                var glTFMaterial = { name: babylonStandardMaterial.name };
-                                if (!babylonStandardMaterial.backFaceCulling) {
-                                    glTFMaterial.doubleSided = true;
-                                }
-                                if (babylonStandardMaterial.diffuseTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.diffuseTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.bumpTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.normalTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.emissiveTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
-                                    if (glTFEmissiveTexture) {
-                                        glTFMaterial.emissiveTexture = glTFEmissiveTexture;
-                                    }
-                                    glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
-                                }
-                                if (babylonStandardMaterial.ambientTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
-                                    if (glTFOcclusionTexture) {
-                                        glTFMaterial.occlusionTexture = glTFOcclusionTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
-                                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
-                                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
-                                    }
-                                    else {
-                                        console.warn("glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
+                            if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                                var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
+                                meshPrimitive.material = materialIndex;
                             }
                             }
-                            else if (bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
-                                var babylonPBRMaterial = bufferMesh.material;
-                                var glTFPbrMetallicRoughness = {};
-                                if (babylonPBRMaterial.baseColor) {
-                                    glTFPbrMetallicRoughness.baseColorFactor = [
-                                        babylonPBRMaterial.baseColor.r,
-                                        babylonPBRMaterial.baseColor.g,
-                                        babylonPBRMaterial.baseColor.b,
-                                        babylonPBRMaterial.alpha
-                                    ];
-                                }
-                                if (babylonPBRMaterial.baseTexture !== undefined) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.baseTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                                    }
-                                    glTFPbrMetallicRoughness.baseColorTexture;
-                                }
-                                if (babylonPBRMaterial.metallic !== undefined) {
-                                    glTFPbrMetallicRoughness.metallicFactor = babylonPBRMaterial.metallic;
-                                }
-                                if (babylonPBRMaterial.roughness !== undefined) {
-                                    glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMaterial.roughness;
-                                }
-                                var glTFMaterial = {
-                                    name: babylonPBRMaterial.name
-                                };
-                                if (babylonPBRMaterial.doubleSided) {
-                                    glTFMaterial.doubleSided = babylonPBRMaterial.doubleSided;
-                                }
-                                if (babylonPBRMaterial.normalTexture) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.normalTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.normalTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonPBRMaterial.occlusionTexture) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.occlusionTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.occlusionTexture = glTFTexture;
-                                        if (babylonPBRMaterial.occlusionStrength !== undefined) {
-                                            glTFMaterial.occlusionTexture.strength = babylonPBRMaterial.occlusionStrength;
-                                        }
-                                    }
-                                }
-                                if (babylonPBRMaterial.emissiveTexture) {
-                                    var glTFTexture = this.exportTexture(babylonPBRMaterial.emissiveTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFMaterial.emissiveTexture = glTFTexture;
-                                    }
-                                }
-                                if (!babylonPBRMaterial.emissiveColor.equals(new BABYLON.Color3(0.0, 0.0, 0.0))) {
-                                    glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
+                            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);
+                                    meshPrimitive.material = materialIndex;
                                 }
                                 }
-                                if (babylonPBRMaterial.transparencyMode) {
-                                    var alphaMode = GLTF2._GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
-                                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
-                                        glTFMaterial.alphaMode = alphaMode;
-                                        if (alphaMode === "BLEND" /* BLEND */) {
-                                            glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
-                                        }
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
                             }
                             }
                             else {
                             else {
-                                console.warn("Material type is not yet implemented in glTF serializer: " + bufferMesh.material.name);
+                                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);
@@ -1076,6 +898,9 @@ var BABYLON;
                 if (babylonScene.meshes.length > 0) {
                 if (babylonScene.meshes.length > 0) {
                     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);
+                    }
                     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 &&
@@ -1186,70 +1011,79 @@ var BABYLON;
             function _GLTFMaterial() {
             function _GLTFMaterial() {
             }
             }
             /**
             /**
+             * Gets the materials from a Babylon scene and converts them to glTF materials.
+             * @param scene
+             * @param mimeType
+             * @param images
+             * @param textures
+             * @param materials
+             * @param imageData
+             * @param hasTextureCoords
+             */
+            _GLTFMaterial.ConvertMaterialsToGLTF = function (babylonMaterials, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                for (var i = 0; i < babylonMaterials.length; ++i) {
+                    var babylonMaterial = babylonMaterials[i];
+                    if (babylonMaterial instanceof BABYLON.StandardMaterial) {
+                        _GLTFMaterial.ConvertStandardMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                    else if (babylonMaterial instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                        _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                }
+            };
+            /**
              * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
              * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
              * @param babylonStandardMaterial
              * @param babylonStandardMaterial
              * @returns - glTF Metallic Roughness Material representation
              * @returns - glTF Metallic Roughness Material representation
              */
              */
             _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness = function (babylonStandardMaterial) {
             _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness = function (babylonStandardMaterial) {
-                var babylonSpecularGlossiness = {
-                    diffuse: babylonStandardMaterial.diffuseColor,
-                    opacity: babylonStandardMaterial.alpha,
-                    specular: babylonStandardMaterial.specularColor || BABYLON.Color3.Black(),
-                    glossiness: babylonStandardMaterial.specularPower / 256
-                };
-                if (babylonStandardMaterial.specularTexture) {
+                var P0 = new BABYLON.Vector2(0, 1);
+                var P1 = new BABYLON.Vector2(0, 0.1);
+                var P2 = new BABYLON.Vector2(0, 0.1);
+                var P3 = new BABYLON.Vector2(1300, 0.1);
+                /**
+                 * Given the control points, solve for x based on a given t for a cubic bezier curve.
+                 * @param t - a value between 0 and 1.
+                 * @param p0 - first control point.
+                 * @param p1 - second control point.
+                 * @param p2 - third control point.
+                 * @param p3 - fourth control point.
+                 * @returns - number result of cubic bezier curve at the specified t.
+                 */
+                function cubicBezierCurve(t, p0, p1, p2, p3) {
+                    return ((1 - t) * (1 - t) * (1 - t) * p0 +
+                        3 * (1 - t) * (1 - t) * t * p1 +
+                        3 * (1 - t) * t * t * p2 +
+                        t * t * t * p3);
                 }
                 }
-                var babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
+                /**
+                 * Evaluates a specified specular power value to determine the appropriate roughness value,
+                 * based on a pre-defined cubic bezier curve with specular on the abscissa axis (x-axis)
+                 * and roughness on the ordinant axis (y-axis).
+                 * @param specularPower - specular power of standard material.
+                 * @returns - Number representing the roughness value.
+                 */
+                function solveForRoughness(specularPower) {
+                    var t = Math.pow(specularPower / P3.x, 0.333333);
+                    return cubicBezierCurve(t, P0.y, P1.y, P2.y, P3.y);
+                }
+                var diffuse = babylonStandardMaterial.diffuseColor.toLinearSpace().scale(0.5);
+                var opacity = babylonStandardMaterial.alpha;
+                var specularPower = BABYLON.Scalar.Clamp(babylonStandardMaterial.specularPower, 0, this.maxSpecularPower);
+                var roughness = solveForRoughness(specularPower);
                 var glTFPbrMetallicRoughness = {
                 var glTFPbrMetallicRoughness = {
                     baseColorFactor: [
                     baseColorFactor: [
-                        babylonMetallicRoughness.baseColor.r,
-                        babylonMetallicRoughness.baseColor.g,
-                        babylonMetallicRoughness.baseColor.b,
-                        babylonMetallicRoughness.opacity
+                        diffuse.r,
+                        diffuse.g,
+                        diffuse.b,
+                        opacity
                     ],
                     ],
-                    metallicFactor: babylonMetallicRoughness.metallic,
-                    roughnessFactor: babylonMetallicRoughness.roughness
+                    metallicFactor: 0,
+                    roughnessFactor: roughness,
                 };
                 };
                 return glTFPbrMetallicRoughness;
                 return glTFPbrMetallicRoughness;
             };
             };
             /**
             /**
-             * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-             * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-             * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
-             * @returns - Babylon metallic roughness values
-             */
-            _GLTFMaterial._ConvertToMetallicRoughness = function (babylonSpecularGlossiness) {
-                var diffuse = babylonSpecularGlossiness.diffuse;
-                var opacity = babylonSpecularGlossiness.opacity;
-                var specular = babylonSpecularGlossiness.specular;
-                var glossiness = BABYLON.Scalar.Clamp(babylonSpecularGlossiness.glossiness);
-                var oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
-                var diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
-                var specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
-                var metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
-                var diffuseScaleFactor = oneMinusSpecularStrength / (1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
-                var baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
-                var baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1 / Math.max(metallic, this.epsilon));
-                var lerpColor = BABYLON.Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
-                var baseColor = new BABYLON.Color3();
-                lerpColor.clampToRef(0, 1, baseColor);
-                var babylonMetallicRoughness = {
-                    baseColor: baseColor,
-                    opacity: opacity,
-                    metallic: metallic,
-                    roughness: 1.0 - glossiness
-                };
-                return babylonMetallicRoughness;
-            };
-            /**
-             * Returns the perceived brightness value based on the provided color
-             * @param color - color used in calculating the perceived brightness
-             * @returns - perceived brightness value
-             */
-            _GLTFMaterial.PerceivedBrightness = function (color) {
-                return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
-            };
-            /**
              * Computes the metallic factor
              * Computes the metallic factor
              * @param diffuse - diffused value
              * @param diffuse - diffused value
              * @param specular - specular value
              * @param specular - specular value
@@ -1257,14 +1091,15 @@ var BABYLON;
              * @returns - metallic value
              * @returns - metallic value
              */
              */
             _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
             _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
-                if (specular < this.dielectricSpecular.r) {
+                if (specular < _GLTFMaterial.dielectricSpecular.r) {
+                    _GLTFMaterial.dielectricSpecular;
                     return 0;
                     return 0;
                 }
                 }
-                var a = this.dielectricSpecular.r;
-                var b = diffuse * oneMinusSpecularStrength / (1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
-                var c = this.dielectricSpecular.r - specular;
+                var a = _GLTFMaterial.dielectricSpecular.r;
+                var b = diffuse * oneMinusSpecularStrength / (1.0 - _GLTFMaterial.dielectricSpecular.r) + specular - 2.0 * _GLTFMaterial.dielectricSpecular.r;
+                var c = _GLTFMaterial.dielectricSpecular.r - specular;
                 var D = b * b - 4.0 * a * c;
                 var D = b * b - 4.0 * a * c;
-                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a));
+                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a), 0, 1);
             };
             };
             /**
             /**
              * Gets the glTF alpha mode from the Babylon Material
              * Gets the glTF alpha mode from the Babylon Material
@@ -1296,7 +1131,7 @@ var BABYLON;
                             return "MASK" /* MASK */;
                             return "MASK" /* MASK */;
                         }
                         }
                         case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
                         case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
-                            console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                            BABYLON.Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
                             return "BLEND" /* BLEND */;
                             return "BLEND" /* BLEND */;
                         }
                         }
                         default: {
                         default: {
@@ -1309,13 +1144,227 @@ var BABYLON;
                 }
                 }
             };
             };
             /**
             /**
+             * Converts a Babylon Standard Material to a glTF Material.
+             * @param babylonStandardMaterial - BJS Standard Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertStandardMaterial = function (babylonStandardMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Standard Material is currently not fully supported/implemented in glTF serializer");
+                var glTFPbrMetallicRoughness = _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
+                var glTFMaterial = { name: babylonStandardMaterial.name };
+                if (babylonStandardMaterial.backFaceCulling) {
+                    if (!babylonStandardMaterial.twoSidedLighting) {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
+                    }
+                    glTFMaterial.doubleSided = true;
+                }
+                if (hasTextureCoords) {
+                    if (babylonStandardMaterial.diffuseTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.diffuseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.bumpTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.bumpTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.emissiveTexture) {
+                        var glTFEmissiveTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFEmissiveTexture) {
+                            glTFMaterial.emissiveTexture = glTFEmissiveTexture;
+                        }
+                        glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
+                    }
+                    if (babylonStandardMaterial.ambientTexture) {
+                        var glTFOcclusionTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData);
+                        if (glTFOcclusionTexture) {
+                            glTFMaterial.occlusionTexture = glTFOcclusionTexture;
+                        }
+                    }
+                }
+                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
+                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
+                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
+                    }
+                    else {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+             * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial = function (babylonPBRMetalRoughMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                var glTFPbrMetallicRoughness = {};
+                if (babylonPBRMetalRoughMaterial.baseColor) {
+                    glTFPbrMetallicRoughness.baseColorFactor = [
+                        babylonPBRMetalRoughMaterial.baseColor.r,
+                        babylonPBRMetalRoughMaterial.baseColor.g,
+                        babylonPBRMetalRoughMaterial.baseColor.b,
+                        babylonPBRMetalRoughMaterial.alpha
+                    ];
+                }
+                if (babylonPBRMetalRoughMaterial.metallic != null) {
+                    glTFPbrMetallicRoughness.metallicFactor = babylonPBRMetalRoughMaterial.metallic;
+                }
+                if (babylonPBRMetalRoughMaterial.roughness != null) {
+                    glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMetalRoughMaterial.roughness;
+                }
+                var glTFMaterial = {
+                    name: babylonPBRMetalRoughMaterial.name
+                };
+                if (babylonPBRMetalRoughMaterial.doubleSided) {
+                    glTFMaterial.doubleSided = babylonPBRMetalRoughMaterial.doubleSided;
+                }
+                if (hasTextureCoords) {
+                    if (babylonPBRMetalRoughMaterial.baseTexture != null) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.baseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.normalTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.normalTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.occlusionTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.occlusionTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.occlusionTexture = glTFTexture;
+                            if (babylonPBRMetalRoughMaterial.occlusionStrength != null) {
+                                glTFMaterial.occlusionTexture.strength = babylonPBRMetalRoughMaterial.occlusionStrength;
+                            }
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.emissiveTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFMaterial.emissiveTexture = glTFTexture;
+                        }
+                    }
+                }
+                if (babylonPBRMetalRoughMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
+                    glTFMaterial.emissiveFactor = babylonPBRMetalRoughMaterial.emissiveColor.asArray();
+                }
+                if (babylonPBRMetalRoughMaterial.transparencyMode != null) {
+                    var alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMetalRoughMaterial);
+                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
+                        glTFMaterial.alphaMode = alphaMode;
+                        if (alphaMode === "BLEND" /* BLEND */) {
+                            glTFMaterial.alphaCutoff = babylonPBRMetalRoughMaterial.alphaCutOff;
+                        }
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Extracts a texture from a Babylon texture into file data and glTF data.
+             * @param babylonTexture - Babylon texture to extract.
+             * @param mimeType - Mime Type of the babylonTexture.
+             * @param images - Array of glTF images.
+             * @param textures - Array of glTF textures.
+             * @param imageData - map of image file name and data.
+             * @return - glTF texture, or null if the texture format is not supported.
+             */
+            _GLTFMaterial.ExportTexture = function (babylonTexture, mimeType, images, textures, imageData) {
+                var textureInfo = null;
+                var glTFTexture = {
+                    source: images.length
+                };
+                var textureName = "texture_" + (textures.length - 1).toString();
+                var textureData = babylonTexture.getInternalTexture();
+                if (textureData != null) {
+                    textureName = textureData.url;
+                }
+                textureName = BABYLON.Tools.GetFilename(textureName);
+                var baseFile = textureName.split('.')[0];
+                var extension = "";
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    extension = ".jpg";
+                }
+                else if (mimeType === "image/png" /* PNG */) {
+                    extension = ".png";
+                }
+                else {
+                    BABYLON.Tools.Error("Unsupported mime type " + mimeType);
+                }
+                textureName = baseFile + extension;
+                var pixels = babylonTexture.readPixels();
+                var imageCanvas = document.createElement('canvas');
+                imageCanvas.id = "ImageCanvas";
+                var ctx = imageCanvas.getContext('2d');
+                var size = babylonTexture.getSize();
+                imageCanvas.width = size.width;
+                imageCanvas.height = size.height;
+                var imgData = ctx.createImageData(size.width, size.height);
+                imgData.data.set(pixels);
+                ctx.putImageData(imgData, 0, 0);
+                var base64Data = imageCanvas.toDataURL(mimeType);
+                var binStr = atob(base64Data.split(',')[1]);
+                var arr = new Uint8Array(binStr.length);
+                for (var i = 0; i < binStr.length; ++i) {
+                    arr[i] = binStr.charCodeAt(i);
+                }
+                var imageValues = { data: arr, mimeType: mimeType };
+                imageData[textureName] = imageValues;
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    var glTFImage = {
+                        uri: textureName
+                    };
+                    var foundIndex = -1;
+                    for (var i = 0; i < images.length; ++i) {
+                        if (images[i].uri === textureName) {
+                            foundIndex = i;
+                            break;
+                        }
+                    }
+                    if (foundIndex === -1) {
+                        images.push(glTFImage);
+                        glTFTexture.source = images.length - 1;
+                        textures.push({
+                            source: images.length - 1
+                        });
+                        textureInfo = {
+                            index: images.length - 1
+                        };
+                    }
+                    else {
+                        glTFTexture.source = foundIndex;
+                        textureInfo = {
+                            index: foundIndex
+                        };
+                    }
+                }
+                return textureInfo;
+            };
+            /**
              * Represents the dielectric specular values for R, G and B.
              * Represents the dielectric specular values for R, G and B.
              */
              */
             _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
             _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
             /**
             /**
-             * Epsilon value, used as a small tolerance value for a numeric value.
+             * Allows the maximum specular power to be defined for material calculations.
              */
              */
-            _GLTFMaterial.epsilon = 1e-6;
+            _GLTFMaterial.maxSpecularPower = 1024;
             return _GLTFMaterial;
             return _GLTFMaterial;
         }());
         }());
         GLTF2._GLTFMaterial = _GLTFMaterial;
         GLTF2._GLTFMaterial = _GLTFMaterial;

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


+ 314 - 22
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -4,6 +4,255 @@
 declare module 'babylonjs-serializers' { 
 declare module 'babylonjs-serializers' { 
     export = BABYLON; 
     export = BABYLON; 
 }
 }
+declare module BABYLON.GLTF2 {
+    const enum AccessorComponentType {
+        BYTE = 5120,
+        UNSIGNED_BYTE = 5121,
+        SHORT = 5122,
+        UNSIGNED_SHORT = 5123,
+        UNSIGNED_INT = 5125,
+        FLOAT = 5126,
+    }
+    const enum AccessorType {
+        SCALAR = "SCALAR",
+        VEC2 = "VEC2",
+        VEC3 = "VEC3",
+        VEC4 = "VEC4",
+        MAT2 = "MAT2",
+        MAT3 = "MAT3",
+        MAT4 = "MAT4",
+    }
+    const enum AnimationChannelTargetPath {
+        TRANSLATION = "translation",
+        ROTATION = "rotation",
+        SCALE = "scale",
+        WEIGHTS = "weights",
+    }
+    const enum AnimationSamplerInterpolation {
+        LINEAR = "LINEAR",
+        STEP = "STEP",
+        CUBICSPLINE = "CUBICSPLINE",
+    }
+    const enum CameraType {
+        PERSPECTIVE = "perspective",
+        ORTHOGRAPHIC = "orthographic",
+    }
+    const enum ImageMimeType {
+        JPEG = "image/jpeg",
+        PNG = "image/png",
+    }
+    const enum MaterialAlphaMode {
+        OPAQUE = "OPAQUE",
+        MASK = "MASK",
+        BLEND = "BLEND",
+    }
+    const enum MeshPrimitiveMode {
+        POINTS = 0,
+        LINES = 1,
+        LINE_LOOP = 2,
+        LINE_STRIP = 3,
+        TRIANGLES = 4,
+        TRIANGLE_STRIP = 5,
+        TRIANGLE_FAN = 6,
+    }
+    const enum TextureMagFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+    }
+    const enum TextureMinFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+        NEAREST_MIPMAP_NEAREST = 9984,
+        LINEAR_MIPMAP_NEAREST = 9985,
+        NEAREST_MIPMAP_LINEAR = 9986,
+        LINEAR_MIPMAP_LINEAR = 9987,
+    }
+    const enum TextureWrapMode {
+        CLAMP_TO_EDGE = 33071,
+        MIRRORED_REPEAT = 33648,
+        REPEAT = 10497,
+    }
+    interface IProperty {
+        extensions?: {
+            [key: string]: any;
+        };
+        extras?: any;
+    }
+    interface IChildRootProperty extends IProperty {
+        name?: string;
+    }
+    interface IAccessorSparseIndices extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+    }
+    interface IAccessorSparseValues extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+    }
+    interface IAccessorSparse extends IProperty {
+        count: number;
+        indices: IAccessorSparseIndices;
+        values: IAccessorSparseValues;
+    }
+    interface IAccessor extends IChildRootProperty {
+        bufferView?: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+        normalized?: boolean;
+        count: number;
+        type: AccessorType;
+        max?: number[];
+        min?: number[];
+        sparse?: IAccessorSparse;
+    }
+    interface IAnimationChannel extends IProperty {
+        sampler: number;
+        target: IAnimationChannelTarget;
+    }
+    interface IAnimationChannelTarget extends IProperty {
+        node: number;
+        path: AnimationChannelTargetPath;
+    }
+    interface IAnimationSampler extends IProperty {
+        input: number;
+        interpolation?: AnimationSamplerInterpolation;
+        output: number;
+    }
+    interface IAnimation extends IChildRootProperty {
+        channels: IAnimationChannel[];
+        samplers: IAnimationSampler[];
+    }
+    interface IAsset extends IChildRootProperty {
+        copyright?: string;
+        generator?: string;
+        version: string;
+        minVersion?: string;
+    }
+    interface IBuffer extends IChildRootProperty {
+        uri?: string;
+        byteLength: number;
+    }
+    interface IBufferView extends IChildRootProperty {
+        buffer: number;
+        byteOffset?: number;
+        byteLength: number;
+        byteStride?: number;
+    }
+    interface ICameraOrthographic extends IProperty {
+        xmag: number;
+        ymag: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICameraPerspective extends IProperty {
+        aspectRatio: number;
+        yfov: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICamera extends IChildRootProperty {
+        orthographic?: ICameraOrthographic;
+        perspective?: ICameraPerspective;
+        type: CameraType;
+    }
+    interface IImage extends IChildRootProperty {
+        uri?: string;
+        mimeType?: ImageMimeType;
+        bufferView?: number;
+    }
+    interface IMaterialNormalTextureInfo extends ITextureInfo {
+        scale?: number;
+    }
+    interface IMaterialOcclusionTextureInfo extends ITextureInfo {
+        strength?: number;
+    }
+    interface IMaterialPbrMetallicRoughness {
+        baseColorFactor?: number[];
+        baseColorTexture?: ITextureInfo;
+        metallicFactor?: number;
+        roughnessFactor?: number;
+        metallicRoughnessTexture?: ITextureInfo;
+    }
+    interface IMaterial extends IChildRootProperty {
+        pbrMetallicRoughness?: IMaterialPbrMetallicRoughness;
+        normalTexture?: IMaterialNormalTextureInfo;
+        occlusionTexture?: IMaterialOcclusionTextureInfo;
+        emissiveTexture?: ITextureInfo;
+        emissiveFactor?: number[];
+        alphaMode?: MaterialAlphaMode;
+        alphaCutoff?: number;
+        doubleSided?: boolean;
+    }
+    interface IMeshPrimitive extends IProperty {
+        attributes: {
+            [name: string]: number;
+        };
+        indices?: number;
+        material?: number;
+        mode?: MeshPrimitiveMode;
+        targets?: {
+            [name: string]: number;
+        }[];
+    }
+    interface IMesh extends IChildRootProperty {
+        primitives: IMeshPrimitive[];
+        weights?: number[];
+    }
+    interface INode extends IChildRootProperty {
+        camera?: number;
+        children?: number[];
+        skin?: number;
+        matrix?: number[];
+        mesh?: number;
+        rotation?: number[];
+        scale?: number[];
+        translation?: number[];
+        weights?: number[];
+    }
+    interface ISampler extends IChildRootProperty {
+        magFilter?: TextureMagFilter;
+        minFilter?: TextureMinFilter;
+        wrapS?: TextureWrapMode;
+        wrapT?: TextureWrapMode;
+    }
+    interface IScene extends IChildRootProperty {
+        nodes: number[];
+    }
+    interface ISkin extends IChildRootProperty {
+        inverseBindMatrices?: number;
+        skeleton?: number;
+        joints: number[];
+    }
+    interface ITexture extends IChildRootProperty {
+        sampler?: number;
+        source: number;
+    }
+    interface ITextureInfo {
+        index: number;
+        texCoord?: number;
+    }
+    interface IGLTF extends IProperty {
+        accessors?: IAccessor[];
+        animations?: IAnimation[];
+        asset: IAsset;
+        buffers?: IBuffer[];
+        bufferViews?: IBufferView[];
+        cameras?: ICamera[];
+        extensionsUsed?: string[];
+        extensionsRequired?: string[];
+        images?: IImage[];
+        materials?: IMaterial[];
+        meshes?: IMesh[];
+        nodes?: INode[];
+        samplers?: ISampler[];
+        scene?: number;
+        scenes?: IScene[];
+        skins?: ISkin[];
+        textures?: ITexture[];
+    }
+}
+
 
 
 declare module BABYLON {
 declare module BABYLON {
     class OBJExport {
     class OBJExport {
@@ -203,13 +452,6 @@ declare module BABYLON.GLTF2 {
          */
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
         /**
-         *
-         * @param babylonTexture - Babylon texture to extract.
-         * @param mimeType - Mime Type of the babylonTexture.
-         * @return - glTF texture, or null if the texture format is not supported.
-         */
-        private exportTexture(babylonTexture, mimeType?);
-        /**
          * 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.
@@ -275,9 +517,25 @@ declare module BABYLON.GLTF2 {
          */
          */
         private static readonly dielectricSpecular;
         private static readonly dielectricSpecular;
         /**
         /**
-         * Epsilon value, used as a small tolerance value for a numeric value.
+         * Allows the maximum specular power to be defined for material calculations.
+         */
+        private static maxSpecularPower;
+        /**
+         * Gets the materials from a Babylon scene and converts them to glTF materials.
+         * @param scene
+         * @param mimeType
+         * @param images
+         * @param textures
+         * @param materials
+         * @param imageData
+         * @param hasTextureCoords
          */
          */
-        private static readonly epsilon;
+        static ConvertMaterialsToGLTF(babylonMaterials: Material[], mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
         /**
         /**
          * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
          * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
          * @param babylonStandardMaterial
          * @param babylonStandardMaterial
@@ -285,19 +543,6 @@ declare module BABYLON.GLTF2 {
          */
          */
         static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
         static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
         /**
         /**
-         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
-         * @returns - Babylon metallic roughness values
-         */
-        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness);
-        /**
-         * Returns the perceived brightness value based on the provided color
-         * @param color - color used in calculating the perceived brightness
-         * @returns - perceived brightness value
-         */
-        private static PerceivedBrightness(color);
-        /**
          * Computes the metallic factor
          * Computes the metallic factor
          * @param diffuse - diffused value
          * @param diffuse - diffused value
          * @param specular - specular value
          * @param specular - specular value
@@ -311,5 +556,52 @@ declare module BABYLON.GLTF2 {
          * @returns - The Babylon alpha mode value
          * @returns - The Babylon alpha mode value
          */
          */
         static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
         static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
+        /**
+         * Converts a Babylon Standard Material to a glTF Material.
+         * @param babylonStandardMaterial - BJS Standard Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertStandardMaterial(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+         * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertPBRMetallicRoughnessMaterial(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Extracts a texture from a Babylon texture into file data and glTF data.
+         * @param babylonTexture - Babylon texture to extract.
+         * @param mimeType - Mime Type of the babylonTexture.
+         * @param images - Array of glTF images.
+         * @param textures - Array of glTF textures.
+         * @param imageData - map of image file name and data.
+         * @return - glTF texture, or null if the texture format is not supported.
+         */
+        static ExportTexture(babylonTexture: BaseTexture, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }): Nullable<ITextureInfo>;
     }
     }
 }
 }

+ 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-alpha6",
+    "version": "3.2.0-alpha7",
     "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
+ 1398 - 4908
dist/preview release/typedocValidationBaseline.json


+ 486 - 0
dist/preview release/viewer/babylon.viewer.d.ts

@@ -0,0 +1,486 @@
+/// <reference path="../babylon.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>;
+    }
+}

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
+ 110728 - 0
dist/preview release/viewer/babylon.viewer.max.js


+ 486 - 0
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -0,0 +1,486 @@
+/// <reference types="babylonjs"/>
+
+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>;
+    }
+}

+ 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-alpha6",
+    "version": "3.2.0-alpha7",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -12,9 +12,11 @@
     "main": "babylon.viewer.js",
     "main": "babylon.viewer.js",
     "files": [
     "files": [
         "babylon.viewer.js",
         "babylon.viewer.js",
+        "babylon.viewer.module.d.ts",
         "readme.md",
         "readme.md",
         "package.json"
         "package.json"
     ],
     ],
+    "typings": "babylon.viewer.module.d.ts",
     "keywords": [
     "keywords": [
         "3D",
         "3D",
         "javascript",
         "javascript",

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

@@ -1,6 +1,8 @@
 # 3.2.0
 # 3.2.0
 
 
 ## Major updates
 ## Major updates
+
+- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles) ([deltakosh](https://github.com/deltakosh))
 - Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
 - Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
 - Introduced texture binding atlas. This optimization allows the engine to reuse texture bindings instead of rebinding textures when they are not on constant sampler indexes ([deltakosh](https://github.com/deltakosh))
 - Introduced texture binding atlas. This optimization allows the engine to reuse texture bindings instead of rebinding textures when they are not on constant sampler indexes ([deltakosh](https://github.com/deltakosh))
 - New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
 - New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
@@ -8,9 +10,14 @@
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
 - Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
 - Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
 - Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
+- 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 [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
 
 
 ## Updates
 ## Updates
+
 - Tons of functions and classes received the code comments they deserved (All the community)
 - Tons of functions and classes received the code comments they deserved (All the community)
+- Added `particleSystem.reset()` to clear a particle system ([deltakosh](https://github.com/deltakosh))
 - Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
 - Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
 - Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
 - Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
@@ -21,7 +28,7 @@
   ([carloslanderas](https://github.com/carloslanderas))
   ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now has onBeforeCameraTeleport and onAfterCameraTeleport observables that will be notified before and after camera teleportation is triggered.
 - VRHelper now has onBeforeCameraTeleport and onAfterCameraTeleport observables that will be notified before and after camera teleportation is triggered.
   ([carloslanderas](https://github.com/carloslanderas))
   ([carloslanderas](https://github.com/carloslanderas))
-- VRHelper now has the public property teleportationEnabled to enable / disable camera teleportation. 
+- VRHelper now has the public property teleportationEnabled to enable / disable camera teleportation.
    ([carloslanderas](https://github.com/carloslanderas))
    ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
    ([carloslanderas](https://github.com/carloslanderas))
    ([carloslanderas](https://github.com/carloslanderas))
@@ -34,7 +41,7 @@
    ([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 default pipeline ([trevordev](https://github.com/trevordev))
+- 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))
@@ -43,15 +50,41 @@
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
 - Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
 - Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
 - 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))
 - (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))
-- (Viewer) It is now possible to update parts of the configuration without rcreating the objects. ([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))
+- (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))
+- (Viewer) Model can be normalized using configuration, camera is dynamically configured. ([RaananW](https://github.com/RaananW))
+- (Gulp) extra/external declarations can be prepended to final NPM declarations during build. ([RaananW](https://github.com/RaananW))
+- GUI.Line can have its world position set from one end or the other ([SvenFrankson](https://github.com/SvenFrankson))
+- Added FOV system to background material for zoom effects in skyboxes without adjusting camera FOV ([DavidHGillen](https://github.com/DavidHGillen))
+- Improved glTF loader by using promises for asynchronous operations. ([bghgary](https://github.com/bghgary)]
+- Improved glTF loader performance by compiling materials in parallel with downloading external resources. ([bghgary](https://github.com/bghgary)]
+- Added unit tests for the glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
+- Added promise-based async functions to the SceneLoader, Scene.whenReadyAsync, and material.forceCompilationAsync. ([bghgary](https://github.com/bghgary)]
+- Added checks to VertexData.merge to ensure data is valid before merging. ([bghgary](https://github.com/bghgary)]
+- Ability to set a mesh to customize the webVR gaze tracker ([trevordev](https://github.com/trevordev))
+- Added promise-based async functions for initWebVRAsync and useStandingMatrixAsync ([trevordev](https://github.com/trevordev))
+- Add stroke (outline) options on GUI text control ([SvenFrankson](https://github.com/SvenFrankson))
+- Add isThumbClamped option on GUI slider control ([JeanPhilippeKernel](https://github.com/JeanPhilippeKernel))
+- 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))
+- (Viewer) Declaration file published. ([RaananW](https://github.com/RaananW))
+- Added Draco mesh compression support to glTF 2.0 loader. ([bghgary](https://github.com/bghgary))
 
 
 ## Bug fixes
 ## Bug fixes
+
 - `setPivotMatrix` ws not setting pivot correctly. This is now fixed. We also introduced a new `setPreTransformMatrix` to reproduce the sometimes needed behavior of the previous `setPivotMatrix` function ([deltakosh](https://github.com/deltakosh))
 - `setPivotMatrix` ws not setting pivot correctly. This is now fixed. We also introduced a new `setPreTransformMatrix` to reproduce the sometimes needed behavior of the previous `setPivotMatrix` function ([deltakosh](https://github.com/deltakosh))
+- SPS solid particle `.pivot` property now also behaves like the standard mesh pivot. Former behavior (particle translation) can be kept with the particle property `.translateFromPivot` set to true ([jbousquie](https://github.com/jbousquie))
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
-- Fixed a bug with merging vertex data ([bghgary](https://github.com/bghgary))
+- 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))
+- Enabling teleportation in the vr helper class caused a redundant post process to be added ([trevordev](https://github.com/trevordev))
 
 
 ## Breaking changes
 ## Breaking changes
-- Removed 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)]
+- 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)]

+ 16 - 9
gui/src/advancedDynamicTexture.ts

@@ -20,7 +20,7 @@ module BABYLON.GUI {
         public _lastPickedControl: Control;
         public _lastPickedControl: Control;
         public _lastControlOver: Nullable<Control>;
         public _lastControlOver: Nullable<Control>;
         public _lastControlDown: Nullable<Control>;
         public _lastControlDown: Nullable<Control>;
-        public _capturingControl: Nullable<Control>;
+        public _capturingControl: {[pointerId:number]:Control} = {};
         public _shouldBlockPointer: boolean;
         public _shouldBlockPointer: boolean;
         public _layerToDispose: Nullable<Layer>;
         public _layerToDispose: Nullable<Layer>;
         public _linkedControls = new Array<Control>();
         public _linkedControls = new Array<Control>();
@@ -196,6 +196,12 @@ module BABYLON.GUI {
 
 
         public markAsDirty() {
         public markAsDirty() {
             this._isDirty = true;
             this._isDirty = true;
+
+            this.executeOnAllControls((control) => {
+                if (control._isFontSizeInPercentage) {
+                    control._resetFontCache();
+                }
+            });
         }
         }
 
 
         public addControl(control: Control): AdvancedDynamicTexture {
         public addControl(control: Control): AdvancedDynamicTexture {
@@ -364,7 +370,7 @@ module BABYLON.GUI {
             this._rootContainer._draw(measure, context);
             this._rootContainer._draw(measure, context);
         }
         }
 
 
-        private _doPicking(x: number, y: number, type: number, buttonIndex: number): void {
+        private _doPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): void {
             var scene = this.getScene();
             var scene = this.getScene();
 
 
             if (!scene) {
             if (!scene) {
@@ -379,12 +385,12 @@ module BABYLON.GUI {
                 y = y * ((textureSize.height / this._renderScale) / engine.getRenderHeight());
                 y = y * ((textureSize.height / this._renderScale) / engine.getRenderHeight());
             }
             }
 
 
-            if (this._capturingControl) {
-                this._capturingControl._processObservables(type, x, y, buttonIndex);
+            if (this._capturingControl[pointerId]) {
+                this._capturingControl[pointerId]._processObservables(type, x, y, pointerId, buttonIndex);
                 return;
                 return;
             }
             }
 
 
-            if (!this._rootContainer._processPicking(x, y, type, buttonIndex)) {
+            if (!this._rootContainer._processPicking(x, y, type, pointerId, buttonIndex)) {
 
 
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     if (this._lastControlOver) {
                     if (this._lastControlOver) {
@@ -426,7 +432,7 @@ module BABYLON.GUI {
                 let y = (scene.pointerY / engine.getHardwareScalingLevel() - viewport.y * engine.getRenderHeight()) / viewport.height;
                 let y = (scene.pointerY / engine.getHardwareScalingLevel() - viewport.y * engine.getRenderHeight()) / viewport.height;
 
 
                 this._shouldBlockPointer = false;
                 this._shouldBlockPointer = false;
-                this._doPicking(x, y, pi.type, pi.event.button);
+                this._doPicking(x, y, pi.type, (pi.event as PointerEvent).pointerId || 0, pi.event.button);
 
 
                 pi.skipOnPointerObservable = this._shouldBlockPointer;
                 pi.skipOnPointerObservable = this._shouldBlockPointer;
             });
             });
@@ -445,17 +451,18 @@ module BABYLON.GUI {
                     && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
                     && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
                     return;
                     return;
                 }
                 }
-
+                var pointerId = (pi.event as PointerEvent).pointerId || 0;
                 if (pi.pickInfo && pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
                 if (pi.pickInfo && pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
                     var uv = pi.pickInfo.getTextureCoordinates();
                     var uv = pi.pickInfo.getTextureCoordinates();
 
 
                     if (uv) {
                     if (uv) {
                         let size = this.getSize();
                         let size = this.getSize();
-                        this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, 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) {
                     if (this._lastControlDown) {
-                        this._lastControlDown.forcePointerUp();
+                        this._lastControlDown.forcePointerUp(pointerId);
                     }
                     }
                     this._lastControlDown = null;
                     this._lastControlDown = null;
 
 

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

@@ -37,7 +37,7 @@ module BABYLON.GUI {
         }
         }
 
 
         // While being a container, the button behaves like a control.
         // While being a container, the button behaves like a control.
-        public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
+        public _processPicking(x: number, y: number, type: number, pointerId:number, buttonIndex: number): boolean {
             if (!this.isHitTestVisible || !this.isVisible || this.notRenderable) {
             if (!this.isHitTestVisible || !this.isVisible || this.notRenderable) {
                 return false;
                 return false;
             }
             }
@@ -46,7 +46,7 @@ module BABYLON.GUI {
                 return false;
                 return false;
             }
             }
 
 
-            this._processObservables(type, x, y, buttonIndex);
+            this._processObservables(type, x, y, pointerId, buttonIndex);
 
 
             return true;
             return true;
         }
         }
@@ -71,8 +71,8 @@ module BABYLON.GUI {
             super._onPointerOut(target);
             super._onPointerOut(target);
         }
         }
 
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
                 return false;
             }
             }
 
 
@@ -84,12 +84,12 @@ module BABYLON.GUI {
             return true;
             return true;
         }
         }
 
 
-        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
             if (this.pointerUpAnimation) {
             if (this.pointerUpAnimation) {
                 this.pointerUpAnimation();
                 this.pointerUpAnimation();
             }
             }
 
 
-            super._onPointerUp(target, coordinates, buttonIndex);
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }        
         }        
 
 
         // Statics
         // Statics

+ 2 - 2
gui/src/controls/checkbox.ts

@@ -115,8 +115,8 @@ module BABYLON.GUI {
         }
         }
 
 
         // Events
         // Events
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
                 return false;
             }
             }
 
 

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

@@ -377,8 +377,8 @@ module BABYLON.GUI {
             return false;
             return false;
         }
         }
 
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
                 return false;
             }            
             }            
 
 
@@ -394,7 +394,7 @@ module BABYLON.GUI {
             }
             }
 
 
             this._updateValueFromPointer(coordinates.x, coordinates.y);
             this._updateValueFromPointer(coordinates.x, coordinates.y);
-            this._host._capturingControl = this;
+            this._host._capturingControl[pointerId] = this;
 
 
             return true;
             return true;
         }
         }
@@ -407,11 +407,11 @@ module BABYLON.GUI {
             super._onPointerMove(target, coordinates);
             super._onPointerMove(target, coordinates);
         }
         }
 
 
-        public _onPointerUp (target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp (target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
             this._pointerIsDown = false;
             this._pointerIsDown = false;
             
             
-            this._host._capturingControl = null;
-            super._onPointerUp(target, coordinates, buttonIndex);
+            delete this._host._capturingControl[pointerId];
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }     
         }     
     }    
     }    
 }
 }

+ 4 - 3
gui/src/controls/container.ts

@@ -159,6 +159,7 @@ module BABYLON.GUI {
                 this._clipForChildren(context);
                 this._clipForChildren(context);
                 for (var child of this._children) {
                 for (var child of this._children) {
                     if (child.isVisible && !child.notRenderable) {
                     if (child.isVisible && !child.notRenderable) {
+                        child._tempParentMeasure.copyFrom(this._measureForChildren);
                         child._draw(this._measureForChildren, context);
                         child._draw(this._measureForChildren, context);
 
 
                         if (child.onAfterDrawObservable.hasObservers()) {
                         if (child.onAfterDrawObservable.hasObservers()) {
@@ -174,7 +175,7 @@ module BABYLON.GUI {
             }
             }
         }
         }
 
 
-        public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
+        public _processPicking(x: number, y: number, type: number, pointerId:number, buttonIndex: number): boolean {
             if (!this.isVisible || this.notRenderable) {
             if (!this.isVisible || this.notRenderable) {
                 return false;
                 return false;
             }
             }
@@ -186,7 +187,7 @@ module BABYLON.GUI {
             // Checking backwards to pick closest first
             // Checking backwards to pick closest first
             for (var index = this._children.length - 1; index >= 0; index--) {
             for (var index = this._children.length - 1; index >= 0; index--) {
                 var child = this._children[index];
                 var child = this._children[index];
-                if (child._processPicking(x, y, type, buttonIndex)) {
+                if (child._processPicking(x, y, type, pointerId, buttonIndex)) {
                     return true;
                     return true;
                 }
                 }
             }
             }
@@ -195,7 +196,7 @@ module BABYLON.GUI {
                 return false;
                 return false;
             }
             }
 
 
-            return this._processObservables(type, x, y, buttonIndex);
+            return this._processObservables(type, x, y, pointerId, buttonIndex);
         }
         }
 
 
         protected _clipForChildren(context: CanvasRenderingContext2D): void {
         protected _clipForChildren(context: CanvasRenderingContext2D): void {

+ 40 - 13
gui/src/controls/control.ts

@@ -20,6 +20,7 @@ module BABYLON.GUI {
         protected _horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         protected _horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         protected _verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
         protected _verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
         private _isDirty = true;
         private _isDirty = true;
+        public _tempParentMeasure = Measure.Empty();
         protected _cachedParentMeasure = Measure.Empty();
         protected _cachedParentMeasure = Measure.Empty();
         private _paddingLeft = new ValueAndUnit(0);
         private _paddingLeft = new ValueAndUnit(0);
         private _paddingRight = new ValueAndUnit(0);
         private _paddingRight = new ValueAndUnit(0);
@@ -45,6 +46,7 @@ module BABYLON.GUI {
         private _downCount = 0;
         private _downCount = 0;
         private _enterCount = 0;
         private _enterCount = 0;
         private _doNotRender = false;
         private _doNotRender = false;
+        private _downPointerIds:{[id:number] : boolean} = {};
 
 
         public isHitTestVisible = true;
         public isHitTestVisible = true;
         public isPointerBlocker = false;
         public isPointerBlocker = false;
@@ -277,8 +279,17 @@ module BABYLON.GUI {
             this._fontSet = true;
             this._fontSet = true;
         }
         }
 
 
+        /** @ignore */
+        public get _isFontSizeInPercentage(): boolean {
+            return this._fontSize.isPercentage;
+        }
+
         public get fontSizeInPixels(): number {
         public get fontSizeInPixels(): number {
-            return this._fontSize.getValueInPixel(this._host, 100);
+            if (this._fontSize.isPixel) {
+                return this._fontSize.getValue(this._host);
+            }
+
+            return this._fontSize.getValueInPixel(this._host, this._tempParentMeasure.height || this._cachedParentMeasure.height);
         }
         }
 
 
         public get fontSize(): string | number {
         public get fontSize(): string | number {
@@ -483,6 +494,11 @@ module BABYLON.GUI {
             return "Control";
             return "Control";
         }
         }
 
 
+        /** @ignore */
+        public _resetFontCache(): void {
+            this._fontSet = true;
+        }
+
         public getLocalCoordinates(globalCoordinates: Vector2): Vector2 {
         public getLocalCoordinates(globalCoordinates: Vector2): Vector2 {
             var result = Vector2.Zero();
             var result = Vector2.Zero();
 
 
@@ -844,7 +860,7 @@ module BABYLON.GUI {
             return true;
             return true;
         }
         }
 
 
-        public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
+        public _processPicking(x: number, y: number, type: number, pointerId:number, buttonIndex: number): boolean {
             if (!this.isHitTestVisible || !this.isVisible || this._doNotRender) {
             if (!this.isHitTestVisible || !this.isVisible || this._doNotRender) {
                 return false;
                 return false;
             }
             }
@@ -853,7 +869,7 @@ module BABYLON.GUI {
                 return false;
                 return false;
             }
             }
 
 
-            this._processObservables(type, x, y, buttonIndex);
+            this._processObservables(type, x, y, pointerId, buttonIndex);
 
 
             return true;
             return true;
         }
         }
@@ -886,33 +902,43 @@ module BABYLON.GUI {
             if (canNotify && this.parent != null) this.parent._onPointerOut(target);
             if (canNotify && this.parent != null) this.parent._onPointerOut(target);
         }
         }
 
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
             if (this._downCount !== 0) {
             if (this._downCount !== 0) {
                 return false;
                 return false;
             }
             }
 
 
             this._downCount++;
             this._downCount++;
 
 
+            this._downPointerIds[pointerId] = true;
+
             var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
             var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
 
 
-            if (canNotify && this.parent != null) this.parent._onPointerDown(target, coordinates, buttonIndex);
+            if (canNotify && this.parent != null) this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex);
 
 
             return true;
             return true;
         }
         }
 
 
-        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
             this._downCount = 0;
             this._downCount = 0;
 
 
+            delete this._downPointerIds[pointerId];
+
             var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
             var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
 
 
-            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, buttonIndex);
+            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }
         }
 
 
-        public forcePointerUp() {
-            this._onPointerUp(this, Vector2.Zero(), 0);
+        public forcePointerUp(pointerId:Nullable<number> = null) {
+            if(pointerId !== null){
+                this._onPointerUp(this, Vector2.Zero(), pointerId, 0);
+            }else{
+                for(var key in this._downPointerIds){
+                    this._onPointerUp(this, Vector2.Zero(), +key as number, 0);
+                }
+            }
         }
         }
 
 
-        public _processObservables(type: number, x: number, y: number, buttonIndex: number): boolean {
+        public _processObservables(type: number, x: number, y: number, pointerId:number, buttonIndex: number): boolean {
             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);
@@ -931,7 +957,7 @@ module BABYLON.GUI {
             }
             }
 
 
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                this._onPointerDown(this, this._dummyVector2, buttonIndex);
+                this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex);
                 this._host._lastControlDown = this;
                 this._host._lastControlDown = this;
                 this._host._lastPickedControl = this;
                 this._host._lastPickedControl = this;
                 return true;
                 return true;
@@ -939,7 +965,7 @@ module BABYLON.GUI {
 
 
             if (type === BABYLON.PointerEventTypes.POINTERUP) {
             if (type === BABYLON.PointerEventTypes.POINTERUP) {
                 if (this._host._lastControlDown) {
                 if (this._host._lastControlDown) {
-                    this._host._lastControlDown._onPointerUp(this, this._dummyVector2, buttonIndex);
+                    this._host._lastControlDown._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
                 }
                 }
                 this._host._lastControlDown = null;
                 this._host._lastControlDown = null;
                 return true;
                 return true;
@@ -948,12 +974,13 @@ module BABYLON.GUI {
             return false;
             return false;
         }
         }
 
 
+
         private _prepareFont() {
         private _prepareFont() {
             if (!this._font && !this._fontSet) {
             if (!this._font && !this._fontSet) {
                 return;
                 return;
             }
             }
 
 
-            this._font = this._fontStyle + " " + this._fontSize.getValue(this._host) + "px " + this._fontFamily;
+            this._font = this._fontStyle + " " + this.fontSizeInPixels + "px " + this._fontFamily;
 
 
             this._fontOffset = Control._GetFontOffset(this._font);
             this._fontOffset = Control._GetFontOffset(this._font);
         }
         }

+ 4 - 4
gui/src/controls/inputText.ts

@@ -432,8 +432,8 @@ module BABYLON.GUI {
             context.restore();
             context.restore();
         }
         }
 
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
                 return false;
             }
             }
 
 
@@ -449,8 +449,8 @@ module BABYLON.GUI {
             return true;
             return true;
         }
         }
 
 
-        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
-            super._onPointerUp(target, coordinates, buttonIndex);
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }
         }
 
 
         public dispose() {
         public dispose() {

+ 45 - 7
gui/src/controls/line.ts

@@ -179,14 +179,52 @@ module BABYLON.GUI {
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void {          
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void {          
             this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
             this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
             this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;            
             this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;            
-        }   
+        }
+
+        /**
+         * Move one end of the line given 3D cartesian coordinates.
+         * @param position Targeted world position
+         * @param scene Scene
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        public moveToVector3(position: Vector3, scene: Scene, end: boolean = false): void {
+            if (!this._host || this._root !== this._host._rootContainer) {
+                Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
+                return;
+            }
+
+            var globalViewport = this._host._getGlobalViewport(scene);
+            var projectedPosition = Vector3.Project(position, Matrix.Identity(), scene.getTransformMatrix(), globalViewport);
 
 
-        public _moveToProjectedPosition(projectedPosition: Vector3): void {
-            this.x1 = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
-            this.y1 = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
+            this._moveToProjectedPosition(projectedPosition, end)
 
 
-            this._x1.ignoreAdaptiveScaling = true;
-            this._y1.ignoreAdaptiveScaling = true;
+            if (projectedPosition.z < 0 || projectedPosition.z > 1) {
+                this.notRenderable = true;
+                return;
+            }
+            this.notRenderable = false;
+        }
+
+        /**
+         * Move one end of the line to a position in screen absolute space.
+         * @param projectedPosition Position in screen absolute space (X, Y)
+         * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
+         */
+        public _moveToProjectedPosition(projectedPosition: Vector3, end: boolean = false): void {
+            let x: string = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
+            let y: string = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
+
+            if (end) {
+                this.x2 = x;
+                this.y2 = y;
+                this._x2.ignoreAdaptiveScaling = true;
+                this._y2.ignoreAdaptiveScaling = true;
+            } else {
+                this.x1 = x;
+                this.y1 = y;
+                this._x1.ignoreAdaptiveScaling = true;
+                this._y1.ignoreAdaptiveScaling = true;
+            }
         }
         }
     }    
     }    
-}
+}

+ 0 - 0
gui/src/controls/radioButton.ts


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